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