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

Annotation of mandoc/mlg.c, Revision 1.28

1.28    ! kristaps    1: /* $Id: mlg.c,v 1.27 2008/12/10 12:09:47 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 {
                     40:        const struct md_args    *args;
                     41:        const struct md_rbuf    *rbuf;
                     42:
                     43:        struct md_mbuf   *mbuf;
                     44:        struct rofftree  *tree;
                     45:        size_t            indent;
                     46:        size_t            pos;
                     47:        enum md_tok       last;
                     48:        void             *arg;
1.11      kristaps   49:        struct ml_cbs     cbs;
1.1       kristaps   50:        int               flags;
                     51: #define        ML_OVERRIDE_ONE  (1 << 0)
                     52: #define        ML_OVERRIDE_ALL  (1 << 1)
1.10      kristaps   53:        void             *data;
1.1       kristaps   54: };
                     55:
1.23      kristaps   56: static int              mlg_roffmsg(void *arg,
1.20      kristaps   57:                                enum roffmsg, const char *,
                     58:                                const char *, const char *);
1.4       kristaps   59: static int              mlg_roffhead(void *, const struct tm *,
                     60:                                const char *, const char *,
1.25      kristaps   61:                                enum roffmsec, enum roffvol);
1.26      kristaps   62: static int              mlg_rofftail(void *, const struct tm *,
                     63:                                const char *, const char *,
                     64:                                enum roffmsec, enum roffvol);
1.20      kristaps   65: static int              mlg_roffin(void *, int,
                     66:                                int *, const char **);
1.5       kristaps   67: static int              mlg_roffdata(void *, int,
1.20      kristaps   68:                                const char *, const char *);
1.1       kristaps   69: static int              mlg_roffout(void *, int);
1.20      kristaps   70: static int              mlg_roffblkin(void *, int, int *,
                     71:                                const char **);
1.1       kristaps   72: static int              mlg_roffblkout(void *, int);
1.8       kristaps   73: static int              mlg_roffspecial(void *, int,
1.16      kristaps   74:                                const char *, const int *,
1.20      kristaps   75:                                const char **, const char **);
1.5       kristaps   76: static int              mlg_roffblkheadin(void *, int,
1.20      kristaps   77:                                int *, const char **);
1.2       kristaps   78: static int              mlg_roffblkheadout(void *, int);
1.5       kristaps   79: static int              mlg_roffblkbodyin(void *, int,
1.20      kristaps   80:                                int *, const char **);
1.2       kristaps   81: static int              mlg_roffblkbodyout(void *, int);
                     82:
1.20      kristaps   83: static int              mlg_ref_special(struct md_mlg *, int,
                     84:                                const char *, const char **);
                     85: static int              mlg_formatted_special(struct md_mlg *,
1.23      kristaps   86:                                int, const char *, const int *,
1.20      kristaps   87:                                const char **, const char **);
                     88: static int              mlg_literal_special(struct md_mlg *,
                     89:                                int,  const char *, const int *,
                     90:                                const char **, const char **);
                     91: static int              mlg_function_special(struct md_mlg *,
                     92:                                const char *, const char **);
                     93: static int              mlg_atom_special(struct md_mlg *, int,
                     94:                                const char *, const char **);
1.28    ! kristaps   95: static int              mlg_link_special(struct md_mlg *, int,
        !            96:                                const char *, const char **);
        !            97: static int              mlg_anchor_special(struct md_mlg *,
        !            98:                                int, const char **);
1.20      kristaps   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.23      kristaps  112: static int              mlg_err(struct md_mlg *, const char *,
1.13      kristaps  113:                                const char *, const char *, ...);
1.23      kristaps  114: static int              mlg_msg(struct md_mlg *,
1.20      kristaps  115:                                enum roffmsg, const char *,
                    116:                                const char *, const char *);
1.23      kristaps  117: static int              mlg_vmsg(struct md_mlg *, enum roffmsg,
1.13      kristaps  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:
                    244:        assert(0 == p->pos);
1.24      kristaps  245:        return(ml_putchars(p->mbuf, ' ', INDENT_SZ *
                    246:                                INDENT(p->indent), &p->pos));
1.1       kristaps  247: }
                    248:
                    249:
                    250: static int
                    251: mlg_newline(struct md_mlg *p)
                    252: {
                    253:
                    254:        p->pos = 0;
1.11      kristaps  255:        return(ml_nputs(p->mbuf, "\n", 1, NULL));
1.1       kristaps  256: }
                    257:
                    258:
                    259: static void
                    260: mlg_mode(struct md_mlg *p, enum md_tok ns)
                    261: {
1.3       kristaps  262:
1.1       kristaps  263:        p->flags &= ~ML_OVERRIDE_ONE;
                    264:        p->last = ns;
                    265: }
                    266:
                    267:
                    268: static int
1.19      kristaps  269: mlg_string(struct md_mlg *p, const char *start, const char *buf)
                    270: {
                    271:
                    272:        return(mlg_nstring(p, start, buf, strlen(buf)));
                    273: }
                    274:
                    275:
                    276: static int
                    277: mlg_nstring(struct md_mlg *p, const char *start,
                    278:                const char *buf, size_t sz)
                    279: {
                    280:        int              c;
                    281:        ssize_t          res;
                    282:
                    283:        assert(p->mbuf);
                    284:        assert(0 != p->indent);
                    285:
                    286:        res = (*p->cbs.ml_beginstring)(p->mbuf, p->args, buf, sz);
                    287:        if (-1 == res)
                    288:                return(0);
                    289:
1.23      kristaps  290:        if (0 == (c = ml_nputstring(p->mbuf, buf, sz, &p->pos)))
                    291:                return(mlg_err(p, start, buf, "bad string "
                    292:                                        "encoding: `%s'", buf));
                    293:        else if (-1 == c)
1.19      kristaps  294:                return(0);
                    295:
                    296:        res = (*p->cbs.ml_endstring)(p->mbuf, p->args, buf, sz);
                    297:        if (-1 == res)
                    298:                return(0);
                    299:
                    300:        return(1);
                    301: }
                    302:
                    303:
                    304: static int
1.20      kristaps  305: mlg_data(struct md_mlg *p, int space,
                    306:                const char *start, const char *buf)
1.1       kristaps  307: {
                    308:        size_t           sz;
                    309:
                    310:        assert(p->mbuf);
                    311:        assert(0 != p->indent);
                    312:
                    313:        if (ML_OVERRIDE_ONE & p->flags ||
                    314:                        ML_OVERRIDE_ALL & p->flags)
                    315:                space = 0;
                    316:
1.8       kristaps  317:        sz = strlen(buf);
1.1       kristaps  318:
1.8       kristaps  319:        if (0 == p->pos) {
                    320:                if ( ! mlg_indent(p))
                    321:                        return(0);
1.19      kristaps  322:                if ( ! mlg_nstring(p, start, buf, sz))
1.8       kristaps  323:                        return(0);
1.1       kristaps  324:
1.24      kristaps  325:                if (INDENT(p->indent) * INDENT_SZ + sz >= COLUMNS)
1.8       kristaps  326:                        if ( ! mlg_newline(p))
1.1       kristaps  327:                                return(0);
1.5       kristaps  328:
1.8       kristaps  329:                return(1);
                    330:        }
1.5       kristaps  331:
1.8       kristaps  332:        if (space && sz + p->pos >= COLUMNS) {
                    333:                if ( ! mlg_newline(p))
1.5       kristaps  334:                        return(0);
1.8       kristaps  335:                if ( ! mlg_indent(p))
1.5       kristaps  336:                        return(0);
1.8       kristaps  337:        } else if (space) {
                    338:                if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos))
1.1       kristaps  339:                        return(0);
1.8       kristaps  340:        }
1.1       kristaps  341:
1.19      kristaps  342:        return(mlg_nstring(p, start, buf, sz));
1.1       kristaps  343: }
                    344:
                    345:
                    346: int
                    347: mlg_line(struct md_mlg *p, char *buf)
                    348: {
                    349:
                    350:        return(roff_engine(p->tree, buf));
                    351: }
                    352:
                    353:
                    354: int
                    355: mlg_exit(struct md_mlg *p, int flush)
                    356: {
                    357:        int              c;
                    358:
                    359:        c = roff_free(p->tree, flush);
1.21      kristaps  360:        (*p->cbs.ml_free)(p->data);
                    361:
1.1       kristaps  362:        free(p);
1.11      kristaps  363:
1.1       kristaps  364:        return(c);
                    365: }
                    366:
                    367:
                    368: struct md_mlg *
1.11      kristaps  369: mlg_alloc(const struct md_args *args,
1.1       kristaps  370:                const struct md_rbuf *rbuf,
                    371:                struct md_mbuf *mbuf,
1.11      kristaps  372:                const struct ml_cbs *cbs)
1.1       kristaps  373: {
                    374:        struct roffcb    cb;
                    375:        struct md_mlg   *p;
                    376:
                    377:        cb.roffhead = mlg_roffhead;
                    378:        cb.rofftail = mlg_rofftail;
                    379:        cb.roffin = mlg_roffin;
                    380:        cb.roffout = mlg_roffout;
                    381:        cb.roffblkin = mlg_roffblkin;
1.2       kristaps  382:        cb.roffblkheadin = mlg_roffblkheadin;
                    383:        cb.roffblkheadout = mlg_roffblkheadout;
                    384:        cb.roffblkbodyin = mlg_roffblkbodyin;
                    385:        cb.roffblkbodyout = mlg_roffblkbodyout;
1.1       kristaps  386:        cb.roffblkout = mlg_roffblkout;
                    387:        cb.roffspecial = mlg_roffspecial;
                    388:        cb.roffmsg = mlg_roffmsg;
                    389:        cb.roffdata = mlg_roffdata;
                    390:
                    391:        if (NULL == (p = calloc(1, sizeof(struct md_mlg))))
                    392:                err(1, "calloc");
                    393:
                    394:        p->args = args;
                    395:        p->mbuf = mbuf;
                    396:        p->rbuf = rbuf;
                    397:
1.11      kristaps  398:        (void)memcpy(&p->cbs, cbs, sizeof(struct ml_cbs));
                    399:
                    400:        if (NULL == (p->tree = roff_alloc(&cb, p)))
                    401:                free(p);
                    402:        else if ( ! (*p->cbs.ml_alloc)(&p->data))
1.1       kristaps  403:                free(p);
1.11      kristaps  404:        else
                    405:                return(p);
1.1       kristaps  406:
1.11      kristaps  407:        return(NULL);
1.1       kristaps  408: }
                    409:
                    410:
                    411: static int
1.4       kristaps  412: mlg_roffhead(void *arg, const struct tm *tm, const char *os,
1.25      kristaps  413:                const char *title, enum roffmsec sec, enum roffvol vol)
1.1       kristaps  414: {
                    415:        struct md_mlg   *p;
                    416:
                    417:        assert(arg);
                    418:        p = (struct md_mlg *)arg;
                    419:
                    420:        mlg_mode(p, MD_BLK_IN);
1.11      kristaps  421:
1.26      kristaps  422:        if ( ! (*p->cbs.ml_begin)(p->mbuf, p->args,
                    423:                                tm, os, title, sec, vol))
1.1       kristaps  424:                return(0);
                    425:
                    426:        p->indent++;
                    427:        return(mlg_newline(p));
                    428: }
                    429:
                    430:
                    431: static int
1.26      kristaps  432: mlg_rofftail(void *arg, const struct tm *tm, const char *os,
                    433:                const char *title, enum roffmsec sec, enum roffvol vol)
1.1       kristaps  434: {
                    435:        struct md_mlg   *p;
                    436:
                    437:        assert(arg);
                    438:        p = (struct md_mlg *)arg;
                    439:
1.11      kristaps  440:        if (0 != p->pos)
                    441:                if ( ! mlg_newline(p))
                    442:                        return(0);
                    443:
1.26      kristaps  444:        if ( ! (*p->cbs.ml_end)(p->mbuf, p->args,
                    445:                                tm, os, title, sec, vol))
1.1       kristaps  446:                return(0);
                    447:
                    448:        mlg_mode(p, MD_BLK_OUT);
                    449:        return(mlg_newline(p));
                    450: }
                    451:
                    452:
1.20      kristaps  453: static int
                    454: mlg_literal_special(struct md_mlg *p, int tok, const char *start,
                    455:                const int *argc, const char **argv, const char **more)
                    456: {
                    457:        char             *lit;
                    458:
                    459:        if ( ! mlg_begintag(p, MD_NS_INLINE, tok, NULL, more))
                    460:                return(0);
                    461:
1.23      kristaps  462:        lit = roff_literal(tok, argc, argv, more);
1.20      kristaps  463:        assert(lit);
                    464:
1.23      kristaps  465:        if ( ! mlg_string(p, start, lit))
1.20      kristaps  466:                return(0);
1.23      kristaps  467:
1.20      kristaps  468:        while (*more) {
                    469:                if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos))
                    470:                        return(0);
                    471:                if ( ! mlg_string(p, start, *more++))
                    472:                        return(0);
                    473:        }
                    474:
                    475:        return(mlg_endtag(p, MD_NS_INLINE, tok));
                    476: }
                    477:
                    478:
                    479: static int
                    480: mlg_ref_special(struct md_mlg *p, int tok,
                    481:                const char *start, const char **more)
                    482: {
                    483:
                    484:        if ( ! mlg_begintag(p, MD_NS_INLINE, tok, NULL, more))
                    485:                return(0);
                    486:
                    487:        assert(*more);
                    488:        if ( ! ml_puts(p->mbuf, *more++, &p->pos))
                    489:                return(0);
                    490:
                    491:        if (*more) {
                    492:                if ( ! ml_nputs(p->mbuf, "(", 1, &p->pos))
                    493:                        return(0);
                    494:                if ( ! mlg_string(p, start, *more++))
                    495:                        return(0);
                    496:                if ( ! ml_nputs(p->mbuf, ")", 1, &p->pos))
                    497:                        return(0);
                    498:        }
                    499:
                    500:        assert(NULL == *more);
                    501:        return(mlg_endtag(p, MD_NS_INLINE, tok));
                    502: }
                    503:
                    504:
1.27      kristaps  505: /* ARGSUSED */
1.20      kristaps  506: static int
1.23      kristaps  507: mlg_formatted_special(struct md_mlg *p, int tok, const char *start,
1.20      kristaps  508:                const int *argc, const char **argv, const char **more)
                    509: {
                    510:        char             buf[256], *lit;
                    511:
                    512:        if ( ! mlg_begintag(p, MD_NS_INLINE, tok, NULL, more))
                    513:                return(0);
                    514:
1.23      kristaps  515:        lit = roff_fmtstring(tok);
1.21      kristaps  516:
1.20      kristaps  517:        assert(lit);
                    518:        assert(*more);
                    519:        (void)snprintf(buf, sizeof(buf), lit, *more++);
                    520:        assert(NULL == *more);
                    521:
1.23      kristaps  522:        if ( ! mlg_string(p, start, buf))
1.20      kristaps  523:                return(0);
                    524:
                    525:        return(mlg_endtag(p, MD_NS_INLINE, tok));
                    526: }
                    527:
                    528:
                    529: static int
                    530: mlg_atom_special(struct md_mlg *p, int tok,
                    531:                const char *start, const char **more)
                    532: {
                    533:
                    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:
                    562:        if ( ! ml_nputs(p->mbuf, "(", 1, &p->pos))
                    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) {
                    575:                if ( ! ml_nputs(p->mbuf, ", ", 2, &p->pos))
                    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:
                    585:        return(ml_nputs(p->mbuf, ")", 1, &p->pos));
                    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):
        !           647:                return(mlg_anchor_special(p, tok, more));
