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

Annotation of mandoc/mlg.c, Revision 1.24

1.24    ! kristaps    1: /* $Id: mlg.c,v 1.23 2008/12/09 17:09:12 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:  */
                     19: #include <assert.h>
                     20: #include <ctype.h>
                     21: #include <err.h>
1.13      kristaps   22: #include <stdarg.h>
1.1       kristaps   23: #include <stdlib.h>
                     24: #include <stdio.h>
                     25: #include <string.h>
                     26:
                     27: #include "ml.h"
                     28:
                     29: /* TODO: literal tokens. */
                     30:
                     31: enum   md_tok {
                     32:        MD_TEXT,
                     33:        MD_INLINE_IN,
                     34:        MD_INLINE_OUT,
                     35:        MD_BLK_IN,
                     36:        MD_BLK_OUT,
                     37: };
                     38:
                     39: struct md_mlg {
                     40:        const struct md_args    *args;
                     41:        const struct md_rbuf    *rbuf;
                     42:
                     43:        struct md_mbuf   *mbuf;
                     44:        struct rofftree  *tree;
                     45:        size_t            indent;
                     46:        size_t            pos;
                     47:        enum md_tok       last;
                     48:        void             *arg;
1.11      kristaps   49:        struct ml_cbs     cbs;
1.1       kristaps   50:        int               flags;
                     51: #define        ML_OVERRIDE_ONE  (1 << 0)
                     52: #define        ML_OVERRIDE_ALL  (1 << 1)
1.10      kristaps   53:        void             *data;
1.1       kristaps   54: };
                     55:
1.23      kristaps   56: static int              mlg_roffmsg(void *arg,
1.20      kristaps   57:                                enum roffmsg, const char *,
                     58:                                const char *, const char *);
1.4       kristaps   59: static int              mlg_roffhead(void *, const struct tm *,
                     60:                                const char *, const char *,
1.21      kristaps   61:                                enum roffmsec, const char *);
1.1       kristaps   62: static int              mlg_rofftail(void *);
1.20      kristaps   63: static int              mlg_roffin(void *, int,
                     64:                                int *, const char **);
1.5       kristaps   65: static int              mlg_roffdata(void *, int,
1.20      kristaps   66:                                const char *, const char *);
1.1       kristaps   67: static int              mlg_roffout(void *, int);
1.20      kristaps   68: static int              mlg_roffblkin(void *, int, int *,
                     69:                                const char **);
1.1       kristaps   70: static int              mlg_roffblkout(void *, int);
1.8       kristaps   71: static int              mlg_roffspecial(void *, int,
1.16      kristaps   72:                                const char *, const int *,
1.20      kristaps   73:                                const char **, const char **);
1.5       kristaps   74: static int              mlg_roffblkheadin(void *, int,
1.20      kristaps   75:                                int *, const char **);
1.2       kristaps   76: static int              mlg_roffblkheadout(void *, int);
1.5       kristaps   77: static int              mlg_roffblkbodyin(void *, int,
1.20      kristaps   78:                                int *, const char **);
1.2       kristaps   79: static int              mlg_roffblkbodyout(void *, int);
                     80:
1.20      kristaps   81: static int              mlg_ref_special(struct md_mlg *, int,
                     82:                                const char *, const char **);
                     83: static int              mlg_formatted_special(struct md_mlg *,
1.23      kristaps   84:                                int, const char *, const int *,
1.20      kristaps   85:                                const char **, const char **);
                     86: static int              mlg_literal_special(struct md_mlg *,
                     87:                                int,  const char *, const int *,
                     88:                                const char **, const char **);
                     89: static int              mlg_function_special(struct md_mlg *,
                     90:                                const char *, const char **);
                     91: static int              mlg_atom_special(struct md_mlg *, int,
                     92:                                const char *, const char **);
                     93:
1.1       kristaps   94: static int              mlg_begintag(struct md_mlg *, enum md_ns,
1.20      kristaps   95:                                int, int *, const char **);
1.1       kristaps   96: static int              mlg_endtag(struct md_mlg *, enum md_ns, int);
                     97: static int              mlg_indent(struct md_mlg *);
                     98: static int              mlg_newline(struct md_mlg *);
                     99: static void             mlg_mode(struct md_mlg *, enum md_tok);
