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