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

Annotation of mandoc/mdoc_markdown.c, Revision 1.2

1.2     ! schwarze    1: /*     $Id: mdoc_markdown.c,v 1.1 2017/03/03 14:23:23 schwarze Exp $ */
1.1       schwarze    2: /*
                      3:  * Copyright (c) 2017 Ingo Schwarze <schwarze@openbsd.org>
                      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 above
                      7:  * copyright notice and this permission notice appear in all copies.
                      8:  *
                      9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
                     10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
                     12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     16:  */
                     17: #include <sys/types.h>
                     18:
                     19: #include <assert.h>
                     20: #include <ctype.h>
                     21: #include <stdio.h>
                     22: #include <string.h>
                     23:
                     24: #include "mandoc_aux.h"
                     25: #include "mandoc.h"
                     26: #include "roff.h"
                     27: #include "mdoc.h"
                     28: #include "main.h"
                     29:
                     30: struct md_act {
                     31:        int             (*cond)(struct roff_node *n);
                     32:        int             (*pre)(struct roff_node *n);
                     33:        void            (*post)(struct roff_node *n);
                     34:        const char       *prefix; /* pre-node string constant */
                     35:        const char       *suffix; /* post-node string constant */
                     36: };
                     37:
                     38: static void     md_nodelist(struct roff_node *);
                     39: static void     md_node(struct roff_node *);
                     40: static const char *md_stack(char c);
                     41: static void     md_preword(void);
                     42: static void     md_rawword(const char *);
                     43: static void     md_word(const char *);
                     44: static void     md_named(const char *);
                     45: static void     md_char(unsigned char);
                     46:
                     47: static int      md_cond_head(struct roff_node *);
                     48: static int      md_cond_body(struct roff_node *);
                     49:
                     50: static int      md_pre_raw(struct roff_node *);
                     51: static int      md_pre_word(struct roff_node *);
                     52: static int      md_pre_skip(struct roff_node *);
                     53: static void     md_pre_syn(struct roff_node *);
                     54: static int      md_pre_Ap(struct roff_node *);
                     55: static int      md_pre_Bd(struct roff_node *);
                     56: static int      md_pre_Bk(struct roff_node *);
                     57: static int      md_pre_Bl(struct roff_node *);
                     58: static int      md_pre_D1(struct roff_node *);
                     59: static int      md_pre_Dl(struct roff_node *);
                     60: static int      md_pre_En(struct roff_node *);
                     61: static int      md_pre_Eo(struct roff_node *);
                     62: static int      md_pre_Fa(struct roff_node *);
                     63: static int      md_pre_Fd(struct roff_node *);
                     64: static int      md_pre_Fn(struct roff_node *);
                     65: static int      md_pre_Fo(struct roff_node *);
                     66: static int      md_pre_In(struct roff_node *);
                     67: static int      md_pre_It(struct roff_node *);
                     68: static int      md_pre_Lk(struct roff_node *);
                     69: static int      md_pre_Nd(struct roff_node *);
                     70: static int      md_pre_Nm(struct roff_node *);
                     71: static int      md_pre_No(struct roff_node *);
                     72: static int      md_pre_Ns(struct roff_node *);
                     73: static int      md_pre_Pp(struct roff_node *);
                     74: static int      md_pre_Rs(struct roff_node *);
                     75: static int      md_pre_Sh(struct roff_node *);
                     76: static int      md_pre_Sm(struct roff_node *);
                     77: static int      md_pre_Vt(struct roff_node *);
                     78: static int      md_pre_Xr(struct roff_node *);
                     79: static int      md_pre__T(struct roff_node *);
                     80: static int      md_pre_br(struct roff_node *);
                     81:
                     82: static void     md_post_raw(struct roff_node *);
                     83: static void     md_post_word(struct roff_node *);
                     84: static void     md_post_pc(struct roff_node *);
                     85: static void     md_post_Bk(struct roff_node *);
                     86: static void     md_post_Bl(struct roff_node *);
                     87: static void     md_post_D1(struct roff_node *);
                     88: static void     md_post_En(struct roff_node *);
                     89: static void     md_post_Eo(struct roff_node *);
                     90: static void     md_post_Fa(struct roff_node *);
                     91: static void     md_post_Fd(struct roff_node *);
                     92: static void     md_post_Fn(struct roff_node *);
                     93: static void     md_post_Fo(struct roff_node *);
                     94: static void     md_post_In(struct roff_node *);
                     95: static void     md_post_It(struct roff_node *);
                     96: static void     md_post_Lb(struct roff_node *);
                     97: static void     md_post_Nm(struct roff_node *);
                     98: static void     md_post_Pf(struct roff_node *);
                     99: static void     md_post_Vt(struct roff_node *);
                    100: static void     md_post__T(struct roff_node *);
                    101:
                    102: static const struct md_act md_acts[MDOC_MAX + 1] = {
                    103:        { NULL, md_pre_Ap, NULL, NULL, NULL }, /* Ap */
                    104:        { NULL, NULL, NULL, NULL, NULL }, /* Dd */
                    105:        { NULL, NULL, NULL, NULL, NULL }, /* Dt */
                    106:        { NULL, NULL, NULL, NULL, NULL }, /* Os */
                    107:        { NULL, md_pre_Sh, NULL, NULL, NULL }, /* Sh */
                    108:        { NULL, md_pre_Sh, NULL, NULL, NULL }, /* Ss */
                    109:        { NULL, md_pre_Pp, NULL, NULL, NULL }, /* Pp */
                    110:        { md_cond_body, md_pre_D1, md_post_D1, NULL, NULL }, /* D1 */
                    111:        { md_cond_body, md_pre_Dl, md_post_D1, NULL, NULL }, /* Dl */
                    112:        { md_cond_body, md_pre_Bd, md_post_D1, NULL, NULL }, /* Bd */
                    113:        { NULL, NULL, NULL, NULL, NULL }, /* Ed */
                    114:        { md_cond_body, md_pre_Bl, md_post_Bl, NULL, NULL }, /* Bl */
                    115:        { NULL, NULL, NULL, NULL, NULL }, /* El */
                    116:        { NULL, md_pre_It, md_post_It, NULL, NULL }, /* It */
                    117:        { NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Ad */
                    118:        { NULL, NULL, NULL, NULL, NULL }, /* An */
                    119:        { NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Ar */
                    120:        { NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Cd */
                    121:        { NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Cm */
                    122:        { NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Dv */
                    123:        { NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Er */
                    124:        { NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Ev */
                    125:        { NULL, NULL, NULL, NULL, NULL }, /* Ex */
                    126:        { NULL, md_pre_Fa, md_post_Fa, NULL, NULL }, /* Fa */
                    127:        { NULL, md_pre_Fd, md_post_Fd, "**", "**" }, /* Fd */
                    128:        { NULL, md_pre_raw, md_post_raw, "**-", "**" }, /* Fl */
                    129:        { NULL, md_pre_Fn, md_post_Fn, NULL, NULL }, /* Fn */
                    130:        { NULL, md_pre_Fd, md_post_raw, "*", "*" }, /* Ft */
                    131:        { NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Ic */
                    132:        { NULL, md_pre_In, md_post_In, "*", "*" }, /* In */
                    133:        { NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Li */
                    134:        { md_cond_head, md_pre_Nd, NULL, NULL, NULL }, /* Nd */
                    135:        { NULL, md_pre_Nm, md_post_Nm, "**", "**" }, /* Nm */
                    136:        { md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Op */
                    137:        { NULL, md_pre_Fd, md_post_raw, "*", "*" }, /* Ot */
                    138:        { NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Pa */
                    139:        { NULL, NULL, NULL, NULL, NULL }, /* Rv */
                    140:        { NULL, NULL, NULL, NULL, NULL }, /* St */
                    141:        { NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Va */
                    142:        { NULL, md_pre_Vt, md_post_Vt, "*", "*" }, /* Vt */
                    143:        { NULL, md_pre_Xr, NULL, NULL, NULL }, /* Xr */
                    144:        { NULL, NULL, md_post_pc, NULL, NULL }, /* %A */
                    145:        { NULL, md_pre_raw, md_post_pc, "*", "*" }, /* %B */
                    146:        { NULL, NULL, md_post_pc, NULL, NULL }, /* %D */
                    147:        { NULL, md_pre_raw, md_post_pc, "*", "*" }, /* %I */
                    148:        { NULL, md_pre_raw, md_post_pc, "*", "*" }, /* %J */
                    149:        { NULL, NULL, md_post_pc, NULL, NULL }, /* %N */
                    150:        { NULL, NULL, md_post_pc, NULL, NULL }, /* %O */
                    151:        { NULL, NULL, md_post_pc, NULL, NULL }, /* %P */
                    152:        { NULL, NULL, md_post_pc, NULL, NULL }, /* %R */
                    153:        { NULL, md_pre__T, md_post__T, NULL, NULL }, /* %T */
                    154:        { NULL, NULL, md_post_pc, NULL, NULL }, /* %V */
                    155:        { NULL, NULL, NULL, NULL, NULL }, /* Ac */
                    156:        { md_cond_body, md_pre_word, md_post_word, "<", ">" }, /* Ao */
                    157:        { md_cond_body, md_pre_word, md_post_word, "<", ">" }, /* Aq */
                    158:        { NULL, NULL, NULL, NULL, NULL }, /* At */
                    159:        { NULL, NULL, NULL, NULL, NULL }, /* Bc */
                    160:        { NULL, NULL, NULL, NULL, NULL }, /* Bf XXX not implemented */
                    161:        { md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Bo */
                    162:        { md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Bq */
                    163:        { NULL, NULL, NULL, NULL, NULL }, /* Bsx */
                    164:        { NULL, NULL, NULL, NULL, NULL }, /* Bx */
                    165:        { NULL, NULL, NULL, NULL, NULL }, /* Db */
                    166:        { NULL, NULL, NULL, NULL, NULL }, /* Dc */
                    167:        { md_cond_body, md_pre_word, md_post_word, "\"", "\"" }, /* Do */
                    168:        { md_cond_body, md_pre_word, md_post_word, "\"", "\"" }, /* Dq */
                    169:        { NULL, NULL, NULL, NULL, NULL }, /* Ec */
                    170:        { NULL, NULL, NULL, NULL, NULL }, /* Ef */
                    171:        { NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Em */
                    172:        { md_cond_body, md_pre_Eo, md_post_Eo, NULL, NULL }, /* Eo */
                    173:        { NULL, NULL, NULL, NULL, NULL }, /* Fx */
                    174:        { NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Ms */
                    175:        { NULL, md_pre_No, NULL, NULL, NULL }, /* No */
                    176:        { NULL, md_pre_Ns, NULL, NULL, NULL }, /* Ns */
                    177:        { NULL, NULL, NULL, NULL, NULL }, /* Nx */
                    178:        { NULL, NULL, NULL, NULL, NULL }, /* Ox */
                    179:        { NULL, NULL, NULL, NULL, NULL }, /* Pc */
                    180:        { NULL, NULL, md_post_Pf, NULL, NULL }, /* Pf */
                    181:        { md_cond_body, md_pre_word, md_post_word, "(", ")" }, /* Po */
                    182:        { md_cond_body, md_pre_word, md_post_word, "(", ")" }, /* Pq */
                    183:        { NULL, NULL, NULL, NULL, NULL }, /* Qc */
                    184:        { md_cond_body, md_pre_raw, md_post_raw, "'`", "`'" }, /* Ql */
                    185:        { md_cond_body, md_pre_word, md_post_word, "\"", "\"" }, /* Qo */
                    186:        { md_cond_body, md_pre_word, md_post_word, "\"", "\"" }, /* Qq */
                    187:        { NULL, NULL, NULL, NULL, NULL }, /* Re */
                    188:        { md_cond_body, md_pre_Rs, NULL, NULL, NULL }, /* Rs */
                    189:        { NULL, NULL, NULL, NULL, NULL }, /* Sc */
                    190:        { md_cond_body, md_pre_word, md_post_word, "'", "'" }, /* So */
                    191:        { md_cond_body, md_pre_word, md_post_word, "'", "'" }, /* Sq */
                    192:        { NULL, md_pre_Sm, NULL, NULL, NULL }, /* Sm */
                    193:        { NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Sx */
                    194:        { NULL, md_pre_raw, md_post_raw, "**", "**" }, /* Sy */
                    195:        { NULL, md_pre_raw, md_post_raw, "`", "`" }, /* Tn */
                    196:        { NULL, NULL, NULL, NULL, NULL }, /* Ux */
                    197:        { NULL, NULL, NULL, NULL, NULL }, /* Xc */
                    198:        { NULL, NULL, NULL, NULL, NULL }, /* Xo */
                    199:        { NULL, md_pre_Fo, md_post_Fo, "**", "**" }, /* Fo */
                    200:        { NULL, NULL, NULL, NULL, NULL }, /* Fc */
                    201:        { md_cond_body, md_pre_word, md_post_word, "[", "]" }, /* Oo */
                    202:        { NULL, NULL, NULL, NULL, NULL }, /* Oc */
                    203:        { NULL, md_pre_Bk, md_post_Bk, NULL, NULL }, /* Bk */
                    204:        { NULL, NULL, NULL, NULL, NULL }, /* Ek */
                    205:        { NULL, NULL, NULL, NULL, NULL }, /* Bt */
                    206:        { NULL, NULL, NULL, NULL, NULL }, /* Hf */
                    207:        { NULL, md_pre_raw, md_post_raw, "*", "*" }, /* Fr */
                    208:        { NULL, NULL, NULL, NULL, NULL }, /* Ud */
                    209:        { NULL, NULL, md_post_Lb, NULL, NULL }, /* Lb */
                    210:        { NULL, md_pre_Pp, NULL, NULL, NULL }, /* Lp */
                    211:        { NULL, md_pre_Lk, NULL, NULL, NULL }, /* Lk */
                    212:        { NULL, md_pre_raw, md_post_raw, "<", ">" }, /* Mt */
                    213:        { md_cond_body, md_pre_word, md_post_word, "{", "}" }, /* Brq */
                    214:        { md_cond_body, md_pre_word, md_post_word, "{", "}" }, /* Bro */
                    215:        { NULL, NULL, NULL, NULL, NULL }, /* Brc */
                    216:        { NULL, NULL, md_post_pc, NULL, NULL }, /* %C */
                    217:        { NULL, md_pre_skip, NULL, NULL, NULL }, /* Es */
                    218:        { md_cond_body, md_pre_En, md_post_En, NULL, NULL }, /* En */
                    219:        { NULL, NULL, NULL, NULL, NULL }, /* Dx */
                    220:        { NULL, NULL, md_post_pc, NULL, NULL }, /* %Q */
                    221:        { NULL, md_pre_br, NULL, NULL, NULL }, /* br */
                    222:        { NULL, md_pre_Pp, NULL, NULL, NULL }, /* sp */
                    223:        { NULL, NULL, md_post_pc, NULL, NULL }, /* %U */
                    224:        { NULL, NULL, NULL, NULL, NULL }, /* Ta */
                    225:        { NULL, NULL, NULL, NULL, NULL }, /* ll */
                    226:        { NULL, NULL, NULL, NULL, NULL }, /* ROOT */
                    227: };
                    228:
                    229: static int      outflags;
                    230: #define        MD_spc           (1 << 0)  /* Blank character before next word. */
                    231: #define        MD_spc_force     (1 << 1)  /* Even before trailing punctuation. */
                    232: #define        MD_nonl          (1 << 2)  /* Prevent linebreak in markdown code. */
                    233: #define        MD_nl            (1 << 3)  /* Break markdown code line. */
                    234: #define        MD_br            (1 << 4)  /* Insert an output line break. */
                    235: #define        MD_sp            (1 << 5)  /* Insert a paragraph break. */
                    236: #define        MD_Sm            (1 << 6)  /* Horizontal spacing mode. */
                    237: #define        MD_Bk            (1 << 7)  /* Word keep mode. */
                    238:
                    239: static int      escflags; /* Escape in generated markdown code: */
                    240: #define        ESC_BOL  (1 << 0)  /* "#*+-" near the beginning of a line. */
                    241: #define        ESC_NUM  (1 << 1)  /* "." after a leading number. */
                    242: #define        ESC_HYP  (1 << 2)  /* "(" immediately after "]". */
                    243: #define        ESC_PAR  (1 << 3)  /* ")" when "(" is open. */
                    244: #define        ESC_SQU  (1 << 4)  /* "]" when "[" is open. */
                    245: #define        ESC_FON  (1 << 5)  /* "*" immediately after unrelated "*". */
                    246:
                    247: static int      code_blocks, quote_blocks, list_blocks;
                    248: static int      outcount;
                    249:
                    250: void
                    251: markdown_mdoc(void *arg, const struct roff_man *mdoc)
                    252: {
                    253:        outflags = MD_Sm;
                    254:        md_word(mdoc->meta.title);
                    255:        if (mdoc->meta.msec != NULL) {
                    256:                outflags &= ~MD_spc;
                    257:                md_word("(");
                    258:                md_word(mdoc->meta.msec);
                    259:                md_word(")");
                    260:        }
                    261:        md_word("-");
                    262:        md_word(mdoc->meta.vol);
                    263:        if (mdoc->meta.arch != NULL) {
                    264:                md_word("(");
                    265:                md_word(mdoc->meta.arch);
                    266:                md_word(")");
                    267:        }
                    268:        outflags |= MD_sp;
                    269:
                    270:        md_nodelist(mdoc->first->child);
                    271:
                    272:        outflags |= MD_sp;
                    273:        md_word(mdoc->meta.os);
                    274:        md_word("-");
                    275:        md_word(mdoc->meta.date);
                    276:        putchar('\n');
                    277: }
                    278:
                    279: static void
                    280: md_nodelist(struct roff_node *n)
                    281: {
                    282:        while (n != NULL) {
                    283:                md_node(n);
                    284:                n = n->next;
                    285:        }
                    286: }
                    287:
                    288: static void
                    289: md_node(struct roff_node *n)
                    290: {
                    291:        const struct md_act     *act;
                    292:        int                      cond, process_children;
                    293:
                    294:        if (n->flags & NODE_NOPRT)
                    295:                return;
                    296:
                    297:        if (outflags & MD_nonl)
                    298:                outflags &= ~(MD_nl | MD_sp);
                    299:        else if (outflags & MD_spc && n->flags & NODE_LINE)
                    300:                outflags |= MD_nl;
                    301:
                    302:        act = NULL;
                    303:        cond = 0;
                    304:        process_children = 1;
                    305:        n->flags &= ~NODE_ENDED;
                    306:
                    307:        switch (n->type) {
                    308:        case ROFFT_TEXT:
                    309:                if (n->flags & NODE_DELIMC)
                    310:                        outflags &= ~(MD_spc | MD_spc_force);
                    311:                else if (outflags & MD_Sm)
                    312:                        outflags |= MD_spc_force;
                    313:                md_word(n->string);
                    314:                if (n->flags & NODE_DELIMO)
                    315:                        outflags &= ~(MD_spc | MD_spc_force);
                    316:                else if (outflags & MD_Sm)
                    317:                        outflags |= MD_spc;
                    318:                break;
                    319:        default:
                    320:                act = md_acts + n->tok;
                    321:                cond = act->cond == NULL || (*act->cond)(n);
                    322:                if (cond && act->pre != NULL &&
                    323:                    (n->end == ENDBODY_NOT || n->child != NULL))
                    324:                        process_children = (*act->pre)(n);
                    325:                break;
                    326:        }
                    327:
                    328:        if (process_children && n->child != NULL)
                    329:                md_nodelist(n->child);
                    330:
                    331:        if (n->flags & NODE_ENDED)
                    332:                return;
                    333:
                    334:        if (cond && act->post != NULL)
                    335:                (*act->post)(n);
                    336:
                    337:        if (n->end != ENDBODY_NOT)
                    338:                n->body->flags |= NODE_ENDED;
                    339: }
                    340:
                    341: static const char *
                    342: md_stack(char c)
                    343: {
                    344:        static char     *stack;
                    345:        static size_t    sz;
                    346:        static size_t    cur;
                    347:
                    348:        switch (c) {
                    349:        case '\0':
                    350:                break;
                    351:        case (char)-1:
                    352:                assert(cur);
                    353:                stack[--cur] = '\0';
                    354:                break;
                    355:        default:
                    356:                if (cur + 1 >= sz) {
                    357:                        sz += 8;
                    358:                        stack = mandoc_realloc(stack, sz);
                    359:                }
                    360:                stack[cur] = c;
                    361:                stack[++cur] = '\0';
                    362:                break;
                    363:        }
                    364:        return stack == NULL ? "" : stack;
                    365: }
                    366:
                    367: /*
                    368:  * Handle vertical and horizontal spacing.
                    369:  */
                    370: static void
                    371: md_preword(void)
                    372: {
                    373:        /*
                    374:         * If a list block is nested inside a code block or a blockquote,
                    375:         * blank lines for paragraph breaks no longer work; instead,
                    376:         * they terminate the list.  Work around this markdown issue
                    377:         * by using mere line breaks instead.
                    378:         */
                    379:        if (list_blocks && outflags & MD_sp) {
                    380:                outflags &= ~MD_sp;
                    381:                outflags |= MD_br;
                    382:        }
                    383:
                    384:        /* End the old line if requested. */
                    385:
                    386:        if (outflags & MD_sp)
                    387:                putchar('\n');
                    388:        else if (outflags & MD_br) {
                    389:                putchar(' ');
                    390:                putchar(' ');
                    391: #ifdef DEBUG
                    392:                putchar(':');
                    393:                putchar(':');
                    394:                putchar(' ');
                    395:                putchar(' ');
                    396: #endif
                    397:        }
                    398:
                    399:        /* Start a new line if necessary. */
                    400:
                    401:        if (outflags & (MD_nl | MD_br | MD_sp)) {
                    402:                putchar('\n');
                    403:                fputs(md_stack('\0'), stdout);
                    404:                outflags &= ~(MD_nl | MD_br | MD_sp);
                    405:                escflags = ESC_BOL;
                    406:                outcount = 0;
                    407:
                    408:        /* Handle horizontal spacing. */
                    409:
                    410:        } else if (outflags & MD_spc) {
                    411:                if (outflags & MD_Bk)
                    412:                        fputs("&nbsp;", stdout);
                    413:                else
                    414:                        putchar(' ');
                    415:                escflags &= ~ESC_FON;
                    416:                outcount++;
                    417:        }
                    418:
                    419:        outflags &= ~(MD_spc_force | MD_nonl);
                    420:        if (outflags & MD_Sm)
                    421:                outflags |= MD_spc;
                    422:        else
                    423:                outflags &= ~MD_spc;
                    424: }
                    425:
                    426: /*
                    427:  * Print markdown syntax elements.
                    428:  * Can also be used for constant strings when neither escaping
                    429:  * nor delimiter handling is required.
                    430:  */
                    431: static void
                    432: md_rawword(const char *s)
                    433: {
                    434:        md_preword();
                    435:
                    436:        if (*s == 0)
                    437:                return;
                    438:
                    439:        if (escflags & ESC_FON) {
                    440:                escflags &= ~ESC_FON;
                    441:                if (*s == '*' && !code_blocks)
                    442:                        fputs("&zwnj;", stdout);
                    443:        }
                    444:
                    445:        while (*s != '\0') {
                    446:                switch(*s) {
                    447:                case '(':
                    448:                        escflags |= ESC_PAR;
                    449:                        break;
                    450:                case ')':
                    451:                        escflags |= ~ESC_PAR;
                    452:                        break;
                    453:                case '*':
                    454:                        if (s[1] == '\0')
                    455:                                escflags |= ESC_FON;
                    456:                        break;
                    457:                case '[':
                    458:                        escflags |= ESC_SQU;
                    459:                        break;
                    460:                case ']':
                    461:                        escflags |= ESC_HYP;
                    462:                        escflags &= ~ESC_SQU;
                    463:                        break;
                    464:                default:
                    465:                        break;
                    466:                }
                    467:                md_char(*s++);
                    468:        }
                    469: }
                    470:
                    471: /*
                    472:  * Print text and mdoc(7) syntax elements.
                    473:  */
                    474: static void
                    475: md_word(const char *s)
                    476: {
                    477:        const char      *seq, *prevfont, *currfont, *nextfont;
                    478:        char             c;
                    479:        int              bs, sz, uc;
                    480:
                    481:        /* No spacing before closing delimiters. */
                    482:        if (s[0] != '\0' && s[1] == '\0' &&
                    483:            strchr("!),.:;?]", s[0]) != NULL &&
                    484:            (outflags & MD_spc_force) == 0)
                    485:                outflags &= ~MD_spc;
                    486:
                    487:        md_preword();
                    488:
                    489:        /* No spacing after opening delimiters. */
                    490:        if ((s[0] == '(' || s[0] == '[') && s[1] == '\0')
                    491:                outflags &= ~MD_spc;
                    492:
                    493:        prevfont = currfont = "";
                    494:        while ((c = *s++) != '\0') {
                    495:                bs = 0;
                    496:                switch(c) {
                    497:                case ASCII_NBRSP:
                    498:                        if (code_blocks)
                    499:                                c = ' ';
                    500:                        else {
                    501:                                md_named("nbsp");
                    502:                                c = '\0';
                    503:                        }
                    504:                        break;
                    505:                case ASCII_HYPH:
                    506:                        bs = escflags & ESC_BOL && !code_blocks;
                    507:                        c = '-';
                    508:                        break;
                    509:                case ASCII_BREAK:
                    510:                        continue;
                    511:                case '#':
                    512:                case '+':
                    513:                case '-':
                    514:                        bs = escflags & ESC_BOL && !code_blocks;
                    515:                        break;
                    516:                case '(':
                    517:                        bs = escflags & ESC_HYP && !code_blocks;
                    518:                        break;
                    519:                case ')':
                    520:                        bs = escflags & ESC_PAR && !code_blocks;
                    521:                        break;
                    522:                case '*':
                    523:                case '[':
                    524:                case '_':
                    525:                case '`':
                    526:                        bs = !code_blocks;
                    527:                        break;
                    528:                case '.':
                    529:                        bs = escflags & ESC_NUM && !code_blocks;
                    530:                        break;
                    531:                case '<':
                    532:                        if (code_blocks == 0) {
                    533:                                md_named("lt");
                    534:                                c = '\0';
                    535:                        }
                    536:                        break;
                    537:                case '=':
                    538:                        if (escflags & ESC_BOL && !code_blocks) {
                    539:                                md_named("equals");
                    540:                                c = '\0';
                    541:                        }
                    542:                        break;
                    543:                case '>':
                    544:                        if (code_blocks == 0) {
                    545:                                md_named("gt");
                    546:                                c = '\0';
                    547:                        }
                    548:                        break;
                    549:                case '\\':
                    550:                        uc = 0;
                    551:                        nextfont = NULL;
                    552:                        switch (mandoc_escape(&s, &seq, &sz)) {
                    553:                        case ESCAPE_UNICODE:
                    554:                                uc = mchars_num2uc(seq + 1, sz - 1);
                    555:                                break;
                    556:                        case ESCAPE_NUMBERED:
                    557:                                uc = mchars_num2char(seq, sz);
                    558:                                break;
                    559:                        case ESCAPE_SPECIAL:
                    560:                                uc = mchars_spec2cp(seq, sz);
                    561:                                break;
                    562:                        case ESCAPE_FONTBOLD:
                    563:                                nextfont = "**";
                    564:                                break;
                    565:                        case ESCAPE_FONTITALIC:
                    566:                                nextfont = "*";
                    567:                                break;
                    568:                        case ESCAPE_FONTBI:
                    569:                                nextfont = "***";
                    570:                                break;
                    571:                        case ESCAPE_FONT:
                    572:                        case ESCAPE_FONTROMAN:
                    573:                                nextfont = "";
                    574:                                break;
                    575:                        case ESCAPE_FONTPREV:
                    576:                                nextfont = prevfont;
                    577:                                break;
                    578:                        case ESCAPE_NOSPACE:
                    579:                        case ESCAPE_SKIPCHAR:
                    580:                        case ESCAPE_OVERSTRIKE:
                    581:                                /* XXX not implemented */
                    582:                                /* FALLTHROUGH */
                    583:                        case ESCAPE_ERROR:
                    584:                        default:
                    585:                                break;
                    586:                        }
                    587:                        if (nextfont != NULL && !code_blocks) {
                    588:                                if (*currfont != '\0') {
                    589:                                        outflags &= ~MD_spc;
                    590:                                        md_rawword(currfont);
                    591:                                }
                    592:                                prevfont = currfont;
                    593:                                currfont = nextfont;
                    594:                                if (*currfont != '\0') {
                    595:                                        outflags &= ~MD_spc;
                    596:                                        md_rawword(currfont);
                    597:                                }
                    598:                        }
                    599:                        if (uc) {
                    600:                                if ((uc < 0x20 && uc != 0x09) ||
                    601:                                    (uc > 0x7E && uc < 0xA0))
                    602:                                        uc = 0xFFFD;
                    603:                                if (code_blocks) {
                    604:                                        seq = mchars_uc2str(uc);
                    605:                                        fputs(seq, stdout);
                    606:                                        outcount += strlen(seq);
                    607:                                } else {
                    608:                                        printf("&#%d;", uc);
                    609:                                        outcount++;
                    610:                                }
                    611:                                escflags &= ~ESC_FON;
                    612:                        }
                    613:                        c = '\0';
                    614:                        break;
                    615:                case ']':
                    616:                        bs = escflags & ESC_SQU && !code_blocks;
                    617:                        escflags |= ESC_HYP;
                    618:                        break;
                    619:                default:
                    620:                        break;
                    621:                }
                    622:                if (bs)
                    623:                        putchar('\\');
                    624:                md_char(c);
                    625:        }
                    626:        if (*currfont != '\0') {
                    627:                outflags &= ~MD_spc;
                    628:                md_rawword(currfont);
                    629:        }
                    630: }
                    631:
                    632: /*
                    633:  * Print a single HTML named character reference.
                    634:  */
                    635: static void
                    636: md_named(const char *s)
                    637: {
                    638:        printf("&%s;", s);
                    639:        escflags &= ~ESC_FON;
                    640:        outcount++;
                    641: }
                    642:
                    643: /*
                    644:  * Print a single raw character and maintain certain escape flags.
                    645:  */
                    646: static void
                    647: md_char(unsigned char c)
                    648: {
                    649:        if (c != '\0') {
                    650:                putchar(c);
                    651:                if (c == '*')
                    652:                        escflags |= ESC_FON;
                    653:                else
                    654:                        escflags &= ~ESC_FON;
                    655:                outcount++;
                    656:        }
                    657:        if (c != ']')
                    658:                escflags &= ~ESC_HYP;
                    659:        if (c == ' ' || c == '\t' || c == '>')
                    660:                return;
                    661:        if (isdigit(c) == 0)
                    662:                escflags &= ~ESC_NUM;
                    663:        else if (escflags & ESC_BOL)
                    664:                escflags |= ESC_NUM;
                    665:        escflags &= ~ESC_BOL;
                    666: }
                    667:
                    668: static int
                    669: md_cond_head(struct roff_node *n)
                    670: {
                    671:        return n->type == ROFFT_HEAD;
                    672: }
                    673:
                    674: static int
                    675: md_cond_body(struct roff_node *n)
                    676: {
                    677:        return n->type == ROFFT_BODY;
                    678: }
                    679:
                    680: static int
                    681: md_pre_raw(struct roff_node *n)
                    682: {
                    683:        const char      *prefix;
                    684:
                    685:        if ((prefix = md_acts[n->tok].prefix) != NULL) {
                    686:                md_rawword(prefix);
                    687:                outflags &= ~MD_spc;
                    688:        }
                    689:        return 1;
                    690: }
                    691:
                    692: static void
                    693: md_post_raw(struct roff_node *n)
                    694: {
                    695:        const char      *suffix;
                    696:
                    697:        if ((suffix = md_acts[n->tok].suffix) != NULL) {
                    698:                outflags &= ~(MD_spc | MD_nl);
                    699:                md_rawword(suffix);
                    700:        }
                    701: }
                    702:
                    703: static int
                    704: md_pre_word(struct roff_node *n)
                    705: {
                    706:        const char      *prefix;
                    707:
                    708:        if ((prefix = md_acts[n->tok].prefix) != NULL) {
                    709:                md_word(prefix);
                    710:                outflags &= ~MD_spc;
                    711:        }
                    712:        return 1;
                    713: }
                    714:
                    715: static void
                    716: md_post_word(struct roff_node *n)
                    717: {
                    718:        const char      *suffix;
                    719:
                    720:        if ((suffix = md_acts[n->tok].suffix) != NULL) {
                    721:                outflags &= ~(MD_spc | MD_nl);
                    722:                md_word(suffix);
                    723:        }
                    724: }
                    725:
                    726: static void
                    727: md_post_pc(struct roff_node *n)
                    728: {
                    729:        md_post_raw(n);
                    730:        if (n->parent->tok != MDOC_Rs)
                    731:                return;
                    732:        if (n->next != NULL) {
                    733:                md_word(",");
                    734:                if (n->prev != NULL &&
                    735:                    n->prev->tok == n->tok &&
                    736:                    n->next->tok == n->tok)
                    737:                        md_word("and");
                    738:        } else {
                    739:                md_word(".");
                    740:                outflags |= MD_nl;
                    741:        }
                    742: }
                    743:
                    744: static int
                    745: md_pre_skip(struct roff_node *n)
                    746: {
                    747:        return 0;
                    748: }
                    749:
                    750: static void
                    751: md_pre_syn(struct roff_node *n)
                    752: {
                    753:        if (n->prev == NULL || ! (n->flags & NODE_SYNPRETTY))
                    754:                return;
                    755:
                    756:        if (n->prev->tok == n->tok &&
                    757:            n->tok != MDOC_Ft &&
                    758:            n->tok != MDOC_Fo &&
                    759:            n->tok != MDOC_Fn) {
                    760:                outflags |= MD_br;
                    761:                return;
                    762:        }
                    763:
                    764:        switch (n->prev->tok) {
                    765:        case MDOC_Fd:
                    766:        case MDOC_Fn:
                    767:        case MDOC_Fo:
                    768:        case MDOC_In:
                    769:        case MDOC_Vt:
                    770:                outflags |= MD_sp;
                    771:                break;
                    772:        case MDOC_Ft:
                    773:                if (n->tok != MDOC_Fn && n->tok != MDOC_Fo) {
                    774:                        outflags |= MD_sp;
                    775:                        break;
                    776:                }
                    777:                /* FALLTHROUGH */
                    778:        default:
                    779:                outflags |= MD_br;
                    780:                break;
                    781:        }
                    782: }
                    783:
                    784: static int
                    785: md_pre_Ap(struct roff_node *n)
                    786: {
                    787:        outflags &= ~MD_spc;
                    788:        md_word("'");
                    789:        outflags &= ~MD_spc;
                    790:        return 0;
                    791: }
                    792:
                    793: static int
                    794: md_pre_Bd(struct roff_node *n)
                    795: {
                    796:        switch (n->norm->Bd.type) {
                    797:        case DISP_unfilled:
                    798:        case DISP_literal:
                    799:                return md_pre_Dl(n);
                    800:        default:
                    801:                return md_pre_D1(n);
                    802:        }
                    803: }
                    804:
                    805: static int
                    806: md_pre_Bk(struct roff_node *n)
                    807: {
                    808:        switch (n->type) {
                    809:        case ROFFT_BLOCK:
                    810:                return 1;
                    811:        case ROFFT_BODY:
                    812:                outflags |= MD_Bk;
                    813:                return 1;
                    814:        default:
                    815:                return 0;
                    816:        }
                    817: }
                    818:
                    819: static void
                    820: md_post_Bk(struct roff_node *n)
                    821: {
                    822:        if (n->type == ROFFT_BODY)
                    823:                outflags &= ~MD_Bk;
                    824: }
                    825:
                    826: static int
                    827: md_pre_Bl(struct roff_node *n)
                    828: {
                    829:        n->norm->Bl.count = 0;
                    830:        if (n->norm->Bl.type == LIST_column)
                    831:                md_pre_Dl(n);
                    832:        outflags |= MD_sp;
                    833:        return 1;
                    834: }
                    835:
                    836: static void
                    837: md_post_Bl(struct roff_node *n)
                    838: {
                    839:        n->norm->Bl.count = 0;
                    840:        if (n->norm->Bl.type == LIST_column)
                    841:                md_post_D1(n);
                    842:        outflags |= MD_sp;
                    843: }
                    844:
                    845: static int
                    846: md_pre_D1(struct roff_node *n)
                    847: {
                    848:        /*
                    849:         * Markdown blockquote syntax does not work inside code blocks.
                    850:         * The best we can do is fall back to another nested code block.
                    851:         */
                    852:        if (code_blocks) {
                    853:                md_stack('\t');
                    854:                code_blocks++;
                    855:        } else {
                    856:                md_stack('>');
                    857:                quote_blocks++;
                    858:        }
                    859:        outflags |= MD_sp;
                    860:        return 1;
                    861: }
                    862:
                    863: static void
                    864: md_post_D1(struct roff_node *n)
                    865: {
                    866:        md_stack((char)-1);
                    867:        if (code_blocks)
                    868:                code_blocks--;
                    869:        else
                    870:                quote_blocks--;
                    871:        outflags |= MD_sp;
                    872: }
                    873:
                    874: static int
                    875: md_pre_Dl(struct roff_node *n)
                    876: {
                    877:        /*
                    878:         * Markdown code block syntax does not work inside blockquotes.
                    879:         * The best we can do is fall back to another nested blockquote.
                    880:         */
                    881:        if (quote_blocks) {
                    882:                md_stack('>');
                    883:                quote_blocks++;
                    884:        } else {
                    885:                md_stack('\t');
                    886:                code_blocks++;
                    887:        }
                    888:        outflags |= MD_sp;
                    889:        return 1;
                    890: }
                    891:
                    892: static int
                    893: md_pre_En(struct roff_node *n)
                    894: {
                    895:        if (n->norm->Es == NULL ||
                    896:            n->norm->Es->child == NULL)
                    897:                return 1;
                    898:
                    899:        md_word(n->norm->Es->child->string);
                    900:        outflags &= ~MD_spc;
                    901:        return 1;
                    902: }
                    903:
                    904: static void
                    905: md_post_En(struct roff_node *n)
                    906: {
                    907:        if (n->norm->Es == NULL ||
                    908:            n->norm->Es->child == NULL ||
                    909:            n->norm->Es->child->next == NULL)
                    910:                return;
                    911:
                    912:        outflags &= ~MD_spc;
                    913:        md_word(n->norm->Es->child->next->string);
                    914: }
                    915:
                    916: static int
                    917: md_pre_Eo(struct roff_node *n)
                    918: {
                    919:        if (n->end == ENDBODY_NOT &&
                    920:            n->parent->head->child == NULL &&
                    921:            n->child != NULL &&
                    922:            n->child->end != ENDBODY_NOT)
                    923:                md_preword();
                    924:        else if (n->end != ENDBODY_NOT ? n->child != NULL :
                    925:            n->parent->head->child != NULL && (n->child != NULL ||
                    926:            (n->parent->tail != NULL && n->parent->tail->child != NULL)))
                    927:                outflags &= ~(MD_spc | MD_nl);
                    928:        return 1;
                    929: }
                    930:
                    931: static void
                    932: md_post_Eo(struct roff_node *n)
                    933: {
                    934:        int      body, tail;
                    935:
                    936:        if (n->end != ENDBODY_NOT) {
                    937:                outflags |= MD_spc;
                    938:                return;
                    939:        }
                    940:
                    941:        body = n->child != NULL || n->parent->head->child != NULL;
                    942:        tail = n->parent->tail != NULL && n->parent->tail->child != NULL;
                    943:
                    944:        if (body && tail)
                    945:                outflags &= ~MD_spc;
                    946:         else if ( ! (body || tail))
                    947:                md_preword();
                    948:         else if ( ! tail)
                    949:                outflags |= MD_spc;
                    950: }
                    951:
                    952: static int
                    953: md_pre_Fa(struct roff_node *n)
                    954: {
                    955:        int      am_Fa;
                    956:
                    957:        am_Fa = n->tok == MDOC_Fa;
                    958:
                    959:        if (am_Fa)
                    960:                n = n->child;
                    961:
                    962:        while (n != NULL) {
                    963:                md_rawword("*");
                    964:                outflags &= ~MD_spc;
                    965:                md_node(n);
                    966:                outflags &= ~MD_spc;
                    967:                md_rawword("*");
                    968:                if ((n = n->next) != NULL)
                    969:                        md_word(",");
                    970:        }
                    971:        return 0;
                    972: }
                    973:
                    974: static void
                    975: md_post_Fa(struct roff_node *n)
                    976: {
                    977:        if (n->next != NULL && n->next->tok == MDOC_Fa)
                    978:                md_word(",");
                    979: }
                    980:
                    981: static int
                    982: md_pre_Fd(struct roff_node *n)
                    983: {
                    984:        md_pre_syn(n);
                    985:        md_pre_raw(n);
                    986:        return 1;
                    987: }
                    988:
                    989: static void
                    990: md_post_Fd(struct roff_node *n)
                    991: {
                    992:        md_post_raw(n);
                    993:        outflags |= MD_br;
                    994: }
                    995:
                    996: static int
                    997: md_pre_Fn(struct roff_node *n)
                    998: {
                    999:        md_pre_syn(n);
                   1000:
                   1001:        if ((n = n->child) == NULL)
                   1002:                return 0;
                   1003:
                   1004:        md_rawword("**");
                   1005:        outflags &= ~MD_spc;
                   1006:        md_node(n);
                   1007:        outflags &= ~MD_spc;
                   1008:        md_rawword("**");
                   1009:        outflags &= ~MD_spc;
                   1010:        md_word("(");
                   1011:
                   1012:        if ((n = n->next) != NULL)
                   1013:                md_pre_Fa(n);
                   1014:        return 0;
                   1015: }
                   1016:
                   1017: static void
                   1018: md_post_Fn(struct roff_node *n)
                   1019: {
                   1020:        md_word(")");
                   1021:        if (n->flags & NODE_SYNPRETTY) {
                   1022:                md_word(";");
                   1023:                outflags |= MD_sp;
                   1024:        }
                   1025: }
                   1026:
                   1027: static int
                   1028: md_pre_Fo(struct roff_node *n)
                   1029: {
                   1030:        switch (n->type) {
                   1031:        case ROFFT_BLOCK:
                   1032:                md_pre_syn(n);
                   1033:                break;
                   1034:        case ROFFT_HEAD:
                   1035:                if (n->child == NULL)
                   1036:                        return 0;
                   1037:                md_pre_raw(n);
                   1038:                break;
                   1039:        case ROFFT_BODY:
                   1040:                outflags &= ~(MD_spc | MD_nl);
                   1041:                md_word("(");
                   1042:                break;
                   1043:        default:
                   1044:                break;
                   1045:        }
                   1046:        return 1;
                   1047: }
                   1048:
                   1049: static void
                   1050: md_post_Fo(struct roff_node *n)
                   1051: {
                   1052:        switch (n->type) {
                   1053:        case ROFFT_HEAD:
                   1054:                if (n->child != NULL)
                   1055:                        md_post_raw(n);
                   1056:                break;
                   1057:        case ROFFT_BODY:
                   1058:                md_post_Fn(n);
                   1059:                break;
                   1060:        default:
                   1061:                break;
                   1062:        }
                   1063: }
                   1064:
                   1065: static int
                   1066: md_pre_In(struct roff_node *n)
                   1067: {
                   1068:        if (n->flags & NODE_SYNPRETTY) {
                   1069:                md_pre_syn(n);
                   1070:                md_pre_raw(n);
                   1071:                md_rawword("*");
                   1072:                outflags &= ~MD_spc;
                   1073:                md_word("#include <");
                   1074:                outflags &= ~MD_spc;
                   1075:        } else {
                   1076:                md_word("<");
                   1077:                outflags &= ~MD_spc;
                   1078:                md_pre_raw(n);
                   1079:        }
                   1080:        return 1;
                   1081: }
                   1082:
                   1083: static void
                   1084: md_post_In(struct roff_node *n)
                   1085: {
                   1086:        if (n->flags & NODE_SYNPRETTY) {
                   1087:                outflags &= ~MD_spc;
                   1088:                md_rawword(">*");
                   1089:                md_post_raw(n);
                   1090:                outflags |= MD_nl;
                   1091:        } else {
                   1092:                md_post_raw(n);
                   1093:                outflags &= ~MD_spc;
                   1094:                md_rawword(">");
                   1095:        }
                   1096: }
                   1097:
                   1098: static int
                   1099: md_pre_It(struct roff_node *n)
                   1100: {
                   1101:        struct roff_node        *bln;
                   1102:
                   1103:        switch (n->type) {
                   1104:        case ROFFT_BLOCK:
                   1105:                return 1;
                   1106:
                   1107:        case ROFFT_HEAD:
                   1108:                bln = n->parent->parent;
                   1109:                if (bln->norm->Bl.comp == 0)
                   1110:                        outflags |= MD_sp;
                   1111:                outflags |= MD_nl;
                   1112:
                   1113:                switch (bln->norm->Bl.type) {
                   1114:                case LIST_item:
                   1115:                        outflags |= MD_br;
                   1116:                        return 0;
                   1117:                case LIST_inset:
                   1118:                case LIST_diag:
                   1119:                case LIST_ohang:
                   1120:                        outflags |= MD_br;
                   1121:                        return 1;
                   1122:                case LIST_tag:
                   1123:                case LIST_hang:
                   1124:                        outflags |= MD_sp;
                   1125:                        return 1;
                   1126:                case LIST_bullet:
                   1127:                        md_rawword("*\t");
                   1128:                        break;
                   1129:                case LIST_dash:
                   1130:                case LIST_hyphen:
                   1131:                        md_rawword("-\t");
                   1132:                        break;
                   1133:                case LIST_enum:
                   1134:                        md_preword();
                   1135:                        printf("%d.\t", ++bln->norm->Bl.count);
                   1136:                        escflags &= ~ESC_FON;
                   1137:                        break;
                   1138:                default:
                   1139:                        return 0;
                   1140:                }
                   1141:                outflags &= ~MD_spc;
                   1142:                outflags |= MD_nonl;
                   1143:                outcount = 0;
                   1144:                md_stack('\t');
                   1145:                if (code_blocks || quote_blocks)
                   1146:                        list_blocks++;
                   1147:                return 0;
                   1148:
                   1149:        case ROFFT_BODY:
                   1150:                bln = n->parent->parent;
                   1151:                switch (bln->norm->Bl.type) {
                   1152:                case LIST_ohang:
                   1153:                        outflags |= MD_br;
                   1154:                        break;
                   1155:                case LIST_tag:
                   1156:                case LIST_hang:
                   1157:                        md_pre_D1(n);
                   1158:                        break;
                   1159:                default:
                   1160:                        break;
                   1161:                }
                   1162:                return 1;
                   1163:
                   1164:        default:
                   1165:                return 0;
                   1166:        }
                   1167: }
                   1168:
                   1169: static void
                   1170: md_post_It(struct roff_node *n)
                   1171: {
                   1172:        struct roff_node        *bln;
                   1173:        int                      i, nc;
                   1174:
                   1175:        if (n->type != ROFFT_BODY)
                   1176:                return;
                   1177:
                   1178:        bln = n->parent->parent;
                   1179:        switch (bln->norm->Bl.type) {
                   1180:        case LIST_bullet:
                   1181:        case LIST_dash:
                   1182:        case LIST_hyphen:
                   1183:        case LIST_enum:
                   1184:                md_stack((char)-1);
                   1185:                if (code_blocks || quote_blocks)
                   1186:                        list_blocks--;
                   1187:                break;
                   1188:        case LIST_tag:
                   1189:        case LIST_hang:
                   1190:                md_post_D1(n);
                   1191:                break;
                   1192:
                   1193:        case LIST_column:
                   1194:                if (n->next == NULL)
                   1195:                        break;
                   1196:
                   1197:                /* Calculate the array index of the current column. */
                   1198:
                   1199:                i = 0;
                   1200:                while ((n = n->prev) != NULL && n->type != ROFFT_HEAD)
                   1201:                        i++;
                   1202:
                   1203:                /*
                   1204:                 * If a width was specified for this column,
                   1205:                 * subtract what printed, and
                   1206:                 * add the same spacing as in mdoc_term.c.
                   1207:                 */
                   1208:
                   1209:                nc = bln->norm->Bl.ncols;
                   1210:                i = i < nc ? strlen(bln->norm->Bl.cols[i]) - outcount +
                   1211:                    (nc < 5 ? 4 : nc == 5 ? 3 : 1) : 1;
                   1212:                if (i < 1)
                   1213:                        i = 1;
                   1214:                while (i-- > 0)
                   1215:                        putchar(' ');
                   1216:
                   1217:                outflags &= ~MD_spc;
                   1218:                escflags &= ~ESC_FON;
                   1219:                outcount = 0;
                   1220:                break;
                   1221:
                   1222:        default:
                   1223:                break;
                   1224:        }
                   1225: }
                   1226:
                   1227: static void
                   1228: md_post_Lb(struct roff_node *n)
                   1229: {
                   1230:        if (n->sec == SEC_LIBRARY)
                   1231:                outflags |= MD_br;
                   1232: }
                   1233:
                   1234: static int
                   1235: md_pre_Lk(struct roff_node *n)
                   1236: {
                   1237:        const struct roff_node *link, *descr;
                   1238:
                   1239:        if ((link = n->child) == NULL)
                   1240:                return 0;
                   1241:
                   1242:        if ((descr = link->next) != NULL) {
                   1243:                md_rawword("[");
                   1244:                outflags &= ~MD_spc;
                   1245:                while (descr != NULL) {
                   1246:                        md_word(descr->string);
                   1247:                        descr = descr->next;
                   1248:                }
                   1249:                outflags &= ~MD_spc;
                   1250:                md_rawword("](");
                   1251:        } else
                   1252:                md_rawword("<");
                   1253:
                   1254:        outflags &= ~MD_spc;
                   1255:        md_word(link->string);
                   1256:        outflags &= ~MD_spc;
                   1257:        md_rawword(link->next == NULL ? ">" : ")");
                   1258:        return 0;
                   1259: }
                   1260:
                   1261: static int
                   1262: md_pre_Nd(struct roff_node *n)
                   1263: {
                   1264:        outflags &= ~MD_nl;
                   1265:        outflags |= MD_spc;
                   1266:        md_word("-");
                   1267:        return 1;
                   1268: }
                   1269:
                   1270: static int
                   1271: md_pre_Nm(struct roff_node *n)
                   1272: {
                   1273:        switch (n->type) {
                   1274:        case ROFFT_BLOCK:
                   1275:                outflags |= MD_Bk;
                   1276:                md_pre_syn(n);
                   1277:                break;
                   1278:        case ROFFT_HEAD:
                   1279:        case ROFFT_ELEM:
                   1280:                md_pre_raw(n);
                   1281:                break;
                   1282:        default:
                   1283:                break;
                   1284:        }
                   1285:        return 1;
                   1286: }
                   1287:
                   1288: static void
                   1289: md_post_Nm(struct roff_node *n)
                   1290: {
                   1291:        switch (n->type) {
                   1292:        case ROFFT_BLOCK:
                   1293:                outflags &= ~MD_Bk;
                   1294:                break;
                   1295:        case ROFFT_HEAD:
                   1296:        case ROFFT_ELEM:
                   1297:                md_post_raw(n);
                   1298:                break;
                   1299:        default:
                   1300:                break;
                   1301:        }
                   1302: }
                   1303:
                   1304: static int
                   1305: md_pre_No(struct roff_node *n)
                   1306: {
                   1307:        outflags |= MD_spc_force;
                   1308:        return 1;
                   1309: }
                   1310:
                   1311: static int
                   1312: md_pre_Ns(struct roff_node *n)
                   1313: {
                   1314:        outflags &= ~MD_spc;
                   1315:        return 0;
                   1316: }
                   1317:
                   1318: static void
                   1319: md_post_Pf(struct roff_node *n)
                   1320: {
                   1321:        if (n->next != NULL && (n->next->flags & NODE_LINE) == 0)
                   1322:                outflags &= ~MD_spc;
                   1323: }
                   1324:
                   1325: static int
                   1326: md_pre_Pp(struct roff_node *n)
                   1327: {
                   1328:        outflags |= MD_sp;
                   1329:        return 0;
                   1330: }
                   1331:
                   1332: static int
                   1333: md_pre_Rs(struct roff_node *n)
                   1334: {
                   1335:        if (n->sec == SEC_SEE_ALSO)
                   1336:                outflags |= MD_sp;
                   1337:        return 1;
                   1338: }
                   1339:
                   1340: static int
                   1341: md_pre_Sh(struct roff_node *n)
                   1342: {
                   1343:        switch (n->type) {
                   1344:        case ROFFT_HEAD:
                   1345:                outflags |= MD_sp;
                   1346:                md_rawword(n->tok == MDOC_Sh ? "#" : "##");
                   1347:                break;
                   1348:        case ROFFT_BODY:
                   1349:                outflags |= MD_sp;
                   1350:                break;
                   1351:        default:
                   1352:                break;
                   1353:        }
                   1354:        return 1;
                   1355: }
                   1356:
                   1357: static int
                   1358: md_pre_Sm(struct roff_node *n)
                   1359: {
                   1360:        if (n->child == NULL)
                   1361:                outflags ^= MD_Sm;
                   1362:        else if (strcmp("on", n->child->string) == 0)
                   1363:                outflags |= MD_Sm;
                   1364:        else
                   1365:                outflags &= ~MD_Sm;
                   1366:
                   1367:        if (outflags & MD_Sm)
                   1368:                outflags |= MD_spc;
                   1369:
                   1370:        return 0;
                   1371: }
                   1372:
                   1373: static int
                   1374: md_pre_Vt(struct roff_node *n)
                   1375: {
                   1376:        switch (n->type) {
                   1377:        case ROFFT_BLOCK:
                   1378:                md_pre_syn(n);
                   1379:                return 1;
                   1380:        case ROFFT_BODY:
                   1381:        case ROFFT_ELEM:
                   1382:                md_pre_raw(n);
                   1383:                return 1;
                   1384:        default:
                   1385:                return 0;
                   1386:        }
                   1387: }
                   1388:
                   1389: static void
                   1390: md_post_Vt(struct roff_node *n)
                   1391: {
                   1392:        switch (n->type) {
                   1393:        case ROFFT_BODY:
                   1394:        case ROFFT_ELEM:
                   1395:                md_post_raw(n);
                   1396:                break;
                   1397:        default:
                   1398:                break;
                   1399:        }
                   1400: }
                   1401:
                   1402: static int
                   1403: md_pre_Xr(struct roff_node *n)
                   1404: {
                   1405:        n = n->child;
                   1406:        if (n == NULL)
                   1407:                return 0;
                   1408:        md_node(n);
                   1409:        n = n->next;
                   1410:        if (n == NULL)
                   1411:                return 0;
                   1412:        outflags &= ~MD_spc;
                   1413:        md_word("(");
                   1414:        md_node(n);
                   1415:        md_word(")");
                   1416:        return 0;
                   1417: }
                   1418:
                   1419: static int
                   1420: md_pre__T(struct roff_node *n)
                   1421: {
1.2     ! schwarze 1422:        if (n->parent->tok == MDOC_Rs && n->parent->norm->Rs.quote_T)
1.1       schwarze 1423:                md_word("\"");
                   1424:        else
                   1425:                md_rawword("*");
                   1426:        outflags &= ~MD_spc;
                   1427:        return 1;
                   1428: }
                   1429:
                   1430: static void
                   1431: md_post__T(struct roff_node *n)
                   1432: {
                   1433:        outflags &= ~MD_spc;
1.2     ! schwarze 1434:        if (n->parent->tok == MDOC_Rs && n->parent->norm->Rs.quote_T)
1.1       schwarze 1435:                md_word("\"");
                   1436:        else
                   1437:                md_rawword("*");
                   1438:        md_post_pc(n);
                   1439: }
                   1440:
                   1441: static int
                   1442: md_pre_br(struct roff_node *n)
                   1443: {
                   1444:        outflags |= MD_br;
                   1445:        return 0;
                   1446: }

CVSweb