1.19      kristaps  100: static int              mlg_nstring(struct md_mlg *,
                    101:                                const char *, const char *, size_t);
                    102: static int              mlg_string(struct md_mlg *,
                    103:                                const char *, const char *);
1.5       kristaps  104: static int              mlg_data(struct md_mlg *, int,
1.20      kristaps  105:                                const char *, const char *);
1.23      kristaps  106: static int              mlg_err(struct md_mlg *, const char *,
1.13      kristaps  107:                                const char *, const char *, ...);
1.23      kristaps  108: static int              mlg_msg(struct md_mlg *,
1.20      kristaps  109:                                enum roffmsg, const char *,
                    110:                                const char *, const char *);
1.23      kristaps  111: static int              mlg_vmsg(struct md_mlg *, enum roffmsg,
1.13      kristaps  112:                                const char *, const char *,
                    113:                                const char *, va_list);
1.1       kristaps  114:
                    115: #ifdef __linux__
                    116: extern size_t           strlcat(char *, const char *, size_t);
                    117: extern size_t           strlcpy(char *, const char *, size_t);
                    118: #endif
                    119:
                    120:
                    121: static int
                    122: mlg_begintag(struct md_mlg *p, enum md_ns ns, int tok,
1.20      kristaps  123:                int *argc, const char **argv)
1.1       kristaps  124: {
                    125:        ssize_t          res;
                    126:
1.8       kristaps  127:        assert(MD_NS_DEFAULT != ns);
                    128:
                    129:        switch (ns) {
                    130:        case (MD_NS_INLINE):
                    131:                if ( ! (ML_OVERRIDE_ONE & p->flags) &&
                    132:                                ! (ML_OVERRIDE_ALL & p->flags) &&
1.9       kristaps  133:                                p->pos + 11 >= COLUMNS)
1.8       kristaps  134:                        if ( ! mlg_newline(p))
                    135:                                return(0);
                    136:                if (0 != p->pos && (MD_TEXT == p->last ||
                    137:                                        MD_INLINE_OUT == p->last)
                    138:                                && ! (ML_OVERRIDE_ONE & p->flags)
                    139:                                && ! (ML_OVERRIDE_ALL & p->flags))
                    140:                        if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos))
                    141:                                return(0);
                    142:                if (0 == p->pos && ! mlg_indent(p))
                    143:                        return(0);
                    144:                mlg_mode(p, MD_INLINE_IN);
                    145:                break;
                    146:        default:
                    147:                if (0 != p->pos) {
                    148:                        if ( ! mlg_newline(p))
                    149:                                return(0);
                    150:                        if ( ! mlg_indent(p))
                    151:                                return(0);
                    152:                } else if ( ! mlg_indent(p))
                    153:                        return(0);
                    154:                p->indent++;
                    155:                mlg_mode(p, MD_BLK_IN);
                    156:                break;
                    157:        }
1.1       kristaps  158:
                    159:        if ( ! ml_nputs(p->mbuf, "<", 1, &p->pos))
                    160:                return(0);
                    161:
1.20      kristaps  162:        res = (*p->cbs.ml_begintag)(p->mbuf, p->data,
                    163:                        p->args, ns, tok, argc, argv);
1.1       kristaps  164:        if (-1 == res)
                    165:                return(0);
                    166:
                    167:        assert(res >= 0);
                    168:        p->pos += (size_t)res;
                    169:
1.8       kristaps  170:        if ( ! ml_nputs(p->mbuf, ">", 1, &p->pos))
                    171:                return(0);
                    172:
                    173:        switch (ns) {
                    174:        case (MD_NS_INLINE):
                    175:                break;
                    176:        default:
                    177:                if ( ! mlg_newline(p))
                    178:                        return(0);
                    179:                break;
                    180:        }
