Import boehm-gc snapshot, taken from
[official-gcc.git] / boehm-gc / cord / cordprnt.c
blob94c49be87d506456cb21396e6ae308f809697e5f
1 /*
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. */
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27 #ifndef CORD_BUILD
28 # define CORD_BUILD
29 #endif
31 #include "cord.h"
32 #include "ec.h"
33 #include <stdio.h>
34 #include <stdarg.h>
35 #include <string.h>
36 #include "gc.h"
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 */
42 /* width and prec. */
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. */
51 # define NONE -1
52 # define VARIABLE -2
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;
72 *width = NONE;
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;
78 switch(current) {
79 case '*':
80 saw_number = 1;
81 current_number = VARIABLE;
82 break;
83 case '0':
84 if (!saw_number) {
85 /* Zero fill flag; ignore */
86 break;
87 } /* otherwise fall through: */
88 case '1':
89 case '2':
90 case '3':
91 case '4':
92 case '5':
93 case '6':
94 case '7':
95 case '8':
96 case '9':
97 saw_number = 1;
98 current_number *= 10;
99 current_number += current - '0';
100 break;
101 case '.':
102 saw_period = 1;
103 if(saw_number) {
104 *width = current_number;
105 saw_number = 0;
107 current_number = 0;
108 break;
109 case 'l':
110 case 'L':
111 *long_arg = 1;
112 current_number = 0;
113 break;
114 case 'h':
115 *long_arg = -1;
116 current_number = 0;
117 break;
118 case ' ':
119 case '+':
120 case '#':
121 current_number = 0;
122 break;
123 case '-':
124 *left = 1;
125 current_number = 0;
126 break;
127 case 'd':
128 case 'i':
129 case 'o':
130 case 'u':
131 case 'x':
132 case 'X':
133 case 'f':
134 case 'e':
135 case 'E':
136 case 'g':
137 case 'G':
138 case 'c':
139 case 'C':
140 case 's':
141 case 'S':
142 case 'p':
143 case 'n':
144 case 'r':
145 goto done;
146 default:
147 return(-1);
149 CORD_next(source);
151 return(-1);
152 done:
153 if (saw_number) {
154 if (saw_period) {
155 *prec = current_number;
156 } else {
157 *prec = NONE;
158 *width = current_number;
160 } else {
161 *prec = NONE;
163 buf[chars_so_far] = '\0';
164 return(result);
167 int CORD_vsprintf(CORD * out, CORD format, va_list args)
169 CORD_ec result;
170 register int count;
171 register char current;
172 CORD_pos pos;
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 == '%') {
179 CORD_next(pos);
180 if (!CORD_pos_valid(pos)) return(-1);
181 current = CORD_pos_fetch(pos);
182 if (current == '%') {
183 CORD_ec_append(result, current);
184 } else {
185 int width, prec;
186 int left_adj = 0;
187 int long_arg = 0;
188 CORD arg;
189 size_t len;
191 if (extract_conv_spec(pos, conv_spec,
192 &width, &prec,
193 &left_adj, &long_arg) < 0) {
194 return(-1);
196 current = CORD_pos_fetch(pos);
197 switch(current) {
198 case 'n':
199 /* Assign length to next arg */
200 if (long_arg == 0) {
201 int * pos_ptr;
202 pos_ptr = va_arg(args, int *);
203 *pos_ptr = ec_len(result);
204 } else if (long_arg > 0) {
205 long * pos_ptr;
206 pos_ptr = va_arg(args, long *);
207 *pos_ptr = ec_len(result);
208 } else {
209 short * pos_ptr;
210 pos_ptr = va_arg(args, short *);
211 *pos_ptr = ec_len(result);
213 goto done;
214 case 'r':
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);
219 len = CORD_len(arg);
220 if (prec != NONE && len > (size_t)prec) {
221 if (prec < 0) return(-1);
222 arg = CORD_substr(arg, 0, prec);
223 len = 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';
230 if (left_adj) {
231 arg = CORD_cat(arg, blanks);
232 } else {
233 arg = CORD_cat(blanks, arg);
236 CORD_ec_append_cord(result, arg);
237 goto done;
238 case 'c':
239 if (width == NONE && prec == NONE) {
240 register char c;
242 c = (char)va_arg(args, int);
243 CORD_ec_append(result, c);
244 goto done;
246 break;
247 case 's':
248 if (width == NONE && prec == NONE) {
249 char * str = va_arg(args, char *);
250 register char c;
252 while ((c = *str++)) {
253 CORD_ec_append(result, c);
255 goto done;
257 break;
258 default:
259 break;
261 /* Use standard sprintf to perform conversion */
263 register char * buf;
264 va_list vsprintf_args;
265 int max_size = 0;
266 int res;
267 # ifdef __va_copy
268 __va_copy(vsprintf_args, args);
269 # else
270 # if defined(__GNUC__) && !defined(__DJGPP__) /* and probably in other cases */
271 va_copy(vsprintf_args, args);
272 # else
273 vsprintf_args = args;
274 # endif
275 # endif
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);
283 } else {
284 if (CORD_BUFSZ - (result[0].ec_bufptr-result[0].ec_buf)
285 < max_size) {
286 CORD_ec_flush_buf(result);
288 buf = result[0].ec_bufptr;
290 switch(current) {
291 case 'd':
292 case 'i':
293 case 'o':
294 case 'u':
295 case 'x':
296 case 'X':
297 case 'c':
298 if (long_arg <= 0) {
299 (void) va_arg(args, int);
300 } else if (long_arg > 0) {
301 (void) va_arg(args, long);
303 break;
304 case 's':
305 case 'p':
306 (void) va_arg(args, char *);
307 break;
308 case 'f':
309 case 'e':
310 case 'E':
311 case 'g':
312 case 'G':
313 (void) va_arg(args, double);
314 break;
315 default:
316 # if defined(__va_copy) \
317 || (defined(__GNUC__) && !defined(__DJGPP__))
318 va_end(vsprintf_args);
319 # endif
320 return(-1);
322 res = vsprintf(buf, conv_spec, vsprintf_args);
323 # if defined(__va_copy) \
324 || (defined(__GNUC__) && !defined(__DJGPP__))
325 va_end(vsprintf_args);
326 # endif
327 len = (size_t)res;
328 if ((char *)(GC_word)res == buf) {
329 /* old style vsprintf */
330 len = strlen(buf);
331 } else if (res < 0) {
332 return(-1);
334 if (buf != result[0].ec_bufptr) {
335 register char c;
337 while ((c = *buf++)) {
338 CORD_ec_append(result, c);
340 } else {
341 result[0].ec_bufptr = buf + len;
344 done:;
346 } else {
347 CORD_ec_append(result, current);
350 count = ec_len(result);
351 *out = CORD_balance(CORD_ec_to_cord(result));
352 return(count);
355 int CORD_sprintf(CORD * out, CORD format, ...)
357 va_list args;
358 int result;
360 va_start(args, format);
361 result = CORD_vsprintf(out, format, args);
362 va_end(args);
363 return(result);
366 int CORD_fprintf(FILE * f, CORD format, ...)
368 va_list args;
369 int result;
370 CORD out = CORD_EMPTY; /* initialized to prevent compiler warning */
372 va_start(args, format);
373 result = CORD_vsprintf(&out, format, args);
374 va_end(args);
375 if (result > 0) CORD_put(out, f);
376 return(result);
379 int CORD_vfprintf(FILE * f, CORD format, va_list args)
381 int result;
382 CORD out = CORD_EMPTY;
384 result = CORD_vsprintf(&out, format, args);
385 if (result > 0) CORD_put(out, f);
386 return(result);
389 int CORD_printf(CORD format, ...)
391 va_list args;
392 int result;
393 CORD out = CORD_EMPTY;
395 va_start(args, format);
396 result = CORD_vsprintf(&out, format, args);
397 va_end(args);
398 if (result > 0) CORD_put(out, stdout);
399 return(result);
402 int CORD_vprintf(CORD format, va_list args)
404 int result;
405 CORD out = CORD_EMPTY;
407 result = CORD_vsprintf(&out, format, args);
408 if (result > 0) CORD_put(out, stdout);
409 return(result);