Blob


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