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 MACRO_BLKSTMT_BEGIN {
48 # define MACRO_BLKSTMT_END }
50 # define MACRO_BLKSTMT_BEGIN do {
51 # define MACRO_BLKSTMT_END } while (0)
54 #define OUT_OF_MEMORY MACRO_BLKSTMT_BEGIN \
55 if (CORD_oom_fn != 0) (*CORD_oom_fn)(); \
56 fprintf(stderr, "Out of memory\n"); \
60 static int ec_len(CORD_ec x)
62 return (int)(CORD_len(x[0].ec_cord) + (x[0].ec_bufptr - x[0].ec_buf));
65 /* Possible nonumeric precision values. */
68 /* Copy the conversion specification from CORD_pos into the buffer buf */
69 /* Return negative on error. */
70 /* Source initially points one past the leading %. */
71 /* It is left pointing at the conversion type. */
72 /* Assign field width and precision to *width and *prec. */
73 /* If width or prec is *, VARIABLE is assigned. */
74 /* Set *left to 1 if left adjustment flag is present. */
75 /* Set *long_arg to 1 if long flag ('l' or 'L') is present, or to */
76 /* -1 if 'h' is present. */
77 static int extract_conv_spec(CORD_pos source, char *buf,
78 int * width, int *prec, int *left, int * long_arg)
81 int current_number = 0;
88 buf[chars_so_far++] = '%';
89 while(CORD_pos_valid(source)) {
90 if (chars_so_far >= CONV_SPEC_LEN) return(-1);
91 current = CORD_pos_fetch(source);
92 buf[chars_so_far++] = current;
96 current_number = VARIABLE;
100 /* Zero fill flag; ignore */
103 current_number *= 10;
115 current_number *= 10;
116 current_number += current - '0';
121 *width = current_number;
172 *prec = current_number;
175 *width = current_number;
180 buf[chars_so_far] = '\0';
184 #if defined(__DJGPP__) || defined(__STRICT_ANSI__)
185 /* vsnprintf is missing in DJGPP (v2.0.3) */
186 # define GC_VSNPRINTF(buf, bufsz, format, args) vsprintf(buf, format, args)
187 #elif defined(_MSC_VER)
188 # if defined(_WIN32_WCE)
189 /* _vsnprintf is deprecated in WinCE */
190 # define GC_VSNPRINTF StringCchVPrintfA
192 # define GC_VSNPRINTF _vsnprintf
195 # define GC_VSNPRINTF vsnprintf
198 int CORD_vsprintf(CORD * out, CORD format, va_list args)
204 char conv_spec[CONV_SPEC_LEN + 1];
206 CORD_ec_init(result);
207 for (CORD_set_pos(pos, format, 0); CORD_pos_valid(pos); CORD_next(pos)) {
208 current = CORD_pos_fetch(pos);
209 if (current == '%') {
211 if (!CORD_pos_valid(pos)) return(-1);
212 current = CORD_pos_fetch(pos);
213 if (current == '%') {
214 CORD_ec_append(result, current);
222 if (extract_conv_spec(pos, conv_spec,
224 &left_adj, &long_arg) < 0) {
227 current = CORD_pos_fetch(pos);
230 /* Assign length to next arg */
233 pos_ptr = va_arg(args, int *);
234 *pos_ptr = ec_len(result);
235 } else if (long_arg > 0) {
237 pos_ptr = va_arg(args, long *);
238 *pos_ptr = ec_len(result);
241 pos_ptr = va_arg(args, short *);
242 *pos_ptr = (short)ec_len(result);
246 /* Append cord and any padding */
247 if (width == VARIABLE) width = va_arg(args, int);
248 if (prec == VARIABLE) prec = va_arg(args, int);
249 arg = va_arg(args, CORD);
251 if (prec != NONE && len > (unsigned)prec) {
252 if (prec < 0) return(-1);
253 arg = CORD_substr(arg, 0, (unsigned)prec);
254 len = (unsigned)prec;
256 if (width != NONE && len < (unsigned)width) {
257 char * blanks = (char *)GC_MALLOC_ATOMIC(
258 (unsigned)width - len + 1);
260 if (NULL == blanks) OUT_OF_MEMORY;
261 memset(blanks, ' ', (unsigned)width - len);
262 blanks[(unsigned)width - len] = '\0';
264 arg = CORD_cat(arg, blanks);
266 arg = CORD_cat(blanks, arg);
269 CORD_ec_append_cord(result, arg);
272 if (width == NONE && prec == NONE) {
275 c = (char)va_arg(args, int);
276 CORD_ec_append(result, c);
281 if (width == NONE && prec == NONE) {
282 char * str = va_arg(args, char *);
285 while ((c = *str++) != '\0') {
286 CORD_ec_append(result, c);
294 /* Use standard sprintf to perform conversion */
297 va_list vsprintf_args;
301 # if defined(CPPCHECK)
302 va_copy(vsprintf_args, args);
303 # elif defined(__va_copy)
304 __va_copy(vsprintf_args, args);
305 # elif defined(__GNUC__) && !defined(__DJGPP__) \
306 && !defined(__EMX__) /* and probably in other cases */
307 va_copy(vsprintf_args, args);
309 vsprintf_args = args;
311 if (width == VARIABLE) width = va_arg(args, int);
312 if (prec == VARIABLE) prec = va_arg(args, int);
313 if (width != NONE) max_size = width;
314 if (prec != NONE && prec > max_size) max_size = prec;
315 max_size += CONV_RESULT_LEN;
316 if (max_size >= CORD_BUFSZ) {
317 buf = (char *)GC_MALLOC_ATOMIC((unsigned)max_size + 1);
318 if (NULL == buf) OUT_OF_MEMORY;
320 if (CORD_BUFSZ - (result[0].ec_bufptr-result[0].ec_buf)
322 CORD_ec_flush_buf(result);
324 buf = result[0].ec_bufptr;
335 (void) va_arg(args, int);
336 } else /* long_arg > 0 */ {
337 (void) va_arg(args, long);
342 (void) va_arg(args, char *);
349 (void) va_arg(args, double);
355 res = GC_VSNPRINTF(buf, max_size + 1, conv_spec,
357 # if defined(CPPCHECK) || defined(__va_copy) \
358 || (defined(__GNUC__) && !defined(__DJGPP__) \
359 && !defined(__EMX__))
360 va_end(vsprintf_args);
363 if ((char *)(GC_word)res == buf) {
364 /* old style vsprintf */
366 } else if (res < 0) {
369 if (buf != result[0].ec_bufptr) {
372 while ((c = *buf++) != '\0') {
373 CORD_ec_append(result, c);
376 result[0].ec_bufptr = buf + len;
382 CORD_ec_append(result, current);
385 count = ec_len(result);
386 *out = CORD_balance(CORD_ec_to_cord(result));
390 int CORD_sprintf(CORD * out, CORD format, ...)
395 va_start(args, format);
396 result = CORD_vsprintf(out, format, args);
401 int CORD_fprintf(FILE * f, CORD format, ...)
405 CORD out = CORD_EMPTY; /* initialized to prevent compiler warning */
407 va_start(args, format);
408 result = CORD_vsprintf(&out, format, args);
410 if (result > 0) CORD_put(out, f);
414 int CORD_vfprintf(FILE * f, CORD format, va_list args)
417 CORD out = CORD_EMPTY;
419 result = CORD_vsprintf(&out, format, args);
420 if (result > 0) CORD_put(out, f);
424 int CORD_printf(CORD format, ...)
428 CORD out = CORD_EMPTY;
430 va_start(args, format);
431 result = CORD_vsprintf(&out, format, args);
433 if (result > 0) CORD_put(out, stdout);
437 int CORD_vprintf(CORD format, va_list args)
440 CORD out = CORD_EMPTY;
442 result = CORD_vsprintf(&out, format, args);
443 if (result > 0) CORD_put(out, stdout);