dofmt.c (11470B)
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 11 * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY 12 * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. 13 */ 14 #include <stdarg.h> 15 #include <string.h> 16 #include "plan9.h" 17 #include "fmt.h" 18 #include "fmtdef.h" 19 20 /* format the output into f->to and return the number of characters fmted */ 21 int 22 dofmt(Fmt *f, const char *fmt) 23 { 24 Rune rune, *rt, *rs; 25 int r; 26 char *t, *s; 27 int n, nfmt; 28 29 nfmt = f->nfmt; 30 for(;;){ 31 if(f->runes){ 32 rt = (Rune*)f->to; 33 rs = (Rune*)f->stop; 34 while((r = *(uchar*)fmt) && r != '%'){ 35 if(r < Runeself) 36 fmt++; 37 else{ 38 fmt += chartorune(&rune, fmt); 39 r = rune; 40 } 41 FMTRCHAR(f, rt, rs, r); 42 } 43 fmt++; 44 f->nfmt += rt - (Rune *)f->to; 45 f->to = rt; 46 if(!r) 47 return f->nfmt - nfmt; 48 f->stop = rs; 49 }else{ 50 t = (char*)f->to; 51 s = (char*)f->stop; 52 while((r = *(uchar*)fmt) && r != '%'){ 53 if(r < Runeself){ 54 FMTCHAR(f, t, s, r); 55 fmt++; 56 }else{ 57 n = chartorune(&rune, fmt); 58 if(t + n > s){ 59 t = (char*)__fmtflush(f, t, n); 60 if(t != nil) 61 s = (char*)f->stop; 62 else 63 return -1; 64 } 65 while(n--) 66 *t++ = *fmt++; 67 } 68 } 69 fmt++; 70 f->nfmt += t - (char *)f->to; 71 f->to = t; 72 if(!r) 73 return f->nfmt - nfmt; 74 f->stop = s; 75 } 76 77 fmt = (char*)__fmtdispatch(f, fmt, 0); 78 if(fmt == nil) 79 return -1; 80 } 81 } 82 83 void * 84 __fmtflush(Fmt *f, void *t, int len) 85 { 86 if(f->runes) 87 f->nfmt += (Rune*)t - (Rune*)f->to; 88 else 89 f->nfmt += (char*)t - (char *)f->to; 90 f->to = t; 91 if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){ 92 f->stop = f->to; 93 return nil; 94 } 95 return f->to; 96 } 97 98 /* 99 * put a formatted block of memory sz bytes long of n runes into the output buffer, 100 * left/right justified in a field of at least f->width charactes 101 */ 102 int 103 __fmtpad(Fmt *f, int n) 104 { 105 char *t, *s; 106 int i; 107 108 t = (char*)f->to; 109 s = (char*)f->stop; 110 for(i = 0; i < n; i++) 111 FMTCHAR(f, t, s, ' '); 112 f->nfmt += t - (char *)f->to; 113 f->to = t; 114 return 0; 115 } 116 117 int 118 __rfmtpad(Fmt *f, int n) 119 { 120 Rune *t, *s; 121 int i; 122 123 t = (Rune*)f->to; 124 s = (Rune*)f->stop; 125 for(i = 0; i < n; i++) 126 FMTRCHAR(f, t, s, ' '); 127 f->nfmt += t - (Rune *)f->to; 128 f->to = t; 129 return 0; 130 } 131 132 int 133 __fmtcpy(Fmt *f, const void *vm, int n, int sz) 134 { 135 Rune *rt, *rs, r; 136 char *t, *s, *m, *me; 137 ulong fl; 138 int nc, w; 139 140 m = (char*)vm; 141 me = m + sz; 142 fl = f->flags; 143 w = 0; 144 if(fl & FmtWidth) 145 w = f->width; 146 if((fl & FmtPrec) && n > f->prec) 147 n = f->prec; 148 if(f->runes){ 149 if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0) 150 return -1; 151 rt = (Rune*)f->to; 152 rs = (Rune*)f->stop; 153 for(nc = n; nc > 0; nc--){ 154 r = *(uchar*)m; 155 if(r < Runeself) 156 m++; 157 else if((me - m) >= UTFmax || fullrune(m, me-m)) 158 m += chartorune(&r, m); 159 else 160 break; 161 FMTRCHAR(f, rt, rs, r); 162 } 163 f->nfmt += rt - (Rune *)f->to; 164 f->to = rt; 165 if(fl & FmtLeft && __rfmtpad(f, w - n) < 0) 166 return -1; 167 }else{ 168 if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0) 169 return -1; 170 t = (char*)f->to; 171 s = (char*)f->stop; 172 for(nc = n; nc > 0; nc--){ 173 r = *(uchar*)m; 174 if(r < Runeself) 175 m++; 176 else if((me - m) >= UTFmax || fullrune(m, me-m)) 177 m += chartorune(&r, m); 178 else 179 break; 180 FMTRUNE(f, t, s, r); 181 } 182 f->nfmt += t - (char *)f->to; 183 f->to = t; 184 if(fl & FmtLeft && __fmtpad(f, w - n) < 0) 185 return -1; 186 } 187 return 0; 188 } 189 190 int 191 __fmtrcpy(Fmt *f, const void *vm, int n) 192 { 193 Rune r, *m, *me, *rt, *rs; 194 char *t, *s; 195 ulong fl; 196 int w; 197 198 m = (Rune*)vm; 199 fl = f->flags; 200 w = 0; 201 if(fl & FmtWidth) 202 w = f->width; 203 if((fl & FmtPrec) && n > f->prec) 204 n = f->prec; 205 if(f->runes){ 206 if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0) 207 return -1; 208 rt = (Rune*)f->to; 209 rs = (Rune*)f->stop; 210 for(me = m + n; m < me; m++) 211 FMTRCHAR(f, rt, rs, *m); 212 f->nfmt += rt - (Rune *)f->to; 213 f->to = rt; 214 if(fl & FmtLeft && __rfmtpad(f, w - n) < 0) 215 return -1; 216 }else{ 217 if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0) 218 return -1; 219 t = (char*)f->to; 220 s = (char*)f->stop; 221 for(me = m + n; m < me; m++){ 222 r = *m; 223 FMTRUNE(f, t, s, r); 224 } 225 f->nfmt += t - (char *)f->to; 226 f->to = t; 227 if(fl & FmtLeft && __fmtpad(f, w - n) < 0) 228 return -1; 229 } 230 return 0; 231 } 232 233 /* fmt out one character */ 234 int 235 __charfmt(Fmt *f) 236 { 237 char x[1]; 238 239 x[0] = va_arg(f->args, int); 240 f->prec = 1; 241 return __fmtcpy(f, (const char*)x, 1, 1); 242 } 243 244 /* fmt out one rune */ 245 int 246 __runefmt(Fmt *f) 247 { 248 Rune x[1]; 249 250 x[0] = va_arg(f->args, int); 251 return __fmtrcpy(f, (const void*)x, 1); 252 } 253 254 /* public helper routine: fmt out a null terminated string already in hand */ 255 int 256 fmtstrcpy(Fmt *f, const char *s) 257 { 258 int i, j; 259 Rune r; 260 261 if(!s) 262 return __fmtcpy(f, "<nil>", 5, 5); 263 /* if precision is specified, make sure we don't wander off the end */ 264 if(f->flags & FmtPrec){ 265 i = 0; 266 for(j=0; j<f->prec && s[i]; j++) 267 i += chartorune(&r, s+i); 268 return __fmtcpy(f, s, j, i); 269 } 270 return __fmtcpy(f, s, utflen(s), strlen(s)); 271 } 272 273 /* fmt out a null terminated utf string */ 274 int 275 __strfmt(Fmt *f) 276 { 277 char *s; 278 279 s = va_arg(f->args, char *); 280 return fmtstrcpy(f, s); 281 } 282 283 /* public helper routine: fmt out a null terminated rune string already in hand */ 284 int 285 fmtrunestrcpy(Fmt *f, Rune *s) 286 { 287 Rune *e; 288 int n, p; 289 290 if(!s) 291 return __fmtcpy(f, "<nil>", 5, 5); 292 /* if precision is specified, make sure we don't wander off the end */ 293 if(f->flags & FmtPrec){ 294 p = f->prec; 295 for(n = 0; n < p; n++) 296 if(s[n] == 0) 297 break; 298 }else{ 299 for(e = s; *e; e++) 300 ; 301 n = e - s; 302 } 303 return __fmtrcpy(f, s, n); 304 } 305 306 /* fmt out a null terminated rune string */ 307 int 308 __runesfmt(Fmt *f) 309 { 310 Rune *s; 311 312 s = va_arg(f->args, Rune *); 313 return fmtrunestrcpy(f, s); 314 } 315 316 /* fmt a % */ 317 int 318 __percentfmt(Fmt *f) 319 { 320 Rune x[1]; 321 322 x[0] = f->r; 323 f->prec = 1; 324 return __fmtrcpy(f, (const void*)x, 1); 325 } 326 327 /* fmt an integer */ 328 int 329 __ifmt(Fmt *f) 330 { 331 char buf[140], *p, *conv; 332 /* 140: for 64 bits of binary + 3-byte sep every 4 digits */ 333 uvlong vu; 334 ulong u; 335 int neg, base, i, n, fl, w, isv; 336 int ndig, len, excess, bytelen; 337 char *grouping; 338 char *thousands; 339 340 neg = 0; 341 fl = f->flags; 342 isv = 0; 343 vu = 0; 344 u = 0; 345 if(f->r == 'p'){ 346 u = (ulong)va_arg(f->args, void*); 347 f->r = 'x'; 348 fl |= FmtUnsigned; 349 }else if(fl & FmtVLong){ 350 isv = 1; 351 if(fl & FmtUnsigned) 352 vu = va_arg(f->args, uvlong); 353 else 354 vu = va_arg(f->args, vlong); 355 }else if(fl & FmtLong){ 356 if(fl & FmtUnsigned) 357 u = va_arg(f->args, ulong); 358 else 359 u = va_arg(f->args, long); 360 }else if(fl & FmtByte){ 361 if(fl & FmtUnsigned) 362 u = (uchar)va_arg(f->args, int); 363 else 364 u = (char)va_arg(f->args, int); 365 }else if(fl & FmtShort){ 366 if(fl & FmtUnsigned) 367 u = (ushort)va_arg(f->args, int); 368 else 369 u = (short)va_arg(f->args, int); 370 }else{ 371 if(fl & FmtUnsigned) 372 u = va_arg(f->args, uint); 373 else 374 u = va_arg(f->args, int); 375 } 376 conv = "0123456789abcdef"; 377 grouping = "\4"; /* for hex, octal etc. (undefined by spec but nice) */ 378 thousands = f->thousands; 379 switch(f->r){ 380 case 'd': 381 case 'i': 382 case 'u': 383 base = 10; 384 grouping = f->grouping; 385 break; 386 case 'X': 387 conv = "0123456789ABCDEF"; 388 /* fall through */ 389 case 'x': 390 base = 16; 391 thousands = ":"; 392 break; 393 case 'b': 394 base = 2; 395 thousands = ":"; 396 break; 397 case 'o': 398 base = 8; 399 break; 400 default: 401 return -1; 402 } 403 if(!(fl & FmtUnsigned)){ 404 if(isv && (vlong)vu < 0){ 405 vu = -(vlong)vu; 406 neg = 1; 407 }else if(!isv && (long)u < 0){ 408 u = -(long)u; 409 neg = 1; 410 } 411 } 412 p = buf + sizeof buf - 1; 413 n = 0; /* in runes */ 414 excess = 0; /* number of bytes > number runes */ 415 ndig = 0; 416 len = utflen(thousands); 417 bytelen = strlen(thousands); 418 if(isv){ 419 while(vu){ 420 i = vu % base; 421 vu /= base; 422 if((fl & FmtComma) && n % 4 == 3){ 423 *p-- = ','; 424 n++; 425 } 426 if((fl & FmtApost) && __needsep(&ndig, &grouping)){ 427 n += len; 428 excess += bytelen - len; 429 p -= bytelen; 430 memmove(p+1, thousands, bytelen); 431 } 432 *p-- = conv[i]; 433 n++; 434 } 435 }else{ 436 while(u){ 437 i = u % base; 438 u /= base; 439 if((fl & FmtComma) && n % 4 == 3){ 440 *p-- = ','; 441 n++; 442 } 443 if((fl & FmtApost) && __needsep(&ndig, &grouping)){ 444 n += len; 445 excess += bytelen - len; 446 p -= bytelen; 447 memmove(p+1, thousands, bytelen); 448 } 449 *p-- = conv[i]; 450 n++; 451 } 452 } 453 if(n == 0){ 454 /* 455 * "The result of converting a zero value with 456 * a precision of zero is no characters." - ANSI 457 * 458 * "For o conversion, # increases the precision, if and only if 459 * necessary, to force the first digit of the result to be a zero 460 * (if the value and precision are both 0, a single 0 is printed)." - ANSI 461 */ 462 if(!(fl & FmtPrec) || f->prec != 0 || (f->r == 'o' && (fl & FmtSharp))){ 463 *p-- = '0'; 464 n = 1; 465 if(fl & FmtApost) 466 __needsep(&ndig, &grouping); 467 } 468 469 /* 470 * Zero values don't get 0x. 471 */ 472 if(f->r == 'x' || f->r == 'X') 473 fl &= ~FmtSharp; 474 } 475 for(w = f->prec; n < w && p > buf+3; n++){ 476 if((fl & FmtApost) && __needsep(&ndig, &grouping)){ 477 n += len; 478 excess += bytelen - len; 479 p -= bytelen; 480 memmove(p+1, thousands, bytelen); 481 } 482 *p-- = '0'; 483 } 484 if(neg || (fl & (FmtSign|FmtSpace))) 485 n++; 486 if(fl & FmtSharp){ 487 if(base == 16) 488 n += 2; 489 else if(base == 8){ 490 if(p[1] == '0') 491 fl &= ~FmtSharp; 492 else 493 n++; 494 } 495 } 496 if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){ 497 w = 0; 498 if(fl & FmtWidth) 499 w = f->width; 500 for(; n < w && p > buf+3; n++){ 501 if((fl & FmtApost) && __needsep(&ndig, &grouping)){ 502 n += len; 503 excess += bytelen - len; 504 p -= bytelen; 505 memmove(p+1, thousands, bytelen); 506 } 507 *p-- = '0'; 508 } 509 f->flags &= ~FmtWidth; 510 } 511 if(fl & FmtSharp){ 512 if(base == 16) 513 *p-- = f->r; 514 if(base == 16 || base == 8) 515 *p-- = '0'; 516 } 517 if(neg) 518 *p-- = '-'; 519 else if(fl & FmtSign) 520 *p-- = '+'; 521 else if(fl & FmtSpace) 522 *p-- = ' '; 523 f->flags &= ~FmtPrec; 524 return __fmtcpy(f, p + 1, n, n + excess); 525 } 526 527 int 528 __countfmt(Fmt *f) 529 { 530 void *p; 531 ulong fl; 532 533 fl = f->flags; 534 p = va_arg(f->args, void*); 535 if(fl & FmtVLong){ 536 *(vlong*)p = f->nfmt; 537 }else if(fl & FmtLong){ 538 *(long*)p = f->nfmt; 539 }else if(fl & FmtByte){ 540 *(char*)p = f->nfmt; 541 }else if(fl & FmtShort){ 542 *(short*)p = f->nfmt; 543 }else{ 544 *(int*)p = f->nfmt; 545 } 546 return 0; 547 } 548 549 int 550 __flagfmt(Fmt *f) 551 { 552 switch(f->r){ 553 case ',': 554 f->flags |= FmtComma; 555 break; 556 case '-': 557 f->flags |= FmtLeft; 558 break; 559 case '+': 560 f->flags |= FmtSign; 561 break; 562 case '#': 563 f->flags |= FmtSharp; 564 break; 565 case '\'': 566 f->flags |= FmtApost; 567 break; 568 case ' ': 569 f->flags |= FmtSpace; 570 break; 571 case 'u': 572 f->flags |= FmtUnsigned; 573 break; 574 case 'h': 575 if(f->flags & FmtShort) 576 f->flags |= FmtByte; 577 f->flags |= FmtShort; 578 break; 579 case 'L': 580 f->flags |= FmtLDouble; 581 break; 582 case 'l': 583 if(f->flags & FmtLong) 584 f->flags |= FmtVLong; 585 f->flags |= FmtLong; 586 break; 587 } 588 return 1; 589 } 590 591 /* default error format */ 592 int 593 __badfmt(Fmt *f) 594 { 595 char x[2+UTFmax]; 596 int n; 597 598 x[0] = '%'; 599 n = 1 + runetochar(x+1, &f->r); 600 x[n++] = '%'; 601 f->prec = n; 602 __fmtcpy(f, (const void*)x, n, n); 603 return 0; 604 }