doprint.c 8.4 KB

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