Blob


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