BSD 4_4_Lite1 development
[unix-history] / usr / src / contrib / rc-1.4 / print.c
CommitLineData
179f9ab4
C
1/* print.c -- formatted printing routines (Paul Haahr, 12/91) */
2
3#include "rc.h"
4#include <setjmp.h>
5
6#define PRINT_ALLOCSIZE ((size_t)64)
7#define SPRINT_BUFSIZ ((size_t)1024)
8
9#define MAXCONV 256
10
11/*
12 * conversion functions
13 * true return -> flag changes only, not a conversion
14 */
15
16#define Flag(name, flag) \
17static bool name(Format *format, int c) { \
18 format->flags |= flag; \
19 return TRUE; \
20}
21
22Flag(uconv, FMT_unsigned)
23Flag(hconv, FMT_short)
24Flag(lconv, FMT_long)
25Flag(altconv, FMT_altform)
26Flag(leftconv, FMT_leftside)
27Flag(dotconv, FMT_f2set)
28
29static 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';
35 }
36 return TRUE;
37}
38
39static 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;
44}
45
46static void pad(Format *format, size_t len, int c) {
47 while (len-- != 0)
48 fmtputc(format, c);
49}
50
51static 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);
63 }
64 }
65 return FALSE;
66}
67
68static 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;
72 }
73 *t++ = digit[u];
74 return t;
75}
76
77static void intconv(Format *format, unsigned int radix, int upper, const char *altform) {
78 static const char * const table[] = {
79 "0123456789abcdefghijklmnopqrstuvwxyz",
80 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ",
81 };
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];
87
88 if (radix > 36)
89 return;
90
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);
98
99 pre = 0;
100 if ((flags & FMT_unsigned) || n >= 0)
101 u = n;
102 else {
103 prefix[pre++] = '-';
104 u = -n;
105 }
106
107 if (flags & FMT_altform)
108 while (*altform != '\0')
109 prefix[pre++] = *altform++;
110
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;
116
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;
122
123 padchar = ' ';
124 if (padding > 0 && flags & FMT_zeropad) {
125 padchar = '0';
126 if ((flags & FMT_leftside) == 0) {
127 zeroes += padding;
128 padding = 0;
129 }
130 }
131
132
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);
140}
141
142static bool cconv(Format *format, int c) {
143 fmtputc(format, va_arg(format->args, int));
144 return FALSE;
145}
146
147static bool dconv(Format *format, int c) {
148 intconv(format, 10, 0, "");
149 return FALSE;
150}
151
152static bool oconv(Format *format, int c) {
153 intconv(format, 8, 0, "0");
154 return FALSE;
155}
156
157static bool xconv(Format *format, int c) {
158 intconv(format, 16, 0, "0x");
159 return FALSE;
160}
161
162static bool pctconv(Format *format, int c) {
163 fmtputc(format, '%');
164 return FALSE;
165}
166
167static bool badconv(Format *format, int c) {
168 panic("bad conversion character in printfmt");
169 /* NOTREACHED */
170 return FALSE; /* hush up gcc -Wall */
171}
172
173
174/*
175 * conversion table management
176 */
177
178static Conv fmttab[MAXCONV];
179
180static void inittab(void) {
181 int i;
182 for (i = 0; i < MAXCONV; i++)
183 fmttab[i] = badconv;
184
185 fmttab['s'] = sconv;
186 fmttab['c'] = cconv;
187 fmttab['d'] = dconv;
188 fmttab['o'] = oconv;
189 fmttab['x'] = xconv;
190 fmttab['%'] = pctconv;
191
192 fmttab['u'] = uconv;
193 fmttab['h'] = hconv;
194 fmttab['l'] = lconv;
195 fmttab['#'] = altconv;
196 fmttab['-'] = leftconv;
197 fmttab['.'] = dotconv;
198
199 fmttab['0'] = zeroconv;
200 for (i = '1'; i <= '9'; i++)
201 fmttab[i] = digitconv;
202}
203
204extern 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;
214}
215
216
217/*
218 * functions for inserting strings in the format buffer
219 */
220
221extern 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);
229 }
230 memcpy(format->buf, s, len);
231 format->buf += len;
232}
233
234extern void fmtcat(Format *format, const char *s) {
235 fmtappend(format, s, strlen(s));
236}
237
238/*
239 * printfmt -- the driver routine
240 */
241
242extern int printfmt(Format *format, const char *fmt) {
243 unsigned const char *s = (unsigned const char *) fmt;
244
245 if (fmttab[0] == NULL)
246 inittab();
247
248 for (;;) {
249 int c = *s++;
250 switch (c) {
251 case '%':
252 format->flags = format->f1 = format->f2 = 0;
253 do
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;
262 }
263 }
264}
265
266
267/*
268 * the public entry points
269 */
270
271extern int fmtprint(Format *format, const char *fmt,...) {
272 int n = -format->flushed;
273 va_list saveargs = format->args;
274
275 va_start(format->args, fmt);
276 n += printfmt(format, fmt);
277 va_end(format->args);
278 format->args = saveargs;
279
280 return n + format->flushed;
281}
282
283static void fprint_flush(Format *format, size_t more) {
284 size_t n = format->buf - format->bufbegin;
285 char *buf = format->bufbegin;
286
287 format->flushed += n;
288 format->buf = format->bufbegin;
289 writeall(format->u.n, buf, n);
290}
291
292extern int fprint(int fd, const char *fmt,...) {
293 char buf[1024];
294 Format format;
295
296 format.buf = buf;
297 format.bufbegin = buf;
298 format.bufend = buf + sizeof buf;
299 format.grow = fprint_flush;
300 format.flushed = 0;
301 format.u.n = fd;
302
303 va_start(format.args, fmt);
304 printfmt(&format, fmt);
305 va_end(format.args);
306
307 fprint_flush(&format, (size_t) 0);
308 return format.flushed;
309}
310
311static void memprint_grow(Format *format, size_t more) {
312 char *buf;
313 size_t len = format->bufend - format->bufbegin + 1;
314 len = (len >= more)
315 ? len * 2
316 : ((len + more) + PRINT_ALLOCSIZE) &~ (PRINT_ALLOCSIZE - 1);
317 if (format->u.n)
318 buf = erealloc(format->bufbegin, len);
319 else {
320 size_t used = format->buf - format->bufbegin;
321 buf = nalloc(len);
322 memcpy(buf, format->bufbegin, used);
323 }
324 format->buf = buf + (format->buf - format->bufbegin);
325 format->bufbegin = buf;
326 format->bufend = buf + len - 1;
327}
328
329static char *memprint(Format *format, const char *fmt, char *buf, size_t len) {
330 format->buf = buf;
331 format->bufbegin = buf;
332 format->bufend = buf + len - 1;
333 format->grow = memprint_grow;
334 format->flushed = 0;
335 printfmt(format, fmt);
336 *format->buf = '\0';
337 return format->bufbegin;
338}
339
340extern char *mprint(const char *fmt,...) {
341 Format format;
342 char *result;
343 format.u.n = 1;
344 va_start(format.args, fmt);
345 result = memprint(&format, fmt, ealloc(PRINT_ALLOCSIZE), PRINT_ALLOCSIZE);
346 va_end(format.args);
347 return result;
348}
349
350extern char *nprint(const char *fmt,...) {
351 Format format;
352 char *result;
353 format.u.n = 0;
354 va_start(format.args, fmt);
355 result = memprint(&format, fmt, nalloc(PRINT_ALLOCSIZE), PRINT_ALLOCSIZE);
356 va_end(format.args);
357 return result;
358}