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

Annotation of mandoc/mlg.c, Revision 1.19

1.19    ! kristaps    1: /* $Id: mlg.c,v 1.18 2008/12/07 16:41:04 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:
                     62:
1.15      kristaps   63: static char            *mlg_literal(int);
                     64: static char            *mlg_At_literal(const char *);
1.17      kristaps   65: static char            *mlg_fmt(int);
1.16      kristaps   66: static char            *mlg_St_literal(int);
1.1       kristaps   67: static void             mlg_roffmsg(void *arg, enum roffmsg,
                     68:                                const char *, const char *, char *);
1.4       kristaps   69: static int              mlg_roffhead(void *, const struct tm *,
                     70:                                const char *, const char *,
                     71:                                const char *, const char *);
1.1       kristaps   72: static int              mlg_rofftail(void *);
                     73: static int              mlg_roffin(void *, int, int *, char **);
1.5       kristaps   74: static int              mlg_roffdata(void *, int,
                     75:                                const char *, char *);
1.1       kristaps   76: static int              mlg_roffout(void *, int);
                     77: static int              mlg_roffblkin(void *, int, int *, char **);
                     78: static int              mlg_roffblkout(void *, int);
1.8       kristaps   79: static int              mlg_roffspecial(void *, int,
1.16      kristaps   80:                                const char *, const int *,
                     81:                                const char **, char **);
1.5       kristaps   82: static int              mlg_roffblkheadin(void *, int,
                     83:                                int *, char **);
1.2       kristaps   84: static int              mlg_roffblkheadout(void *, int);
1.5       kristaps   85: static int              mlg_roffblkbodyin(void *, int,
                     86:                                int *, char **);
1.2       kristaps   87: static int              mlg_roffblkbodyout(void *, int);
                     88:
1.1       kristaps   89: static int              mlg_begintag(struct md_mlg *, enum md_ns,
                     90:                                int, int *, char **);
                     91: static int              mlg_endtag(struct md_mlg *, enum md_ns, int);
                     92: static int              mlg_indent(struct md_mlg *);
                     93: static int              mlg_newline(struct md_mlg *);
                     94: static void             mlg_mode(struct md_mlg *, enum md_tok);
1.19    ! kristaps   95: static int              mlg_nstring(struct md_mlg *,
        !            96:                                const char *, const char *, size_t);
        !            97: static int              mlg_string(struct md_mlg *,
        !            98:                                const char *, const char *);
1.5       kristaps   99: static int              mlg_data(struct md_mlg *, int,
                    100:                                const char *, char *);
                    101: static void             mlg_err(struct md_mlg *, const char *,
1.13      kristaps  102:                                const char *, const char *, ...);
1.5       kristaps  103: static void             mlg_msg(struct md_mlg *, enum roffmsg,
                    104:                                const char *, const char *, char *);
1.13      kristaps  105: static void             mlg_vmsg(struct md_mlg *, enum roffmsg,
                    106:                                const char *, const char *,
                    107:                                const char *, va_list);
1.1       kristaps  108:
                    109: #ifdef __linux__
                    110: extern size_t           strlcat(char *, const char *, size_t);
                    111: extern size_t           strlcpy(char *, const char *, size_t);
                    112: #endif
                    113:
                    114:
1.15      kristaps  115: static char *
1.16      kristaps  116: mlg_St_literal(int argc)
                    117: {
                    118:
                    119:        switch (argc) {
                    120:        case(ROFF_p1003_1_88):
                    121:                return("IEEE Std 1003.1-1988 (&#8220;POSIX&#8221;)");
                    122:        case(ROFF_p1003_1_90):
                    123:                return("IEEE Std 1003.1-1990 (&#8220;POSIX&#8221;)");
                    124:        case(ROFF_p1003_1_96):
                    125:                return("ISO/IEC 9945-1:1996 (&#8220;POSIX&#8221;)");
                    126:        case(ROFF_p1003_1_2001):
                    127:                return("IEEE Std 1003.1-2001 (&#8220;POSIX&#8221;)");
                    128:        case(ROFF_p1003_1_2004):
                    129:                return("IEEE Std 1003.1-2004 (&#8220;POSIX&#8221;)");
                    130:        case(ROFF_p1003_1):
                    131:                return("IEEE Std 1003.1 (&#8220;POSIX&#8221;)");
                    132:        case(ROFF_p1003_1b):
                    133:                return("IEEE Std 1003.1b (&#8220;POSIX&#8221;)");
                    134:        case(ROFF_p1003_1b_93):
                    135:                return("IEEE Std 1003.1b-1993 (&#8220;POSIX&#8221;)");
                    136:        case(ROFF_p1003_1c_95):
                    137:                return("IEEE Std 1003.1c-1995 (&#8220;POSIX&#8221;)");
                    138:        case(ROFF_p1003_1g_2000):
                    139:                return("IEEE Std 1003.1g-2000 (&#8220;POSIX&#8221;)");
                    140:        case(ROFF_p1003_2_92):
                    141:                return("IEEE Std 1003.2-1992 (&#8220;POSIX.2&#8221;)");
                    142:        case(ROFF_p1387_2_95):
                    143:                return("IEEE Std 1387.2-1995 (&#8220;POSIX.7.2&#8221;)");
                    144:        case(ROFF_p1003_2):
                    145:                return("IEEE Std 1003.2 (&#8220;POSIX.2&#8221;)");
                    146:        case(ROFF_p1387_2):
                    147:                return("IEEE Std 1387.2 (&#8220;POSIX.7.2&#8221;)");
                    148:        case(ROFF_isoC_90):
                    149:                return("ISO/IEC 9899:1990 (&#8220;ISO C90&#8221;)");
                    150:        case(ROFF_isoC_amd1):
                    151:                return("ISO/IEC 9899/AMD1:1995 (&#8220;ISO C90&#8221;)");
                    152:        case(ROFF_isoC_tcor1):
                    153:                return("ISO/IEC 9899/TCOR1:1994 (&#8220;ISO C90&#8221;)");
                    154:        case(ROFF_isoC_tcor2):
                    155:                return("ISO/IEC 9899/TCOR2:1995 (&#8220;ISO C90&#8221;)");
                    156:        case(ROFF_isoC_99):
                    157:                return("ISO/IEC 9899:1999 (&#8220;ISO C99&#8221;)");
                    158:        case(ROFF_ansiC):
                    159:                return("ANSI X3.159-1989 (&#8220;ANSI C&#8221;)");
                    160:        case(ROFF_ansiC_89):
                    161:                return("ANSI X3.159-1989 (&#8220;ANSI C&#8221;)");
                    162:        case(ROFF_ansiC_99):
                    163:                return("ANSI/ISO/IEC 9899-1999 (&#8220;ANSI C99&#8221;)");
                    164:        case(ROFF_ieee754):
                    165:                return("IEEE Std 754-1985");
                    166:        case(ROFF_iso8802_3):
                    167:                return("ISO 8802-3: 1989");
                    168:        case(ROFF_xpg3):
                    169:                return("X/Open Portability Guide Issue 3 (&#8220;XPG3&#8221;)");
                    170:        case(ROFF_xpg4):
                    171:                return("X/Open Portability Guide Issue 4 (&#8220;XPG4&#8221;)");
                    172:        case(ROFF_xpg4_2):
                    173:                return("X/Open Portability Guide Issue 4.2 (&#8220;XPG4.2&#8221;)");
                    174:        case(ROFF_xpg4_3):
                    175:                return("X/Open Portability Guide Issue 4.3 (&#8220;XPG4.3&#8221;)");
                    176:        case(ROFF_xbd5):
                    177:                return("X/Open System Interface Definitions Issue 5 (&#8220;XBD5&#8221;)");
                    178:        case(ROFF_xcu5):
                    179:                return("X/Open Commands and Utilities Issue 5 (&#8220;XCU5&#8221;)");
                    180:        case(ROFF_xsh5):
                    181:                return("X/Open System Interfaces and Headers Issue 5 (&#8220;XSH5&#8221;)");
                    182:        case(ROFF_xns5):
                    183:                return("X/Open Networking Services Issue 5 (&#8220;XNS5&#8221;)");
                    184:        case(ROFF_xns5_2d2_0):
                    185:                return("X/Open Networking Services Issue 5.2 Draft 2.0 (&#8220;XNS5.2D2.0&#8221;)");
                    186:        case(ROFF_xcurses4_2):
                    187:                return("X/Open Curses Issue 4 Version 2 (&#8220;XCURSES4.2&#8221;)");
                    188:        case(ROFF_susv2):
                    189:                return("Version 2 of the Single UNIX Specification");
                    190:        case(ROFF_susv3):
                    191:                return("Version 3 of the Single UNIX Specification");
                    192:        case(ROFF_svid4):
                    193:                return("System V Interface Definition, Fourth Edition (&#8220;SVID4&#8221;)");
                    194:        default:
                    195:                break;
                    196:        }
                    197:
                    198:        abort();
                    199:        /* NOTREACHED */
                    200: }
                    201:
                    202:
                    203: static char *
