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

Annotation of mandoc/mlg.c, Revision 1.21

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

CVSweb