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

Annotation of mandoc/mlg.c, Revision 1.20

1.20    ! kristaps    1: /* $Id: mlg.c,v 1.19 2008/12/07 21:30:49 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 *,
                     67:                                const char *, 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);
                    365:        free(p);
1.11      kristaps  366:
                    367:        (*p->cbs.ml_free)(p->data);
                    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,
                    418:                const char *title, const char *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:
        !           465:        lit = ml_literal(tok, argc, argv, more);
        !           466:        assert(lit);
        !           467:
        !           468:        if ( ! ml_puts(p->mbuf, lit, &p->pos))
        !           469:                return(0);
        !           470:        while (*more) {
        !           471:                if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos))
        !           472:                        return(0);
        !           473:                if ( ! mlg_string(p, start, *more++))
        !           474:                        return(0);
        !           475:        }
        !           476:
        !           477:        return(mlg_endtag(p, MD_NS_INLINE, tok));
        !           478: }
        !           479:
        !           480:
        !           481: static int
        !           482: mlg_ref_special(struct md_mlg *p, int tok,
        !           483:                const char *start, const char **more)
        !           484: {
        !           485:
        !           486:        if ( ! mlg_begintag(p, MD_NS_INLINE, tok, NULL, more))
        !           487:                return(0);
        !           488:
        !           489:        assert(*more);
        !           490:        if ( ! ml_puts(p->mbuf, *more++, &p->pos))
        !           491:                return(0);
        !           492:
        !           493:        if (*more) {
        !           494:                if ( ! ml_nputs(p->mbuf, "(", 1, &p->pos))
        !           495:                        return(0);
        !           496:                if ( ! mlg_string(p, start, *more++))
        !           497:                        return(0);
        !           498:                if ( ! ml_nputs(p->mbuf, ")", 1, &p->pos))
        !           499:                        return(0);
        !           500:        }
        !           501:
        !           502:        assert(NULL == *more);
        !           503:        return(mlg_endtag(p, MD_NS_INLINE, tok));
        !           504: }
        !           505:
        !           506:
        !           507: static int
        !           508: mlg_formatted_special(struct md_mlg *p, int tok,
        !           509:                const int *argc, const char **argv, const char **more)
        !           510: {
        !           511:        char             buf[256], *lit;
        !           512:
        !           513:        /* FIXME: *more must be ml-filtered. */
        !           514:
        !           515:        if ( ! mlg_begintag(p, MD_NS_INLINE, tok, NULL, more))
        !           516:                return(0);
        !           517:
        !           518:        lit = ml_literal(tok, argc, argv, more);
        !           519:        assert(lit);
        !           520:        assert(*more);
        !           521:        (void)snprintf(buf, sizeof(buf), lit, *more++);
        !           522:        assert(NULL == *more);
        !           523:
        !           524:        if ( ! ml_puts(p->mbuf, buf, &p->pos))
        !           525:                return(0);
        !           526:
        !           527:        return(mlg_endtag(p, MD_NS_INLINE, tok));
        !           528: }
        !           529:
        !           530:
        !           531: static int
        !           532: mlg_atom_special(struct md_mlg *p, int tok,
        !           533:                const char *start, const char **more)
        !           534: {
        !           535:
        !           536:        if ( ! mlg_begintag(p, MD_NS_INLINE, tok, NULL, more))
        !           537:                return(0);
        !           538:
        !           539:        assert(*more);
        !           540:        if ( ! mlg_string(p, start, *more++))
        !           541:                return(0);
        !           542:
        !           543:        assert(NULL == *more);
        !           544:        return(mlg_endtag(p, MD_NS_INLINE, tok));
        !           545: }
        !           546:
        !           547:
        !           548: static int
        !           549: mlg_function_special(struct md_mlg *p,
        !           550:                const char *start, const char **more)
        !           551: {
        !           552:
        !           553:        assert(*more);
        !           554:
        !           555:        if ( ! mlg_begintag(p, MD_NS_INLINE, ROFF_Fn, NULL, more))
        !           556:                return(0);
        !           557:        if ( ! mlg_string(p, start, *more++))
        !           558:                return(0);
        !           559:        if ( ! mlg_endtag(p, MD_NS_INLINE, ROFF_Fn))
        !           560:                return(0);
        !           561:
        !           562:        if (NULL == *more)
        !           563:                return(1);
        !           564:
        !           565:        if ( ! ml_nputs(p->mbuf, "(", 1, &p->pos))
        !           566:                return(0);
        !           567:
        !           568:        p->flags |= ML_OVERRIDE_ONE;
        !           569:
        !           570:        if ( ! mlg_begintag(p, MD_NS_INLINE, ROFF_Fa, NULL, more))
        !           571:                return(0);
        !           572:        if ( ! mlg_string(p, start, *more++))
        !           573:                return(0);
        !           574:        if ( ! mlg_endtag(p, MD_NS_INLINE, ROFF_Fa))
        !           575:                return(0);
        !           576:
        !           577:        while (*more) {
        !           578:                if ( ! ml_nputs(p->mbuf, ", ", 2, &p->pos))
        !           579:                        return(0);
        !           580:                if ( ! mlg_begintag(p, MD_NS_INLINE, ROFF_Fa, NULL, more))
        !           581:                        return(0);
        !           582:                if ( ! mlg_string(p, start, *more++))
        !           583:                        return(0);
        !           584:                if ( ! mlg_endtag(p, MD_NS_INLINE, ROFF_Fa))
        !           585:                        return(0);
        !           586:        }
        !           587:
        !           588:        return(ml_nputs(p->mbuf, ")", 1, &p->pos));
        !           589: }
        !           590:
        !           591:
