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