ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/cms/source/ihost/libukcprog/formf.c
Revision: 1.1
Committed: Fri Mar 8 14:37:29 2002 UTC (22 years, 6 months ago) by tdb
Content type: text/plain
Branch: MAIN
CVS Tags: IHOST_1_5_3, IHOST_1_5_2, IHOST_1_5_1, IHOST_1_5, IHOST_1_0_RC1
Log Message:
I'm not usually up for putting third party sources in here, but in this
case I'll make an exception. This is ukcprog, a set of useful C functions
which the ihost plugins Pete's writing uses. It's got a pretty free license
too. I've munged the Makefile around, as all it needs to do now is make the
library, not install anything. The idea is to statically compile the other
programs against this library, making the final binary independent of this
code etc.

File Contents

# User Rev Content
1 tdb 1.1 /* formf.c -- formatted strings and error messages */
2    
3     /* Copyright 1992 Godfrey Paul, University of Kent at Canterbury.
4     *
5     * You can do what you like with this source code as long as
6     * you don't try to make money out of it and you include an
7     * unaltered copy of this message (including the copyright).
8     */
9    
10     char ukcprog_formf_sccsid[] = "$Id: formf.c,v 1.25 1999/07/15 11:10:21 djb1 Exp $ UKC";
11    
12     #ifdef __STDC__
13     #include <stdarg.h>
14     #else
15     #include <varargs.h>
16     #endif
17    
18     #include <stdio.h>
19     #include <ctype.h>
20     #include <errno.h>
21     #include <stdlib.h>
22     #include <string.h>
23     #ifndef __STDC__
24     #include <memory.h>
25     #endif
26    
27     #include "ukcprog.h"
28    
29     #ifndef MSDOS
30     #ifndef __FreeBSD__
31     #ifndef linux
32     extern int sys_nerr, errno;
33     extern char *sys_errlist[];
34     #endif /* !linux */
35     #endif /* !__FreeBSD__ */
36     #endif /* !MSDOS */
37    
38    
39     /* forward declarations */
40     static void new_buffer PROTO((char ** p_buf, int *p_lim, bool *p_from_malloc));
41     static void concat PROTO((char **p_buf, int *p_pos, int* p_lim,
42     bool *p_from_malloc, const char *str, int len));
43     static char *long_to_ascii PROTO((unsigned long unum, int base,
44     bool want_uppercase));
45     static char *float_to_ascii PROTO((double d, int precision));
46     static char *efloat_to_ascii PROTO((double d, int precision,
47     bool want_uppercase));
48     static char *gfloat_to_ascii PROTO((double d, int precision,
49     bool want_uppercase));
50    
51     #define MAX_NUM_LEN 40 /* buffer sizes used in numeric conversions */
52     #define MAX_FLOAT_LEN 128
53    
54    
55     /*
56     * new_buffer()
57     * Reallocate the given buffer to twice its current size. *p_lim is the
58     * last usable character in the buffer. The buffer passed in might
59     * not have been allocated by malloc(); this is indicated by *p_from_malloc.
60     */
61     static void
62     new_buffer(p_buf, p_lim, p_from_malloc)
63     char **p_buf;
64     int *p_lim;
65     bool *p_from_malloc;
66     {
67     char *new;
68     size_t size;
69    
70     size = *p_lim + 1;
71    
72     if (*p_from_malloc)
73     new = realloc(*p_buf, size * 2);
74    
75     else {
76     if ((new = malloc(size * 2)) != NULL)
77     memcpy(new, *p_buf, size);
78     *p_from_malloc = TRUE;
79     }
80    
81     if (new == NULL)
82     panic("malloc returned NULL in new_buffer");
83    
84     *p_buf = new;
85     *p_lim = (size * 2) - 1;
86     }
87    
88    
89     /*
90     * concat()
91     * Add exactly len bytes of str to the buffer, expanding it with
92     * new_buffer() if we need extra space. Str must be at least len
93     * bytes long.
94     */
95     static void
96     concat(p_buf, p_pos, p_lim, p_from_malloc, str, len)
97     char **p_buf;
98     int *p_pos, *p_lim;
99     bool *p_from_malloc;
100     const char *str;
101     int len;
102     {
103     while (*p_lim - *p_pos < len)
104     new_buffer(p_buf, p_lim, p_from_malloc);
105    
106     memcpy(&(*p_buf)[*p_pos], str, (size_t)len);
107     *p_pos += len;
108     }
109    
110    
111     static char *
112     long_to_ascii(unum, base, want_uppercase)
113     unsigned long unum;
114     int base;
115     bool want_uppercase;
116     {
117     static char nbuf[MAX_NUM_LEN + 1];
118     char *s;
119     const char *digs;
120    
121     s = nbuf + MAX_NUM_LEN;
122    
123     digs = want_uppercase ? "0123456789ABCDEF" : "0123456789abcdef";
124     do {
125     *--s = digs[unum % base];
126     unum /= base;
127     } while (unum != 0);
128    
129    
130     return s;
131     }
132    
133    
134     static char *
135     float_to_ascii(d, precision)
136     double d;
137     int precision;
138     {
139     static char buf[MAX_FLOAT_LEN];
140    
141     sprintf(buf, "%.*f", precision, d);
142     return buf;
143     }
144    
145    
146     static char *
147     efloat_to_ascii(d, precision, want_uppercase)
148     double d;
149     int precision;
150     bool want_uppercase;
151     {
152     static char buf[MAX_FLOAT_LEN];
153     const char *format;
154    
155     if (want_uppercase)
156     format = "%.*E";
157     else
158     format = "%.*e";
159    
160     sprintf(buf, format, precision, d);
161     return buf;
162     }
163    
164    
165    
166     static char *
167     gfloat_to_ascii(d, precision, want_uppercase)
168     double d;
169     int precision;
170     bool want_uppercase;
171     {
172     static char buf[MAX_FLOAT_LEN];
173     const char *format;
174    
175     if (want_uppercase)
176     format = "%.*G";
177     else
178     format = "%.*g";
179    
180     sprintf(buf, format, precision, d);
181     return buf;
182     }
183    
184     #ifdef VMS
185     static const char *
186     vms_error_text(unsigned long msgid)
187     {
188     unsigned long status;
189     unsigned short msglen;
190     static char buf[256 + 1];
191     static struct dsc$descriptor_s msg = {
192     sizeof buf - 1, /* length */
193     DSC$K_DTYPE_T, /* data type (8 bit chars) */
194     DSC$K_CLASS_S, /* class (fixed length) */
195     buf
196     };
197    
198     status = SYS$GETMSG(msgid, &msglen, &msg, 0, 0);
199     if (status != SS$_NORMAL && status != SS$_MSGNOTFND)
200     sprintf(buf, "Unknown VMS message ID 0x%x", msgid);
201     else
202     buf[msglen] = '\0';
203    
204     return buf;
205     }
206     #endif /* VMS */
207    
208     /*
209     * formf()
210     * Returns a pointer to a string formatted from the arguments given.
211     * If the string has been obtained from malloc(), the return value will
212     * be different to the buffer pased in; it is the caller's responsibility
213     * to free() this when no longer required.
214     */
215     char *
216     formf(buffer_space, buffer_size, format, args)
217     char *buffer_space;
218     int buffer_size;
219     const char *format;
220     va_list args;
221     {
222     bool left_justify, print_sign, zero_pad, alternate_form;
223     bool is_negative, precision_given, want_uppercase, from_malloc;
224     int min_field_width, precision, modifier, base, pos, lim, len;
225     const char *fmt, *alternate_prefix, *s;
226     char *buf, str[2], errno_buffer[42];
227     int alternate_size, saved_errno;
228     unsigned long u;
229     long i;
230     int *ip;
231     double d;
232    
233     saved_errno = errno; /* for use later in %m format */
234    
235     /*
236     * The formatted string is prepared in a buffer pointed to by buf.
237     * This starts out pointing to a buffer passed in as an argument,
238     * but if this fills, a new one is obtained from malloc().
239     * Pos is the index of the position for the *next* character
240     * in the output string, and lim is the index of the last
241     * usable character.
242     */
243     from_malloc = FALSE;
244     buf = buffer_space;
245     lim = buffer_size - 1;
246     pos = 0;
247     fmt = format;
248    
249     for (;;) {
250     min_field_width = 0;
251     precision_given = FALSE;
252     precision = 0;
253     modifier = 0;
254     left_justify = FALSE;
255     print_sign = FALSE;
256     zero_pad = FALSE;
257     alternate_form = FALSE;
258    
259     /* Find next argument for conversion */
260     while (*fmt != '\0' && *fmt != '%') {
261     if (pos == lim)
262     new_buffer(&buf, &lim, &from_malloc);
263    
264     buf[pos++] = *fmt++;
265     }
266    
267     if (*fmt == '\0') {
268     buf[pos] = '\0';
269     return buf; /* end of format string */
270     }
271    
272     /* flags, in any order */
273     for (;;) {
274     if (*++fmt == '\0')
275     panic("confused format flags in formf");
276    
277     if (*fmt == '-')
278     left_justify = TRUE;
279    
280     else if (*fmt == '+')
281     print_sign = TRUE;
282    
283     else if (*fmt == '0')
284     zero_pad = TRUE;
285    
286     else if (*fmt == '#')
287     alternate_form = TRUE;
288    
289     else
290     break; /* end of flags */
291    
292     }
293    
294     /* minimum field width */
295     if (*fmt == '*') {
296     min_field_width = va_arg(args, int);
297     ++fmt;
298     } else
299     while (isdigit(*fmt)) {
300     min_field_width *= 10;
301     min_field_width += *fmt - '0';
302     ++fmt;
303     }
304    
305     if (*fmt == '.') {
306    
307     /* precision */
308     if (*++fmt == '*') {
309     precision_given = TRUE;
310     precision = va_arg(args, int);
311     ++fmt;
312     } else if (isdigit(*fmt)) {
313     precision_given = TRUE;
314     precision = 0;
315     do {
316     precision *= 10;
317     precision += *fmt - '0';
318     ++fmt;
319     } while (isdigit(*fmt));
320     }
321     }
322    
323     if (strchr("hlL", *fmt) != NULL)
324     modifier = *fmt++;
325    
326     want_uppercase = TRUE;
327     alternate_prefix = "0X";
328     alternate_size = 2;
329     is_negative = FALSE;
330    
331     switch (*fmt) {
332     case 'd':
333     case 'i':
334     if (modifier == 'h')
335     i = va_arg(args, short);
336     else if (modifier == 'l')
337     i = va_arg(args, long);
338     else
339     i = va_arg(args, int);
340     is_negative = i < 0;
341     u = is_negative ? -i : i;
342     s = long_to_ascii(u, 10, want_uppercase);
343     break;
344    
345     case 'o':
346     base = 8;
347     alternate_prefix = "0";
348     alternate_size = 1;
349     goto gencase;
350     case 'p':
351     alternate_prefix = "0x";
352     alternate_size = 2;
353     want_uppercase = FALSE;
354     base = 16;
355     print_sign = FALSE;
356     u = (unsigned long)va_arg(args, char *);
357     s = long_to_ascii(u, base, want_uppercase);
358     #ifdef MSDOS
359     /* The traditional format for pointers on
360     * MSDOS is segment:offset. NOTE: we depend
361     * on long_to_ascii() returning a buffer with
362     * space before the beginning.
363     */
364     if ((len = strlen(s)) <= 8) {
365     s -= 8 - len;
366     memset(s, '0', 8 - len);
367    
368     --s;
369     memmove(s, s + 1, 4);
370     s[4] = ':';
371     }
372     #endif
373     break;
374     case 'x':
375     alternate_prefix = "0x";
376     alternate_size = 2;
377     want_uppercase = FALSE;
378     /* fall through */;
379     case 'X':
380     base = 16;
381     goto gencase;
382     case 'u':
383     base = 10;
384     gencase: if (modifier == 'h')
385     u = va_arg(args, short);
386     else if (modifier == 'l')
387     u = va_arg(args, long);
388     else
389     u = va_arg(args, int);
390     s = long_to_ascii(u, base, want_uppercase);
391     break;
392    
393     case 'c':
394     str[0] = (char)va_arg(args, int); /* promoted char */
395     str[1] = '\0';
396     s = str;
397     print_sign = FALSE;
398     break;
399    
400     case '%':
401     str[0] = '%';
402     str[1] = '\0';
403     s = str;
404     print_sign = FALSE;
405     break;
406    
407     case 's':
408     s = va_arg(args, char *);
409     if (s == NULL)
410     panic("null pointer for %s in formf");
411     print_sign = FALSE;
412     break;
413     case 'm':
414     if (saved_errno < 0 || saved_errno > sys_nerr ||
415     *sys_errlist[saved_errno] == '\0') {
416     sprintf(errno_buffer,
417     "errno %d out of range",
418     saved_errno);
419     s = errno_buffer;
420     } else
421     s = sys_errlist[saved_errno];
422     print_sign = FALSE;
423     break;
424     #ifdef VMS
425     case 'M':
426     s = vms_error_text(va_arg(args, unsigned));
427     print_sign = FALSE;
428     break;
429     #endif /* VMS */
430     case 'f':
431     d = va_arg(args, double);
432     is_negative = d < 0.0;
433     if (is_negative)
434     d = -d;
435     if (!precision_given)
436     precision = 6; /* from K&R */
437     s = float_to_ascii(d, precision);
438     break;
439     case 'e':
440     want_uppercase = FALSE; /* fall through */
441     case 'E':
442     d = va_arg(args, double);
443     is_negative = d < 0.0;
444     if (is_negative)
445     d = -d;
446     if (!precision_given)
447     precision = 6; /* from K&R */
448     s = efloat_to_ascii(d, precision,
449     want_uppercase);
450     break;
451     case 'g':
452     want_uppercase = FALSE; /* fall through */
453     case 'G':
454     d = va_arg(args, double);
455     is_negative = d < 0.0;
456     if (is_negative)
457     d = -d;
458     if (!precision_given)
459     precision = 6; /* from K&R */
460     s = gfloat_to_ascii(d, precision,
461     want_uppercase);
462     break;
463     case 'n':
464     ip = va_arg(args, int *);
465     *ip = pos;
466    
467     ++fmt; /* step over format character */
468     continue;
469    
470     default:
471     panic("illegal format in formf");
472     s = NULL; /* to satisfy gcc */
473     break;
474     }
475    
476     len = strlen(s);
477    
478     /* truncate strings if requested */
479     if ((*fmt == 's' || *fmt == 'm')
480     && precision_given && precision < len)
481     len = precision;
482    
483     if (!left_justify) {
484     const char *fillch_str = zero_pad ? "0" : " ";
485    
486     if ((is_negative || print_sign) && zero_pad) {
487     concat(&buf, &pos, &lim, &from_malloc,
488     is_negative ? "-" : "+", 1);
489     is_negative = print_sign = FALSE;
490     --min_field_width;
491     }
492    
493     if (alternate_form && alternate_prefix != NULL) {
494     concat(&buf, &pos, &lim, &from_malloc,
495     alternate_prefix, alternate_size);
496     min_field_width -= alternate_size;
497     alternate_form = FALSE;
498     }
499    
500     while (len < min_field_width) {
501     concat(&buf, &pos, &lim, &from_malloc,
502     fillch_str, 1);
503     --min_field_width;
504     }
505     }
506    
507     if (is_negative || print_sign) {
508     concat(&buf, &pos, &lim, &from_malloc,
509     is_negative ? "-" : "+", 1);
510     --min_field_width;
511     }
512    
513     if (alternate_form && alternate_prefix != NULL) {
514     concat(&buf, &pos, &lim, &from_malloc,
515     alternate_prefix, alternate_size);
516     min_field_width -= alternate_size;
517     }
518    
519    
520     concat(&buf, &pos, &lim, &from_malloc, s, len);
521     min_field_width -= len;
522    
523     if (left_justify) {
524     while (min_field_width > 0) {
525     concat(&buf, &pos, &lim, &from_malloc, " ", 1);
526     --min_field_width;
527     }
528     }
529    
530     ++fmt; /* step over format character */
531     }
532     }