[BACK]Return to mdocml.c CVS log [TXT][DIR] Up to [cvsweb.bsd.lv] / mandoc

Annotation of mandoc/mdocml.c, Revision 1.36

1.36    ! kristaps    1: /* $Id: mdocml.c,v 1.35 2009/01/05 17:57:08 kristaps Exp $ */
1.1       kristaps    2: /*
                      3:  * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
                      4:  *
                      5:  * Permission to use, copy, modify, and distribute this software for any
                      6:  * purpose with or without fee is hereby granted, provided that the
                      7:  * above copyright notice and this permission notice appear in all
                      8:  * copies.
                      9:  *
                     10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
                     11:  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
                     12:  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
                     13:  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
                     14:  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
                     15:  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
                     16:  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
                     17:  * PERFORMANCE OF THIS SOFTWARE.
                     18:  */
1.21      kristaps   19: #include <sys/stat.h>
1.1       kristaps   20: #include <sys/param.h>
                     21:
                     22: #include <assert.h>
1.21      kristaps   23: #include <fcntl.h>
1.1       kristaps   24: #include <err.h>
                     25: #include <getopt.h>
                     26: #include <stdio.h>
                     27: #include <stdlib.h>
                     28: #include <string.h>
                     29: #include <unistd.h>
                     30:
1.21      kristaps   31: #include "mdoc.h"
1.1       kristaps   32:
1.21      kristaps   33: #define        MD_LINE_SZ      (256)
1.2       kristaps   34:
1.21      kristaps   35: struct md_parse {
                     36:        int              warn;
                     37: #define        MD_WARN_ALL     (1 << 0)
                     38: #define        MD_WARN_ERR     (1 << 1)
                     39:        int              dbg;
                     40:        struct mdoc     *mdoc;
                     41:        char            *buf;
                     42:        u_long           bufsz;
                     43:        char            *name;
                     44:        int              fd;
                     45:        int              lnn;
                     46:        char            *line;
                     47: };
1.17      kristaps   48:
1.9       kristaps   49: static void             usage(void);
                     50:
1.21      kristaps   51: static int              parse_begin(struct md_parse *);
                     52: static int              parse_leave(struct md_parse *, int);
                     53: static int              io_begin(struct md_parse *);
                     54: static int              io_leave(struct md_parse *, int);
                     55: static int              buf_begin(struct md_parse *);
                     56: static int              buf_leave(struct md_parse *, int);
                     57:
                     58: static int              msg_err(void *, int, int, enum mdoc_err);
                     59: static int              msg_warn(void *, int, int, enum mdoc_warn);
                     60: static void             msg_msg(void *, int, const char *);
1.1       kristaps   61:
1.19      kristaps   62: #ifdef __linux__
                     63: extern int              getsubopt(char **, char *const *, char **);
                     64: #endif
                     65:
1.1       kristaps   66: int
                     67: main(int argc, char *argv[])
                     68: {
                     69:        int              c;
1.21      kristaps   70:        struct md_parse  parser;
                     71:        char            *opts, *v;
1.18      kristaps   72: #define ALL             0
                     73: #define ERROR           1
                     74:        char            *toks[] = { "all", "error", NULL };
1.1       kristaps   75:
                     76:        extern char     *optarg;
                     77:        extern int       optind;
                     78:
1.21      kristaps   79:        (void)memset(&parser, 0, sizeof(struct md_parse));
1.17      kristaps   80:
1.21      kristaps   81:        while (-1 != (c = getopt(argc, argv, "vW:")))
1.1       kristaps   82:                switch (c) {
1.13      kristaps   83:                case ('v'):
1.21      kristaps   84:                        parser.dbg++;
1.13      kristaps   85:                        break;
                     86:                case ('W'):
1.18      kristaps   87:                        opts = optarg;
                     88:                        while (*opts)
                     89:                                switch (getsubopt(&opts, toks, &v)) {
                     90:                                case (ALL):
1.21      kristaps   91:                                        parser.warn |= MD_WARN_ALL;
1.18      kristaps   92:                                        break;
                     93:                                case (ERROR):
1.21      kristaps   94:                                        parser.warn |= MD_WARN_ERR;
1.18      kristaps   95:                                        break;
                     96:                                default:
                     97:                                        usage();
                     98:                                        return(1);
                     99:                                }
1.13      kristaps  100:                        break;
1.1       kristaps  101:                default:
                    102:                        usage();
                    103:                        return(1);
                    104:                }
                    105:
                    106:        argv += optind;
1.4       kristaps  107:        argc -= optind;
1.1       kristaps  108:
1.21      kristaps  109:        parser.name = "-";
1.4       kristaps  110:        if (1 == argc)
1.21      kristaps  111:                parser.name = *argv++;
                    112:
                    113:        if ( ! io_begin(&parser))
                    114:                return(EXIT_FAILURE);
1.1       kristaps  115:
1.21      kristaps  116:        return(EXIT_SUCCESS);
1.1       kristaps  117: }
                    118:
                    119:
                    120: static int
