diff options
Diffstat (limited to 'arch/powerpc/boot/stdio.c')
-rw-r--r-- | arch/powerpc/boot/stdio.c | 325 |
1 files changed, 325 insertions, 0 deletions
diff --git a/arch/powerpc/boot/stdio.c b/arch/powerpc/boot/stdio.c new file mode 100644 index 00000000000..b5aa522f8b7 --- /dev/null +++ b/arch/powerpc/boot/stdio.c | |||
@@ -0,0 +1,325 @@ | |||
1 | /* | ||
2 | * Copyright (C) Paul Mackerras 1997. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version | ||
7 | * 2 of the License, or (at your option) any later version. | ||
8 | */ | ||
9 | #include <stdarg.h> | ||
10 | #include <stddef.h> | ||
11 | #include "string.h" | ||
12 | #include "stdio.h" | ||
13 | #include "prom.h" | ||
14 | |||
15 | size_t strnlen(const char * s, size_t count) | ||
16 | { | ||
17 | const char *sc; | ||
18 | |||
19 | for (sc = s; count-- && *sc != '\0'; ++sc) | ||
20 | /* nothing */; | ||
21 | return sc - s; | ||
22 | } | ||
23 | |||
24 | extern unsigned int __div64_32(unsigned long long *dividend, | ||
25 | unsigned int divisor); | ||
26 | |||
27 | /* The unnecessary pointer compare is there | ||
28 | * to check for type safety (n must be 64bit) | ||
29 | */ | ||
30 | # define do_div(n,base) ({ \ | ||
31 | unsigned int __base = (base); \ | ||
32 | unsigned int __rem; \ | ||
33 | (void)(((typeof((n)) *)0) == ((unsigned long long *)0)); \ | ||
34 | if (((n) >> 32) == 0) { \ | ||
35 | __rem = (unsigned int)(n) % __base; \ | ||
36 | (n) = (unsigned int)(n) / __base; \ | ||
37 | } else \ | ||
38 | __rem = __div64_32(&(n), __base); \ | ||
39 | __rem; \ | ||
40 | }) | ||
41 | |||
42 | static int skip_atoi(const char **s) | ||
43 | { | ||
44 | int i, c; | ||
45 | |||
46 | for (i = 0; '0' <= (c = **s) && c <= '9'; ++*s) | ||
47 | i = i*10 + c - '0'; | ||
48 | return i; | ||
49 | } | ||
50 | |||
51 | #define ZEROPAD 1 /* pad with zero */ | ||
52 | #define SIGN 2 /* unsigned/signed long */ | ||
53 | #define PLUS 4 /* show plus */ | ||
54 | #define SPACE 8 /* space if plus */ | ||
55 | #define LEFT 16 /* left justified */ | ||
56 | #define SPECIAL 32 /* 0x */ | ||
57 | #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ | ||
58 | |||
59 | static char * number(char * str, unsigned long long num, int base, int size, int precision, int type) | ||
60 | { | ||
61 | char c,sign,tmp[66]; | ||
62 | const char *digits="0123456789abcdefghijklmnopqrstuvwxyz"; | ||
63 | int i; | ||
64 | |||
65 | if (type & LARGE) | ||
66 | digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; | ||
67 | if (type & LEFT) | ||
68 | type &= ~ZEROPAD; | ||
69 | if (base < 2 || base > 36) | ||
70 | return 0; | ||
71 | c = (type & ZEROPAD) ? '0' : ' '; | ||
72 | sign = 0; | ||
73 | if (type & SIGN) { | ||
74 | if ((signed long long)num < 0) { | ||
75 | sign = '-'; | ||
76 | num = - (signed long long)num; | ||
77 | size--; | ||
78 | } else if (type & PLUS) { | ||
79 | sign = '+'; | ||
80 | size--; | ||
81 | } else if (type & SPACE) { | ||
82 | sign = ' '; | ||
83 | size--; | ||
84 | } | ||
85 | } | ||
86 | if (type & SPECIAL) { | ||
87 | if (base == 16) | ||
88 | size -= 2; | ||
89 | else if (base == 8) | ||
90 | size--; | ||
91 | } | ||
92 | i = 0; | ||
93 | if (num == 0) | ||
94 | tmp[i++]='0'; | ||
95 | else while (num != 0) { | ||
96 | tmp[i++] = digits[do_div(num, base)]; | ||
97 | } | ||
98 | if (i > precision) | ||
99 | precision = i; | ||
100 | size -= precision; | ||
101 | if (!(type&(ZEROPAD+LEFT))) | ||
102 | while(size-->0) | ||
103 | *str++ = ' '; | ||
104 | if (sign) | ||
105 | *str++ = sign; | ||
106 | if (type & SPECIAL) { | ||
107 | if (base==8) | ||
108 | *str++ = '0'; | ||
109 | else if (base==16) { | ||
110 | *str++ = '0'; | ||
111 | *str++ = digits[33]; | ||
112 | } | ||
113 | } | ||
114 | if (!(type & LEFT)) | ||
115 | while (size-- > 0) | ||
116 | *str++ = c; | ||
117 | while (i < precision--) | ||
118 | *str++ = '0'; | ||
119 | while (i-- > 0) | ||
120 | *str++ = tmp[i]; | ||
121 | while (size-- > 0) | ||
122 | *str++ = ' '; | ||
123 | return str; | ||
124 | } | ||
125 | |||
126 | int vsprintf(char *buf, const char *fmt, va_list args) | ||
127 | { | ||
128 | int len; | ||
129 | unsigned long long num; | ||
130 | int i, base; | ||
131 | char * str; | ||
132 | const char *s; | ||
133 | |||
134 | int flags; /* flags to number() */ | ||
135 | |||
136 | int field_width; /* width of output field */ | ||
137 | int precision; /* min. # of digits for integers; max | ||
138 | number of chars for from string */ | ||
139 | int qualifier; /* 'h', 'l', or 'L' for integer fields */ | ||
140 | /* 'z' support added 23/7/1999 S.H. */ | ||
141 | /* 'z' changed to 'Z' --davidm 1/25/99 */ | ||
142 | |||
143 | |||
144 | for (str=buf ; *fmt ; ++fmt) { | ||
145 | if (*fmt != '%') { | ||
146 | *str++ = *fmt; | ||
147 | continue; | ||
148 | } | ||
149 | |||
150 | /* process flags */ | ||
151 | flags = 0; | ||
152 | repeat: | ||
153 | ++fmt; /* this also skips first '%' */ | ||
154 | switch (*fmt) { | ||
155 | case '-': flags |= LEFT; goto repeat; | ||
156 | case '+': flags |= PLUS; goto repeat; | ||
157 | case ' ': flags |= SPACE; goto repeat; | ||
158 | case '#': flags |= SPECIAL; goto repeat; | ||
159 | case '0': flags |= ZEROPAD; goto repeat; | ||
160 | } | ||
161 | |||
162 | /* get field width */ | ||
163 | field_width = -1; | ||
164 | if ('0' <= *fmt && *fmt <= '9') | ||
165 | field_width = skip_atoi(&fmt); | ||
166 | else if (*fmt == '*') { | ||
167 | ++fmt; | ||
168 | /* it's the next argument */ | ||
169 | field_width = va_arg(args, int); | ||
170 | if (field_width < 0) { | ||
171 | field_width = -field_width; | ||
172 | flags |= LEFT; | ||
173 | } | ||
174 | } | ||
175 | |||
176 | /* get the precision */ | ||
177 | precision = -1; | ||
178 | if (*fmt == '.') { | ||
179 | ++fmt; | ||
180 | if ('0' <= *fmt && *fmt <= '9') | ||
181 | precision = skip_atoi(&fmt); | ||
182 | else if (*fmt == '*') { | ||
183 | ++fmt; | ||
184 | /* it's the next argument */ | ||
185 | precision = va_arg(args, int); | ||
186 | } | ||
187 | if (precision < 0) | ||
188 | precision = 0; | ||
189 | } | ||
190 | |||
191 | /* get the conversion qualifier */ | ||
192 | qualifier = -1; | ||
193 | if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt =='Z') { | ||
194 | qualifier = *fmt; | ||
195 | ++fmt; | ||
196 | } | ||
197 | |||
198 | /* default base */ | ||
199 | base = 10; | ||
200 | |||
201 | switch (*fmt) { | ||
202 | case 'c': | ||
203 | if (!(flags & LEFT)) | ||
204 | while (--field_width > 0) | ||
205 | *str++ = ' '; | ||
206 | *str++ = (unsigned char) va_arg(args, int); | ||
207 | while (--field_width > 0) | ||
208 | *str++ = ' '; | ||
209 | continue; | ||
210 | |||
211 | case 's': | ||
212 | s = va_arg(args, char *); | ||
213 | if (!s) | ||
214 | s = "<NULL>"; | ||
215 | |||
216 | len = strnlen(s, precision); | ||
217 | |||
218 | if (!(flags & LEFT)) | ||
219 | while (len < field_width--) | ||
220 | *str++ = ' '; | ||
221 | for (i = 0; i < len; ++i) | ||
222 | *str++ = *s++; | ||
223 | while (len < field_width--) | ||
224 | *str++ = ' '; | ||
225 | continue; | ||
226 | |||
227 | case 'p': | ||
228 | if (field_width == -1) { | ||
229 | field_width = 2*sizeof(void *); | ||
230 | flags |= ZEROPAD; | ||
231 | } | ||
232 | str = number(str, | ||
233 | (unsigned long) va_arg(args, void *), 16, | ||
234 | field_width, precision, flags); | ||
235 | continue; | ||
236 | |||
237 | |||
238 | case 'n': | ||
239 | if (qualifier == 'l') { | ||
240 | long * ip = va_arg(args, long *); | ||
241 | *ip = (str - buf); | ||
242 | } else if (qualifier == 'Z') { | ||
243 | size_t * ip = va_arg(args, size_t *); | ||
244 | *ip = (str - buf); | ||
245 | } else { | ||
246 | int * ip = va_arg(args, int *); | ||
247 | *ip = (str - buf); | ||
248 | } | ||
249 | continue; | ||
250 | |||
251 | case '%': | ||
252 | *str++ = '%'; | ||
253 | continue; | ||
254 | |||
255 | /* integer number formats - set up the flags and "break" */ | ||
256 | case 'o': | ||
257 | base = 8; | ||
258 | break; | ||
259 | |||
260 | case 'X': | ||
261 | flags |= LARGE; | ||
262 | case 'x': | ||
263 | base = 16; | ||
264 | break; | ||
265 | |||
266 | case 'd': | ||
267 | case 'i': | ||
268 | flags |= SIGN; | ||
269 | case 'u': | ||
270 | break; | ||
271 | |||
272 | default: | ||
273 | *str++ = '%'; | ||
274 | if (*fmt) | ||
275 | *str++ = *fmt; | ||
276 | else | ||
277 | --fmt; | ||
278 | continue; | ||
279 | } | ||
280 | if (qualifier == 'l') { | ||
281 | num = va_arg(args, unsigned long); | ||
282 | if (flags & SIGN) | ||
283 | num = (signed long) num; | ||
284 | } else if (qualifier == 'Z') { | ||
285 | num = va_arg(args, size_t); | ||
286 | } else if (qualifier == 'h') { | ||
287 | num = (unsigned short) va_arg(args, int); | ||
288 | if (flags & SIGN) | ||
289 | num = (signed short) num; | ||
290 | } else { | ||
291 | num = va_arg(args, unsigned int); | ||
292 | if (flags & SIGN) | ||
293 | num = (signed int) num; | ||
294 | } | ||
295 | str = number(str, num, base, field_width, precision, flags); | ||
296 | } | ||
297 | *str = '\0'; | ||
298 | return str-buf; | ||
299 | } | ||
300 | |||
301 | int sprintf(char * buf, const char *fmt, ...) | ||
302 | { | ||
303 | va_list args; | ||
304 | int i; | ||
305 | |||
306 | va_start(args, fmt); | ||
307 | i=vsprintf(buf,fmt,args); | ||
308 | va_end(args); | ||
309 | return i; | ||
310 | } | ||
311 | |||
312 | static char sprint_buf[1024]; | ||
313 | |||
314 | int | ||
315 | printf(const char *fmt, ...) | ||
316 | { | ||
317 | va_list args; | ||
318 | int n; | ||
319 | |||
320 | va_start(args, fmt); | ||
321 | n = vsprintf(sprint_buf, fmt, args); | ||
322 | va_end(args); | ||
323 | write(stdout, sprint_buf, n); | ||
324 | return n; | ||
325 | } | ||