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 applying 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. */
31 #define CONV_SPEC_LEN 50 /* Maximum length of a single */
32 /* conversion specification. */
33 #define CONV_RESULT_LEN 50 /* Maximum length of any */
34 /* conversion with default */
38 static int ec_len(CORD_ec x)
40 return(CORD_len(x[0].ec_cord) + (x[0].ec_bufptr - x[0].ec_buf));
43 /* Possible nonumeric precision values. */
46 /* Copy the conversion specification from CORD_pos into the buffer buf */
47 /* Return negative on error. */
48 /* Source initially points one past the leading %. */
49 /* It is left pointing at the conversion type. */
50 /* Assign field width and precision to *width and *prec. */
51 /* If width or prec is *, VARIABLE is assigned. */
52 /* Set *left to 1 if left adjustment flag is present. */
53 /* Set *long_arg to 1 if long flag ('l' or 'L') is present, or to */
54 /* -1 if 'h' is present. */
55 static int extract_conv_spec(CORD_pos source, char *buf,
56 int * width, int *prec, int *left, int * long_arg)
58 register int result = 0;
59 register int current_number = 0;
60 register int saw_period = 0;
61 register int saw_number = 0;
62 register int chars_so_far = 0;
63 register char current;
66 buf[chars_so_far++] = '%';
67 while(CORD_pos_valid(source)) {
68 if (chars_so_far >= CONV_SPEC_LEN) return(-1);
69 current = CORD_pos_fetch(source);
70 buf[chars_so_far++] = current;
74 current_number = VARIABLE;
78 /* Zero fill flag; ignore */
80 } /* otherwise fall through: */
92 current_number += current - '0';
97 *width = current_number;
148 *prec = current_number;
151 *width = current_number;
156 buf[chars_so_far] = '\0';
160 int CORD_vsprintf(CORD * out, CORD format, va_list args)
164 register char current;
166 char conv_spec[CONV_SPEC_LEN + 1];
168 CORD_ec_init(result);
169 for (CORD_set_pos(pos, format, 0); CORD_pos_valid(pos); CORD_next(pos)) {
170 current = CORD_pos_fetch(pos);
171 if (current == '%') {
173 if (!CORD_pos_valid(pos)) return(-1);
174 current = CORD_pos_fetch(pos);
175 if (current == '%') {
176 CORD_ec_append(result, current);
184 if (extract_conv_spec(pos, conv_spec,
186 &left_adj, &long_arg) < 0) {
189 current = CORD_pos_fetch(pos);
192 /* Assign length to next arg */
195 pos_ptr = va_arg(args, int *);
196 *pos_ptr = ec_len(result);
197 } else if (long_arg > 0) {
199 pos_ptr = va_arg(args, long *);
200 *pos_ptr = ec_len(result);
203 pos_ptr = va_arg(args, short *);
204 *pos_ptr = ec_len(result);
208 /* Append cord and any padding */
209 if (width == VARIABLE) width = va_arg(args, int);
210 if (prec == VARIABLE) prec = va_arg(args, int);
211 arg = va_arg(args, CORD);
213 if (prec != NONE && len > (size_t)prec) {
214 if (prec < 0) return(-1);
215 arg = CORD_substr(arg, 0, prec);
218 if (width != NONE && len < (size_t)width) {
219 char * blanks = GC_MALLOC_ATOMIC(width-len+1);
221 memset(blanks, ' ', width-len);
222 blanks[width-len] = '\0';
224 arg = CORD_cat(arg, blanks);
226 arg = CORD_cat(blanks, arg);
229 CORD_ec_append_cord(result, arg);
232 if (width == NONE && prec == NONE) {
235 c = (char)va_arg(args, int);
236 CORD_ec_append(result, c);
241 if (width == NONE && prec == NONE) {
242 char * str = va_arg(args, char *);
245 while ((c = *str++)) {
246 CORD_ec_append(result, c);
254 /* Use standard sprintf to perform conversion */
257 va_list vsprintf_args;
261 __va_copy(vsprintf_args, args);
263 # if defined(__GNUC__) && !defined(__DJGPP__) /* and probably in other cases */
264 va_copy(vsprintf_args, args);
266 vsprintf_args = args;
269 if (width == VARIABLE) width = va_arg(args, int);
270 if (prec == VARIABLE) prec = va_arg(args, int);
271 if (width != NONE) max_size = width;
272 if (prec != NONE && prec > max_size) max_size = prec;
273 max_size += CONV_RESULT_LEN;
274 if (max_size >= CORD_BUFSZ) {
275 buf = GC_MALLOC_ATOMIC(max_size + 1);
277 if (CORD_BUFSZ - (result[0].ec_bufptr-result[0].ec_buf)
279 CORD_ec_flush_buf(result);
281 buf = result[0].ec_bufptr;
292 (void) va_arg(args, int);
293 } else if (long_arg > 0) {
294 (void) va_arg(args, long);
299 (void) va_arg(args, char *);
306 (void) va_arg(args, double);
311 res = vsprintf(buf, conv_spec, vsprintf_args);
313 if ((char *)(GC_word)res == buf) {
314 /* old style vsprintf */
316 } else if (res < 0) {
319 if (buf != result[0].ec_bufptr) {
322 while ((c = *buf++)) {
323 CORD_ec_append(result, c);
326 result[0].ec_bufptr = buf + len;
332 CORD_ec_append(result, current);
335 count = ec_len(result);
336 *out = CORD_balance(CORD_ec_to_cord(result));
340 int CORD_sprintf(CORD * out, CORD format, ...)
345 va_start(args, format);
346 result = CORD_vsprintf(out, format, args);
351 int CORD_fprintf(FILE * f, CORD format, ...)
357 va_start(args, format);
358 result = CORD_vsprintf(&out, format, args);
360 if (result > 0) CORD_put(out, f);
364 int CORD_vfprintf(FILE * f, CORD format, va_list args)
369 result = CORD_vsprintf(&out, format, args);
370 if (result > 0) CORD_put(out, f);
374 int CORD_printf(CORD format, ...)
380 va_start(args, format);
381 result = CORD_vsprintf(&out, format, args);
383 if (result > 0) CORD_put(out, stdout);
387 int CORD_vprintf(CORD format, va_list args)
392 result = CORD_vsprintf(&out, format, args);
393 if (result > 0) CORD_put(out, stdout);