[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.27

1.27    ! martijn     1: /*     $OpenBSD: printf.c,v 1.26 2016/11/18 15:53:16 schwarze 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.
1.9       millert    15:  * 3. Neither the name of the University nor the names of its contributors
1.1       deraadt    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 <ctype.h>
1.26      schwarze   33: #include <err.h>
                     34: #include <errno.h>
                     35: #include <limits.h>
1.1       deraadt    36: #include <stdio.h>
                     37: #include <stdlib.h>
1.26      schwarze   38: #include <string.h>
1.23      deraadt    39: #include <unistd.h>
1.1       deraadt    40:
1.6       millert    41: static int      print_escape_str(const char *);
                     42: static int      print_escape(const char *);
1.1       deraadt    43:
1.6       millert    44: static int      getchr(void);
                     45: static double   getdouble(void);
                     46: static int      getint(void);
                     47: static long     getlong(void);
                     48: static unsigned long getulong(void);
                     49: static char    *getstr(void);
                     50: static char    *mklong(const char *, int);
                     51: static void      check_conversion(const char *, const char *);
1.26      schwarze   52: static void __dead usage(void);
1.1       deraadt    53:
                     54: static int     rval;
                     55: static char  **gargv;
                     56:
                     57: #define isodigit(c)    ((c) >= '0' && (c) <= '7')
                     58: #define octtobin(c)    ((c) - '0')
                     59: #define hextobin(c)    ((c) >= 'A' && (c) <= 'F' ? c - 'A' + 10 : (c) >= 'a' && (c) <= 'f' ? c - 'a' + 10 : c - '0')
                     60:
                     61: #define PF(f, func) { \
1.20      guenther   62:        if (havefieldwidth) \
                     63:                if (haveprecision) \
1.1       deraadt    64:                        (void)printf(f, fieldwidth, precision, func); \
                     65:                else \
                     66:                        (void)printf(f, fieldwidth, func); \
1.20      guenther   67:        else if (haveprecision) \
1.1       deraadt    68:                (void)printf(f, precision, func); \
                     69:        else \
                     70:                (void)printf(f, func); \
                     71: }
                     72:
                     73: int
1.10      deraadt    74: main(int argc, char *argv[])
1.1       deraadt    75: {
1.5       mpech      76:        char *fmt, *start;
1.20      guenther   77:        int havefieldwidth, haveprecision;
1.5       mpech      78:        int fieldwidth, precision;
1.1       deraadt    79:        char convch, nextch;
                     80:        char *format;
                     81:
1.24      deraadt    82:        if (pledge("stdio", NULL) == -1)
                     83:                err(1, "pledge");
1.13      millert    84:
                     85:        /* Need to accept/ignore "--" option. */
                     86:        if (argc > 1 && strcmp(argv[1], "--") == 0) {
                     87:                argc--;
                     88:                argv++;
                     89:        }
1.1       deraadt    90:
1.26      schwarze   91:        if (argc < 2)
1.1       deraadt    92:                usage();
                     93:
1.11      millert    94:        format = *++argv;
1.1       deraadt    95:        gargv = ++argv;
                     96:
                     97: #define SKIP1  "#-+ 0"
1.15      martynas   98: #define SKIP2  "0123456789"
1.1       deraadt    99:        do {
                    100:                /*
                    101:                 * Basic algorithm is to scan the format string for conversion
                    102:                 * specifications -- once one is found, find out if the field
                    103:                 * width or precision is a '*'; if it is, gather up value.
                    104:                 * Note, format strings are reused as necessary to use up the
                    105:                 * provided arguments, arguments of zero/null string are
                    106:                 * provided to use up the format string.
                    107:                 */
                    108:
                    109:                /* find next format specification */
                    110:                for (fmt = format; *fmt; fmt++) {
                    111:                        switch (*fmt) {
                    112:                        case '%':
                    113:                                start = fmt++;
                    114:
                    115:                                if (*fmt == '%') {
                    116:                                        putchar ('%');
                    117:                                        break;
                    118:                                } else if (*fmt == 'b') {
                    119:                                        char *p = getstr();
                    120:                                        if (print_escape_str(p)) {
                    121:                                                return (rval);
                    122:                                        }
                    123:                                        break;
                    124:                                }
                    125:
                    126:                                /* skip to field width */
1.15      martynas  127:                                for (; strchr(SKIP1, *fmt); ++fmt)
                    128:                                        ;
                    129:                                if (*fmt == '*') {
                    130:                                        ++fmt;
1.20      guenther  131:                                        havefieldwidth = 1;
1.15      martynas  132:                                        fieldwidth = getint();
                    133:                                } else
1.20      guenther  134:                                        havefieldwidth = 0;
1.15      martynas  135:
                    136:                                /* skip to field precision */
                    137:                                for (; strchr(SKIP2, *fmt); ++fmt)
                    138:                                        ;
1.20      guenther  139:                                haveprecision = 0;
1.15      martynas  140:                                if (*fmt == '.') {
1.1       deraadt   141:                                        ++fmt;
1.15      martynas  142:                                        if (*fmt == '*') {
                    143:                                                ++fmt;
1.20      guenther  144:                                                haveprecision = 1;
1.15      martynas  145:                                                precision = getint();
                    146:                                        }
                    147:                                        for (; strchr(SKIP2, *fmt); ++fmt)
                    148:                                                ;
                    149:                                }
1.1       deraadt   150:
                    151:                                if (!*fmt) {
                    152:                                        warnx ("missing format character");
                    153:                                        return(1);
                    154:                                }
                    155:
                    156:                                convch = *fmt;
                    157:                                nextch = *(fmt + 1);
                    158:                                *(fmt + 1) = '\0';
                    159:                                switch(convch) {
                    160:                                case 'c': {
                    161:                                        char p = getchr();
                    162:                                        PF(start, p);
                    163:                                        break;
                    164:                                }
                    165:                                case 's': {
                    166:                                        char *p = getstr();
                    167:                                        PF(start, p);
                    168:                                        break;
                    169:                                }
                    170:                                case 'd':
                    171:                                case 'i': {
1.4       deraadt   172:                                        long p;
1.1       deraadt   173:                                        char *f = mklong(start, convch);
1.4       deraadt   174:                                        if (!f) {
                    175:                                                warnx("out of memory");
                    176:                                                return (1);
                    177:                                        }
                    178:                                        p = getlong();
1.1       deraadt   179:                                        PF(f, p);
                    180:                                        break;
                    181:                                }
                    182:                                case 'o':
                    183:                                case 'u':
                    184:                                case 'x':
                    185:                                case 'X': {
1.4       deraadt   186:                                        unsigned long p;
1.1       deraadt   187:                                        char *f = mklong(start, convch);
1.4       deraadt   188:                                        if (!f) {
                    189:                                                warnx("out of memory");
                    190:                                                return (1);
                    191:                                        }
                    192:                                        p = getulong();
1.1       deraadt   193:                                        PF(f, p);
                    194:                                        break;
                    195:                                }
1.14      martynas  196:                                case 'a':
                    197:                                case 'A':
1.1       deraadt   198:                                case 'e':
                    199:                                case 'E':
                    200:                                case 'f':
1.14      martynas  201:                                case 'F':
1.1       deraadt   202:                                case 'g':
                    203:                                case 'G': {
                    204:                                        double p = getdouble();
                    205:                                        PF(start, p);
                    206:                                        break;
                    207:                                }
                    208:                                default:
                    209:                                        warnx ("%s: invalid directive", start);
                    210:                                        return(1);
                    211:                                }
                    212:                                *(fmt + 1) = nextch;
                    213:                                break;
                    214:
                    215:                        case '\\':
                    216:                                fmt += print_escape(fmt);
                    217:                                break;
                    218:
                    219:                        default:
                    220:                                putchar (*fmt);
                    221:                                break;
                    222:                        }
                    223:                }
                    224:        } while (gargv > argv && *gargv);
                    225:
                    226:        return (rval);
                    227: }
                    228:
                    229:
                    230: /*
                    231:  * Print SysV echo(1) style escape string
                    232:  *     Halts processing string and returns 1 if a \c escape is encountered.
                    233:  */
                    234: static int
