Annotation of OpenXM_contrib2/asir2000/gc/cord/cordprnt.c, Revision 1.4
1.1 noro 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;
235:
1.4 ! noro 236: c = (char)va_arg(args, int);
1.1 noro 237: CORD_ec_append(result, c);
238: goto done;
239: }
240: break;
241: case 's':
242: if (width == NONE && prec == NONE) {
243: char * str = va_arg(args, char *);
244: register char c;
245:
246: while (c = *str++) {
247: CORD_ec_append(result, c);
248: }
249: goto done;
250: }
251: break;
252: default:
253: break;
254: }
255: /* Use standard sprintf to perform conversion */
256: {
257: register char * buf;
1.4 ! noro 258: va_list vsprintf_args;
1.1 noro 259: int max_size = 0;
260: int res;
1.4 ! noro 261: # ifdef __va_copy
! 262: __va_copy(vsprintf_args, args);
! 263: # else
! 264: # if defined(__GNUC__) /* and probably in other cases */
! 265: va_copy(vsprintf_args, args);
! 266: # else
! 267: vsprintf_args = args;
! 268: # endif
! 269: # endif
1.1 noro 270: if (width == VARIABLE) width = va_arg(args, int);
271: if (prec == VARIABLE) prec = va_arg(args, int);
272: if (width != NONE) max_size = width;
273: if (prec != NONE && prec > max_size) max_size = prec;
274: max_size += CONV_RESULT_LEN;
275: if (max_size >= CORD_BUFSZ) {
276: buf = GC_MALLOC_ATOMIC(max_size + 1);
277: } else {
278: if (CORD_BUFSZ - (result[0].ec_bufptr-result[0].ec_buf)
279: < max_size) {
280: CORD_ec_flush_buf(result);
281: }
282: buf = result[0].ec_bufptr;
283: }
284: switch(current) {
285: case 'd':
286: case 'i':
287: case 'o':
288: case 'u':
289: case 'x':
290: case 'X':
291: case 'c':
292: if (long_arg <= 0) {
293: (void) va_arg(args, int);
294: } else if (long_arg > 0) {
295: (void) va_arg(args, long);
296: }
297: break;
298: case 's':
299: case 'p':
300: (void) va_arg(args, char *);
301: break;
302: case 'f':
303: case 'e':
304: case 'E':
305: case 'g':
306: case 'G':
307: (void) va_arg(args, double);
308: break;
309: default:
310: return(-1);
311: }
312: res = vsprintf(buf, conv_spec, vsprintf_args);
313: len = (size_t)res;
314: if ((char *)(GC_word)res == buf) {
315: /* old style vsprintf */
316: len = strlen(buf);
317: } else if (res < 0) {
318: return(-1);
319: }
320: if (buf != result[0].ec_bufptr) {
321: register char c;
322:
323: while (c = *buf++) {
324: CORD_ec_append(result, c);
325: }
326: } else {
327: result[0].ec_bufptr = buf + len;
328: }
329: }
330: done:;
331: }
332: } else {
333: CORD_ec_append(result, current);
334: }
335: }
336: count = ec_len(result);
337: *out = CORD_balance(CORD_ec_to_cord(result));
338: return(count);
339: }
340:
341: int CORD_sprintf(CORD * out, CORD format, ...)
342: {
343: va_list args;
344: int result;
345:
346: va_start(args, format);
347: result = CORD_vsprintf(out, format, args);
348: va_end(args);
349: return(result);
350: }
351:
352: int CORD_fprintf(FILE * f, CORD format, ...)
353: {
354: va_list args;
355: int result;
356: CORD out;
357:
358: va_start(args, format);
359: result = CORD_vsprintf(&out, format, args);
360: va_end(args);
361: if (result > 0) CORD_put(out, f);
362: return(result);
363: }
364:
365: int CORD_vfprintf(FILE * f, CORD format, va_list args)
366: {
367: int result;
368: CORD out;
369:
370: result = CORD_vsprintf(&out, format, args);
371: if (result > 0) CORD_put(out, f);
372: return(result);
373: }
374:
375: int CORD_printf(CORD format, ...)
376: {
377: va_list args;
378: int result;
379: CORD out;
380:
381: va_start(args, format);
382: result = CORD_vsprintf(&out, format, args);
383: va_end(args);
384: if (result > 0) CORD_put(out, stdout);
385: return(result);
386: }
387:
388: int CORD_vprintf(CORD format, va_list args)
389: {
390: int result;
391: CORD out;
392:
393: result = CORD_vsprintf(&out, format, args);
394: if (result > 0) CORD_put(out, stdout);
395: return(result);
396: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>