* reordered a little bit
[mascara-docs.git] / i86 / elks / elkscmd / rc / print.c
bloba5cf25fd862c85bde5bf9fd7e519870dfb075906
1 /* print.c -- formatted printing routines (Paul Haahr, 12/91) */
3 #include "rc.h"
4 #include <setjmp.h>
6 #define PRINT_ALLOCSIZE ((SIZE_T)64)
7 #define SPRINT_BUFSIZ ((SIZE_T)1024)
9 #define MAXCONV 256
12 * conversion functions
13 * true return -> flag changes only, not a conversion
16 #define Flag(name, flag) \
17 static bool name(Format *format, int c) { \
18 format->flags |= flag; \
19 return TRUE; \
22 Flag(uconv, FMT_unsigned)
23 Flag(hconv, FMT_short)
24 Flag(lconv, FMT_long)
25 Flag(altconv, FMT_altform)
26 Flag(leftconv, FMT_leftside)
27 Flag(dotconv, FMT_f2set)
29 static bool digitconv(Format *format, int c) {
30 if (format->flags & FMT_f2set)
31 format->f2 = 10 * format->f2 + c - '0';
32 else {
33 format->flags |= FMT_f1set;
34 format->f1 = 10 * format->f1 + c - '0';
36 return TRUE;
39 static bool zeroconv(Format *format, int c) {
40 if (format->flags & (FMT_f1set | FMT_f2set))
41 return digitconv(format, '0');
42 format->flags |= FMT_zeropad;
43 return TRUE;
46 static void pad(Format *format, SIZE_T len, int c) {
47 while (len-- != 0)
48 fmtputc(format, c);
51 static bool sconv(Format *format, int c) {
52 char *s = va_arg(format->args, char *);
53 if ((format->flags & FMT_f1set) == 0)
54 fmtcat(format, s);
55 else {
56 SIZE_T len = strlen(s), width = format->f1 - len;
57 if (format->flags & FMT_leftside) {
58 fmtappend(format, s, len);
59 pad(format, width, ' ');
60 } else {
61 pad(format, width, ' ');
62 fmtappend(format, s, len);
65 return FALSE;
68 static char *utoa(unsigned long u, char *t, unsigned int radix, const char *digit) {
69 if (u >= radix) {
70 t = utoa(u / radix, t, radix, digit);
71 u %= radix;
73 *t++ = digit[u];
74 return t;
77 static void intconv(Format *format, unsigned int radix, int upper, const char *altform) {
78 static const char * const table[] = {
79 "0123456789abcdefghijklmnopqrstuvwxyz",
80 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ",
82 char padchar;
83 SIZE_T len, pre, zeroes, padding, width;
84 long n, flags;
85 unsigned long u;
86 char number[64], prefix[20];
88 if (radix > 36)
89 return;
91 flags = format->flags;
92 if (flags & FMT_long)
93 n = va_arg(format->args, long);
94 else if (flags & FMT_short)
95 n = va_arg(format->args, short);
96 else
97 n = va_arg(format->args, int);
99 pre = 0;
100 if ((flags & FMT_unsigned) || n >= 0)
101 u = n;
102 else {
103 prefix[pre++] = '-';
104 u = -n;
107 if (flags & FMT_altform)
108 while (*altform != '\0')
109 prefix[pre++] = *altform++;
111 len = utoa(u, number, radix, table[upper]) - number;
112 if ((flags & FMT_f2set) && (SIZE_T) format->f2 > len)
113 zeroes = format->f2 - len;
114 else
115 zeroes = 0;
117 width = pre + zeroes + len;
118 if ((flags & FMT_f1set) && (SIZE_T) format->f1 > width) {
119 padding = format->f1 - width;
120 } else
121 padding = 0;
123 padchar = ' ';
124 if (padding > 0 && flags & FMT_zeropad) {
125 padchar = '0';
126 if ((flags & FMT_leftside) == 0) {
127 zeroes += padding;
128 padding = 0;
133 if ((flags & FMT_leftside) == 0)
134 pad(format, padding, padchar);
135 fmtappend(format, prefix, pre);
136 pad(format, zeroes, '0');
137 fmtappend(format, number, len);
138 if (flags & FMT_leftside)
139 pad(format, padding, padchar);
142 static bool cconv(Format *format, int c) {
143 fmtputc(format, va_arg(format->args, int));
144 return FALSE;
147 static bool dconv(Format *format, int c) {
148 intconv(format, 10, 0, "");
149 return FALSE;
152 static bool oconv(Format *format, int c) {
153 intconv(format, 8, 0, "0");
154 return FALSE;
157 static bool xconv(Format *format, int c) {
158 intconv(format, 16, 0, "0x");
159 return FALSE;
162 static bool pctconv(Format *format, int c) {
163 fmtputc(format, '%');
164 return FALSE;
167 static bool badconv(Format *format, int c) {
168 panic("bad conversion character in printfmt");
169 /* NOTREACHED */
170 return FALSE; /* hush up gcc -Wall */
175 * conversion table management
178 static Conv fmttab[MAXCONV];
180 static void inittab(void) {
181 int i;
182 for (i = 0; i < MAXCONV; i++)
183 fmttab[i] = badconv;
185 fmttab['s'] = sconv;
186 fmttab['c'] = cconv;
187 fmttab['d'] = dconv;
188 fmttab['o'] = oconv;
189 fmttab['x'] = xconv;
190 fmttab['%'] = pctconv;
192 fmttab['u'] = uconv;
193 fmttab['h'] = hconv;
194 fmttab['l'] = lconv;
195 fmttab['#'] = altconv;
196 fmttab['-'] = leftconv;
197 fmttab['.'] = dotconv;
199 fmttab['0'] = zeroconv;
200 for (i = '1'; i <= '9'; i++)
201 fmttab[i] = digitconv;
204 extern bool (*fmtinstall(int c, bool (*f)(Format *, int)))(Format *, int) {
205 /*Conv fmtinstall(int c, Conv f) {*/
206 Conv oldf;
207 if (fmttab[0] == NULL)
208 inittab();
209 c &= MAXCONV - 1;
210 oldf = fmttab[c];
211 if (f != NULL)
212 fmttab[c] = f;
213 return oldf;
218 * functions for inserting strings in the format buffer
221 extern void fmtappend(Format *format, const char *s, SIZE_T len) {
222 while (format->buf + len > format->bufend) {
223 SIZE_T split = format->bufend - format->buf;
224 memcpy(format->buf, s, split);
225 format->buf += split;
226 s += split;
227 len -= split;
228 (*format->grow)(format, len);
230 memcpy(format->buf, s, len);
231 format->buf += len;
234 extern void fmtcat(Format *format, const char *s) {
235 fmtappend(format, s, strlen(s));
239 * printfmt -- the driver routine
242 extern int printfmt(Format *format, const char *fmt) {
243 unsigned const char *s = (unsigned const char *) fmt;
245 if (fmttab[0] == NULL)
246 inittab();
248 for (;;) {
249 int c = *s++;
250 switch (c) {
251 case '%':
252 format->flags = format->f1 = format->f2 = 0;
254 c = *s++;
255 while ((*fmttab[c])(format, c));
256 break;
257 case '\0':
258 return format->buf - format->bufbegin + format->flushed;
259 default:
260 fmtputc(format, c);
261 break;
268 * the public entry points
271 extern int fmtprint(Format *format, const char *fmt,...) {
272 int n = -format->flushed;
273 va_list ap, saveargs;
275 va_start(ap, fmt);
276 saveargs = format->args;
277 format->args = ap;
278 n += printfmt(format, fmt);
279 va_end(format->args);
280 format->args = saveargs;
282 return n + format->flushed;
285 static void fprint_flush(Format *format, SIZE_T more) {
286 SIZE_T n = format->buf - format->bufbegin;
287 char *buf = format->bufbegin;
289 format->flushed += n;
290 format->buf = format->bufbegin;
291 writeall(format->u.n, buf, n);
294 extern int fprint(int fd, const char *fmt,...) {
295 char buf[1024];
296 Format format;
297 va_list ap;
299 format.buf = buf;
300 format.bufbegin = buf;
301 format.bufend = buf + sizeof buf;
302 format.grow = fprint_flush;
303 format.flushed = 0;
304 format.u.n = fd;
306 va_start(ap, fmt);
307 format.args = ap;
308 printfmt(&format, fmt);
309 va_end(format.args);
311 fprint_flush(&format, (SIZE_T) 0);
312 return format.flushed;
315 static void memprint_grow(Format *format, SIZE_T more) {
316 char *buf;
317 SIZE_T len = format->bufend - format->bufbegin + 1;
318 len = (len >= more)
319 ? len * 2
320 : ((len + more) + PRINT_ALLOCSIZE) &~ (PRINT_ALLOCSIZE - 1);
321 if (format->u.n)
322 buf = erealloc(format->bufbegin, len);
323 else {
324 SIZE_T used = format->buf - format->bufbegin;
325 buf = nalloc(len);
326 memcpy(buf, format->bufbegin, used);
328 format->buf = buf + (format->buf - format->bufbegin);
329 format->bufbegin = buf;
330 format->bufend = buf + len - 1;
333 static char *memprint(Format *format, const char *fmt, char *buf, SIZE_T len) {
334 format->buf = buf;
335 format->bufbegin = buf;
336 format->bufend = buf + len - 1;
337 format->grow = memprint_grow;
338 format->flushed = 0;
339 printfmt(format, fmt);
340 *format->buf = '\0';
341 return format->bufbegin;
344 extern char *mprint(const char *fmt,...) {
345 Format format;
346 char *result;
347 va_list ap;
349 format.u.n = 1;
350 va_start(ap, fmt);
351 format.args = ap;
352 result = memprint(&format, fmt, ealloc(PRINT_ALLOCSIZE), PRINT_ALLOCSIZE);
353 va_end(format.args);
354 return result;
357 extern char *nprint(const char *fmt,...) {
358 Format format;
359 char *result;
360 va_list ap;
362 format.u.n = 0;
363 va_start(ap, fmt);
364 format.args = ap;
365 result = memprint(&format, fmt, nalloc(PRINT_ALLOCSIZE), PRINT_ALLOCSIZE);
366 va_end(format.args);
367 return result;
371 /* THESE ARE UNUSED IN rc */
373 #if 0
375 extern int print(const char *fmt,...) {
376 char buf[1024];
377 Format format;
379 format.buf = buf;
380 format.bufbegin = buf;
381 format.bufend = buf + sizeof buf;
382 format.grow = fprint_flush;
383 format.flushed = 0;
384 format.u.n = 1;
386 va_start(format.args, fmt);
387 printfmt(&format, fmt);
388 va_end(format.args);
390 fprint_flush(&format, 0);
391 return format.flushed;
394 extern int eprint(const char *fmt,...) {
395 char buf[1024];
396 Format format;
398 format.buf = buf;
399 format.bufbegin = buf;
400 format.bufend = buf + sizeof buf;
401 format.grow = fprint_flush;
402 format.flushed = 0;
403 format.u.n = 2;
405 va_start(format.args, fmt);
406 printfmt(&format, fmt);
407 va_end(format.args);
409 fprint_flush(&format, 0);
410 return format.flushed;
413 static void snprint_grow(Format *format, SIZE_T more) {
414 longjmp(format->u.p, 1);
417 extern int snprint(char *buf, int buflen, const char *fmt,...) {
418 int n;
419 jmp_buf jbuf;
420 Format format;
422 if (setjmp(jbuf)) {
423 *format.buf = '\0';
424 return format.buf - format.bufbegin;
427 format.buf = buf;
428 format.bufbegin = buf;
429 format.bufend = buf + buflen - 1;
430 format.grow = snprint_grow;
431 format.flushed = 0;
432 format.u.p = jbuf;
434 va_start(format.args, fmt);
435 n = printfmt(&format, fmt);
436 va_end(format.args);
438 *format.buf = '\0';
439 return n;
442 extern int sprint(char *buf, const char *fmt,...) {
443 int n;
444 jmp_buf jbuf;
445 Format format;
447 if (setjmp(jbuf)) {
448 *format.buf = '\0';
449 return format.buf - format.bufbegin;
452 format.buf = buf;
453 format.bufbegin = buf;
454 format.bufend = buf + SPRINT_BUFSIZ - 1;
455 format.grow = snprint_grow;
456 format.flushed = 0;
457 format.u.p = jbuf;
459 va_start(format.args, fmt);
460 n = printfmt(&format, fmt);
461 va_end(format.args);
463 *format.buf = '\0';
464 return n;
466 #endif