1.10      deraadt   235: print_escape_str(const char *str)
1.1       deraadt   236: {
                    237:        int value;
                    238:        int c;
                    239:
                    240:        while (*str) {
                    241:                if (*str == '\\') {
                    242:                        str++;
                    243:                        /*
                    244:                         * %b string octal constants are not like those in C.
                    245:                         * They start with a \0, and are followed by 0, 1, 2,
                    246:                         * or 3 octal digits.
                    247:                         */
                    248:                        if (*str == '0') {
                    249:                                str++;
                    250:                                for (c = 3, value = 0; c-- && isodigit(*str); str++) {
                    251:                                        value <<= 3;
                    252:                                        value += octtobin(*str);
                    253:                                }
                    254:                                putchar (value);
                    255:                                str--;
                    256:                        } else if (*str == 'c') {
                    257:                                return 1;
                    258:                        } else {
                    259:                                str--;
                    260:                                str += print_escape(str);
                    261:                        }
                    262:                } else {
                    263:                        putchar (*str);
                    264:                }
                    265:                str++;
                    266:        }
                    267:
                    268:        return 0;
                    269: }
                    270:
                    271: /*
                    272:  * Print "standard" escape characters
                    273:  */
                    274: static int
1.10      deraadt   275: print_escape(const char *str)
1.1       deraadt   276: {
                    277:        const char *start = str;
1.27    ! martijn   278:        int value = 0;
1.1       deraadt   279:        int c;
                    280:
                    281:        str++;
                    282:
                    283:        switch (*str) {
                    284:        case '0': case '1': case '2': case '3':
                    285:        case '4': case '5': case '6': case '7':
1.27    ! martijn   286:                for (c = 3; c-- && isodigit(*str); str++) {
1.1       deraadt   287:                        value <<= 3;
                    288:                        value += octtobin(*str);
                    289:                }
                    290:                putchar(value);
                    291:                return str - start - 1;
                    292:                /* NOTREACHED */
                    293:
                    294:        case 'x':
                    295:                str++;
1.27    ! martijn   296:                for (c = 2; c-- && isxdigit((unsigned char)*str); str++) {
1.1       deraadt   297:                        value <<= 4;
                    298:                        value += hextobin(*str);
                    299:                }
                    300:                putchar (value);
                    301:                return str - start - 1;
                    302:                /* NOTREACHED */
                    303:
                    304:        case '\\':                      /* backslash */
                    305:                putchar('\\');
                    306:                break;
                    307:
                    308:        case '\'':                      /* single quote */
                    309:                putchar('\'');
                    310:                break;
                    311:
                    312:        case '"':                       /* double quote */
                    313:                putchar('"');
                    314:                break;
                    315:
                    316:        case 'a':                       /* alert */
                    317:                putchar('\a');
                    318:                break;
                    319:
                    320:        case 'b':                       /* backspace */
                    321:                putchar('\b');
                    322:                break;
                    323:
                    324:        case 'e':                       /* escape */
                    325: #ifdef __GNUC__
                    326:                putchar('\e');
                    327: #else
                    328:                putchar(033);
                    329: #endif
                    330:                break;
                    331:
                    332:        case 'f':                       /* form-feed */
                    333:                putchar('\f');
                    334:                break;
                    335:
                    336:        case 'n':                       /* newline */
                    337:                putchar('\n');
                    338:                break;
                    339:
                    340:        case 'r':                       /* carriage-return */
                    341:                putchar('\r');
                    342:                break;
                    343:
                    344:        case 't':                       /* tab */
                    345:                putchar('\t');
                    346:                break;
                    347:
                    348:        case 'v':                       /* vertical-tab */
                    349:                putchar('\v');
                    350:                break;
1.18      guenther  351:
                    352:        case '\0':
                    353:                warnx("null escape sequence");
                    354:                rval = 1;
                    355:                return 0;
1.1       deraadt   356:
                    357:        default:
                    358:                putchar(*str);
                    359:                warnx("unknown escape sequence `\\%c'", *str);
                    360:                rval = 1;
                    361:        }
                    362:
                    363:        return 1;
                    364: }
                    365:
                    366: static char *
