1 /*
2 voutf.c Process formatted text through an output function.
3
4 MODULE: voutf
5 FILES: voutf.c (this one) and voutf.h.
6
7 This package implements a flexible variable argument list
8 output function similar to the System V vprintf function;
9 however, it differs by using a function as an output sink
10 instead of a string buffer or an output file. This increases
11 the flexibility of the package by allowing the supplied
12 function to post-process and redirect the output as required
13 by the application.
14
15 Note: This procedure was adapted from earlier projects and
16 edited slightly to fit Medline project syle criteria.
17
18 Edit History:
19
20 25 July 1991 Rand S. Huntzinger, NLM/NCBI
21 Adapted to meet style criterial for modules in the
22 Medline project.
23
24 14 Dec 1989 Modified to permit unlimited-length
25 format statements and output of
26 super long strings with unqualified
27 %s format (ie. %s not %30s).
28
29 Written: 5/21/87 by Rand S. Huntzinger
30 *
31 *
32 * RCS Modification History:
33 * $Log: voutf.c,v $
34 * Revision 6.0 1997/08/25 18:37:08 madden
35 * Revision changed to 6.0
36 *
37 * Revision 1.2 1995/05/17 17:56:14 epstein
38 * add RCS log revision history
39 *
40 */
41
42 #include <stdio.h>
43 #include <string.h>
44 #include "voutf.h"
45
46 #define index(s,c) strchr(s,c)
47
48 /* Local definitions and declarations */
49
50 #define MAX_ARG_EXPANSION 128 /* Largest single output field */
51 #define MAX_FMT_ITEM 128 /* Largest single field format */
52 #define EOS '\0' /* End of string marker */
53 #ifndef TRUE
54 #define TRUE 1 /* Boolean constants */
55 #define FALSE 0
56 #endif
57
58 typedef int ifunc();
59
60 /* Macro to support error handling in the output function */
61
62 #define OUTPUT(S) if((rv = out_func(S)) != 0) return (rv)
63
64 /* List of printf style format characters recognized by voutf */
65
66 static char *fmt_chars = "sdcfgGeEduoxX%";
67
68 /* External functions required */
69
70
71 /*
72 voutf Variable argument list output function.
73
74 This routine implements interprets a variable length argument
75 list with respect to a format in a manner similar to the
76 printf functions in the standard I/O package. As each output
77 field is interpreted, the resulting string is passed to a
78 supplied output function, which processes it as required by
79 the application [usually collects it into a string or outputs
80 it].
81
82 Parameters:
83
84 out_func The address of the function to be used
85 as an output sink. It is called for
86 each output field (including constant
87 fields).
88
89 fmt A printf-style format statement
90 describing how to format the remaining
91 arguments into strings to pass to
92 out_func.
93
94 args A variable of type va_list (from a
95 variable argument list in the calling
96 program).
97
98 Returns:
99
100 0 If no error.
101 NOT 0 An error status from out_func.
102 Interpretation depends upon out_func.
103 */
104
105 /*
106 * voutf(int(out_func)(),charfmt,voidargs)
107 */
voutf(int (* out_func)(),char * fmt,void * args)108 int voutf(int (*out_func)(), char *fmt, void *args)
109 {
110 char buf[MAX_ARG_EXPANSION+1];
111 char afmt[MAX_FMT_ITEM];
112 int rv;
113
114 /* Scan the format and output text */
115
116 rv = 0; /* Assume success for now */
117 while(*fmt) {
118 char *p; /* Advancing char pointer */
119 char f_char; /* Formatting character */
120 short longvar; /* TRUE if a long integer */
121 short shortvar; /* TRUE if a long integer */
122
123 /* Variables to hold arguments of various types */
124
125 double dval; char * sval;
126 int ival; long lval;
127
128 /* Non-formatting codes simply get output */
129 if(*fmt != '%') {
130 for(p = buf; *fmt && *fmt!= '%'; *p++ = *fmt++)
131 if(p == &buf[MAX_ARG_EXPANSION]) {
132 *p = EOS;
133 OUTPUT(buf);
134 p = buf;
135 }
136 *p = EOS;
137 OUTPUT(buf);
138 }
139 /* Format items require conversion */
140 if(*fmt == '%') {
141 /* Extract the conversion specification */
142 longvar = shortvar = FALSE;
143 p = afmt;
144 *p++ = *fmt++;
145 while(*fmt && index(fmt_chars, *fmt) == NULL) {
146 char ivstr[32], *q;
147 if(*fmt == '*') {
148 /* Get format width from data */
149 ival= va_arg(args, int);
150 sprintf(ivstr, "%d", ival);
151 for(q=ivstr; *q; ) *p++ = *q++;
152 fmt++; /* Skip * */
153 continue;
154 }
155 if(*fmt == 'l') longvar = TRUE;
156 if(*fmt == 'h') shortvar = TRUE;
157 *p++ = *fmt++;
158 }
159 *p++ = f_char = *fmt;
160 *p = EOS;
161 if(*fmt) fmt++;
162 /* Convert next argument by format */
163 switch(f_char) {
164 case '%': /* Quoted % */
165 strcpy(buf, "%");
166 break;
167 case 'd': /* Integer conversions */
168 case 'o': case 'u': case 'x': case 'X':
169 case 'c': /* char is an integer on stack */
170 if(longvar) {
171 lval = va_arg(args, long);
172 sprintf(buf, afmt, lval);
173 } else if(shortvar) {
174 lval = va_arg(args, int);
175 sprintf(buf, afmt, lval);
176 } else {
177 ival = va_arg(args, int);
178 sprintf(buf, afmt, ival);
179 }
180 break;
181 case 'f': /* Floating point conversions */
182 case 'e': case 'E': case 'g': case 'G':
183 /* NOTE - PROBLEMS if float <> double? */
184 dval = va_arg(args, double);
185 sprintf(buf, afmt, dval);
186 break;
187 case 's': /* String argument */
188 sval = va_arg(args, char *);
189 if(strcmp(afmt, "%s") == 0) {
190 OUTPUT( sval ); /* Unrestricted string */
191 continue;
192 } else sprintf(buf, afmt, sval);
193 break;
194 case EOS: /* End of string */
195 default: /* Unexpected character */
196 strcpy(buf, afmt);
197 break;
198 }
199 /* Output the resulting string */
200 OUTPUT(buf);
201 }
202 }
203
204 /* Exit at this point */
205
206 return( rv );
207 }
208
209
210 /*
211 voutput Output with variable argument list.
212
213 Call voutf with a direct variable argument list. This is
214 used when the function is not called from a variable argument
215 list function.
216
217 Parameters:
218
219 out_func The address of the function to be used
220 as an output sync. It is called for
221 each output field (including constant
222 fields).
223
224 fmt A printf-style format statement
225 describing how to format the remaining
226 arguments into strings to pass to
227 out_func.
228
229 args ... The remaining arguments are interpreted
230 according to the format passed as 'fmt'.
231
232 Returns:
233
234 0 If no error.
235 NOT 0 An error status from out_func.
236 Interpretation depends upon out_func.
237 */
238
239 /*
240 * voutput(int(out_func)(),charfmt,...)
241 */
voutput(int (* out_func)(),char * fmt,...)242 int voutput(int (*out_func)(), char *fmt, ...)
243 {
244 va_list args;
245 int rv;
246
247 /* Extract the fixed parameters */
248
249 va_start(args, fmt);
250
251 /* Now use voutf */
252
253 rv = voutf(out_func, fmt, args);
254 va_end( args );
255
256 /* Done */
257
258 return( rv );
259 }
260