1.1       kristaps  181:
1.8       kristaps  182:        return(1);
1.1       kristaps  183: }
                    184:
                    185:
                    186: static int
                    187: mlg_endtag(struct md_mlg *p, enum md_ns ns, int tok)
                    188: {
                    189:        ssize_t          res;
                    190:
1.9       kristaps  191:        assert(MD_NS_DEFAULT != ns);
                    192:
                    193:        switch (ns) {
                    194:        case (MD_NS_INLINE):
                    195:                break;
                    196:        default:
                    197:                p->indent--;
                    198:                if (0 != p->pos) {
                    199:                        if ( ! mlg_newline(p))
                    200:                                return(0);
                    201:                        if ( ! mlg_indent(p))
                    202:                                return(0);
                    203:                } else if ( ! mlg_indent(p))
                    204:                        return(0);
                    205:                break;
                    206:        }
1.1       kristaps  207:
                    208:        if ( ! ml_nputs(p->mbuf, "</", 2, &p->pos))
                    209:                return(0);
                    210:
1.11      kristaps  211:        res = (*p->cbs.ml_endtag)(p->mbuf, p->data, p->args, ns, tok);
1.1       kristaps  212:        if (-1 == res)
                    213:                return(0);
                    214:
                    215:        assert(res >= 0);
                    216:        p->pos += (size_t)res;
                    217:
1.9       kristaps  218:        if ( ! ml_nputs(p->mbuf, ">", 1, &p->pos))
                    219:                return(0);
                    220:
                    221:        switch (ns) {
                    222:        case (MD_NS_INLINE):
                    223:                mlg_mode(p, MD_INLINE_OUT);
                    224:                break;
                    225:        default:
                    226:                mlg_mode(p, MD_BLK_OUT);
                    227:                break;
                    228:        }
1.1       kristaps  229:
1.9       kristaps  230:        return(1);
1.1       kristaps  231: }
                    232:
                    233:
                    234: static int
                    235: mlg_indent(struct md_mlg *p)
                    236: {
                    237:
                    238:        assert(0 == p->pos);
1.24    ! kristaps  239:        return(ml_putchars(p->mbuf, ' ', INDENT_SZ *
        !           240:                                INDENT(p->indent), &p->pos));
1.1       kristaps  241: }
                    242:
                    243:
                    244: static int
                    245: mlg_newline(struct md_mlg *p)
                    246: {
                    247:
                    248:        p->pos = 0;
1.11      kristaps  249:        return(ml_nputs(p->mbuf, "\n", 1, NULL));
1.1       kristaps  250: }
                    251:
                    252:
                    253: static void
                    254: mlg_mode(struct md_mlg *p, enum md_tok ns)
                    255: {
1.3       kristaps  256:
1.1       kristaps  257:        p->flags &= ~ML_OVERRIDE_ONE;
                    258:        p->last = ns;
                    259: }
                    260:
                    261:
                    262: static int
1.19      kristaps  263: mlg_string(struct md_mlg *p, const char *start, const char *buf)
                    264: {
                    265:
                    266:        return(mlg_nstring(p, start, buf, strlen(buf)));
                    267: }
                    268:
                    269:
                    270: static int
                    271: mlg_nstring(struct md_mlg *p, const char *start,
                    272:                const char *buf, size_t sz)
                    273: {
                    274:        int              c;
                    275:        ssize_t          res;
                    276:
                    277:        assert(p->mbuf);
                    278:        assert(0 != p->indent);
                    279:
                    280:        res = (*p->cbs.ml_beginstring)(p->mbuf, p->args, buf, sz);
                    281:        if (-1 == res)
                    282:                return(0);
                    283:
1.23      kristaps  284:        if (0 == (c = ml_nputstring(p->mbuf, buf, sz, &p->pos)))
                    285:                return(mlg_err(p, start, buf, "bad string "
                    286:                                        "encoding: `%s'", buf));
                    287:        else if (-1 == c)
1.19      kristaps  288:                return(0);
                    289:
                    290:        res = (*p->cbs.ml_endstring)(p->mbuf, p->args, buf, sz);
                    291:        if (-1 == res)
                    292:                return(0);
                    293:
                    294:        return(1);
                    295: }
                    296:
                    297:
                    298: static int
1.20      kristaps  299: mlg_data(struct md_mlg *p, int space,
                    300:                const char *start, const char *buf)
