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"
19
20 /* format the output into f->to and return the number of characters fmted */
21 int
dofmt(Fmt * f,char * fmt)22 dofmt(Fmt *f, char *fmt)
23 {
24 Rune rune, *rt, *rs;
25 int r;
26 char *t, *s;
27 int n, nfmt;
28
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 }
76
77 fmt = (char*)__fmtdispatch(f, fmt, 0);
78 if(fmt == nil)
79 return -1;
80 }
81 }
82
83 void *
__fmtflush(Fmt * f,void * t,int len)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 }
97
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
__fmtpad(Fmt * f,int n)103 __fmtpad(Fmt *f, int n)
104 {
105 char *t, *s;
106 int i;
107
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;
115 }
116
117 int
__rfmtpad(Fmt * f,int n)118 __rfmtpad(Fmt *f, int n)
119 {
120 Rune *t, *s;
121 int i;
122
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;
130 }
131
132 int
__fmtcpy(Fmt * f,const void * vm,int n,int sz)133 __fmtcpy(Fmt *f, const void *vm, int n, int sz)
134 {
135 Rune *rt, *rs, r;
136 char *t, *s, *m, *me;
137 ulong fl;
138 int nc, w;
139
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);
160 }
161 f->nfmt += rt - (Rune *)f->to;
162 f->to = rt;
163 if(m < me)
164 return -1;
165 if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
166 return -1;
167 }else{
168 if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
169 return -1;
170 t = (char*)f->to;
171 s = (char*)f->stop;
172 for(nc = n; nc > 0; nc--){
173 r = *(uchar*)m;
174 if(r < Runeself)
175 m++;
176 else if((me - m) >= UTFmax || fullrune(m, me-m))
177 m += chartorune(&r, m);
178 else
179 break;
180 FMTRUNE(f, t, s, r);
181 }
182 f->nfmt += t - (char *)f->to;
183 f->to = t;
184 if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
185 return -1;
186 }
187 return 0;
188 }
189
190 int
__fmtrcpy(Fmt * f,const void * vm,int n)191 __fmtrcpy(Fmt *f, const void *vm, int n)
192 {
193 Rune r, *m, *me, *rt, *rs;
194 char *t, *s;
195 ulong fl;
196 int w;
197
198 m = (Rune*)vm;
199 w = f->width;
200 fl = f->flags;
201 if((fl & FmtPrec) && n > f->prec)
202 n = f->prec;
203 if(f->runes){
204 if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
205 return -1;
206 rt = (Rune*)f->to;
207 rs = (Rune*)f->stop;
208 for(me = m + n; m < me; m++)
209 FMTRCHAR(f, rt, rs, *m);
210 f->nfmt += rt - (Rune *)f->to;
211 f->to = rt;
212 if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
213 return -1;
214 }else{
215 if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
216 return -1;
217 t = (char*)f->to;
218 s = (char*)f->stop;
219 for(me = m + n; m < me; m++){
220 r = *m;
221 FMTRUNE(f, t, s, r);
222 }
223 f->nfmt += t - (char *)f->to;
224 f->to = t;
225 if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
226 return -1;
227 }
228 return 0;
229 }
230
231 /* fmt out one character */
232 int
__charfmt(Fmt * f)233 __charfmt(Fmt *f)
234 {
235 char x[1];
236
237 x[0] = va_arg(f->args, int);
238 f->prec = 1;
239 return __fmtcpy(f, (const char*)x, 1, 1);
240 }
241
242 /* fmt out one rune */
243 int
__runefmt(Fmt * f)244 __runefmt(Fmt *f)
245 {
246 Rune x[1];
247
248 x[0] = va_arg(f->args, int);
249 return __fmtrcpy(f, (const void*)x, 1);
250 }
251
252 /* public helper routine: fmt out a null terminated string already in hand */
253 int
fmtstrcpy(Fmt * f,char * s)254 fmtstrcpy(Fmt *f, char *s)
255 {
256 int p, i;
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 p = f->prec;
262 for(i = 0; i < p; i++)
263 if(s[i] == 0)
264 break;
265 return __fmtcpy(f, s, utfnlen(s, i), i); /* BUG?: won't print a partial rune at end */
266 }
267
268 return __fmtcpy(f, s, utflen(s), strlen(s));
269 }
270
271 /* fmt out a null terminated utf string */
272 int
__strfmt(Fmt * f)273 __strfmt(Fmt *f)
274 {
275 char *s;
276
277 s = va_arg(f->args, char *);
278 return fmtstrcpy(f, s);
279 }
280
281 /* public helper routine: fmt out a null terminated rune string already in hand */
282 int
fmtrunestrcpy(Fmt * f,Rune * s)283 fmtrunestrcpy(Fmt *f, Rune *s)
284 {
285 Rune *e;
286 int n, p;
287
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++)
298 ;
299 n = e - s;
300 }
301 return __fmtrcpy(f, s, n);
302 }
303
304 /* fmt out a null terminated rune string */
305 int
__runesfmt(Fmt * f)306 __runesfmt(Fmt *f)
307 {
308 Rune *s;
309
310 s = va_arg(f->args, Rune *);
311 return fmtrunestrcpy(f, s);
312 }
313
314 /* fmt a % */
315 int
__percentfmt(Fmt * f)316 __percentfmt(Fmt *f)
317 {
318 Rune x[1];
319
320 x[0] = f->r;
321 f->prec = 1;
322 return __fmtrcpy(f, (const void*)x, 1);
323 }
324
325 /* fmt an integer */
326 int
__ifmt(Fmt * f)327 __ifmt(Fmt *f)
328 {
329 char buf[70], *p, *conv;
330 uvlong vu;
331 ulong u;
332 int neg, base, i, n, fl, w, isv;
333
334 neg = 0;
335 fl = f->flags;
336 isv = 0;
337 vu = 0;
338 u = 0;
339 /*
340 * Unsigned verbs
341 */
342 switch(f->r){
343 case 'o':
344 case 'u':
345 case 'x':
346 case 'X':
347 fl |= FmtUnsigned;
348 break;
349 }
350 if(f->r == 'p'){
351 u = (ulong)va_arg(f->args, void*);
352 f->r = 'x';
353 fl |= FmtUnsigned;
354 }else if(fl & FmtVLong){
355 isv = 1;
356 if(fl & FmtUnsigned)
357 vu = va_arg(f->args, uvlong);
358 else
359 vu = va_arg(f->args, vlong);
360 }else if(fl & FmtLong){
361 if(fl & FmtUnsigned)
362 u = va_arg(f->args, ulong);
363 else
364 u = va_arg(f->args, long);
365 }else if(fl & FmtByte){
366 if(fl & FmtUnsigned)
367 u = (uchar)va_arg(f->args, int);
368 else
369 u = (char)va_arg(f->args, int);
370 }else if(fl & FmtShort){
371 if(fl & FmtUnsigned)
372 u = (ushort)va_arg(f->args, int);
373 else
374 u = (short)va_arg(f->args, int);
375 }else{
376 if(fl & FmtUnsigned)
377 u = va_arg(f->args, uint);
378 else
379 u = va_arg(f->args, int);
380 }
381 conv = "0123456789abcdef";
382 switch(f->r){
383 case 'd':
384 case 'i':
385 base = 10;
386 break;
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;
405 }
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;
413 }
414 }else{
415 fl &= ~(FmtSign|FmtSpace); /* no + for unsigned conversions */
416 }
417 p = buf + sizeof buf - 1;
418 n = 0;
419 if(isv){
420 while(vu){
421 i = vu % base;
422 vu /= base;
423 if((fl & FmtComma) && n % 4 == 3){
424 *p-- = ',';
425 n++;
426 }
427 *p-- = conv[i];
428 n++;
429 }
430 }else{
431 while(u){
432 i = u % base;
433 u /= base;
434 if((fl & FmtComma) && n % 4 == 3){
435 *p-- = ',';
436 n++;
437 }
438 *p-- = conv[i];
439 n++;
440 }
441 }
442 if(n == 0){
443 if(!(fl & FmtPrec) || f->prec != 0){
444 *p-- = '0';
445 n = 1;
446 }
447 fl &= ~FmtSharp;
448 }
449 for(w = f->prec; n < w && p > buf+3; n++)
450 *p-- = '0';
451 if(neg || (fl & (FmtSign|FmtSpace)))
452 n++;
453 if(fl & FmtSharp){
454 if(base == 16)
455 n += 2;
456 else if(base == 8){
457 if(p[1] == '0')
458 fl &= ~FmtSharp;
459 else
460 n++;
461 }
462 }
463 if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){
464 for(w = f->width; n < w && p > buf+3; n++)
465 *p-- = '0';
466 f->width = 0;
467 }
468 if(fl & FmtSharp){
469 if(base == 16)
470 *p-- = f->r;
471 if(base == 16 || base == 8)
472 *p-- = '0';
473 }
474 if(neg)
475 *p-- = '-';
476 else if(fl & FmtSign)
477 *p-- = '+';
478 else if(fl & FmtSpace)
479 *p-- = ' ';
480 f->flags &= ~FmtPrec;
481 return __fmtcpy(f, p + 1, n, n);
482 }
483
484 int
__countfmt(Fmt * f)485 __countfmt(Fmt *f)
486 {
487 void *p;
488 ulong fl;
489
490 fl = f->flags;
491 p = va_arg(f->args, void*);
492 if(fl & FmtVLong){
493 *(vlong*)p = f->nfmt;
494 }else if(fl & FmtLong){
495 *(long*)p = f->nfmt;
496 }else if(fl & FmtByte){
497 *(char*)p = f->nfmt;
498 }else if(fl & FmtShort){
499 *(short*)p = f->nfmt;
500 }else{
501 *(int*)p = f->nfmt;
502 }
503 return 0;
504 }
505
506 int
__flagfmt(Fmt * f)507 __flagfmt(Fmt *f)
508 {
509 switch(f->r){
510 case ',':
511 f->flags |= FmtComma;
512 break;
513 case '-':
514 f->flags |= FmtLeft;
515 break;
516 case '+':
517 f->flags |= FmtSign;
518 break;
519 case '#':
520 f->flags |= FmtSharp;
521 break;
522 case ' ':
523 f->flags |= FmtSpace;
524 break;
525 case 'u':
526 f->flags |= FmtUnsigned;
527 break;
528 case 'h':
529 if(f->flags & FmtShort)
530 f->flags |= FmtByte;
531 f->flags |= FmtShort;
532 break;
533 case 'L':
534 f->flags |= FmtLDouble;
535 break;
536 case 'l':
537 if(f->flags & FmtLong)
538 f->flags |= FmtVLong;
539 f->flags |= FmtLong;
540 break;
541 }
542 return 1;
543 }
544
545 /* default error format */
546 int
__badfmt(Fmt * f)547 __badfmt(Fmt *f)
548 {
549 char x[3];
550
551 x[0] = '%';
552 x[1] = f->r;
553 x[2] = '%';
554 f->prec = 3;
555 __fmtcpy(f, (const void*)x, 3, 3);
556 return 0;
557 }
558