1.21      kristaps  121: io_leave(struct md_parse *p, int code)
1.1       kristaps  122: {
                    123:
1.21      kristaps  124:        if (-1 == p->fd || STDIN_FILENO == p->fd)
                    125:                return(code);
                    126:
                    127:        if (-1 == close(p->fd)) {
                    128:                warn("%s", p->name);
                    129:                code = 0;
1.4       kristaps  130:        }
1.21      kristaps  131:        return(code);
                    132: }
                    133:
                    134:
                    135: static int
                    136: io_begin(struct md_parse *p)
                    137: {
                    138:
                    139:        p->fd = STDIN_FILENO;
                    140:        if (0 != strncmp(p->name, "-", 1))
                    141:                if (-1 == (p->fd = open(p->name, O_RDONLY, 0))) {
                    142:                        warn("%s", p->name);
                    143:                        return(io_leave(p, 0));
                    144:                }
1.1       kristaps  145:
1.21      kristaps  146:        return(io_leave(p, buf_begin(p)));
1.1       kristaps  147: }
                    148:
                    149:
                    150: static int
1.21      kristaps  151: buf_leave(struct md_parse *p, int code)
1.1       kristaps  152: {
1.4       kristaps  153:
1.21      kristaps  154:        if (p->buf)
                    155:                free(p->buf);
                    156:        return(code);
                    157: }
1.1       kristaps  158:
                    159:
1.21      kristaps  160: static int
                    161: buf_begin(struct md_parse *p)
                    162: {
                    163:        struct stat      st;
1.1       kristaps  164:
1.21      kristaps  165:        if (-1 == fstat(p->fd, &st)) {
                    166:                warn("%s", p->name);
                    167:                return(1);
                    168:        }
                    169:
                    170:        p->bufsz = MAX(st.st_blksize, BUFSIZ);
                    171:
                    172:        if (NULL == (p->buf = malloc(p->bufsz))) {
                    173:                warn("malloc");
                    174:                return(buf_leave(p, 0));
                    175:        }
                    176:
                    177:        return(buf_leave(p, parse_begin(p)));
                    178: }
                    179:
                    180:
                    181: static void
                    182: print_node(const struct mdoc_node *n, int indent)
                    183: {
1.26      kristaps  184:        const char       *p, *t;
                    185:        int               i, j;
                    186:        size_t            argc, sz;
                    187:        char            **params;
                    188:        struct mdoc_arg  *argv;
1.24      kristaps  189:
                    190:        argv = NULL;
                    191:        argc = 0;
1.26      kristaps  192:        params = NULL;
                    193:        sz = 0;
1.21      kristaps  194:
                    195:        switch (n->type) {
                    196:        case (MDOC_TEXT):
                    197:                assert(NULL == n->child);
1.25      kristaps  198:                p = n->data.text.string;
1.21      kristaps  199:                t = "text";
                    200:                break;
                    201:        case (MDOC_BODY):
                    202:                p = mdoc_macronames[n->data.body.tok];
                    203:                t = "block-body";
                    204:                break;
                    205:        case (MDOC_HEAD):
                    206:                p = mdoc_macronames[n->data.head.tok];
                    207:                t = "block-head";
                    208:                break;
1.34      kristaps  209:        case (MDOC_TAIL):
                    210:                p = mdoc_macronames[n->data.tail.tok];
                    211:                t = "block-tail";
                    212:                break;
1.21      kristaps  213:        case (MDOC_ELEM):
                    214:                p = mdoc_macronames[n->data.elem.tok];
                    215:                t = "element";
1.24      kristaps  216:                argv = n->data.elem.argv;
                    217:                argc = n->data.elem.argc;
1.21      kristaps  218:                break;
                    219:        case (MDOC_BLOCK):
                    220:                p = mdoc_macronames[n->data.block.tok];
                    221:                t = "block";
1.24      kristaps  222:                argv = n->data.block.argv;
                    223:                argc = n->data.block.argc;
1.21      kristaps  224:                break;
1.22      kristaps  225:        default:
                    226:                abort();
                    227:                /* NOTREACHED */
1.21      kristaps  228:        }
                    229:
                    230:        for (i = 0; i < indent; i++)
                    231:                (void)printf("    ");
1.24      kristaps  232:        (void)printf("%s (%s)", p, t);
                    233:
                    234:        for (i = 0; i < (int)argc; i++) {
                    235:                (void)printf(" -%s", mdoc_argnames[argv[i].arg]);
                    236:                for (j = 0; j < (int)argv[i].sz; j++)
                    237:                        (void)printf(" \"%s\"", argv[i].value[j]);
                    238:        }
                    239:
1.26      kristaps  240:        for (i = 0; i < (int)sz; i++)
                    241:                (void)printf(" \"%s\"", params[i]);
                    242:
1.24      kristaps  243:        (void)printf("\n");
1.21      kristaps  244:
                    245:        if (n->child)
                    246:                print_node(n->child, indent + 1);
                    247:        if (n->next)
                    248:                print_node(n->next, indent);
                    249: }