1.1       kristaps  301: {
                    302:        size_t           sz;
                    303:
                    304:        assert(p->mbuf);
                    305:        assert(0 != p->indent);
                    306:
                    307:        if (ML_OVERRIDE_ONE & p->flags ||
                    308:                        ML_OVERRIDE_ALL & p->flags)
                    309:                space = 0;
                    310:
1.8       kristaps  311:        sz = strlen(buf);
1.1       kristaps  312:
1.8       kristaps  313:        if (0 == p->pos) {
                    314:                if ( ! mlg_indent(p))
                    315:                        return(0);
1.19      kristaps  316:                if ( ! mlg_nstring(p, start, buf, sz))
1.8       kristaps  317:                        return(0);
1.1       kristaps  318:
1.24    ! kristaps  319:                if (INDENT(p->indent) * INDENT_SZ + sz >= COLUMNS)
1.8       kristaps  320:                        if ( ! mlg_newline(p))
1.1       kristaps  321:                                return(0);
1.5       kristaps  322:
1.8       kristaps  323:                return(1);
                    324:        }
1.5       kristaps  325:
1.8       kristaps  326:        if (space && sz + p->pos >= COLUMNS) {
                    327:                if ( ! mlg_newline(p))
1.5       kristaps  328:                        return(0);
1.8       kristaps  329:                if ( ! mlg_indent(p))
1.5       kristaps  330:                        return(0);
1.8       kristaps  331:        } else if (space) {
                    332:                if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos))
1.1       kristaps  333:                        return(0);
1.8       kristaps  334:        }
1.1       kristaps  335:
1.19      kristaps  336:        return(mlg_nstring(p, start, buf, sz));
1.1       kristaps  337: }
                    338:
                    339:
                    340: int
                    341: mlg_line(struct md_mlg *p, char *buf)
                    342: {
                    343:
                    344:        return(roff_engine(p->tree, buf));
                    345: }
                    346:
                    347:
                    348: int
                    349: mlg_exit(struct md_mlg *p, int flush)
                    350: {
                    351:        int              c;
                    352:
                    353:        c = roff_free(p->tree, flush);
1.21      kristaps  354:        (*p->cbs.ml_free)(p->data);
                    355:
1.1       kristaps  356:        free(p);
1.11      kristaps  357:
1.1       kristaps  358:        return(c);
                    359: }
                    360:
                    361:
                    362: struct md_mlg *
1.11      kristaps  363: mlg_alloc(const struct md_args *args,
1.1       kristaps  364:                const struct md_rbuf *rbuf,
                    365:                struct md_mbuf *mbuf,
1.11      kristaps  366:                const struct ml_cbs *cbs)
1.1       kristaps  367: {
                    368:        struct roffcb    cb;
                    369:        struct md_mlg   *p;
                    370:
                    371:        cb.roffhead = mlg_roffhead;
                    372:        cb.rofftail = mlg_rofftail;
                    373:        cb.roffin = mlg_roffin;
                    374:        cb.roffout = mlg_roffout;
                    375:        cb.roffblkin = mlg_roffblkin;
1.2       kristaps  376:        cb.roffblkheadin = mlg_roffblkheadin;
                    377:        cb.roffblkheadout = mlg_roffblkheadout;
                    378:        cb.roffblkbodyin = mlg_roffblkbodyin;
                    379:        cb.roffblkbodyout = mlg_roffblkbodyout;
1.1       kristaps  380:        cb.roffblkout = mlg_roffblkout;
                    381:        cb.roffspecial = mlg_roffspecial;
                    382:        cb.roffmsg = mlg_roffmsg;
                    383:        cb.roffdata = mlg_roffdata;
                    384:
                    385:        if (NULL == (p = calloc(1, sizeof(struct md_mlg))))
                    386:                err(1, "calloc");
                    387:
                    388:        p->args = args;
                    389:        p->mbuf = mbuf;
                    390:        p->rbuf = rbuf;
                    391:
1.11      kristaps  392:        (void)memcpy(&p->cbs, cbs, sizeof(struct ml_cbs));
                    393:
                    394:        if (NULL == (p->tree = roff_alloc(&cb, p)))
                    395:                free(p);
                    396:        else if ( ! (*p->cbs.ml_alloc)(&p->data))
1.1       kristaps  397:                free(p);
1.11      kristaps  398:        else
                    399:                return(p);
1.1       kristaps  400:
1.11      kristaps  401:        return(NULL);
1.1       kristaps  402: }
                    403:
                    404:
                    405: static int
