1 #include "u.h" 2 #include "../port/lib.h" 3 4 enum 5 { 6 SIZE = 1024, 7 IDIGIT = 30, 8 MAXCONV = 40, 9 FDIGIT = 30, 10 FDEFLT = 6, 11 NONE = -1000, 12 MAXFMT = 512, 13 14 FPLUS = (1<<0), 15 FMINUS = (1<<1), 16 FSHARP = (1<<2), 17 FLONG = (1<<3), 18 FSHORT = (1<<4), 19 FUNSIGN = (1<<5), 20 FVLONG = (1<<6), 21 }; 22 23 #define PTR sizeof(char*) 24 #define SHORT sizeof(int) 25 #define INT sizeof(int) 26 #define LONG sizeof(long) 27 #define VLONG sizeof(vlong) 28 29 int printcol; 30 31 static int convcount; 32 static char fmtindex[MAXFMT]; 33 34 static int noconv(void*, Fconv*); 35 static int flags(void*, Fconv*); 36 37 static int cconv(void*, Fconv*); 38 static int sconv(void*, Fconv*); 39 static int percent(void*, Fconv*); 40 41 int numbconv(void*, Fconv*); 42 43 static 44 int (*fmtconv[MAXCONV])(void*, Fconv*) = 45 { 46 noconv 47 }; 48 49 static 50 void 51 initfmt(void) 52 { 53 int cc; 54 55 cc = 0; 56 fmtconv[cc] = noconv; 57 cc++; 58 59 fmtconv[cc] = flags; 60 fmtindex['+'] = cc; 61 fmtindex['-'] = cc; 62 fmtindex['#'] = cc; 63 fmtindex['h'] = cc; 64 fmtindex['l'] = cc; 65 fmtindex['u'] = cc; 66 cc++; 67 68 fmtconv[cc] = numbconv; 69 fmtindex['d'] = cc; 70 fmtindex['o'] = cc; 71 fmtindex['x'] = cc; 72 fmtindex['X'] = cc; 73 cc++; 74 75 fmtconv[cc] = cconv; 76 fmtindex['c'] = cc; 77 fmtindex['C'] = cc; 78 cc++; 79 80 fmtconv[cc] = sconv; 81 fmtindex['s'] = cc; 82 fmtindex['S'] = cc; 83 cc++; 84 85 fmtconv[cc] = percent; 86 fmtindex['%'] = cc; 87 cc++; 88 89 convcount = cc; 90 } 91 92 int 93 fmtinstall(int c, int (*f)(void*, Fconv*)) 94 { 95 96 if(convcount == 0) 97 initfmt(); 98 if(c < 0 || c >= MAXFMT) 99 return 1; 100 if(convcount >= MAXCONV) 101 return 1; 102 fmtconv[convcount] = f; 103 fmtindex[c] = convcount; 104 convcount++; 105 return 0; 106 } 107 108 char* 109 doprint(char *s, char *es, char *fmt, void *argp) 110 { 111 int n, c; 112 Rune rune; 113 Fconv local; 114 115 local.out = s; 116 local.eout = es-4; /* room for multi-byte character and 0 */ 117 118 loop: 119 c = *fmt & 0xff; 120 if(c >= Runeself) { 121 n = chartorune(&rune, fmt); 122 fmt += n; 123 c = rune; 124 } else 125 fmt++; 126 switch(c) { 127 case 0: 128 *local.out = 0; 129 return local.out; 130 131 default: 132 printcol++; 133 goto common; 134 135 case '\n': 136 printcol = 0; 137 goto common; 138 139 case '\t': 140 printcol = (printcol+8) & ~7; 141 goto common; 142 143 common: 144 if(local.out < local.eout) 145 if(c >= Runeself) { 146 rune = c; 147 n = runetochar(local.out, &rune); /* BUG */ 148 local.out += n; 149 } else 150 *local.out++ = c; 151 goto loop; 152 153 case '%': 154 break; 155 } 156 local.f1 = NONE; 157 local.f2 = NONE; 158 local.f3 = 0; 159 160 /* 161 * read one of the following 162 * 1. number, => f1, f2 in order. 163 * 2. '*' same as number (from args) 164 * 3. '.' ignored (separates numbers) 165 * 4. flag => f3 166 * 5. verb and terminate 167 */ 168 l0: 169 c = *fmt & 0xff; 170 if(c >= Runeself) { 171 n = chartorune(&rune, fmt); 172 fmt += n; 173 c = rune; 174 } else 175 fmt++; 176 177 l1: 178 if(c == 0) { 179 fmt--; 180 goto loop; 181 } 182 if(c == '.') { 183 if(local.f1 == NONE) 184 local.f1 = 0; 185 local.f2 = 0; 186 goto l0; 187 } 188 if((c >= '1' && c <= '9') || 189 (c == '0' && local.f1 != NONE)) { /* '0' is a digit for f2 */ 190 n = 0; 191 while(c >= '0' && c <= '9') { 192 n = n*10 + c-'0'; 193 c = *fmt++; 194 } 195 if(local.f1 == NONE) 196 local.f1 = n; 197 else 198 local.f2 = n; 199 goto l1; 200 } 201 if(c == '*') { 202 n = *(int*)argp; 203 argp = (char*)argp + INT; 204 if(local.f1 == NONE) 205 local.f1 = n; 206 else 207 local.f2 = n; 208 goto l0; 209 } 210 n = 0; 211 if(c >= 0 && c < MAXFMT) 212 n = fmtindex[c]; 213 local.chr = c; 214 n = (*fmtconv[n])(argp, &local); 215 if(n < 0) { 216 local.f3 |= -n; 217 goto l0; 218 } 219 argp = (char*)argp + n; 220 goto loop; 221 } 222 223 int 224 numbconv(void *o, Fconv *fp) 225 { 226 char s[IDIGIT]; 227 int i, f, n, r, b, ucase; 228 short h; 229 long v; 230 vlong vl; 231 232 SET(v); 233 SET(vl); 234 235 ucase = 0; 236 b = fp->chr; 237 switch(fp->chr) { 238 case 'u': 239 fp->f3 |= FUNSIGN; 240 case 'd': 241 b = 10; 242 break; 243 244 case 'o': 245 b = 8; 246 break; 247 248 case 'X': 249 ucase = 1; 250 case 'x': 251 b = 16; 252 break; 253 } 254 255 f = 0; 256 switch(fp->f3 & (FVLONG|FLONG|FSHORT|FUNSIGN)) { 257 case FVLONG|FLONG: 258 vl = *(vlong*)o; 259 r = VLONG; 260 break; 261 262 case FLONG: 263 v = *(long*)o; 264 r = LONG; 265 break; 266 267 case FUNSIGN|FLONG: 268 v = *(ulong*)o; 269 r = LONG; 270 break; 271 272 case FSHORT: 273 h = *(int*)o; 274 v = h; 275 r = SHORT; 276 break; 277 278 case FUNSIGN|FSHORT: 279 h = *(int*)o; 280 v = (ushort)h; 281 r = SHORT; 282 break; 283 284 default: 285 v = *(int*)o; 286 r = INT; 287 break; 288 289 case FUNSIGN: 290 v = *(unsigned*)o; 291 r = INT; 292 break; 293 } 294 if(!(fp->f3 & FUNSIGN) && v < 0) { 295 v = -v; 296 f = 1; 297 } 298 s[IDIGIT-1] = 0; 299 for(i = IDIGIT-2;; i--) { 300 if(fp->f3 & FVLONG) 301 n = vl % b; 302 else 303 n = (ulong)v % b; 304 n += '0'; 305 if(n > '9') { 306 n += 'a' - ('9'+1); 307 if(ucase) 308 n += 'A'-'a'; 309 } 310 s[i] = n; 311 if(i < 2) 312 break; 313 if(fp->f3 & FVLONG) 314 vl = vl / b; 315 else 316 v = (ulong)v / b; 317 if(fp->f2 != NONE && i >= IDIGIT-fp->f2) 318 continue; 319 if(fp->f3 & FVLONG) 320 if(vl <= 0) 321 break; 322 if(v <= 0) 323 break; 324 } 325 if(fp->f3 & FSHARP) 326 if(s[i] != '0') { 327 if(b == 8) 328 s[--i] = '0'; 329 else 330 if(b == 16) { 331 if(ucase) 332 s[--i] = 'X'; 333 else 334 s[--i] = 'x'; 335 s[--i] = '0'; 336 } 337 } 338 if(f) 339 s[--i] = '-'; 340 fp->f2 = NONE; 341 strconv(s+i, fp); 342 return r; 343 } 344 345 void 346 Strconv(Rune *s, Fconv *fp) 347 { 348 int n, c, i; 349 Rune rune; 350 351 if(fp->f3 & FMINUS) 352 fp->f1 = -fp->f1; 353 n = 0; 354 if(fp->f1 != NONE && fp->f1 >= 0) { 355 for(; s[n]; n++) 356 ; 357 while(n < fp->f1) { 358 if(fp->out < fp->eout) 359 *fp->out++ = ' '; 360 printcol++; 361 n++; 362 } 363 } 364 for(;;) { 365 c = *s++; 366 if(c == 0) 367 break; 368 n++; 369 if(fp->f2 == NONE || fp->f2 > 0) { 370 if(fp->out < fp->eout) 371 if(c >= Runeself) { 372 rune = c; 373 i = runetochar(fp->out, &rune); 374 fp->out += i; 375 } else 376 *fp->out++ = c; 377 if(fp->f2 != NONE) 378 fp->f2--; 379 switch(c) { 380 default: 381 printcol++; 382 break; 383 case '\n': 384 printcol = 0; 385 break; 386 case '\t': 387 printcol = (printcol+8) & ~7; 388 break; 389 } 390 } 391 } 392 if(fp->f1 != NONE && fp->f1 < 0) { 393 fp->f1 = -fp->f1; 394 while(n < fp->f1) { 395 if(fp->out < fp->eout) 396 *fp->out++ = ' '; 397 printcol++; 398 n++; 399 } 400 } 401 } 402 403 void 404 strconv(char *s, Fconv *fp) 405 { 406 int n, c, i; 407 Rune rune; 408 409 if(fp->f3 & FMINUS) 410 fp->f1 = -fp->f1; 411 n = 0; 412 if(fp->f1 != NONE && fp->f1 >= 0) { 413 n = utflen(s); 414 while(n < fp->f1) { 415 if(fp->out < fp->eout) 416 *fp->out++ = ' '; 417 printcol++; 418 n++; 419 } 420 } 421 for(;;) { 422 c = *s & 0xff; 423 if(c >= Runeself) { 424 i = chartorune(&rune, s); 425 s += i; 426 c = rune; 427 } else 428 s++; 429 if(c == 0) 430 break; 431 n++; 432 if(fp->f2 == NONE || fp->f2 > 0) { 433 if(fp->out < fp->eout) 434 if(c >= Runeself) { 435 rune = c; 436 i = runetochar(fp->out, &rune); 437 fp->out += i; 438 } else 439 *fp->out++ = c; 440 if(fp->f2 != NONE) 441 fp->f2--; 442 switch(c) { 443 default: 444 printcol++; 445 break; 446 case '\n': 447 printcol = 0; 448 break; 449 case '\t': 450 printcol = (printcol+8) & ~7; 451 break; 452 } 453 } 454 } 455 if(fp->f1 != NONE && fp->f1 < 0) { 456 fp->f1 = -fp->f1; 457 while(n < fp->f1) { 458 if(fp->out < fp->eout) 459 *fp->out++ = ' '; 460 printcol++; 461 n++; 462 } 463 } 464 } 465 466 static 467 int 468 noconv(void *o, Fconv *fp) 469 { 470 int n; 471 char s[10]; 472 473 if(convcount == 0) { 474 initfmt(); 475 n = 0; 476 if(fp->chr >= 0 && fp->chr < MAXFMT) 477 n = fmtindex[fp->chr]; 478 return (*fmtconv[n])(o, fp); 479 } 480 sprint(s, "*%c*", fp->chr); 481 fp->f1 = 0; 482 fp->f2 = NONE; 483 fp->f3 = 0; 484 strconv(s, fp); 485 return 0; 486 } 487 488 static 489 int 490 cconv(void *o, Fconv *fp) 491 { 492 char s[10]; 493 Rune rune; 494 495 rune = *(int*)o; 496 if(fp->chr == 'c') 497 rune &= 0xff; 498 s[runetochar(s, &rune)] = 0; 499 500 fp->f2 = NONE; 501 strconv(s, fp); 502 return INT; 503 } 504 505 static 506 int 507 sconv(void *o, Fconv *fp) 508 { 509 char *s; 510 Rune *r; 511 512 if(fp->chr == 's') { 513 s = *(char**)o; 514 if(s == 0) 515 s = "<null>"; 516 strconv(s, fp); 517 } else { 518 r = *(Rune**)o; 519 if(r == 0) 520 r = L"<null>"; 521 Strconv(r, fp); 522 } 523 return PTR; 524 } 525 526 static 527 int 528 percent(void *o, Fconv *fp) 529 { 530 531 USED(o); 532 if(fp->out < fp->eout) 533 *fp->out++ = '%'; 534 return 0; 535 } 536 537 static 538 int 539 flags(void *o, Fconv *fp) 540 { 541 int f; 542 543 USED(o); 544 545 f = 0; 546 switch(fp->chr) { 547 case '+': 548 f = FPLUS; 549 break; 550 551 case '-': 552 f = FMINUS; 553 break; 554 555 case '#': 556 f = FSHARP; 557 break; 558 559 case 'h': 560 f = FSHORT; 561 break; 562 563 case 'l': 564 f = FLONG; 565 if(fp->f3 & FLONG) 566 f = FVLONG; 567 break; 568 569 case 'u': 570 f = FUNSIGN; 571 break; 572 } 573 return -f; 574 } 575