1.20      kristaps  648:
1.28    ! kristaps  649:        case (ROFF_Sx):
        !           650:                return(mlg_link_special(p, tok, start, more));
        !           651:
1.12      kristaps  652:        case (ROFF_Nm):
1.20      kristaps  653:                return(mlg_atom_special(p, tok, start, more));
1.18      kristaps  654:
                    655:        case (ROFF_In):
                    656:                /* NOTREACHED */
1.13      kristaps  657:        case (ROFF_Ex):
1.17      kristaps  658:                /* NOTREACHED */
                    659:        case (ROFF_Rv):
1.23      kristaps  660:                return(mlg_formatted_special(p, tok, start,
1.20      kristaps  661:                                        argc, argv, more));
1.19      kristaps  662:
1.15      kristaps  663:        case (ROFF_At):
1.20      kristaps  664:                /* FALLTHROUGH */
                    665:        case (ROFF_Bt):
                    666:                /* FALLTHROUGH */
                    667:        case (ROFF_Ud):
                    668:                /* FALLTHROUGH */
                    669:        case (ROFF_Ux):
                    670:                /* FALLTHROUGH */
1.15      kristaps  671:        case (ROFF_Bx):
                    672:                /* FALLTHROUGH */
                    673:        case (ROFF_Bsx):
                    674:                /* FALLTHROUGH */
                    675:        case (ROFF_Fx):
                    676:                /* FALLTHROUGH */
                    677:        case (ROFF_Nx):
                    678:                /* FALLTHROUGH */