1.4       kristaps  406: mlg_roffhead(void *arg, const struct tm *tm, const char *os,
1.21      kristaps  407:                const char *title, enum roffmsec sec, const char *vol)
1.1       kristaps  408: {
                    409:        struct md_mlg   *p;
                    410:
                    411:        assert(arg);
                    412:        p = (struct md_mlg *)arg;
                    413:
                    414:        mlg_mode(p, MD_BLK_IN);
1.11      kristaps  415:
                    416:        if ( ! (*p->cbs.ml_begin)(p->mbuf, p->args, tm, os, title, sec, vol))
1.1       kristaps  417:                return(0);
                    418:
                    419:        p->indent++;
                    420:        return(mlg_newline(p));
                    421: }
                    422:
                    423:
                    424: static int
                    425: mlg_rofftail(void *arg)
                    426: {
                    427:        struct md_mlg   *p;
                    428:
                    429:        assert(arg);
                    430:        p = (struct md_mlg *)arg;
                    431:
1.11      kristaps  432:        if (0 != p->pos)
                    433:                if ( ! mlg_newline(p))
                    434:                        return(0);
                    435:
                    436:        if ( ! (*p->cbs.ml_end)(p->mbuf, p->args))
1.1       kristaps  437:                return(0);
                    438:
                    439:        mlg_mode(p, MD_BLK_OUT);
                    440:
                    441:        return(mlg_newline(p));
                    442: }
                    443:
                    444:
1.20      kristaps  445: static int
                    446: mlg_literal_special(struct md_mlg *p, int tok, const char *start,
                    447:                const int *argc, const char **argv, const char **more)
                    448: {
                    449:        char             *lit;
                    450:
                    451:        if ( ! mlg_begintag(p, MD_NS_INLINE, tok, NULL, more))
                    452:                return(0);
                    453:
1.23      kristaps  454:        lit = roff_literal(tok, argc, argv, more);
1.20      kristaps  455:        assert(lit);
                    456:
1.23      kristaps  457:        if ( ! mlg_string(p, start, lit))
1.20      kristaps  458:                return(0);
1.23      kristaps  459:
1.20      kristaps  460:        while (*more) {
                    461:                if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos))
                    462:                        return(0);
                    463:                if ( ! mlg_string(p, start, *more++))
                    464:                        return(0);
                    465:        }
                    466:
                    467:        return(mlg_endtag(p, MD_NS_INLINE, tok));
                    468: }
                    469:
                    470:
                    471: static int
                    472: mlg_ref_special(struct md_mlg *p, int tok,
                    473:                const char *start, const char **more)
                    474: {
                    475:
                    476:        if ( ! mlg_begintag(p, MD_NS_INLINE, tok, NULL, more))
                    477:                return(0);
                    478:
                    479:        assert(*more);
                    480:        if ( ! ml_puts(p->mbuf, *more++, &p->pos))
                    481:                return(0);
                    482:
                    483:        if (*more) {
                    484:                if ( ! ml_nputs(p->mbuf, "(", 1, &p->pos))
                    485:                        return(0);
                    486:                if ( ! mlg_string(p, start, *more++))
                    487:                        return(0);
                    488:                if ( ! ml_nputs(p->mbuf, ")", 1, &p->pos))
                    489:                        return(0);
                    490:        }
                    491:
                    492:        assert(NULL == *more);
                    493:        return(mlg_endtag(p, MD_NS_INLINE, tok));
                    494: }
                    495:
                    496:
                    497: static int
