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 u = (ulong)va_arg(f->args, void*); 337 f->r = 'x'; 338 fl |= FmtUnsigned; 339 }else if(fl & FmtVLong){ 340 isv = 1; 341 if(fl & FmtUnsigned) 342 vu = va_arg(f->args, uvlong); 343 else 344 vu = va_arg(f->args, vlong); 345 }else if(fl & FmtLong){ 346 if(fl & FmtUnsigned) 347 u = va_arg(f->args, ulong); 348 else 349 u = va_arg(f->args, long); 350 }else if(fl & FmtByte){ 351 if(fl & FmtUnsigned) 352 u = (uchar)va_arg(f->args, int); 353 else 354 u = (char)va_arg(f->args, int); 355 }else if(fl & FmtShort){ 356 if(fl & FmtUnsigned) 357 u = (ushort)va_arg(f->args, int); 358 else 359 u = (short)va_arg(f->args, int); 360 }else{ 361 if(fl & FmtUnsigned) 362 u = va_arg(f->args, uint); 363 else 364 u = va_arg(f->args, int); 365 } 366 conv = "0123456789abcdef"; 367 switch(f->r){ 368 case 'd': 369 case 'i': 370 case 'u': 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|FmtPrec))){ 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 f->flags |= FmtLDouble; 513 break; 514 case 'l': 515 if(f->flags & FmtLong) 516 f->flags |= FmtVLong; 517 f->flags |= FmtLong; 518 break; 519 } 520 return 1; 521 } 522 523 /* default error format */ 524 int 525 __badfmt(Fmt *f) 526 { 527 char x[3]; 528 529 x[0] = '%'; 530 x[1] = f->r; 531 x[2] = '%'; 532 f->prec = 3; 533 __fmtcpy(f, (const void*)x, 3, 3); 534 return 0; 535 } 536