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