1.10      deraadt   367: mklong(const char *str, int ch)
1.1       deraadt   368: {
1.4       deraadt   369:        static char *copy;
                    370:        static int copysize;
1.1       deraadt   371:        int len;
                    372:
                    373:        len = strlen(str) + 2;
1.4       deraadt   374:        if (copysize < len) {
                    375:                char *newcopy;
                    376:                copysize = len + 256;
                    377:
                    378:                newcopy = realloc(copy, copysize);
                    379:                if (newcopy == NULL) {
                    380:                        copysize = 0;
                    381:                        free(copy);
                    382:                        copy = NULL;
                    383:                        return (NULL);
                    384:                }
                    385:                copy = newcopy;
                    386:        }
1.1       deraadt   387:        (void) memmove(copy, str, len - 3);
                    388:        copy[len - 3] = 'l';
                    389:        copy[len - 2] = ch;
                    390:        copy[len - 1] = '\0';
                    391:        return (copy);
                    392: }
                    393:
                    394: static int
1.10      deraadt   395: getchr(void)
1.1       deraadt   396: {
                    397:        if (!*gargv)
                    398:                return((int)'\0');
                    399:        return((int)**gargv++);
                    400: }
                    401:
                    402: static char *
1.10      deraadt   403: getstr(void)
1.1       deraadt   404: {
                    405:        if (!*gargv)
                    406:                return("");
                    407:        return(*gargv++);
                    408: }
                    409:
                    410: static char *number = "+-.0123456789";
                    411: static int