1.20      kristaps  679:        case (ROFF_St):
                    680:                /* FALLTHROUGH */
1.15      kristaps  681:        case (ROFF_Ox):
1.20      kristaps  682:                return(mlg_literal_special(p, tok, start,
                    683:                                        argc, argv, more));
                    684:        default:
1.15      kristaps  685:                break;
1.1       kristaps  686:        }
                    687:
1.23      kristaps  688:        return(mlg_err(p, start, start, "`%s' not yet supported",
                    689:                                toknames[tok]));
1.1       kristaps  690: }
                    691:
                    692:
                    693: static int
1.20      kristaps  694: mlg_roffblkin(void *arg, int tok,
                    695:                int *argc, const char **argv)
1.1       kristaps  696: {
                    697:
1.8       kristaps  698:        return(mlg_begintag((struct md_mlg *)arg,
1.2       kristaps  699:                                MD_NS_BLOCK, tok, argc, argv));
                    700: }
                    701:
                    702:
                    703: static int
                    704: mlg_roffblkout(void *arg, int tok)
                    705: {
                    706:
1.9       kristaps  707:        return(mlg_endtag((struct md_mlg *)arg, MD_NS_BLOCK, tok));
1.2       kristaps  708: }
                    709:
                    710:
                    711: static int
1.20      kristaps  712: mlg_roffblkbodyin(void *arg, int tok,
                    713:                int *argc, const char **argv)
