OSDN Git Service

libjava:
[pf3gnuchains/gcc-fork.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;
235
236                             c = (char)va_arg(args, int);
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;
258                     va_list vsprintf_args;
259                     int max_size = 0;
260                     int res;
261 #                   ifdef __va_copy
262                       __va_copy(vsprintf_args, args);
263 #                   else
264 #                     if defined(__GNUC__) && !defined(__DJGPP__) /* and probably in other cases */
265                         va_copy(vsprintf_args, args);
266 #                     else
267                         vsprintf_args = args;
268 #                     endif
269 #                   endif
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 }