dofmt.c (11644B) download
1/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
2/* Copyright (c) 2004 Google Inc.; see LICENSE */
3
4#include "fmt.h"
5#include "fmtdef.h"
6#include "plan9.h"
7
8#include <stdarg.h>
9#include <string.h>
10
11/* format the output into f->to and return the number of characters fmted */
12int dofmt(Fmt* f, char* fmt) {
13 Rune rune, *rt, *rs;
14 int r;
15 char *t, *s;
16 int n, nfmt;
17
18 nfmt = f->nfmt;
19 for (;;) {
20 if (f->runes) {
21 rt = (Rune*) f->to;
22 rs = (Rune*) f->stop;
23 while ((r = *(uchar*) fmt) && r != '%') {
24 if (r < Runeself)
25 fmt++;
26 else {
27 fmt += chartorune(&rune, fmt);
28 r = rune;
29 }
30 FMTRCHAR(f, rt, rs, r);
31 }
32 fmt++;
33 f->nfmt += rt - (Rune*) f->to;
34 f->to = rt;
35 if (!r)
36 return f->nfmt - nfmt;
37 f->stop = rs;
38 } else {
39 t = (char*) f->to;
40 s = (char*) f->stop;
41 while ((r = *(uchar*) fmt) && r != '%') {
42 if (r < Runeself) {
43 FMTCHAR(f, t, s, r);
44 fmt++;
45 } else {
46 n = chartorune(&rune, fmt);
47 if (t + n > s) {
48 t = (char*) __fmtflush(f, t, n);
49 if (t != nil)
50 s = (char*) f->stop;
51 else
52 return -1;
53 }
54 while (n--)
55 *t++ = *fmt++;
56 }
57 }
58 fmt++;
59 f->nfmt += t - (char*) f->to;
60 f->to = t;
61 if (!r)
62 return f->nfmt - nfmt;
63 f->stop = s;
64 }
65
66 fmt = (char*) __fmtdispatch(f, fmt, 0);
67 if (fmt == nil)
68 return -1;
69 }
70}
71
72void* __fmtflush(Fmt* f, void* t, int len) {
73 if (f->runes)
74 f->nfmt += (Rune*) t - (Rune*) f->to;
75 else
76 f->nfmt += (char*) t - (char*) f->to;
77 f->to = t;
78 if (f->flush == 0 || (*f->flush)(f) == 0 || (char*) f->to + len > (char*) f->stop) {
79 f->stop = f->to;
80 return nil;
81 }
82 return f->to;
83}
84
85/*
86 * put a formatted block of memory sz bytes long of n runes into the output buffer,
87 * left/right justified in a field of at least f->width characters (if FmtWidth is set)
88 */
89int __fmtpad(Fmt* f, int n) {
90 char *t, *s;
91 int i;
92
93 t = (char*) f->to;
94 s = (char*) f->stop;
95 for (i = 0; i < n; i++)
96 FMTCHAR(f, t, s, ' ');
97 f->nfmt += t - (char*) f->to;
98 f->to = t;
99 return 0;
100}
101
102int __rfmtpad(Fmt* f, int n) {
103 Rune *t, *s;
104 int i;
105
106 t = (Rune*) f->to;
107 s = (Rune*) f->stop;
108 for (i = 0; i < n; i++)
109 FMTRCHAR(f, t, s, ' ');
110 f->nfmt += t - (Rune*) f->to;
111 f->to = t;
112 return 0;
113}
114
115int __fmtcpy(Fmt* f, const void* vm, int n, int sz) {
116 Rune *rt, *rs, r;
117 char *t, *s, *m, *me;
118 ulong fl;
119 int nc, w;
120
121 m = (char*) vm;
122 me = m + sz;
123 fl = f->flags;
124 w = 0;
125 if (fl & FmtWidth)
126 w = f->width;
127 if ((fl & FmtPrec) && n > f->prec)
128 n = f->prec;
129 if (f->runes) {
130 if (!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
131 return -1;
132 rt = (Rune*) f->to;
133 rs = (Rune*) f->stop;
134 for (nc = n; nc > 0; nc--) {
135 r = *(uchar*) m;
136 if (r < Runeself)
137 m++;
138 else if ((me - m) >= UTFmax || fullrune(m, me - m))
139 m += chartorune(&r, m);
140 else
141 break;
142 FMTRCHAR(f, rt, rs, r);
143 }
144 f->nfmt += rt - (Rune*) f->to;
145 f->to = rt;
146 if (fl & FmtLeft && __rfmtpad(f, w - n) < 0)
147 return -1;
148 } else {
149 if (!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
150 return -1;
151 t = (char*) f->to;
152 s = (char*) f->stop;
153 for (nc = n; nc > 0; nc--) {
154 r = *(uchar*) m;
155 if (r < Runeself)
156 m++;
157 else if ((me - m) >= UTFmax || fullrune(m, me - m))
158 m += chartorune(&r, m);
159 else
160 break;
161 FMTRUNE(f, t, s, r);
162 }
163 f->nfmt += t - (char*) f->to;
164 f->to = t;
165 if (fl & FmtLeft && __fmtpad(f, w - n) < 0)
166 return -1;
167 }
168 return 0;
169}
170
171int __fmtrcpy(Fmt* f, const void* vm, int n) {
172 Rune r, *m, *me, *rt, *rs;
173 char *t, *s;
174 ulong fl;
175 int w;
176
177 m = (Rune*) vm;
178 fl = f->flags;
179 w = 0;
180 if (fl & FmtWidth)
181 w = f->width;
182 if ((fl & FmtPrec) && n > f->prec)
183 n = f->prec;
184 if (f->runes) {
185 if (!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
186 return -1;
187 rt = (Rune*) f->to;
188 rs = (Rune*) f->stop;
189 for (me = m + n; m < me; m++)
190 FMTRCHAR(f, rt, rs, *m);
191 f->nfmt += rt - (Rune*) f->to;
192 f->to = rt;
193 if (fl & FmtLeft && __rfmtpad(f, w - n) < 0)
194 return -1;
195 } else {
196 if (!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
197 return -1;
198 t = (char*) f->to;
199 s = (char*) f->stop;
200 for (me = m + n; m < me; m++) {
201 r = *m;
202 FMTRUNE(f, t, s, r);
203 }
204 f->nfmt += t - (char*) f->to;
205 f->to = t;
206 if (fl & FmtLeft && __fmtpad(f, w - n) < 0)
207 return -1;
208 }
209 return 0;
210}
211
212/* fmt out one character */
213int __charfmt(Fmt* f) {
214 char x[1];
215
216 x[0] = va_arg(f->args, int);
217 f->prec = 1;
218 return __fmtcpy(f, (const char*) x, 1, 1);
219}
220
221/* fmt out one rune */
222int __runefmt(Fmt* f) {
223 Rune x[1];
224
225 x[0] = va_arg(f->args, int);
226 return __fmtrcpy(f, (const void*) x, 1);
227}
228
229/* public helper routine: fmt out a null terminated string already in hand */
230int fmtstrcpy(Fmt* f, char* s) {
231 int i, j;
232
233 if (!s)
234 return __fmtcpy(f, "<nil>", 5, 5);
235 /* if precision is specified, make sure we don't wander off the end */
236 if (f->flags & FmtPrec) {
237#ifdef PLAN9PORT
238 Rune r;
239 i = 0;
240 for (j = 0; j < f->prec && s[i]; j++)
241 i += chartorune(&r, s + i);
242#else
243 /* ANSI requires precision in bytes, not Runes */
244 for (i = 0; i < f->prec; i++)
245 if (s[i] == 0)
246 break;
247 j = utfnlen(s, i); /* won't print partial at end */
248#endif
249 return __fmtcpy(f, s, j, i);
250 }
251 return __fmtcpy(f, s, utflen(s), strlen(s));
252}
253
254/* fmt out a null terminated utf string */
255int __strfmt(Fmt* f) {
256 char* s;
257
258 s = va_arg(f->args, char*);
259 return fmtstrcpy(f, s);
260}
261
262/* public helper routine: fmt out a null terminated rune string already in hand */
263int fmtrunestrcpy(Fmt* f, Rune* s) {
264 Rune* e;
265 int n, p;
266
267 if (!s)
268 return __fmtcpy(f, "<nil>", 5, 5);
269 /* if precision is specified, make sure we don't wander off the end */
270 if (f->flags & FmtPrec) {
271 p = f->prec;
272 for (n = 0; n < p; n++)
273 if (s[n] == 0)
274 break;
275 } else {
276 for (e = s; *e; e++)
277 ;
278 n = e - s;
279 }
280 return __fmtrcpy(f, s, n);
281}
282
283/* fmt out a null terminated rune string */
284int __runesfmt(Fmt* f) {
285 Rune* s;
286
287 s = va_arg(f->args, Rune*);
288 return fmtrunestrcpy(f, s);
289}
290
291/* fmt a % */
292int __percentfmt(Fmt* f) {
293 Rune x[1];
294
295 x[0] = f->r;
296 f->prec = 1;
297 return __fmtrcpy(f, (const void*) x, 1);
298}
299
300/* fmt an integer */
301int __ifmt(Fmt* f) {
302 char buf[140], *p, *conv;
303 /* 140: for 64 bits of binary + 3-byte sep every 4 digits */
304 uvlong vu;
305 ulong u;
306 int neg, base, i, n, fl, w, isv;
307 int ndig, len, excess, bytelen;
308 char* grouping;
309 char* thousands;
310
311 neg = 0;
312 fl = f->flags;
313 isv = 0;
314 vu = 0;
315 u = 0;
316#ifndef PLAN9PORT
317 /*
318 * Unsigned verbs for ANSI C
319 */
320 switch (f->r) {
321 case 'o':
322 case 'p':
323 case 'u':
324 case 'x':
325 case 'X':
326 fl |= FmtUnsigned;
327 fl &= ~(FmtSign | FmtSpace);
328 break;
329 }
330#endif
331 if (f->r == 'p') {
332 u = (ulong) va_arg(f->args, void*);
333 f->r = 'x';
334 fl |= FmtUnsigned;
335 } else if (fl & FmtVLong) {
336 isv = 1;
337 if (fl & FmtUnsigned)
338 vu = va_arg(f->args, uvlong);
339 else
340 vu = va_arg(f->args, vlong);
341 } else if (fl & FmtLong) {
342 if (fl & FmtUnsigned)
343 u = va_arg(f->args, ulong);
344 else
345 u = va_arg(f->args, long);
346 } else if (fl & FmtByte) {
347 if (fl & FmtUnsigned)
348 u = (uchar) va_arg(f->args, int);
349 else
350 u = (char) va_arg(f->args, int);
351 } else if (fl & FmtShort) {
352 if (fl & FmtUnsigned)
353 u = (ushort) va_arg(f->args, int);
354 else
355 u = (short) va_arg(f->args, int);
356 } else {
357 if (fl & FmtUnsigned)
358 u = va_arg(f->args, uint);
359 else
360 u = va_arg(f->args, int);
361 }
362 conv = "0123456789abcdef";
363 grouping = "\4"; /* for hex, octal etc. (undefined by spec but nice) */
364 thousands = f->thousands;
365 switch (f->r) {
366 case 'd':
367 case 'i':
368 case 'u':
369 base = 10;
370 grouping = f->grouping;
371 break;
372 case 'X':
373 conv = "0123456789ABCDEF";
374 /* fall through */
375 case 'x':
376 base = 16;
377 thousands = ":";
378 break;
379 case 'b':
380 base = 2;
381 thousands = ":";
382 break;
383 case 'o':
384 base = 8;
385 break;
386 default:
387 return -1;
388 }
389 if (!(fl & FmtUnsigned)) {
390 if (isv && (vlong) vu < 0) {
391 vu = -(vlong) vu;
392 neg = 1;
393 } else if (!isv && (long) u < 0) {
394 u = -(long) u;
395 neg = 1;
396 }
397 }
398 p = buf + sizeof buf - 1;
399 n = 0; /* in runes */
400 excess = 0; /* number of bytes > number runes */
401 ndig = 0;
402 len = utflen(thousands);
403 bytelen = strlen(thousands);
404 if (isv) {
405 while (vu) {
406 i = vu % base;
407 vu /= base;
408 if ((fl & FmtComma) && n % 4 == 3) {
409 *p-- = ',';
410 n++;
411 }
412 if ((fl & FmtApost) && __needsep(&ndig, &grouping)) {
413 n += len;
414 excess += bytelen - len;
415 p -= bytelen;
416 memmove(p + 1, thousands, bytelen);
417 }
418 *p-- = conv[i];
419 n++;
420 }
421 } else {
422 while (u) {
423 i = u % base;
424 u /= base;
425 if ((fl & FmtComma) && n % 4 == 3) {
426 *p-- = ',';
427 n++;
428 }
429 if ((fl & FmtApost) && __needsep(&ndig, &grouping)) {
430 n += len;
431 excess += bytelen - len;
432 p -= bytelen;
433 memmove(p + 1, thousands, bytelen);
434 }
435 *p-- = conv[i];
436 n++;
437 }
438 }
439 if (n == 0) {
440 /*
441 * "The result of converting a zero value with
442 * a precision of zero is no characters." - ANSI
443 *
444 * "For o conversion, # increases the precision, if and only if
445 * necessary, to force the first digit of the result to be a zero
446 * (if the value and precision are both 0, a single 0 is printed)." - ANSI
447 */
448 if (!(fl & FmtPrec) || f->prec != 0 || (f->r == 'o' && (fl & FmtSharp))) {
449 *p-- = '0';
450 n = 1;
451 if (fl & FmtApost)
452 __needsep(&ndig, &grouping);
453 }
454
455 /*
456 * Zero values don't get 0x.
457 */
458 if (f->r == 'x' || f->r == 'X')
459 fl &= ~FmtSharp;
460 }
461 for (w = f->prec; n < w && p > buf + 3; n++) {
462 if ((fl & FmtApost) && __needsep(&ndig, &grouping)) {
463 n += len;
464 excess += bytelen - len;
465 p -= bytelen;
466 memmove(p + 1, thousands, bytelen);
467 }
468 *p-- = '0';
469 }
470 if (neg || (fl & (FmtSign | FmtSpace)))
471 n++;
472 if (fl & FmtSharp) {
473 if (base == 16)
474 n += 2;
475 else if (base == 8) {
476 if (p[1] == '0')
477 fl &= ~FmtSharp;
478 else
479 n++;
480 }
481 }
482 if ((fl & FmtZero) && !(fl & (FmtLeft | FmtPrec))) {
483 w = 0;
484 if (fl & FmtWidth)
485 w = f->width;
486 for (; n < w && p > buf + 3; n++) {
487 if ((fl & FmtApost) && __needsep(&ndig, &grouping)) {
488 n += len;
489 excess += bytelen - len;
490 p -= bytelen;
491 memmove(p + 1, thousands, bytelen);
492 }
493 *p-- = '0';
494 }
495 f->flags &= ~FmtWidth;
496 }
497 if (fl & FmtSharp) {
498 if (base == 16)
499 *p-- = f->r;
500 if (base == 16 || base == 8)
501 *p-- = '0';
502 }
503 if (neg)
504 *p-- = '-';
505 else if (fl & FmtSign)
506 *p-- = '+';
507 else if (fl & FmtSpace)
508 *p-- = ' ';
509 f->flags &= ~FmtPrec;
510 return __fmtcpy(f, p + 1, n, n + excess);
511}
512
513int __countfmt(Fmt* f) {
514 void* p;
515 ulong fl;
516
517 fl = f->flags;
518 p = va_arg(f->args, void*);
519 if (fl & FmtVLong) {
520 *(vlong*) p = f->nfmt;
521 } else if (fl & FmtLong) {
522 *(long*) p = f->nfmt;
523 } else if (fl & FmtByte) {
524 *(char*) p = f->nfmt;
525 } else if (fl & FmtShort) {
526 *(short*) p = f->nfmt;
527 } else {
528 *(int*) p = f->nfmt;
529 }
530 return 0;
531}
532
533int __flagfmt(Fmt* f) {
534 switch (f->r) {
535 case ',':
536 f->flags |= FmtComma;
537 break;
538 case '-':
539 f->flags |= FmtLeft;
540 break;
541 case '+':
542 f->flags |= FmtSign;
543 break;
544 case '#':
545 f->flags |= FmtSharp;
546 break;
547 case '\'':
548 f->flags |= FmtApost;
549 break;
550 case ' ':
551 f->flags |= FmtSpace;
552 break;
553 case 'u':
554 f->flags |= FmtUnsigned;
555 break;
556 case 'h':
557 if (f->flags & FmtShort)
558 f->flags |= FmtByte;
559 f->flags |= FmtShort;
560 break;
561 case 'L':
562 f->flags |= FmtLDouble;
563 break;
564 case 'l':
565 if (f->flags & FmtLong)
566 f->flags |= FmtVLong;
567 f->flags |= FmtLong;
568 break;
569 }
570 return 1;
571}
572
573/* default error format */
574int __badfmt(Fmt* f) {
575 char x[2 + UTFmax];
576 int n;
577
578 x[0] = '%';
579 n = 1 + runetochar(x + 1, &f->r);
580 x[n++] = '%';
581 f->prec = n;
582 __fmtcpy(f, (const void*) x, n, n);
583 return 0;
584}