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

Annotation of mandoc/mlg.c, Revision 1.17

1.17    ! kristaps    1: /* $Id: mlg.c,v 1.16 2008/12/06 21:10:31 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.");
        !           237:        default:
        !           238:                break;
        !           239:        }
        !           240:
        !           241:        abort();
        !           242:        /* NOTREACHED */
        !           243: }
        !           244:
        !           245:
        !           246: static char *
1.15      kristaps  247: mlg_literal(int tok)
                    248: {
1.17    ! kristaps  249:
1.15      kristaps  250:        switch (tok) {
                    251:        case (ROFF_Bt):
                    252:                return("is currently in beta test.");
                    253:        case (ROFF_Ud):
                    254:                return("currently under development.");
                    255:        case (ROFF_Fx):
                    256:                return("FreeBSD");
                    257:        case (ROFF_Nx):
                    258:                return("NetBSD");
                    259:        case (ROFF_Ox):
                    260:                return("OpenBSD");
                    261:        case (ROFF_Ux):
                    262:                return("UNIX");
                    263:        case (ROFF_Bx):
                    264:                return("BSD");
                    265:        case (ROFF_Bsx):
                    266:                return("BSDI BSD/OS");
                    267:        default:
                    268:                break;
                    269:        }
                    270:        abort();
                    271:        /* NOTREACHED */
                    272: }
                    273:
                    274:
1.1       kristaps  275: static int
                    276: mlg_begintag(struct md_mlg *p, enum md_ns ns, int tok,
                    277:                int *argc, char **argv)
                    278: {
                    279:        ssize_t          res;
                    280:
1.8       kristaps  281:        assert(MD_NS_DEFAULT != ns);
                    282:
                    283:        switch (ns) {
                    284:        case (MD_NS_INLINE):
                    285:                if ( ! (ML_OVERRIDE_ONE & p->flags) &&
                    286:                                ! (ML_OVERRIDE_ALL & p->flags) &&
1.9       kristaps  287:                                p->pos + 11 >= COLUMNS)
1.8       kristaps  288:                        if ( ! mlg_newline(p))
                    289:                                return(0);
                    290:                if (0 != p->pos && (MD_TEXT == p->last ||
                    291:                                        MD_INLINE_OUT == p->last)
                    292:                                && ! (ML_OVERRIDE_ONE & p->flags)
                    293:                                && ! (ML_OVERRIDE_ALL & p->flags))
                    294:                        if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos))
                    295:                                return(0);
                    296:                if (0 == p->pos && ! mlg_indent(p))
                    297:                        return(0);
                    298:                mlg_mode(p, MD_INLINE_IN);
                    299:                break;
                    300:        default:
                    301:                if (0 != p->pos) {
                    302:                        if ( ! mlg_newline(p))
                    303:                                return(0);
                    304:                        if ( ! mlg_indent(p))
                    305:                                return(0);
                    306:                } else if ( ! mlg_indent(p))
                    307:                        return(0);
                    308:                p->indent++;
                    309:                mlg_mode(p, MD_BLK_IN);
                    310:                break;
                    311:        }
1.1       kristaps  312:
                    313:        if ( ! ml_nputs(p->mbuf, "<", 1, &p->pos))
                    314:                return(0);
                    315:
1.11      kristaps  316:        res = (*p->cbs.ml_begintag)(p->mbuf, p->data, p->args, ns, tok,
1.1       kristaps  317:                        argc, (const char **)argv);
                    318:        if (-1 == res)
                    319:                return(0);
                    320:
                    321:        assert(res >= 0);
                    322:        p->pos += (size_t)res;
                    323:
1.8       kristaps  324:        if ( ! ml_nputs(p->mbuf, ">", 1, &p->pos))
                    325:                return(0);
                    326:
                    327:        switch (ns) {
                    328:        case (MD_NS_INLINE):
                    329:                break;
                    330:        default:
                    331:                if ( ! mlg_newline(p))
                    332:                        return(0);
                    333:                break;
                    334:        }
