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 "lib9.h" 15 #include "fmtdef.h" 16 17 /* format the output into f->to and return the number of characters fmted */ 18 int 19 dofmt(Fmt *f, char *fmt) 20 { 21 Rune rune, *rt, *rs; 22 int r; 23 char *t, *s; 24 int n, nfmt; 25 26 nfmt = f->nfmt; 27 for(;;){ 28 if(f->runes){ 29 rt = f->to; 30 rs = f->stop; 31 while((r = *(uchar*)fmt) && r != '%'){ 32 if(r < Runeself) 33 fmt++; 34 else{ 35 fmt += chartorune(&rune, fmt); 36 r = rune; 37 } 38 FMTRCHAR(f, rt, rs, r); 39 } 40 fmt++; 41 f->nfmt += rt - (Rune *)f->to; 42 f->to = rt; 43 if(!r) 44 return f->nfmt - nfmt; 45 f->stop = rs; 46 }else{ 47 t = f->to; 48 s = f->stop; 49 while((r = *(uchar*)fmt) && r != '%'){ 50 if(r < Runeself){ 51 FMTCHAR(f, t, s, r); 52 fmt++; 53 }else{ 54 n = chartorune(&rune, fmt); 55 if(t + n > s){ 56 t = _fmtflush(f, t, n); 57 if(t != nil) 58 s = f->stop; 59 else 60 return -1; 61 } 62 while(n--) 63 *t++ = *fmt++; 64 } 65 } 66 fmt++; 67 f->nfmt += t - (char *)f->to; 68 f->to = t; 69 if(!r) 70 return f->nfmt - nfmt; 71 f->stop = s; 72 } 73 74 fmt = _fmtdispatch(f, fmt, 0); 75 if(fmt == nil) 76 return -1; 77 } 78 return 0; /* not reached */ 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 = f->to; 107 s = 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 = f->to; 122 s = 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, 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 = 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 = f->to; 148 rs = 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(m < me) 162 return -1; 163 if(fl & FmtLeft && _rfmtpad(f, w - n) < 0) 164 return -1; 165 }else{ 166 if(!(fl & FmtLeft) && _fmtpad(f, w - n) < 0) 167 return -1; 168 t = f->to; 169 s = f->stop; 170 for(nc = n; nc > 0; nc--){ 171 r = *(uchar*)m; 172 if(r < Runeself) 173 m++; 174 else if((me - m) >= UTFmax || fullrune(m, me-m)) 175 m += chartorune(&r, m); 176 else 177 break; 178 FMTRUNE(f, t, s, r); 179 } 180 f->nfmt += t - (char *)f->to; 181 f->to = t; 182 if(fl & FmtLeft && _fmtpad(f, w - n) < 0) 183 return -1; 184 } 185 return 0; 186 } 187 188 int 189 _fmtrcpy(Fmt *f, void *vm, int n) 190 { 191 Rune r, *m, *me, *rt, *rs; 192 char *t, *s; 193 ulong fl; 194 int w; 195 196 m = vm; 197 w = f->width; 198 fl = f->flags; 199 if((fl & FmtPrec) && n > f->prec) 200 n = f->prec; 201 if(f->runes){ 202 if(!(fl & FmtLeft) && _rfmtpad(f, w - n) < 0) 203 return -1; 204 rt = f->to; 205 rs = f->stop; 206 for(me = m + n; m < me; m++) 207 FMTRCHAR(f, rt, rs, *m); 208 f->nfmt += rt - (Rune *)f->to; 209 f->to = rt; 210 if(fl & FmtLeft && _rfmtpad(f, w - n) < 0) 211 return -1; 212 }else{ 213 if(!(fl & FmtLeft) && _fmtpad(f, w - n) < 0) 214 return -1; 215 t = f->to; 216 s = f->stop; 217 for(me = m + n; m < me; m++){ 218 r = *m; 219 FMTRUNE(f, t, s, r); 220 } 221 f->nfmt += t - (char *)f->to; 222 f->to = t; 223 if(fl & FmtLeft && _fmtpad(f, w - n) < 0) 224 return -1; 225 } 226 return 0; 227 } 228 229 /* fmt out one character */ 230 int 231 _charfmt(Fmt *f) 232 { 233 char x[1]; 234 235 x[0] = va_arg(f->args, int); 236 f->prec = 1; 237 return _fmtcpy(f, x, 1, 1); 238 } 239 240 /* fmt out one rune */ 241 int 242 _runefmt(Fmt *f) 243 { 244 Rune x[1]; 245 246 x[0] = va_arg(f->args, int); 247 return _fmtrcpy(f, x, 1); 248 } 249 250 /* public helper routine: fmt out a null terminated string already in hand */ 251 int 252 fmtstrcpy(Fmt *f, char *s) 253 { 254 int p, i; 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 p = f->prec; 260 for(i = 0; i < p; i++) 261 if(s[i] == 0) 262 break; 263 return _fmtcpy(f, s, utfnlen(s, i), i); /* BUG?: won't print a partial rune at end */ 264 } 265 266 return _fmtcpy(f, s, utflen(s), strlen(s)); 267 } 268 269 /* fmt out a null terminated utf string */ 270 int 271 _strfmt(Fmt *f) 272 { 273 char *s; 274 275 s = va_arg(f->args, char *); 276 return fmtstrcpy(f, s); 277 } 278 279 /* public helper routine: fmt out a null terminated rune string already in hand */ 280 int 281 fmtrunestrcpy(Fmt *f, Rune *s) 282 { 283 Rune *e; 284 int n, p; 285 286 if(!s) 287 return _fmtcpy(f, "<nil>", 5, 5); 288 /* if precision is specified, make sure we don't wander off the end */ 289 if(f->flags & FmtPrec){ 290 p = f->prec; 291 for(n = 0; n < p; n++) 292 if(s[n] == 0) 293 break; 294 }else{ 295 for(e = s; *e; e++) 296 ; 297 n = e - s; 298 } 299 return _fmtrcpy(f, s, n); 300 } 301 302 /* fmt out a null terminated rune string */ 303 int 304 _runesfmt(Fmt *f) 305 { 306 Rune *s; 307 308 s = va_arg(f->args, Rune *); 309 return fmtrunestrcpy(f, s); 310 } 311 312 /* fmt a % */ 313 int 314 _percentfmt(Fmt *f) 315 { 316 Rune x[1]; 317 318 x[0] = f->r; 319 f->prec = 1; 320 return _fmtrcpy(f, x, 1); 321 } 322 323 /* fmt an integer */ 324 int 325 _ifmt(Fmt *f) 326 { 327 char buf[70], *p, *conv; 328 uvlong vu; 329 ulong u; 330 int neg, base, i, n, fl, w, isv; 331 332 neg = 0; 333 fl = f->flags; 334 isv = 0; 335 vu = 0; 336 u = 0; 337 if(f->r == 'p'){ 338 u = (ulong)va_arg(f->args, void*); 339 f->r = 'x'; 340 fl |= FmtUnsigned; 341 }else if(fl & FmtVLong){ 342 isv = 1; 343 if(fl & FmtUnsigned) 344 vu = va_arg(f->args, uvlong); 345 else 346 vu = va_arg(f->args, vlong); 347 }else if(fl & FmtLong){ 348 if(fl & FmtUnsigned) 349 u = va_arg(f->args, ulong); 350 else 351 u = va_arg(f->args, long); 352 }else if(fl & FmtByte){ 353 if(fl & FmtUnsigned) 354 u = (uchar)va_arg(f->args, int); 355 else 356 u = (char)va_arg(f->args, int); 357 }else if(fl & FmtShort){ 358 if(fl & FmtUnsigned) 359 u = (ushort)va_arg(f->args, int); 360 else 361 u = (short)va_arg(f->args, int); 362 }else{ 363 if(fl & FmtUnsigned) 364 u = va_arg(f->args, uint); 365 else 366 u = va_arg(f->args, int); 367 } 368 conv = "0123456789abcdef"; 369 switch(f->r){ 370 case 'd': 371 base = 10; 372 break; 373 case 'x': 374 base = 16; 375 break; 376 case 'X': 377 base = 16; 378 conv = "0123456789ABCDEF"; 379 break; 380 case 'b': 381 base = 2; 382 break; 383 case 'o': 384 base = 8; 385 break; 386 default: 387 return -1; 388 } 389 if(!(fl & FmtUnsigned)){ 390 if(isv && (vlong)vu < 0){ 391 vu = -(vlong)vu; 392 neg = 1; 393 }else if(!isv && (long)u < 0){ 394 u = -(long)u; 395 neg = 1; 396 } 397 } 398 p = buf + sizeof buf - 1; 399 n = 0; 400 if(isv){ 401 while(vu){ 402 i = vu % base; 403 vu /= base; 404 if((fl & FmtComma) && n % 4 == 3){ 405 *p-- = ','; 406 n++; 407 } 408 *p-- = conv[i]; 409 n++; 410 } 411 }else{ 412 while(u){ 413 i = u % base; 414 u /= base; 415 if((fl & FmtComma) && n % 4 == 3){ 416 *p-- = ','; 417 n++; 418 } 419 *p-- = conv[i]; 420 n++; 421 } 422 } 423 if(n == 0){ 424 *p-- = '0'; 425 n = 1; 426 } 427 for(w = f->prec; n < w && p > buf+3; n++) 428 *p-- = '0'; 429 if(neg || (fl & (FmtSign|FmtSpace))) 430 n++; 431 if(fl & FmtSharp){ 432 if(base == 16) 433 n += 2; 434 else if(base == 8){ 435 if(p[1] == '0') 436 fl &= ~FmtSharp; 437 else 438 n++; 439 } 440 } 441 if((fl & FmtZero) && !(fl & FmtLeft)){ 442 for(w = f->width; n < w && p > buf+3; n++) 443 *p-- = '0'; 444 f->width = 0; 445 } 446 if(fl & FmtSharp){ 447 if(base == 16) 448 *p-- = f->r; 449 if(base == 16 || base == 8) 450 *p-- = '0'; 451 } 452 if(neg) 453 *p-- = '-'; 454 else if(fl & FmtSign) 455 *p-- = '+'; 456 else if(fl & FmtSpace) 457 *p-- = ' '; 458 f->flags &= ~FmtPrec; 459 return _fmtcpy(f, p + 1, n, n); 460 } 461 462 int 463 _countfmt(Fmt *f) 464 { 465 void *p; 466 ulong fl; 467 468 fl = f->flags; 469 p = va_arg(f->args, void*); 470 if(fl & FmtVLong){ 471 *(vlong*)p = f->nfmt; 472 }else if(fl & FmtLong){ 473 *(long*)p = f->nfmt; 474 }else if(fl & FmtByte){ 475 *(char*)p = f->nfmt; 476 }else if(fl & FmtShort){ 477 *(short*)p = f->nfmt; 478 }else{ 479 *(int*)p = f->nfmt; 480 } 481 return 0; 482 } 483 484 int 485 _flagfmt(Fmt *f) 486 { 487 switch(f->r){ 488 case ',': 489 f->flags |= FmtComma; 490 break; 491 case '-': 492 f->flags |= FmtLeft; 493 break; 494 case '+': 495 f->flags |= FmtSign; 496 break; 497 case '#': 498 f->flags |= FmtSharp; 499 break; 500 case ' ': 501 f->flags |= FmtSpace; 502 break; 503 case 'u': 504 f->flags |= FmtUnsigned; 505 break; 506 case 'h': 507 if(f->flags & FmtShort) 508 f->flags |= FmtByte; 509 f->flags |= FmtShort; 510 break; 511 case 'l': 512 if(f->flags & FmtLong) 513 f->flags |= FmtVLong; 514 f->flags |= FmtLong; 515 break; 516 } 517 return 1; 518 } 519 520 /* default error format */ 521 int 522 _badfmt(Fmt *f) 523 { 524 char x[3]; 525 526 x[0] = '%'; 527 x[1] = f->r; 528 x[2] = '%'; 529 f->prec = 3; 530 _fmtcpy(f, x, 3, 3); 531 return 0; 532 } 533