1.23      kristaps  498: mlg_formatted_special(struct md_mlg *p, int tok, const char *start,
1.20      kristaps  499:                const int *argc, const char **argv, const char **more)
                    500: {
                    501:        char             buf[256], *lit;
                    502:
                    503:        if ( ! mlg_begintag(p, MD_NS_INLINE, tok, NULL, more))
                    504:                return(0);
                    505:
1.23      kristaps  506:        lit = roff_fmtstring(tok);
1.21      kristaps  507:
1.20      kristaps  508:        assert(lit);
                    509:        assert(*more);
                    510:        (void)snprintf(buf, sizeof(buf), lit, *more++);
                    511:        assert(NULL == *more);
                    512:
1.23      kristaps  513:        if ( ! mlg_string(p, start, buf))
1.20      kristaps  514:                return(0);
                    515:
                    516:        return(mlg_endtag(p, MD_NS_INLINE, tok));
                    517: }
                    518:
                    519:
                    520: static int
                    521: mlg_atom_special(struct md_mlg *p, int tok,
                    522:                const char *start, const char **more)
                    523: {
                    524:
                    525:        if ( ! mlg_begintag(p, MD_NS_INLINE, tok, NULL, more))
                    526:                return(0);
                    527:
                    528:        assert(*more);
                    529:        if ( ! mlg_string(p, start, *more++))
                    530:                return(0);
                    531:
1.22      kristaps  532:        /*assert(NULL == *more);*/ /* FIXME: ROFF_Sx */
1.20      kristaps  533:        return(mlg_endtag(p, MD_NS_INLINE, tok));
                    534: }
                    535:
                    536:
                    537: static int
                    538: mlg_function_special(struct md_mlg *p,
                    539:                const char *start, const char **more)
                    540: {
                    541:
                    542:        assert(*more);
                    543:
                    544:        if ( ! mlg_begintag(p, MD_NS_INLINE, ROFF_Fn, NULL, more))
                    545:                return(0);
                    546:        if ( ! mlg_string(p, start, *more++))
                    547:                return(0);
                    548:        if ( ! mlg_endtag(p, MD_NS_INLINE, ROFF_Fn))
                    549:                return(0);
                    550:
                    551:        if (NULL == *more)
                    552:                return(1);
                    553:
                    554:        if ( ! ml_nputs(p->mbuf, "(", 1, &p->pos))
                    555:                return(0);
                    556:
                    557:        p->flags |= ML_OVERRIDE_ONE;
                    558:
                    559:        if ( ! mlg_begintag(p, MD_NS_INLINE, ROFF_Fa, NULL, more))
                    560:                return(0);
                    561:        if ( ! mlg_string(p, start, *more++))
                    562:                return(0);
                    563:        if ( ! mlg_endtag(p, MD_NS_INLINE, ROFF_Fa))
                    564:                return(0);
                    565:
                    566:        while (*more) {
                    567:                if ( ! ml_nputs(p->mbuf, ", ", 2, &p->pos))
                    568:                        return(0);
                    569:                if ( ! mlg_begintag(p, MD_NS_INLINE, ROFF_Fa, NULL, more))
                    570:                        return(0);
                    571:                if ( ! mlg_string(p, start, *more++))
                    572:                        return(0);
                    573:                if ( ! mlg_endtag(p, MD_NS_INLINE, ROFF_Fa))
                    574:                        return(0);
                    575:        }
                    576:
                    577:        return(ml_nputs(p->mbuf, ")", 1, &p->pos));
                    578: }
                    579:
                    580:
1.16      kristaps  581: /* ARGSUSED */
1.1       kristaps  582: static int
1.16      kristaps  583: mlg_roffspecial(void *arg, int tok, const char *start,
1.20      kristaps  584:                const int *argc, const char **argv, const char **more)
1.1       kristaps  585: {
                    586:        struct md_mlg   *p;
                    587:
                    588:        assert(arg);
                    589:        p = (struct md_mlg *)arg;
                    590:
                    591:        switch (tok) {
1.15      kristaps  592:        case (ROFF_Ns):
                    593:                p->flags |= ML_OVERRIDE_ONE;
                    594:                return(1);
1.20      kristaps  595:
1.15      kristaps  596:        case (ROFF_Sm):
                    597:                assert(*more);
                    598:                if (0 == strcmp(*more, "on"))
                    599:                        p->flags |= ML_OVERRIDE_ALL;
                    600:                else
                    601:                        p->flags &= ~ML_OVERRIDE_ALL;
                    602:                return(1);
1.18      kristaps  603:
                    604:        case (ROFF_Fn):
1.20      kristaps  605:                return(mlg_function_special(p, start, more));
1.16      kristaps  606:
1.8       kristaps  607:        case (ROFF_Xr):
1.20      kristaps  608:                return(mlg_ref_special(p, tok, start, more));
                    609:
                    610:        case (ROFF_Sx): /* FIXME */
1.15      kristaps  611:                /* FALLTHROUGH */
1.12      kristaps  612:        case (ROFF_Nm):
1.20      kristaps  613:                return(mlg_atom_special(p, tok, start, more));
1.18      kristaps  614:
                    615:        case (ROFF_In):
                    616:                /* NOTREACHED */
1.13      kristaps  617:        case (ROFF_Ex):
1.17      kristaps  618:                /* NOTREACHED */
                    619:        case (ROFF_Rv):
1.23      kristaps  620:                return(mlg_formatted_special(p, tok, start,
1.20      kristaps  621:                                        argc, argv, more));
1.19      kristaps  622:
1.15      kristaps  623:        case (ROFF_At):
1.20      kristaps  624:                /* FALLTHROUGH */
                    625:        case (ROFF_Bt):
                    626:                /* FALLTHROUGH */
                    627:        case (ROFF_Ud):
                    628:                /* FALLTHROUGH */
                    629:        case (ROFF_Ux):
                    630:                /* FALLTHROUGH */
1.15      kristaps  631:        case (ROFF_Bx):
                    632:                /* FALLTHROUGH */
                    633:        case (ROFF_Bsx):
                    634:                /* FALLTHROUGH */
                    635:        case (ROFF_Fx):
                    636:                /* FALLTHROUGH */
                    637:        case (ROFF_Nx):
                    638:                /* FALLTHROUGH */
1.20      kristaps  639:        case (ROFF_St):
                    640:                /* FALLTHROUGH */
1.15      kristaps  641:        case (ROFF_Ox):
1.20      kristaps  642:                return(mlg_literal_special(p, tok, start,
                    643:                                        argc, argv, more));
                    644:        default:
1.15      kristaps  645:                break;
1.1       kristaps  646:        }
                    647:
1.23      kristaps  648:        return(mlg_err(p, start, start, "`%s' not yet supported",
                    649:                                toknames[tok]));
1.1       kristaps  650: }
                    651:
                    652:
                    653: static int