1.15      kristaps  204: mlg_At_literal(const char *p)
                    205: {
1.17      kristaps  206:
1.15      kristaps  207:        if (NULL == p)
                    208:                return("AT&amp;T UNIX");
                    209:        if (0 == strcmp(p, "v6"))
                    210:                return("Version 6 AT&amp;T UNIX");
                    211:        else if (0 == strcmp(p, "v7"))
                    212:                return("Version 7 AT&amp;T UNIX");
                    213:        else if (0 == strcmp(p, "32v"))
                    214:                return("Version 32v AT&amp;T UNIX");
                    215:        else if (0 == strcmp(p, "V.1"))
                    216:                return("AT&amp;T System V.1 UNIX");
                    217:        else if (0 == strcmp(p, "V.4"))
                    218:                return("AT&amp;T System V.4 UNIX");
                    219:
                    220:        abort();
                    221:        /* NOTREACHED */
                    222: }
                    223:
                    224:
                    225: static char *
1.17      kristaps  226: mlg_fmt(int tok)
                    227: {
                    228:
                    229:        switch (tok) {
                    230:        case (ROFF_Ex):
                    231:                return ("The %s utility exits 0 on success, and "
                    232:                                "&gt;0 if an error occurs.");
                    233:        case (ROFF_Rv):
                    234:                return ("The %s() function returns the value 0 if "
                    235:                                "successful; otherwise the value -1 "
                    236:                                "is returned and the global variable "
                    237:                                "<span class=\"inline-Va\">errno</span> "
                    238:                                "is set to indicate the error.");
1.18      kristaps  239:        case (ROFF_In):
                    240:                return("#include &lt;%s&gt;");
1.17      kristaps  241:        default:
                    242:                break;
                    243:        }
                    244:
                    245:        abort();
                    246:        /* NOTREACHED */
                    247: }
                    248:
                    249:
                    250: static char *
