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 = (Rune*)f->to; 18 rs = (Rune*)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 = (char*)f->to; 36 s = (char*)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 = (char*)__fmtflush(f, t, n); 45 if(t != nil) 46 s = (char*)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 = (char*)__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 = (char*)f->to; 94 s = (char*)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 = (Rune*)f->to; 109 s = (Rune*)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, const 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 = (char*)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 = (Rune*)f->to; 135 rs = (Rune*)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 = (char*)f->to; 154 s = (char*)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, const 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 = (Rune*)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 = (Rune*)f->to; 190 rs = (Rune*)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 = (char*)f->to; 201 s = (char*)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, (const char*)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, (const void*)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, (const void*)x, 1); 306 } 307 308 /* fmt an integer */ 309 int 310 __ifmt(Fmt *f) 311 { 312 char buf[70], *p, *conv; 313 uvlong vu; 314 ulong u; 315 int neg, base, i, n, fl, w, isv; 316 317 neg = 0; 318 fl = f->flags; 319 isv = 0; 320 vu = 0; 321 u = 0; 322 /* 323 * Unsigned verbs for ANSI C 324 */ 325 switch(f->r){ 326 case 'x': 327 case 'X': 328 case 'o': 329 case 'u': 330 case 'p': 331 fl |= FmtUnsigned; 332 fl &= ~(FmtSign|FmtSpace); 333 break; 334 } 335 if(f->r == 'p'){ 336 if(sizeof(void*) == sizeof(uvlong)){ 337 isv = 1; 338 vu = (uvlong)va_arg(f->args, uvlong); 339 }else 340 u = (ulong)va_arg(f->args, ulong); 341 f->r = 'x'; 342 fl |= FmtUnsigned; 343 }else if(fl & FmtVLong){ 344 isv = 1; 345 if(fl & FmtUnsigned) 346 vu = va_arg(f->args, uvlong); 347 else 348 vu = va_arg(f->args, vlong); 349 }else if(fl & FmtLong){ 350 if(fl & FmtUnsigned) 351 u = va_arg(f->args, ulong); 352 else 353 u = va_arg(f->args, long); 354 }else if(fl & FmtByte){ 355 if(fl & FmtUnsigned) 356 u = (uchar)va_arg(f->args, int); 357 else 358 u = (char)va_arg(f->args, int); 359 }else if(fl & FmtShort){ 360 if(fl & FmtUnsigned) 361 u = (ushort)va_arg(f->args, int); 362 else 363 u = (short)va_arg(f->args, int); 364 }else{ 365 if(fl & FmtUnsigned) 366 u = va_arg(f->args, uint); 367 else 368 u = va_arg(f->args, int); 369 } 370 conv = "0123456789abcdef"; 371 switch(f->r){ 372 case 'd': 373 case 'i': 374 case 'u': 375 base = 10; 376 break; 377 case 'x': 378 base = 16; 379 break; 380 case 'X': 381 base = 16; 382 conv = "0123456789ABCDEF"; 383 break; 384 case 'b': 385 base = 2; 386 break; 387 case 'o': 388 base = 8; 389 break; 390 default: 391 return -1; 392 } 393 if(!(fl & FmtUnsigned)){ 394 if(isv && (vlong)vu < 0){ 395 vu = -(vlong)vu; 396 neg = 1; 397 }else if(!isv && (long)u < 0){ 398 u = -(long)u; 399 neg = 1; 400 } 401 } 402 p = buf + sizeof buf - 1; 403 n = 0; 404 if(isv){ 405 while(vu){ 406 i = vu % base; 407 vu /= base; 408 if((fl & FmtComma) && n % 4 == 3){ 409 *p-- = ','; 410 n++; 411 } 412 *p-- = conv[i]; 413 n++; 414 } 415 }else{ 416 while(u){ 417 i = u % base; 418 u /= base; 419 if((fl & FmtComma) && n % 4 == 3){ 420 *p-- = ','; 421 n++; 422 } 423 *p-- = conv[i]; 424 n++; 425 } 426 } 427 if(n == 0){ 428 *p-- = '0'; 429 n = 1; 430 } 431 for(w = f->prec; n < w && p > buf+3; n++) 432 *p-- = '0'; 433 if(neg || (fl & (FmtSign|FmtSpace))) 434 n++; 435 if(fl & FmtSharp){ 436 if(base == 16) 437 n += 2; 438 else if(base == 8){ 439 if(p[1] == '0') 440 fl &= ~FmtSharp; 441 else 442 n++; 443 } 444 } 445 if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){ 446 for(w = f->width; n < w && p > buf+3; n++) 447 *p-- = '0'; 448 f->width = 0; 449 } 450 if(fl & FmtSharp){ 451 if(base == 16) 452 *p-- = f->r; 453 if(base == 16 || base == 8) 454 *p-- = '0'; 455 } 456 if(neg) 457 *p-- = '-'; 458 else if(fl & FmtSign) 459 *p-- = '+'; 460 else if(fl & FmtSpace) 461 *p-- = ' '; 462 f->flags &= ~FmtPrec; 463 return __fmtcpy(f, p + 1, n, n); 464 } 465 466 int 467 __countfmt(Fmt *f) 468 { 469 void *p; 470 ulong fl; 471 472 fl = f->flags; 473 p = va_arg(f->args, void*); 474 if(fl & FmtVLong){ 475 *(vlong*)p = f->nfmt; 476 }else if(fl & FmtLong){ 477 *(long*)p = f->nfmt; 478 }else if(fl & FmtByte){ 479 *(char*)p = f->nfmt; 480 }else if(fl & FmtShort){ 481 *(short*)p = f->nfmt; 482 }else{ 483 *(int*)p = f->nfmt; 484 } 485 return 0; 486 } 487 488 int 489 __flagfmt(Fmt *f) 490 { 491 switch(f->r){ 492 case ',': 493 f->flags |= FmtComma; 494 break; 495 case '-': 496 f->flags |= FmtLeft; 497 break; 498 case '+': 499 f->flags |= FmtSign; 500 break; 501 case '#': 502 f->flags |= FmtSharp; 503 break; 504 case ' ': 505 f->flags |= FmtSpace; 506 break; 507 case 'u': 508 f->flags |= FmtUnsigned; 509 break; 510 case 'h': 511 if(f->flags & FmtShort) 512 f->flags |= FmtByte; 513 f->flags |= FmtShort; 514 break; 515 case 'L': 516 f->flags |= FmtLDouble; 517 break; 518 case 'l': 519 if(f->flags & FmtLong) 520 f->flags |= FmtVLong; 521 f->flags |= FmtLong; 522 break; 523 } 524 return 1; 525 } 526 527 /* default error format */ 528 int 529 __badfmt(Fmt *f) 530 { 531 char x[3]; 532 533 x[0] = '%'; 534 x[1] = f->r; 535 x[2] = '%'; 536 f->prec = 3; 537 __fmtcpy(f, (const void*)x, 3, 3); 538 return 0; 539 } 540