[BACK]Return to printf.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / printf

Annotation of src/usr.bin/printf/printf.c, Revision 1.5

1.5     ! mpech       1: /*     $OpenBSD: printf.c,v 1.4 2000/12/22 22:53:10 deraadt Exp $      */
1.2       deraadt     2:
1.1       deraadt     3: /*
                      4:  * Copyright (c) 1989 The Regents of the University of California.
                      5:  * 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. All advertising materials mentioning features or use of this software
                     16:  *    must display the following acknowledgement:
                     17:  *     This product includes software developed by the University of
                     18:  *     California, Berkeley and its contributors.
                     19:  * 4. Neither the name of the University nor the names of its contributors
                     20:  *    may be used to endorse or promote products derived from this software
                     21:  *    without specific prior written permission.
                     22:  *
                     23:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     24:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     25:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     26:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     27:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     28:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     29:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     30:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     31:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     32:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     33:  * SUCH DAMAGE.
                     34:  */
                     35:
                     36: #ifndef lint
                     37: #if !defined(SHELL) && !defined(BUILTIN)
                     38: char copyright[] =
                     39: "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
                     40:  All rights reserved.\n";
                     41: #endif
                     42: #endif /* not lint */
                     43:
                     44: #ifndef lint
                     45: /*static char sccsid[] = "from: @(#)printf.c   5.9 (Berkeley) 6/1/90";*/