1.1       kristaps  335:
1.8       kristaps  336:        return(1);
1.1       kristaps  337: }
                    338:
                    339:
                    340: static int
                    341: mlg_endtag(struct md_mlg *p, enum md_ns ns, int tok)
                    342: {
                    343:        ssize_t          res;
                    344:
1.9       kristaps  345:        assert(MD_NS_DEFAULT != ns);
                    346:
                    347:        switch (ns) {
                    348:        case (MD_NS_INLINE):
                    349:                break;
                    350:        default:
                    351:                p->indent--;
                    352:                if (0 != p->pos) {
                    353:                        if ( ! mlg_newline(p))
                    354:                                return(0);
                    355:                        if ( ! mlg_indent(p))
                    356:                                return(0);
                    357:                } else if ( ! mlg_indent(p))
                    358:                        return(0);
                    359:                break;
                    360:        }
1.1       kristaps  361:
                    362:        if ( ! ml_nputs(p->mbuf, "</", 2, &p->pos))
                    363:                return(0);
                    364:
1.11      kristaps  365:        res = (*p->cbs.ml_endtag)(p->mbuf, p->data, p->args, ns, tok);
1.1       kristaps  366:        if (-1 == res)
                    367:                return(0);
                    368:
                    369:        assert(res >= 0);
                    370:        p->pos += (size_t)res;
                    371:
1.9       kristaps  372:        if ( ! ml_nputs(p->mbuf, ">", 1, &p->pos))
                    373:                return(0);
                    374:
                    375:        switch (ns) {
                    376:        case (MD_NS_INLINE):
                    377:                mlg_mode(p, MD_INLINE_OUT);
                    378:                break;
                    379:        default:
                    380:                mlg_mode(p, MD_BLK_OUT);
                    381:                break;
                    382:        }
1.1       kristaps  383:
1.9       kristaps  384:        return(1);
1.1       kristaps  385: }
                    386:
                    387:
                    388: static int
                    389: mlg_indent(struct md_mlg *p)
                    390: {
                    391:        size_t           count;
                    392:
1.9       kristaps  393:        count = p->indent > MAXINDENT ?
                    394:                (size_t)MAXINDENT : p->indent;
1.1       kristaps  395:        count *= INDENT;
                    396:
                    397:        assert(0 == p->pos);
                    398:        return(ml_putchars(p->mbuf, ' ', count, &p->pos));
                    399: }
                    400:
                    401:
                    402: static int
                    403: mlg_newline(struct md_mlg *p)
                    404: {
                    405:
                    406:        p->pos = 0;
1.11      kristaps  407:        return(ml_nputs(p->mbuf, "\n", 1, NULL));
1.1       kristaps  408: }
                    409:
                    410:
                    411: static void
                    412: mlg_mode(struct md_mlg *p, enum md_tok ns)
                    413: {
1.3       kristaps  414:
1.1       kristaps  415:        p->flags &= ~ML_OVERRIDE_ONE;
                    416:        p->last = ns;
                    417: }
                    418:
                    419:
                    420: static int
1.5       kristaps  421: mlg_data(struct md_mlg *p, int space, const char *start, char *buf)
1.1       kristaps  422: {
                    423:        size_t           sz;
1.5       kristaps  424:        int              c;
1.1       kristaps  425:
                    426:        assert(p->mbuf);
                    427:        assert(0 != p->indent);
                    428:
                    429:        if (ML_OVERRIDE_ONE & p->flags ||
                    430:                        ML_OVERRIDE_ALL & p->flags)
                    431:                space = 0;
                    432:
1.8       kristaps  433:        sz = strlen(buf);
1.1       kristaps  434:
1.8       kristaps  435:        if (0 == p->pos) {
                    436:                if ( ! mlg_indent(p))
                    437:                        return(0);
1.1       kristaps  438:
1.8       kristaps  439:                c = ml_nputstring(p->mbuf, buf, sz, &p->pos);
1.1       kristaps  440:
1.8       kristaps  441:                if (0 == c) {
                    442:                        mlg_err(p, start, buf, "bad char sequence");
                    443:                        return(0);
                    444:                } else if (c > 1) {
                    445:                        mlg_warn(p, start, buf, "bogus char sequence");
                    446:                        return(0);
                    447:                } else if (-1 == c)
                    448:                        return(0);
1.1       kristaps  449:
1.8       kristaps  450:                if (p->indent * INDENT + sz >= COLUMNS)
                    451:                        if ( ! mlg_newline(p))
1.1       kristaps  452:                                return(0);
1.5       kristaps  453:
1.8       kristaps  454:                return(1);
                    455:        }
1.5       kristaps  456:
1.8       kristaps  457:        if (space && sz + p->pos >= COLUMNS) {
                    458:                if ( ! mlg_newline(p))
1.5       kristaps  459:                        return(0);
1.8       kristaps  460:                if ( ! mlg_indent(p))
1.5       kristaps  461:                        return(0);
1.8       kristaps  462:        } else if (space) {
                    463:                if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos))
