1 /* print.c -- formatted printing routines (Paul Haahr, 12/91) */
6 #define PRINT_ALLOCSIZE ((SIZE_T)64)
7 #define SPRINT_BUFSIZ ((SIZE_T)1024)
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; \
22 Flag(uconv
, FMT_unsigned
)
23 Flag(hconv
, FMT_short
)
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';
33 format
->flags
|= FMT_f1set
;
34 format
->f1
= 10 * format
->f1
+ c
- '0';
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
;
46 static void pad(Format
*format
, SIZE_T len
, int c
) {
51 static bool sconv(Format
*format
, int c
) {
52 char *s
= va_arg(format
->args
, char *);
53 if ((format
->flags
& FMT_f1set
) == 0)
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
, ' ');
61 pad(format
, width
, ' ');
62 fmtappend(format
, s
, len
);
68 static char *utoa(unsigned long u
, char *t
, unsigned int radix
, const char *digit
) {
70 t
= utoa(u
/ radix
, t
, radix
, digit
);
77 static void intconv(Format
*format
, unsigned int radix
, int upper
, const char *altform
) {
78 static const char * const table
[] = {
79 "0123456789abcdefghijklmnopqrstuvwxyz",
80 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ",
83 SIZE_T len
, pre
, zeroes
, padding
, width
;
86 char number
[64], prefix
[20];
91 flags
= format
->flags
;
93 n
= va_arg(format
->args
, long);
94 else if (flags
& FMT_short
)
95 n
= va_arg(format
->args
, short);
97 n
= va_arg(format
->args
, int);
100 if ((flags
& FMT_unsigned
) || n
>= 0)
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
;
117 width
= pre
+ zeroes
+ len
;
118 if ((flags
& FMT_f1set
) && (SIZE_T
) format
->f1
> width
) {
119 padding
= format
->f1
- width
;
124 if (padding
> 0 && flags
& FMT_zeropad
) {
126 if ((flags
& FMT_leftside
) == 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));
147 static bool dconv(Format
*format
, int c
) {
148 intconv(format
, 10, 0, "");
152 static bool oconv(Format
*format
, int c
) {
153 intconv(format
, 8, 0, "0");
157 static bool xconv(Format
*format
, int c
) {
158 intconv(format
, 16, 0, "0x");
162 static bool pctconv(Format
*format
, int c
) {
163 fmtputc(format
, '%');
167 static bool badconv(Format
*format
, int c
) {
168 panic("bad conversion character in printfmt");
170 return FALSE
; /* hush up gcc -Wall */
175 * conversion table management
178 static Conv fmttab
[MAXCONV
];
180 static void inittab(void) {
182 for (i
= 0; i
< MAXCONV
; i
++)
190 fmttab
['%'] = pctconv
;
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) {*/
207 if (fmttab
[0] == NULL
)
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
;
228 (*format
->grow
)(format
, len
);
230 memcpy(format
->buf
, s
, 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
)
252 format
->flags
= format
->f1
= format
->f2
= 0;
255 while ((*fmttab
[c
])(format
, c
));
258 return format
->buf
- format
->bufbegin
+ format
->flushed
;
268 * the public entry points
271 extern int fmtprint(Format
*format
, const char *fmt
,...) {
272 int n
= -format
->flushed
;
273 va_list ap
, saveargs
;
276 saveargs
= format
->args
;
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
,...) {
300 format
.bufbegin
= buf
;
301 format
.bufend
= buf
+ sizeof buf
;
302 format
.grow
= fprint_flush
;
308 printfmt(&format
, fmt
);
311 fprint_flush(&format
, (SIZE_T
) 0);
312 return format
.flushed
;
315 static void memprint_grow(Format
*format
, SIZE_T more
) {
317 SIZE_T len
= format
->bufend
- format
->bufbegin
+ 1;
320 : ((len
+ more
) + PRINT_ALLOCSIZE
) &~ (PRINT_ALLOCSIZE
- 1);
322 buf
= erealloc(format
->bufbegin
, len
);
324 SIZE_T used
= format
->buf
- format
->bufbegin
;
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
) {
335 format
->bufbegin
= buf
;
336 format
->bufend
= buf
+ len
- 1;
337 format
->grow
= memprint_grow
;
339 printfmt(format
, fmt
);
341 return format
->bufbegin
;
344 extern char *mprint(const char *fmt
,...) {
352 result
= memprint(&format
, fmt
, ealloc(PRINT_ALLOCSIZE
), PRINT_ALLOCSIZE
);
357 extern char *nprint(const char *fmt
,...) {
365 result
= memprint(&format
, fmt
, nalloc(PRINT_ALLOCSIZE
), PRINT_ALLOCSIZE
);
371 /* THESE ARE UNUSED IN rc */
375 extern int print(const char *fmt
,...) {
380 format
.bufbegin
= buf
;
381 format
.bufend
= buf
+ sizeof buf
;
382 format
.grow
= fprint_flush
;
386 va_start(format
.args
, fmt
);
387 printfmt(&format
, fmt
);
390 fprint_flush(&format
, 0);
391 return format
.flushed
;
394 extern int eprint(const char *fmt
,...) {
399 format
.bufbegin
= buf
;
400 format
.bufend
= buf
+ sizeof buf
;
401 format
.grow
= fprint_flush
;
405 va_start(format
.args
, fmt
);
406 printfmt(&format
, fmt
);
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
,...) {
424 return format
.buf
- format
.bufbegin
;
428 format
.bufbegin
= buf
;
429 format
.bufend
= buf
+ buflen
- 1;
430 format
.grow
= snprint_grow
;
434 va_start(format
.args
, fmt
);
435 n
= printfmt(&format
, fmt
);
442 extern int sprint(char *buf
, const char *fmt
,...) {
449 return format
.buf
- format
.bufbegin
;
453 format
.bufbegin
= buf
;
454 format
.bufend
= buf
+ SPRINT_BUFSIZ
- 1;
455 format
.grow
= snprint_grow
;
459 va_start(format
.args
, fmt
);
460 n
= printfmt(&format
, fmt
);