1.20      kristaps  654: mlg_roffblkin(void *arg, int tok,
                    655:                int *argc, const char **argv)
1.1       kristaps  656: {
                    657:
1.8       kristaps  658:        return(mlg_begintag((struct md_mlg *)arg,
1.2       kristaps  659:                                MD_NS_BLOCK, tok, argc, argv));
                    660: }
                    661:
                    662:
                    663: static int
                    664: mlg_roffblkout(void *arg, int tok)
                    665: {
                    666:
1.9       kristaps  667:        return(mlg_endtag((struct md_mlg *)arg, MD_NS_BLOCK, tok));
1.2       kristaps  668: }
                    669:
                    670:
                    671: static int
1.20      kristaps  672: mlg_roffblkbodyin(void *arg, int tok,
                    673:                int *argc, const char **argv)
1.2       kristaps  674: {
                    675:
1.8       kristaps  676:        return(mlg_begintag((struct md_mlg *)arg,
1.2       kristaps  677:                                MD_NS_BODY, tok, argc, argv));
                    678: }
1.1       kristaps  679:
                    680:
1.2       kristaps  681: static int
                    682: mlg_roffblkbodyout(void *arg, int tok)
                    683: {
1.1       kristaps  684:
1.9       kristaps  685:        return(mlg_endtag((struct md_mlg *)arg, MD_NS_BODY, tok));
1.1       kristaps  686: }
                    687:
                    688:
                    689: static int
1.20      kristaps  690: mlg_roffblkheadin(void *arg, int tok,
                    691:                int *argc, const char **argv)
1.1       kristaps  692: {
                    693:
1.8       kristaps  694:        return(mlg_begintag((struct md_mlg *)arg,
1.2       kristaps  695:                                MD_NS_HEAD, tok, argc, argv));
                    696: }
1.1       kristaps  697:
                    698:
1.2       kristaps  699: static int
                    700: mlg_roffblkheadout(void *arg, int tok)
                    701: {
1.1       kristaps  702:
1.9       kristaps  703:        return(mlg_endtag((struct md_mlg *)arg, MD_NS_HEAD, tok));
1.1       kristaps  704: }
                    705:
                    706:
                    707: static int
1.20      kristaps  708: mlg_roffin(void *arg, int tok, int *argc, const char **argv)
1.1       kristaps  709: {
                    710:
1.8       kristaps  711:        return(mlg_begintag((struct md_mlg *)arg,
                    712:                                MD_NS_INLINE, tok, argc, argv));
1.1       kristaps  713: }
                    714:
                    715:
                    716: static int
                    717: mlg_roffout(void *arg, int tok)
                    718: {
                    719:
1.9       kristaps  720:        return(mlg_endtag((struct md_mlg *)arg, MD_NS_INLINE, tok));
1.1       kristaps  721: }
                    722:
                    723:
1.23      kristaps  724: static int
1.20      kristaps  725: mlg_roffmsg(void *arg, enum roffmsg lvl, const char *buf,
                    726:                const char *pos, const char *msg)
1.1       kristaps  727: {
1.5       kristaps  728:
1.23      kristaps  729:        return(mlg_msg((struct md_mlg *)arg, lvl, buf, pos, msg));
1.5       kristaps  730: }
                    731:
                    732:
                    733: static int