1.15      kristaps  251: mlg_literal(int tok)
                    252: {
1.17      kristaps  253:
1.15      kristaps  254:        switch (tok) {
                    255:        case (ROFF_Bt):
                    256:                return("is currently in beta test.");
                    257:        case (ROFF_Ud):
                    258:                return("currently under development.");
                    259:        case (ROFF_Fx):
                    260:                return("FreeBSD");
                    261:        case (ROFF_Nx):
                    262:                return("NetBSD");
                    263:        case (ROFF_Ox):
                    264:                return("OpenBSD");
                    265:        case (ROFF_Ux):
                    266:                return("UNIX");
                    267:        case (ROFF_Bx):
                    268:                return("BSD");
                    269:        case (ROFF_Bsx):
                    270:                return("BSDI BSD/OS");
                    271:        default:
                    272:                break;
                    273:        }
                    274:        abort();
                    275:        /* NOTREACHED */
                    276: }
                    277:
                    278:
1.1       kristaps  279: static int
                    280: mlg_begintag(struct md_mlg *p, enum md_ns ns, int tok,
                    281:                int *argc, char **argv)
                    282: {
                    283:        ssize_t          res;
                    284:
1.8       kristaps  285:        assert(MD_NS_DEFAULT != ns);
                    286:
                    287:        switch (ns) {
                    288:        case (MD_NS_INLINE):
                    289:                if ( ! (ML_OVERRIDE_ONE & p->flags) &&
                    290:                                ! (ML_OVERRIDE_ALL & p->flags) &&
1.9       kristaps  291:                                p->pos + 11 >= COLUMNS)
1.8       kristaps  292:                        if ( ! mlg_newline(p))
                    293:                                return(0);
                    294:                if (0 != p->pos && (MD_TEXT == p->last ||
                    295:                                        MD_INLINE_OUT == p->last)
                    296:                                && ! (ML_OVERRIDE_ONE & p->flags)
                    297:                                && ! (ML_OVERRIDE_ALL & p->flags))
                    298:                        if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos))
                    299:                                return(0);
                    300:                if (0 == p->pos && ! mlg_indent(p))
                    301:                        return(0);
                    302:                mlg_mode(p, MD_INLINE_IN);
                    303:                break;
                    304:        default:
                    305:                if (0 != p->pos) {
                    306:                        if ( ! mlg_newline(p))
                    307:                                return(0);
                    308:                        if ( ! mlg_indent(p))
                    309:                                return(0);
                    310:                } else if ( ! mlg_indent(p))
                    311:                        return(0);
                    312:                p->indent++;
                    313:                mlg_mode(p, MD_BLK_IN);
                    314:                break;
                    315:        }
1.1       kristaps  316:
                    317:        if ( ! ml_nputs(p->mbuf, "<", 1, &p->pos))
                    318:                return(0);
                    319:
1.11      kristaps  320:        res = (*p->cbs.ml_begintag)(p->mbuf, p->data, p->args, ns, tok,
1.1       kristaps  321:                        argc, (const char **)argv);
                    322:        if (-1 == res)
                    323:                return(0);
                    324:
                    325:        assert(res >= 0);
                    326:        p->pos += (size_t)res;
                    327:
1.8       kristaps  328:        if ( ! ml_nputs(p->mbuf, ">", 1, &p->pos))
                    329:                return(0);
                    330:
                    331:        switch (ns) {
                    332:        case (MD_NS_INLINE):
                    333:                break;
                    334:        default:
                    335:                if ( ! mlg_newline(p))
                    336:                        return(0);
                    337:                break;
                    338:        }