1.1       kristaps  250:
                    251:
1.21      kristaps  252: static int
                    253: parse_leave(struct md_parse *p, int code)
                    254: {
                    255:        const struct mdoc_node *n;
                    256:
1.36    ! kristaps  257:        if (NULL == p->mdoc)
        !           258:                return(code);
        !           259:
        !           260:        if ( ! mdoc_endparse(p->mdoc))
        !           261:                code = 0;
        !           262:        if ((n = mdoc_result(p->mdoc)))
        !           263:                print_node(n, 0);
        !           264:
1.21      kristaps  265:        return(code);
                    266: }
                    267:
                    268:
                    269: static int
                    270: parse_begin(struct md_parse *p)
                    271: {
                    272:        ssize_t          sz, i;
                    273:        size_t           pos;
                    274:        char             line[256], sv[256];
                    275:        struct mdoc_cb   cb;
                    276:
                    277:        cb.mdoc_err = msg_err;
                    278:        cb.mdoc_warn = msg_warn;
                    279:        cb.mdoc_msg = msg_msg;
                    280:
                    281:        if (NULL == (p->mdoc = mdoc_alloc(p, &cb)))
                    282:                return(parse_leave(p, 0));
                    283:
                    284:        p->lnn = 1;
                    285:        p->line = sv;
                    286:
                    287:        for (pos = 0; ; ) {
                    288:                if (-1 == (sz = read(p->fd, p->buf, p->bufsz))) {
                    289:                        warn("%s", p->name);
                    290:                        return(parse_leave(p, 0));
                    291:                } else if (0 == sz)
                    292:                        break;
                    293:
                    294:                for (i = 0; i < sz; i++) {
                    295:                        if ('\n' != p->buf[i]) {
                    296:                                if (pos < sizeof(line)) {
1.23      kristaps  297:                                        sv[(int)pos] = p->buf[(int)i];
                    298:                                        line[(int)pos++] =
                    299:                                                p->buf[(int)i];
1.21      kristaps  300:                                        continue;
                    301:                                }
                    302:                                warnx("%s: line %d too long",
                    303:                                                p->name, p->lnn);
                    304:                                return(parse_leave(p, 0));
                    305:                        }
                    306:
                    307:                        line[(int)pos] = sv[(int)pos] = 0;
1.36    ! kristaps  308:                        if ( ! mdoc_parseln(p->mdoc, p->lnn, line))
1.21      kristaps  309:                                return(parse_leave(p, 0));
1.1       kristaps  310:
1.21      kristaps  311:                        p->lnn++;
                    312:                        pos = 0;
1.4       kristaps  313:                }
1.21      kristaps  314:        }
1.1       kristaps  315:
1.21      kristaps  316:        return(parse_leave(p, 1));
1.4       kristaps  317: }
1.1       kristaps  318:
                    319:
1.4       kristaps  320: static int
1.21      kristaps  321: msg_err(void *arg, int tok, int col, enum mdoc_err type)
                    322: {
                    323:        char             *fmt, *lit;
                    324:        struct md_parse  *p;
                    325:        int               i;
                    326:
                    327:        p = (struct md_parse *)arg;
                    328:
                    329:        fmt = lit = NULL;
                    330:
                    331:        switch (type) {
1.35      kristaps  332:        case (ERR_SYNTAX_NOTEXT):
                    333:                lit = "syntax: context-free text disallowed";
                    334:                break;
1.21      kristaps  335:        case (ERR_SYNTAX_QUOTE):
1.24      kristaps  336:                lit = "syntax: disallowed argument quotation";
                    337:                break;
                    338:        case (ERR_SYNTAX_UNQUOTE):
1.21      kristaps  339:                lit = "syntax: unterminated quotation";
                    340:                break;
                    341:        case (ERR_SYNTAX_WS):
                    342:                lit = "syntax: whitespace in argument";
                    343:                break;
1.25      kristaps  344:        case (ERR_SYNTAX_ARGFORM):
1.23      kristaps  345:                fmt = "syntax: macro `%s' arguments malformed";
                    346:                break;
1.28      kristaps  347:        case (ERR_SYNTAX_NOPUNCT):
                    348:                fmt = "syntax: macro `%s' doesn't understand punctuation";
                    349:                break;
1.25      kristaps  350:        case (ERR_SYNTAX_ARG):
1.24      kristaps  351:                fmt = "syntax: unknown argument for macro `%s'";
                    352:                break;
1.21      kristaps  353:        case (ERR_SCOPE_BREAK):
                    354:                /* Which scope is broken? */
1.24      kristaps  355:                fmt = "scope: macro `%s' breaks prior explicit scope";
                    356:                break;
                    357:        case (ERR_SCOPE_NOCTX):
                    358:                fmt = "scope: closure macro `%s' has no context";
1.21      kristaps  359:                break;
1.25      kristaps  360:        case (ERR_SCOPE_NONEST):
1.26      kristaps  361:                fmt = "scope: macro `%s' may not be nested in the current context";
1.25      kristaps  362:                break;
1.21      kristaps  363:        case (ERR_MACRO_NOTSUP):
1.35      kristaps  364:                lit = "macro not supported";
1.21      kristaps  365:                break;
                    366:        case (ERR_MACRO_NOTCALL):
                    367:                fmt = "macro `%s' not callable";
                    368:                break;
1.23      kristaps  369:        case (ERR_SEC_PROLOGUE):
                    370:                fmt = "macro `%s' cannot be called in the prologue";
                    371:                break;
                    372:        case (ERR_SEC_NPROLOGUE):
                    373:                fmt = "macro `%s' called outside of prologue";
                    374:                break;
1.28      kristaps  375:        case (ERR_ARGS_EQ0):
                    376:                fmt = "macro `%s' expects zero arguments";
                    377:                break;
1.29      kristaps  378:        case (ERR_ARGS_EQ1):
                    379:                fmt = "macro `%s' expects one argument";
                    380:                break;
1.21      kristaps  381:        case (ERR_ARGS_GE1):
                    382:                fmt = "macro `%s' expects one or more arguments";
                    383:                break;
1.28      kristaps  384:        case (ERR_ARGS_LE2):
                    385:                fmt = "macro `%s' expects two or fewer arguments";
                    386:                break;
1.36    ! kristaps  387:        case (ERR_ARGS_LE8):
        !           388:                fmt = "macro `%s' expects eight or fewer arguments";
        !           389:                break;
1.23      kristaps  390:        case (ERR_ARGS_MANY):
                    391:                fmt = "macro `%s' has too many arguments";
                    392:                break;
                    393:        case (ERR_SEC_PROLOGUE_OO):
                    394:                fmt = "prologue macro `%s' is out-of-order";
                    395:                break;
                    396:        case (ERR_SEC_PROLOGUE_REP):
                    397:                fmt = "prologue macro `%s' repeated";
                    398:                break;
                    399:        case (ERR_SEC_NAME):
                    400:                lit = "`NAME' section must be first";
                    401:                break;
1.24      kristaps  402:        case (ERR_SYNTAX_ARGVAL):
                    403:                lit = "syntax: expected value for macro argument";
                    404:                break;
1.25      kristaps  405:        case (ERR_SYNTAX_ARGBAD):
                    406:                lit = "syntax: invalid value for macro argument";
                    407:                break;
1.24      kristaps  408:        case (ERR_SYNTAX_ARGMANY):
                    409:                lit = "syntax: too many values for macro argument";
                    410:                break;
1.32      kristaps  411:        case (ERR_SYNTAX_CHILDHEAD):
                    412:                lit = "syntax: expected only block-header section";
                    413:                break;
                    414:        case (ERR_SYNTAX_CHILDBODY):
                    415:                lit = "syntax: expected only a block-body section";
                    416:                break;
                    417:        case (ERR_SYNTAX_EMPTYHEAD):
                    418:                lit = "syntax: block-header section may not be empty";
                    419:                break;
                    420:        case (ERR_SYNTAX_EMPTYBODY):
                    421:                lit = "syntax: block-body section may not be empty";
1.31      kristaps  422:                break;
1.21      kristaps  423:        default:
                    424:                abort();
                    425:                /* NOTREACHED */
                    426:        }
                    427:
                    428:        if (fmt) {
                    429:                (void)fprintf(stderr, "%s:%d: error: ",
                    430:                                p->name, p->lnn);
                    431:                (void)fprintf(stderr, fmt, mdoc_macronames[tok]);
                    432:        } else
                    433:                (void)fprintf(stderr, "%s:%d: error: %s",
                    434:                                p->name, p->lnn, lit);
                    435:
                    436:        if (p->dbg < 1) {
1.23      kristaps  437:                if (-1 != col)
                    438:                        (void)fprintf(stderr, " (column %d)\n", col);
                    439:                return(0);
                    440:        } else if (-1 == col) {
1.36    ! kristaps  441:                (void)fprintf(stderr, "\nFrom: %s\n", p->line);
1.21      kristaps  442:                return(0);
                    443:        }
                    444:
                    445:        (void)fprintf(stderr, "\nFrom: %s\n      ", p->line);
                    446:        for (i = 0; i < col; i++)
                    447:                (void)fprintf(stderr, " ");
                    448:        (void)fprintf(stderr, "^\n");
                    449:
                    450:        return(0);
                    451: }
                    452:
                    453:
                    454: static void
                    455: msg_msg(void *arg, int col, const char *msg)