1.2       kristaps  714: {
                    715:
1.8       kristaps  716:        return(mlg_begintag((struct md_mlg *)arg,
1.2       kristaps  717:                                MD_NS_BODY, tok, argc, argv));
                    718: }
1.1       kristaps  719:
                    720:
1.2       kristaps  721: static int
                    722: mlg_roffblkbodyout(void *arg, int tok)
                    723: {
1.1       kristaps  724:
1.9       kristaps  725:        return(mlg_endtag((struct md_mlg *)arg, MD_NS_BODY, tok));
1.1       kristaps  726: }
                    727:
                    728:
                    729: static int
1.20      kristaps  730: mlg_roffblkheadin(void *arg, int tok,
                    731:                int *argc, const char **argv)
1.1       kristaps  732: {
                    733:
1.8       kristaps  734:        return(mlg_begintag((struct md_mlg *)arg,
1.2       kristaps  735:                                MD_NS_HEAD, tok, argc, argv));
                    736: }
1.1       kristaps  737:
                    738:
1.2       kristaps  739: static int
                    740: mlg_roffblkheadout(void *arg, int tok)
                    741: {
1.1       kristaps  742:
1.9       kristaps  743:        return(mlg_endtag((struct md_mlg *)arg, MD_NS_HEAD, tok));
1.1       kristaps  744: }
                    745:
                    746:
                    747: static int
