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