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 ANY
11 * 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 "utf.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 return 0; /* not reached */
82 }
84 void *
85 __fmtflush(Fmt *f, void *t, int len)
86 {
87 if(f->runes)
88 f->nfmt += (Rune*)t - (Rune*)f->to;
89 else
90 f->nfmt += (char*)t - (char *)f->to;
91 f->to = t;
92 if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){
93 f->stop = f->to;
94 return nil;
95 }
96 return f->to;
97 }
99 /*
100 * put a formatted block of memory sz bytes long of n runes into the output buffer,
101 * left/right justified in a field of at least f->width charactes
102 */
103 int
104 __fmtpad(Fmt *f, int n)
106 char *t, *s;
107 int i;
109 t = (char*)f->to;
110 s = (char*)f->stop;
111 for(i = 0; i < n; i++)
112 FMTCHAR(f, t, s, ' ');
113 f->nfmt += t - (char *)f->to;
114 f->to = t;
115 return 0;
118 int
119 __rfmtpad(Fmt *f, int n)
121 Rune *t, *s;
122 int i;
124 t = (Rune*)f->to;
125 s = (Rune*)f->stop;
126 for(i = 0; i < n; i++)
127 FMTRCHAR(f, t, s, ' ');
128 f->nfmt += t - (Rune *)f->to;
129 f->to = t;
130 return 0;
133 int
134 __fmtcpy(Fmt *f, const void *vm, int n, int sz)
136 Rune *rt, *rs, r;
137 char *t, *s, *m, *me;
138 ulong fl;
139 int nc, w;
141 m = (char*)vm;
142 me = m + sz;
143 w = f->width;
144 fl = f->flags;
145 if((fl & FmtPrec) && n > f->prec)
146 n = f->prec;
147 if(f->runes){
148 if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
149 return -1;
150 rt = (Rune*)f->to;
151 rs = (Rune*)f->stop;
152 for(nc = n; nc > 0; nc--){
153 r = *(uchar*)m;
154 if(r < Runeself)
155 m++;
156 else if((me - m) >= UTFmax || fullrune(m, me-m))
157 m += chartorune(&r, m);
158 else
159 break;
160 FMTRCHAR(f, rt, rs, r);
162 f->nfmt += rt - (Rune *)f->to;
163 f->to = rt;
164 if(m < me)
165 return -1;
166 if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
167 return -1;
168 }else{
169 if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
170 return -1;
171 t = (char*)f->to;
172 s = (char*)f->stop;
173 for(nc = n; nc > 0; nc--){
174 r = *(uchar*)m;
175 if(r < Runeself)
176 m++;
177 else if((me - m) >= UTFmax || fullrune(m, me-m))
178 m += chartorune(&r, m);
179 else
180 break;
181 FMTRUNE(f, t, s, r);
183 f->nfmt += t - (char *)f->to;
184 f->to = t;
185 if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
186 return -1;
188 return 0;
191 int
192 __fmtrcpy(Fmt *f, const void *vm, int n)
194 Rune r, *m, *me, *rt, *rs;
195 char *t, *s;
196 ulong fl;
197 int w;
199 m = (Rune*)vm;
200 w = f->width;
201 fl = f->flags;
202 if((fl & FmtPrec) && n > f->prec)
203 n = f->prec;
204 if(f->runes){
205 if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
206 return -1;
207 rt = (Rune*)f->to;
208 rs = (Rune*)f->stop;
209 for(me = m + n; m < me; m++)
210 FMTRCHAR(f, rt, rs, *m);
211 f->nfmt += rt - (Rune *)f->to;
212 f->to = rt;
213 if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
214 return -1;
215 }else{
216 if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
217 return -1;
218 t = (char*)f->to;
219 s = (char*)f->stop;
220 for(me = m + n; m < me; m++){
221 r = *m;
222 FMTRUNE(f, t, s, r);
224 f->nfmt += t - (char *)f->to;
225 f->to = t;
226 if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
227 return -1;
229 return 0;
232 /* fmt out one character */
233 int
234 __charfmt(Fmt *f)
236 char x[1];
238 x[0] = va_arg(f->args, int);
239 f->prec = 1;
240 return __fmtcpy(f, (const char*)x, 1, 1);
243 /* fmt out one rune */
244 int
245 __runefmt(Fmt *f)
247 Rune x[1];
249 x[0] = va_arg(f->args, int);
250 return __fmtrcpy(f, (const void*)x, 1);
253 /* public helper routine: fmt out a null terminated string already in hand */
254 int
255 fmtstrcpy(Fmt *f, char *s)
257 int p, i;
258 if(!s)
259 return __fmtcpy(f, "<nil>", 5, 5);
260 /* if precision is specified, make sure we don't wander off the end */
261 if(f->flags & FmtPrec){
262 p = f->prec;
263 for(i = 0; i < p; i++)
264 if(s[i] == 0)
265 break;
266 return __fmtcpy(f, s, utfnlen(s, i), i); /* BUG?: won't print a partial rune at end */
269 return __fmtcpy(f, s, utflen(s), strlen(s));
272 /* fmt out a null terminated utf string */
273 int
274 __strfmt(Fmt *f)
276 char *s;
278 s = va_arg(f->args, char *);
279 return fmtstrcpy(f, s);
282 /* public helper routine: fmt out a null terminated rune string already in hand */
283 int
284 fmtrunestrcpy(Fmt *f, Rune *s)
286 Rune *e;
287 int n, p;
289 if(!s)
290 return __fmtcpy(f, "<nil>", 5, 5);
291 /* if precision is specified, make sure we don't wander off the end */
292 if(f->flags & FmtPrec){
293 p = f->prec;
294 for(n = 0; n < p; n++)
295 if(s[n] == 0)
296 break;
297 }else{
298 for(e = s; *e; e++)
300 n = e - s;
302 return __fmtrcpy(f, s, n);
305 /* fmt out a null terminated rune string */
306 int
307 __runesfmt(Fmt *f)
309 Rune *s;
311 s = va_arg(f->args, Rune *);
312 return fmtrunestrcpy(f, s);
315 /* fmt a % */
316 int
317 __percentfmt(Fmt *f)
319 Rune x[1];
321 x[0] = f->r;
322 f->prec = 1;
323 return __fmtrcpy(f, (const void*)x, 1);
326 /* fmt an integer */
327 int
328 __ifmt(Fmt *f)
330 char buf[70], *p, *conv;
331 uvlong vu;
332 ulong u;
333 int neg, base, i, n, fl, w, isv;
335 neg = 0;
336 fl = f->flags;
337 isv = 0;
338 vu = 0;
339 u = 0;
340 /*
341 * Unsigned verbs
342 */
343 switch(f->r){
344 case 'o':
345 case 'u':
346 case 'x':
347 case 'X':
348 fl |= FmtUnsigned;
349 break;
351 if(f->r == 'p'){
352 u = (ulong)va_arg(f->args, void*);
353 f->r = 'x';
354 fl |= FmtUnsigned;
355 }else if(fl & FmtVLong){
356 isv = 1;
357 if(fl & FmtUnsigned)
358 vu = va_arg(f->args, uvlong);
359 else
360 vu = va_arg(f->args, vlong);
361 }else if(fl & FmtLong){
362 if(fl & FmtUnsigned)
363 u = va_arg(f->args, ulong);
364 else
365 u = va_arg(f->args, long);
366 }else if(fl & FmtByte){
367 if(fl & FmtUnsigned)
368 u = (uchar)va_arg(f->args, int);
369 else
370 u = (char)va_arg(f->args, int);
371 }else if(fl & FmtShort){
372 if(fl & FmtUnsigned)
373 u = (ushort)va_arg(f->args, int);
374 else
375 u = (short)va_arg(f->args, int);
376 }else{
377 if(fl & FmtUnsigned)
378 u = va_arg(f->args, uint);
379 else
380 u = va_arg(f->args, int);
382 conv = "0123456789abcdef";
383 switch(f->r){
384 case 'd':
385 case 'i':
386 base = 10;
387 break;
388 case 'u':
389 base = 10;
390 break;
391 case 'x':
392 base = 16;
393 break;
394 case 'X':
395 base = 16;
396 conv = "0123456789ABCDEF";
397 break;
398 case 'b':
399 base = 2;
400 break;
401 case 'o':
402 base = 8;
403 break;
404 default:
405 return -1;
407 if(!(fl & FmtUnsigned)){
408 if(isv && (vlong)vu < 0){
409 vu = -(vlong)vu;
410 neg = 1;
411 }else if(!isv && (long)u < 0){
412 u = -(long)u;
413 neg = 1;
415 }else{
416 fl &= ~(FmtSign|FmtSpace); /* no + for unsigned conversions */
418 p = buf + sizeof buf - 1;
419 n = 0;
420 if(isv){
421 while(vu){
422 i = vu % base;
423 vu /= base;
424 if((fl & FmtComma) && n % 4 == 3){
425 *p-- = ',';
426 n++;
428 *p-- = conv[i];
429 n++;
431 }else{
432 while(u){
433 i = u % base;
434 u /= base;
435 if((fl & FmtComma) && n % 4 == 3){
436 *p-- = ',';
437 n++;
439 *p-- = conv[i];
440 n++;
443 if(n == 0){
444 if(!(fl & FmtPrec) || f->prec != 0){
445 *p-- = '0';
446 n = 1;
448 fl &= ~FmtSharp;
450 for(w = f->prec; n < w && p > buf+3; n++)
451 *p-- = '0';
452 if(neg || (fl & (FmtSign|FmtSpace)))
453 n++;
454 if(fl & FmtSharp){
455 if(base == 16)
456 n += 2;
457 else if(base == 8){
458 if(p[1] == '0')
459 fl &= ~FmtSharp;
460 else
461 n++;
464 if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){
465 for(w = f->width; n < w && p > buf+3; n++)
466 *p-- = '0';
467 f->width = 0;
469 if(fl & FmtSharp){
470 if(base == 16)
471 *p-- = f->r;
472 if(base == 16 || base == 8)
473 *p-- = '0';
475 if(neg)
476 *p-- = '-';
477 else if(fl & FmtSign)
478 *p-- = '+';
479 else if(fl & FmtSpace)
480 *p-- = ' ';
481 f->flags &= ~FmtPrec;
482 return __fmtcpy(f, p + 1, n, n);
485 int
486 __countfmt(Fmt *f)
488 void *p;
489 ulong fl;
491 fl = f->flags;
492 p = va_arg(f->args, void*);
493 if(fl & FmtVLong){
494 *(vlong*)p = f->nfmt;
495 }else if(fl & FmtLong){
496 *(long*)p = f->nfmt;
497 }else if(fl & FmtByte){
498 *(char*)p = f->nfmt;
499 }else if(fl & FmtShort){
500 *(short*)p = f->nfmt;
501 }else{
502 *(int*)p = f->nfmt;
504 return 0;
507 int
508 __flagfmt(Fmt *f)
510 switch(f->r){
511 case ',':
512 f->flags |= FmtComma;
513 break;
514 case '-':
515 f->flags |= FmtLeft;
516 break;
517 case '+':
518 f->flags |= FmtSign;
519 break;
520 case '#':
521 f->flags |= FmtSharp;
522 break;
523 case ' ':
524 f->flags |= FmtSpace;
525 break;
526 case 'u':
527 f->flags |= FmtUnsigned;
528 break;
529 case 'h':
530 if(f->flags & FmtShort)
531 f->flags |= FmtByte;
532 f->flags |= FmtShort;
533 break;
534 case 'L':
535 f->flags |= FmtLDouble;
536 break;
537 case 'l':
538 if(f->flags & FmtLong)
539 f->flags |= FmtVLong;
540 f->flags |= FmtLong;
541 break;
543 return 1;
546 /* default error format */
547 int
548 __badfmt(Fmt *f)
550 char x[3];
552 x[0] = '%';
553 x[1] = f->r;
554 x[2] = '%';
555 f->prec = 3;
556 __fmtcpy(f, (const void*)x, 3, 3);
557 return 0;