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

Annotation of mandoc/mlg.c, Revision 1.18

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

CVSweb