1.1       kristaps  464:                        return(0);
1.8       kristaps  465:        }
1.1       kristaps  466:
1.8       kristaps  467:        c = ml_nputstring(p->mbuf, buf, sz, &p->pos);
                    468:
                    469:        if (0 == c) {
                    470:                mlg_err(p, start, buf, "bad char sequence");
                    471:                return(0);
                    472:        } else if (c > 1) {
                    473:                mlg_warn(p, start, buf, "bogus char sequence");
                    474:                return(0);
                    475:        } else if (-1 == c)
                    476:                return(0);
1.1       kristaps  477:
                    478:        return(1);
                    479: }
                    480:
                    481:
                    482: int
                    483: mlg_line(struct md_mlg *p, char *buf)
                    484: {
                    485:
                    486:        return(roff_engine(p->tree, buf));
                    487: }
                    488:
                    489:
                    490: int
                    491: mlg_exit(struct md_mlg *p, int flush)
                    492: {
                    493:        int              c;
                    494:
                    495:        c = roff_free(p->tree, flush);
                    496:        free(p);
1.11      kristaps  497:
                    498:        (*p->cbs.ml_free)(p->data);
                    499:
1.1       kristaps  500:        return(c);
                    501: }
                    502:
                    503:
                    504: struct md_mlg *
1.11      kristaps  505: mlg_alloc(const struct md_args *args,
1.1       kristaps  506:                const struct md_rbuf *rbuf,
                    507:                struct md_mbuf *mbuf,
1.11      kristaps  508:                const struct ml_cbs *cbs)
1.1       kristaps  509: {
                    510:        struct roffcb    cb;
                    511:        struct md_mlg   *p;
                    512:
                    513:        cb.roffhead = mlg_roffhead;
                    514:        cb.rofftail = mlg_rofftail;
                    515:        cb.roffin = mlg_roffin;
                    516:        cb.roffout = mlg_roffout;
                    517:        cb.roffblkin = mlg_roffblkin;
1.2       kristaps  518:        cb.roffblkheadin = mlg_roffblkheadin;
                    519:        cb.roffblkheadout = mlg_roffblkheadout;
                    520:        cb.roffblkbodyin = mlg_roffblkbodyin;
                    521:        cb.roffblkbodyout = mlg_roffblkbodyout;
1.1       kristaps  522:        cb.roffblkout = mlg_roffblkout;
                    523:        cb.roffspecial = mlg_roffspecial;
                    524:        cb.roffmsg = mlg_roffmsg;
                    525:        cb.roffdata = mlg_roffdata;
                    526:
                    527:        if (NULL == (p = calloc(1, sizeof(struct md_mlg))))
                    528:                err(1, "calloc");
                    529:
                    530:        p->args = args;
                    531:        p->mbuf = mbuf;
                    532:        p->rbuf = rbuf;
                    533:
1.11      kristaps  534:        (void)memcpy(&p->cbs, cbs, sizeof(struct ml_cbs));
                    535:
                    536:        if (NULL == (p->tree = roff_alloc(&cb, p)))
                    537:                free(p);
                    538:        else if ( ! (*p->cbs.ml_alloc)(&p->data))
1.1       kristaps  539:                free(p);
1.11      kristaps  540:        else
                    541:                return(p);
1.1       kristaps  542:
1.11      kristaps  543:        return(NULL);
1.1       kristaps  544: }
                    545:
                    546:
                    547: static int
1.4       kristaps  548: mlg_roffhead(void *arg, const struct tm *tm, const char *os,
                    549:                const char *title, const char *sec, const char *vol)
