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