Adjust memory layout for 2.6.22+ kernels with 32KB setup code
[mknbi.git] / printf.c
1 #include "misc.h"
2 #include "printf.h"
3 #include "etherboot.h"
4 #include <stdarg.h>
5 #include <limits.h>
6 #include <stdint.h>
7 #include <sys/types.h>
8
9 #define LONG_SHIFT  ((int)((sizeof(unsigned long)*CHAR_BIT) - 4))
10 #define INT_SHIFT   ((int)((sizeof(unsigned int)*CHAR_BIT) - 4))
11 #define SHRT_SHIFT  ((int)((sizeof(unsigned short)*CHAR_BIT) - 4))
12 #define CHAR_SHIFT  ((int)((sizeof(unsigned char)*CHAR_BIT) - 4))
13
14 /**************************************************************************
15 PRINTF and friends
16
17         Formats:
18                 %[#]x   - 4 bytes int (8 hex digits, lower case)
19                 %[#]X   - 4 bytes int (8 hex digits, upper case)
20                 %[#]lx  - 8 bytes long (16 hex digits, lower case)
21                 %[#]lX  - 8 bytes long (16 hex digits, upper case)
22                 %[#]hx  - 2 bytes int (4 hex digits, lower case)
23                 %[#]hX  - 2 bytes int (4 hex digits, upper case)
24                 %[#]hhx - 1 byte int (2 hex digits, lower case)
25                 %[#]hhX - 1 byte int (2 hex digits, upper case)
26                         - optional # prefixes 0x or 0X
27                 %d      - decimal int
28                 %c      - char
29                 %s      - string
30                 %@      - Internet address in ddd.ddd.ddd.ddd notation
31 #ifdef  PRINT_ENET_ADDRS
32                 %!      - Ethernet address in xx:xx:xx:xx:xx:xx notation
33 #endif
34         Note: width specification ignored
35 **************************************************************************/
36 int vsprintf(char *buf, const char *fmt, va_list args)
37 {
38         char *p, *s;
39         s = buf;
40         for ( ; *fmt != '\0'; ++fmt) {
41                 if (*fmt != '%') {
42                         buf ? *s++ = *fmt : putchar(*fmt);
43                         continue;
44                 }
45                 /* skip width specs */
46                 fmt++;
47                 while (*fmt >= '0' && *fmt <= '9')
48                         fmt++;
49                 if (*fmt == '.')
50                         fmt++;
51                 while (*fmt >= '0' && *fmt <= '9')
52                         fmt++;
53                 if (*fmt == 's') {
54                         for(p = va_arg(args, char *); *p != '\0'; p++)
55                                 buf ? *s++ = *p : putchar(*p);
56                 }
57                 else {  /* Length of item is bounded */
58                         char tmp[40], *q = tmp;
59                         int alt = 0;
60                         int shift = INT_SHIFT;
61                         if (*fmt == '#') {
62                                 alt = 1;
63                                 fmt++;
64                         }
65                         if (*fmt == 'l') {
66                                 shift = LONG_SHIFT;
67                                 fmt++;
68                         }
69                         else if (*fmt == 'h') {
70                                 shift = SHRT_SHIFT;
71                                 fmt++;
72                                 if (*fmt == 'h') {
73                                         shift = CHAR_SHIFT;
74                                         fmt++;
75                                 }
76                         }
77
78                         /*
79                          * Before each format q points to tmp buffer
80                          * After each format q points past end of item
81                          */
82                         if ((*fmt | 0x20) == 'x') {
83                                 /* With x86 gcc, sizeof(long) == sizeof(int) */
84                                 unsigned long h;
85                                 int ncase;
86                                 if (shift > INT_SHIFT) {
87                                         h = va_arg(args, unsigned long);
88                                 } else {
89                                         h = va_arg(args, unsigned int);
90                                 }
91                                 ncase = (*fmt & 0x20);
92                                 if (alt) {
93                                         *q++ = '0';
94                                         *q++ = 'X' | ncase;
95                                 }
96                                 for ( ; shift >= 0; shift -= 4)
97                                         *q++ = "0123456789ABCDEF"[(h >> shift) & 0xF] | ncase;
98                         }
99                         else if (*fmt == 'd') {
100                                 char *r;
101                                 long i;
102                                 if (shift > INT_SHIFT) {
103                                         i = va_arg(args, long);
104                                 } else {
105                                         i = va_arg(args, int);
106                                 }
107                                 if (i < 0) {
108                                         *q++ = '-';
109                                         i = -i;
110                                 }
111                                 p = q;          /* save beginning of digits */
112                                 do {
113                                         *q++ = '0' + (i % 10);
114                                         i /= 10;
115                                 } while (i);
116                                 /* reverse digits, stop in middle */
117                                 r = q;          /* don't alter q */
118                                 while (--r > p) {
119                                         i = *r;
120                                         *r = *p;
121                                         *p++ = i;
122                                 }
123                         }
124                         else if (*fmt == '@') {
125                                 unsigned char *r;
126                                 union {
127                                         uint32_t        l;
128                                         unsigned char   c[4];
129                                 } u;
130                                 u.l = va_arg(args, uint32_t);
131                                 for (r = &u.c[0]; r < &u.c[4]; ++r)
132                                         q += sprintf(q, "%d.", *r);
133                                 --q;
134                         }
135 #ifdef  PRINT_ENET_ADDRS
136                         else if (*fmt == '!') {
137                                 char *r;
138                                 p = va_arg(args, char *);
139                                 for (r = p + ETH_ALEN; p < r; ++p)
140                                         q += sprintf(q, "%hhX:", *p);
141                                 --q;
142                         }
143 #endif  /* PRINT_ENET_ADDRS */
144                         else if (*fmt == 'c')
145                                 *q++ = va_arg(args, int);
146                         else
147                                 *q++ = *fmt;
148                         /* now output the saved string */
149                         for (p = tmp; p < q; ++p)
150                                 buf ? *s++ = *p : putchar(*p);
151                 }
152         }
153         if (buf)
154                 *s = '\0';
155         return (s - buf);
156 }
157
158 int sprintf(char *buf, const char *fmt, ...)
159 {
160         va_list args;
161         int i;
162         va_start(args, fmt);
163         i=vsprintf(buf, fmt, args);
164         va_end(args);
165         return i;
166 }
167
168 int printf(const char *fmt, ...)
169 {
170         va_list args;
171         int i;
172         va_start(args, fmt);
173         i=vsprintf(0, fmt, args);
174         va_end(args);
175         return i;
176 }