1.1       kristaps  550: {
                    551:        struct md_mlg   *p;
                    552:
                    553:        assert(arg);
                    554:        p = (struct md_mlg *)arg;
                    555:
                    556:        mlg_mode(p, MD_BLK_IN);
1.11      kristaps  557:
                    558:        if ( ! (*p->cbs.ml_begin)(p->mbuf, p->args, tm, os, title, sec, vol))
1.1       kristaps  559:                return(0);
                    560:
                    561:        p->indent++;
                    562:        return(mlg_newline(p));
                    563: }
                    564:
                    565:
                    566: static int
                    567: mlg_rofftail(void *arg)
                    568: {
                    569:        struct md_mlg   *p;
                    570:
                    571:        assert(arg);
                    572:        p = (struct md_mlg *)arg;
                    573:
1.11      kristaps  574:        if (0 != p->pos)
                    575:                if ( ! mlg_newline(p))
                    576:                        return(0);
                    577:
                    578:        if ( ! (*p->cbs.ml_end)(p->mbuf, p->args))
1.1       kristaps  579:                return(0);
                    580:
                    581:        mlg_mode(p, MD_BLK_OUT);
                    582:
                    583:        return(mlg_newline(p));
                    584: }
                    585:
                    586:
1.16      kristaps  587: /* ARGSUSED */
1.1       kristaps  588: static int
1.16      kristaps  589: mlg_roffspecial(void *arg, int tok, const char *start,
                    590:                const int *argc, const char **argv, char **more)
1.1       kristaps  591: {
                    592:        struct md_mlg   *p;
1.17    ! kristaps  593:        char             buf[256];
1.1       kristaps  594:
                    595:        assert(arg);
                    596:        p = (struct md_mlg *)arg;
                    597:
1.15      kristaps  598:        /*
                    599:         * First handle macros without content.
                    600:         */
                    601:
1.1       kristaps  602:        switch (tok) {
1.15      kristaps  603:        case (ROFF_Ns):
                    604:                p->flags |= ML_OVERRIDE_ONE;
                    605:                return(1);
                    606:        case (ROFF_Sm):
                    607:                assert(*more);
                    608:                if (0 == strcmp(*more, "on"))
                    609:                        p->flags |= ML_OVERRIDE_ALL;
                    610:                else
                    611:                        p->flags &= ~ML_OVERRIDE_ALL;
                    612:                return(1);
                    613:        default:
1.14      kristaps  614:                break;
1.15      kristaps  615:        }
                    616:
                    617:        if ( ! mlg_begintag(p, MD_NS_INLINE, tok, NULL, more))
                    618:                return(0);
1.14      kristaps  619:
1.15      kristaps  620:        switch (tok) {
1.16      kristaps  621:        case (ROFF_St):
                    622:                assert(NULL == *argv);
                    623:                assert(ROFF_ARGMAX != *argc);
                    624:                if ( ! ml_puts(p->mbuf, mlg_St_literal(*argc),
                    625:                                        &p->pos))
                    626:                        return(0);
                    627:                while (*more) {
                    628:                        if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos))
                    629:                                return(0);
                    630:                        if ( ! ml_putstring(p->mbuf, *more++, &p->pos))
                    631:                                return(0);
                    632:                }
                    633:                break;
                    634:
1.8       kristaps  635:        case (ROFF_Xr):
                    636:                if ( ! *more) {
1.9       kristaps  637:                        mlg_err(p, start, start, "missing argument");
1.8       kristaps  638:                        return(0);
                    639:                }
                    640:                if ( ! ml_puts(p->mbuf, *more++, &p->pos))
                    641:                        return(0);
                    642:                if (*more) {
                    643:                        if ( ! ml_nputs(p->mbuf, "(", 1, &p->pos))
                    644:                                return(0);
1.9       kristaps  645:                        if ( ! ml_puts(p->mbuf, *more++, &p->pos))
1.8       kristaps  646:                                return(0);
                    647:                        if ( ! ml_nputs(p->mbuf, ")", 1, &p->pos))
                    648:                                return(0);
                    649:                }
                    650:                if (*more) {
                    651:                        mlg_err(p, start, start, "too many arguments");
                    652:                        return(0);
                    653:                }
                    654:                break;
1.15      kristaps  655:        case (ROFF_Sx):
                    656:                /* FALLTHROUGH */
1.12      kristaps  657:        case (ROFF_Nm):
                    658:                assert(*more);
                    659:                if ( ! ml_puts(p->mbuf, *more++, &p->pos))
                    660:                        return(0);
                    661:                assert(NULL == *more);