1.20      kristaps  734: mlg_roffdata(void *arg, int space,
                    735:                const char *start, const char *buf)
1.5       kristaps  736: {
1.1       kristaps  737:        struct md_mlg   *p;
                    738:
                    739:        assert(arg);
                    740:        p = (struct md_mlg *)arg;
                    741:
1.5       kristaps  742:        if ( ! mlg_data(p, space, start, buf))
                    743:                return(0);
                    744:
                    745:        mlg_mode(p, MD_TEXT);
                    746:        return(1);
                    747: }
                    748:
                    749:
1.23      kristaps  750: static int
1.13      kristaps  751: mlg_vmsg(struct md_mlg *p, enum roffmsg lvl, const char *start,
                    752:                const char *pos, const char *fmt, va_list ap)
1.5       kristaps  753: {
1.13      kristaps  754:        char             buf[128];
1.5       kristaps  755:
1.13      kristaps  756:        (void)vsnprintf(buf, sizeof(buf), fmt, ap);
1.23      kristaps  757:        return(mlg_msg(p, lvl, start, pos, buf));
1.5       kristaps  758: }
                    759:
                    760:
1.23      kristaps  761: static int
1.13      kristaps  762: mlg_err(struct md_mlg *p, const char *start,
                    763:                const char *pos, const char *fmt, ...)
                    764: {
                    765:        va_list          ap;
1.23      kristaps  766:        int              c;
1.13      kristaps  767:
                    768:        va_start(ap, fmt);
1.23      kristaps  769:        c = mlg_vmsg(p, ROFF_ERROR, start, pos, fmt, ap);
1.13      kristaps  770:        va_end(ap);
1.23      kristaps  771:        return(c);
1.5       kristaps  772: }
                    773:
                    774:
1.23      kristaps  775: static int
1.5       kristaps  776: mlg_msg(struct md_mlg *p, enum roffmsg lvl,
1.20      kristaps  777:                const char *buf, const char *pos, const char *msg)
1.5       kristaps  778: {
                    779:        char            *level;
1.22      kristaps  780:        char             b[256];
                    781:        int              i;
1.5       kristaps  782:
1.1       kristaps  783:        switch (lvl) {
                    784:        case (ROFF_WARN):
1.23      kristaps  785:                level = "warning";
1.1       kristaps  786:                if ( ! (MD_WARN_ALL & p->args->warnings))
1.23      kristaps  787:                        return(1);
1.1       kristaps  788:                break;
                    789:        case (ROFF_ERROR):
                    790:                level = "error";
                    791:                break;
                    792:        default:
                    793:                abort();
1.23      kristaps  794:                /* NOTREACHED */
1.1       kristaps  795:        }
1.22      kristaps  796:
                    797:        if (pos) {
                    798:                assert(pos >= buf);
                    799:                if (0 < p->args->verbosity) {
                    800:                        (void)snprintf(b, sizeof(b),
                    801:                                        "%s:%zu: %s: %s\n",
                    802:                                        p->rbuf->name, p->rbuf->line,
                    803:                                        level, msg);
                    804:                        (void)strlcat(b, "Error at: ", sizeof(b));
                    805:                        (void)strlcat(b, p->rbuf->linebuf, sizeof(b));
                    806:
                    807:                        (void)strlcat(b, "\n          ", sizeof(b));
                    808:                        for (i = 0; i < pos - buf; i++)
                    809:                                (void)strlcat(b, " ", sizeof(b));
                    810:                        (void)strlcat(b, "^", sizeof(b));
                    811:
                    812:                } else
                    813:                        (void)snprintf(b, sizeof(b),
                    814:                                        "%s:%zu: %s: %s (col %zu)",
                    815:                                        p->rbuf->name, p->rbuf->line,
                    816:                                        level, msg, pos - buf);
                    817:        } else
                    818:                (void)snprintf(b, sizeof(b), "%s: %s: %s",
1.1       kristaps  819:                                p->rbuf->name, level, msg);
1.22      kristaps  820:
                    821:        (void)fprintf(stderr, "%s\n", b);
1.23      kristaps  822:        return(lvl == ROFF_WARN ? 1 : 0);
1.1       kristaps  823: }
1.22      kristaps  824:

CVSweb