| @@ -1,271 +1,272 @@ | | | @@ -1,271 +1,272 @@ |
1 | /* $NetBSD: printf.c,v 1.2 2011/01/23 01:32:08 nisimura Exp $ */ | | 1 | /* $NetBSD: printf.c,v 1.3 2011/01/23 02:08:24 nisimura Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2007 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2007 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Tohru Nishimura. | | 8 | * by Tohru Nishimura. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright | | 15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the | | 16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. | | 17 | * documentation and/or other materials provided with the distribution. |
18 | * | | 18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | /* | | 32 | /* |
33 | * printf -- format and write output using 'func' to write characters | | 33 | * printf -- format and write output using 'func' to write characters |
34 | */ | | 34 | */ |
35 | | | 35 | |
36 | #include <sys/types.h> | | 36 | #include <sys/types.h> |
37 | #include <machine/stdarg.h> | | 37 | #include <machine/stdarg.h> |
38 | #include <lib/libsa/stand.h> | | 38 | #include <lib/libsa/stand.h> |
39 | | | 39 | |
40 | #define MAXSTR 80 | | 40 | #define MAXSTR 80 |
41 | | | 41 | |
42 | static int _doprnt(void (*)(int), const char *, va_list); | | 42 | static int _doprnt(void (*)(int), const char *, va_list); |
43 | static void mkdigit(unsigned long long, int, char *); | | 43 | static void mkdigit(unsigned long long, int, char *); |
44 | static void sputchar(int); | | 44 | static void sputchar(int); |
45 | | | 45 | |
46 | static char *sbuf, *ebuf; | | 46 | static char *sbuf, *ebuf; |
47 | | | 47 | |
48 | void | | 48 | void |
49 | printf(const char *fmt, ...) | | 49 | printf(const char *fmt, ...) |
50 | { | | 50 | { |
51 | va_list ap; | | 51 | va_list ap; |
52 | | | 52 | |
53 | va_start(ap, fmt); | | 53 | va_start(ap, fmt); |
54 | _doprnt(putchar, fmt, ap); | | 54 | _doprnt(putchar, fmt, ap); |
55 | va_end(ap); | | 55 | va_end(ap); |
56 | } | | 56 | } |
57 | | | 57 | |
58 | void | | 58 | void |
59 | vprintf(const char *fmt, va_list ap) | | 59 | vprintf(const char *fmt, va_list ap) |
60 | { | | 60 | { |
61 | | | 61 | |
62 | _doprnt(putchar, fmt, ap); | | 62 | _doprnt(putchar, fmt, ap); |
63 | } | | 63 | } |
64 | | | 64 | |
65 | int | | 65 | int |
66 | sprintf(char *buf, const char *fmt, ...) | | 66 | sprintf(char *buf, const char *fmt, ...) |
67 | { | | 67 | { |
68 | va_list ap; | | 68 | va_list ap; |
69 | | | 69 | |
70 | sbuf = buf; | | 70 | sbuf = buf; |
71 | ebuf = buf + -(size_t)buf - 1; | | 71 | ebuf = buf + -(size_t)buf - 1; |
72 | va_start(ap, fmt); | | 72 | va_start(ap, fmt); |
73 | _doprnt(sputchar, fmt, ap); | | 73 | _doprnt(sputchar, fmt, ap); |
74 | *sbuf = '\0'; | | 74 | *sbuf = '\0'; |
75 | return (sbuf - buf); | | 75 | return (sbuf - buf); |
76 | } | | 76 | } |
77 | | | 77 | |
78 | int | | 78 | int |
79 | snprintf(char *buf, size_t size, const char *fmt, ...) | | 79 | snprintf(char *buf, size_t size, const char *fmt, ...) |
80 | { | | 80 | { |
81 | va_list ap; | | 81 | va_list ap; |
82 | | | 82 | |
83 | sbuf = buf; | | 83 | sbuf = buf; |
84 | ebuf = buf + size - 1; | | 84 | ebuf = buf + size - 1; |
85 | va_start(ap, fmt); | | 85 | va_start(ap, fmt); |
86 | _doprnt(sputchar, fmt, ap); | | 86 | _doprnt(sputchar, fmt, ap); |
87 | *sbuf = '\0'; | | 87 | *sbuf = '\0'; |
88 | return (sbuf - buf); | | 88 | return (sbuf - buf); |
89 | } | | 89 | } |
90 | | | 90 | |
91 | static int | | 91 | static int |
92 | _doprnt(void (*func)(int), const char *fmt, va_list ap) | | 92 | _doprnt(void (*func)(int), const char *fmt, va_list ap) |
93 | { | | 93 | { |
94 | int i, outcnt; | | 94 | int i, outcnt; |
95 | char buf[23], *str; /* requires 23 digits in octal at most */ | | 95 | char buf[23], *str; /* requires 23 digits in octal at most */ |
96 | int length, fmax, fmin, leading; | | 96 | int length, fmax, fmin, leading; |
97 | int leftjust, llflag; | | 97 | int leftjust, llflag; |
98 | char fill, sign; | | 98 | char fill, sign; |
99 | long long v; | | 99 | long long d; |
| | | 100 | unsigned long long v; |
100 | | | 101 | |
101 | outcnt = 0; | | 102 | outcnt = 0; |
102 | while ((i = *fmt++) != '\0') { | | 103 | while ((i = *fmt++) != '\0') { |
103 | if (i != '%') { | | 104 | if (i != '%') { |
104 | (*func)(i); | | 105 | (*func)(i); |
105 | outcnt += 1; | | 106 | outcnt += 1; |
106 | continue; | | 107 | continue; |
107 | } | | 108 | } |
108 | if (*fmt == '%') { | | 109 | if (*fmt == '%') { |
109 | (*func)(*fmt++); | | 110 | (*func)(*fmt++); |
110 | outcnt += 1; | | 111 | outcnt += 1; |
111 | continue; | | 112 | continue; |
112 | } | | 113 | } |
113 | leftjust = (*fmt == '-'); | | 114 | leftjust = (*fmt == '-'); |
114 | if (leftjust) | | 115 | if (leftjust) |
115 | fmt++; | | 116 | fmt++; |
116 | fill = (*fmt == '0') ? *fmt++ : ' '; | | 117 | fill = (*fmt == '0') ? *fmt++ : ' '; |
117 | if (*fmt == '*') | | 118 | if (*fmt == '*') |
118 | fmin = va_arg(ap, int); | | 119 | fmin = va_arg(ap, int); |
119 | else { | | 120 | else { |
120 | fmin = 0; | | 121 | fmin = 0; |
121 | while ('0' <= *fmt && *fmt <= '9') | | 122 | while ('0' <= *fmt && *fmt <= '9') |
122 | fmin = fmin * 10 + *fmt++ - '0'; | | 123 | fmin = fmin * 10 + *fmt++ - '0'; |
123 | } | | 124 | } |
124 | if (*fmt != '.') | | 125 | if (*fmt != '.') |
125 | fmax = 0; | | 126 | fmax = 0; |
126 | else { | | 127 | else { |
127 | fmt++; | | 128 | fmt++; |
128 | if (*fmt == '*') | | 129 | if (*fmt == '*') |
129 | fmax = va_arg(ap, int); | | 130 | fmax = va_arg(ap, int); |
130 | else { | | 131 | else { |
131 | fmax = 0; | | 132 | fmax = 0; |
132 | while ('0' <= *fmt && *fmt <= '9') | | 133 | while ('0' <= *fmt && *fmt <= '9') |
133 | fmax = fmax * 10 + *fmt++ - '0'; | | 134 | fmax = fmax * 10 + *fmt++ - '0'; |
134 | } | | 135 | } |
135 | } | | 136 | } |
136 | llflag = 0; | | 137 | llflag = 0; |
137 | if (*fmt == 'l' && *++fmt == 'l') { | | 138 | if (*fmt == 'l' && *++fmt == 'l') { |
138 | llflag = 1; | | 139 | llflag = 1; |
139 | fmt += 1; | | 140 | fmt += 1; |
140 | } | | 141 | } |
141 | if ((i = *fmt++) == '\0') { | | 142 | if ((i = *fmt++) == '\0') { |
142 | (*func)('%'); | | 143 | (*func)('%'); |
143 | outcnt += 1; | | 144 | outcnt += 1; |
144 | break; | | 145 | break; |
145 | } | | 146 | } |
146 | str = buf; | | 147 | str = buf; |
147 | sign = ' '; | | 148 | sign = ' '; |
148 | switch (i) { | | 149 | switch (i) { |
149 | case 'c': | | 150 | case 'c': |
150 | str[0] = va_arg(ap, int); | | 151 | str[0] = va_arg(ap, int); |
151 | str[1] = '\0'; | | 152 | str[1] = '\0'; |
152 | fmax = 0; | | 153 | fmax = 0; |
153 | fill = ' '; | | 154 | fill = ' '; |
154 | break; | | 155 | break; |
155 | | | 156 | |
156 | case 's': | | 157 | case 's': |
157 | str = va_arg(ap, char *); | | 158 | str = va_arg(ap, char *); |
158 | fill = ' '; | | 159 | fill = ' '; |
159 | break; | | 160 | break; |
160 | | | 161 | |
161 | case 'd': | | 162 | case 'd': |
162 | if (llflag) | | 163 | if (llflag) |
163 | v = va_arg(ap, long long); | | 164 | d = va_arg(ap, long long); |
164 | else | | 165 | else |
165 | v = va_arg(ap, int); | | 166 | d = va_arg(ap, int); |
166 | if (v < 0) { | | 167 | if (d < 0) { |
167 | sign = '-' ; v = -v; | | 168 | sign = '-' ; d = -d; |
168 | } | | 169 | } |
169 | mkdigit((unsigned long long)v, 10, str); | | 170 | mkdigit((unsigned long long)d, 10, str); |
170 | break; | | 171 | break; |
171 | | | 172 | |
172 | case 'u': | | 173 | case 'u': |
173 | if (llflag) | | 174 | if (llflag) |
174 | v = va_arg(ap, long long); | | 175 | v = va_arg(ap, unsigned long long); |
175 | else | | 176 | else |
176 | v = va_arg(ap, int); | | 177 | v = va_arg(ap, unsigned int); |
177 | mkdigit((unsigned long long)v, 10, str); | | 178 | mkdigit(v, 10, str); |
178 | break; | | 179 | break; |
179 | | | 180 | |
180 | case 'o': | | 181 | case 'o': |
181 | if (llflag) | | 182 | if (llflag) |
182 | v = va_arg(ap, long long); | | 183 | v = va_arg(ap, unsigned long long); |
183 | else | | 184 | else |
184 | v = va_arg(ap, int); | | 185 | v = va_arg(ap, unsigned int); |
185 | mkdigit((unsigned long long)v, 8, str); | | 186 | mkdigit(v, 8, str); |
186 | fmax = 0; | | 187 | fmax = 0; |
187 | break; | | 188 | break; |
188 | | | 189 | |
189 | case 'X': | | 190 | case 'X': |
190 | case 'x': | | 191 | case 'x': |
191 | if (llflag) | | 192 | if (llflag) |
192 | v = va_arg(ap, long long); | | 193 | v = va_arg(ap, unsigned long long); |
193 | else | | 194 | else |
194 | v = va_arg(ap, int); | | 195 | v = va_arg(ap, unsigned int); |
195 | mkdigit((unsigned long long)v, 16, str); | | 196 | mkdigit(v, 16, str); |
196 | fmax = 0; | | 197 | fmax = 0; |
197 | break; | | 198 | break; |
198 | | | 199 | |
199 | case 'p': | | 200 | case 'p': |
200 | mkdigit(va_arg(ap, unsigned int), 16, str); | | 201 | mkdigit(va_arg(ap, unsigned int), 16, str); |
201 | fill = '0'; | | 202 | fill = '0'; |
202 | fmin = 8; | | 203 | fmin = 8; |
203 | fmax = 0; | | 204 | fmax = 0; |
204 | (*func)('0'); (*func)('x'); | | 205 | (*func)('0'); (*func)('x'); |
205 | outcnt += 2; | | 206 | outcnt += 2; |
206 | break; | | 207 | break; |
207 | | | 208 | |
208 | default: | | 209 | default: |
209 | (*func)(i); | | 210 | (*func)(i); |
210 | break; | | 211 | break; |
211 | } | | 212 | } |
212 | for (i = 0; str[i] != '\0'; i++) | | 213 | for (i = 0; str[i] != '\0'; i++) |
213 | ; | | 214 | ; |
214 | length = i; | | 215 | length = i; |
215 | if (fmin > MAXSTR || fmin < 0) | | 216 | if (fmin > MAXSTR || fmin < 0) |
216 | fmin = 0; | | 217 | fmin = 0; |
217 | if (fmax > MAXSTR || fmax < 0) | | 218 | if (fmax > MAXSTR || fmax < 0) |
218 | fmax = 0; | | 219 | fmax = 0; |
219 | leading = 0; | | 220 | leading = 0; |
220 | if (fmax != 0 || fmin != 0) { | | 221 | if (fmax != 0 || fmin != 0) { |
221 | if (fmax != 0 && length > fmax) | | 222 | if (fmax != 0 && length > fmax) |
222 | length = fmax; | | 223 | length = fmax; |
223 | if (fmin != 0) | | 224 | if (fmin != 0) |
224 | leading = fmin - length; | | 225 | leading = fmin - length; |
225 | if (sign == '-') | | 226 | if (sign == '-') |
226 | --leading; | | 227 | --leading; |
227 | } | | 228 | } |
228 | outcnt += leading + length; | | 229 | outcnt += leading + length; |
229 | if (sign == '-') | | 230 | if (sign == '-') |
230 | outcnt += 1; | | 231 | outcnt += 1; |
231 | if (sign == '-' && fill == '0') | | 232 | if (sign == '-' && fill == '0') |
232 | (*func)(sign); | | 233 | (*func)(sign); |
233 | if (leftjust == 0) | | 234 | if (leftjust == 0) |
234 | for (i = 0; i < leading; i++) (*func)(fill); | | 235 | for (i = 0; i < leading; i++) (*func)(fill); |
235 | if (sign == '-' && fill == ' ') | | 236 | if (sign == '-' && fill == ' ') |
236 | (*func)(sign); | | 237 | (*func)(sign); |
237 | for (i = 0; i < length; i++) | | 238 | for (i = 0; i < length; i++) |
238 | (*func)(str[i]); | | 239 | (*func)(str[i]); |
239 | if (leftjust != 0) | | 240 | if (leftjust != 0) |
240 | for (i = 0; i < leading; i++) (*func)(fill); | | 241 | for (i = 0; i < leading; i++) (*func)(fill); |
241 | } | | 242 | } |
242 | return outcnt; | | 243 | return outcnt; |
243 | } | | 244 | } |
244 | | | 245 | |
245 | | | 246 | |
246 | static void | | 247 | static void |
247 | mkdigit(unsigned long long llval, int base, char *s) | | 248 | mkdigit(unsigned long long llval, int base, char *s) |
248 | { | | 249 | { |
249 | char ptmp[23], *t; /* requires 22 digit in octal at most */ | | 250 | char ptmp[23], *t; /* requires 22 digit in octal at most */ |
250 | int n; | | 251 | int n; |
251 | static const char hexdigit[] = "0123456789abcdef"; | | 252 | static const char hexdigit[] = "0123456789abcdef"; |
252 | | | 253 | |
253 | n = 1; | | 254 | n = 1; |
254 | t = ptmp; | | 255 | t = ptmp; |
255 | *t++ = '\0'; | | 256 | *t++ = '\0'; |
256 | do { | | 257 | do { |
257 | int d = (int)llval % base; | | 258 | int d = (int)llval % base; |
258 | *t++ = hexdigit[d]; | | 259 | *t++ = hexdigit[d]; |
259 | llval /= base; | | 260 | llval /= base; |
260 | } while (llval != 0 && ++n < sizeof(ptmp)); | | 261 | } while (llval != 0 && ++n < sizeof(ptmp)); |
261 | while ((*s++ = *--t) != '\0') | | 262 | while ((*s++ = *--t) != '\0') |
262 | /* copy reserved digits */ ; | | 263 | /* copy reserved digits */ ; |
263 | } | | 264 | } |
264 | | | 265 | |
265 | static void | | 266 | static void |
266 | sputchar(int c) | | 267 | sputchar(int c) |
267 | { | | 268 | { |
268 | | | 269 | |
269 | if (sbuf < ebuf) | | 270 | if (sbuf < ebuf) |
270 | *sbuf++ = c; | | 271 | *sbuf++ = c; |
271 | } | | 272 | } |