1.10      deraadt   412: getint(void)
1.1       deraadt   413: {
                    414:        if (!*gargv)
                    415:                return(0);
                    416:
1.3       millert   417:        if (strchr(number, **gargv))
1.1       deraadt   418:                return(atoi(*gargv++));
                    419:
                    420:        return 0;
                    421: }
                    422:
                    423: static long
1.10      deraadt   424: getlong(void)
1.1       deraadt   425: {
                    426:        long val;
                    427:        char *ep;
                    428:
                    429:        if (!*gargv)
                    430:                return(0L);
                    431:
                    432:        if (**gargv == '\"' || **gargv == '\'')
1.25      tedu      433:                return (unsigned char) *((*gargv++)+1);
1.1       deraadt   434:
                    435:        errno = 0;
                    436:        val = strtol (*gargv, &ep, 0);
                    437:        check_conversion(*gargv++, ep);
                    438:        return val;
                    439: }
                    440:
                    441: static unsigned long
1.10      deraadt   442: getulong(void)
1.1       deraadt   443: {
                    444:        unsigned long val;
                    445:        char *ep;
                    446:
                    447:        if (!*gargv)
                    448:                return(0UL);
                    449:
                    450:        if (**gargv == '\"' || **gargv == '\'')
1.25      tedu      451:                return (unsigned char) *((*gargv++)+1);
1.1       deraadt   452:
                    453:        errno = 0;
                    454:        val = strtoul (*gargv, &ep, 0);
                    455:        check_conversion(*gargv++, ep);
                    456:        return val;
                    457: }
                    458:
                    459: static double
1.10      deraadt   460: getdouble(void)
1.1       deraadt   461: {
                    462:        double val;
                    463:        char *ep;
                    464:
                    465:        if (!*gargv)
                    466:                return(0.0);
                    467:
                    468:        if (**gargv == '\"' || **gargv == '\'')
1.25      tedu      469:                return (unsigned char) *((*gargv++)+1);
1.1       deraadt   470:
                    471:        errno = 0;
                    472:        val = strtod (*gargv, &ep);
                    473:        check_conversion(*gargv++, ep);
                    474:        return val;
                    475: }
                    476:
                    477: static void
1.10      deraadt   478: check_conversion(const char *s, const char *ep)
1.1       deraadt   479: {
                    480:        if (*ep) {
                    481:                if (ep == s)
                    482:                        warnx ("%s: expected numeric value", s);
                    483:                else
                    484:                        warnx ("%s: not completely converted", s);
                    485:                rval = 1;
                    486:        } else if (errno == ERANGE) {
1.21      guenther  487:                warnc(ERANGE, "%s", s);
1.1       deraadt   488:                rval = 1;
                    489:        }
                    490: }
                    491:
1.26      schwarze  492: static void __dead
1.10      deraadt   493: usage(void)
1.1       deraadt   494: {
1.22      jmc       495:        (void)fprintf(stderr, "usage: printf format [argument ...]\n");
1.26      schwarze  496:        exit(1);
1.1       deraadt   497: }