doprint.xc 8.4 KB

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