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 <stdarg.h> 15 #include <string.h> 16 #include "utf.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, 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 return 0; /* not reached */ 82 } 83 84 void * 85 __fmtflush(Fmt *f, void *t, int len) 86 { 87 if(f->runes) 88 f->nfmt += (Rune*)t - (Rune*)f->to; 89 else 90 f->nfmt += (char*)t - (char *)f->to; 91 f->to = t; 92 if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){ 93 f->stop = f->to; 94 return nil; 95 } 96 return f->to; 97 } 98 99 /* 100 * put a formatted block of memory sz bytes long of n runes into the output buffer, 101 * left/right justified in a field of at least f->width charactes 102 */ 103 int 104 __fmtpad(Fmt *f, int n) 105 { 106 char *t, *s; 107 int i; 108 109 t = (char*)f->to; 110 s = (char*)f->stop; 111 for(i = 0; i < n; i++) 112 FMTCHAR(f, t, s, ' '); 113 f->nfmt += t - (char *)f->to; 114 f->to = t; 115 return 0; 116 } 117 118 int 119 __rfmtpad(Fmt *f, int n) 120 { 121 Rune *t, *s; 122 int i; 123 124 t = (Rune*)f->to; 125 s = (Rune*)f->stop; 126 for(i = 0; i < n; i++) 127 FMTRCHAR(f, t, s, ' '); 128 f->nfmt += t - (Rune *)f->to; 129 f->to = t; 130 return 0; 131 } 132 133 int 134 __fmtcpy(Fmt *f, const void *vm, int n, int sz) 135 { 136 Rune *rt, *rs, r; 137 char *t, *s, *m, *me; 138 ulong fl; 139 int nc, w; 140 141 m = (char*)vm; 142 me = m + sz; 143 w = f->width; 144 fl = f->flags; 145 if((fl & FmtPrec) && n > f->prec) 146 n = f->prec; 147 if(f->runes){ 148 if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0) 149 return -1; 150 rt = (Rune*)f->to; 151 rs = (Rune*)f->stop; 152 for(nc = n; nc > 0; nc--){ 153 r = *(uchar*)m; 154 if(r < Runeself) 155 m++; 156 else if((me - m) >= UTFmax || fullrune(m, me-m)) 157 m += chartorune(&r, m); 158 else 159 break; 160 FMTRCHAR(f, rt, rs, r); 161 } 162 f->nfmt += rt - (Rune *)f->to; 163 f->to = rt; 164 if(m < me) 165 return -1; 166 if(fl & FmtLeft && __rfmtpad(f, w - n) < 0) 167 return -1; 168 }else{ 169 if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0) 170 return -1; 171 t = (char*)f->to; 172 s = (char*)f->stop; 173 for(nc = n; nc > 0; nc--){ 174 r = *(uchar*)m; 175 if(r < Runeself) 176 m++; 177 else if((me - m) >= UTFmax || fullrune(m, me-m)) 178 m += chartorune(&r, m); 179 else 180 break; 181 FMTRUNE(f, t, s, r); 182 } 183 f->nfmt += t - (char *)f->to; 184 f->to = t; 185 if(fl & FmtLeft && __fmtpad(f, w - n) < 0) 186 return -1; 187 } 188 return 0; 189 } 190 191 int 192 __fmtrcpy(Fmt *f, const void *vm, int n) 193 { 194 Rune r, *m, *me, *rt, *rs; 195 char *t, *s; 196 ulong fl; 197 int w; 198 199 m = (Rune*)vm; 200 w = f->width; 201 fl = f->flags; 202 if((fl & FmtPrec) && n > f->prec) 203 n = f->prec; 204 if(f->runes){ 205 if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0) 206 return -1; 207 rt = (Rune*)f->to; 208 rs = (Rune*)f->stop; 209 for(me = m + n; m < me; m++) 210 FMTRCHAR(f, rt, rs, *m); 211 f->nfmt += rt - (Rune *)f->to; 212 f->to = rt; 213 if(fl & FmtLeft && __rfmtpad(f, w - n) < 0) 214 return -1; 215 }else{ 216 if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0) 217 return -1; 218 t = (char*)f->to; 219 s = (char*)f->stop; 220 for(me = m + n; m < me; m++){ 221 r = *m; 222 FMTRUNE(f, t, s, r); 223 } 224 f->nfmt += t - (char *)f->to; 225 f->to = t; 226 if(fl & FmtLeft && __fmtpad(f, w - n) < 0) 227 return -1; 228 } 229 return 0; 230 } 231 232 /* fmt out one character */ 233 int 234 __charfmt(Fmt *f) 235 { 236 char x[1]; 237 238 x[0] = va_arg(f->args, int); 239 f->prec = 1; 240 return __fmtcpy(f, (const char*)x, 1, 1); 241 } 242 243 /* fmt out one rune */ 244 int 245 __runefmt(Fmt *f) 246 { 247 Rune x[1]; 248 249 x[0] = va_arg(f->args, int); 250 return __fmtrcpy(f, (const void*)x, 1); 251 } 252 253 /* public helper routine: fmt out a null terminated string already in hand */ 254 int 255 fmtstrcpy(Fmt *f, char *s) 256 { 257 int p, i; 258 if(!s) 259 return __fmtcpy(f, "<nil>", 5, 5); 260 /* if precision is specified, make sure we don't wander off the end */ 261 if(f->flags & FmtPrec){ 262 p = f->prec; 263 for(i = 0; i < p; i++) 264 if(s[i] == 0) 265 break; 266 return __fmtcpy(f, s, utfnlen(s, i), i); /* BUG?: won't print a partial rune at end */ 267 } 268 269 return __fmtcpy(f, s, utflen(s), strlen(s)); 270 } 271 272 /* fmt out a null terminated utf string */ 273 int 274 __strfmt(Fmt *f) 275 { 276 char *s; 277 278 s = va_arg(f->args, char *); 279 return fmtstrcpy(f, s); 280 } 281 282 /* public helper routine: fmt out a null terminated rune string already in hand */ 283 int 284 fmtrunestrcpy(Fmt *f, Rune *s) 285 { 286 Rune *e; 287 int n, p; 288 289 if(!s) 290 return __fmtcpy(f, "<nil>", 5, 5); 291 /* if precision is specified, make sure we don't wander off the end */ 292 if(f->flags & FmtPrec){ 293 p = f->prec; 294 for(n = 0; n < p; n++) 295 if(s[n] == 0) 296 break; 297 }else{ 298 for(e = s; *e; e++) 299 ; 300 n = e - s; 301 } 302 return __fmtrcpy(f, s, n); 303 } 304 305 /* fmt out a null terminated rune string */ 306 int 307 __runesfmt(Fmt *f) 308 { 309 Rune *s; 310 311 s = va_arg(f->args, Rune *); 312 return fmtrunestrcpy(f, s); 313 } 314 315 /* fmt a % */ 316 int 317 __percentfmt(Fmt *f) 318 { 319 Rune x[1]; 320 321 x[0] = f->r; 322 f->prec = 1; 323 return __fmtrcpy(f, (const void*)x, 1); 324 } 325 326 /* fmt an integer */ 327 int 328 __ifmt(Fmt *f) 329 { 330 char buf[70], *p, *conv; 331 uvlong vu; 332 ulong u; 333 int neg, base, i, n, fl, w, isv; 334 335 neg = 0; 336 fl = f->flags; 337 isv = 0; 338 vu = 0; 339 u = 0; 340 /* 341 * Unsigned verbs 342 */ 343 switch(f->r){ 344 case 'o': 345 case 'u': 346 case 'x': 347 case 'X': 348 fl |= FmtUnsigned; 349 break; 350 } 351 if(f->r == 'p'){ 352 u = (ulong)va_arg(f->args, void*); 353 f->r = 'x'; 354 fl |= FmtUnsigned; 355 }else if(fl & FmtVLong){ 356 isv = 1; 357 if(fl & FmtUnsigned) 358 vu = va_arg(f->args, uvlong); 359 else 360 vu = va_arg(f->args, vlong); 361 }else if(fl & FmtLong){ 362 if(fl & FmtUnsigned) 363 u = va_arg(f->args, ulong); 364 else 365 u = va_arg(f->args, long); 366 }else if(fl & FmtByte){ 367 if(fl & FmtUnsigned) 368 u = (uchar)va_arg(f->args, int); 369 else 370 u = (char)va_arg(f->args, int); 371 }else if(fl & FmtShort){ 372 if(fl & FmtUnsigned) 373 u = (ushort)va_arg(f->args, int); 374 else 375 u = (short)va_arg(f->args, int); 376 }else{ 377 if(fl & FmtUnsigned) 378 u = va_arg(f->args, uint); 379 else 380 u = va_arg(f->args, int); 381 } 382 conv = "0123456789abcdef"; 383 switch(f->r){ 384 case 'd': 385 case 'i': 386 base = 10; 387 break; 388 case 'u': 389 base = 10; 390 break; 391 case 'x': 392 base = 16; 393 break; 394 case 'X': 395 base = 16; 396 conv = "0123456789ABCDEF"; 397 break; 398 case 'b': 399 base = 2; 400 break; 401 case 'o': 402 base = 8; 403 break; 404 default: 405 return -1; 406 } 407 if(!(fl & FmtUnsigned)){ 408 if(isv && (vlong)vu < 0){ 409 vu = -(vlong)vu; 410 neg = 1; 411 }else if(!isv && (long)u < 0){ 412 u = -(long)u; 413 neg = 1; 414 } 415 }else{ 416 fl &= ~(FmtSign|FmtSpace); /* no + for unsigned conversions */ 417 } 418 p = buf + sizeof buf - 1; 419 n = 0; 420 if(isv){ 421 while(vu){ 422 i = vu % base; 423 vu /= base; 424 if((fl & FmtComma) && n % 4 == 3){ 425 *p-- = ','; 426 n++; 427 } 428 *p-- = conv[i]; 429 n++; 430 } 431 }else{ 432 while(u){ 433 i = u % base; 434 u /= base; 435 if((fl & FmtComma) && n % 4 == 3){ 436 *p-- = ','; 437 n++; 438 } 439 *p-- = conv[i]; 440 n++; 441 } 442 } 443 if(n == 0){ 444 if(!(fl & FmtPrec) || f->prec != 0){ 445 *p-- = '0'; 446 n = 1; 447 } 448 fl &= ~FmtSharp; 449 } 450 for(w = f->prec; n < w && p > buf+3; n++) 451 *p-- = '0'; 452 if(neg || (fl & (FmtSign|FmtSpace))) 453 n++; 454 if(fl & FmtSharp){ 455 if(base == 16) 456 n += 2; 457 else if(base == 8){ 458 if(p[1] == '0') 459 fl &= ~FmtSharp; 460 else 461 n++; 462 } 463 } 464 if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){ 465 for(w = f->width; n < w && p > buf+3; n++) 466 *p-- = '0'; 467 f->width = 0; 468 } 469 if(fl & FmtSharp){ 470 if(base == 16) 471 *p-- = f->r; 472 if(base == 16 || base == 8) 473 *p-- = '0'; 474 } 475 if(neg) 476 *p-- = '-'; 477 else if(fl & FmtSign) 478 *p-- = '+'; 479 else if(fl & FmtSpace) 480 *p-- = ' '; 481 f->flags &= ~FmtPrec; 482 return __fmtcpy(f, p + 1, n, n); 483 } 484 485 int 486 __countfmt(Fmt *f) 487 { 488 void *p; 489 ulong fl; 490 491 fl = f->flags; 492 p = va_arg(f->args, void*); 493 if(fl & FmtVLong){ 494 *(vlong*)p = f->nfmt; 495 }else if(fl & FmtLong){ 496 *(long*)p = f->nfmt; 497 }else if(fl & FmtByte){ 498 *(char*)p = f->nfmt; 499 }else if(fl & FmtShort){ 500 *(short*)p = f->nfmt; 501 }else{ 502 *(int*)p = f->nfmt; 503 } 504 return 0; 505 } 506 507 int 508 __flagfmt(Fmt *f) 509 { 510 switch(f->r){ 511 case ',': 512 f->flags |= FmtComma; 513 break; 514 case '-': 515 f->flags |= FmtLeft; 516 break; 517 case '+': 518 f->flags |= FmtSign; 519 break; 520 case '#': 521 f->flags |= FmtSharp; 522 break; 523 case ' ': 524 f->flags |= FmtSpace; 525 break; 526 case 'u': 527 f->flags |= FmtUnsigned; 528 break; 529 case 'h': 530 if(f->flags & FmtShort) 531 f->flags |= FmtByte; 532 f->flags |= FmtShort; 533 break; 534 case 'L': 535 f->flags |= FmtLDouble; 536 break; 537 case 'l': 538 if(f->flags & FmtLong) 539 f->flags |= FmtVLong; 540 f->flags |= FmtLong; 541 break; 542 } 543 return 1; 544 } 545 546 /* default error format */ 547 int 548 __badfmt(Fmt *f) 549 { 550 char x[3]; 551 552 x[0] = '%'; 553 x[1] = f->r; 554 x[2] = '%'; 555 f->prec = 3; 556 __fmtcpy(f, (const void*)x, 3, 3); 557 return 0; 558 } 559