1.20      kristaps  748: mlg_roffin(void *arg, int tok, int *argc, const char **argv)
1.1       kristaps  749: {
                    750:
1.8       kristaps  751:        return(mlg_begintag((struct md_mlg *)arg,
                    752:                                MD_NS_INLINE, tok, argc, argv));
1.1       kristaps  753: }
                    754:
                    755:
                    756: static int
                    757: mlg_roffout(void *arg, int tok)
                    758: {
                    759:
1.9       kristaps  760:        return(mlg_endtag((struct md_mlg *)arg, MD_NS_INLINE, tok));
1.1       kristaps  761: }
                    762:
                    763:
1.23      kristaps  764: static int
1.20      kristaps  765: mlg_roffmsg(void *arg, enum roffmsg lvl, const char *buf,
                    766:                const char *pos, const char *msg)
1.1       kristaps  767: {
1.5       kristaps  768:
1.23      kristaps  769:        return(mlg_msg((struct md_mlg *)arg, lvl, buf, pos, msg));
1.5       kristaps  770: }
                    771:
                    772:
                    773: static int
1.20      kristaps  774: mlg_roffdata(void *arg, int space,
                    775:                const char *start, const char *buf)
1.5       kristaps  776: {
1.1       kristaps  777:        struct md_mlg   *p;
                    778:
                    779:        assert(arg);
                    780:        p = (struct md_mlg *)arg;
                    781:
1.5       kristaps  782:        if ( ! mlg_data(p, space, start, buf))
                    783:                return(0);
                    784:
                    785:        mlg_mode(p, MD_TEXT);
                    786:        return(1);
                    787: }
                    788:
                    789:
