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