1.5     ! mpech      46: static char rcsid[] = "$OpenBSD: printf.c,v 1.4 2000/12/22 22:53:10 deraadt Exp $";
1.1       deraadt    47: #endif /* not lint */
                     48:
                     49: #include <ctype.h>
                     50: #include <stdio.h>
                     51: #include <stdlib.h>
                     52: #include <string.h>
                     53: #include <limits.h>
                     54: #include <locale.h>
                     55: #include <errno.h>
                     56: #include <err.h>
                     57:
                     58: static int      print_escape_str __P((const char *));
                     59: static int      print_escape __P((const char *));
                     60:
                     61: static int      getchr __P((void));
                     62: static double   getdouble __P((void));
                     63: static int      getint __P((void));
                     64: static long     getlong __P((void));
                     65: static unsigned long getulong __P ((void));
                     66: static char    *getstr __P((void));
                     67: static char    *mklong __P((const char *, int));
                     68: static void      check_conversion __P((const char *, const char *));
                     69: static void     usage __P((void));
                     70:
                     71: static int     rval;
                     72: static char  **gargv;
                     73:
                     74: #define isodigit(c)    ((c) >= '0' && (c) <= '7')
                     75: #define octtobin(c)    ((c) - '0')
                     76: #define hextobin(c)    ((c) >= 'A' && (c) <= 'F' ? c - 'A' + 10 : (c) >= 'a' && (c) <= 'f' ? c - 'a' + 10 : c - '0')
                     77:
                     78: #ifdef SHELL
                     79: #define main printfcmd
                     80: #include "../../bin/sh/bltin/bltin.h"
                     81:
                     82: #ifdef __STDC__
                     83: #include <stdarg.h>
                     84: #else
                     85: #include <vararg.h>
                     86: #endif
                     87:
                     88: static void
                     89: #ifdef __STDC__
                     90: warnx(const char *fmt, ...)
                     91: #else
                     92: warnx(fmt, va_alist)
                     93:        const char *fmt;
                     94:        va_dcl
                     95: #endif
                     96: {
                     97:
                     98:        char buf[64];
                     99:        va_list ap;
                    100:
                    101: #ifdef __STDC__
                    102:        va_start(ap, fmt);
                    103: #else
                    104:        va_start(ap);
                    105: #endif
                    106:        vsprintf(buf, fmt, ap);
                    107:        va_end(ap);
                    108:
                    109:        error(buf);
                    110: }
                    111: #endif /* SHELL */
                    112:
                    113: #define PF(f, func) { \
                    114:        if (fieldwidth) \
                    115:                if (precision) \
                    116:                        (void)printf(f, fieldwidth, precision, func); \
                    117:                else \
                    118:                        (void)printf(f, fieldwidth, func); \
                    119:        else if (precision) \
                    120:                (void)printf(f, precision, func); \
                    121:        else \
                    122:                (void)printf(f, func); \
                    123: }
                    124:
                    125: int
                    126: #ifdef BUILTIN
                    127: progprintf(argc, argv)
                    128: #else
                    129: main(argc, argv)
                    130: #endif
                    131:        int argc;
                    132:        char **argv;
                    133: {
1.5     ! mpech     134:        char *fmt, *start;
        !           135:        int fieldwidth, precision;
1.1       deraadt   136:        char convch, nextch;
                    137:        char *format;
                    138:        int ch;
                    139:
                    140: #if !defined(SHELL) && !defined(BUILTIN)
                    141:        setlocale (LC_ALL, "");
                    142: #endif
                    143:
                    144:        while ((ch = getopt(argc, argv, "")) != -1) {
                    145:                switch (ch) {
                    146:                case '?':
                    147:                default:
                    148:                        usage();
                    149:                        return (1);
                    150:                }
                    151:        }
                    152:        argc -= optind;
                    153:        argv += optind;
                    154:
                    155:        if (argc < 1) {
                    156:                usage();
                    157:                return (1);
                    158:        }
                    159:
                    160:        format = *argv;
                    161:        gargv = ++argv;
                    162:
                    163: #define SKIP1  "#-+ 0"
                    164: #define SKIP2  "*0123456789"
                    165:        do {
                    166:                /*
                    167:                 * Basic algorithm is to scan the format string for conversion
                    168:                 * specifications -- once one is found, find out if the field
                    169:                 * width or precision is a '*'; if it is, gather up value.
                    170:                 * Note, format strings are reused as necessary to use up the
                    171:                 * provided arguments, arguments of zero/null string are
                    172:                 * provided to use up the format string.
                    173:                 */
                    174:
                    175:                /* find next format specification */
                    176:                for (fmt = format; *fmt; fmt++) {
                    177:                        switch (*fmt) {
                    178:                        case '%':
                    179:                                start = fmt++;
                    180:
                    181:                                if (*fmt == '%') {
                    182:                                        putchar ('%');
                    183:                                        break;
                    184:                                } else if (*fmt == 'b') {
                    185:                                        char *p = getstr();
                    186:                                        if (print_escape_str(p)) {
                    187:                                                return (rval);
                    188:                                        }
                    189:                                        break;
                    190:                                }
                    191:
                    192:                                /* skip to field width */
1.3       millert   193:                                for (; strchr(SKIP1, *fmt); ++fmt) ;
1.1       deraadt   194:                                fieldwidth = *fmt == '*' ? getint() : 0;
                    195:
                    196:                                /* skip to possible '.', get following precision */
1.3       millert   197:                                for (; strchr(SKIP2, *fmt); ++fmt) ;
1.1       deraadt   198:                                if (*fmt == '.')
                    199:                                        ++fmt;
                    200:                                precision = *fmt == '*' ? getint() : 0;
                    201:
1.3       millert   202:                                for (; strchr(SKIP2, *fmt); ++fmt) ;
1.1       deraadt   203:                                if (!*fmt) {
                    204:                                        warnx ("missing format character");
                    205:                                        return(1);
                    206:                                }
                    207:
                    208:                                convch = *fmt;
                    209:                                nextch = *(fmt + 1);
                    210:                                *(fmt + 1) = '\0';
                    211:                                switch(convch) {
                    212:                                case 'c': {
                    213:                                        char p = getchr();
                    214:                                        PF(start, p);
                    215:                                        break;
                    216:                                }
                    217:                                case 's': {
                    218:                                        char *p = getstr();
                    219:                                        PF(start, p);
                    220:                                        break;
                    221:                                }
                    222:                                case 'd':
                    223:                                case 'i': {
1.4       deraadt   224:                                        long p;
1.1       deraadt   225:                                        char *f = mklong(start, convch);
1.4       deraadt   226:                                        if (!f) {
                    227:                                                warnx("out of memory");
                    228:                                                return (1);
                    229:                                        }
                    230:                                        p = getlong();
1.1       deraadt   231:                                        PF(f, p);
                    232:                                        break;
                    233:                                }
                    234:                                case 'o':
                    235:                                case 'u':
                    236:                                case 'x':
                    237:                                case 'X': {
1.4       deraadt   238:                                        unsigned long p;
1.1       deraadt   239:                                        char *f = mklong(start, convch);
1.4       deraadt   240:                                        if (!f) {
                    241:                                                warnx("out of memory");
                    242:                                                return (1);
                    243:                                        }
                    244:                                        p = getulong();
1.1       deraadt   245:                                        PF(f, p);
                    246:                                        break;
                    247:                                }
                    248:                                case 'e':
                    249:                                case 'E':
                    250:                                case 'f':
                    251:                                case 'g':
                    252:                                case 'G': {
                    253:                                        double p = getdouble();
                    254:                                        PF(start, p);
                    255:                                        break;
                    256:                                }
                    257:                                default:
                    258:                                        warnx ("%s: invalid directive", start);
                    259:                                        return(1);
                    260:                                }
                    261:                                *(fmt + 1) = nextch;
                    262:                                break;
                    263:
                    264:                        case '\\':
                    265:                                fmt += print_escape(fmt);
                    266:                                break;
                    267:
                    268:                        default:
                    269:                                putchar (*fmt);
                    270:                                break;
                    271:                        }
                    272:                }
                    273:        } while (gargv > argv && *gargv);
                    274:
                    275:        return (rval);
                    276: }
                    277:
                    278:
                    279: /*
                    280:  * Print SysV echo(1) style escape string
                    281:  *     Halts processing string and returns 1 if a \c escape is encountered.
                    282:  */
                    283: static int
                    284: print_escape_str(str)
