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