Chameleon Applications

Chameleon Applications Svn Source Tree

Root/branches/iFabio/Chameleon/i386/modules/klibc/vsnprintf.c

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

Archive Download this file

Revision: 307