Contents of /trunk/mkinitrd-magellan/busybox/coreutils/printf.c
Parent Directory | Revision Log
Revision 532 -
(show annotations)
(download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 9 months ago) by niro
File MIME type: text/plain
File size: 6625 byte(s)
Sat Sep 1 22:45:15 2007 UTC (16 years, 9 months ago) by niro
File MIME type: text/plain
File size: 6625 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd
1 | /* vi: set sw=4 ts=4: */ |
2 | /* printf - format and print data |
3 | |
4 | Copyright 1999 Dave Cinege |
5 | Portions copyright (C) 1990-1996 Free Software Foundation, Inc. |
6 | |
7 | Licensed under GPL v2 or later, see file LICENSE in this tarball for details. |
8 | */ |
9 | |
10 | /* Usage: printf format [argument...] |
11 | |
12 | A front end to the printf function that lets it be used from the shell. |
13 | |
14 | Backslash escapes: |
15 | |
16 | \" = double quote |
17 | \\ = backslash |
18 | \a = alert (bell) |
19 | \b = backspace |
20 | \c = produce no further output |
21 | \f = form feed |
22 | \n = new line |
23 | \r = carriage return |
24 | \t = horizontal tab |
25 | \v = vertical tab |
26 | \0ooo = octal number (ooo is 0 to 3 digits) |
27 | \xhhh = hexadecimal number (hhh is 1 to 3 digits) |
28 | |
29 | Additional directive: |
30 | |
31 | %b = print an argument string, interpreting backslash escapes |
32 | |
33 | The 'format' argument is re-used as many times as necessary |
34 | to convert all of the given arguments. |
35 | |
36 | David MacKenzie <djm@gnu.ai.mit.edu> */ |
37 | |
38 | |
39 | // 19990508 Busy Boxed! Dave Cinege |
40 | |
41 | #include "busybox.h" |
42 | |
43 | static int print_formatted(char *format, int argc, char **argv); |
44 | static void print_direc(char *start, size_t length, |
45 | int field_width, int precision, char *argument); |
46 | |
47 | typedef void (*converter)(char *arg, void *result); |
48 | |
49 | static void multiconvert(char *arg, void *result, converter convert) |
50 | { |
51 | char s[16]; |
52 | if (*arg == '"' || *arg == '\'') { |
53 | sprintf(s, "%d", (unsigned char)arg[1]); |
54 | arg = s; |
55 | } |
56 | convert(arg, result); |
57 | if (errno) /* Huh, looks strange... bug? */ |
58 | fputs(arg, stderr); |
59 | } |
60 | |
61 | static void conv_strtoul(char *arg, void *result) |
62 | { |
63 | *(unsigned long*)result = bb_strtoul(arg, NULL, 10); |
64 | } |
65 | static void conv_strtol(char *arg, void *result) |
66 | { |
67 | *(long*)result = bb_strtol(arg, NULL, 10); |
68 | } |
69 | static void conv_strtod(char *arg, void *result) |
70 | { |
71 | char *end; |
72 | /* Well, this one allows leading whitespace... so what */ |
73 | /* What I like much less is that "-" is accepted too! :( */ |
74 | *(double*)result = strtod(arg, &end); |
75 | if (end[0]) errno = ERANGE; |
76 | } |
77 | |
78 | static unsigned long my_xstrtoul(char *arg) |
79 | { |
80 | unsigned long result; |
81 | multiconvert(arg, &result, conv_strtoul); |
82 | return result; |
83 | } |
84 | |
85 | static long my_xstrtol(char *arg) |
86 | { |
87 | long result; |
88 | multiconvert(arg, &result, conv_strtol); |
89 | return result; |
90 | } |
91 | |
92 | static double my_xstrtod(char *arg) |
93 | { |
94 | double result; |
95 | multiconvert(arg, &result, conv_strtod); |
96 | return result; |
97 | } |
98 | |
99 | static void print_esc_string(char *str) |
100 | { |
101 | for (; *str; str++) { |
102 | if (*str == '\\') { |
103 | str++; |
104 | putchar(bb_process_escape_sequence((const char **)&str)); |
105 | } else { |
106 | putchar(*str); |
107 | } |
108 | |
109 | } |
110 | } |
111 | |
112 | int printf_main(int argc, char **argv) |
113 | { |
114 | char *format; |
115 | int args_used; |
116 | |
117 | if (argc <= 1 || argv[1][0] == '-') { |
118 | bb_show_usage(); |
119 | } |
120 | |
121 | format = argv[1]; |
122 | argc -= 2; |
123 | argv += 2; |
124 | |
125 | do { |
126 | args_used = print_formatted(format, argc, argv); |
127 | argc -= args_used; |
128 | argv += args_used; |
129 | } |
130 | while (args_used > 0 && argc > 0); |
131 | |
132 | /* if (argc > 0) |
133 | fprintf(stderr, "excess args ignored"); |
134 | */ |
135 | |
136 | return EXIT_SUCCESS; |
137 | } |
138 | |
139 | /* Print the text in FORMAT, using ARGV (with ARGC elements) for |
140 | arguments to any '%' directives. |
141 | Return the number of elements of ARGV used. */ |
142 | |
143 | static int print_formatted(char *format, int argc, char **argv) |
144 | { |
145 | int save_argc = argc; /* Preserve original value. */ |
146 | char *f; /* Pointer into 'format'. */ |
147 | char *direc_start; /* Start of % directive. */ |
148 | size_t direc_length; /* Length of % directive. */ |
149 | int field_width; /* Arg to first '*', or -1 if none. */ |
150 | int precision; /* Arg to second '*', or -1 if none. */ |
151 | |
152 | for (f = format; *f; ++f) { |
153 | switch (*f) { |
154 | case '%': |
155 | direc_start = f++; |
156 | direc_length = 1; |
157 | field_width = precision = -1; |
158 | if (*f == '%') { |
159 | putchar('%'); |
160 | break; |
161 | } |
162 | if (*f == 'b') { |
163 | if (argc > 0) { |
164 | print_esc_string(*argv); |
165 | ++argv; |
166 | --argc; |
167 | } |
168 | break; |
169 | } |
170 | if (strchr("-+ #", *f)) { |
171 | ++f; |
172 | ++direc_length; |
173 | } |
174 | if (*f == '*') { |
175 | ++f; |
176 | ++direc_length; |
177 | if (argc > 0) { |
178 | field_width = my_xstrtoul(*argv); |
179 | ++argv; |
180 | --argc; |
181 | } else |
182 | field_width = 0; |
183 | } else |
184 | while (isdigit(*f)) { |
185 | ++f; |
186 | ++direc_length; |
187 | } |
188 | if (*f == '.') { |
189 | ++f; |
190 | ++direc_length; |
191 | if (*f == '*') { |
192 | ++f; |
193 | ++direc_length; |
194 | if (argc > 0) { |
195 | precision = my_xstrtoul(*argv); |
196 | ++argv; |
197 | --argc; |
198 | } else |
199 | precision = 0; |
200 | } else |
201 | while (isdigit(*f)) { |
202 | ++f; |
203 | ++direc_length; |
204 | } |
205 | } |
206 | if (*f == 'l' || *f == 'L' || *f == 'h') { |
207 | ++f; |
208 | ++direc_length; |
209 | } |
210 | /* |
211 | if (!strchr ("diouxXfeEgGcs", *f)) |
212 | fprintf(stderr, "%%%c: invalid directive", *f); |
213 | */ |
214 | ++direc_length; |
215 | if (argc > 0) { |
216 | print_direc(direc_start, direc_length, field_width, |
217 | precision, *argv); |
218 | ++argv; |
219 | --argc; |
220 | } else |
221 | print_direc(direc_start, direc_length, field_width, |
222 | precision, ""); |
223 | break; |
224 | |
225 | case '\\': |
226 | if (*++f == 'c') |
227 | exit(0); |
228 | putchar(bb_process_escape_sequence((const char **)&f)); |
229 | f--; |
230 | break; |
231 | |
232 | default: |
233 | putchar(*f); |
234 | } |
235 | } |
236 | |
237 | return save_argc - argc; |
238 | } |
239 | |
240 | static void |
241 | print_direc(char *start, size_t length, int field_width, int precision, |
242 | char *argument) |
243 | { |
244 | char *p; /* Null-terminated copy of % directive. */ |
245 | |
246 | p = xmalloc((unsigned) (length + 1)); |
247 | strncpy(p, start, length); |
248 | p[length] = 0; |
249 | |
250 | switch (p[length - 1]) { |
251 | case 'd': |
252 | case 'i': |
253 | if (field_width < 0) { |
254 | if (precision < 0) |
255 | printf(p, my_xstrtol(argument)); |
256 | else |
257 | printf(p, precision, my_xstrtol(argument)); |
258 | } else { |
259 | if (precision < 0) |
260 | printf(p, field_width, my_xstrtol(argument)); |
261 | else |
262 | printf(p, field_width, precision, my_xstrtol(argument)); |
263 | } |
264 | break; |
265 | |
266 | case 'o': |
267 | case 'u': |
268 | case 'x': |
269 | case 'X': |
270 | if (field_width < 0) { |
271 | if (precision < 0) |
272 | printf(p, my_xstrtoul(argument)); |
273 | else |
274 | printf(p, precision, my_xstrtoul(argument)); |
275 | } else { |
276 | if (precision < 0) |
277 | printf(p, field_width, my_xstrtoul(argument)); |
278 | else |
279 | printf(p, field_width, precision, my_xstrtoul(argument)); |
280 | } |
281 | break; |
282 | |
283 | case 'f': |
284 | case 'e': |
285 | case 'E': |
286 | case 'g': |
287 | case 'G': |
288 | if (field_width < 0) { |
289 | if (precision < 0) |
290 | printf(p, my_xstrtod(argument)); |
291 | else |
292 | printf(p, precision, my_xstrtod(argument)); |
293 | } else { |
294 | if (precision < 0) |
295 | printf(p, field_width, my_xstrtod(argument)); |
296 | else |
297 | printf(p, field_width, precision, my_xstrtod(argument)); |
298 | } |
299 | break; |
300 | |
301 | case 'c': |
302 | printf(p, *argument); |
303 | break; |
304 | |
305 | case 's': |
306 | if (field_width < 0) { |
307 | if (precision < 0) |
308 | printf(p, argument); |
309 | else |
310 | printf(p, precision, argument); |
311 | } else { |
312 | if (precision < 0) |
313 | printf(p, field_width, argument); |
314 | else |
315 | printf(p, field_width, precision, argument); |
316 | } |
317 | break; |
318 | } |
319 | |
320 | free(p); |
321 | } |