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

Annotation of mandoc/mlg.c, Revision 1.29

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

CVSweb