implemented Setup.hs to build boehm cpp libs and install them;
[hs-boehmgc.git] / gc-7.2 / 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 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.                            */
23
24 #include "cord.h"
25 #include "ec.h"
26 #include <stdio.h>
27 #include <stdarg.h>
28 #include <string.h>
29 #include "gc.h"
30
31 #define CONV_SPEC_LEN 50        /* Maximum length of a single   */
32                                 /* conversion specification.    */
33 #define CONV_RESULT_LEN 50      /* Maximum length of any        */
34                                 /* conversion with default      */
35                                 /* width and prec.              */
36
37
38 static int ec_len(CORD_ec x)
39 {
40     return(CORD_len(x[0].ec_cord) + (x[0].ec_bufptr - x[0].ec_buf));
41 }
42
43 /* Possible nonumeric precision values. */
44 # define NONE -1
45 # define VARIABLE -2
46 /* Copy the conversion specification from CORD_pos into the buffer buf  */
47 /* Return negative on error.                                            */
48 /* Source initially points one past the leading %.                      */
49 /* It is left pointing at the conversion type.                          */
50 /* Assign field width and precision to *width and *prec.                */
51 /* If width or prec is *, VARIABLE is assigned.                         */
52 /* Set *left to 1 if left adjustment flag is present.                   */
53 /* Set *long_arg to 1 if long flag ('l' or 'L') is present, or to       */
54 /* -1 if 'h' is present.                                                */
55 static int extract_conv_spec(CORD_pos source, char *buf,
56                              int * width, int *prec, int *left, int * long_arg)
57 {
58     register int result = 0;
59     register int current_number = 0;
60     register int saw_period = 0;
61     register int saw_number = 0;
62     register int chars_so_far = 0;
63     register char current;
64
65     *width = NONE;
66     buf[chars_so_far++] = '%';
67     while(CORD_pos_valid(source)) {
68         if (chars_so_far >= CONV_SPEC_LEN) return(-1);
69         current = CORD_pos_fetch(source);
70         buf[chars_so_far++] = current;
71         switch(current) {
72           case '*':
73             saw_number = 1;
74             current_number = VARIABLE;
75             break;
76           case '0':
77             if (!saw_number) {
78                 /* Zero fill flag; ignore */
79                 break;
80             } /* otherwise fall through: */
81           case '1':
82           case '2':
83           case '3':
84           case '4':
85           case '5':
86           case '6':
87           case '7':
88           case '8':
89           case '9':
90             saw_number = 1;
91             current_number *= 10;
92             current_number += current - '0';
93             break;
94           case '.':
95             saw_period = 1;
96             if(saw_number) {
97                 *width = current_number;
98                 saw_number = 0;
99             }
100             current_number = 0;
101             break;
102           case 'l':
103           case 'L':
104             *long_arg = 1;
105             current_number = 0;
106             break;
107           case 'h':
108             *long_arg = -1;
109             current_number = 0;
110             break;
111           case ' ':
112           case '+':
113           case '#':
114             current_number = 0;
115             break;
116           case '-':
117             *left = 1;
118             current_number = 0;
119             break;
120           case 'd':
121           case 'i':
122           case 'o':
123           case 'u':
124           case 'x':
125           case 'X':
126           case 'f':
127           case 'e':
128           case 'E':
129           case 'g':
130           case 'G':
131           case 'c':
132           case 'C':
133           case 's':
134           case 'S':
135           case 'p':
136           case 'n':
137           case 'r':
138             goto done;
139           default:
140             return(-1);
141         }
142         CORD_next(source);
143     }
144     return(-1);
145   done:
146     if (saw_number) {
147         if (saw_period) {
148             *prec = current_number;
149         } else {
150             *prec = NONE;
151             *width = current_number;
152         }
153     } else {
154         *prec = NONE;
155     }
156     buf[chars_so_far] = '\0';
157     return(result);
158 }
159
160 int CORD_vsprintf(CORD * out, CORD format, va_list args)
161 {
162     CORD_ec result;
163     register int count;
164     register char current;
165     CORD_pos pos;
166     char conv_spec[CONV_SPEC_LEN + 1];
167
168     CORD_ec_init(result);
169     for (CORD_set_pos(pos, format, 0); CORD_pos_valid(pos); CORD_next(pos)) {
170         current = CORD_pos_fetch(pos);
171         if (current == '%') {
172             CORD_next(pos);
173             if (!CORD_pos_valid(pos)) return(-1);
174             current = CORD_pos_fetch(pos);
175             if (current == '%') {
176                 CORD_ec_append(result, current);
177             } else {
178                 int width, prec;
179                 int left_adj = 0;
180                 int long_arg = 0;
181                 CORD arg;
182                 size_t len;
183
184                 if (extract_conv_spec(pos, conv_spec,
185                                       &width, &prec,
186                                       &left_adj, &long_arg) < 0) {
187                     return(-1);
188                 }
189                 current = CORD_pos_fetch(pos);
190                 switch(current) {
191                     case 'n':
192                         /* Assign length to next arg */
193                         if (long_arg == 0) {
194                             int * pos_ptr;
195                             pos_ptr = va_arg(args, int *);
196                             *pos_ptr = ec_len(result);
197                         } else if (long_arg > 0) {
198                             long * pos_ptr;
199                             pos_ptr = va_arg(args, long *);
200                             *pos_ptr = ec_len(result);
201                         } else {
202                             short * pos_ptr;
203                             pos_ptr = va_arg(args, short *);
204                             *pos_ptr = ec_len(result);
205                         }
206                         goto done;
207                     case 'r':
208                         /* Append cord and any padding  */
209                         if (width == VARIABLE) width = va_arg(args, int);
210                         if (prec == VARIABLE) prec = va_arg(args, int);
211                         arg = va_arg(args, CORD);
212                         len = CORD_len(arg);
213                         if (prec != NONE && len > (size_t)prec) {
214                           if (prec < 0) return(-1);
215                           arg = CORD_substr(arg, 0, prec);
216                           len = prec;
217                         }
218                         if (width != NONE && len < (size_t)width) {
219                           char * blanks = GC_MALLOC_ATOMIC(width-len+1);
220
221                           memset(blanks, ' ', width-len);
222                           blanks[width-len] = '\0';
223                           if (left_adj) {
224                             arg = CORD_cat(arg, blanks);
225                           } else {
226                             arg = CORD_cat(blanks, arg);
227                           }
228                         }
229                         CORD_ec_append_cord(result, arg);
230                         goto done;
231                     case 'c':
232                         if (width == NONE && prec == NONE) {
233                             register char c;
234
235                             c = (char)va_arg(args, int);
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;
258                     int max_size = 0;
259                     int res;
260 #                   ifdef __va_copy
261                       __va_copy(vsprintf_args, args);
262 #                   else
263 #                     if defined(__GNUC__) && !defined(__DJGPP__) /* and probably in other cases */
264                         va_copy(vsprintf_args, args);
265 #                     else
266                         vsprintf_args = args;
267 #                     endif
268 #                   endif
269                     if (width == VARIABLE) width = va_arg(args, int);
270                     if (prec == VARIABLE) prec = va_arg(args, int);
271                     if (width != NONE) max_size = width;
272                     if (prec != NONE && prec > max_size) max_size = prec;
273                     max_size += CONV_RESULT_LEN;
274                     if (max_size >= CORD_BUFSZ) {
275                         buf = GC_MALLOC_ATOMIC(max_size + 1);
276                     } else {
277                         if (CORD_BUFSZ - (result[0].ec_bufptr-result[0].ec_buf)
278                             < max_size) {
279                             CORD_ec_flush_buf(result);
280                         }
281                         buf = result[0].ec_bufptr;
282                     }
283                     switch(current) {
284                         case 'd':
285                         case 'i':
286                         case 'o':
287                         case 'u':
288                         case 'x':
289                         case 'X':
290                         case 'c':
291                             if (long_arg <= 0) {
292                               (void) va_arg(args, int);
293                             } else if (long_arg > 0) {
294                               (void) va_arg(args, long);
295                             }
296                             break;
297                         case 's':
298                         case 'p':
299                             (void) va_arg(args, char *);
300                             break;
301                         case 'f':
302                         case 'e':
303                         case 'E':
304                         case 'g':
305                         case 'G':
306                             (void) va_arg(args, double);
307                             break;
308                         default:
309                             return(-1);
310                     }
311                     res = vsprintf(buf, conv_spec, vsprintf_args);
312                     len = (size_t)res;
313                     if ((char *)(GC_word)res == buf) {
314                         /* old style vsprintf */
315                         len = strlen(buf);
316                     } else if (res < 0) {
317                         return(-1);
318                     }
319                     if (buf != result[0].ec_bufptr) {
320                         register char c;
321
322                         while ((c = *buf++)) {
323                             CORD_ec_append(result, c);
324                         }
325                     } else {
326                         result[0].ec_bufptr = buf + len;
327                     }
328                 }
329               done:;
330             }
331         } else {
332             CORD_ec_append(result, current);
333         }
334     }
335     count = ec_len(result);
336     *out = CORD_balance(CORD_ec_to_cord(result));
337     return(count);
338 }
339
340 int CORD_sprintf(CORD * out, CORD format, ...)
341 {
342     va_list args;
343     int result;
344
345     va_start(args, format);
346     result = CORD_vsprintf(out, format, args);
347     va_end(args);
348     return(result);
349 }
350
351 int CORD_fprintf(FILE * f, CORD format, ...)
352 {
353     va_list args;
354     int result;
355     CORD out;
356
357     va_start(args, format);
358     result = CORD_vsprintf(&out, format, args);
359     va_end(args);
360     if (result > 0) CORD_put(out, f);
361     return(result);
362 }
363
364 int CORD_vfprintf(FILE * f, CORD format, va_list args)
365 {
366     int result;
367     CORD out;
368
369     result = CORD_vsprintf(&out, format, args);
370     if (result > 0) CORD_put(out, f);
371     return(result);
372 }
373
374 int CORD_printf(CORD format, ...)
375 {
376     va_list args;
377     int result;
378     CORD out;
379
380     va_start(args, format);
381     result = CORD_vsprintf(&out, format, args);
382     va_end(args);
383     if (result > 0) CORD_put(out, stdout);
384     return(result);
385 }
386
387 int CORD_vprintf(CORD format, va_list args)
388 {
389     int result;
390     CORD out;
391
392     result = CORD_vsprintf(&out, format, args);
393     if (result > 0) CORD_put(out, stdout);
394     return(result);
395 }