1.1       kristaps  662:                break;
1.17    ! kristaps  663:
1.13      kristaps  664:        case (ROFF_Ex):
1.17    ! kristaps  665:                /* NOTREACHED */
        !           666:        case (ROFF_Rv):
1.13      kristaps  667:                assert(*more);
1.17    ! kristaps  668:                (void)snprintf(buf, sizeof(buf),
        !           669:                                mlg_fmt(tok), *more++);
        !           670:                if ( ! ml_puts(p->mbuf, buf, &p->pos))
1.13      kristaps  671:                        return(0);
                    672:                assert(NULL == *more);
1.15      kristaps  673:                break;
                    674:        case (ROFF_At):
                    675:                if ( ! ml_puts(p->mbuf, mlg_At_literal(*more), &p->pos))
1.13      kristaps  676:                        return(0);
                    677:                break;
1.15      kristaps  678:        case (ROFF_Bx):
                    679:                /* FALLTHROUGH */
                    680:        case (ROFF_Bsx):
                    681:                /* FALLTHROUGH */
                    682:        case (ROFF_Fx):
                    683:                /* FALLTHROUGH */
                    684:        case (ROFF_Nx):
                    685:                /* FALLTHROUGH */
                    686:        case (ROFF_Ox):
                    687:                if ( ! ml_puts(p->mbuf, mlg_literal(tok), &p->pos))
                    688:                        return(0);
                    689:                while (*more) {
                    690:                        if ( ! ml_nputs(p->mbuf, " ", 1, &p->pos))
                    691:                                return(0);
                    692:                        if ( ! ml_putstring(p->mbuf, *more++, &p->pos))
                    693:                                return(0);
                    694:                }
                    695:                break;
                    696:        case (ROFF_Bt):
                    697:                /* FALLTHROUGH */
1.14      kristaps  698:        case (ROFF_Ud):
1.15      kristaps  699:                /* FALLTHROUGH */
                    700:        case (ROFF_Ux):
1.14      kristaps  701:                assert(NULL == *more);
1.15      kristaps  702:                if ( ! ml_puts(p->mbuf, mlg_literal(tok), &p->pos))
1.14      kristaps  703:                        return(0);
                    704:                break;
1.1       kristaps  705:        default:
1.13      kristaps  706:                mlg_err(p, start, start, "`%s' not yet supported",
                    707:                                toknames[tok]);
                    708:                return(0);
1.1       kristaps  709:        }
                    710:
1.15      kristaps  711:        return(mlg_endtag(p, MD_NS_INLINE, tok));
1.1       kristaps  712: }
                    713:
                    714:
                    715: static int
                    716: mlg_roffblkin(void *arg, int tok, int *argc, char **argv)
                    717: {
                    718:
1.8       kristaps  719:        return(mlg_begintag((struct md_mlg *)arg,
1.2       kristaps  720:                                MD_NS_BLOCK, tok, argc, argv));
                    721: }
                    722:
                    723:
                    724: static int
                    725: mlg_roffblkout(void *arg, int tok)
                    726: {
                    727:
1.9       kristaps  728:        return(mlg_endtag((struct md_mlg *)arg, MD_NS_BLOCK, tok));
1.2       kristaps  729: }
                    730:
                    731:
                    732: static int
                    733: mlg_roffblkbodyin(void *arg, int tok, int *argc, char **argv)
                    734: {
                    735:
1.8       kristaps  736:        return(mlg_begintag((struct md_mlg *)arg,
1.2       kristaps  737:                                MD_NS_BODY, tok, argc, argv));
                    738: }
1.1       kristaps  739:
                    740:
1.2       kristaps  741: static int
                    742: mlg_roffblkbodyout(void *arg, int tok)
                    743: {
1.1       kristaps  744:
1.9       kristaps  745:        return(mlg_endtag((struct md_mlg *)arg, MD_NS_BODY, tok));
1.1       kristaps  746: }
                    747:
                    748:
                    749: static int
1.2       kristaps  750: mlg_roffblkheadin(void *arg, int tok, int *argc, char **argv)
1.1       kristaps  751: {
                    752:
1.8       kristaps  753:        return(mlg_begintag((struct md_mlg *)arg,
1.2       kristaps  754:                                MD_NS_HEAD, tok, argc, argv));
                    755: }
1.1       kristaps  756:
                    757:
