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