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

Annotation of mandoc/mlg.c, Revision 1.16

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

CVSweb