Magellan Linux

Annotation of /trunk/mkinitrd-magellan/klibc/usr/dash/bltin/printf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 815 - (hide annotations) (download)
Fri Apr 24 18:32:46 2009 UTC (15 years ago) by niro
File MIME type: text/plain
File size: 9111 byte(s)
-updated to klibc-1.5.15
1 niro 532 /*
2     * Copyright (c) 1989, 1993
3     * The Regents of the University of California. All rights reserved.
4     * Copyright (c) 1997-2005
5     * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
6     *
7     * Redistribution and use in source and binary forms, with or without
8     * modification, are permitted provided that the following conditions
9     * are met:
10     * 1. Redistributions of source code must retain the above copyright
11     * notice, this list of conditions and the following disclaimer.
12     * 2. Redistributions in binary form must reproduce the above copyright
13     * notice, this list of conditions and the following disclaimer in the
14     * documentation and/or other materials provided with the distribution.
15     * 3. Neither the name of the University nor the names of its contributors
16     * may be used to endorse or promote products derived from this software
17     * without specific prior written permission.
18     *
19     * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22     * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29     * SUCH DAMAGE.
30     */
31    
32     #include <sys/types.h>
33    
34     #include <ctype.h>
35     #include <errno.h>
36     #include <inttypes.h>
37     #include <limits.h>
38     #include <stdarg.h>
39     #include <stdlib.h>
40     #include <string.h>
41     #include <unistd.h>
42    
43 niro 815 static int conv_escape_str(char *);
44 niro 532 static char *conv_escape(char *, int *);
45     static int getchr(void);
46     static intmax_t getintmax(void);
47     static uintmax_t getuintmax(void);
48     static char *getstr(void);
49     static char *mklong(const char *, const char *);
50     static void check_conversion(const char *, const char *);
51     #ifdef HAVE_STRTOD
52     static double getdouble(void);
53     #endif
54    
55     static int rval;
56     static char **gargv;
57    
58     #define isodigit(c) ((c) >= '0' && (c) <= '7')
59     #define octtobin(c) ((c) - '0')
60    
61     #include "bltin.h"
62     #include "system.h"
63    
64     #define PF(f, func) { \
65     switch ((char *)param - (char *)array) { \
66     default: \
67     (void)printf(f, array[0], array[1], func); \
68     break; \
69     case sizeof(*param): \
70     (void)printf(f, array[0], func); \
71     break; \
72     case 0: \
73     (void)printf(f, func); \
74     break; \
75     } \
76     }
77    
78     int printfcmd(int argc, char *argv[])
79     {
80     char *fmt;
81     char *format;
82     int ch;
83    
84     rval = 0;
85    
86     nextopt(nullstr);
87    
88     argv = argptr;
89     format = *argv;
90    
91     if (!format) {
92     warnx("usage: printf format [arg ...]");
93     goto err;
94     }
95    
96     gargv = ++argv;
97    
98     #define SKIP1 "#-+ 0"
99     #define SKIP2 "*0123456789"
100     do {
101     /*
102     * Basic algorithm is to scan the format string for conversion
103     * specifications -- once one is found, find out if the field
104     * width or precision is a '*'; if it is, gather up value.
105     * Note, format strings are reused as necessary to use up the
106     * provided arguments, arguments of zero/null string are
107     * provided to use up the format string.
108     */
109    
110     /* find next format specification */
111     for (fmt = format; (ch = *fmt++) ;) {
112     char *start;
113     char nextch;
114     int array[2];
115     int *param;
116    
117     if (ch == '\\') {
118     int c_ch;
119     fmt = conv_escape(fmt, &c_ch);
120     ch = c_ch;
121     goto pc;
122     }
123     if (ch != '%' || (*fmt == '%' && (++fmt || 1))) {
124     pc:
125     putchar(ch);
126     continue;
127     }
128    
129     /* Ok - we've found a format specification,
130     Save its address for a later printf(). */
131     start = fmt - 1;
132     param = array;
133    
134     /* skip to field width */
135     fmt += strspn(fmt, SKIP1);
136     if (*fmt == '*')
137     *param++ = getintmax();
138    
139     /* skip to possible '.', get following precision */
140     fmt += strspn(fmt, SKIP2);
141     if (*fmt == '.')
142     ++fmt;
143     if (*fmt == '*')
144     *param++ = getintmax();
145    
146     fmt += strspn(fmt, SKIP2);
147    
148     ch = *fmt;
149     if (!ch) {
150     warnx("missing format character");
151     goto err;
152     }
153     /* null terminate format string to we can use it
154     as an argument to printf. */
155     nextch = fmt[1];
156     fmt[1] = 0;
157     switch (ch) {
158    
159     case 'b': {
160 niro 815 int done = conv_escape_str(getstr());
161     char *p = stackblock();
162 niro 532 *fmt = 's';
163     PF(start, p);
164     /* escape if a \c was encountered */
165 niro 815 if (done)
166 niro 532 goto out;
167     *fmt = 'b';
168     break;
169     }
170     case 'c': {
171     int p = getchr();
172     PF(start, p);
173     break;
174     }
175     case 's': {
176     char *p = getstr();
177     PF(start, p);
178     break;
179     }
180     case 'd':
181     case 'i': {
182     intmax_t p = getintmax();
183     char *f = mklong(start, fmt);
184     PF(f, p);
185     break;
186     }
187     case 'o':
188     case 'u':
189     case 'x':
190     case 'X': {
191     uintmax_t p = getuintmax();
192     char *f = mklong(start, fmt);
193     PF(f, p);
194     break;
195     }
196     #ifdef HAVE_STRTOD
197     case 'e':
198     case 'E':
199     case 'f':
200     case 'g':
201     case 'G': {
202     double p = getdouble();
203     PF(start, p);
204     break;
205     }
206     #endif
207     default:
208     warnx("%s: invalid directive", start);
209     goto err;
210     }
211     *++fmt = nextch;
212     }
213     } while (gargv != argv && *gargv);
214    
215     out:
216 niro 815 return rval;
217 niro 532 err:
218     return 1;
219     }
220    
221    
222     /*
223     * Print SysV echo(1) style escape string
224     * Halts processing string if a \c escape is encountered.
225     */
226 niro 815 static int
227 niro 532 conv_escape_str(char *str)
228     {
229     int ch;
230     char *cp;
231    
232     /* convert string into a temporary buffer... */
233     STARTSTACKSTR(cp);
234    
235     do {
236     int c;
237    
238     ch = *str++;
239     if (ch != '\\')
240     continue;
241    
242     ch = *str++;
243     if (ch == 'c') {
244     /* \c as in SYSV echo - abort all processing.... */
245 niro 815 ch = 0x100;
246 niro 532 continue;
247     }
248    
249     /*
250     * %b string octal constants are not like those in C.
251     * They start with a \0, and are followed by 0, 1, 2,
252     * or 3 octal digits.
253     */
254     if (ch == '0') {
255     unsigned char i;
256     i = 3;
257     ch = 0;
258     do {
259     unsigned k = octtobin(*str);
260     if (k > 7)
261     break;
262     str++;
263     ch <<= 3;
264     ch += k;
265     } while (--i);
266     continue;
267     }
268    
269     /* Finally test for sequences valid in the format string */
270     str = conv_escape(str - 1, &c);
271     ch = c;
272 niro 815 } while (STPUTC(ch, cp), (char)ch);
273 niro 532
274 niro 815 return ch;
275 niro 532 }
276    
277     /*
278     * Print "standard" escape characters
279     */
280     static char *
281     conv_escape(char *str, int *conv_ch)
282     {
283     int value;
284     int ch;
285    
286     ch = *str;
287    
288     switch (ch) {
289     default:
290     case 0:
291     value = '\\';
292     goto out;
293    
294     case '0': case '1': case '2': case '3':
295     case '4': case '5': case '6': case '7':
296     ch = 3;
297     value = 0;
298     do {
299     value <<= 3;
300     value += octtobin(*str++);
301     } while (isodigit(*str) && --ch);
302     goto out;
303    
304     case '\\': value = '\\'; break; /* backslash */
305     case 'a': value = '\a'; break; /* alert */
306     case 'b': value = '\b'; break; /* backspace */
307     case 'f': value = '\f'; break; /* form-feed */
308     case 'n': value = '\n'; break; /* newline */
309     case 'r': value = '\r'; break; /* carriage-return */
310     case 't': value = '\t'; break; /* tab */
311     case 'v': value = '\v'; break; /* vertical-tab */
312     }
313    
314     str++;
315     out:
316     *conv_ch = value;
317     return str;
318     }
319    
320     static char *
321     mklong(const char *str, const char *ch)
322     {
323     char *copy;
324     size_t len;
325    
326     len = ch - str + 3;
327     STARTSTACKSTR(copy);
328     copy = makestrspace(len, copy);
329     memcpy(copy, str, len - 3);
330     copy[len - 3] = 'j';
331     copy[len - 2] = *ch;
332     copy[len - 1] = '\0';
333     return (copy);
334     }
335    
336     static int
337     getchr(void)
338     {
339     int val = 0;
340    
341     if (*gargv)
342     val = **gargv++;
343     return val;
344     }
345    
346     static char *
347     getstr(void)
348     {
349     char *val = nullstr;
350    
351     if (*gargv)
352     val = *gargv++;
353     return val;
354     }
355    
356     static intmax_t
357     getintmax(void)
358     {
359     intmax_t val = 0;
360     char *cp, *ep;
361    
362     cp = *gargv;
363     if (cp == NULL)
364     goto out;
365     gargv++;
366    
367     val = (unsigned char) cp[1];
368     if (*cp == '\"' || *cp == '\'')
369     goto out;
370    
371     errno = 0;
372     val = strtoimax(cp, &ep, 0);
373     check_conversion(cp, ep);
374     out:
375     return val;
376     }
377    
378     static uintmax_t
379     getuintmax(void)
380     {
381     uintmax_t val = 0;
382     char *cp, *ep;
383    
384     cp = *gargv;
385     if (cp == NULL)
386     goto out;
387     gargv++;
388    
389     val = (unsigned char) cp[1];
390     if (*cp == '\"' || *cp == '\'')
391     goto out;
392    
393     errno = 0;
394     val = strtoumax(cp, &ep, 0);
395     check_conversion(cp, ep);
396     out:
397     return val;
398     }
399    
400     #ifdef HAVE_STRTOD
401     static double
402     getdouble(void)
403     {
404     double val;
405     char *cp, *ep;
406    
407     cp = *gargv;
408     if (cp == NULL)
409     return 0;
410     gargv++;
411    
412     if (*cp == '\"' || *cp == '\'')
413     return (unsigned char) cp[1];
414    
415     errno = 0;
416     val = strtod(cp, &ep);
417     check_conversion(cp, ep);
418     return val;
419     }
420     #endif
421    
422     static void
423     check_conversion(const char *s, const char *ep)
424     {
425     if (*ep) {
426     if (ep == s)
427     warnx("%s: expected numeric value", s);
428     else
429     warnx("%s: not completely converted", s);
430     rval = 1;
431     } else if (errno == ERANGE) {
432     warnx("%s: %s", s, strerror(ERANGE));
433     rval = 1;
434     }
435     }
436    
437     int
438     echocmd(int argc, char **argv)
439     {
440     int nonl = 0;
441     struct output *outs = out1;
442    
443     if (!*++argv)
444     goto end;
445     if (equal(*argv, "-n")) {
446     nonl = ~nonl;
447     if (!*++argv)
448     goto end;
449     }
450    
451     do {
452     char c;
453    
454 niro 815 nonl += conv_escape_str(*argv);
455     outstr(stackblock(), outs);
456     if (nonl > 0)
457     break;
458 niro 532
459     c = ' ';
460     if (!*++argv) {
461     end:
462     if (nonl) {
463     break;
464     }
465     c = '\n';
466     }
467     outc(c, outs);
468     } while (*argv);
469     return 0;
470     }