1 /* 2 * The authors of this software are Rob Pike and Ken Thompson. 3 * Copyright (c) 2002 by Lucent Technologies. 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose without fee is hereby granted, provided that this entire notice 6 * is included in all copies of any software which is or includes a copy 7 * or modification of this software and in all copies of the supporting 8 * documentation for such software. 9 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED 10 * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY 11 * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY 12 * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. 13 */ 14 #include "lib9.h" 15 #include "fmtdef.h" 16 17 /* format the output into f->to and return the number of characters fmted */ 18 int 19 dofmt(Fmt *f, char *fmt) 20 { 21 Rune rune, *rt, *rs; 22 int r; 23 char *t, *s; 24 int n, nfmt; 25 26 nfmt = f->nfmt; 27 for(;;){ 28 if(f->runes){ 29 rt = f->to; 30 rs = f->stop; 31 while((r = *(uchar*)fmt) && r != '%'){ 32 if(r < Runeself) 33 fmt++; 34 else{ 35 fmt += chartorune(&rune, fmt); 36 r = rune; 37 } 38 FMTRCHAR(f, rt, rs, r); 39 } 40 fmt++; 41 f->nfmt += rt - (Rune *)f->to; 42 f->to = rt; 43 if(!r) 44 return f->nfmt - nfmt; 45 f->stop = rs; 46 }else{ 47 t = f->to; 48 s = f->stop; 49 while((r = *(uchar*)fmt) && r != '%'){ 50 if(r < Runeself){ 51 FMTCHAR(f, t, s, r); 52 fmt++; 53 }else{ 54 n = chartorune(&rune, fmt); 55 if(t + n > s){ 56 t = _fmtflush(f, t, n); 57 if(t != nil) 58 s = f->stop; 59 else 60 return -1; 61 } 62 while(n--) 63 *t++ = *fmt++; 64 } 65 } 66 fmt++; 67 f->nfmt += t - (char *)f->to; 68 f->to = t; 69 if(!r) 70 return f->nfmt - nfmt; 71 f->stop = s; 72 } 73 74 fmt = _fmtdispatch(f, fmt, 0); 75 if(fmt == nil) 76 return -1; 77 } 78 } 79 80 void * 81 _fmtflush(Fmt *f, void *t, int len) 82 { 83 if(f->runes) 84 f->nfmt += (Rune*)t - (Rune*)f->to; 85 else 86 f->nfmt += (char*)t - (char *)f->to; 87 f->to = t; 88 if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){ 89 f->stop = f->to; 90 return nil; 91 } 92 return f->to; 93 } 94 95 /* 96 * put a formatted block of memory sz bytes long of n runes into the output buffer, 97 * left/right justified in a field of at least f->width charactes 98 */ 99 int 100 _fmtpad(Fmt *f, int n) 101 { 102 char *t, *s; 103 int i; 104 105 t = f->to; 106 s = f->stop; 107 for(i = 0; i < n; i++) 108 FMTCHAR(f, t, s, ' '); 109 f->nfmt += t - (char *)f->to; 110 f->to = t; 111 return 0; 112 } 113 114 int 115 _rfmtpad(Fmt *f, int n) 116 { 117 Rune *t, *s; 118 int i; 119 120 t = f->to; 121 s = f->stop; 122 for(i = 0; i < n; i++) 123 FMTRCHAR(f, t, s, ' '); 124 f->nfmt += t - (Rune *)f->to; 125 f->to = t; 126 return 0; 127 } 128 129 int 130 _fmtcpy(Fmt *f, void *vm, int n, int sz) 131 { 132 Rune *rt, *rs, r; 133 char *t, *s, *m, *me; 134 ulong fl; 135 int nc, w; 136 137 m = vm; 138 me = m + sz; 139 w = f->width; 140 fl = f->flags; 141 if((fl & FmtPrec) && n > f->prec) 142 n = f->prec; 143 if(f->runes){ 144 if(!(fl & FmtLeft) && _rfmtpad(f, w - n) < 0) 145 return -1; 146 rt = f->to; 147 rs = f->stop; 148 for(nc = n; nc > 0; nc--){ 149 r = *(uchar*)m; 150 if(r < Runeself) 151 m++; 152 else if((me - m) >= UTFmax || fullrune(m, me-m)) 153 m += chartorune(&r, m); 154 else 155 break; 156 FMTRCHAR(f, rt, rs, r); 157 } 158 f->nfmt += rt - (Rune *)f->to; 159 f->to = rt; 160 if(m < me) 161 return -1; 162 if(fl & FmtLeft && _rfmtpad(f, w - n) < 0) 163 return -1; 164 }else{ 165 if(!(fl & FmtLeft) && _fmtpad(f, w - n) < 0) 166 return -1; 167 t = f->to; 168 s = f->stop; 169 for(nc = n; nc > 0; nc--){ 170 r = *(uchar*)m; 171 if(r < Runeself) 172 m++; 173 else if((me - m) >= UTFmax || fullrune(m, me-m)) 174 m += chartorune(&r, m); 175 else 176 break; 177 FMTRUNE(f, t, s, r); 178 } 179 f->nfmt += t - (char *)f->to; 180 f->to = t; 181 if(fl & FmtLeft && _fmtpad(f, w - n) < 0) 182 return -1; 183 } 184 return 0; 185 } 186 187 int 188 _fmtrcpy(Fmt *f, void *vm, int n) 189 { 190 Rune r, *m, *me, *rt, *rs; 191 char *t, *s; 192 ulong fl; 193 int w; 194 195 m = vm; 196 w = f->width; 197 fl = f->flags; 198 if((fl & FmtPrec) && n > f->prec) 199 n = f->prec; 200 if(f->runes){ 201 if(!(fl & FmtLeft) && _rfmtpad(f, w - n) < 0) 202 return -1; 203 rt = f->to; 204 rs = f->stop; 205 for(me = m + n; m < me; m++) 206 FMTRCHAR(f, rt, rs, *m); 207 f->nfmt += rt - (Rune *)f->to; 208 f->to = rt; 209 if(fl & FmtLeft && _rfmtpad(f, w - n) < 0) 210 return -1; 211 }else{ 212 if(!(fl & FmtLeft) && _fmtpad(f, w - n) < 0) 213 return -1; 214 t = f->to; 215 s = f->stop; 216 for(me = m + n; m < me; m++){ 217 r = *m; 218 FMTRUNE(f, t, s, r); 219 } 220 f->nfmt += t - (char *)f->to; 221 f->to = t; 222 if(fl & FmtLeft && _fmtpad(f, w - n) < 0) 223 return -1; 224 } 225 return 0; 226 } 227 228 /* fmt out one character */ 229 int 230 _charfmt(Fmt *f) 231 { 232 char x[1]; 233 234 x[0] = va_arg(f->args, int); 235 f->prec = 1; 236 return _fmtcpy(f, x, 1, 1); 237 } 238 239 /* fmt out one rune */ 240 int 241 _runefmt(Fmt *f) 242 { 243 Rune x[1]; 244 245 x[0] = va_arg(f->args, int); 246 return _fmtrcpy(f, x, 1); 247 } 248 249 /* public helper routine: fmt out a null terminated string already in hand */ 250 int 251 fmtstrcpy(Fmt *f, char *s) 252 { 253 int p, i; 254 if(!s) 255 return _fmtcpy(f, "<nil>", 5, 5); 256 /* if precision is specified, make sure we don't wander off the end */ 257 if(f->flags & FmtPrec){ 258 p = f->prec; 259 for(i = 0; i < p; i++) 260 if(s[i] == 0) 261 break; 262 return _fmtcpy(f, s, utfnlen(s, i), i); /* BUG?: won't print a partial rune at end */ 263 } 264 265 return _fmtcpy(f, s, utflen(s), strlen(s)); 266 } 267 268 /* fmt out a null terminated utf string */ 269 int 270 _strfmt(Fmt *f) 271 { 272 char *s; 273 274 s = va_arg(f->args, char *); 275 return fmtstrcpy(f, s); 276 } 277 278 /* public helper routine: fmt out a null terminated rune string already in hand */ 279 int 280 fmtrunestrcpy(Fmt *f, Rune *s) 281 { 282 Rune *e; 283 int n, p; 284 285 if(!s) 286 return _fmtcpy(f, "<nil>", 5, 5); 287 /* if precision is specified, make sure we don't wander off the end */ 288 if(f->flags & FmtPrec){ 289 p = f->prec; 290 for(n = 0; n < p; n++) 291 if(s[n] == 0) 292 break; 293 }else{ 294 for(e = s; *e; e++) 295 ; 296 n = e - s; 297 } 298 return _fmtrcpy(f, s, n); 299 } 300 301 /* fmt out a null terminated rune string */ 302 int 303 _runesfmt(Fmt *f) 304 { 305 Rune *s; 306 307 s = va_arg(f->args, Rune *); 308 return fmtrunestrcpy(f, s); 309 } 310 311 /* fmt a % */ 312 int 313 _percentfmt(Fmt *f) 314 { 315 Rune x[1]; 316 317 x[0] = f->r; 318 f->prec = 1; 319 return _fmtrcpy(f, x, 1); 320 } 321 322 /* fmt an integer */ 323 int 324 _ifmt(Fmt *f) 325 { 326 char buf[70], *p, *conv; 327 uvlong vu; 328 ulong u; 329 int neg, base, i, n, fl, w, isv; 330 331 neg = 0; 332 fl = f->flags; 333 isv = 0; 334 vu = 0; 335 u = 0; 336 if(f->r == 'p'){ 337 u = (ulong)va_arg(f->args, void*); 338 f->r = 'x'; 339 fl |= FmtUnsigned; 340 }else if(fl & FmtVLong){ 341 isv = 1; 342 if(fl & FmtUnsigned) 343 vu = va_arg(f->args, uvlong); 344 else 345 vu = va_arg(f->args, vlong); 346 }else if(fl & FmtLong){ 347 if(fl & FmtUnsigned) 348 u = va_arg(f->args, ulong); 349 else 350 u = va_arg(f->args, long); 351 }else if(fl & FmtByte){ 352 if(fl & FmtUnsigned) 353 u = (uchar)va_arg(f->args, int); 354 else 355 u = (char)va_arg(f->args, int); 356 }else if(fl & FmtShort){ 357 if(fl & FmtUnsigned) 358 u = (ushort)va_arg(f->args, int); 359 else 360 u = (short)va_arg(f->args, int); 361 }else{ 362 if(fl & FmtUnsigned) 363 u = va_arg(f->args, uint); 364 else 365 u = va_arg(f->args, int); 366 } 367 conv = "0123456789abcdef"; 368 switch(f->r){ 369 case 'd': 370 base = 10; 371 break; 372 case 'x': 373 base = 16; 374 break; 375 case 'X': 376 base = 16; 377 conv = "0123456789ABCDEF"; 378 break; 379 case 'b': 380 base = 2; 381 break; 382 case 'o': 383 base = 8; 384 break; 385 default: 386 return -1; 387 } 388 if(!(fl & FmtUnsigned)){ 389 if(isv && (vlong)vu < 0){ 390 vu = -(vlong)vu; 391 neg = 1; 392 }else if(!isv && (long)u < 0){ 393 u = -(long)u; 394 neg = 1; 395 } 396 } 397 p = buf + sizeof buf - 1; 398 n = 0; 399 if(isv){ 400 while(vu){ 401 i = vu % base; 402 vu /= base; 403 if((fl & FmtComma) && n % 4 == 3){ 404 *p-- = ','; 405 n++; 406 } 407 *p-- = conv[i]; 408 n++; 409 } 410 }else{ 411 while(u){ 412 i = u % base; 413 u /= base; 414 if((fl & FmtComma) && n % 4 == 3){ 415 *p-- = ','; 416 n++; 417 } 418 *p-- = conv[i]; 419 n++; 420 } 421 } 422 if(n == 0){ 423 *p-- = '0'; 424 n = 1; 425 } 426 for(w = f->prec; n < w && p > buf+3; n++) 427 *p-- = '0'; 428 if(neg || (fl & (FmtSign|FmtSpace))) 429 n++; 430 if(fl & FmtSharp){ 431 if(base == 16) 432 n += 2; 433 else if(base == 8){ 434 if(p[1] == '0') 435 fl &= ~FmtSharp; 436 else 437 n++; 438 } 439 } 440 if((fl & FmtZero) && !(fl & FmtLeft)){ 441 for(w = f->width; n < w && p > buf+3; n++) 442 *p-- = '0'; 443 f->width = 0; 444 } 445 if(fl & FmtSharp){ 446 if(base == 16) 447 *p-- = f->r; 448 if(base == 16 || base == 8) 449 *p-- = '0'; 450 } 451 if(neg) 452 *p-- = '-'; 453 else if(fl & FmtSign) 454 *p-- = '+'; 455 else if(fl & FmtSpace) 456 *p-- = ' '; 457 f->flags &= ~FmtPrec; 458 return _fmtcpy(f, p + 1, n, n); 459 } 460 461 int 462 _countfmt(Fmt *f) 463 { 464 void *p; 465 ulong fl; 466 467 fl = f->flags; 468 p = va_arg(f->args, void*); 469 if(fl & FmtVLong){ 470 *(vlong*)p = f->nfmt; 471 }else if(fl & FmtLong){ 472 *(long*)p = f->nfmt; 473 }else if(fl & FmtByte){ 474 *(char*)p = f->nfmt; 475 }else if(fl & FmtShort){ 476 *(short*)p = f->nfmt; 477 }else{ 478 *(int*)p = f->nfmt; 479 } 480 return 0; 481 } 482 483 int 484 _flagfmt(Fmt *f) 485 { 486 switch(f->r){ 487 case ',': 488 f->flags |= FmtComma; 489 break; 490 case '-': 491 f->flags |= FmtLeft; 492 break; 493 case '+': 494 f->flags |= FmtSign; 495 break; 496 case '#': 497 f->flags |= FmtSharp; 498 break; 499 case ' ': 500 f->flags |= FmtSpace; 501 break; 502 case 'u': 503 f->flags |= FmtUnsigned; 504 break; 505 case 'h': 506 if(f->flags & FmtShort) 507 f->flags |= FmtByte; 508 f->flags |= FmtShort; 509 break; 510 case 'l': 511 if(f->flags & FmtLong) 512 f->flags |= FmtVLong; 513 f->flags |= FmtLong; 514 break; 515 } 516 return 1; 517 } 518 519 /* default error format */ 520 int 521 _badfmt(Fmt *f) 522 { 523 char x[3]; 524 525 x[0] = '%'; 526 x[1] = f->r; 527 x[2] = '%'; 528 f->prec = 3; 529 _fmtcpy(f, x, 3, 3); 530 return 0; 531 } 532