source: MondoRescue/branches/2.2.5/mindi-busybox/coreutils/printf.c@ 1765

Last change on this file since 1765 was 1765, checked in by Bruno Cornec, 16 years ago

Update to busybox 1.7.2

File size: 6.5 KB
Line 
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 "libbb.h"
42
43typedef void (*converter)(const char *arg, void *result);
44
45static void multiconvert(const char *arg, void *result, converter convert)
46{
47 char s[sizeof(int)*3 + 2];
48
49 if (*arg == '"' || *arg == '\'') {
50 sprintf(s, "%d", (unsigned char)arg[1]);
51 arg = s;
52 }
53 convert(arg, result);
54 /* if there was conversion error, print unconverted string */
55 if (errno)
56 fputs(arg, stderr);
57}
58
59static void conv_strtoul(const char *arg, void *result)
60{
61 *(unsigned long*)result = bb_strtoul(arg, NULL, 0);
62}
63static void conv_strtol(const char *arg, void *result)
64{
65 *(long*)result = bb_strtol(arg, NULL, 0);
66}
67static void conv_strtod(const char *arg, void *result)
68{
69 char *end;
70 /* Well, this one allows leading whitespace... so what */
71 /* What I like much less is that "-" is accepted too! :( */
72 *(double*)result = strtod(arg, &end);
73 if (end[0]) errno = ERANGE;
74}
75
76static unsigned long my_xstrtoul(const char *arg)
77{
78 unsigned long result;
79 multiconvert(arg, &result, conv_strtoul);
80 return result;
81}
82
83static long my_xstrtol(const char *arg)
84{
85 long result;
86 multiconvert(arg, &result, conv_strtol);
87 return result;
88}
89
90static double my_xstrtod(const char *arg)
91{
92 double result;
93 multiconvert(arg, &result, conv_strtod);
94 return result;
95}
96
97static void print_esc_string(char *str)
98{
99 for (; *str; str++) {
100 if (*str == '\\') {
101 str++;
102 putchar(bb_process_escape_sequence((const char **)&str));
103 } else {
104 putchar(*str);
105 }
106
107 }
108}
109
110static void print_direc(char *start, size_t length, int field_width, int precision,
111 const char *argument)
112{
113 char *p; /* Null-terminated copy of % directive. */
114
115 p = xmalloc((unsigned) (length + 1));
116 strncpy(p, start, length);
117 p[length] = 0;
118
119 switch (p[length - 1]) {
120 case 'd':
121 case 'i':
122 if (field_width < 0) {
123 if (precision < 0)
124 printf(p, my_xstrtol(argument));
125 else
126 printf(p, precision, my_xstrtol(argument));
127 } else {
128 if (precision < 0)
129 printf(p, field_width, my_xstrtol(argument));
130 else
131 printf(p, field_width, precision, my_xstrtol(argument));
132 }
133 break;
134 case 'o':
135 case 'u':
136 case 'x':
137 case 'X':
138 if (field_width < 0) {
139 if (precision < 0)
140 printf(p, my_xstrtoul(argument));
141 else
142 printf(p, precision, my_xstrtoul(argument));
143 } else {
144 if (precision < 0)
145 printf(p, field_width, my_xstrtoul(argument));
146 else
147 printf(p, field_width, precision, my_xstrtoul(argument));
148 }
149 break;
150 case 'f':
151 case 'e':
152 case 'E':
153 case 'g':
154 case 'G':
155 if (field_width < 0) {
156 if (precision < 0)
157 printf(p, my_xstrtod(argument));
158 else
159 printf(p, precision, my_xstrtod(argument));
160 } else {
161 if (precision < 0)
162 printf(p, field_width, my_xstrtod(argument));
163 else
164 printf(p, field_width, precision, my_xstrtod(argument));
165 }
166 break;
167 case 'c':
168 printf(p, *argument);
169 break;
170 case 's':
171 if (field_width < 0) {
172 if (precision < 0)
173 printf(p, argument);
174 else
175 printf(p, precision, argument);
176 } else {
177 if (precision < 0)
178 printf(p, field_width, argument);
179 else
180 printf(p, field_width, precision, argument);
181 }
182 break;
183 }
184
185 free(p);
186}
187
188/* Print the text in FORMAT, using ARGV (with ARGC elements) for
189 arguments to any '%' directives.
190 Return the number of elements of ARGV used. */
191
192static int print_formatted(char *format, int argc, char **argv)
193{
194 int save_argc = argc; /* Preserve original value. */
195 char *f; /* Pointer into 'format'. */
196 char *direc_start; /* Start of % directive. */
197 size_t direc_length; /* Length of % directive. */
198 int field_width; /* Arg to first '*', or -1 if none. */
199 int precision; /* Arg to second '*', or -1 if none. */
200
201 for (f = format; *f; ++f) {
202 switch (*f) {
203 case '%':
204 direc_start = f++;
205 direc_length = 1;
206 field_width = precision = -1;
207 if (*f == '%') {
208 putchar('%');
209 break;
210 }
211 if (*f == 'b') {
212 if (argc > 0) {
213 print_esc_string(*argv);
214 ++argv;
215 --argc;
216 }
217 break;
218 }
219 if (strchr("-+ #", *f)) {
220 ++f;
221 ++direc_length;
222 }
223 if (*f == '*') {
224 ++f;
225 ++direc_length;
226 if (argc > 0) {
227 field_width = my_xstrtoul(*argv);
228 ++argv;
229 --argc;
230 } else
231 field_width = 0;
232 } else {
233 while (isdigit(*f)) {
234 ++f;
235 ++direc_length;
236 }
237 }
238 if (*f == '.') {
239 ++f;
240 ++direc_length;
241 if (*f == '*') {
242 ++f;
243 ++direc_length;
244 if (argc > 0) {
245 precision = my_xstrtoul(*argv);
246 ++argv;
247 --argc;
248 } else
249 precision = 0;
250 } else
251 while (isdigit(*f)) {
252 ++f;
253 ++direc_length;
254 }
255 }
256 if (*f == 'l' || *f == 'L' || *f == 'h') {
257 ++f;
258 ++direc_length;
259 }
260 /*
261 if (!strchr ("diouxXfeEgGcs", *f))
262 fprintf(stderr, "%%%c: invalid directive", *f);
263 */
264 ++direc_length;
265 if (argc > 0) {
266 print_direc(direc_start, direc_length, field_width,
267 precision, *argv);
268 ++argv;
269 --argc;
270 } else
271 print_direc(direc_start, direc_length, field_width,
272 precision, "");
273 break;
274 case '\\':
275 if (*++f == 'c')
276 exit(0);
277 putchar(bb_process_escape_sequence((const char **)&f));
278 f--;
279 break;
280 default:
281 putchar(*f);
282 }
283 }
284
285 return save_argc - argc;
286}
287
288int printf_main(int argc, char **argv);
289int printf_main(int argc, char **argv)
290{
291 char *format;
292 int args_used;
293
294 if (argc <= 1 || argv[1][0] == '-') {
295 bb_show_usage();
296 }
297
298 format = argv[1];
299 argc -= 2;
300 argv += 2;
301
302 do {
303 args_used = print_formatted(format, argc, argv);
304 argc -= args_used;
305 argv += args_used;
306 } while (args_used > 0 && argc > 0);
307
308/* if (argc > 0)
309 fprintf(stderr, "excess args ignored");
310*/
311
312 return EXIT_SUCCESS;
313}
Note: See TracBrowser for help on using the repository browser.