1 | /*␊ |
2 | * vsnprintf.c␊ |
3 | *␊ |
4 | * vsnprintf(), from which the rest of the printf()␊ |
5 | * family is built␊ |
6 | */␊ |
7 | ␊ |
8 | #include "libsaio.h"␊ |
9 | #include "limits.h"␊ |
10 | enum flags {␊ |
11 | ␉FL_ZERO␉␉= 0x01,␉/* Zero modifier */␊ |
12 | ␉FL_MINUS␉= 0x02,␉/* Minus modifier */␊ |
13 | ␉FL_PLUS␉␉= 0x04,␉/* Plus modifier */␊ |
14 | ␉FL_TICK␉␉= 0x08,␉/* ' modifier */␊ |
15 | ␉FL_SPACE␉= 0x10,␉/* Space modifier */␊ |
16 | ␉FL_HASH␉␉= 0x20,␉/* # modifier */␊ |
17 | ␉FL_SIGNED␉= 0x40,␉/* Number is signed */␊ |
18 | ␉FL_UPPER␉= 0x80␉/* Upper case digits */␊ |
19 | };␊ |
20 | ␊ |
21 | /* These may have to be adjusted on certain implementations */␊ |
22 | enum ranks {␊ |
23 | ␉rank_char␉= -2,␊ |
24 | ␉rank_short␉= -1,␊ |
25 | ␉rank_int␉= 0,␊ |
26 | ␉rank_long␉= 1,␊ |
27 | ␉rank_longlong␉= 2␊ |
28 | };␊ |
29 | ␊ |
30 | #define MIN_RANK␉rank_char␊ |
31 | #define MAX_RANK␉rank_longlong␊ |
32 | ␊ |
33 | #define INTMAX_RANK␉rank_longlong␊ |
34 | #define SIZE_T_RANK␉rank_long␊ |
35 | #define PTRDIFF_T_RANK␉rank_long␊ |
36 | ␊ |
37 | #define EMIT(x) ({ if (o<n){*q++ = (x);} o++; })␊ |
38 | ␊ |
39 | static size_t␊ |
40 | format_int(char *q, size_t n, uintmax_t val, enum flags flags,␊ |
41 | ␉ int base, int width, int prec)␊ |
42 | {␊ |
43 | ␉char *qq;␊ |
44 | ␉size_t o = 0, oo;␊ |
45 | ␉static const char lcdigits[] = "0123456789abcdef";␊ |
46 | ␉static const char ucdigits[] = "0123456789ABCDEF";␊ |
47 | ␉const char *digits;␊ |
48 | ␉uintmax_t tmpval;␊ |
49 | ␉int minus = 0;␊ |
50 | ␉int ndigits = 0, nchars;␊ |
51 | ␉int tickskip, b4tick;␊ |
52 | ␊ |
53 | ␉/* Select type of digits */␊ |
54 | ␉digits = (flags & FL_UPPER) ? ucdigits : lcdigits;␊ |
55 | ␊ |
56 | ␉/* If signed, separate out the minus */␊ |
57 | ␉if (flags & FL_SIGNED && (intmax_t) val < 0) {␊ |
58 | ␉␉minus = 1;␊ |
59 | ␉␉val = (uintmax_t) (-(intmax_t) val);␊ |
60 | ␉}␊ |
61 | ␊ |
62 | ␉/* Count the number of digits needed. This returns zero for 0. */␊ |
63 | ␉tmpval = val;␊ |
64 | ␉while (tmpval) {␊ |
65 | ␉␉tmpval /= base;␊ |
66 | ␉␉ndigits++;␊ |
67 | ␉}␊ |
68 | ␊ |
69 | ␉/* Adjust ndigits for size of output */␊ |
70 | ␊ |
71 | ␉if (flags & FL_HASH && base == 8) {␊ |
72 | ␉␉if (prec < ndigits + 1)␊ |
73 | ␉␉␉prec = ndigits + 1;␊ |
74 | ␉}␊ |
75 | ␊ |
76 | ␉if (ndigits < prec) {␊ |
77 | ␉␉ndigits = prec;␉/* Mandatory number padding */␊ |
78 | ␉} else if (val == 0) {␊ |
79 | ␉␉ndigits = 1;␉/* Zero still requires space */␊ |
80 | ␉}␊ |
81 | ␊ |
82 | ␉/* For ', figure out what the skip should be */␊ |
83 | ␉if (flags & FL_TICK) {␊ |
84 | ␉␉tickskip = (base == 16) ? 4 : 3;␊ |
85 | ␉} else {␊ |
86 | ␉␉tickskip = ndigits;␉/* No tick marks */␊ |
87 | ␉}␊ |
88 | ␊ |
89 | ␉/* Tick marks aren't digits, but generated by the number converter */␊ |
90 | ␉ndigits += (ndigits - 1) / tickskip;␊ |
91 | ␊ |
92 | ␉/* Now compute the number of nondigits */␊ |
93 | ␉nchars = ndigits;␊ |
94 | ␊ |
95 | ␉if (minus || (flags & (FL_PLUS | FL_SPACE)))␊ |
96 | ␉␉nchars++;␉/* Need space for sign */␊ |
97 | ␉if ((flags & FL_HASH) && base == 16) {␊ |
98 | ␉␉nchars += 2;␉/* Add 0x for hex */␊ |
99 | ␉}␊ |
100 | ␊ |
101 | ␉/* Emit early space padding */␊ |
102 | ␉if (!(flags & (FL_MINUS | FL_ZERO)) && width > nchars) {␊ |
103 | ␉␉while (width > nchars) {␊ |
104 | ␉␉␉EMIT(' ');␊ |
105 | ␉␉␉width--;␊ |
106 | ␉␉}␊ |
107 | ␉}␊ |
108 | ␊ |
109 | ␉/* Emit nondigits */␊ |
110 | ␉if (minus)␊ |
111 | ␉␉EMIT('-');␊ |
112 | ␉else if (flags & FL_PLUS)␊ |
113 | ␉␉EMIT('+');␊ |
114 | ␉else if (flags & FL_SPACE)␊ |
115 | ␉␉EMIT(' ');␊ |
116 | ␊ |
117 | ␉if ((flags & FL_HASH) && base == 16) {␊ |
118 | ␉␉EMIT('0');␊ |
119 | ␉␉EMIT((flags & FL_UPPER) ? 'X' : 'x');␊ |
120 | ␉}␊ |
121 | ␊ |
122 | ␉/* Emit zero padding */␊ |
123 | ␉if ((flags & (FL_MINUS | FL_ZERO)) == FL_ZERO && width > ndigits) {␊ |
124 | ␉␉while (width > nchars) {␊ |
125 | ␉␉␉EMIT('0');␊ |
126 | ␉␉␉width--;␊ |
127 | ␉␉}␊ |
128 | ␉}␊ |
129 | ␊ |
130 | ␉/* Generate the number. This is done from right to left. */␊ |
131 | ␉q += ndigits;␉␉/* Advance the pointer to end of number */␊ |
132 | ␉o += ndigits;␊ |
133 | ␉qq = q;␊ |
134 | ␉oo = o;␉␉␉/* Temporary values */␊ |
135 | ␊ |
136 | ␉b4tick = tickskip;␊ |
137 | ␉while (ndigits > 0) {␊ |
138 | ␉␉if (!b4tick--) {␊ |
139 | ␉␉␉qq--;␊ |
140 | ␉␉␉oo--;␊ |
141 | ␉␉␉ndigits--;␊ |
142 | ␉␉␉if (oo < n)␊ |
143 | ␉␉␉␉*qq = '_';␊ |
144 | ␉␉␉b4tick = tickskip - 1;␊ |
145 | ␉␉}␊ |
146 | ␉␉qq--;␊ |
147 | ␉␉oo--;␊ |
148 | ␉␉ndigits--;␊ |
149 | ␉␉if (oo < n)␊ |
150 | ␉␉␉*qq = digits[val % base];␊ |
151 | ␉␉val /= base;␊ |
152 | ␉}␊ |
153 | ␊ |
154 | ␉/* Emit late space padding */␊ |
155 | ␉while ((flags & FL_MINUS) && width > nchars) {␊ |
156 | ␉␉EMIT(' ');␊ |
157 | ␉␉width--;␊ |
158 | ␉}␊ |
159 | ␊ |
160 | ␉return o;␊ |
161 | }␊ |
162 | ␊ |
163 | int vsnprintf(char *buffer, size_t n, const char *format, va_list ap)␊ |
164 | {␊ |
165 | ␉const char *p = format;␊ |
166 | ␉char ch;␊ |
167 | ␉char *q = buffer;␊ |
168 | ␉size_t o = 0;␉␉/* Number of characters output */␊ |
169 | ␉uintmax_t val = 0;␊ |
170 | ␉int rank = rank_int;␉/* Default rank */␊ |
171 | ␉int width = 0;␊ |
172 | ␉int prec = -1;␊ |
173 | ␉int base;␊ |
174 | ␉size_t sz;␊ |
175 | ␉enum flags flags = 0;␊ |
176 | ␉enum {␊ |
177 | ␉␉st_normal,␉/* Ground state */␊ |
178 | ␉␉st_flags,␉/* Special flags */␊ |
179 | ␉␉st_width,␉/* Field width */␊ |
180 | ␉␉st_prec,␉/* Field precision */␊ |
181 | ␉␉st_modifiers␉/* Length or conversion modifiers */␊ |
182 | ␉} state = st_normal;␊ |
183 | ␉const char *sarg;␉/* %s string argument */␊ |
184 | ␉char carg;␉␉/* %c char argument */␊ |
185 | ␉int slen;␉␉/* String length */␊ |
186 | ␊ |
187 | ␉while ((ch = *p++)) {␊ |
188 | ␉␉switch (state) {␊ |
189 | ␉␉case st_normal:␊ |
190 | ␉␉␉if (ch == '%') {␊ |
191 | ␉␉␉␉state = st_flags;␊ |
192 | ␉␉␉␉flags = 0;␊ |
193 | ␉␉␉␉rank = rank_int;␊ |
194 | ␉␉␉␉width = 0;␊ |
195 | ␉␉␉␉prec = -1;␊ |
196 | ␉␉␉} else {␊ |
197 | ␉␉␉␉EMIT(ch);␊ |
198 | ␉␉␉}␊ |
199 | ␉␉␉break;␊ |
200 | ␊ |
201 | ␉␉case st_flags:␊ |
202 | ␉␉␉switch (ch) {␊ |
203 | ␉␉␉case '-':␊ |
204 | ␉␉␉␉flags |= FL_MINUS;␊ |
205 | ␉␉␉␉break;␊ |
206 | ␉␉␉case '+':␊ |
207 | ␉␉␉␉flags |= FL_PLUS;␊ |
208 | ␉␉␉␉break;␊ |
209 | ␉␉␉case '\'':␊ |
210 | ␉␉␉␉flags |= FL_TICK;␊ |
211 | ␉␉␉␉break;␊ |
212 | ␉␉␉case ' ':␊ |
213 | ␉␉␉␉flags |= FL_SPACE;␊ |
214 | ␉␉␉␉break;␊ |
215 | ␉␉␉case '#':␊ |
216 | ␉␉␉␉flags |= FL_HASH;␊ |
217 | ␉␉␉␉break;␊ |
218 | ␉␉␉case '0':␊ |
219 | ␉␉␉␉flags |= FL_ZERO;␊ |
220 | ␉␉␉␉break;␊ |
221 | ␉␉␉default:␊ |
222 | ␉␉␉␉state = st_width;␊ |
223 | ␉␉␉␉p--;␉/* Process this character again */␊ |
224 | ␉␉␉␉break;␊ |
225 | ␉␉␉}␊ |
226 | ␉␉␉break;␊ |
227 | ␊ |
228 | ␉␉case st_width:␊ |
229 | ␉␉␉if (ch >= '0' && ch <= '9') {␊ |
230 | ␉␉␉␉width = width * 10 + (ch - '0');␊ |
231 | ␉␉␉} else if (ch == '*') {␊ |
232 | ␉␉␉␉width = va_arg(ap, int);␊ |
233 | ␉␉␉␉if (width < 0) {␊ |
234 | ␉␉␉␉␉width = -width;␊ |
235 | ␉␉␉␉␉flags |= FL_MINUS;␊ |
236 | ␉␉␉␉}␊ |
237 | ␉␉␉} else if (ch == '.') {␊ |
238 | ␉␉␉␉prec = 0;␉/* Precision given */␊ |
239 | ␉␉␉␉state = st_prec;␊ |
240 | ␉␉␉} else {␊ |
241 | ␉␉␉␉state = st_modifiers;␊ |
242 | ␉␉␉␉p--;␉/* Process this character again */␊ |
243 | ␉␉␉}␊ |
244 | ␉␉␉break;␊ |
245 | ␊ |
246 | ␉␉case st_prec:␊ |
247 | ␉␉␉if (ch >= '0' && ch <= '9') {␊ |
248 | ␉␉␉␉prec = prec * 10 + (ch - '0');␊ |
249 | ␉␉␉} else if (ch == '*') {␊ |
250 | ␉␉␉␉prec = va_arg(ap, int);␊ |
251 | ␉␉␉␉if (prec < 0)␊ |
252 | ␉␉␉␉␉prec = -1;␊ |
253 | ␉␉␉} else {␊ |
254 | ␉␉␉␉state = st_modifiers;␊ |
255 | ␉␉␉␉p--;␉/* Process this character again */␊ |
256 | ␉␉␉}␊ |
257 | ␉␉␉break;␊ |
258 | ␊ |
259 | ␉␉case st_modifiers:␊ |
260 | ␉␉␉switch (ch) {␊ |
261 | ␉␉␉␉/* Length modifiers - nonterminal sequences */␊ |
262 | ␉␉␉case 'h':␊ |
263 | ␉␉␉␉rank--;␉/* Shorter rank */␊ |
264 | ␉␉␉␉break;␊ |
265 | ␉␉␉case 'l':␊ |
266 | ␉␉␉␉rank++;␉/* Longer rank */␊ |
267 | ␉␉␉␉break;␊ |
268 | ␉␉␉case 'j':␊ |
269 | ␉␉␉␉rank = INTMAX_RANK;␊ |
270 | ␉␉␉␉break;␊ |
271 | ␉␉␉case 'z':␊ |
272 | ␉␉␉␉rank = SIZE_T_RANK;␊ |
273 | ␉␉␉␉break;␊ |
274 | ␉␉␉case 't':␊ |
275 | ␉␉␉␉rank = PTRDIFF_T_RANK;␊ |
276 | ␉␉␉␉break;␊ |
277 | ␉␉␉case 'L':␊ |
278 | ␉␉␉case 'q':␊ |
279 | ␉␉␉␉rank += 2;␊ |
280 | ␉␉␉␉break;␊ |
281 | ␉␉␉default:␊ |
282 | ␉␉␉␉/* Output modifiers - terminal sequences */␊ |
283 | ␊ |
284 | ␉␉␉␉/* Next state will be normal */␊ |
285 | ␉␉␉␉state = st_normal;␊ |
286 | ␊ |
287 | ␉␉␉␉/* Canonicalize rank */␊ |
288 | ␉␉␉␉if (rank < MIN_RANK)␊ |
289 | ␉␉␉␉␉rank = MIN_RANK;␊ |
290 | ␉␉␉␉else if (rank > MAX_RANK)␊ |
291 | ␉␉␉␉␉rank = MAX_RANK;␊ |
292 | ␊ |
293 | ␉␉␉␉switch (ch) {␊ |
294 | ␉␉␉␉case 'P':␉/* Upper case pointer */␊ |
295 | ␉␉␉␉␉flags |= FL_UPPER;␊ |
296 | ␉␉␉␉␉/* fall through */␊ |
297 | ␉␉␉␉case 'p':␉/* Pointer */␊ |
298 | ␉␉␉␉␉base = 16;␊ |
299 | ␉␉␉␉␉prec = (CHAR_BIT*sizeof(void *)+3)/4;␊ |
300 | ␉␉␉␉␉flags |= FL_HASH;␊ |
301 | ␉␉␉␉␉val = (uintmax_t)(uintptr_t)␊ |
302 | ␉␉␉␉␉␉va_arg(ap, void *);␊ |
303 | ␉␉␉␉␉goto is_integer;␊ |
304 | ␊ |
305 | ␉␉␉␉case 'd':␉/* Signed decimal output */␊ |
306 | ␉␉␉␉case 'i':␊ |
307 | ␉␉␉␉␉base = 10;␊ |
308 | ␉␉␉␉␉flags |= FL_SIGNED;␊ |
309 | ␉␉␉␉␉switch (rank) {␊ |
310 | ␉␉␉␉␉case rank_char:␊ |
311 | ␉␉␉␉␉␉/* Yes, all these casts are␊ |
312 | ␉␉␉␉␉␉ needed... */␊ |
313 | ␉␉␉␉␉␉val = (uintmax_t)(intmax_t)␊ |
314 | ␉␉␉␉␉␉␉(signed char)␊ |
315 | ␉␉␉␉␉␉␉va_arg(ap, signed int);␊ |
316 | ␉␉␉␉␉␉break;␊ |
317 | ␉␉␉␉␉case rank_short:␊ |
318 | ␉␉␉␉␉␉val = (uintmax_t)(intmax_t)␊ |
319 | ␉␉␉␉␉␉␉(signed short)␊ |
320 | ␉␉␉␉␉␉␉va_arg(ap, signed int);␊ |
321 | ␉␉␉␉␉␉break;␊ |
322 | ␉␉␉␉␉case rank_int:␊ |
323 | ␉␉␉␉␉␉val = (uintmax_t)(intmax_t)␊ |
324 | ␉␉␉␉␉␉ va_arg(ap, signed int);␊ |
325 | ␉␉␉␉␉␉break;␊ |
326 | ␉␉␉␉␉case rank_long:␊ |
327 | ␉␉␉␉␉␉val = (uintmax_t)(intmax_t)␊ |
328 | ␉␉␉␉␉␉ va_arg(ap, signed long);␊ |
329 | ␉␉␉␉␉␉break;␊ |
330 | ␉␉␉␉␉case rank_longlong:␊ |
331 | ␉␉␉␉␉␉val = (uintmax_t)(intmax_t)␊ |
332 | ␉␉␉␉␉␉ va_arg(ap,␊ |
333 | ␉␉␉␉␉␉␉ signed long long);␊ |
334 | ␉␉␉␉␉␉break;␊ |
335 | ␉␉␉␉␉}␊ |
336 | ␉␉␉␉␉goto is_integer;␊ |
337 | ␉␉␉␉case 'o':␉/* Octal */␊ |
338 | ␉␉␉␉␉base = 8;␊ |
339 | ␉␉␉␉␉goto is_unsigned;␊ |
340 | ␉␉␉␉case 'u':␉/* Unsigned decimal */␊ |
341 | ␉␉␉␉␉base = 10;␊ |
342 | ␉␉␉␉␉goto is_unsigned;␊ |
343 | ␉␉␉␉case 'X':␉/* Upper case hexadecimal */␊ |
344 | ␉␉␉␉␉flags |= FL_UPPER;␊ |
345 | ␉␉␉␉␉/* fall through */␊ |
346 | ␉␉␉␉case 'x':␉/* Hexadecimal */␊ |
347 | ␉␉␉␉␉base = 16;␊ |
348 | ␉␉␉␉␉goto is_unsigned;␊ |
349 | ␊ |
350 | ␉␉␉␉is_unsigned:␊ |
351 | ␉␉␉␉␉switch (rank) {␊ |
352 | ␉␉␉␉␉case rank_char:␊ |
353 | ␉␉␉␉␉␉val = (uintmax_t)␊ |
354 | ␉␉␉␉␉␉␉(unsigned char)␊ |
355 | ␉␉␉␉␉␉␉va_arg(ap, unsigned␊ |
356 | ␉␉␉␉␉␉␉ int);␊ |
357 | ␉␉␉␉␉␉break;␊ |
358 | ␉␉␉␉␉case rank_short:␊ |
359 | ␉␉␉␉␉␉val = (uintmax_t)␊ |
360 | ␉␉␉␉␉␉␉(unsigned short)␊ |
361 | ␉␉␉␉␉␉␉va_arg(ap, unsigned␊ |
362 | ␉␉␉␉␉␉␉ int);␊ |
363 | ␉␉␉␉␉␉break;␊ |
364 | ␉␉␉␉␉case rank_int:␊ |
365 | ␉␉␉␉␉␉val = (uintmax_t)␊ |
366 | ␉␉␉␉␉␉␉va_arg(ap, unsigned␊ |
367 | ␉␉␉␉␉␉␉ int);␊ |
368 | ␉␉␉␉␉␉break;␊ |
369 | ␉␉␉␉␉case rank_long:␊ |
370 | ␉␉␉␉␉␉val = (uintmax_t)␊ |
371 | ␉␉␉␉␉␉␉va_arg(ap, unsigned␊ |
372 | ␉␉␉␉␉␉␉ long);␊ |
373 | ␉␉␉␉␉␉break;␊ |
374 | ␉␉␉␉␉case rank_longlong:␊ |
375 | ␉␉␉␉␉␉val = (uintmax_t)␊ |
376 | ␉␉␉␉␉␉␉va_arg(ap, unsigned␊ |
377 | ␉␉␉␉␉␉␉ long long);␊ |
378 | ␉␉␉␉␉␉break;␊ |
379 | ␉␉␉␉␉}␊ |
380 | ␉␉␉␉␉/* fall through */␊ |
381 | ␊ |
382 | ␉␉␉␉is_integer:␊ |
383 | ␉␉␉␉␉sz = format_int(q, (o < n) ? n - o : 0,␊ |
384 | ␉␉␉␉␉␉␉val, flags, base,␊ |
385 | ␉␉␉␉␉␉␉width, prec);␊ |
386 | ␉␉␉␉␉q += sz;␊ |
387 | ␉␉␉␉␉o += sz;␊ |
388 | ␉␉␉␉␉break;␊ |
389 | ␊ |
390 | ␉␉␉␉case 'c':␉/* Character */␊ |
391 | ␉␉␉␉␉carg = (char)va_arg(ap, int);␊ |
392 | ␉␉␉␉␉sarg = &carg;␊ |
393 | ␉␉␉␉␉slen = 1;␊ |
394 | ␉␉␉␉␉goto is_string;␊ |
395 | ␉␉␉␉case 's':␉/* String */␊ |
396 | ␉␉␉␉␉sarg = va_arg(ap, const char *);␊ |
397 | ␉␉␉␉␉sarg = sarg ? sarg : "(null)";␊ |
398 | ␉␉␉␉␉slen = strlen(sarg);␊ |
399 | ␉␉␉␉␉goto is_string;␊ |
400 | ␊ |
401 | ␉␉␉␉is_string:␊ |
402 | ␉␉␉␉␉{␊ |
403 | ␉␉␉␉␉␉char sch;␊ |
404 | ␉␉␉␉␉␉int i;␊ |
405 | ␊ |
406 | ␉␉␉␉␉␉if (prec != -1 && slen > prec)␊ |
407 | ␉␉␉␉␉␉␉slen = prec;␊ |
408 | ␊ |
409 | ␉␉␉␉␉␉if (width > slen␊ |
410 | ␉␉␉␉␉␉ && !(flags & FL_MINUS)) {␊ |
411 | ␉␉␉␉␉␉␉char pad =␊ |
412 | ␉␉␉␉␉␉␉ (flags & FL_ZERO) ?␊ |
413 | ␉␉␉␉␉␉␉ '0' : ' ';␊ |
414 | ␉␉␉␉␉␉␉while (width > slen) {␊ |
415 | ␉␉␉␉␉␉␉␉EMIT(pad);␊ |
416 | ␉␉␉␉␉␉␉␉width--;␊ |
417 | ␉␉␉␉␉␉␉}␊ |
418 | ␉␉␉␉␉␉}␊ |
419 | ␉␉␉␉␉␉for (i = slen; i; i--) {␊ |
420 | ␉␉␉␉␉␉␉sch = *sarg++;␊ |
421 | ␉␉␉␉␉␉␉EMIT(sch);␊ |
422 | ␉␉␉␉␉␉}␊ |
423 | ␉␉␉␉␉␉if (width > slen␊ |
424 | ␉␉␉␉␉␉ && (flags & FL_MINUS)) {␊ |
425 | ␉␉␉␉␉␉␉while (width > slen) {␊ |
426 | ␉␉␉␉␉␉␉␉EMIT(' ');␊ |
427 | ␉␉␉␉␉␉␉␉width--;␊ |
428 | ␉␉␉␉␉␉␉}␊ |
429 | ␉␉␉␉␉␉}␊ |
430 | ␉␉␉␉␉}␊ |
431 | ␉␉␉␉␉break;␊ |
432 | ␊ |
433 | ␉␉␉␉case 'n':␊ |
434 | ␉␉␉␉␉{␊ |
435 | ␉␉␉␉␉␉/* Output the number of␊ |
436 | ␉␉␉␉␉␉ characters written */␊ |
437 | ␊ |
438 | ␉␉␉␉␉␉switch (rank) {␊ |
439 | ␉␉␉␉␉␉case rank_char:␊ |
440 | ␉␉␉␉␉␉␉*va_arg(ap,␊ |
441 | ␉␉␉␉␉␉␉␉signed char *)␊ |
442 | ␉␉␉␉␉␉␉␉= o;␊ |
443 | ␉␉␉␉␉␉␉break;␊ |
444 | ␉␉␉␉␉␉case rank_short:␊ |
445 | ␉␉␉␉␉␉␉*va_arg(ap,␊ |
446 | ␉␉␉␉␉␉␉␉signed short *)␊ |
447 | ␉␉␉␉␉␉␉␉= o;␊ |
448 | ␉␉␉␉␉␉␉break;␊ |
449 | ␉␉␉␉␉␉case rank_int:␊ |
450 | ␉␉␉␉␉␉␉*va_arg(ap,␊ |
451 | ␉␉␉␉␉␉␉␉signed int *)␊ |
452 | ␉␉␉␉␉␉␉␉= o;␊ |
453 | ␉␉␉␉␉␉␉break;␊ |
454 | ␉␉␉␉␉␉case rank_long:␊ |
455 | ␉␉␉␉␉␉␉*va_arg(ap,␊ |
456 | ␉␉␉␉␉␉␉␉signed long *)␊ |
457 | ␉␉␉␉␉␉␉␉= o;␊ |
458 | ␉␉␉␉␉␉␉break;␊ |
459 | ␉␉␉␉␉␉case rank_longlong:␊ |
460 | ␉␉␉␉␉␉␉*va_arg(ap,␊ |
461 | ␉␉␉␉␉␉␉␉signed long long *)␊ |
462 | ␉␉␉␉␉␉␉␉= o;␊ |
463 | ␉␉␉␉␉␉␉break;␊ |
464 | ␉␉␉␉␉␉}␊ |
465 | ␉␉␉␉␉}␊ |
466 | ␉␉␉␉␉break;␊ |
467 | ␊ |
468 | ␉␉␉␉default:␉/* Anything else, including % */␊ |
469 | ␉␉␉␉␉EMIT(ch);␊ |
470 | ␉␉␉␉␉break;␊ |
471 | ␉␉␉␉}␊ |
472 | ␉␉␉}␊ |
473 | ␉␉}␊ |
474 | ␉}␊ |
475 | ␊ |
476 | ␉/* Null-terminate the string */␊ |
477 | ␉if (o < n)␊ |
478 | ␉␉*q = '\0';␉/* No overflow */␊ |
479 | ␉else if (n > 0)␊ |
480 | ␉␉buffer[n - 1] = '\0';␉/* Overflow - terminate at end of buffer */␊ |
481 | ␊ |
482 | ␉return o;␊ |
483 | }␊ |
484 | |