1.5     ! mpech     285:        const char *str;
1.1       deraadt   286: {
                    287:        int value;
                    288:        int c;
                    289:
                    290:        while (*str) {
                    291:                if (*str == '\\') {
                    292:                        str++;
                    293:                        /*
                    294:                         * %b string octal constants are not like those in C.
                    295:                         * They start with a \0, and are followed by 0, 1, 2,
                    296:                         * or 3 octal digits.
                    297:                         */
                    298:                        if (*str == '0') {
                    299:                                str++;
                    300:                                for (c = 3, value = 0; c-- && isodigit(*str); str++) {
                    301:                                        value <<= 3;
                    302:                                        value += octtobin(*str);
                    303:                                }
                    304:                                putchar (value);
                    305:                                str--;
                    306:                        } else if (*str == 'c') {
                    307:                                return 1;
                    308:                        } else {
                    309:                                str--;
                    310:                                str += print_escape(str);
                    311:                        }
                    312:                } else {
                    313:                        putchar (*str);
                    314:                }
                    315:                str++;
                    316:        }
                    317:
                    318:        return 0;
                    319: }
                    320:
                    321: /*
                    322:  * Print "standard" escape characters
                    323:  */
                    324: static int
                    325: print_escape(str)
1.5     ! mpech     326:        const char *str;
1.1       deraadt   327: {
                    328:        const char *start = str;
                    329:        int value;
                    330:        int c;
                    331:
                    332:        str++;
                    333:
                    334:        switch (*str) {
                    335:        case '0': case '1': case '2': case '3':
                    336:        case '4': case '5': case '6': case '7':
                    337:                for (c = 3, value = 0; c-- && isodigit(*str); str++) {
                    338:                        value <<= 3;
                    339:                        value += octtobin(*str);
                    340:                }
                    341:                putchar(value);
                    342:                return str - start - 1;
                    343:                /* NOTREACHED */
                    344:
                    345:        case 'x':
                    346:                str++;
                    347:                for (value = 0; isxdigit(*str); str++) {
                    348:                        value <<= 4;
                    349:                        value += hextobin(*str);
                    350:                }
                    351:                if (value > UCHAR_MAX) {
                    352:                        warnx ("escape sequence out of range for character");
                    353:                        rval = 1;
                    354:                }
                    355:                putchar (value);
                    356:                return str - start - 1;
                    357:                /* NOTREACHED */
                    358:
                    359:        case '\\':                      /* backslash */
                    360:                putchar('\\');
                    361:                break;
                    362:
                    363:        case '\'':                      /* single quote */
                    364:                putchar('\'');
                    365:                break;
                    366:
                    367:        case '"':                       /* double quote */
                    368:                putchar('"');
                    369:                break;
                    370:
                    371:        case 'a':                       /* alert */
                    372: #ifdef __STDC__
                    373:                putchar('\a');
                    374: #else
                    375:                putchar(007);
                    376: #endif
                    377:                break;
                    378:
                    379:        case 'b':                       /* backspace */
                    380:                putchar('\b');
                    381:                break;
                    382:
                    383:        case 'e':                       /* escape */
                    384: #ifdef __GNUC__
                    385:                putchar('\e');
                    386: #else
                    387:                putchar(033);
                    388: #endif
                    389:                break;
                    390:
                    391:        case 'f':                       /* form-feed */
                    392:                putchar('\f');
                    393:                break;
                    394:
                    395:        case 'n':                       /* newline */
                    396:                putchar('\n');
                    397:                break;
                    398:
                    399:        case 'r':                       /* carriage-return */
                    400:                putchar('\r');
                    401:                break;
                    402:
                    403:        case 't':                       /* tab */
                    404:                putchar('\t');
                    405:                break;
                    406:
                    407:        case 'v':                       /* vertical-tab */
                    408:                putchar('\v');
                    409:                break;
                    410:
                    411:        default:
                    412:                putchar(*str);
                    413:                warnx("unknown escape sequence `\\%c'", *str);
                    414:                rval = 1;
                    415:        }
                    416:
                    417:        return 1;
                    418: }
                    419:
                    420: static char *
                    421: mklong(str, ch)
                    422:        const char *str;
                    423:        char ch;
                    424: {
1.4       deraadt   425:        static char *copy;
                    426:        static int copysize;
1.1       deraadt   427:        int len;
                    428:
                    429:        len = strlen(str) + 2;
1.4       deraadt   430:        if (copysize < len) {
                    431:                char *newcopy;
                    432:                copysize = len + 256;
                    433:
                    434:                newcopy = realloc(copy, copysize);
                    435:                if (newcopy == NULL) {
                    436:                        copysize = 0;
                    437:                        free(copy);
                    438:                        copy = NULL;
                    439:                        return (NULL);
                    440:                }
                    441:                copy = newcopy;
                    442:        }
1.1       deraadt   443:        (void) memmove(copy, str, len - 3);
                    444:        copy[len - 3] = 'l';
                    445:        copy[len - 2] = ch;
                    446:        copy[len - 1] = '\0';
                    447:        return (copy);
                    448: }
                    449:
                    450: static int
                    451: getchr()
                    452: {
                    453:        if (!*gargv)
                    454:                return((int)'\0');
                    455:        return((int)**gargv++);
                    456: }
                    457:
                    458: static char *
                    459: getstr()
                    460: {
                    461:        if (!*gargv)
                    462:                return("");
                    463:        return(*gargv++);
                    464: }
                    465:
                    466: static char *number = "+-.0123456789";
                    467: static int
                    468: getint()
                    469: {
                    470:        if (!*gargv)
                    471:                return(0);
                    472:
1.3       millert   473:        if (strchr(number, **gargv))
1.1       deraadt   474:                return(atoi(*gargv++));
                    475:
                    476:        return 0;
                    477: }
                    478:
                    479: static long
                    480: getlong()
                    481: {
                    482:        long val;
                    483:        char *ep;
                    484:
                    485:        if (!*gargv)
                    486:                return(0L);
                    487:
                    488:        if (**gargv == '\"' || **gargv == '\'')
                    489:                return (long) *((*gargv++)+1);
                    490:
                    491:        errno = 0;
                    492:        val = strtol (*gargv, &ep, 0);
                    493:        check_conversion(*gargv++, ep);
                    494:        return val;
                    495: }
                    496:
                    497: static unsigned long
                    498: getulong()
                    499: {
                    500:        unsigned long val;
                    501:        char *ep;
                    502:
                    503:        if (!*gargv)
                    504:                return(0UL);
                    505:
                    506:        if (**gargv == '\"' || **gargv == '\'')
                    507:                return (unsigned long) *((*gargv++)+1);
                    508:
                    509:        errno = 0;
                    510:        val = strtoul (*gargv, &ep, 0);
                    511:        check_conversion(*gargv++, ep);
                    512:        return val;
                    513: }
                    514:
                    515: static double
                    516: getdouble()
                    517: {
                    518:        double val;
                    519:        char *ep;
                    520:
                    521:        if (!*gargv)
                    522:                return(0.0);
                    523:
                    524:        if (**gargv == '\"' || **gargv == '\'')
                    525:                return (double) *((*gargv++)+1);
                    526:
                    527:        errno = 0;
                    528:        val = strtod (*gargv, &ep);
                    529:        check_conversion(*gargv++, ep);
                    530:        return val;
                    531: }
                    532:
                    533: static void
                    534: check_conversion(s, ep)
                    535:        const char *s;
                    536:        const char *ep;
                    537: {
                    538:        if (*ep) {
                    539:                if (ep == s)
                    540:                        warnx ("%s: expected numeric value", s);
                    541:                else
                    542:                        warnx ("%s: not completely converted", s);
                    543:                rval = 1;
                    544:        } else if (errno == ERANGE) {
                    545:                warnx ("%s: %s", s, strerror(ERANGE));
                    546:                rval = 1;
                    547:        }
                    548: }
                    549:
                    550: static void
                    551: usage()
                    552: {
                    553:        (void)fprintf(stderr, "usage: printf format [arg ...]\n");
                    554: }