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
;
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
= va_arg(args
, int);
237 CORD_ec_append(result
, c
);
242 if (width
== NONE
&& prec
== NONE
) {
243 char * str
= va_arg(args
, char *);
247 CORD_ec_append(result
, c
);
255 /* Use standard sprintf to perform conversion */
258 va_list vsprintf_args
= args
;
259 /* The above does not appear to be sanctioned */
260 /* by the ANSI C standard. */
264 if (width
== VARIABLE
) width
= va_arg(args
, int);
265 if (prec
== VARIABLE
) prec
= va_arg(args
, int);
266 if (width
!= NONE
) max_size
= width
;
267 if (prec
!= NONE
&& prec
> max_size
) max_size
= prec
;
268 max_size
+= CONV_RESULT_LEN
;
269 if (max_size
>= CORD_BUFSZ
) {
270 buf
= GC_MALLOC_ATOMIC(max_size
+ 1);
272 if (CORD_BUFSZ
- (result
[0].ec_bufptr
-result
[0].ec_buf
)
274 CORD_ec_flush_buf(result
);
276 buf
= result
[0].ec_bufptr
;
287 (void) va_arg(args
, int);
288 } else if (long_arg
> 0) {
289 (void) va_arg(args
, long);
294 (void) va_arg(args
, char *);
301 (void) va_arg(args
, double);
306 res
= vsprintf(buf
, conv_spec
, vsprintf_args
);
308 if ((char *)(GC_word
)res
== buf
) {
309 /* old style vsprintf */
311 } else if (res
< 0) {
314 if (buf
!= result
[0].ec_bufptr
) {
318 CORD_ec_append(result
, c
);
321 result
[0].ec_bufptr
= buf
+ len
;
327 CORD_ec_append(result
, current
);
330 count
= ec_len(result
);
331 *out
= CORD_balance(CORD_ec_to_cord(result
));
335 int CORD_sprintf(CORD
* out
, CORD format
, ...)
340 va_start(args
, format
);
341 result
= CORD_vsprintf(out
, format
, args
);
346 int CORD_fprintf(FILE * f
, CORD format
, ...)
352 va_start(args
, format
);
353 result
= CORD_vsprintf(&out
, format
, args
);
355 if (result
> 0) CORD_put(out
, f
);
359 int CORD_vfprintf(FILE * f
, CORD format
, va_list args
)
364 result
= CORD_vsprintf(&out
, format
, args
);
365 if (result
> 0) CORD_put(out
, f
);
369 int CORD_printf(CORD format
, ...)
375 va_start(args
, format
);
376 result
= CORD_vsprintf(&out
, format
, args
);
378 if (result
> 0) CORD_put(out
, stdout
);
382 int CORD_vprintf(CORD format
, va_list args
)
387 result
= CORD_vsprintf(&out
, format
, args
);
388 if (result
> 0) CORD_put(out
, stdout
);