2 * Copyright (c) 1993-1994 by Xerox Corporation. All rights reserved.
4 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
5 * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
7 * Permission is hereby granted to use or copy this program
8 * for any purpose, provided the above notices are retained on all copies.
9 * Permission to modify the code and to distribute modified code is granted,
10 * provided the above notices are retained, and a notice that the code was
11 * modified is included with the above copyright notice.
13 /* An sprintf implementation that understands cords. This is probably */
14 /* not terribly portable. It assumes an ANSI stdarg.h. It further */
15 /* assumes that I can make copies of va_list variables, and read */
16 /* arguments repeatedly by applyting va_arg to the copies. This */
17 /* could be avoided at some performance cost. */
18 /* We also assume that unsigned and signed integers of various kinds */
19 /* have the same sizes, and can be cast back and forth. */
20 /* We assume that void * and char * have the same size. */
21 /* All this cruft is needed because we want to rely on the underlying */
22 /* sprintf implementation whenever possible. */
23 /* Boehm, September 21, 1995 6:00 pm PDT */
32 #define CONV_SPEC_LEN 50 /* Maximum length of a single */
33 /* conversion specification. */
34 #define CONV_RESULT_LEN 50 /* Maximum length of any */
35 /* conversion with default */
39 static int ec_len(CORD_ec x)
41 return(CORD_len(x[0].ec_cord) + (x[0].ec_bufptr - x[0].ec_buf));
44 /* Possible nonumeric precision values. */
47 /* Copy the conversion specification from CORD_pos into the buffer buf */
48 /* Return negative on error. */
49 /* Source initially points one past the leading %. */
50 /* It is left pointing at the conversion type. */
51 /* Assign field width and precision to *width and *prec. */
52 /* If width or prec is *, VARIABLE is assigned. */
53 /* Set *left to 1 if left adjustment flag is present. */
54 /* Set *long_arg to 1 if long flag ('l' or 'L') is present, or to */
55 /* -1 if 'h' is present. */
56 static int extract_conv_spec(CORD_pos source, char *buf,
57 int * width, int *prec, int *left, int * long_arg)
59 register int result = 0;
60 register int current_number = 0;
61 register int saw_period = 0;
62 register int saw_number = 0;
63 register int chars_so_far = 0;
64 register char current;
67 buf[chars_so_far++] = '%';
68 while(CORD_pos_valid(source)) {
69 if (chars_so_far >= CONV_SPEC_LEN) return(-1);
70 current = CORD_pos_fetch(source);
71 buf[chars_so_far++] = current;
75 current_number = VARIABLE;
79 /* Zero fill flag; ignore */
81 } /* otherwise fall through: */
93 current_number += current - '0';
98 *width = current_number;
149 *prec = current_number;
152 *width = current_number;
157 buf[chars_so_far] = '\0';
161 int CORD_vsprintf(CORD * out, CORD format, va_list args)
165 register char current;
167 char conv_spec[CONV_SPEC_LEN + 1];
169 CORD_ec_init(result);
170 for (CORD_set_pos(pos, format, 0); CORD_pos_valid(pos); CORD_next(pos)) {
171 current = CORD_pos_fetch(pos);
172 if (current == '%') {
174 if (!CORD_pos_valid(pos)) return(-1);
175 current = CORD_pos_fetch(pos);
176 if (current == '%') {
177 CORD_ec_append(result, current);
185 if (extract_conv_spec(pos, conv_spec,
187 &left_adj, &long_arg) < 0) {
190 current = CORD_pos_fetch(pos);
193 /* Assign length to next arg */
196 pos_ptr = va_arg(args, int *);
197 *pos_ptr = ec_len(result);
198 } else if (long_arg > 0) {
200 pos_ptr = va_arg(args, long *);
201 *pos_ptr = ec_len(result);
204 pos_ptr = va_arg(args, short *);
205 *pos_ptr = ec_len(result);
209 /* Append cord and any padding */
210 if (width == VARIABLE) width = va_arg(args, int);
211 if (prec == VARIABLE) prec = va_arg(args, int);
212 arg = va_arg(args, CORD);
214 if (prec != NONE && len > prec) {
215 if (prec < 0) return(-1);
216 arg = CORD_substr(arg, 0, prec);
219 if (width != NONE && len < width) {
220 char * blanks = GC_MALLOC_ATOMIC(width-len+1);
222 memset(blanks, ' ', width-len);
223 blanks[width-len] = '\0';
225 arg = CORD_cat(arg, blanks);
227 arg = CORD_cat(blanks, arg);
230 CORD_ec_append_cord(result, arg);
233 if (width == NONE && prec == NONE) {
236 c = (char)va_arg(args, int);
237 CORD_ec_append(result, c);
242 if (width == NONE && prec == NONE) {
243 char * str = va_arg(args, char *);
246 while ((c = *str++)) {
247 CORD_ec_append(result, c);
255 /* Use standard sprintf to perform conversion */
258 va_list vsprintf_args;
262 __va_copy(vsprintf_args, args);
264 # if defined(__GNUC__) && !defined(__DJGPP__) /* and probably in other cases */
265 va_copy(vsprintf_args, args);
267 vsprintf_args = args;
270 if (width == VARIABLE) width = va_arg(args, int);
271 if (prec == VARIABLE) prec = va_arg(args, int);
272 if (width != NONE) max_size = width;
273 if (prec != NONE && prec > max_size) max_size = prec;
274 max_size += CONV_RESULT_LEN;
275 if (max_size >= CORD_BUFSZ) {
276 buf = GC_MALLOC_ATOMIC(max_size + 1);
278 if (CORD_BUFSZ - (result[0].ec_bufptr-result[0].ec_buf)
280 CORD_ec_flush_buf(result);
282 buf = result[0].ec_bufptr;
293 (void) va_arg(args, int);
294 } else if (long_arg > 0) {
295 (void) va_arg(args, long);
300 (void) va_arg(args, char *);
307 (void) va_arg(args, double);
312 res = vsprintf(buf, conv_spec, vsprintf_args);
314 if ((char *)(GC_word)res == buf) {
315 /* old style vsprintf */
317 } else if (res < 0) {
320 if (buf != result[0].ec_bufptr) {
323 while ((c = *buf++)) {
324 CORD_ec_append(result, c);
327 result[0].ec_bufptr = buf + len;
333 CORD_ec_append(result, current);
336 count = ec_len(result);
337 *out = CORD_balance(CORD_ec_to_cord(result));
341 int CORD_sprintf(CORD * out, CORD format, ...)
346 va_start(args, format);
347 result = CORD_vsprintf(out, format, args);
352 int CORD_fprintf(FILE * f, CORD format, ...)
358 va_start(args, format);
359 result = CORD_vsprintf(&out, format, args);
361 if (result > 0) CORD_put(out, f);
365 int CORD_vfprintf(FILE * f, CORD format, va_list args)
370 result = CORD_vsprintf(&out, format, args);
371 if (result > 0) CORD_put(out, f);
375 int CORD_printf(CORD format, ...)
381 va_start(args, format);
382 result = CORD_vsprintf(&out, format, args);
384 if (result > 0) CORD_put(out, stdout);
388 int CORD_vprintf(CORD format, va_list args)
393 result = CORD_vsprintf(&out, format, args);
394 if (result > 0) CORD_put(out, stdout);