doprint.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832
  1. #include "lib9.h"
  2. enum
  3. {
  4. IDIGIT = 40,
  5. MAXCONV = 40,
  6. FDIGIT = 30,
  7. FDEFLT = 6,
  8. NONE = -1000,
  9. MAXFMT = 512,
  10. FPLUS = 1<<0,
  11. FMINUS = 1<<1,
  12. FSHARP = 1<<2,
  13. FLONG = 1<<3,
  14. FUNSIGN = 1<<5,
  15. FVLONG = 1<<6,
  16. FPOINTER= 1<<7
  17. };
  18. int printcol;
  19. static struct
  20. {
  21. Lock lk;
  22. int convcount;
  23. char index[MAXFMT];
  24. int (*conv[MAXCONV])(va_list*, Fconv*);
  25. } fmtalloc;
  26. static int noconv(va_list*, Fconv*);
  27. static int flags(va_list*, Fconv*);
  28. static int cconv(va_list*, Fconv*);
  29. static int rconv(va_list*, Fconv*);
  30. static int sconv(va_list*, Fconv*);
  31. static int percent(va_list*, Fconv*);
  32. static int column(va_list*, Fconv*);
  33. extern int numbconv(va_list*, Fconv*);
  34. extern int fltconv(va_list*, Fconv*);
  35. static void
  36. initfmt(void)
  37. {
  38. int cc;
  39. lock(&fmtalloc.lk);
  40. if(fmtalloc.convcount <= 0) {
  41. cc = 0;
  42. fmtalloc.conv[cc] = noconv;
  43. cc++;
  44. fmtalloc.conv[cc] = flags;
  45. fmtalloc.index['+'] = cc;
  46. fmtalloc.index['-'] = cc;
  47. fmtalloc.index['#'] = cc;
  48. fmtalloc.index['l'] = cc;
  49. fmtalloc.index['u'] = cc;
  50. cc++;
  51. fmtalloc.conv[cc] = numbconv;
  52. fmtalloc.index['d'] = cc;
  53. fmtalloc.index['o'] = cc;
  54. fmtalloc.index['x'] = cc;
  55. fmtalloc.index['X'] = cc;
  56. fmtalloc.index['p'] = cc;
  57. cc++;
  58. fmtalloc.conv[cc] = fltconv;
  59. fmtalloc.index['e'] = cc;
  60. fmtalloc.index['f'] = cc;
  61. fmtalloc.index['g'] = cc;
  62. fmtalloc.index['E'] = cc;
  63. fmtalloc.index['G'] = cc;
  64. cc++;
  65. fmtalloc.conv[cc] = cconv;
  66. fmtalloc.index['c'] = cc;
  67. fmtalloc.index['C'] = cc;
  68. cc++;
  69. fmtalloc.conv[cc] = rconv;
  70. fmtalloc.index['r'] = cc;
  71. cc++;
  72. fmtalloc.conv[cc] = sconv;
  73. fmtalloc.index['s'] = cc;
  74. fmtalloc.index['S'] = cc;
  75. cc++;
  76. fmtalloc.conv[cc] = percent;
  77. fmtalloc.index['%'] = cc;
  78. cc++;
  79. fmtalloc.conv[cc] = column;
  80. fmtalloc.index['|'] = cc;
  81. cc++;
  82. fmtalloc.convcount = cc;
  83. }
  84. unlock(&fmtalloc.lk);
  85. }
  86. int
  87. fmtinstall(int c, int (*f)(va_list*, Fconv*))
  88. {
  89. if(fmtalloc.convcount <= 0)
  90. initfmt();
  91. lock(&fmtalloc.lk);
  92. if(c < 0 || c >= MAXFMT) {
  93. unlock(&fmtalloc.lk);
  94. return -1;
  95. }
  96. if(fmtalloc.convcount >= MAXCONV) {
  97. unlock(&fmtalloc.lk);
  98. return -1;
  99. }
  100. fmtalloc.conv[fmtalloc.convcount] = f;
  101. fmtalloc.index[c] = fmtalloc.convcount;
  102. fmtalloc.convcount++;
  103. unlock(&fmtalloc.lk);
  104. return 0;
  105. }
  106. static void
  107. pchar(Rune c, Fconv *fp)
  108. {
  109. int n;
  110. n = fp->eout - fp->out;
  111. if(n > 0) {
  112. if(c < Runeself) {
  113. *fp->out++ = c;
  114. return;
  115. }
  116. if(n >= UTFmax || n >= runelen(c)) {
  117. n = runetochar(fp->out, &c);
  118. fp->out += n;
  119. return;
  120. }
  121. fp->eout = fp->out;
  122. }
  123. }
  124. char*
  125. doprint(char *s, char *es, char *fmt, va_list argp)
  126. {
  127. int n, c;
  128. Rune rune;
  129. Fconv local;
  130. if(fmtalloc.convcount <= 0)
  131. initfmt();
  132. if(s >= es)
  133. return s;
  134. local.out = s;
  135. local.eout = es-1;
  136. loop:
  137. c = *fmt & 0xff;
  138. if(c >= Runeself) {
  139. n = chartorune(&rune, fmt);
  140. fmt += n;
  141. c = rune;
  142. } else
  143. fmt++;
  144. switch(c) {
  145. case 0:
  146. *local.out = 0;
  147. return local.out;
  148. default:
  149. printcol++;
  150. goto common;
  151. case '\n':
  152. printcol = 0;
  153. goto common;
  154. case '\t':
  155. printcol = (printcol+8) & ~7;
  156. goto common;
  157. common:
  158. pchar(c, &local);
  159. goto loop;
  160. case '%':
  161. break;
  162. }
  163. local.f1 = NONE;
  164. local.f2 = NONE;
  165. local.f3 = 0;
  166. /*
  167. * read one of the following
  168. * 1. number, => f1, f2 in order.
  169. * 2. '*' same as number (from args)
  170. * 3. '.' ignored (separates numbers)
  171. * 4. flag => f3
  172. * 5. verb and terminate
  173. */
  174. l0:
  175. c = *fmt & 0xff;
  176. if(c >= Runeself) {
  177. n = chartorune(&rune, fmt);
  178. fmt += n;
  179. c = rune;
  180. } else
  181. fmt++;
  182. l1:
  183. if(c == 0) {
  184. fmt--;
  185. goto loop;
  186. }
  187. if(c == '.') {
  188. if(local.f1 == NONE)
  189. local.f1 = 0;
  190. local.f2 = 0;
  191. goto l0;
  192. }
  193. if((c >= '1' && c <= '9') ||
  194. (c == '0' && local.f1 != NONE)) { /* '0' is a digit for f2 */
  195. n = 0;
  196. while(c >= '0' && c <= '9') {
  197. n = n*10 + c-'0';
  198. c = *fmt++;
  199. }
  200. if(local.f1 == NONE)
  201. local.f1 = n;
  202. else
  203. local.f2 = n;
  204. goto l1;
  205. }
  206. if(c == '*') {
  207. n = va_arg(argp, int);
  208. if(local.f1 == NONE)
  209. local.f1 = n;
  210. else
  211. local.f2 = n;
  212. goto l0;
  213. }
  214. n = 0;
  215. if(c >= 0 && c < MAXFMT)
  216. n = fmtalloc.index[c];
  217. local.chr = c;
  218. n = (*fmtalloc.conv[n])(&argp, &local);
  219. if(n < 0) {
  220. local.f3 |= -n;
  221. goto l0;
  222. }
  223. goto loop;
  224. }
  225. int
  226. numbconv(va_list *arg, Fconv *fp)
  227. {
  228. char s[IDIGIT];
  229. int i, f, n, b, ucase;
  230. long v;
  231. vlong vl;
  232. SET(v);
  233. SET(vl);
  234. ucase = 0;
  235. b = fp->chr;
  236. switch(fp->chr) {
  237. case 'u':
  238. fp->f3 |= FUNSIGN;
  239. case 'd':
  240. b = 10;
  241. break;
  242. case 'b':
  243. b = 2;
  244. break;
  245. case 'o':
  246. b = 8;
  247. break;
  248. case 'X':
  249. ucase = 1;
  250. case 'x':
  251. b = 16;
  252. break;
  253. case 'p':
  254. fp->f3 |= FPOINTER|FUNSIGN;
  255. b = 16;
  256. break;
  257. }
  258. f = 0;
  259. switch(fp->f3 & (FVLONG|FLONG|FUNSIGN|FPOINTER)) {
  260. case FVLONG|FLONG:
  261. vl = va_arg(*arg, vlong);
  262. break;
  263. case FUNSIGN|FVLONG|FLONG:
  264. vl = va_arg(*arg, uvlong);
  265. break;
  266. case FUNSIGN|FPOINTER:
  267. v = (ulong)va_arg(*arg, void*);
  268. break;
  269. case FLONG:
  270. v = va_arg(*arg, long);
  271. break;
  272. case FUNSIGN|FLONG:
  273. v = va_arg(*arg, ulong);
  274. break;
  275. default:
  276. v = va_arg(*arg, int);
  277. break;
  278. case FUNSIGN:
  279. v = va_arg(*arg, unsigned);
  280. break;
  281. }
  282. if(fp->f3 & FVLONG) {
  283. if(!(fp->f3 & FUNSIGN) && vl < 0) {
  284. vl = -vl;
  285. f = 1;
  286. }
  287. } else {
  288. if(!(fp->f3 & FUNSIGN) && v < 0) {
  289. v = -v;
  290. f = 1;
  291. }
  292. }
  293. s[IDIGIT-1] = 0;
  294. for(i = IDIGIT-2;; i--) {
  295. if(fp->f3 & FVLONG)
  296. n = (uvlong)vl % b;
  297. else
  298. n = (ulong)v % b;
  299. n += '0';
  300. if(n > '9') {
  301. n += 'a' - ('9'+1);
  302. if(ucase)
  303. n += 'A'-'a';
  304. }
  305. s[i] = n;
  306. if(i < 2)
  307. break;
  308. if(fp->f3 & FVLONG)
  309. vl = (uvlong)vl / b;
  310. else
  311. v = (ulong)v / b;
  312. if(fp->f2 != NONE && i >= IDIGIT-fp->f2)
  313. continue;
  314. if(fp->f3 & FVLONG) {
  315. if(vl <= 0)
  316. break;
  317. continue;
  318. }
  319. if(v <= 0)
  320. break;
  321. }
  322. if(fp->f3 & FSHARP) {
  323. if(b == 8 && s[i] != '0')
  324. s[--i] = '0';
  325. if(b == 16) {
  326. if(ucase)
  327. s[--i] = 'X';
  328. else
  329. s[--i] = 'x';
  330. s[--i] = '0';
  331. }
  332. }
  333. if(f)
  334. s[--i] = '-';
  335. fp->f2 = NONE;
  336. strconv(s+i, fp);
  337. return 0;
  338. }
  339. void
  340. Strconv(Rune *s, Fconv *fp)
  341. {
  342. int n, c;
  343. if(fp->f3 & FMINUS)
  344. fp->f1 = -fp->f1;
  345. n = 0;
  346. if(fp->f1 != NONE && fp->f1 >= 0) {
  347. for(; s[n]; n++)
  348. ;
  349. while(n < fp->f1) {
  350. pchar(' ', fp);
  351. printcol++;
  352. n++;
  353. }
  354. }
  355. for(;;) {
  356. c = *s++;
  357. if(c == 0)
  358. break;
  359. n++;
  360. if(fp->f2 == NONE || fp->f2 > 0) {
  361. pchar(c, fp);
  362. if(fp->f2 != NONE)
  363. fp->f2--;
  364. switch(c) {
  365. default:
  366. printcol++;
  367. break;
  368. case '\n':
  369. printcol = 0;
  370. break;
  371. case '\t':
  372. printcol = (printcol+8) & ~7;
  373. break;
  374. }
  375. }
  376. }
  377. if(fp->f1 != NONE && fp->f1 < 0) {
  378. fp->f1 = -fp->f1;
  379. while(n < fp->f1) {
  380. pchar(' ', fp);
  381. printcol++;
  382. n++;
  383. }
  384. }
  385. }
  386. void
  387. strconv(char *s, Fconv *fp)
  388. {
  389. int n, c, i;
  390. Rune rune;
  391. if(fp->f3 & FMINUS)
  392. fp->f1 = -fp->f1;
  393. n = 0;
  394. if(fp->f1 != NONE && fp->f1 >= 0) {
  395. n = utflen(s);
  396. while(n < fp->f1) {
  397. pchar(' ', fp);
  398. printcol++;
  399. n++;
  400. }
  401. }
  402. for(;;) {
  403. c = *s & 0xff;
  404. if(c >= Runeself) {
  405. i = chartorune(&rune, s);
  406. s += i;
  407. c = rune;
  408. } else
  409. s++;
  410. if(c == 0)
  411. break;
  412. n++;
  413. if(fp->f2 == NONE || fp->f2 > 0) {
  414. pchar(c, fp);
  415. if(fp->f2 != NONE)
  416. fp->f2--;
  417. switch(c) {
  418. default:
  419. printcol++;
  420. break;
  421. case '\n':
  422. printcol = 0;
  423. break;
  424. case '\t':
  425. printcol = (printcol+8) & ~7;
  426. break;
  427. }
  428. }
  429. }
  430. if(fp->f1 != NONE && fp->f1 < 0) {
  431. fp->f1 = -fp->f1;
  432. while(n < fp->f1) {
  433. pchar(' ', fp);
  434. printcol++;
  435. n++;
  436. }
  437. }
  438. }
  439. static int
  440. noconv(va_list *o, Fconv *fp)
  441. {
  442. char s[10];
  443. USED(o);
  444. s[0] = '*';
  445. s[1] = fp->chr;
  446. s[2] = '*';
  447. s[3] = 0;
  448. fp->f1 = 0;
  449. fp->f2 = NONE;
  450. fp->f3 = 0;
  451. strconv(s, fp);
  452. return 0;
  453. }
  454. static int
  455. rconv(va_list *o, Fconv *fp)
  456. {
  457. char s[ERRLEN];
  458. USED(o);
  459. s[0] = 0;
  460. errstr(s);
  461. fp->f2 = NONE;
  462. strconv(s, fp);
  463. return 0;
  464. }
  465. static int
  466. cconv(va_list *arg, Fconv *fp)
  467. {
  468. char s[10];
  469. Rune rune;
  470. rune = va_arg(*arg, unsigned int);
  471. if(fp->chr == 'c')
  472. rune &= 0xff;
  473. s[runetochar(s, &rune)] = 0;
  474. fp->f2 = NONE;
  475. strconv(s, fp);
  476. return 0;
  477. }
  478. static int
  479. sconv(va_list *arg, Fconv *fp)
  480. {
  481. char *s;
  482. Rune *r;
  483. if(fp->chr == 's') {
  484. s = va_arg(*arg, char*);
  485. if(s == 0)
  486. s = "<null>";
  487. strconv(s, fp);
  488. } else {
  489. r = va_arg(*arg, Rune*);
  490. if(r == 0)
  491. r = (Rune*)L"<null>";
  492. Strconv(r, fp);
  493. }
  494. return 0;
  495. }
  496. static int
  497. percent(va_list *o, Fconv *fp)
  498. {
  499. USED(o);
  500. pchar('%', fp);
  501. printcol++;
  502. return 0;
  503. }
  504. static int
  505. column(va_list *arg, Fconv *fp)
  506. {
  507. int col, pc;
  508. col = va_arg(*arg, int);
  509. while(printcol < col) {
  510. pc = (printcol+8) & ~7;
  511. if(pc <= col) {
  512. pchar('\t', fp);
  513. printcol = pc;
  514. } else {
  515. pchar(' ', fp);
  516. printcol++;
  517. }
  518. }
  519. return 0;
  520. }
  521. static int
  522. flags(va_list *o, Fconv *fp)
  523. {
  524. int f;
  525. USED(o);
  526. f = 0;
  527. switch(fp->chr) {
  528. case '+':
  529. f = FPLUS;
  530. break;
  531. case '-':
  532. f = FMINUS;
  533. break;
  534. case '#':
  535. f = FSHARP;
  536. break;
  537. case 'l':
  538. f = FLONG;
  539. if(fp->f3 & FLONG)
  540. f = FVLONG;
  541. break;
  542. case 'u':
  543. f = FUNSIGN;
  544. break;
  545. }
  546. return -f;
  547. }
  548. int
  549. fltconv(va_list *arg, Fconv *fp)
  550. {
  551. char s1[FDIGIT+10], s2[FDIGIT+10];
  552. double f, g, h;
  553. int e, d, i, n, s;
  554. int c1, c2, c3, f2, ucase;
  555. f2 = fp->f2;
  556. fp->f2 = NONE;
  557. f = va_arg(*arg, double);
  558. if(isNaN(f)){
  559. strconv("NaN", fp);
  560. return 0;
  561. }
  562. if(isInf(f, 1)){
  563. strconv("+Inf", fp);
  564. return 0;
  565. }
  566. if(isInf(f, -1)){
  567. strconv("-Inf", fp);
  568. return 0;
  569. }
  570. s = 0;
  571. if(f < 0) {
  572. f = -f;
  573. s++;
  574. }
  575. ucase = 0;
  576. if(fp->chr >= 'A' && fp->chr <= 'Z') {
  577. ucase = 1;
  578. fp->chr += 'a'-'A';
  579. }
  580. loop:
  581. e = 0;
  582. if(f != 0) {
  583. frexp(f, &e);
  584. e = e * .30103;
  585. d = e/2;
  586. h = f * pow10(-d); /* 10**-e in 2 parts */
  587. g = h * pow10(d-e);
  588. while(g < 1) {
  589. e--;
  590. g = h * pow10(d-e);
  591. }
  592. while(g >= 10) {
  593. e++;
  594. g = h * pow10(d-e);
  595. }
  596. }
  597. if(f2 == NONE)
  598. f2 = FDEFLT;
  599. if(fp->chr == 'g' && f2 > 0)
  600. f2--;
  601. if(f2 > FDIGIT)
  602. f2 = FDIGIT;
  603. /*
  604. * n is number of digits to convert
  605. * 1 before, f2 after, 1 extra for rounding
  606. */
  607. n = f2 + 2;
  608. if(fp->chr == 'f') {
  609. /*
  610. * e+1 before, f2 after, 1 extra
  611. */
  612. n += e;
  613. if(n <= 0)
  614. n = 1;
  615. }
  616. if(n >= FDIGIT+2) {
  617. if(fp->chr == 'e')
  618. f2 = -1;
  619. fp->chr = 'e';
  620. goto loop;
  621. }
  622. /*
  623. * convert n digits
  624. */
  625. g = f;
  626. if(e < 0) {
  627. if(e < -55) {
  628. g *= pow10(50);
  629. g *= pow10(-e-51);
  630. } else
  631. g *= pow10(-e-1);
  632. }
  633. for(i=0; i<n; i++) {
  634. d = e-i;
  635. if(d >= 0) {
  636. h = pow10(d);
  637. d = floor(g/h);
  638. g -= d * h;
  639. } else {
  640. g *= 10;
  641. d = floor(g);
  642. g -= d;
  643. }
  644. s1[i+1] = d + '0';
  645. }
  646. /*
  647. * round by adding .5 into extra digit
  648. */
  649. d = 5;
  650. for(i=n-1; i>=0; i--) {
  651. s1[i+1] += d;
  652. d = 0;
  653. if(s1[i+1] > '9') {
  654. s1[i+1] -= 10;
  655. d++;
  656. }
  657. }
  658. i = 1;
  659. if(d) {
  660. s1[0] = '1';
  661. e++;
  662. i = 0;
  663. }
  664. /*
  665. * copy into final place
  666. * c1 digits of leading '0'
  667. * c2 digits from conversion
  668. * c3 digits after '.'
  669. */
  670. d = 0;
  671. if(s)
  672. s2[d++] = '-';
  673. else
  674. if(fp->f3 & FPLUS)
  675. s2[d++] = '+';
  676. c1 = 0;
  677. c2 = f2 + 1;
  678. c3 = f2;
  679. if(fp->chr == 'g')
  680. if(e >= -5 && e <= f2) {
  681. c1 = -e - 1;
  682. if(c1 < 0)
  683. c1 = 0;
  684. c3 = f2 - e;
  685. fp->chr = 'h';
  686. }
  687. if(fp->chr == 'f') {
  688. c1 = -e;
  689. if(c1 < 0)
  690. c1 = 0;
  691. if(c1 > f2)
  692. c1 = c2;
  693. c2 += e;
  694. if(c2 < 0)
  695. c2 = 0;
  696. }
  697. while(c1 > 0) {
  698. if(c1+c2 == c3)
  699. s2[d++] = '.';
  700. s2[d++] = '0';
  701. c1--;
  702. }
  703. while(c2 > 0) {
  704. if(c1+c2 == c3)
  705. s2[d++] = '.';
  706. s2[d++] = s1[i++];
  707. c2--;
  708. }
  709. /*
  710. * strip trailing '0' on g conv
  711. */
  712. if(fp->f3 & FSHARP) {
  713. if(c1+c2 == c3)
  714. s2[d++] = '.';
  715. } else
  716. if(fp->chr == 'g' || fp->chr == 'h') {
  717. for(n=d-1; n>=0; n--)
  718. if(s2[n] != '0')
  719. break;
  720. for(i=n; i>=0; i--)
  721. if(s2[i] == '.') {
  722. d = n;
  723. if(i != n)
  724. d++;
  725. break;
  726. }
  727. }
  728. if(fp->chr == 'e' || fp->chr == 'g') {
  729. if(ucase)
  730. s2[d++] = 'E';
  731. else
  732. s2[d++] = 'e';
  733. c1 = e;
  734. if(c1 < 0) {
  735. s2[d++] = '-';
  736. c1 = -c1;
  737. } else
  738. s2[d++] = '+';
  739. if(c1 >= 100) {
  740. s2[d++] = c1/100 + '0';
  741. c1 = c1%100;
  742. }
  743. s2[d++] = c1/10 + '0';
  744. s2[d++] = c1%10 + '0';
  745. }
  746. s2[d] = 0;
  747. strconv(s2, fp);
  748. return 0;
  749. }