]> git.lizzy.rs Git - plan9front.git/blob - sys/src/ape/lib/fmt/dofmt.c
sdiahci, sdodin: avoid calling kproc() while holding ilock()
[plan9front.git] / sys / src / ape / lib / fmt / dofmt.c
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
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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                 if(sizeof(void*) == sizeof(uvlong)){
352                         isv = 1;
353                         vu = (uvlong)va_arg(f->args, void*);
354                 } else
355                         u = (ulong)va_arg(f->args, void*);
356                 f->r = 'x';
357                 fl |= FmtUnsigned;
358         }else if(fl & FmtVLong){
359                 isv = 1;
360                 if(fl & FmtUnsigned)
361                         vu = va_arg(f->args, uvlong);
362                 else
363                         vu = va_arg(f->args, vlong);
364         }else if(fl & FmtLong){
365                 if(fl & FmtUnsigned)
366                         u = va_arg(f->args, ulong);
367                 else
368                         u = va_arg(f->args, long);
369         }else if(fl & FmtByte){
370                 if(fl & FmtUnsigned)
371                         u = (uchar)va_arg(f->args, int);
372                 else
373                         u = (char)va_arg(f->args, int);
374         }else if(fl & FmtShort){
375                 if(fl & FmtUnsigned)
376                         u = (ushort)va_arg(f->args, int);
377                 else
378                         u = (short)va_arg(f->args, int);
379         }else{
380                 if(fl & FmtUnsigned)
381                         u = va_arg(f->args, uint);
382                 else
383                         u = va_arg(f->args, int);
384         }
385         conv = "0123456789abcdef";
386         switch(f->r){
387         case 'd':
388         case 'i':
389                 base = 10;
390                 break;
391         case 'u':
392                 base = 10;
393                 break;
394         case 'x':
395                 base = 16;
396                 break;
397         case 'X':
398                 base = 16;
399                 conv = "0123456789ABCDEF";
400                 break;
401         case 'b':
402                 base = 2;
403                 break;
404         case 'o':
405                 base = 8;
406                 break;
407         default:
408                 return -1;
409         }
410         if(!(fl & FmtUnsigned)){
411                 if(isv && (vlong)vu < 0){
412                         vu = -(vlong)vu;
413                         neg = 1;
414                 }else if(!isv && (long)u < 0){
415                         u = -(long)u;
416                         neg = 1;
417                 }
418         }else{
419                 fl &= ~(FmtSign|FmtSpace);      /* no + for unsigned conversions */
420         }
421         p = buf + sizeof buf - 1;
422         n = 0;
423         if(isv){
424                 while(vu){
425                         i = vu % base;
426                         vu /= base;
427                         if((fl & FmtComma) && n % 4 == 3){
428                                 *p-- = ',';
429                                 n++;
430                         }
431                         *p-- = conv[i];
432                         n++;
433                 }
434         }else{
435                 while(u){
436                         i = u % base;
437                         u /= base;
438                         if((fl & FmtComma) && n % 4 == 3){
439                                 *p-- = ',';
440                                 n++;
441                         }
442                         *p-- = conv[i];
443                         n++;
444                 }
445         }
446         if(n == 0){
447                 if(!(fl & FmtPrec) || f->prec != 0){
448                         *p-- = '0';
449                         n = 1;
450                 }
451                 fl &= ~FmtSharp;
452         }
453         for(w = f->prec; n < w && p > buf+3; n++)
454                 *p-- = '0';
455         if(neg || (fl & (FmtSign|FmtSpace)))
456                 n++;
457         if(fl & FmtSharp){
458                 if(base == 16)
459                         n += 2;
460                 else if(base == 8){
461                         if(p[1] == '0')
462                                 fl &= ~FmtSharp;
463                         else
464                                 n++;
465                 }
466         }
467         if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){
468                 for(w = f->width; n < w && p > buf+3; n++)
469                         *p-- = '0';
470                 f->width = 0;
471         }
472         if(fl & FmtSharp){
473                 if(base == 16)
474                         *p-- = f->r;
475                 if(base == 16 || base == 8)
476                         *p-- = '0';
477         }
478         if(neg)
479                 *p-- = '-';
480         else if(fl & FmtSign)
481                 *p-- = '+';
482         else if(fl & FmtSpace)
483                 *p-- = ' ';
484         f->flags &= ~FmtPrec;
485         return __fmtcpy(f, p + 1, n, n);
486 }
487
488 int
489 __countfmt(Fmt *f)
490 {
491         void *p;
492         ulong fl;
493
494         fl = f->flags;
495         p = va_arg(f->args, void*);
496         if(fl & FmtVLong){
497                 *(vlong*)p = f->nfmt;
498         }else if(fl & FmtLong){
499                 *(long*)p = f->nfmt;
500         }else if(fl & FmtByte){
501                 *(char*)p = f->nfmt;
502         }else if(fl & FmtShort){
503                 *(short*)p = f->nfmt;
504         }else{
505                 *(int*)p = f->nfmt;
506         }
507         return 0;
508 }
509
510 int
511 __flagfmt(Fmt *f)
512 {
513         switch(f->r){
514         case ',':
515                 f->flags |= FmtComma;
516                 break;
517         case '-':
518                 f->flags |= FmtLeft;
519                 break;
520         case '+':
521                 f->flags |= FmtSign;
522                 break;
523         case '#':
524                 f->flags |= FmtSharp;
525                 break;
526         case ' ':
527                 f->flags |= FmtSpace;
528                 break;
529         case 'u':
530                 f->flags |= FmtUnsigned;
531                 break;
532         case 'h':
533                 if(f->flags & FmtShort)
534                         f->flags |= FmtByte;
535                 f->flags |= FmtShort;
536                 break;
537         case 'L':
538                 f->flags |= FmtLDouble;
539                 break;
540         case 'l':
541                 if(f->flags & FmtLong)
542                         f->flags |= FmtVLong;
543                 f->flags |= FmtLong;
544                 break;
545         case 'z':
546                 f->flags |= FmtLong;
547                 if(sizeof(size_t) == sizeof(vlong))
548                         f->flags |= FmtVLong;
549                 break;
550         }
551         return 1;
552 }
553
554 /* default error format */
555 int
556 __badfmt(Fmt *f)
557 {
558         char x[2+UTFmax];
559         Rune r;
560         int n;
561
562         r = f->r;
563         x[0] = '%';
564         n = 1+runetochar(x+1, &r);
565         x[n++] = '%';
566         f->prec = n;
567         __fmtcpy(f, x, n, n);
568         return 0;
569 }