1.23      kristaps  790: static int
1.13      kristaps  791: mlg_vmsg(struct md_mlg *p, enum roffmsg lvl, const char *start,
                    792:                const char *pos, const char *fmt, va_list ap)
1.5       kristaps  793: {
1.13      kristaps  794:        char             buf[128];
1.5       kristaps  795:
1.13      kristaps  796:        (void)vsnprintf(buf, sizeof(buf), fmt, ap);
1.23      kristaps  797:        return(mlg_msg(p, lvl, start, pos, buf));
1.5       kristaps  798: }
                    799:
                    800:
1.23      kristaps  801: static int
1.13      kristaps  802: mlg_err(struct md_mlg *p, const char *start,
                    803:                const char *pos, const char *fmt, ...)
                    804: {
                    805:        va_list          ap;
1.23      kristaps  806:        int              c;
1.13      kristaps  807:
                    808:        va_start(ap, fmt);
1.23      kristaps  809:        c = mlg_vmsg(p, ROFF_ERROR, start, pos, fmt, ap);
1.13      kristaps  810:        va_end(ap);
1.23      kristaps  811:        return(c);
1.5       kristaps  812: }
                    813:
                    814:
1.23      kristaps  815: static int
1.5       kristaps  816: mlg_msg(struct md_mlg *p, enum roffmsg lvl,
1.20      kristaps  817:                const char *buf, const char *pos, const char *msg)
1.5       kristaps  818: {
                    819:        char            *level;
1.22      kristaps  820:        char             b[256];
                    821:        int              i;
1.5       kristaps  822:
1.1       kristaps  823:        switch (lvl) {
                    824:        case (ROFF_WARN):
1.23      kristaps  825:                level = "warning";
1.1       kristaps  826:                if ( ! (MD_WARN_ALL & p->args->warnings))
1.23      kristaps  827:                        return(1);
1.1       kristaps  828:                break;
                    829:        case (ROFF_ERROR):
                    830:                level = "error";
                    831:                break;
                    832:        default:
                    833:                abort();
1.23      kristaps  834:                /* NOTREACHED */
1.1       kristaps  835:        }
1.22      kristaps  836:
                    837:        if (pos) {
                    838:                assert(pos >= buf);
                    839:                if (0 < p->args->verbosity) {
                    840:                        (void)snprintf(b, sizeof(b),
                    841:                                        "%s:%zu: %s: %s\n",
                    842:                                        p->rbuf->name, p->rbuf->line,
                    843:                                        level, msg);
                    844:                        (void)strlcat(b, "Error at: ", sizeof(b));
                    845:                        (void)strlcat(b, p->rbuf->linebuf, sizeof(b));
                    846:
                    847:                        (void)strlcat(b, "\n          ", sizeof(b));
                    848:                        for (i = 0; i < pos - buf; i++)
                    849:                                (void)strlcat(b, " ", sizeof(b));
                    850:                        (void)strlcat(b, "^", sizeof(b));
                    851:
                    852:                } else
                    853:                        (void)snprintf(b, sizeof(b),
                    854:                                        "%s:%zu: %s: %s (col %zu)",
                    855:                                        p->rbuf->name, p->rbuf->line,
                    856:                                        level, msg, pos - buf);
                    857:        } else
                    858:                (void)snprintf(b, sizeof(b), "%s: %s: %s",
1.1       kristaps  859:                                p->rbuf->name, level, msg);
1.22      kristaps  860:
                    861:        (void)fprintf(stderr, "%s\n", b);
1.23      kristaps  862:        return(lvl == ROFF_WARN ? 1 : 0);
1.1       kristaps  863: }
1.22      kristaps  864:

CVSweb