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. */
38 #define CONV_SPEC_LEN 50 /* Maximum length of a single */
39 /* conversion specification. */
40 #define CONV_RESULT_LEN 50 /* Maximum length of any */
41 /* conversion with default */
45 static int ec_len(CORD_ec x
)
47 return(CORD_len(x
[0].ec_cord
) + (x
[0].ec_bufptr
- x
[0].ec_buf
));
50 /* Possible nonumeric precision values. */
53 /* Copy the conversion specification from CORD_pos into the buffer buf */
54 /* Return negative on error. */
55 /* Source initially points one past the leading %. */
56 /* It is left pointing at the conversion type. */
57 /* Assign field width and precision to *width and *prec. */
58 /* If width or prec is *, VARIABLE is assigned. */
59 /* Set *left to 1 if left adjustment flag is present. */
60 /* Set *long_arg to 1 if long flag ('l' or 'L') is present, or to */
61 /* -1 if 'h' is present. */
62 static int extract_conv_spec(CORD_pos source
, char *buf
,
63 int * width
, int *prec
, int *left
, int * long_arg
)
65 register int result
= 0;
66 register int current_number
= 0;
67 register int saw_period
= 0;
68 register int saw_number
= 0;
69 register int chars_so_far
= 0;
70 register char current
;
73 buf
[chars_so_far
++] = '%';
74 while(CORD_pos_valid(source
)) {
75 if (chars_so_far
>= CONV_SPEC_LEN
) return(-1);
76 current
= CORD_pos_fetch(source
);
77 buf
[chars_so_far
++] = current
;
81 current_number
= VARIABLE
;
85 /* Zero fill flag; ignore */
87 } /* otherwise fall through: */
99 current_number
+= current
- '0';
104 *width
= current_number
;
155 *prec
= current_number
;
158 *width
= current_number
;
163 buf
[chars_so_far
] = '\0';
167 int CORD_vsprintf(CORD
* out
, CORD format
, va_list args
)
171 register char current
;
173 char conv_spec
[CONV_SPEC_LEN
+ 1];
175 CORD_ec_init(result
);
176 for (CORD_set_pos(pos
, format
, 0); CORD_pos_valid(pos
); CORD_next(pos
)) {
177 current
= CORD_pos_fetch(pos
);
178 if (current
== '%') {
180 if (!CORD_pos_valid(pos
)) return(-1);
181 current
= CORD_pos_fetch(pos
);
182 if (current
== '%') {
183 CORD_ec_append(result
, current
);
191 if (extract_conv_spec(pos
, conv_spec
,
193 &left_adj
, &long_arg
) < 0) {
196 current
= CORD_pos_fetch(pos
);
199 /* Assign length to next arg */
202 pos_ptr
= va_arg(args
, int *);
203 *pos_ptr
= ec_len(result
);
204 } else if (long_arg
> 0) {
206 pos_ptr
= va_arg(args
, long *);
207 *pos_ptr
= ec_len(result
);
210 pos_ptr
= va_arg(args
, short *);
211 *pos_ptr
= ec_len(result
);
215 /* Append cord and any padding */
216 if (width
== VARIABLE
) width
= va_arg(args
, int);
217 if (prec
== VARIABLE
) prec
= va_arg(args
, int);
218 arg
= va_arg(args
, CORD
);
220 if (prec
!= NONE
&& len
> (size_t)prec
) {
221 if (prec
< 0) return(-1);
222 arg
= CORD_substr(arg
, 0, prec
);
225 if (width
!= NONE
&& len
< (size_t)width
) {
226 char * blanks
= GC_MALLOC_ATOMIC(width
-len
+1);
228 memset(blanks
, ' ', width
-len
);
229 blanks
[width
-len
] = '\0';
231 arg
= CORD_cat(arg
, blanks
);
233 arg
= CORD_cat(blanks
, arg
);
236 CORD_ec_append_cord(result
, arg
);
239 if (width
== NONE
&& prec
== NONE
) {
242 c
= (char)va_arg(args
, int);
243 CORD_ec_append(result
, c
);
248 if (width
== NONE
&& prec
== NONE
) {
249 char * str
= va_arg(args
, char *);
252 while ((c
= *str
++)) {
253 CORD_ec_append(result
, c
);
261 /* Use standard sprintf to perform conversion */
264 va_list vsprintf_args
;
268 __va_copy(vsprintf_args
, args
);
270 # if defined(__GNUC__) && !defined(__DJGPP__) /* and probably in other cases */
271 va_copy(vsprintf_args
, args
);
273 vsprintf_args
= args
;
276 if (width
== VARIABLE
) width
= va_arg(args
, int);
277 if (prec
== VARIABLE
) prec
= va_arg(args
, int);
278 if (width
!= NONE
) max_size
= width
;
279 if (prec
!= NONE
&& prec
> max_size
) max_size
= prec
;
280 max_size
+= CONV_RESULT_LEN
;
281 if (max_size
>= CORD_BUFSZ
) {
282 buf
= GC_MALLOC_ATOMIC(max_size
+ 1);
284 if (CORD_BUFSZ
- (result
[0].ec_bufptr
-result
[0].ec_buf
)
286 CORD_ec_flush_buf(result
);
288 buf
= result
[0].ec_bufptr
;
299 (void) va_arg(args
, int);
300 } else if (long_arg
> 0) {
301 (void) va_arg(args
, long);
306 (void) va_arg(args
, char *);
313 (void) va_arg(args
, double);
316 # if defined(__va_copy) \
317 || (defined(__GNUC__) && !defined(__DJGPP__))
318 va_end(vsprintf_args
);
322 res
= vsprintf(buf
, conv_spec
, vsprintf_args
);
323 # if defined(__va_copy) \
324 || (defined(__GNUC__) && !defined(__DJGPP__))
325 va_end(vsprintf_args
);
328 if ((char *)(GC_word
)res
== buf
) {
329 /* old style vsprintf */
331 } else if (res
< 0) {
334 if (buf
!= result
[0].ec_bufptr
) {
337 while ((c
= *buf
++)) {
338 CORD_ec_append(result
, c
);
341 result
[0].ec_bufptr
= buf
+ len
;
347 CORD_ec_append(result
, current
);
350 count
= ec_len(result
);
351 *out
= CORD_balance(CORD_ec_to_cord(result
));
355 int CORD_sprintf(CORD
* out
, CORD format
, ...)
360 va_start(args
, format
);
361 result
= CORD_vsprintf(out
, format
, args
);
366 int CORD_fprintf(FILE * f
, CORD format
, ...)
370 CORD out
= CORD_EMPTY
; /* initialized to prevent compiler warning */
372 va_start(args
, format
);
373 result
= CORD_vsprintf(&out
, format
, args
);
375 if (result
> 0) CORD_put(out
, f
);
379 int CORD_vfprintf(FILE * f
, CORD format
, va_list args
)
382 CORD out
= CORD_EMPTY
;
384 result
= CORD_vsprintf(&out
, format
, args
);
385 if (result
> 0) CORD_put(out
, f
);
389 int CORD_printf(CORD format
, ...)
393 CORD out
= CORD_EMPTY
;
395 va_start(args
, format
);
396 result
= CORD_vsprintf(&out
, format
, args
);
398 if (result
> 0) CORD_put(out
, stdout
);
402 int CORD_vprintf(CORD format
, va_list args
)
405 CORD out
= CORD_EMPTY
;
407 result
= CORD_vsprintf(&out
, format
, args
);
408 if (result
> 0) CORD_put(out
, stdout
);