dofmt.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. /*
  2. * The authors of this software are Rob Pike and Ken Thompson.
  3. * Copyright (c) 2002 by Lucent Technologies.
  4. * Permission to use, copy, modify, and distribute this software for any
  5. * purpose without fee is hereby granted, provided that this entire notice
  6. * is included in all copies of any software which is or includes a copy
  7. * or modification of this software and in all copies of the supporting
  8. * documentation for such software.
  9. * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
  10. * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
  11. * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
  12. * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
  13. */
  14. #include "lib9.h"
  15. #include "fmtdef.h"
  16. /* format the output into f->to and return the number of characters fmted */
  17. int
  18. dofmt(Fmt *f, char *fmt)
  19. {
  20. Rune rune, *rt, *rs;
  21. int r;
  22. char *t, *s;
  23. int n, nfmt;
  24. nfmt = f->nfmt;
  25. for(;;){
  26. if(f->runes){
  27. rt = f->to;
  28. rs = f->stop;
  29. while((r = *(uchar*)fmt) && r != '%'){
  30. if(r < Runeself)
  31. fmt++;
  32. else{
  33. fmt += chartorune(&rune, fmt);
  34. r = rune;
  35. }
  36. FMTRCHAR(f, rt, rs, r);
  37. }
  38. fmt++;
  39. f->nfmt += rt - (Rune *)f->to;
  40. f->to = rt;
  41. if(!r)
  42. return f->nfmt - nfmt;
  43. f->stop = rs;
  44. }else{
  45. t = f->to;
  46. s = f->stop;
  47. while((r = *(uchar*)fmt) && r != '%'){
  48. if(r < Runeself){
  49. FMTCHAR(f, t, s, r);
  50. fmt++;
  51. }else{
  52. n = chartorune(&rune, fmt);
  53. if(t + n > s){
  54. t = _fmtflush(f, t, n);
  55. if(t != nil)
  56. s = f->stop;
  57. else
  58. return -1;
  59. }
  60. while(n--)
  61. *t++ = *fmt++;
  62. }
  63. }
  64. fmt++;
  65. f->nfmt += t - (char *)f->to;
  66. f->to = t;
  67. if(!r)
  68. return f->nfmt - nfmt;
  69. f->stop = s;
  70. }
  71. fmt = _fmtdispatch(f, fmt, 0);
  72. if(fmt == nil)
  73. return -1;
  74. }
  75. }
  76. void *
  77. _fmtflush(Fmt *f, void *t, int len)
  78. {
  79. if(f->runes)
  80. f->nfmt += (Rune*)t - (Rune*)f->to;
  81. else
  82. f->nfmt += (char*)t - (char *)f->to;
  83. f->to = t;
  84. if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){
  85. f->stop = f->to;
  86. return nil;
  87. }
  88. return f->to;
  89. }
  90. /*
  91. * put a formatted block of memory sz bytes long of n runes into the output buffer,
  92. * left/right justified in a field of at least f->width charactes
  93. */
  94. int
  95. _fmtpad(Fmt *f, int n)
  96. {
  97. char *t, *s;
  98. int i;
  99. t = f->to;
  100. s = f->stop;
  101. for(i = 0; i < n; i++)
  102. FMTCHAR(f, t, s, ' ');
  103. f->nfmt += t - (char *)f->to;
  104. f->to = t;
  105. return 0;
  106. }
  107. int
  108. _rfmtpad(Fmt *f, int n)
  109. {
  110. Rune *t, *s;
  111. int i;
  112. t = f->to;
  113. s = f->stop;
  114. for(i = 0; i < n; i++)
  115. FMTRCHAR(f, t, s, ' ');
  116. f->nfmt += t - (Rune *)f->to;
  117. f->to = t;
  118. return 0;
  119. }
  120. int
  121. _fmtcpy(Fmt *f, void *vm, int n, int sz)
  122. {
  123. Rune *rt, *rs, r;
  124. char *t, *s, *m, *me;
  125. ulong fl;
  126. int nc, w;
  127. m = vm;
  128. me = m + sz;
  129. w = f->width;
  130. fl = f->flags;
  131. if((fl & FmtPrec) && n > f->prec)
  132. n = f->prec;
  133. if(f->runes){
  134. if(!(fl & FmtLeft) && _rfmtpad(f, w - n) < 0)
  135. return -1;
  136. rt = f->to;
  137. rs = f->stop;
  138. for(nc = n; nc > 0; nc--){
  139. r = *(uchar*)m;
  140. if(r < Runeself)
  141. m++;
  142. else if((me - m) >= UTFmax || fullrune(m, me-m))
  143. m += chartorune(&r, m);
  144. else
  145. break;
  146. FMTRCHAR(f, rt, rs, r);
  147. }
  148. f->nfmt += rt - (Rune *)f->to;
  149. f->to = rt;
  150. if(m < me)
  151. return -1;
  152. if(fl & FmtLeft && _rfmtpad(f, w - n) < 0)
  153. return -1;
  154. }else{
  155. if(!(fl & FmtLeft) && _fmtpad(f, w - n) < 0)
  156. return -1;
  157. t = f->to;
  158. s = f->stop;
  159. for(nc = n; nc > 0; nc--){
  160. r = *(uchar*)m;
  161. if(r < Runeself)
  162. m++;
  163. else if((me - m) >= UTFmax || fullrune(m, me-m))
  164. m += chartorune(&r, m);
  165. else
  166. break;
  167. FMTRUNE(f, t, s, r);
  168. }
  169. f->nfmt += t - (char *)f->to;
  170. f->to = t;
  171. if(fl & FmtLeft && _fmtpad(f, w - n) < 0)
  172. return -1;
  173. }
  174. return 0;
  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. m = vm;
  184. w = f->width;
  185. fl = f->flags;
  186. if((fl & FmtPrec) && n > f->prec)
  187. n = f->prec;
  188. if(f->runes){
  189. if(!(fl & FmtLeft) && _rfmtpad(f, w - n) < 0)
  190. return -1;
  191. rt = f->to;
  192. rs = f->stop;
  193. for(me = m + n; m < me; m++)
  194. FMTRCHAR(f, rt, rs, *m);
  195. f->nfmt += rt - (Rune *)f->to;
  196. f->to = rt;
  197. if(fl & FmtLeft && _rfmtpad(f, w - n) < 0)
  198. return -1;
  199. }else{
  200. if(!(fl & FmtLeft) && _fmtpad(f, w - n) < 0)
  201. return -1;
  202. t = f->to;
  203. s = f->stop;
  204. for(me = m + n; m < me; m++){
  205. r = *m;
  206. FMTRUNE(f, t, s, r);
  207. }
  208. f->nfmt += t - (char *)f->to;
  209. f->to = t;
  210. if(fl & FmtLeft && _fmtpad(f, w - n) < 0)
  211. return -1;
  212. }
  213. return 0;
  214. }
  215. /* fmt out one character */
  216. int
  217. _charfmt(Fmt *f)
  218. {
  219. char x[1];
  220. x[0] = va_arg(f->args, int);
  221. f->prec = 1;
  222. return _fmtcpy(f, x, 1, 1);
  223. }
  224. /* fmt out one rune */
  225. int
  226. _runefmt(Fmt *f)
  227. {
  228. Rune x[1];
  229. x[0] = va_arg(f->args, int);
  230. return _fmtrcpy(f, x, 1);
  231. }
  232. /* public helper routine: fmt out a null terminated string already in hand */
  233. int
  234. fmtstrcpy(Fmt *f, char *s)
  235. {
  236. int p, i;
  237. if(!s)
  238. return _fmtcpy(f, "<nil>", 5, 5);
  239. /* if precision is specified, make sure we don't wander off the end */
  240. if(f->flags & FmtPrec){
  241. p = f->prec;
  242. for(i = 0; i < p; i++)
  243. if(s[i] == 0)
  244. break;
  245. return _fmtcpy(f, s, utfnlen(s, i), i); /* BUG?: won't print a partial rune at end */
  246. }
  247. return _fmtcpy(f, s, utflen(s), strlen(s));
  248. }
  249. /* fmt out a null terminated utf string */
  250. int
  251. _strfmt(Fmt *f)
  252. {
  253. char *s;
  254. s = va_arg(f->args, char *);
  255. return fmtstrcpy(f, s);
  256. }
  257. /* public helper routine: fmt out a null terminated rune string already in hand */
  258. int
  259. fmtrunestrcpy(Fmt *f, Rune *s)
  260. {
  261. Rune *e;
  262. int n, p;
  263. if(!s)
  264. return _fmtcpy(f, "<nil>", 5, 5);
  265. /* if precision is specified, make sure we don't wander off the end */
  266. if(f->flags & FmtPrec){
  267. p = f->prec;
  268. for(n = 0; n < p; n++)
  269. if(s[n] == 0)
  270. break;
  271. }else{
  272. for(e = s; *e; e++)
  273. ;
  274. n = e - s;
  275. }
  276. return _fmtrcpy(f, s, n);
  277. }
  278. /* fmt out a null terminated rune string */
  279. int
  280. _runesfmt(Fmt *f)
  281. {
  282. Rune *s;
  283. s = va_arg(f->args, Rune *);
  284. return fmtrunestrcpy(f, s);
  285. }
  286. /* fmt a % */
  287. int
  288. _percentfmt(Fmt *f)
  289. {
  290. Rune x[1];
  291. x[0] = f->r;
  292. f->prec = 1;
  293. return _fmtrcpy(f, x, 1);
  294. }
  295. /* fmt an integer */
  296. int
  297. _ifmt(Fmt *f)
  298. {
  299. char buf[70], *p, *conv;
  300. uvlong vu;
  301. ulong u;
  302. int neg, base, i, n, fl, w, isv;
  303. neg = 0;
  304. fl = f->flags;
  305. isv = 0;
  306. vu = 0;
  307. u = 0;
  308. if(f->r == 'p'){
  309. u = (ulong)va_arg(f->args, void*);
  310. f->r = 'x';
  311. fl |= FmtUnsigned;
  312. }else if(fl & FmtVLong){
  313. isv = 1;
  314. if(fl & FmtUnsigned)
  315. vu = va_arg(f->args, uvlong);
  316. else
  317. vu = va_arg(f->args, vlong);
  318. }else if(fl & FmtLong){
  319. if(fl & FmtUnsigned)
  320. u = va_arg(f->args, ulong);
  321. else
  322. u = va_arg(f->args, long);
  323. }else if(fl & FmtByte){
  324. if(fl & FmtUnsigned)
  325. u = (uchar)va_arg(f->args, int);
  326. else
  327. u = (char)va_arg(f->args, int);
  328. }else if(fl & FmtShort){
  329. if(fl & FmtUnsigned)
  330. u = (ushort)va_arg(f->args, int);
  331. else
  332. u = (short)va_arg(f->args, int);
  333. }else{
  334. if(fl & FmtUnsigned)
  335. u = va_arg(f->args, uint);
  336. else
  337. u = va_arg(f->args, int);
  338. }
  339. conv = "0123456789abcdef";
  340. switch(f->r){
  341. case 'd':
  342. base = 10;
  343. break;
  344. case 'x':
  345. base = 16;
  346. break;
  347. case 'X':
  348. base = 16;
  349. conv = "0123456789ABCDEF";
  350. break;
  351. case 'b':
  352. base = 2;
  353. break;
  354. case 'o':
  355. base = 8;
  356. break;
  357. default:
  358. return -1;
  359. }
  360. if(!(fl & FmtUnsigned)){
  361. if(isv && (vlong)vu < 0){
  362. vu = -(vlong)vu;
  363. neg = 1;
  364. }else if(!isv && (long)u < 0){
  365. u = -(long)u;
  366. neg = 1;
  367. }
  368. }
  369. p = buf + sizeof buf - 1;
  370. n = 0;
  371. if(isv){
  372. while(vu){
  373. i = vu % base;
  374. vu /= base;
  375. if((fl & FmtComma) && n % 4 == 3){
  376. *p-- = ',';
  377. n++;
  378. }
  379. *p-- = conv[i];
  380. n++;
  381. }
  382. }else{
  383. while(u){
  384. i = u % base;
  385. u /= base;
  386. if((fl & FmtComma) && n % 4 == 3){
  387. *p-- = ',';
  388. n++;
  389. }
  390. *p-- = conv[i];
  391. n++;
  392. }
  393. }
  394. if(n == 0){
  395. *p-- = '0';
  396. n = 1;
  397. }
  398. for(w = f->prec; n < w && p > buf+3; n++)
  399. *p-- = '0';
  400. if(neg || (fl & (FmtSign|FmtSpace)))
  401. n++;
  402. if(fl & FmtSharp){
  403. if(base == 16)
  404. n += 2;
  405. else if(base == 8){
  406. if(p[1] == '0')
  407. fl &= ~FmtSharp;
  408. else
  409. n++;
  410. }
  411. }
  412. if((fl & FmtZero) && !(fl & FmtLeft)){
  413. for(w = f->width; n < w && p > buf+3; n++)
  414. *p-- = '0';
  415. f->width = 0;
  416. }
  417. if(fl & FmtSharp){
  418. if(base == 16)
  419. *p-- = f->r;
  420. if(base == 16 || base == 8)
  421. *p-- = '0';
  422. }
  423. if(neg)
  424. *p-- = '-';
  425. else if(fl & FmtSign)
  426. *p-- = '+';
  427. else if(fl & FmtSpace)
  428. *p-- = ' ';
  429. f->flags &= ~FmtPrec;
  430. return _fmtcpy(f, p + 1, n, n);
  431. }
  432. int
  433. _countfmt(Fmt *f)
  434. {
  435. void *p;
  436. ulong fl;
  437. fl = f->flags;
  438. p = va_arg(f->args, void*);
  439. if(fl & FmtVLong){
  440. *(vlong*)p = f->nfmt;
  441. }else if(fl & FmtLong){
  442. *(long*)p = f->nfmt;
  443. }else if(fl & FmtByte){
  444. *(char*)p = f->nfmt;
  445. }else if(fl & FmtShort){
  446. *(short*)p = f->nfmt;
  447. }else{
  448. *(int*)p = f->nfmt;
  449. }
  450. return 0;
  451. }
  452. int
  453. _flagfmt(Fmt *f)
  454. {
  455. switch(f->r){
  456. case ',':
  457. f->flags |= FmtComma;
  458. break;
  459. case '-':
  460. f->flags |= FmtLeft;
  461. break;
  462. case '+':
  463. f->flags |= FmtSign;
  464. break;
  465. case '#':
  466. f->flags |= FmtSharp;
  467. break;
  468. case ' ':
  469. f->flags |= FmtSpace;
  470. break;
  471. case 'u':
  472. f->flags |= FmtUnsigned;
  473. break;
  474. case 'h':
  475. if(f->flags & FmtShort)
  476. f->flags |= FmtByte;
  477. f->flags |= FmtShort;
  478. break;
  479. case 'l':
  480. if(f->flags & FmtLong)
  481. f->flags |= FmtVLong;
  482. f->flags |= FmtLong;
  483. break;
  484. }
  485. return 1;
  486. }
  487. /* default error format */
  488. int
  489. _badfmt(Fmt *f)
  490. {
  491. char x[3];
  492. x[0] = '%';
  493. x[1] = f->r;
  494. x[2] = '%';
  495. f->prec = 3;
  496. _fmtcpy(f, x, 3, 3);
  497. return 0;
  498. }