1.2       kristaps  758: static int
                    759: mlg_roffblkheadout(void *arg, int tok)
                    760: {
1.1       kristaps  761:
1.9       kristaps  762:        return(mlg_endtag((struct md_mlg *)arg, MD_NS_HEAD, tok));
1.1       kristaps  763: }
                    764:
                    765:
                    766: static int
                    767: mlg_roffin(void *arg, int tok, int *argc, char **argv)
                    768: {
                    769:
1.8       kristaps  770:        return(mlg_begintag((struct md_mlg *)arg,
                    771:                                MD_NS_INLINE, tok, argc, argv));
1.1       kristaps  772: }
                    773:
                    774:
                    775: static int
                    776: mlg_roffout(void *arg, int tok)
                    777: {
                    778:
1.9       kristaps  779:        return(mlg_endtag((struct md_mlg *)arg, MD_NS_INLINE, tok));
1.1       kristaps  780: }
                    781:
                    782:
                    783: static void
                    784: mlg_roffmsg(void *arg, enum roffmsg lvl,
                    785:                const char *buf, const char *pos, char *msg)
                    786: {
1.5       kristaps  787:
                    788:        mlg_msg((struct md_mlg *)arg, lvl, buf, pos, msg);
                    789: }
                    790:
                    791:
                    792: static int
                    793: mlg_roffdata(void *arg, int space, const char *start, char *buf)
                    794: {
1.1       kristaps  795:        struct md_mlg   *p;
                    796:
                    797:        assert(arg);
                    798:        p = (struct md_mlg *)arg;
                    799:
1.5       kristaps  800:        if ( ! mlg_data(p, space, start, buf))
                    801:                return(0);
                    802:
                    803:        mlg_mode(p, MD_TEXT);
1.11      kristaps  804:
1.5       kristaps  805:        return(1);
                    806: }
                    807:
                    808:
                    809: static void
1.13      kristaps  810: mlg_vmsg(struct md_mlg *p, enum roffmsg lvl, const char *start,
                    811:                const char *pos, const char *fmt, va_list ap)
1.5       kristaps  812: {
1.13      kristaps  813:        char             buf[128];
1.5       kristaps  814:
1.13      kristaps  815:        (void)vsnprintf(buf, sizeof(buf), fmt, ap);
                    816:        mlg_msg(p, lvl, start, pos, buf);
1.5       kristaps  817: }
                    818:
                    819:
                    820: static void
1.13      kristaps  821: mlg_warn(struct md_mlg *p, const char *start,
                    822:                const char *pos, const char *fmt, ...)
1.5       kristaps  823: {
1.13      kristaps  824:        va_list          ap;
1.5       kristaps  825:
1.13      kristaps  826:        va_start(ap, fmt);
                    827:        mlg_vmsg(p, ROFF_WARN, start, pos, fmt, ap);
                    828:        va_end(ap);
                    829: }
                    830:
                    831:
                    832: static void
                    833: mlg_err(struct md_mlg *p, const char *start,
                    834:                const char *pos, const char *fmt, ...)
                    835: {
                    836:        va_list          ap;
                    837:
                    838:        va_start(ap, fmt);
                    839:        mlg_vmsg(p, ROFF_ERROR, start, pos, fmt, ap);
                    840:        va_end(ap);
1.5       kristaps  841: }
                    842:
                    843:
                    844: static void
                    845: mlg_msg(struct md_mlg *p, enum roffmsg lvl,
                    846:                const char *buf, const char *pos, char *msg)
                    847: {
                    848:        char            *level;
                    849:
1.1       kristaps  850:        switch (lvl) {
                    851:        case (ROFF_WARN):
                    852:                if ( ! (MD_WARN_ALL & p->args->warnings))
                    853:                        return;
                    854:                level = "warning";
                    855:                break;
                    856:        case (ROFF_ERROR):
                    857:                level = "error";
                    858:                break;
                    859:        default:
                    860:                abort();
                    861:        }
                    862:
                    863:        if (pos)
                    864:                (void)fprintf(stderr, "%s:%zu: %s: %s (column %zu)\n",
                    865:                                p->rbuf->name, p->rbuf->line, level,
                    866:                                msg, pos - buf);
                    867:        else
                    868:                (void)fprintf(stderr, "%s: %s: %s\n",
                    869:                                p->rbuf->name, level, msg);
                    870: }

CVSweb