]> gcc.gnu.org Git - gcc.git/blob - boehm-gc/cord/cordprnt.c
Initial revision
[gcc.git] / boehm-gc / cord / cordprnt.c
1 /*
2 * Copyright (c) 1993-1994 by Xerox Corporation. All rights reserved.
3 *
4 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
5 * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
6 *
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.
12 */
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 */
24
25 #include "cord.h"
26 #include "ec.h"
27 #include <stdio.h>
28 #include <stdarg.h>
29 #include <string.h>
30 #include "gc.h"
31
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 */
36 /* width and prec. */
37
38
39 static int ec_len(CORD_ec x)
40 {
41 return(CORD_len(x[0].ec_cord) + (x[0].ec_bufptr - x[0].ec_buf));
42 }
43
44 /* Possible nonumeric precision values. */
45 # define NONE -1
46 # define VARIABLE -2
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)
58 {
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;
65
66 *width = NONE;
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;
72 switch(current) {
73 case '*':
74 saw_number = 1;
75 current_number = VARIABLE;
76 break;
77 case '0':
78 if (!saw_number) {
79 /* Zero fill flag; ignore */
80 break;
81 } /* otherwise fall through: */
82 case '1':
83 case '2':
84 case '3':
85 case '4':
86 case '5':
87 case '6':
88 case '7':
89 case '8':
90 case '9':
91 saw_number = 1;
92 current_number *= 10;
93 current_number += current - '0';
94 break;
95 case '.':
96 saw_period = 1;
97 if(saw_number) {
98 *width = current_number;
99 saw_number = 0;
100 }
101 current_number = 0;
102 break;
103 case 'l':
104 case 'L':
105 *long_arg = 1;
106 current_number = 0;
107 break;
108 case 'h':
109 *long_arg = -1;
110 current_number = 0;
111 break;
112 case ' ':
113 case '+':
114 case '#':
115 current_number = 0;
116 break;
117 case '-':
118 *left = 1;
119 current_number = 0;
120 break;
121 case 'd':
122 case 'i':
123 case 'o':
124 case 'u':
125 case 'x':
126 case 'X':
127 case 'f':
128 case 'e':
129 case 'E':
130 case 'g':
131 case 'G':
132 case 'c':
133 case 'C':
134 case 's':
135 case 'S':
136 case 'p':
137 case 'n':
138 case 'r':
139 goto done;
140 default:
141 return(-1);
142 }
143 CORD_next(source);
144 }
145 return(-1);
146 done:
147 if (saw_number) {
148 if (saw_period) {
149 *prec = current_number;
150 } else {
151 *prec = NONE;
152 *width = current_number;
153 }
154 } else {
155 *prec = NONE;
156 }
157 buf[chars_so_far] = '\0';
158 return(result);
159 }
160
161 int CORD_vsprintf(CORD * out, CORD format, va_list args)
162 {
163 CORD_ec result;
164 register int count;
165 register char current;
166 CORD_pos pos;
167 char conv_spec[CONV_SPEC_LEN + 1];
168
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 == '%') {
173 CORD_next(pos);
174 if (!CORD_pos_valid(pos)) return(-1);
175 current = CORD_pos_fetch(pos);
176 if (current == '%') {
177 CORD_ec_append(result, current);
178 } else {
179 int width, prec;
180 int left_adj = 0;
181 int long_arg = 0;
182 CORD arg;
183 size_t len;
184
185 if (extract_conv_spec(pos, conv_spec,
186 &width, &prec,
187 &left_adj, &long_arg) < 0) {
188 return(-1);
189 }
190 current = CORD_pos_fetch(pos);
191 switch(current) {
192 case 'n':
193 /* Assign length to next arg */
194 if (long_arg == 0) {
195 int * pos_ptr;
196 pos_ptr = va_arg(args, int *);
197 *pos_ptr = ec_len(result);
198 } else if (long_arg > 0) {
199 long * pos_ptr;
200 pos_ptr = va_arg(args, long *);
201 *pos_ptr = ec_len(result);
202 } else {
203 short * pos_ptr;
204 pos_ptr = va_arg(args, short *);
205 *pos_ptr = ec_len(result);
206 }
207 goto done;
208 case 'r':
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);
213 len = CORD_len(arg);
214 if (prec != NONE && len > prec) {
215 if (prec < 0) return(-1);
216 arg = CORD_substr(arg, 0, prec);
217 len = prec;
218 }
219 if (width != NONE && len < width) {
220 char * blanks = GC_MALLOC_ATOMIC(width-len+1);
221
222 memset(blanks, ' ', width-len);
223 blanks[width-len] = '\0';
224 if (left_adj) {
225 arg = CORD_cat(arg, blanks);
226 } else {
227 arg = CORD_cat(blanks, arg);
228 }
229 }
230 CORD_ec_append_cord(result, arg);
231 goto done;
232 case 'c':
233 if (width == NONE && prec == NONE) {
234 register char c = va_arg(args, char);
235
236 CORD_ec_append(result, c);
237 goto done;
238 }
239 break;
240 case 's':
241 if (width == NONE && prec == NONE) {
242 char * str = va_arg(args, char *);
243 register char c;
244
245 while (c = *str++) {
246 CORD_ec_append(result, c);
247 }
248 goto done;
249 }
250 break;
251 default:
252 break;
253 }
254 /* Use standard sprintf to perform conversion */
255 {
256 register char * buf;
257 va_list vsprintf_args = args;
258 /* The above does not appear to be sanctioned */
259 /* by the ANSI C standard. */
260 int max_size = 0;
261 int res;
262
263 if (width == VARIABLE) width = va_arg(args, int);
264 if (prec == VARIABLE) prec = va_arg(args, int);
265 if (width != NONE) max_size = width;
266 if (prec != NONE && prec > max_size) max_size = prec;
267 max_size += CONV_RESULT_LEN;
268 if (max_size >= CORD_BUFSZ) {
269 buf = GC_MALLOC_ATOMIC(max_size + 1);
270 } else {
271 if (CORD_BUFSZ - (result[0].ec_bufptr-result[0].ec_buf)
272 < max_size) {
273 CORD_ec_flush_buf(result);
274 }
275 buf = result[0].ec_bufptr;
276 }
277 switch(current) {
278 case 'd':
279 case 'i':
280 case 'o':
281 case 'u':
282 case 'x':
283 case 'X':
284 case 'c':
285 if (long_arg <= 0) {
286 (void) va_arg(args, int);
287 } else if (long_arg > 0) {
288 (void) va_arg(args, long);
289 }
290 break;
291 case 's':
292 case 'p':
293 (void) va_arg(args, char *);
294 break;
295 case 'f':
296 case 'e':
297 case 'E':
298 case 'g':
299 case 'G':
300 (void) va_arg(args, double);
301 break;
302 default:
303 return(-1);
304 }
305 res = vsprintf(buf, conv_spec, vsprintf_args);
306 len = (size_t)res;
307 if ((char *)(GC_word)res == buf) {
308 /* old style vsprintf */
309 len = strlen(buf);
310 } else if (res < 0) {
311 return(-1);
312 }
313 if (buf != result[0].ec_bufptr) {
314 register char c;
315
316 while (c = *buf++) {
317 CORD_ec_append(result, c);
318 }
319 } else {
320 result[0].ec_bufptr = buf + len;
321 }
322 }
323 done:;
324 }
325 } else {
326 CORD_ec_append(result, current);
327 }
328 }
329 count = ec_len(result);
330 *out = CORD_balance(CORD_ec_to_cord(result));
331 return(count);
332 }
333
334 int CORD_sprintf(CORD * out, CORD format, ...)
335 {
336 va_list args;
337 int result;
338
339 va_start(args, format);
340 result = CORD_vsprintf(out, format, args);
341 va_end(args);
342 return(result);
343 }
344
345 int CORD_fprintf(FILE * f, CORD format, ...)
346 {
347 va_list args;
348 int result;
349 CORD out;
350
351 va_start(args, format);
352 result = CORD_vsprintf(&out, format, args);
353 va_end(args);
354 if (result > 0) CORD_put(out, f);
355 return(result);
356 }
357
358 int CORD_vfprintf(FILE * f, CORD format, va_list args)
359 {
360 int result;
361 CORD out;
362
363 result = CORD_vsprintf(&out, format, args);
364 if (result > 0) CORD_put(out, f);
365 return(result);
366 }
367
368 int CORD_printf(CORD format, ...)
369 {
370 va_list args;
371 int result;
372 CORD out;
373
374 va_start(args, format);
375 result = CORD_vsprintf(&out, format, args);
376 va_end(args);
377 if (result > 0) CORD_put(out, stdout);
378 return(result);
379 }
380
381 int CORD_vprintf(CORD format, va_list args)
382 {
383 int result;
384 CORD out;
385
386 result = CORD_vsprintf(&out, format, args);
387 if (result > 0) CORD_put(out, stdout);
388 return(result);
389 }
This page took 0.053212 seconds and 5 git commands to generate.