1.4       kristaps  456: {
1.21      kristaps  457:        struct md_parse  *p;
                    458:        int               i;
                    459:
                    460:        p = (struct md_parse *)arg;
                    461:
                    462:        if (p->dbg < 2)
                    463:                return;
                    464:
                    465:        (void)printf("%s:%d: %s", p->name, p->lnn, msg);
                    466:
                    467:        if (p->dbg < 3) {
1.23      kristaps  468:                if (-1 != col)
                    469:                        (void)printf(" (column %d)\n", col);
                    470:                return;
                    471:        } else if (-1 == col) {
                    472:                (void)printf("\nFrom %s\n", p->line);
1.21      kristaps  473:                return;
                    474:        }
                    475:
                    476:        (void)printf("\nFrom: %s\n      ", p->line);
                    477:        for (i = 0; i < col; i++)
                    478:                (void)printf(" ");
                    479:        (void)printf("^\n");
1.1       kristaps  480: }
                    481:
                    482:
                    483: static int
1.21      kristaps  484: msg_warn(void *arg, int tok, int col, enum mdoc_warn type)
1.1       kristaps  485: {
1.21      kristaps  486:        char             *fmt, *lit;
                    487:        struct md_parse  *p;
                    488:        int               i;
                    489:        extern char      *__progname;
1.1       kristaps  490:
1.21      kristaps  491:        p = (struct md_parse *)arg;
1.1       kristaps  492:
1.21      kristaps  493:        if ( ! (p->warn & MD_WARN_ALL))
1.1       kristaps  494:                return(1);
1.21      kristaps  495:
                    496:        fmt = lit = NULL;
                    497:
                    498:        switch (type) {
                    499:        case (WARN_SYNTAX_WS_EOLN):
                    500:                lit = "syntax: whitespace at end-of-line";
                    501:                break;
1.25      kristaps  502:        case (WARN_SYNTAX_QUOTED):
                    503:                lit = "syntax: quotation mark starting string";
                    504:                break;
1.21      kristaps  505:        case (WARN_SYNTAX_MACLIKE):
                    506:                lit = "syntax: macro-like argument";
                    507:                break;
1.24      kristaps  508:        case (WARN_SYNTAX_ARGLIKE):
                    509:                lit = "syntax: argument-like value";
                    510:                break;
1.32      kristaps  511:        case (WARN_SYNTAX_EMPTYBODY):
                    512:                lit = "syntax: empty block-body section";
                    513:                break;
1.23      kristaps  514:        case (WARN_SEC_OO):
                    515:                lit = "section is out of conventional order";
                    516:                break;
1.21      kristaps  517:        case (WARN_ARGS_GE1):
                    518:                fmt = "macro `%s' suggests one or more arguments";
                    519:                break;
1.25      kristaps  520:        case (WARN_ARGS_EQ0):
                    521:                fmt = "macro `%s' suggests zero arguments";
                    522:                break;
                    523:        case (WARN_IGN_AFTER_BLK):
                    524:                fmt = "ignore: macro `%s' ignored after block macro";
                    525:                break;
1.30      kristaps  526:        case (WARN_IGN_OBSOLETE):
                    527:                fmt = "ignore: macro `%s' is obsolete";
                    528:                break;
1.25      kristaps  529:        case (WARN_IGN_BEFORE_BLK):
                    530:                fmt = "ignore: macro before block macro `%s' ignored";
                    531:                break;
1.27      kristaps  532:        case (WARN_COMPAT_TROFF):
                    533:                fmt = "compat: macro `%s' behaves differently in troff and nroff";
                    534:                break;
1.21      kristaps  535:        default:
                    536:                abort();
                    537:                /* NOTREACHED */
1.1       kristaps  538:        }
                    539:
1.21      kristaps  540:        if (fmt) {
                    541:                (void)fprintf(stderr, "%s:%d: warning: ",
                    542:                                p->name, p->lnn);
                    543:                (void)fprintf(stderr, fmt, mdoc_macronames[tok]);
                    544:        } else
                    545:                (void)fprintf(stderr, "%s:%d: warning: %s",
                    546:                                p->name, p->lnn, lit);
                    547:
1.36    ! kristaps  548:        if (col >= 0 && p->dbg >= 1) {
1.21      kristaps  549:                (void)fprintf(stderr, "\nFrom: %s\n      ", p->line);
                    550:                for (i = 0; i < col; i++)
                    551:                        (void)fprintf(stderr, " ");
                    552:                (void)fprintf(stderr, "^\n");
1.36    ! kristaps  553:        } else if (col >= 0)
1.21      kristaps  554:                (void)fprintf(stderr, " (column %d)\n", col);
1.36    ! kristaps  555:        else
        !           556:                (void)fprintf(stderr, "\n");
1.21      kristaps  557:
                    558:        if (p->warn & MD_WARN_ERR) {
                    559:                (void)fprintf(stderr, "%s: considering warnings as "
                    560:                                "errors\n", __progname);
                    561:                return(0);
1.1       kristaps  562:        }
                    563:
1.21      kristaps  564:        return(1);
1.1       kristaps  565: }
                    566:
                    567:
                    568: static void
                    569: usage(void)
                    570: {
                    571:        extern char     *__progname;
                    572:
1.21      kristaps  573:        (void)fprintf(stderr, "usage: %s [-v] [-Wwarn...] [infile]\n",
1.19      kristaps  574:                        __progname);
1.1       kristaps  575: }
1.18      kristaps  576:

CVSweb