source: branches/2.2.2/mindi-busybox/coreutils/printf.c @ 1247

Last change on this file since 1247 was 821, checked in by Bruno Cornec, 14 years ago

Addition of busybox 1.2.1 as a mindi-busybox new package
This should avoid delivering binary files in mindi not built there (Fedora and Debian are quite serious about that)

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