Chameleon

Chameleon Svn Source Tree

Root/branches/rewrite/i386/modules/klibc/vsnprintf.c

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

Archive Download this file

Revision: 1146