1.1       kristaps  339:
1.8       kristaps  340:        return(1);
1.1       kristaps  341: }
                    342:
                    343:
                    344: static int
                    345: mlg_endtag(struct md_mlg *p, enum md_ns ns, int tok)
                    346: {
                    347:        ssize_t          res;
                    348:
1.9       kristaps  349:        assert(MD_NS_DEFAULT != ns);
                    350:
                    351:        switch (ns) {
                    352:        case (MD_NS_INLINE):
                    353:                break;
                    354:        default:
                    355:                p->indent--;
                    356:                if (0 != p->pos) {
                    357:                        if ( ! mlg_newline(p))
                    358:                                return(0);
                    359:                        if ( ! mlg_indent(p))
                    360:                                return(0);
                    361:                } else if ( ! mlg_indent(p))
                    362:                        return(0);
                    363:                break;
                    364:        }
1.1       kristaps  365:
                    366:        if ( ! ml_nputs(p->mbuf, "</", 2, &p->pos))
                    367:                return(0);
                    368:
1.11      kristaps  369:        res = (*p->cbs.ml_endtag)(p->mbuf, p->data, p->args, ns, tok);
1.1       kristaps  370:        if (-1 == res)
                    371:                return(0);
                    372:
                    373:        assert(res >= 0);
                    374:        p->pos += (size_t)res;
                    375:
1.9       kristaps  376:        if ( ! ml_nputs(p->mbuf, ">", 1, &p->pos))
                    377:                return(0);
                    378:
                    379:        switch (ns) {
                    380:        case (MD_NS_INLINE):
                    381:                mlg_mode(p, MD_INLINE_OUT);
                    382:                break;
                    383:        default:
                    384:                mlg_mode(p, MD_BLK_OUT);
                    385:                break;
                    386:        }
1.1       kristaps  387:
1.9       kristaps  388:        return(1);
1.1       kristaps  389: }
                    390:
                    391:
                    392: static int
                    393: mlg_indent(struct md_mlg *p)
                    394: {
                    395:        size_t           count;
                    396:
1.9       kristaps  397:        count = p->indent > MAXINDENT ?
                    398:                (size_t)MAXINDENT : p->indent;
1.1       kristaps  399:        count *= INDENT;
                    400:
                    401:        assert(0 == p->pos);
                    402:        return(ml_putchars(p->mbuf, ' ', count, &p->pos));
                    403: }
                    404:
                    405:
                    406: static int
                    407: mlg_newline(struct md_mlg *p)
                    408: {
                    409:
                    410:        p->pos = 0;
1.11      kristaps  411:        return(ml_nputs(p->mbuf, "\n", 1, NULL));
1.1       kristaps  412: }
                    413:
                    414:
                    415: static void
                    416: mlg_mode(struct md_mlg *p, enum md_tok ns)
                    417: {
1.3       kristaps  418:
1.1       kristaps  419:        p->flags &= ~ML_OVERRIDE_ONE;
                    420:        p->last = ns;
                    421: }
                    422:
                    423:
                    424: static int
1.19    ! kristaps  425: mlg_string(struct md_mlg *p, const char *start, const char *buf)
        !           426: {
        !           427:
        !           428:        return(mlg_nstring(p, start, buf, strlen(buf)));
        !           429: }
        !           430:
        !           431:
        !           432: static int
        !           433: mlg_nstring(struct md_mlg *p, const char *start,
        !           434:                const char *buf, size_t sz)
        !           435: {
        !           436:        int              c;
        !           437:        ssize_t          res;
        !           438:
        !           439:        assert(p->mbuf);
        !           440:        assert(0 != p->indent);
        !           441:
        !           442:        res = (*p->cbs.ml_beginstring)(p->mbuf, p->args, buf, sz);
        !           443:        if (-1 == res)
        !           444:                return(0);
        !           445:
        !           446:        if (0 == (c = ml_nputstring(p->mbuf, buf, sz, &p->pos))) {
        !           447:                mlg_err(p, start, buf, "bad string "
        !           448:                                "encoding: `%s'", buf);
        !           449:                return(0);
        !           450:        } else if (-1 == c)
        !           451:                return(0);
        !           452:
        !           453:        res = (*p->cbs.ml_endstring)(p->mbuf, p->args, buf, sz);
        !           454:        if (-1 == res)
        !           455:                return(0);
        !           456:
        !           457:        return(1);
        !           458: }
        !           459:
        !           460:
        !           461: static int
