]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libc/arm/doprint.xc
pool: do poolcheck when free nodes get corrupted instead of assert
[plan9front.git] / sys / src / libc / arm / doprint.xc
1 #include        <u.h>
2 #include        <libc.h>
3
4 enum
5 {
6         SIZE    = 1024,
7         IDIGIT  = 40,
8         MAXCONV = 40,
9         FDIGIT  = 30,
10         FDEFLT  = 6,
11         NONE    = -1000,
12         MAXFMT  = 512,
13
14         FPLUS   = 1<<0,
15         FMINUS  = 1<<1,
16         FSHARP  = 1<<2,
17         FLONG   = 1<<3,
18         FSHORT  = 1<<4,
19         FUNSIGN = 1<<5,
20         FVLONG  = 1<<6,
21 };
22
23 int     printcol;
24
25 static  int     convcount;
26 static  char    fmtindex[MAXFMT];
27
28 static  int     noconv(va_list*, Fconv*);
29 static  int     flags(va_list*, Fconv*);
30
31 static  int     cconv(va_list*, Fconv*);
32 static  int     rconv(va_list*, Fconv*);
33 static  int     sconv(va_list*, Fconv*);
34 static  int     percent(va_list*, Fconv*);
35 static  int     column(va_list*, Fconv*);
36
37 int     numbconv(va_list*, Fconv*);
38
39 static
40 int     (*fmtconv[MAXCONV])(va_list*, Fconv*) =
41 {
42         noconv
43 };
44
45 static
46 void
47 initfmt(void)
48 {
49         int cc;
50
51         cc = 0;
52         fmtconv[cc] = noconv;
53         cc++;
54
55         fmtconv[cc] = flags;
56         fmtindex['+'] = cc;
57         fmtindex['-'] = cc;
58         fmtindex['#'] = cc;
59         fmtindex['h'] = cc;
60         fmtindex['l'] = cc;
61         fmtindex['u'] = cc;
62         cc++;
63
64         fmtconv[cc] = numbconv;
65         fmtindex['d'] = cc;
66         fmtindex['o'] = cc;
67         fmtindex['x'] = cc;
68         fmtindex['X'] = cc;
69         cc++;
70
71         fmtconv[cc] = cconv;
72         fmtindex['c'] = cc;
73         fmtindex['C'] = cc;
74         cc++;
75
76         fmtconv[cc] = rconv;
77         fmtindex['r'] = cc;
78         cc++;
79
80         fmtconv[cc] = sconv;
81         fmtindex['s'] = cc;
82         fmtindex['S'] = cc;
83         cc++;
84
85         fmtconv[cc] = percent;
86         fmtindex['%'] = cc;
87         cc++;
88
89         fmtconv[cc] = column;
90         fmtindex['|'] = cc;
91         cc++;
92
93         convcount = cc;
94 }
95
96 int
97 fmtinstall(int c, int (*f)(va_list*, Fconv*))
98 {
99
100         if(convcount == 0)
101                 initfmt();
102         if(c < 0 || c >= MAXFMT)
103                 return -1;
104         if(convcount >= MAXCONV)
105                 return -1;
106         fmtconv[convcount] = f;
107         fmtindex[c] = convcount;
108         convcount++;
109         return 0;
110 }
111
112 char*
113 doprint(char *s, char *es, char *fmt, va_list argp)
114 {
115         int n, c;
116         Rune rune;
117         Fconv local;
118
119         if(s >= es)
120                 return s;
121         local.out = s;
122         local.eout = es-UTFmax-1;
123
124 loop:
125         c = *fmt & 0xff;
126         if(c >= Runeself) {
127                 n = chartorune(&rune, fmt);
128                 fmt += n;
129                 c = rune;
130         } else
131                 fmt++;
132         switch(c) {
133         case 0:
134                 *local.out = 0;
135                 return local.out;
136         
137         default:
138                 printcol++;
139                 goto common;
140
141         case '\n':
142                 printcol = 0;
143                 goto common;
144
145         case '\t':
146                 printcol = (printcol+8) & ~7;
147                 goto common;
148
149         common:
150                 if(local.out < local.eout)
151                         if(c >= Runeself) {
152                                 rune = c;
153                                 n = runetochar(local.out, &rune);
154                                 local.out += n;
155                         } else
156                                 *local.out++ = c;
157                 goto loop;
158
159         case '%':
160                 break;
161         }
162         local.f1 = NONE;
163         local.f2 = NONE;
164         local.f3 = 0;
165
166         /*
167          * read one of the following
168          *      1. number, => f1, f2 in order.
169          *      2. '*' same as number (from args)
170          *      3. '.' ignored (separates numbers)
171          *      4. flag => f3
172          *      5. verb and terminate
173          */
174 l0:
175         c = *fmt & 0xff;
176         if(c >= Runeself) {
177                 n = chartorune(&rune, fmt);
178                 fmt += n;
179                 c = rune;
180         } else
181                 fmt++;
182
183 l1:
184         if(c == 0) {
185                 fmt--;
186                 goto loop;
187         }
188         if(c == '.') {
189                 if(local.f1 == NONE)
190                         local.f1 = 0;
191                 local.f2 = 0;
192                 goto l0;
193         }
194         if((c >= '1' && c <= '9') ||
195            (c == '0' && local.f1 != NONE)) {    /* '0' is a digit for f2 */
196                 n = 0;
197                 while(c >= '0' && c <= '9') {
198                         n = n*10 + c-'0';
199                         c = *fmt++;
200                 }
201                 if(local.f1 == NONE)
202                         local.f1 = n;
203                 else
204                         local.f2 = n;
205                 goto l1;
206         }
207         if(c == '*') {
208                 n = va_arg(argp, int);
209                 if(local.f1 == NONE)
210                         local.f1 = n;
211                 else
212                         local.f2 = n;
213                 goto l0;
214         }
215         n = 0;
216         if(c >= 0 && c < MAXFMT)
217                 n = fmtindex[c];
218         local.chr = c;
219         n = (*fmtconv[n])(&argp, &local);
220         if(n < 0) {
221                 local.f3 |= -n;
222                 goto l0;
223         }
224         goto loop;
225 }
226
227 int
228 numbconv(va_list *arg, Fconv *fp)
229 {
230         char s[IDIGIT];
231         int i, f, n, b, ucase;
232         short h;
233         long v;
234         vlong vl;
235
236         SET(v);
237         SET(vl);
238
239         ucase = 0;
240         b = fp->chr;
241         switch(fp->chr) {
242         case 'u':
243                 fp->f3 |= FUNSIGN;
244         case 'd':
245                 b = 10;
246                 break;
247
248         case 'o':
249                 b = 8;
250                 break;
251
252         case 'X':
253                 ucase = 1;
254         case 'x':
255                 b = 16;
256                 break;
257         }
258
259         f = 0;
260         switch(fp->f3 & (FVLONG|FLONG|FSHORT|FUNSIGN)) {
261         case FVLONG|FLONG:
262                 vl = va_arg(*arg, vlong);
263                 break;
264
265         case FUNSIGN|FVLONG|FLONG:
266                 vl = va_arg(*arg, uvlong);
267                 break;
268
269         case FLONG:
270                 v = va_arg(*arg, long);
271                 break;
272
273         case FUNSIGN|FLONG:
274                 v = va_arg(*arg, ulong);
275                 break;
276
277         case FSHORT:
278                 h = va_arg(*arg, int);
279                 v = h;
280                 break;
281
282         case FUNSIGN|FSHORT:
283                 h = va_arg(*arg, int);
284                 v = (ushort)h;
285                 break;
286
287         default:
288                 v = va_arg(*arg, int);
289                 break;
290
291         case FUNSIGN:
292                 v = va_arg(*arg, unsigned);
293                 break;
294         }
295         if(fp->f3 & FVLONG) {
296                 if(!(fp->f3 & FUNSIGN) && vl < 0) {
297                         vl = -vl;
298                         f = 1;
299                 }
300         } else {
301                 if(!(fp->f3 & FUNSIGN) && v < 0) {
302                         v = -v;
303                         f = 1;
304                 }
305         }
306         s[IDIGIT-1] = 0;
307         for(i = IDIGIT-2;; i--) {
308                 if(fp->f3 & FVLONG)
309                         n = (uvlong)vl % b;
310                 else
311                         n = (ulong)v % b;
312                 n += '0';
313                 if(n > '9') {
314                         n += 'a' - ('9'+1);
315                         if(ucase)
316                                 n += 'A'-'a';
317                 }
318                 s[i] = n;
319                 if(i < 2)
320                         break;
321                 if(fp->f3 & FVLONG)
322                         vl = (uvlong)vl / b;
323                 else
324                         v = (ulong)v / b;
325                 if(fp->f2 != NONE && i >= IDIGIT-fp->f2)
326                         continue;
327                 if(fp->f3 & FVLONG) {
328                         if(vl <= 0)
329                                 break;
330                         continue;
331                 }
332                 if(v <= 0)
333                         break;
334         }
335
336         if(fp->f3 & FSHARP) {
337                 if(b == 8 && s[i] != '0')
338                         s[--i] = '0';
339                 if(b == 16) {
340                         if(ucase)
341                                 s[--i] = 'X';
342                         else
343                                 s[--i] = 'x';
344                         s[--i] = '0';
345                 }
346         }
347         if(f)
348                 s[--i] = '-';
349         fp->f2 = NONE;
350         strconv(s+i, fp);
351         return 0;
352 }
353
354 void
355 Strconv(Rune *s, Fconv *fp)
356 {
357         int n, c, i;
358         Rune rune;
359
360         if(fp->f3 & FMINUS)
361                 fp->f1 = -fp->f1;
362         n = 0;
363         if(fp->f1 != NONE && fp->f1 >= 0) {
364                 for(; s[n]; n++)
365                         ;
366                 while(n < fp->f1) {
367                         if(fp->out < fp->eout)
368                                 *fp->out++ = ' ';
369                         printcol++;
370                         n++;
371                 }
372         }
373         for(;;) {
374                 c = *s++;
375                 if(c == 0)
376                         break;
377                 n++;
378                 if(fp->f2 == NONE || fp->f2 > 0) {
379                         if(fp->out < fp->eout)
380                                 if(c >= Runeself) {
381                                         rune = c;
382                                         i = runetochar(fp->out, &rune);
383                                         fp->out += i;
384                                 } else
385                                         *fp->out++ = c;
386                         if(fp->f2 != NONE)
387                                 fp->f2--;
388                         switch(c) {
389                         default:
390                                 printcol++;
391                                 break;
392                         case '\n':
393                                 printcol = 0;
394                                 break;
395                         case '\t':
396                                 printcol = (printcol+8) & ~7;
397                                 break;
398                         }
399                 }
400         }
401         if(fp->f1 != NONE && fp->f1 < 0) {
402                 fp->f1 = -fp->f1;
403                 while(n < fp->f1) {
404                         if(fp->out < fp->eout)
405                                 *fp->out++ = ' ';
406                         printcol++;
407                         n++;
408                 }
409         }
410 }
411
412 void
413 strconv(char *s, Fconv *fp)
414 {
415         int n, c, i;
416         Rune rune;
417
418         if(fp->f3 & FMINUS)
419                 fp->f1 = -fp->f1;
420         n = 0;
421         if(fp->f1 != NONE && fp->f1 >= 0) {
422                 n = utflen(s);
423                 while(n < fp->f1) {
424                         if(fp->out < fp->eout)
425                                 *fp->out++ = ' ';
426                         printcol++;
427                         n++;
428                 }
429         }
430         for(;;) {
431                 c = *s & 0xff;
432                 if(c >= Runeself) {
433                         i = chartorune(&rune, s);
434                         s += i;
435                         c = rune;
436                 } else
437                         s++;
438                 if(c == 0)
439                         break;
440                 n++;
441                 if(fp->f2 == NONE || fp->f2 > 0) {
442                         if(fp->out < fp->eout)
443                                 if(c >= Runeself) {
444                                         rune = c;
445                                         i = runetochar(fp->out, &rune);
446                                         fp->out += i;
447                                 } else
448                                         *fp->out++ = c;
449                         if(fp->f2 != NONE)
450                                 fp->f2--;
451                         switch(c) {
452                         default:
453                                 printcol++;
454                                 break;
455                         case '\n':
456                                 printcol = 0;
457                                 break;
458                         case '\t':
459                                 printcol = (printcol+8) & ~7;
460                                 break;
461                         }
462                 }
463         }
464         if(fp->f1 != NONE && fp->f1 < 0) {
465                 fp->f1 = -fp->f1;
466                 while(n < fp->f1) {
467                         if(fp->out < fp->eout)
468                                 *fp->out++ = ' ';
469                         printcol++;
470                         n++;
471                 }
472         }
473 }
474
475 static
476 int
477 noconv(va_list *arg, Fconv *fp)
478 {
479         int n;
480         char s[10];
481
482         if(convcount == 0) {
483                 initfmt();
484                 n = 0;
485                 if(fp->chr >= 0 && fp->chr < MAXFMT)
486                         n = fmtindex[fp->chr];
487                 return (*fmtconv[n])(arg, fp);
488         }
489         s[0] = '*';
490         s[1] = fp->chr;
491         s[2] = '*';
492         s[3] = 0;
493         fp->f1 = 0;
494         fp->f2 = NONE;
495         fp->f3 = 0;
496         strconv(s, fp);
497         return 0;
498 }
499
500 static
501 int
502 rconv(va_list*, Fconv *fp)
503 {
504         char s[ERRLEN];
505
506         s[0] = 0;
507         errstr(s);
508         fp->f2 = NONE;
509         strconv(s, fp);
510         return 0;
511 }
512
513 static
514 int
515 cconv(va_list *arg, Fconv *fp)
516 {
517         char s[10];
518         Rune rune;
519
520         rune = va_arg(*arg, int);
521         if(fp->chr == 'c')
522                 rune &= 0xff;
523         s[runetochar(s, &rune)] = 0;
524
525         fp->f2 = NONE;
526         strconv(s, fp);
527         return 0;
528 }
529
530 static
531 int
532 sconv(va_list *arg, Fconv *fp)
533 {
534         char *s;
535         Rune *r;
536
537         if(fp->chr == 's') {
538                 s = va_arg(*arg, char*);
539                 if(s == 0)
540                         s = "<null>";
541                 strconv(s, fp);
542         } else {
543                 r = va_arg(*arg, Rune*);
544                 if(r == 0)
545                         r = L"<null>";
546                 Strconv(r, fp);
547         }
548         return 0;
549 }
550
551 static
552 int
553 percent(va_list*, Fconv *fp)
554 {
555
556         if(fp->out < fp->eout)
557                 *fp->out++ = '%';
558         printcol++;
559         return 0;
560 }
561
562 static
563 int
564 column(va_list *arg, Fconv *fp)
565 {
566         int col, pc;
567
568         col = va_arg(*arg, int);
569         while(fp->out < fp->eout && printcol < col) {
570                 pc = (printcol+8) & ~7;
571                 if(pc <= col) {
572                         *fp->out++ = '\t';
573                         printcol = pc;
574                 } else {
575                         *fp->out++ = ' ';
576                         printcol++;
577                 }
578         }
579         return 0;
580 }
581
582 static
583 int
584 flags(va_list*, Fconv *fp)
585 {
586         int f;
587
588         f = 0;
589         switch(fp->chr) {
590         case '+':
591                 f = FPLUS;
592                 break;
593
594         case '-':
595                 f = FMINUS;
596                 break;
597
598         case '#':
599                 f = FSHARP;
600                 break;
601
602         case 'h':
603                 f = FSHORT;
604                 break;
605
606         case 'l':
607                 f = FLONG;
608                 if(fp->f3 & FLONG)
609                         f = FVLONG;
610                 break;
611
612         case 'u':
613                 f = FUNSIGN;
614                 break;
615         }
616         return -f;
617 }