dofmt.c 9.5 KB

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