1.5       kristaps  462: mlg_data(struct md_mlg *p, int space, const char *start, char *buf)
1.1       kristaps  463: {
                    464:        size_t           sz;
                    465:
                    466:        assert(p->mbuf);
                    467:        assert(0 != p->indent);
                    468:
                    469:        if (ML_OVERRIDE_ONE & p->flags ||
                    470:                        ML_OVERRIDE_ALL & p->flags)
                    471:                space = 0;
                    472:
1.8       kristaps  473:        sz = strlen(buf);
1.1       kristaps  474:
1.8       kristaps  475:        if (0 == p->pos) {
                    476:                if ( ! mlg_indent(p))
                    477:                        return(0);
1.19    ! kristaps  478:                if ( ! mlg_nstring(p, start, buf, sz))
1.8       kristaps  479:                        return(0);
1.1       kristaps  480:
1.8       kristaps  481:                if (p->indent * INDENT + sz >= COLUMNS)
                    482:                        if ( ! mlg_newline(p))
1.1       kristaps  483:                                return(0);
1.5       kristaps  484:
1.8       kristaps  485:                return(1);
                    486:        }
1.5       kristaps  487:
1.8       kristaps  488:        if (space && sz + p->pos >= COLUMNS) {
                    489:                if ( ! mlg_newline(p))
1.5       kristaps  490:                        return(0);
1.8       kristaps  491:                if ( ! mlg_indent(p))
1.5       kristaps  492:                        return(0);
1.8       kristaps  493:        } else if (space) {
                    494:                if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos))
1.1       kristaps  495:                        return(0);
1.8       kristaps  496:        }
1.1       kristaps  497:
1.19    ! kristaps  498:        return(mlg_nstring(p, start, buf, sz));
1.1       kristaps  499: }
                    500:
                    501:
                    502: int
                    503: mlg_line(struct md_mlg *p, char *buf)
                    504: {
                    505:
                    506:        return(roff_engine(p->tree, buf));
                    507: }
                    508:
                    509:
                    510: int
                    511: mlg_exit(struct md_mlg *p, int flush)
                    512: {
                    513:        int              c;
                    514:
                    515:        c = roff_free(p->tree, flush);
                    516:        free(p);
1.11      kristaps  517:
                    518:        (*p->cbs.ml_free)(p->data);
                    519:
1.1       kristaps  520:        return(c);
                    521: }
                    522:
                    523:
                    524: struct md_mlg *
1.11      kristaps  525: mlg_alloc(const struct md_args *args,
1.1       kristaps  526:                const struct md_rbuf *rbuf,
                    527:                struct md_mbuf *mbuf,
1.11      kristaps  528:                const struct ml_cbs *cbs)
1.1       kristaps  529: {
                    530:        struct roffcb    cb;
                    531:        struct md_mlg   *p;
                    532:
                    533:        cb.roffhead = mlg_roffhead;
                    534:        cb.rofftail = mlg_rofftail;
                    535:        cb.roffin = mlg_roffin;
                    536:        cb.roffout = mlg_roffout;
                    537:        cb.roffblkin = mlg_roffblkin;
1.2       kristaps  538:        cb.roffblkheadin = mlg_roffblkheadin;
                    539:        cb.roffblkheadout = mlg_roffblkheadout;
                    540:        cb.roffblkbodyin = mlg_roffblkbodyin;
                    541:        cb.roffblkbodyout = mlg_roffblkbodyout;
1.1       kristaps  542:        cb.roffblkout = mlg_roffblkout;
                    543:        cb.roffspecial = mlg_roffspecial;
                    544:        cb.roffmsg = mlg_roffmsg;
                    545:        cb.roffdata = mlg_roffdata;
                    546:
                    547:        if (NULL == (p = calloc(1, sizeof(struct md_mlg))))
                    548:                err(1, "calloc");
                    549:
                    550:        p->args = args;
                    551:        p->mbuf = mbuf;
                    552:        p->rbuf = rbuf;
                    553:
1.11      kristaps  554:        (void)memcpy(&p->cbs, cbs, sizeof(struct ml_cbs));
                    555:
                    556:        if (NULL == (p->tree = roff_alloc(&cb, p)))
                    557:                free(p);
                    558:        else if ( ! (*p->cbs.ml_alloc)(&p->data))
1.1       kristaps  559:                free(p);
1.11      kristaps  560:        else
                    561:                return(p);
1.1       kristaps  562:
1.11      kristaps  563:        return(NULL);
1.1       kristaps  564: }
                    565:
                    566:
                    567: static int
1.4       kristaps  568: mlg_roffhead(void *arg, const struct tm *tm, const char *os,
                    569:                const char *title, const char *sec, const char *vol)
1.1       kristaps  570: {
                    571:        struct md_mlg   *p;
                    572:
                    573:        assert(arg);
                    574:        p = (struct md_mlg *)arg;
                    575:
                    576:        mlg_mode(p, MD_BLK_IN);
1.11      kristaps  577:
                    578:        if ( ! (*p->cbs.ml_begin)(p->mbuf, p->args, tm, os, title, sec, vol))
1.1       kristaps  579:                return(0);
                    580:
                    581:        p->indent++;
                    582:        return(mlg_newline(p));
                    583: }
                    584:
                    585:
                    586: static int
                    587: mlg_rofftail(void *arg)
                    588: {
                    589:        struct md_mlg   *p;
                    590:
                    591:        assert(arg);
                    592:        p = (struct md_mlg *)arg;
                    593:
1.11      kristaps  594:        if (0 != p->pos)
                    595:                if ( ! mlg_newline(p))
                    596:                        return(0);
                    597:
                    598:        if ( ! (*p->cbs.ml_end)(p->mbuf, p->args))
1.1       kristaps  599:                return(0);
                    600:
                    601:        mlg_mode(p, MD_BLK_OUT);
                    602:
                    603:        return(mlg_newline(p));
                    604: }
                    605:
                    606:
