FreeCalypso > hg > ffs-editor
comparison src/libsys/sprintf/vspcore.c @ 0:92470e5d0b9e
src: partial import from FC Selenite
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Fri, 15 May 2020 01:28:16 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:92470e5d0b9e |
---|---|
1 /* | |
2 * Embedded [v]sprintf() implementation by Mychaela Falconia, | |
3 * loosely based on the 4.3BSD-Tahoe version. | |
4 * | |
5 * This module contains the core of the vsprintf() function, which may | |
6 * be either used directly by user code or called by the sprintf() | |
7 * trivial wrapper. | |
8 */ | |
9 | |
10 #include <sys/types.h> | |
11 #include <ctype.h> | |
12 #include <stdarg.h> | |
13 #include "defs.h" | |
14 | |
15 extern u_char * _sprintf_integer(u_char *op, int width, int flags, int sign, | |
16 unsigned number, int base, int prec); | |
17 extern u_char * _sprintf_percent_f(u_char *op, int width, int flags, int sign, | |
18 double number, int prec); | |
19 | |
20 u_char * | |
21 _sprintf_field(u_char *op, int width, int flags, int sign, | |
22 u_char *body, int size, int dprec, int fpprec) | |
23 { | |
24 int fieldsz; /* field size expanded by sign, etc */ | |
25 int realsz; /* field size expanded by decimal precision */ | |
26 int n; /* scratch */ | |
27 | |
28 /* | |
29 * All reasonable formats wind up here. At this point, | |
30 * `body' points to a string which (if not flags&LADJUST) | |
31 * should be padded out to `width' places. If | |
32 * flags&ZEROPAD, it should first be prefixed by any | |
33 * sign or other prefix; otherwise, it should be blank | |
34 * padded before the prefix is emitted. After any | |
35 * left-hand padding and prefixing, emit zeroes | |
36 * required by a decimal [diouxX] precision, then print | |
37 * the string proper, then emit zeroes required by any | |
38 * leftover floating precision; finally, if LADJUST, | |
39 * pad with blanks. | |
40 */ | |
41 | |
42 /* | |
43 * compute actual size, so we know how much to pad | |
44 * fieldsz excludes decimal prec; realsz includes it | |
45 */ | |
46 fieldsz = size + fpprec; | |
47 if (sign) | |
48 fieldsz++; | |
49 if (flags & HEXPREFIX) | |
50 fieldsz += 2; | |
51 realsz = dprec > fieldsz ? dprec : fieldsz; | |
52 | |
53 /* right-adjusting blank padding */ | |
54 if ((flags & (LADJUST|ZEROPAD)) == 0 && width) | |
55 for (n = realsz; n < width; n++) | |
56 *op++ = ' '; | |
57 /* prefix */ | |
58 if (sign) | |
59 *op++ = sign; | |
60 if (flags & HEXPREFIX) { | |
61 *op++ = '0'; | |
62 *op++ = (flags & UPPERCASE) ? 'X' : 'x'; | |
63 } | |
64 /* right-adjusting zero padding */ | |
65 if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) | |
66 for (n = realsz; n < width; n++) | |
67 *op++ = '0'; | |
68 /* leading zeroes from decimal precision */ | |
69 for (n = fieldsz; n < dprec; n++) | |
70 *op++ = '0'; | |
71 | |
72 /* the string or number proper */ | |
73 bcopy(body, op, size); | |
74 op += size; | |
75 /* trailing f.p. zeroes */ | |
76 while (--fpprec >= 0) | |
77 *op++ = '0'; | |
78 /* left-adjusting padding (always blank) */ | |
79 if (flags & LADJUST) | |
80 for (n = realsz; n < width; n++) | |
81 *op++ = ' '; | |
82 | |
83 return(op); | |
84 } | |
85 | |
86 int | |
87 vsprintf(buf0, fmt0, argp) | |
88 u_char *buf0, *fmt0; | |
89 va_list argp; | |
90 { | |
91 u_char *op; /* output buffer working ptr */ | |
92 u_char *fmt; /* format string working ptr */ | |
93 int ch; /* character from fmt */ | |
94 int n; /* scratch integer */ | |
95 char *t; /* scratch pointer */ | |
96 int flags; /* flags as above */ | |
97 int prec; /* precision from format (%.3d), or -1 */ | |
98 int width; /* width from format (%8d), or 0 */ | |
99 char sign; /* sign prefix (' ', '+', '-', or \0) */ | |
100 unsigned un; /* unsigned number for conversion */ | |
101 | |
102 op = buf0; | |
103 for (fmt = fmt0; ; ++fmt) { | |
104 for (; (ch = *fmt) && ch != '%'; ++fmt) | |
105 *op++ = ch; | |
106 if (!ch) { | |
107 out: *op = '\0'; | |
108 return (op - buf0); | |
109 } | |
110 | |
111 flags = 0; width = 0; | |
112 prec = -1; | |
113 sign = '\0'; | |
114 | |
115 rflag: switch (*++fmt) { | |
116 case ' ': | |
117 /* | |
118 * ``If the space and + flags both appear, the space | |
119 * flag will be ignored.'' | |
120 * -- ANSI X3J11 | |
121 */ | |
122 if (!sign) | |
123 sign = ' '; | |
124 goto rflag; | |
125 case '#': | |
126 flags |= ALT; | |
127 goto rflag; | |
128 case '*': | |
129 /* | |
130 * ``A negative field width argument is taken as a | |
131 * - flag followed by a positive field width.'' | |
132 * -- ANSI X3J11 | |
133 * They don't exclude field widths read from args. | |
134 */ | |
135 if ((width = va_arg(argp, int)) >= 0) | |
136 goto rflag; | |
137 width = -width; | |
138 /* FALLTHROUGH */ | |
139 case '-': | |
140 flags |= LADJUST; | |
141 goto rflag; | |
142 case '+': | |
143 sign = '+'; | |
144 goto rflag; | |
145 case '.': | |
146 if (*++fmt == '*') | |
147 n = va_arg(argp, int); | |
148 else { | |
149 n = 0; | |
150 while (isascii(*fmt) && isdigit(*fmt)) | |
151 n = 10 * n + todigit(*fmt++); | |
152 --fmt; | |
153 } | |
154 prec = n < 0 ? -1 : n; | |
155 goto rflag; | |
156 case '0': | |
157 /* | |
158 * ``Note that 0 is taken as a flag, not as the | |
159 * beginning of a field width.'' | |
160 * -- ANSI X3J11 | |
161 */ | |
162 flags |= ZEROPAD; | |
163 goto rflag; | |
164 case '1': case '2': case '3': case '4': | |
165 case '5': case '6': case '7': case '8': case '9': | |
166 n = 0; | |
167 do { | |
168 n = 10 * n + todigit(*fmt); | |
169 } while (isascii(*++fmt) && isdigit(*fmt)); | |
170 width = n; | |
171 --fmt; | |
172 goto rflag; | |
173 case 'L': | |
174 flags |= LONGDBL; | |
175 goto rflag; | |
176 case 'h': | |
177 flags |= SHORTINT; | |
178 goto rflag; | |
179 case 'l': | |
180 flags |= LONGINT; | |
181 goto rflag; | |
182 case 'c': | |
183 /* | |
184 * XXX reusing a variable of type char | |
185 * for an unrelated purpose | |
186 */ | |
187 sign = (char) va_arg(argp, int); | |
188 op = _sprintf_field(op, width, flags, 0, &sign, 1, | |
189 0, 0); | |
190 break; | |
191 case 'D': | |
192 flags |= LONGINT; | |
193 /*FALLTHROUGH*/ | |
194 case 'd': | |
195 case 'i': | |
196 n = va_arg(argp, int); | |
197 if (n < 0) { | |
198 un = -n; | |
199 sign = '-'; | |
200 } else | |
201 un = n; | |
202 op = _sprintf_integer(op, width, flags, sign, un, 10, | |
203 prec); | |
204 break; | |
205 case 'f': | |
206 op = _sprintf_percent_f(op, width, flags, sign, | |
207 va_arg(argp, double), prec); | |
208 break; | |
209 case 'n': | |
210 n = op - buf0; | |
211 if (flags & LONGINT) | |
212 *va_arg(argp, long *) = n; | |
213 else if (flags & SHORTINT) | |
214 *va_arg(argp, short *) = n; | |
215 else | |
216 *va_arg(argp, int *) = n; | |
217 break; | |
218 case 'O': | |
219 flags |= LONGINT; | |
220 /*FALLTHROUGH*/ | |
221 case 'o': | |
222 un = va_arg(argp, unsigned); | |
223 op = _sprintf_integer(op, width, flags, 0, un, 8, prec); | |
224 break; | |
225 case 'p': | |
226 /* | |
227 * ``The argument shall be a pointer to void. The | |
228 * value of the pointer is converted to a sequence | |
229 * of printable characters, in an implementation- | |
230 * defined manner.'' | |
231 * -- ANSI X3J11 | |
232 */ | |
233 /* NOSTRICT */ | |
234 un = (unsigned)va_arg(argp, void *); | |
235 op = _sprintf_integer(op, width, flags | HEXPREFIX, 0, | |
236 un, 16, prec); | |
237 break; | |
238 case 's': | |
239 if (!(t = va_arg(argp, char *))) | |
240 t = "(null)"; | |
241 if (prec >= 0) { | |
242 /* | |
243 * can't use strlen; can only look for the | |
244 * NUL in the first `prec' characters, and | |
245 * strlen() will go further. | |
246 */ | |
247 char *p, *memchr(); | |
248 | |
249 if (p = memchr(t, 0, prec)) { | |
250 n = p - t; | |
251 if (n > prec) | |
252 n = prec; | |
253 } else | |
254 n = prec; | |
255 } else | |
256 n = strlen(t); | |
257 op = _sprintf_field(op, width, flags, 0, t, n, 0, 0); | |
258 break; | |
259 case 'U': | |
260 flags |= LONGINT; | |
261 /*FALLTHROUGH*/ | |
262 case 'u': | |
263 un = va_arg(argp, unsigned); | |
264 op = _sprintf_integer(op, width, flags, 0, un, 10, | |
265 prec); | |
266 break; | |
267 case 'X': | |
268 flags |= UPPERCASE; | |
269 /* FALLTHROUGH */ | |
270 case 'x': | |
271 un = va_arg(argp, unsigned); | |
272 /* leading 0x/X only if non-zero */ | |
273 if (flags & ALT && un != 0) | |
274 flags |= HEXPREFIX; | |
275 op = _sprintf_integer(op, width, flags, 0, un, 16, | |
276 prec); | |
277 break; | |
278 case '\0': /* "%?" prints ?, unless ? is NULL */ | |
279 goto out; | |
280 default: | |
281 *op++ = *fmt; | |
282 } | |
283 } | |
284 /* NOTREACHED */ | |
285 } |