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. */
41 #define CONV_SPEC_LEN 50 /* Maximum length of a single */
42 /* conversion specification. */
43 #define CONV_RESULT_LEN 50 /* Maximum length of any */
44 /* conversion with default */
47 #define OUT_OF_MEMORY do { \
48 if (CORD_oom_fn != 0) (*CORD_oom_fn)(); \
49 fprintf(stderr, "Out of memory\n"); \
53 static int ec_len(CORD_ec x)
55 return (int)(CORD_len(x[0].ec_cord) + (x[0].ec_bufptr - x[0].ec_buf));
58 /* Possible nonumeric precision values. */
61 /* Copy the conversion specification from CORD_pos into the buffer buf */
62 /* Return negative on error. */
63 /* Source initially points one past the leading %. */
64 /* It is left pointing at the conversion type. */
65 /* Assign field width and precision to *width and *prec. */
66 /* If width or prec is *, VARIABLE is assigned. */
67 /* Set *left to 1 if left adjustment flag is present. */
68 /* Set *long_arg to 1 if long flag ('l' or 'L') is present, or to */
69 /* -1 if 'h' is present. */
70 static int extract_conv_spec(CORD_pos source, char *buf,
71 int * width, int *prec, int *left, int * long_arg)
74 int current_number = 0;
81 buf[chars_so_far++] = '%';
82 while(CORD_pos_valid(source)) {
83 if (chars_so_far >= CONV_SPEC_LEN) return(-1);
84 current = CORD_pos_fetch(source);
85 buf[chars_so_far++] = current;
89 current_number = VARIABLE;
93 /* Zero fill flag; ignore */
108 current_number *= 10;
109 current_number += current - '0';
114 *width = current_number;
165 *prec = current_number;
168 *width = current_number;
173 buf[chars_so_far] = '\0';
177 #if defined(__DJGPP__) || defined(__STRICT_ANSI__)
178 /* vsnprintf is missing in DJGPP (v2.0.3) */
179 # define GC_VSNPRINTF(buf, bufsz, format, args) vsprintf(buf, format, args)
180 #elif defined(_MSC_VER)
181 # if defined(_WIN32_WCE)
182 /* _vsnprintf is deprecated in WinCE */
183 # define GC_VSNPRINTF StringCchVPrintfA
185 # define GC_VSNPRINTF _vsnprintf
188 # define GC_VSNPRINTF vsnprintf
191 int CORD_vsprintf(CORD * out, CORD format, va_list args)
197 char conv_spec[CONV_SPEC_LEN + 1];
199 CORD_ec_init(result);
200 for (CORD_set_pos(pos, format, 0); CORD_pos_valid(pos); CORD_next(pos)) {
201 current = CORD_pos_fetch(pos);
202 if (current == '%') {
204 if (!CORD_pos_valid(pos)) return(-1);
205 current = CORD_pos_fetch(pos);
206 if (current == '%') {
207 CORD_ec_append(result, current);
215 if (extract_conv_spec(pos, conv_spec,
217 &left_adj, &long_arg) < 0) {
220 current = CORD_pos_fetch(pos);
223 /* Assign length to next arg */
226 pos_ptr = va_arg(args, int *);
227 *pos_ptr = ec_len(result);
228 } else if (long_arg > 0) {
230 pos_ptr = va_arg(args, long *);
231 *pos_ptr = ec_len(result);
234 pos_ptr = va_arg(args, short *);
235 *pos_ptr = (short)ec_len(result);
239 /* Append cord and any padding */
240 if (width == VARIABLE) width = va_arg(args, int);
241 if (prec == VARIABLE) prec = va_arg(args, int);
242 arg = va_arg(args, CORD);
244 if (prec != NONE && len > (unsigned)prec) {
245 if (prec < 0) return(-1);
246 arg = CORD_substr(arg, 0, (unsigned)prec);
247 len = (unsigned)prec;
249 if (width != NONE && len < (unsigned)width) {
250 char * blanks = (char *)GC_MALLOC_ATOMIC(
251 (unsigned)width - len + 1);
253 if (NULL == blanks) OUT_OF_MEMORY;
254 memset(blanks, ' ', (unsigned)width - len);
255 blanks[(unsigned)width - len] = '\0';
257 arg = CORD_cat(arg, blanks);
259 arg = CORD_cat(blanks, arg);
262 CORD_ec_append_cord(result, arg);
265 if (width == NONE && prec == NONE) {
268 c = (char)va_arg(args, int);
269 CORD_ec_append(result, c);
274 if (width == NONE && prec == NONE) {
275 char * str = va_arg(args, char *);
278 while ((c = *str++) != '\0') {
279 CORD_ec_append(result, c);
287 /* Use standard sprintf to perform conversion */
290 va_list vsprintf_args;
294 # if defined(CPPCHECK)
295 va_copy(vsprintf_args, args);
296 # elif defined(__va_copy)
297 __va_copy(vsprintf_args, args);
298 # elif defined(__GNUC__) && !defined(__DJGPP__) \
299 && !defined(__EMX__) /* and probably in other cases */
300 va_copy(vsprintf_args, args);
302 vsprintf_args = args;
304 if (width == VARIABLE) width = va_arg(args, int);
305 if (prec == VARIABLE) prec = va_arg(args, int);
306 if (width != NONE) max_size = width;
307 if (prec != NONE && prec > max_size) max_size = prec;
308 max_size += CONV_RESULT_LEN;
309 if (max_size >= CORD_BUFSZ) {
310 buf = (char *)GC_MALLOC_ATOMIC((unsigned)max_size + 1);
311 if (NULL == buf) OUT_OF_MEMORY;
313 if (CORD_BUFSZ - (result[0].ec_bufptr-result[0].ec_buf)
315 CORD_ec_flush_buf(result);
317 buf = result[0].ec_bufptr;
328 (void) va_arg(args, int);
329 } else /* long_arg > 0 */ {
330 (void) va_arg(args, long);
335 (void) va_arg(args, char *);
342 (void) va_arg(args, double);
348 res = GC_VSNPRINTF(buf, max_size + 1, conv_spec,
350 # if defined(CPPCHECK) || defined(__va_copy) \
351 || (defined(__GNUC__) && !defined(__DJGPP__) \
352 && !defined(__EMX__))
353 va_end(vsprintf_args);
356 if ((char *)(GC_word)res == buf) {
357 /* old style vsprintf */
359 } else if (res < 0) {
362 if (buf != result[0].ec_bufptr) {
365 while ((c = *buf++) != '\0') {
366 CORD_ec_append(result, c);
369 result[0].ec_bufptr = buf + len;
375 CORD_ec_append(result, current);
378 count = ec_len(result);
379 *out = CORD_balance(CORD_ec_to_cord(result));
383 int CORD_sprintf(CORD * out, CORD format, ...)
388 va_start(args, format);
389 result = CORD_vsprintf(out, format, args);
394 int CORD_fprintf(FILE * f, CORD format, ...)
398 CORD out = CORD_EMPTY; /* initialized to prevent compiler warning */
400 va_start(args, format);
401 result = CORD_vsprintf(&out, format, args);
403 if (result > 0) CORD_put(out, f);
407 int CORD_vfprintf(FILE * f, CORD format, va_list args)
410 CORD out = CORD_EMPTY;
412 result = CORD_vsprintf(&out, format, args);
413 if (result > 0) CORD_put(out, f);
417 int CORD_printf(CORD format, ...)
421 CORD out = CORD_EMPTY;
423 va_start(args, format);
424 result = CORD_vsprintf(&out, format, args);
426 if (result > 0) CORD_put(out, stdout);
430 int CORD_vprintf(CORD format, va_list args)
433 CORD out = CORD_EMPTY;
435 result = CORD_vsprintf(&out, format, args);
436 if (result > 0) CORD_put(out, stdout);