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 = f->to;
18 rs = 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 = f->to;
36 s = 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 = _fmtflush(f, t, n);
45 if(t != nil)
46 s = 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 = _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 = f->to;
94 s = 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 = f->to;
109 s = 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,void * vm,int n,int sz)118 _fmtcpy(Fmt *f, 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 = 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 = f->to;
135 rs = 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 = f->to;
154 s = 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,void * vm,int n)174 _fmtrcpy(Fmt *f, 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 = 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 = f->to;
190 rs = 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 = f->to;
201 s = 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, 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, 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, x, 1);
306 }
307
308 enum {
309 /* %,#llb could emit a sign, "0b" and 64 digits with 21 commas */
310 Maxintwidth = 1 + 2 + 64 + 64/3,
311 };
312
313 /* fmt an integer */
314 int
_ifmt(Fmt * f)315 _ifmt(Fmt *f)
316 {
317 char buf[Maxintwidth + 1], *p, *conv;
318 uvlong vu;
319 ulong u;
320 uintptr pu;
321 int neg, base, i, n, fl, w, isv;
322
323 neg = 0;
324 fl = f->flags;
325 isv = 0;
326 vu = 0;
327 u = 0;
328 if(f->r == 'p'){
329 pu = va_arg(f->args, uintptr);
330 if(sizeof(uintptr) == sizeof(uvlong)){
331 vu = pu;
332 isv = 1;
333 }else
334 u = pu;
335 f->r = 'x';
336 fl |= FmtUnsigned;
337 }else if(fl & FmtVLong){
338 isv = 1;
339 if(fl & FmtUnsigned)
340 vu = va_arg(f->args, uvlong);
341 else
342 vu = va_arg(f->args, vlong);
343 }else if(fl & FmtLong){
344 if(fl & FmtUnsigned)
345 u = va_arg(f->args, ulong);
346 else
347 u = va_arg(f->args, long);
348 }else if(fl & FmtByte){
349 if(fl & FmtUnsigned)
350 u = (uchar)va_arg(f->args, int);
351 else
352 u = (char)va_arg(f->args, int);
353 }else if(fl & FmtShort){
354 if(fl & FmtUnsigned)
355 u = (ushort)va_arg(f->args, int);
356 else
357 u = (short)va_arg(f->args, int);
358 }else{
359 if(fl & FmtUnsigned)
360 u = va_arg(f->args, uint);
361 else
362 u = va_arg(f->args, int);
363 }
364 conv = "0123456789abcdef";
365 switch(f->r){
366 case 'd':
367 base = 10;
368 break;
369 case 'x':
370 base = 16;
371 break;
372 case 'X':
373 base = 16;
374 conv = "0123456789ABCDEF";
375 break;
376 case 'b':
377 base = 2;
378 break;
379 case 'o':
380 base = 8;
381 break;
382 default:
383 return -1;
384 }
385 if(!(fl & FmtUnsigned)){
386 if(isv && (vlong)vu < 0){
387 vu = -(vlong)vu;
388 neg = 1;
389 }else if(!isv && (long)u < 0){
390 u = -(long)u;
391 neg = 1;
392 }
393 }
394 p = buf + sizeof buf - 1;
395 n = 0;
396 if(isv){
397 while(vu){
398 i = vu % base;
399 vu /= base;
400 if((fl & FmtComma) && n % 4 == 3){
401 *p-- = ',';
402 n++;
403 }
404 *p-- = conv[i];
405 n++;
406 }
407 }else{
408 while(u){
409 i = u % base;
410 u /= base;
411 if((fl & FmtComma) && n % 4 == 3){
412 *p-- = ',';
413 n++;
414 }
415 *p-- = conv[i];
416 n++;
417 }
418 }
419 if(n == 0){
420 *p-- = '0';
421 n = 1;
422 }
423 for(w = f->prec; n < w && p > buf+3; n++)
424 *p-- = '0';
425 if(neg || (fl & (FmtSign|FmtSpace)))
426 n++;
427 if(fl & FmtSharp){
428 if(base == 16)
429 n += 2;
430 else if(base == 8){
431 if(p[1] == '0')
432 fl &= ~FmtSharp;
433 else
434 n++;
435 }
436 }
437 if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){
438 for(w = f->width; n < w && p > buf+3; n++)
439 *p-- = '0';
440 f->width = 0;
441 }
442 if(fl & FmtSharp){
443 if(base == 16)
444 *p-- = f->r;
445 if(base == 16 || base == 8)
446 *p-- = '0';
447 }
448 if(neg)
449 *p-- = '-';
450 else if(fl & FmtSign)
451 *p-- = '+';
452 else if(fl & FmtSpace)
453 *p-- = ' ';
454 f->flags &= ~FmtPrec;
455 return _fmtcpy(f, p + 1, n, n);
456 }
457
458 int
_countfmt(Fmt * f)459 _countfmt(Fmt *f)
460 {
461 void *p;
462 ulong fl;
463
464 fl = f->flags;
465 p = va_arg(f->args, void*);
466 if(fl & FmtVLong){
467 *(vlong*)p = f->nfmt;
468 }else if(fl & FmtLong){
469 *(long*)p = f->nfmt;
470 }else if(fl & FmtByte){
471 *(char*)p = f->nfmt;
472 }else if(fl & FmtShort){
473 *(short*)p = f->nfmt;
474 }else{
475 *(int*)p = f->nfmt;
476 }
477 return 0;
478 }
479
480 int
_flagfmt(Fmt * f)481 _flagfmt(Fmt *f)
482 {
483 switch(f->r){
484 case ',':
485 f->flags |= FmtComma;
486 break;
487 case '-':
488 f->flags |= FmtLeft;
489 break;
490 case '+':
491 f->flags |= FmtSign;
492 break;
493 case '#':
494 f->flags |= FmtSharp;
495 break;
496 case ' ':
497 f->flags |= FmtSpace;
498 break;
499 case 'u':
500 f->flags |= FmtUnsigned;
501 break;
502 case 'h':
503 if(f->flags & FmtShort)
504 f->flags |= FmtByte;
505 f->flags |= FmtShort;
506 break;
507 case 'l':
508 if(f->flags & FmtLong)
509 f->flags |= FmtVLong;
510 f->flags |= FmtLong;
511 break;
512 }
513 return 1;
514 }
515
516 /* default error format */
517 int
_badfmt(Fmt * f)518 _badfmt(Fmt *f)
519 {
520 Rune x[3];
521
522 x[0] = '%';
523 x[1] = f->r;
524 x[2] = '%';
525 f->prec = 3;
526 _fmtrcpy(f, x, 3);
527 return 0;
528 }
529