1.16      kristaps  607: /* ARGSUSED */
1.1       kristaps  608: static int
1.16      kristaps  609: mlg_roffspecial(void *arg, int tok, const char *start,
                    610:                const int *argc, const char **argv, char **more)
1.1       kristaps  611: {
                    612:        struct md_mlg   *p;
1.17      kristaps  613:        char             buf[256];
1.1       kristaps  614:
                    615:        assert(arg);
                    616:        p = (struct md_mlg *)arg;
                    617:
1.15      kristaps  618:        /*
                    619:         * First handle macros without content.
                    620:         */
                    621:
1.1       kristaps  622:        switch (tok) {
1.15      kristaps  623:        case (ROFF_Ns):
                    624:                p->flags |= ML_OVERRIDE_ONE;
                    625:                return(1);
                    626:        case (ROFF_Sm):
                    627:                assert(*more);
                    628:                if (0 == strcmp(*more, "on"))
                    629:                        p->flags |= ML_OVERRIDE_ALL;
                    630:                else
                    631:                        p->flags &= ~ML_OVERRIDE_ALL;
                    632:                return(1);
                    633:        default:
1.14      kristaps  634:                break;
1.15      kristaps  635:        }
                    636:
1.18      kristaps  637:        /*
                    638:         * Handle macros put into different-token tags.
                    639:         */
                    640:
                    641:        switch (tok) {
                    642:        case (ROFF_Fn):
                    643:                assert(*more);
                    644:                if ( ! mlg_begintag(p, MD_NS_INLINE, tok, NULL, more))
                    645:                        return(0);
1.19    ! kristaps  646:                if ( ! mlg_string(p, start, *more++))
1.18      kristaps  647:                        return(0);
                    648:                if ( ! mlg_endtag(p, MD_NS_INLINE, tok))
                    649:                        return(0);
                    650:                if (*more) {
                    651:                        if ( ! ml_nputs(p->mbuf, "(", 1, &p->pos))
                    652:                                return(0);
                    653:                        p->flags |= ML_OVERRIDE_ONE;
                    654:                        if ( ! mlg_begintag(p, MD_NS_INLINE,
                    655:                                                ROFF_Fa, NULL, more))
                    656:                                return(0);
1.19    ! kristaps  657:                        if ( ! mlg_string(p, start, *more++))
1.18      kristaps  658:                                return(0);
                    659:                        if ( ! mlg_endtag(p, MD_NS_INLINE, ROFF_Fa))
                    660:                                return(0);
                    661:                        while (*more) {
                    662:                                if ( ! ml_nputs(p->mbuf, ", ", 2, &p->pos))
                    663:                                        return(0);
                    664:                                if ( ! mlg_begintag(p, MD_NS_INLINE, ROFF_Fa, NULL, more))
                    665:                                        return(0);
1.19    ! kristaps  666:                                if ( ! mlg_string(p, start, *more++))
1.18      kristaps  667:                                        return(0);
                    668:                                if ( ! mlg_endtag(p, MD_NS_INLINE, ROFF_Fa))
                    669:                                        return(0);
                    670:                        }
                    671:                        if ( ! ml_nputs(p->mbuf, ")", 1, &p->pos))
                    672:                                return(0);
                    673:                }
                    674:                return(1);
                    675:        default:
                    676:                break;
                    677:        }
                    678:
                    679:        /*
                    680:         * Now handle macros in their environments.
                    681:         */
                    682:
1.15      kristaps  683:        if ( ! mlg_begintag(p, MD_NS_INLINE, tok, NULL, more))
                    684:                return(0);
1.14      kristaps  685:
1.15      kristaps  686:        switch (tok) {
1.16      kristaps  687:        case (ROFF_St):
                    688:                assert(NULL == *argv);
                    689:                assert(ROFF_ARGMAX != *argc);
                    690:                if ( ! ml_puts(p->mbuf, mlg_St_literal(*argc),
                    691:                                        &p->pos))
                    692:                        return(0);
                    693:                while (*more) {
                    694:                        if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos))
                    695:                                return(0);
1.19    ! kristaps  696:                        if ( ! mlg_string(p, start, *more++))
1.16      kristaps  697:                                return(0);
                    698:                }
                    699:                break;
                    700:
1.8       kristaps  701:        case (ROFF_Xr):
                    702:                if ( ! *more) {
1.9       kristaps  703:                        mlg_err(p, start, start, "missing argument");
1.8       kristaps  704:                        return(0);
                    705:                }
                    706:                if ( ! ml_puts(p->mbuf, *more++, &p->pos))
                    707:                        return(0);
                    708:                if (*more) {
                    709:                        if ( ! ml_nputs(p->mbuf, "(", 1, &p->pos))
                    710:                                return(0);
1.19    ! kristaps  711:                        if ( ! mlg_string(p, start, *more++))
1.8       kristaps  712:                                return(0);
                    713:                        if ( ! ml_nputs(p->mbuf, ")", 1, &p->pos))
                    714:                                return(0);
                    715:                }
                    716:                if (*more) {
                    717:                        mlg_err(p, start, start, "too many arguments");
                    718:                        return(0);
                    719:                }
                    720:                break;
1.19    ! kristaps  721:
1.15      kristaps  722:        case (ROFF_Sx):
                    723:                /* FALLTHROUGH */
1.12      kristaps  724:        case (ROFF_Nm):
                    725:                assert(*more);
1.19    ! kristaps  726:                if ( ! mlg_string(p, start, *more++))
1.12      kristaps  727:                        return(0);
                    728:                assert(NULL == *more);
1.1       kristaps  729:                break;
1.18      kristaps  730:
                    731:        case (ROFF_In):
                    732:                /* NOTREACHED */
1.13      kristaps  733:        case (ROFF_Ex):
1.17      kristaps  734:                /* NOTREACHED */
                    735:        case (ROFF_Rv):
1.13      kristaps  736:                assert(*more);
1.18      kristaps  737:                /* FIXME: *more must be ml-filtered. */
1.17      kristaps  738:                (void)snprintf(buf, sizeof(buf),
                    739:                                mlg_fmt(tok), *more++);
                    740:                if ( ! ml_puts(p->mbuf, buf, &p->pos))
1.13      kristaps  741:                        return(0);
                    742:                assert(NULL == *more);
1.15      kristaps  743:                break;
1.19    ! kristaps  744:
1.15      kristaps  745:        case (ROFF_At):
1.19    ! kristaps  746:                /* FIXME: *more must be ml-filtered. */
1.15      kristaps  747:                if ( ! ml_puts(p->mbuf, mlg_At_literal(*more), &p->pos))
1.13      kristaps  748:                        return(0);
                    749:                break;
1.19    ! kristaps  750:
1.15      kristaps  751:        case (ROFF_Bx):
                    752:                /* FALLTHROUGH */
                    753:        case (ROFF_Bsx):
                    754:                /* FALLTHROUGH */
                    755:        case (ROFF_Fx):
                    756:                /* FALLTHROUGH */
                    757:        case (ROFF_Nx):
                    758:                /* FALLTHROUGH */
                    759:        case (ROFF_Ox):
                    760:                if ( ! ml_puts(p->mbuf, mlg_literal(tok), &p->pos))
                    761:                        return(0);
                    762:                while (*more) {
                    763:                        if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos))
                    764:                                return(0);
1.19    ! kristaps  765:                        if ( ! mlg_string(p, start, *more++))
1.15      kristaps  766:                                return(0);
                    767:                }
                    768:                break;
1.19    ! kristaps  769:
1.15      kristaps  770:        case (ROFF_Bt):
                    771:                /* FALLTHROUGH */
1.14      kristaps  772:        case (ROFF_Ud):
1.15      kristaps  773:                /* FALLTHROUGH */
                    774:        case (ROFF_Ux):
1.14      kristaps  775:                assert(NULL == *more);
1.15      kristaps  776:                if ( ! ml_puts(p->mbuf, mlg_literal(tok), &p->pos))
1.14      kristaps  777:                        return(0);
                    778:                break;
1.19    ! kristaps  779:
1.1       kristaps  780:        default:
1.13      kristaps  781:                mlg_err(p, start, start, "`%s' not yet supported",
                    782:                                toknames[tok]);
                    783:                return(0);
1.1       kristaps  784:        }
                    785:
1.15      kristaps  786:        return(mlg_endtag(p, MD_NS_INLINE, tok));
1.1       kristaps  787: }
                    788:
                    789:
                    790: static int
                    791: mlg_roffblkin(void *arg, int tok, int *argc, char **argv)
                    792: {
                    793:
1.8       kristaps  794:        return(mlg_begintag((struct md_mlg *)arg,
1.2       kristaps  795:                                MD_NS_BLOCK, tok, argc, argv));
                    796: }
                    797:
                    798:
                    799: static int
                    800: mlg_roffblkout(void *arg, int tok)
                    801: {
                    802:
1.9       kristaps  803:        return(mlg_endtag((struct md_mlg *)arg, MD_NS_BLOCK, tok));
1.2       kristaps  804: }
                    805:
                    806:
                    807: static int
                    808: mlg_roffblkbodyin(void *arg, int tok, int *argc, char **argv)
                    809: {
                    810:
1.8       kristaps  811:        return(mlg_begintag((struct md_mlg *)arg,
1.2       kristaps  812:                                MD_NS_BODY, tok, argc, argv));
                    813: }