1.16      kristaps  592: /* ARGSUSED */
1.1       kristaps  593: static int
1.16      kristaps  594: mlg_roffspecial(void *arg, int tok, const char *start,
1.20    ! kristaps  595:                const int *argc, const char **argv, const char **more)
1.1       kristaps  596: {
                    597:        struct md_mlg   *p;
                    598:
                    599:        assert(arg);
                    600:        p = (struct md_mlg *)arg;
                    601:
                    602:        switch (tok) {
1.15      kristaps  603:        case (ROFF_Ns):
                    604:                p->flags |= ML_OVERRIDE_ONE;
                    605:                return(1);
1.20    ! kristaps  606:
1.15      kristaps  607:        case (ROFF_Sm):
                    608:                assert(*more);
                    609:                if (0 == strcmp(*more, "on"))
                    610:                        p->flags |= ML_OVERRIDE_ALL;
                    611:                else
                    612:                        p->flags &= ~ML_OVERRIDE_ALL;
                    613:                return(1);
1.18      kristaps  614:
                    615:        case (ROFF_Fn):
1.20    ! kristaps  616:                return(mlg_function_special(p, start, more));
1.16      kristaps  617:
1.8       kristaps  618:        case (ROFF_Xr):
1.20    ! kristaps  619:                return(mlg_ref_special(p, tok, start, more));
        !           620:
        !           621:        case (ROFF_Sx): /* FIXME */
1.15      kristaps  622:                /* FALLTHROUGH */
1.12      kristaps  623:        case (ROFF_Nm):
1.20    ! kristaps  624:                return(mlg_atom_special(p, tok, start, more));
1.18      kristaps  625:
                    626:        case (ROFF_In):
                    627:                /* NOTREACHED */
1.13      kristaps  628:        case (ROFF_Ex):
1.17      kristaps  629:                /* NOTREACHED */
                    630:        case (ROFF_Rv):
1.20    ! kristaps  631:                return(mlg_formatted_special(p, tok,
        !           632:                                        argc, argv, more));
1.19      kristaps  633:
1.15      kristaps  634:        case (ROFF_At):
1.20    ! kristaps  635:                /* FALLTHROUGH */
        !           636:        case (ROFF_Bt):
        !           637:                /* FALLTHROUGH */
        !           638:        case (ROFF_Ud):
        !           639:                /* FALLTHROUGH */
        !           640:        case (ROFF_Ux):
        !           641:                /* FALLTHROUGH */
1.15      kristaps  642:        case (ROFF_Bx):
                    643:                /* FALLTHROUGH */
                    644:        case (ROFF_Bsx):
                    645:                /* FALLTHROUGH */
                    646:        case (ROFF_Fx):
                    647:                /* FALLTHROUGH */
                    648:        case (ROFF_Nx):
                    649:                /* FALLTHROUGH */
1.20    ! kristaps  650:        case (ROFF_St):
        !           651:                /* FALLTHROUGH */
1.15      kristaps  652:        case (ROFF_Ox):
1.20    ! kristaps  653:                return(mlg_literal_special(p, tok, start,
        !           654:                                        argc, argv, more));
        !           655:        default:
1.15      kristaps  656:                break;
1.1       kristaps  657:        }
                    658:
1.20    ! kristaps  659:        mlg_err(p, start, start, "`%s' not yet supported",
        !           660:                        toknames[tok]);
        !           661:        return(0);
1.1       kristaps  662: }
                    663:
                    664:
                    665: static int
1.20    ! kristaps  666: mlg_roffblkin(void *arg, int tok,
        !           667:                int *argc, const char **argv)
1.1       kristaps  668: {
                    669:
1.8       kristaps  670:        return(mlg_begintag((struct md_mlg *)arg,
1.2       kristaps  671:                                MD_NS_BLOCK, tok, argc, argv));
                    672: }
                    673:
                    674:
                    675: static int
                    676: mlg_roffblkout(void *arg, int tok)
                    677: {
                    678:
1.9       kristaps  679:        return(mlg_endtag((struct md_mlg *)arg, MD_NS_BLOCK, tok));
1.2       kristaps  680: }
                    681:
                    682:
                    683: static int
1.20    ! kristaps  684: mlg_roffblkbodyin(void *arg, int tok,
        !           685:                int *argc, const char **argv)
