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, 8 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

# Content
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 }