1.1       kristaps  814:
                    815:
1.2       kristaps  816: static int
                    817: mlg_roffblkbodyout(void *arg, int tok)
                    818: {
1.1       kristaps  819:
1.9       kristaps  820:        return(mlg_endtag((struct md_mlg *)arg, MD_NS_BODY, tok));
1.1       kristaps  821: }
                    822:
                    823:
                    824: static int
1.2       kristaps  825: mlg_roffblkheadin(void *arg, int tok, int *argc, char **argv)
1.1       kristaps  826: {
                    827:
1.8       kristaps  828:        return(mlg_begintag((struct md_mlg *)arg,
1.2       kristaps  829:                                MD_NS_HEAD, tok, argc, argv));
                    830: }
1.1       kristaps  831:
                    832:
1.2       kristaps  833: static int
                    834: mlg_roffblkheadout(void *arg, int tok)
                    835: {
1.1       kristaps  836:
1.9       kristaps  837:        return(mlg_endtag((struct md_mlg *)arg, MD_NS_HEAD, tok));
1.1       kristaps  838: }
                    839:
                    840:
                    841: static int
                    842: mlg_roffin(void *arg, int tok, int *argc, char **argv)
                    843: {
                    844:
1.8       kristaps  845:        return(mlg_begintag((struct md_mlg *)arg,
                    846:                                MD_NS_INLINE, tok, argc, argv));
1.1       kristaps  847: }
                    848:
                    849:
                    850: static int
                    851: mlg_roffout(void *arg, int tok)
                    852: {
                    853:
1.9       kristaps  854:        return(mlg_endtag((struct md_mlg *)arg, MD_NS_INLINE, tok));
1.1       kristaps  855: }
                    856:
                    857:
                    858: static void
                    859: mlg_roffmsg(void *arg, enum roffmsg lvl,
                    860:                const char *buf, const char *pos, char *msg)
                    861: {
1.5       kristaps  862:
                    863:        mlg_msg((struct md_mlg *)arg, lvl, buf, pos, msg);
                    864: }
                    865:
                    866:
                    867: static int
                    868: mlg_roffdata(void *arg, int space, const char *start, char *buf)
                    869: {
1.1       kristaps  870:        struct md_mlg   *p;
                    871:
                    872:        assert(arg);
                    873:        p = (struct md_mlg *)arg;
                    874:
1.5       kristaps  875:        if ( ! mlg_data(p, space, start, buf))
                    876:                return(0);
                    877:
                    878:        mlg_mode(p, MD_TEXT);
1.11      kristaps  879:
1.5       kristaps  880:        return(1);
                    881: }
                    882:
                    883:
                    884: static void
1.13      kristaps  885: mlg_vmsg(struct md_mlg *p, enum roffmsg lvl, const char *start,
                    886:                const char *pos, const char *fmt, va_list ap)
1.5       kristaps  887: {
1.13      kristaps  888:        char             buf[128];
1.5       kristaps  889:
1.13      kristaps  890:        (void)vsnprintf(buf, sizeof(buf), fmt, ap);
                    891:        mlg_msg(p, lvl, start, pos, buf);
1.5       kristaps  892: }
                    893:
                    894:
                    895: static void
1.13      kristaps  896: mlg_err(struct md_mlg *p, const char *start,
                    897:                const char *pos, const char *fmt, ...)
                    898: {
                    899:        va_list          ap;
                    900:
                    901:        va_start(ap, fmt);
                    902:        mlg_vmsg(p, ROFF_ERROR, start, pos, fmt, ap);
                    903:        va_end(ap);
1.5       kristaps  904: }
                    905:
                    906:
                    907: static void
                    908: mlg_msg(struct md_mlg *p, enum roffmsg lvl,
                    909:                const char *buf, const char *pos, char *msg)
                    910: {
                    911:        char            *level;
                    912:
1.1       kristaps  913:        switch (lvl) {
                    914:        case (ROFF_WARN):
                    915:                if ( ! (MD_WARN_ALL & p->args->warnings))
                    916:                        return;
                    917:                level = "warning";
                    918:                break;
                    919:        case (ROFF_ERROR):
                    920:                level = "error";
                    921:                break;
                    922:        default:
                    923:                abort();
                    924:        }
                    925:
                    926:        if (pos)
                    927:                (void)fprintf(stderr, "%s:%zu: %s: %s (column %zu)\n",
                    928:                                p->rbuf->name, p->rbuf->line, level,
                    929:                                msg, pos - buf);
                    930:        else
                    931:                (void)fprintf(stderr, "%s: %s: %s\n",
                    932:                                p->rbuf->name, level, msg);
                    933: }

CVSweb