1.2       kristaps  686: {
                    687:
1.8       kristaps  688:        return(mlg_begintag((struct md_mlg *)arg,
1.2       kristaps  689:                                MD_NS_BODY, tok, argc, argv));
                    690: }
1.1       kristaps  691:
                    692:
1.2       kristaps  693: static int
                    694: mlg_roffblkbodyout(void *arg, int tok)
                    695: {
1.1       kristaps  696:
1.9       kristaps  697:        return(mlg_endtag((struct md_mlg *)arg, MD_NS_BODY, tok));
1.1       kristaps  698: }
                    699:
                    700:
                    701: static int
1.20    ! kristaps  702: mlg_roffblkheadin(void *arg, int tok,
        !           703:                int *argc, const char **argv)
1.1       kristaps  704: {
                    705:
1.8       kristaps  706:        return(mlg_begintag((struct md_mlg *)arg,
1.2       kristaps  707:                                MD_NS_HEAD, tok, argc, argv));
                    708: }
1.1       kristaps  709:
                    710:
1.2       kristaps  711: static int
                    712: mlg_roffblkheadout(void *arg, int tok)
                    713: {
1.1       kristaps  714:
1.9       kristaps  715:        return(mlg_endtag((struct md_mlg *)arg, MD_NS_HEAD, tok));
1.1       kristaps  716: }
                    717:
                    718:
                    719: static int
1.20    ! kristaps  720: mlg_roffin(void *arg, int tok, int *argc, const char **argv)
1.1       kristaps  721: {
                    722:
1.8       kristaps  723:        return(mlg_begintag((struct md_mlg *)arg,
                    724:                                MD_NS_INLINE, tok, argc, argv));
1.1       kristaps  725: }
                    726:
                    727:
                    728: static int
                    729: mlg_roffout(void *arg, int tok)
                    730: {
                    731:
1.9       kristaps  732:        return(mlg_endtag((struct md_mlg *)arg, MD_NS_INLINE, tok));
1.1       kristaps  733: }
                    734:
                    735:
                    736: static void
1.20    ! kristaps  737: mlg_roffmsg(void *arg, enum roffmsg lvl, const char *buf,
        !           738:                const char *pos, const char *msg)
1.1       kristaps  739: {
1.5       kristaps  740:
                    741:        mlg_msg((struct md_mlg *)arg, lvl, buf, pos, msg);
                    742: }
                    743:
                    744:
                    745: static int
1.20    ! kristaps  746: mlg_roffdata(void *arg, int space,
        !           747:                const char *start, const char *buf)
1.5       kristaps  748: {
1.1       kristaps  749:        struct md_mlg   *p;
                    750:
                    751:        assert(arg);
                    752:        p = (struct md_mlg *)arg;
                    753:
1.5       kristaps  754:        if ( ! mlg_data(p, space, start, buf))
                    755:                return(0);
                    756:
                    757:        mlg_mode(p, MD_TEXT);
                    758:        return(1);
                    759: }
                    760:
                    761:
                    762: static void
1.13      kristaps  763: mlg_vmsg(struct md_mlg *p, enum roffmsg lvl, const char *start,
                    764:                const char *pos, const char *fmt, va_list ap)
1.5       kristaps  765: {
1.13      kristaps  766:        char             buf[128];
1.5       kristaps  767:
1.13      kristaps  768:        (void)vsnprintf(buf, sizeof(buf), fmt, ap);
                    769:        mlg_msg(p, lvl, start, pos, buf);
1.5       kristaps  770: }
                    771:
                    772:
                    773: static void
1.13      kristaps  774: mlg_err(struct md_mlg *p, const char *start,
                    775:                const char *pos, const char *fmt, ...)
                    776: {
                    777:        va_list          ap;
                    778:
                    779:        va_start(ap, fmt);
                    780:        mlg_vmsg(p, ROFF_ERROR, start, pos, fmt, ap);
                    781:        va_end(ap);
1.5       kristaps  782: }
                    783:
                    784:
                    785: static void
                    786: mlg_msg(struct md_mlg *p, enum roffmsg lvl,
1.20    ! kristaps  787:                const char *buf, const char *pos, const char *msg)
1.5       kristaps  788: {
                    789:        char            *level;
                    790:
1.1       kristaps  791:        switch (lvl) {
                    792:        case (ROFF_WARN):
                    793:                if ( ! (MD_WARN_ALL & p->args->warnings))
                    794:                        return;
                    795:                level = "warning";
                    796:                break;
                    797:        case (ROFF_ERROR):
                    798:                level = "error";
                    799:                break;
                    800:        default:
                    801:                abort();
                    802:        }
                    803:
                    804:        if (pos)
                    805:                (void)fprintf(stderr, "%s:%zu: %s: %s (column %zu)\n",
                    806:                                p->rbuf->name, p->rbuf->line, level,
                    807:                                msg, pos - buf);
                    808:        else
                    809:                (void)fprintf(stderr, "%s: %s: %s\n",
                    810:                                p->rbuf->name, level, msg);
                    811: }

CVSweb