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

Annotation of docbook2mdoc/docbook2mdoc.c, Revision 1.98

1.98    ! schwarze    1: /* $Id: docbook2mdoc.c,v 1.97 2019/04/07 17:42:36 schwarze Exp $ */
1.1       kristaps    2: /*
                      3:  * Copyright (c) 2014 Kristaps Dzonsons <kristaps@bsd.lv>
1.50      schwarze    4:  * Copyright (c) 2019 Ingo Schwarze <schwarze@openbsd.org>
1.1       kristaps    5:  *
                      6:  * Permission to use, copy, modify, and distribute this software for any
                      7:  * purpose with or without fee is hereby granted, provided that the above
                      8:  * copyright notice and this permission notice appear in all copies.
                      9:  *
                     10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
                     11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
                     13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     17:  */
                     18: #include <assert.h>
                     19: #include <ctype.h>
                     20: #include <stdio.h>
                     21: #include <stdlib.h>
                     22:
1.74      schwarze   23: #include "node.h"
1.75      schwarze   24: #include "macro.h"
1.74      schwarze   25: #include "format.h"
                     26:
                     27: /*
                     28:  * The implementation of the mdoc(7) formatter.
                     29:  */
1.12      kristaps   30:
1.74      schwarze   31: static void     pnode_print(struct format *, struct pnode *);
1.25      kristaps   32:
1.37      kristaps   33:
1.54      schwarze   34: static void
1.93      schwarze   35: pnode_printtext(struct format *f, struct pnode *n)
                     36: {
1.94      schwarze   37:        struct pnode    *nn;
1.93      schwarze   38:        char            *cp;
                     39:        char             last;
                     40:
                     41:        if (n->bsz == 0) {
                     42:                assert(n->real < n->b);
                     43:                return;
1.94      schwarze   44:        }
                     45:
                     46:        /*
                     47:         * Text preceding a macro without intervening whitespace
                     48:         * requires a .Pf macro.
                     49:         * Set the spacing flag to avoid a redundant .Ns macro.
                     50:         */
                     51:
                     52:        if (f->linestate != LINE_MACRO &&
                     53:            (nn = TAILQ_NEXT(n, child)) != NULL && nn->spc == 0 &&
                     54:            (nn->node != NODE_TEXT && nn->node != NODE_ESCAPE)) {
                     55:                macro_open(f, "Pf");
                     56:                nn->spc = 1;
1.93      schwarze   57:        }
                     58:
                     59:        if (f->linestate == LINE_NEW) {
                     60:                last = '\n';
                     61:                f->linestate = LINE_TEXT;
                     62:        } else {
                     63:                last = ' ';
                     64:                if (n->spc || f->linestate == LINE_MACRO)
                     65:                        putchar(' ');
                     66:        }
                     67:
                     68:        if (n->node == NODE_ESCAPE) {
                     69:                fputs(n->b, stdout);
                     70:                return;
                     71:        }
                     72:
                     73:        /*
                     74:         * Remove the prefix '-' from <option> elements
                     75:         * because the arguments of .Fl macros do not need it.
                     76:         */
                     77:
                     78:        cp = n->b;
                     79:        if (n->parent != NULL && n->parent->node == NODE_OPTION && *cp == '-')
                     80:                cp++;
                     81:
                     82:        /*
                     83:         * Print the text, skipping whitespace on new lines,
                     84:         * escaping control characters on new lines,
                     85:         * and escaping backslashes.
                     86:         */
                     87:
                     88:        for (; *cp != '\0'; cp++) {
                     89:                if (last == '\n') {
                     90:                        if (isspace((unsigned char)*cp))
                     91:                                continue;
                     92:                        if (*cp == '\'' || *cp == '.')
                     93:                                fputs("\\&", stdout);
                     94:                }
                     95:                putchar(last = *cp);
                     96:                if (last == '\\')
                     97:                        putchar('e');
                     98:        }
                     99: }
                    100:
                    101: static void
1.74      schwarze  102: pnode_printpara(struct format *p, struct pnode *pn)
1.54      schwarze  103: {
                    104:        struct pnode    *pp;
                    105:
1.97      schwarze  106:        if (pn->parent == NULL)
1.54      schwarze  107:                return;
                    108:
1.97      schwarze  109:        if ((pp = TAILQ_PREV(pn, pnodeq, child)) == NULL)
                    110:            pp = pn->parent;
                    111:
1.61      schwarze  112:        switch (pp->node) {
                    113:        case NODE_ENTRY:
                    114:        case NODE_LISTITEM:
                    115:                return;
                    116:        case NODE_PREFACE:
                    117:        case NODE_SECTION:
                    118:                if (p->level < 3)
                    119:                        return;
                    120:                break;
                    121:        default:
                    122:                break;
                    123:        }
1.69      schwarze  124:        macro_line(p, "Pp");
1.54      schwarze  125: }
                    126:
1.37      kristaps  127: /*
1.10      kristaps  128:  * If the SYNOPSIS macro has a superfluous title, kill it.
1.8       kristaps  129:  */
1.1       kristaps  130: static void
1.74      schwarze  131: pnode_printrefsynopsisdiv(struct format *p, struct pnode *pn)
1.6       kristaps  132: {
1.71      schwarze  133:        struct pnode    *pp, *pq;
1.6       kristaps  134:
1.71      schwarze  135:        TAILQ_FOREACH_SAFE(pp, &pn->childq, child, pq)
                    136:                if (pp->node == NODE_TITLE)
1.6       kristaps  137:                        pnode_unlink(pp);
1.71      schwarze  138:
                    139:        macro_line(p, "Sh SYNOPSIS");
1.6       kristaps  140: }
                    141:
1.8       kristaps  142: /*
                    143:  * Start a hopefully-named `Sh' section.
                    144:  */
1.6       kristaps  145: static void
1.74      schwarze  146: pnode_printrefsect(struct format *p, struct pnode *pn)
1.1       kristaps  147: {
                    148:        struct pnode    *pp;
1.52      schwarze  149:        const char      *title;
                    150:        int              flags, level;
                    151:
1.64      schwarze  152:        if (pn->parent == NULL)
1.56      schwarze  153:                return;
                    154:
1.52      schwarze  155:        level = ++p->level;
1.72      schwarze  156:        flags = ARG_SPACE;
                    157:        if (level == 1)
                    158:                flags |= ARG_UPPER;
1.64      schwarze  159:        if (level < 3) {
1.52      schwarze  160:                switch (pn->node) {
1.62      schwarze  161:                case NODE_CAUTION:
                    162:                case NODE_NOTE:
                    163:                case NODE_TIP:
                    164:                case NODE_WARNING:
1.52      schwarze  165:                        level = 3;
                    166:                        break;
                    167:                default:
                    168:                        break;
                    169:                }
                    170:        }
1.1       kristaps  171:
                    172:        TAILQ_FOREACH(pp, &pn->childq, child)
1.64      schwarze  173:                if (pp->node == NODE_TITLE)
1.1       kristaps  174:                        break;
                    175:
1.64      schwarze  176:        if (pp == NULL) {
1.52      schwarze  177:                switch (pn->node) {
1.62      schwarze  178:                case NODE_PREFACE:
1.52      schwarze  179:                        title = "Preface";
                    180:                        break;
1.62      schwarze  181:                case NODE_CAUTION:
1.52      schwarze  182:                        title = "Caution";
                    183:                        break;
1.62      schwarze  184:                case NODE_NOTE:
1.52      schwarze  185:                        title = "Note";
                    186:                        break;
1.62      schwarze  187:                case NODE_TIP:
1.52      schwarze  188:                        title = "Tip";
                    189:                        break;
1.62      schwarze  190:                case NODE_WARNING:
1.52      schwarze  191:                        title = "Warning";
                    192:                        break;
                    193:                default:
                    194:                        title = "Unknown";
                    195:                        break;
                    196:                }
                    197:        }
                    198:
                    199:        switch (level) {
1.62      schwarze  200:        case 1:
1.95      schwarze  201:                macro_close(p);
1.69      schwarze  202:                macro_open(p, "Sh");
1.29      kristaps  203:                break;
1.62      schwarze  204:        case 2:
1.95      schwarze  205:                macro_close(p);
1.69      schwarze  206:                macro_open(p, "Ss");
1.29      kristaps  207:                break;
1.52      schwarze  208:        default:
1.54      schwarze  209:                pnode_printpara(p, pn);
1.69      schwarze  210:                macro_open(p, "Sy");
1.29      kristaps  211:                break;
                    212:        }
1.20      kristaps  213:
1.64      schwarze  214:        if (pp != NULL) {
1.69      schwarze  215:                macro_addnode(p, pp, flags);
1.5       kristaps  216:                pnode_unlink(pp);
1.52      schwarze  217:        } else
1.72      schwarze  218:                macro_addarg(p, title, ARG_SPACE | ARG_QUOTED);
1.69      schwarze  219:        macro_close(p);
1.1       kristaps  220: }
                    221:
1.8       kristaps  222: /*
                    223:  * Start a reference, extracting the title and volume.
                    224:  */
1.1       kristaps  225: static void
1.74      schwarze  226: pnode_printciterefentry(struct format *p, struct pnode *pn)
1.1       kristaps  227: {
                    228:        struct pnode    *pp, *title, *manvol;
                    229:
                    230:        title = manvol = NULL;
1.69      schwarze  231:        TAILQ_FOREACH(pp, &pn->childq, child) {
1.64      schwarze  232:                if (pp->node == NODE_MANVOLNUM)
1.1       kristaps  233:                        manvol = pp;
1.64      schwarze  234:                else if (pp->node == NODE_REFENTRYTITLE)
1.1       kristaps  235:                        title = pp;
1.69      schwarze  236:        }
                    237:        macro_open(p, "Xr");
                    238:        if (title == NULL)
1.72      schwarze  239:                macro_addarg(p, "unknown", ARG_SPACE);
1.69      schwarze  240:        else
1.72      schwarze  241:                macro_addnode(p, title, ARG_SPACE | ARG_SINGLE);
1.69      schwarze  242:        if (manvol == NULL)
1.72      schwarze  243:                macro_addarg(p, "1", ARG_SPACE);
1.64      schwarze  244:        else
1.72      schwarze  245:                macro_addnode(p, manvol, ARG_SPACE | ARG_SINGLE);
1.71      schwarze  246:        pnode_unlinksub(pn);
1.1       kristaps  247: }
                    248:
                    249: static void
1.74      schwarze  250: pnode_printrefmeta(struct format *p, struct pnode *pn)
1.1       kristaps  251: {
                    252:        struct pnode    *pp, *title, *manvol;
                    253:
                    254:        title = manvol = NULL;
1.69      schwarze  255:        TAILQ_FOREACH(pp, &pn->childq, child) {
1.64      schwarze  256:                if (pp->node == NODE_MANVOLNUM)
1.1       kristaps  257:                        manvol = pp;
1.64      schwarze  258:                else if (pp->node == NODE_REFENTRYTITLE)
1.1       kristaps  259:                        title = pp;
1.69      schwarze  260:        }
1.95      schwarze  261:        macro_close(p);
1.69      schwarze  262:        macro_open(p, "Dt");
                    263:        if (title == NULL)
1.72      schwarze  264:                macro_addarg(p, "UNKNOWN", ARG_SPACE);
1.69      schwarze  265:        else
1.72      schwarze  266:                macro_addnode(p, title, ARG_SPACE | ARG_SINGLE | ARG_UPPER);
1.69      schwarze  267:        if (manvol == NULL)
1.72      schwarze  268:                macro_addarg(p, "1", ARG_SPACE);
1.13      kristaps  269:        else
1.72      schwarze  270:                macro_addnode(p, manvol, ARG_SPACE | ARG_SINGLE);
1.69      schwarze  271:        macro_close(p);
1.71      schwarze  272:        pnode_unlink(pn);
1.1       kristaps  273: }
                    274:
1.3       kristaps  275: static void
1.86      schwarze  276: pnode_printfuncdef(struct format *f, struct pnode *n)
1.3       kristaps  277: {
1.86      schwarze  278:        struct pnode    *nc;
1.3       kristaps  279:
1.86      schwarze  280:        nc = TAILQ_FIRST(&n->childq);
                    281:        if (nc != NULL && nc->node == NODE_TEXT) {
                    282:                macro_argline(f, "Ft", nc->b);
                    283:                pnode_unlink(nc);
1.13      kristaps  284:        }
1.86      schwarze  285:        macro_nodeline(f, "Fo", n, ARG_SINGLE);
                    286:        pnode_unlinksub(n);
1.3       kristaps  287: }
                    288:
1.40      kristaps  289: /*
1.41      kristaps  290:  * The <mml:mfenced> node is a little peculiar.
                    291:  * First, it can have arbitrary open and closing tokens, which default
                    292:  * to parentheses.
                    293:  * Second, >1 arguments are separated by commas.
                    294:  */
                    295: static void
1.74      schwarze  296: pnode_printmathfenced(struct format *p, struct pnode *pn)
1.41      kristaps  297: {
                    298:        struct pnode    *pp;
                    299:
1.59      schwarze  300:        printf("left %s ", pnode_getattr_raw(pn, ATTRKEY_OPEN, "("));
1.41      kristaps  301:
                    302:        pp = TAILQ_FIRST(&pn->childq);
                    303:        pnode_print(p, pp);
                    304:
1.64      schwarze  305:        while ((pp = TAILQ_NEXT(pp, child)) != NULL) {
1.41      kristaps  306:                putchar(',');
                    307:                pnode_print(p, pp);
                    308:        }
1.59      schwarze  309:        printf("right %s ", pnode_getattr_raw(pn, ATTRKEY_CLOSE, ")"));
1.71      schwarze  310:        pnode_unlinksub(pn);
1.41      kristaps  311: }
                    312:
                    313: /*
1.40      kristaps  314:  * These math nodes require special handling because they have infix
                    315:  * syntax, instead of the usual prefix or prefix.
                    316:  * So we need to break up the first and second child node with a
                    317:  * particular eqn(7) word.
                    318:  */
                    319: static void
1.74      schwarze  320: pnode_printmath(struct format *p, struct pnode *pn)
1.40      kristaps  321: {
                    322:        struct pnode    *pp;
                    323:
                    324:        pp = TAILQ_FIRST(&pn->childq);
                    325:        pnode_print(p, pp);
                    326:
                    327:        switch (pn->node) {
1.62      schwarze  328:        case NODE_MML_MSUP:
1.42      kristaps  329:                fputs(" sup ", stdout);
1.40      kristaps  330:                break;
1.62      schwarze  331:        case NODE_MML_MFRAC:
1.42      kristaps  332:                fputs(" over ", stdout);
1.40      kristaps  333:                break;
1.62      schwarze  334:        case NODE_MML_MSUB:
1.42      kristaps  335:                fputs(" sub ", stdout);
1.40      kristaps  336:                break;
                    337:        default:
                    338:                break;
                    339:        }
                    340:
                    341:        pp = TAILQ_NEXT(pp, child);
                    342:        pnode_print(p, pp);
1.71      schwarze  343:        pnode_unlinksub(pn);
1.40      kristaps  344: }
                    345:
1.3       kristaps  346: static void
1.74      schwarze  347: pnode_printfuncprototype(struct format *p, struct pnode *pn)
1.3       kristaps  348: {
                    349:        struct pnode    *pp, *fdef;
                    350:
                    351:        TAILQ_FOREACH(fdef, &pn->childq, child)
1.64      schwarze  352:                if (fdef->node == NODE_FUNCDEF)
1.3       kristaps  353:                        break;
                    354:
1.86      schwarze  355:        if (fdef != NULL) {
1.3       kristaps  356:                pnode_printfuncdef(p, fdef);
1.86      schwarze  357:                pnode_unlink(fdef);
                    358:        } else
1.69      schwarze  359:                macro_line(p, "Fo UNKNOWN");
1.3       kristaps  360:
1.44      schwarze  361:        TAILQ_FOREACH(pp, &pn->childq, child)
1.86      schwarze  362:                macro_nodeline(p, "Fa", pp, ARG_SINGLE);
1.3       kristaps  363:
1.69      schwarze  364:        macro_line(p, "Fc");
1.71      schwarze  365:        pnode_unlinksub(pn);
1.3       kristaps  366: }
                    367:
1.44      schwarze  368: /*
1.10      kristaps  369:  * The <arg> element is more complicated than it should be because text
                    370:  * nodes are treated like ".Ar foo", but non-text nodes need to be
                    371:  * re-sent into the printer (i.e., without the preceding ".Ar").
1.12      kristaps  372:  * This also handles the case of "repetition" (or in other words, the
                    373:  * ellipsis following an argument) and optionality.
1.10      kristaps  374:  */
1.4       kristaps  375: static void
1.74      schwarze  376: pnode_printarg(struct format *p, struct pnode *pn)
1.4       kristaps  377: {
                    378:        struct pnode    *pp;
1.12      kristaps  379:        struct pattr    *ap;
                    380:        int              isop, isrep;
                    381:
                    382:        isop = 1;
                    383:        isrep = 0;
1.69      schwarze  384:        TAILQ_FOREACH(ap, &pn->attrq, child) {
1.64      schwarze  385:                if (ap->key == ATTRKEY_CHOICE &&
                    386:                    (ap->val == ATTRVAL_PLAIN || ap->val == ATTRVAL_REQ))
1.12      kristaps  387:                        isop = 0;
1.64      schwarze  388:                else if (ap->key == ATTRKEY_REP && ap->val == ATTRVAL_REPEAT)
1.12      kristaps  389:                        isrep = 1;
                    390:        }
1.69      schwarze  391:        if (isop)
                    392:                macro_open(p, "Op");
1.4       kristaps  393:
1.10      kristaps  394:        TAILQ_FOREACH(pp, &pn->childq, child) {
1.69      schwarze  395:                if (pp->node == NODE_TEXT)
                    396:                        macro_open(p, "Ar");
1.10      kristaps  397:                pnode_print(p, pp);
1.64      schwarze  398:                if (isrep && pp->node == NODE_TEXT)
1.72      schwarze  399:                        macro_addarg(p, "...", ARG_SPACE);
1.10      kristaps  400:        }
1.71      schwarze  401:        pnode_unlinksub(pn);
1.4       kristaps  402: }
                    403:
1.24      kristaps  404: static void
1.74      schwarze  405: pnode_printgroup(struct format *p, struct pnode *pn)
1.24      kristaps  406: {
                    407:        struct pnode    *pp, *np;
                    408:        struct pattr    *ap;
                    409:        int              isop, sv;
                    410:
                    411:        isop = 1;
1.44      schwarze  412:        TAILQ_FOREACH(ap, &pn->attrq, child)
1.64      schwarze  413:                if (ap->key == ATTRKEY_CHOICE &&
                    414:                    (ap->val == ATTRVAL_PLAIN || ap->val == ATTRVAL_REQ)) {
1.24      kristaps  415:                        isop = 0;
                    416:                        break;
                    417:                }
                    418:
1.44      schwarze  419:        /*
1.24      kristaps  420:         * Make sure we're on a macro line.
                    421:         * This will prevent pnode_print() for putting us on a
                    422:         * subsequent line.
                    423:         */
1.69      schwarze  424:        sv = p->linestate == LINE_NEW;
1.44      schwarze  425:        if (isop)
1.69      schwarze  426:                macro_open(p, "Op");
1.24      kristaps  427:        else if (sv)
1.69      schwarze  428:                macro_open(p, "No");
1.24      kristaps  429:
                    430:        /*
                    431:         * Keep on printing text separated by the vertical bar as long
                    432:         * as we're within the same origin node as the group.
                    433:         * This is kind of a nightmare.
                    434:         * Eh, DocBook...
                    435:         * FIXME: if there's a "Fl", we don't cut off the leading "-"
                    436:         * like we do in pnode_print().
                    437:         */
                    438:        TAILQ_FOREACH(pp, &pn->childq, child) {
                    439:                pnode_print(p, pp);
                    440:                np = TAILQ_NEXT(pp, child);
1.64      schwarze  441:                while (np != NULL) {
1.24      kristaps  442:                        if (pp->node != np->node)
                    443:                                break;
1.72      schwarze  444:                        macro_addarg(p, "|", ARG_SPACE);
                    445:                        macro_addnode(p, np, ARG_SPACE);
1.24      kristaps  446:                        pp = np;
                    447:                        np = TAILQ_NEXT(np, child);
                    448:                }
                    449:        }
1.69      schwarze  450:        if (sv)
                    451:                macro_close(p);
1.71      schwarze  452:        pnode_unlinksub(pn);
1.24      kristaps  453: }
                    454:
1.7       kristaps  455: static void
1.78      schwarze  456: pnode_printauthor(struct format *f, struct pnode *n)
                    457: {
                    458:        struct pnode    *nc, *ncn;
                    459:        int              have_contrib, have_name;
                    460:
                    461:        /*
                    462:         * Print <contrib> children up front, before the .An scope,
                    463:         * and figure out whether we a name of a person.
                    464:         */
                    465:
                    466:        have_contrib = have_name = 0;
                    467:        TAILQ_FOREACH_SAFE(nc, &n->childq, child, ncn) {
                    468:                switch (nc->node) {
                    469:                case NODE_CONTRIB:
                    470:                        if (have_contrib)
                    471:                                print_text(f, ",", 0);
                    472:                        print_textnode(f, nc);
                    473:                        pnode_unlink(nc);
                    474:                        have_contrib = 1;
                    475:                        break;
                    476:                case NODE_PERSONNAME:
                    477:                        have_name = 1;
                    478:                        break;
                    479:                default:
                    480:                        break;
                    481:                }
                    482:        }
                    483:        if (TAILQ_FIRST(&n->childq) == NULL)
                    484:                return;
                    485:
                    486:        if (have_contrib)
                    487:                print_text(f, ":", 0);
                    488:
                    489:        /*
                    490:          * If we have a name, print it in the .An scope and leave
                    491:          * all other content for child handlers, to print after the
                    492:          * scope.  Otherwise, print everything in the scope.
                    493:         */
                    494:
                    495:        macro_open(f, "An");
                    496:        TAILQ_FOREACH_SAFE(nc, &n->childq, child, ncn) {
                    497:                if (nc->node == NODE_PERSONNAME || have_name == 0) {
                    498:                        macro_addnode(f, nc, ARG_SPACE);
                    499:                        pnode_unlink(nc);
                    500:                }
1.80      schwarze  501:        }
                    502:
                    503:        /*
                    504:         * If there is an email address,
                    505:         * print it on the same macro line.
                    506:         */
                    507:
                    508:        if ((nc = pnode_findfirst(n, NODE_EMAIL)) != NULL) {
                    509:                pnode_print(f, nc);
                    510:                pnode_unlink(nc);
1.78      schwarze  511:        }
                    512:
                    513:        /*
                    514:         * If there are still unprinted children, end the scope
                    515:         * with a comma.  Otherwise, leave the scope open in case
                    516:         * a text node follows that starts with closing punctuation.
                    517:         */
                    518:
                    519:        if (TAILQ_FIRST(&n->childq) != NULL) {
                    520:                macro_addarg(f, ",", ARG_SPACE);
                    521:                macro_close(f);
                    522:        }
                    523: }
                    524:
                    525: static void
1.96      schwarze  526: pnode_printlink(struct format *f, struct pnode *n)
                    527: {
                    528:        const char      *uri, *text;
                    529:
                    530:        uri = pnode_getattr_raw(n, ATTRKEY_LINKEND, NULL);
                    531:        if (uri != NULL) {
                    532:                if (TAILQ_FIRST(&n->childq) != NULL) {
                    533:                        print_textnode(f, n);
                    534:                        text = "";
                    535:                } else {
                    536:                        text = pnode_getattr_raw(n, ATTRKEY_ENDTERM, NULL);
                    537:                        if (text != NULL)
                    538:                                print_text(f, text, ARG_SPACE);
                    539:                }
                    540:                if (text != NULL)
                    541:                        macro_open(f, "Pq");
                    542:                macro_open(f, "Sx");
                    543:                macro_addarg(f, uri, ARG_SPACE);
                    544:                pnode_unlinksub(n);
                    545:                return;
                    546:        }
                    547:        uri = pnode_getattr_raw(n, ATTRKEY_XLINK_HREF, NULL);
                    548:        if (uri == NULL)
                    549:                uri = pnode_getattr_raw(n, ATTRKEY_URL, NULL);
                    550:        if (uri != NULL) {
                    551:                macro_open(f, "Lk");
                    552:                macro_addarg(f, uri, ARG_SPACE | ARG_SINGLE);
                    553:                if (TAILQ_FIRST(&n->childq) != NULL)
                    554:                        macro_addnode(f, n, ARG_SPACE | ARG_SINGLE);
                    555:                pnode_unlinksub(n);
                    556:                return;
                    557:        }
                    558: }
                    559:
                    560: static void
1.74      schwarze  561: pnode_printprologue(struct format *p, struct ptree *tree)
1.7       kristaps  562: {
1.74      schwarze  563:        struct pnode    *refmeta;
1.7       kristaps  564:
1.74      schwarze  565:        refmeta = tree->root == NULL ? NULL :
                    566:            pnode_findfirst(tree->root, NODE_REFMETA);
1.9       kristaps  567:
1.69      schwarze  568:        macro_line(p, "Dd $Mdocdate" "$");
1.74      schwarze  569:        if (refmeta == NULL) {
1.69      schwarze  570:                macro_open(p, "Dt");
                    571:                macro_addarg(p,
1.74      schwarze  572:                    pnode_getattr_raw(tree->root, ATTRKEY_ID, "UNKNOWN"),
1.72      schwarze  573:                    ARG_SPACE | ARG_SINGLE | ARG_UPPER);
                    574:                macro_addarg(p, "1", ARG_SPACE);
1.69      schwarze  575:                macro_close(p);
1.74      schwarze  576:        } else
                    577:                pnode_printrefmeta(p, refmeta);
1.69      schwarze  578:        macro_line(p, "Os");
1.43      kristaps  579:
1.74      schwarze  580:        if (tree->flags & TREE_EQN) {
1.69      schwarze  581:                macro_line(p, "EQ");
1.78      schwarze  582:                print_text(p, "delim $$", 0);
1.69      schwarze  583:                macro_line(p, "EN");
1.43      kristaps  584:        }
1.7       kristaps  585: }
                    586:
1.42      kristaps  587: /*
                    588:  * We can have multiple <term> elements within a <varlistentry>, which
                    589:  * we should comma-separate as list headers.
                    590:  */
1.13      kristaps  591: static void
1.74      schwarze  592: pnode_printvarlistentry(struct format *p, struct pnode *pn)
1.13      kristaps  593: {
                    594:        struct pnode    *pp;
1.42      kristaps  595:        int              first = 1;
1.13      kristaps  596:
1.95      schwarze  597:        macro_close(p);
1.69      schwarze  598:        macro_open(p, "It");
                    599:        TAILQ_FOREACH(pp, &pn->childq, child) {
                    600:                if (pp->node != NODE_TERM)
                    601:                        continue;
                    602:                if ( ! first)
1.72      schwarze  603:                        macro_addarg(p, ",", 0);
1.69      schwarze  604:                pnode_print(p, pp);
                    605:                first = 0;
                    606:        }
                    607:        macro_close(p);
1.13      kristaps  608:        TAILQ_FOREACH(pp, &pn->childq, child)
1.69      schwarze  609:                if (pp->node != NODE_TERM)
1.13      kristaps  610:                        pnode_print(p, pp);
1.71      schwarze  611:        pnode_unlinksub(pn);
                    612: }
                    613:
                    614: static void
1.74      schwarze  615: pnode_printtitle(struct format *p, struct pnode *pn)
1.71      schwarze  616: {
                    617:        struct pnode    *pp, *pq;
                    618:
                    619:        TAILQ_FOREACH_SAFE(pp, &pn->childq, child, pq) {
                    620:                if (pp->node == NODE_TITLE) {
                    621:                        pnode_printpara(p, pp);
                    622:                        pnode_print(p, pp);
                    623:                        pnode_unlink(pp);
                    624:                }
                    625:        }
1.13      kristaps  626: }
                    627:
                    628: static void
1.74      schwarze  629: pnode_printrow(struct format *p, struct pnode *pn)
1.25      kristaps  630: {
                    631:        struct pnode    *pp;
                    632:
1.69      schwarze  633:        macro_line(p, "Bl -dash -compact");
1.25      kristaps  634:        TAILQ_FOREACH(pp, &pn->childq, child) {
1.69      schwarze  635:                macro_line(p, "It");
1.25      kristaps  636:                pnode_print(p, pp);
                    637:        }
1.69      schwarze  638:        macro_line(p, "El");
1.71      schwarze  639:        pnode_unlink(pn);
1.25      kristaps  640: }
                    641:
                    642: static void
1.83      schwarze  643: pnode_printtgroup1(struct format *f, struct pnode *n)
1.16      kristaps  644: {
1.82      schwarze  645:        struct pnode    *nc;
                    646:
1.83      schwarze  647:        macro_line(f, "Bl -bullet -compact");
1.82      schwarze  648:        while ((nc = pnode_findfirst(n, NODE_ENTRY)) != NULL) {
1.83      schwarze  649:                macro_line(f, "It");
                    650:                pnode_print(f, nc);
1.82      schwarze  651:                pnode_unlink(nc);
                    652:        }
1.83      schwarze  653:        macro_line(f, "El");
                    654:        pnode_unlinksub(n);
                    655: }
                    656:
                    657: static void
                    658: pnode_printtgroup2(struct format *f, struct pnode *n)
                    659: {
                    660:        struct pnode    *nr, *ne;
                    661:
                    662:        macro_line(f, "Bl -tag -width Ds");
                    663:        while ((nr = pnode_findfirst(n, NODE_ROW)) != NULL) {
                    664:                if ((ne = pnode_findfirst(n, NODE_ENTRY)) == NULL)
                    665:                        break;
1.95      schwarze  666:                macro_close(f);
1.83      schwarze  667:                macro_open(f, "It");
                    668:                pnode_print(f, ne);
1.84      schwarze  669:                macro_close(f);
1.83      schwarze  670:                pnode_unlink(ne);
                    671:                pnode_print(f, nr);
                    672:                pnode_unlink(nr);
                    673:        }
                    674:        macro_line(f, "El");
1.82      schwarze  675:        pnode_unlinksub(n);
                    676: }
                    677:
                    678: static void
1.83      schwarze  679: pnode_printtgroup(struct format *f, struct pnode *n)
1.82      schwarze  680: {
                    681:        struct pnode    *nc;
                    682:
                    683:        switch (atoi(pnode_getattr_raw(n, ATTRKEY_COLS, "0"))) {
                    684:        case 1:
1.83      schwarze  685:                pnode_printtgroup1(f, n);
                    686:                return;
                    687:        case 2:
                    688:                pnode_printtgroup2(f, n);
1.82      schwarze  689:                return;
                    690:        default:
                    691:                break;
                    692:        }
1.16      kristaps  693:
1.83      schwarze  694:        macro_line(f, "Bl -ohang");
1.82      schwarze  695:        while ((nc = pnode_findfirst(n, NODE_ROW)) != NULL) {
1.83      schwarze  696:                macro_line(f, "It Table Row");
                    697:                pnode_printrow(f, nc);
1.25      kristaps  698:        }
1.83      schwarze  699:        macro_line(f, "El");
1.82      schwarze  700:        pnode_unlinksub(n);
1.25      kristaps  701: }
                    702:
                    703: static void
1.74      schwarze  704: pnode_printlist(struct format *p, struct pnode *pn)
1.25      kristaps  705: {
                    706:        struct pnode    *pp;
1.16      kristaps  707:
1.71      schwarze  708:        pnode_printtitle(p, pn);
1.69      schwarze  709:        macro_argline(p, "Bl",
                    710:            pn->node == NODE_ORDEREDLIST ? "-enum" : "-bullet");
1.16      kristaps  711:        TAILQ_FOREACH(pp, &pn->childq, child) {
1.69      schwarze  712:                macro_line(p, "It");
1.16      kristaps  713:                pnode_print(p, pp);
                    714:        }
1.69      schwarze  715:        macro_line(p, "El");
1.71      schwarze  716:        pnode_unlinksub(pn);
1.16      kristaps  717: }
                    718:
                    719: static void
1.74      schwarze  720: pnode_printvariablelist(struct format *p, struct pnode *pn)
1.13      kristaps  721: {
                    722:        struct pnode    *pp;
                    723:
1.71      schwarze  724:        pnode_printtitle(p, pn);
1.69      schwarze  725:        macro_line(p, "Bl -tag -width Ds");
                    726:        TAILQ_FOREACH(pp, &pn->childq, child) {
                    727:                if (pp->node == NODE_VARLISTENTRY)
1.85      schwarze  728:                        pnode_printvarlistentry(p, pp);
1.69      schwarze  729:                else
1.72      schwarze  730:                        macro_nodeline(p, "It", pp, 0);
1.69      schwarze  731:        }
                    732:        macro_line(p, "El");
1.71      schwarze  733:        pnode_unlinksub(pn);
1.13      kristaps  734: }
                    735:
1.1       kristaps  736: /*
                    737:  * Print a parsed node (or ignore it--whatever).
                    738:  * This is a recursive function.
1.23      kristaps  739:  * FIXME: if we're in a literal context (<screen> or <programlisting> or
                    740:  * whatever), don't print inline macros.
1.1       kristaps  741:  */
                    742: static void
1.74      schwarze  743: pnode_print(struct format *p, struct pnode *pn)
1.1       kristaps  744: {
                    745:        struct pnode    *pp;
1.69      schwarze  746:        enum linestate   sv;
1.1       kristaps  747:
1.64      schwarze  748:        if (pn == NULL)
1.1       kristaps  749:                return;
                    750:
1.92      schwarze  751:        p->spc = pn->spc;
1.69      schwarze  752:        sv = p->linestate;
1.1       kristaps  753:
                    754:        switch (pn->node) {
1.62      schwarze  755:        case NODE_APPLICATION:
1.69      schwarze  756:                macro_open(p, "Nm");
1.27      kristaps  757:                break;
1.62      schwarze  758:        case NODE_ARG:
1.10      kristaps  759:                pnode_printarg(p, pn);
1.4       kristaps  760:                break;
1.62      schwarze  761:        case NODE_AUTHOR:
1.78      schwarze  762:                pnode_printauthor(p, pn);
1.50      schwarze  763:                break;
1.62      schwarze  764:        case NODE_AUTHORGROUP:
1.69      schwarze  765:                macro_line(p, "An -split");
1.50      schwarze  766:                break;
1.98    ! schwarze  767:        case NODE_BLOCKQUOTE:
        !           768:                macro_line(p, "Bd -ragged -offset indent");
        !           769:                break;
1.62      schwarze  770:        case NODE_BOOKINFO:
1.69      schwarze  771:                macro_line(p, "Sh NAME");
1.50      schwarze  772:                break;
1.62      schwarze  773:        case NODE_CITEREFENTRY:
1.1       kristaps  774:                pnode_printciterefentry(p, pn);
                    775:                break;
1.68      schwarze  776:        case NODE_CITETITLE:
1.69      schwarze  777:                macro_open(p, "%T");
1.68      schwarze  778:                break;
1.62      schwarze  779:        case NODE_COMMAND:
1.69      schwarze  780:                macro_open(p, "Nm");
1.13      kristaps  781:                break;
1.62      schwarze  782:        case NODE_CONSTANT:
1.69      schwarze  783:                macro_open(p, "Dv");
1.33      kristaps  784:                break;
1.62      schwarze  785:        case NODE_EDITOR:
1.78      schwarze  786:                print_text(p, "editor:", ARG_SPACE);
1.92      schwarze  787:                sv = LINE_TEXT;
1.69      schwarze  788:                macro_open(p, "An");
1.50      schwarze  789:                break;
1.65      schwarze  790:        case NODE_EMAIL:
1.69      schwarze  791:                macro_open(p, "Aq Mt");
1.65      schwarze  792:                break;
1.62      schwarze  793:        case NODE_EMPHASIS:
                    794:        case NODE_FIRSTTERM:
1.69      schwarze  795:                macro_open(p, "Em");
1.1       kristaps  796:                break;
1.62      schwarze  797:        case NODE_ENVAR:
1.69      schwarze  798:                macro_open(p, "Ev");
1.79      schwarze  799:                break;
1.90      schwarze  800:        case NODE_ERRORNAME:
                    801:                macro_open(p, "Er");
                    802:                break;
1.62      schwarze  803:        case NODE_FILENAME:
1.69      schwarze  804:                macro_open(p, "Pa");
1.17      kristaps  805:                break;
1.62      schwarze  806:        case NODE_FUNCTION:
1.69      schwarze  807:                macro_open(p, "Fn");
1.3       kristaps  808:                break;
1.62      schwarze  809:        case NODE_FUNCPROTOTYPE:
1.3       kristaps  810:                pnode_printfuncprototype(p, pn);
                    811:                break;
1.62      schwarze  812:        case NODE_FUNCSYNOPSISINFO:
1.69      schwarze  813:                macro_open(p, "Fd");
1.16      kristaps  814:                break;
1.62      schwarze  815:        case NODE_INFORMALEQUATION:
1.69      schwarze  816:                macro_line(p, "EQ");
1.43      kristaps  817:                break;
1.62      schwarze  818:        case NODE_INLINEEQUATION:
1.69      schwarze  819:                if (p->linestate == LINE_NEW)
                    820:                        p->linestate = LINE_TEXT;
                    821:                putchar('$');
1.43      kristaps  822:                break;
1.62      schwarze  823:        case NODE_ITEMIZEDLIST:
1.25      kristaps  824:                pnode_printlist(p, pn);
1.24      kristaps  825:                break;
1.62      schwarze  826:        case NODE_GROUP:
1.24      kristaps  827:                pnode_printgroup(p, pn);
1.10      kristaps  828:                break;
1.67      schwarze  829:        case NODE_KEYSYM:
1.69      schwarze  830:                macro_open(p, "Sy");
1.67      schwarze  831:                break;
1.62      schwarze  832:        case NODE_LEGALNOTICE:
1.69      schwarze  833:                macro_line(p, "Sh LEGAL NOTICE");
1.50      schwarze  834:                break;
1.62      schwarze  835:        case NODE_LINK:
1.96      schwarze  836:                pnode_printlink(p, pn);
                    837:                break;
1.62      schwarze  838:        case NODE_LITERAL:
1.90      schwarze  839:                macro_open(p, "Ql");
1.19      kristaps  840:                break;
1.62      schwarze  841:        case NODE_LITERALLAYOUT:
1.95      schwarze  842:                macro_close(p);
1.69      schwarze  843:                macro_argline(p, "Bd", pnode_getattr(pn, ATTRKEY_CLASS) ==
1.66      schwarze  844:                    ATTRVAL_MONOSPACED ? "-literal" : "-unfilled");
1.60      schwarze  845:                break;
1.62      schwarze  846:        case NODE_MML_MFENCED:
1.41      kristaps  847:                pnode_printmathfenced(p, pn);
1.40      kristaps  848:                break;
1.62      schwarze  849:        case NODE_MML_MROW:
                    850:        case NODE_MML_MI:
                    851:        case NODE_MML_MN:
                    852:        case NODE_MML_MO:
1.43      kristaps  853:                if (TAILQ_EMPTY(&pn->childq))
                    854:                        break;
                    855:                fputs(" { ", stdout);
1.40      kristaps  856:                break;
1.62      schwarze  857:        case NODE_MML_MFRAC:
                    858:        case NODE_MML_MSUB:
                    859:        case NODE_MML_MSUP:
1.40      kristaps  860:                pnode_printmath(p, pn);
                    861:                break;
1.62      schwarze  862:        case NODE_OPTION:
1.69      schwarze  863:                macro_open(p, "Fl");
1.1       kristaps  864:                break;
1.62      schwarze  865:        case NODE_ORDEREDLIST:
1.25      kristaps  866:                pnode_printlist(p, pn);
                    867:                break;
1.62      schwarze  868:        case NODE_PARA:
1.54      schwarze  869:                pnode_printpara(p, pn);
1.3       kristaps  870:                break;
1.87      schwarze  871:        case NODE_PARAMDEF:
1.62      schwarze  872:        case NODE_PARAMETER:
1.72      schwarze  873:                macro_nodeline(p, "Fa", pn, ARG_SINGLE);
1.4       kristaps  874:                pnode_unlinksub(pn);
1.1       kristaps  875:                break;
1.62      schwarze  876:        case NODE_QUOTE:
1.69      schwarze  877:                macro_open(p, "Qo");
1.28      kristaps  878:                break;
1.62      schwarze  879:        case NODE_PROGRAMLISTING:
                    880:        case NODE_SCREEN:
1.88      schwarze  881:        case NODE_SYNOPSIS:
1.69      schwarze  882:                macro_line(p, "Bd -literal");
1.15      kristaps  883:                break;
1.62      schwarze  884:        case NODE_REFENTRYINFO:
1.15      kristaps  885:                /* Suppress. */
                    886:                pnode_unlinksub(pn);
1.1       kristaps  887:                break;
1.62      schwarze  888:        case NODE_REFNAME:
1.10      kristaps  889:                /* Suppress non-text children... */
1.70      schwarze  890:                macro_open(p, "Nm");
1.72      schwarze  891:                macro_addnode(p, pn, ARG_SPACE | ARG_SINGLE);
1.4       kristaps  892:                pnode_unlinksub(pn);
1.10      kristaps  893:                break;
1.62      schwarze  894:        case NODE_REFNAMEDIV:
1.69      schwarze  895:                macro_line(p, "Sh NAME");
1.1       kristaps  896:                break;
1.62      schwarze  897:        case NODE_REFPURPOSE:
1.69      schwarze  898:                macro_open(p, "Nd");
1.10      kristaps  899:                break;
1.62      schwarze  900:        case NODE_REFSYNOPSISDIV:
1.6       kristaps  901:                pnode_printrefsynopsisdiv(p, pn);
1.1       kristaps  902:                break;
1.62      schwarze  903:        case NODE_PREFACE:
                    904:        case NODE_SECTION:
                    905:        case NODE_NOTE:
                    906:        case NODE_TIP:
                    907:        case NODE_CAUTION:
                    908:        case NODE_WARNING:
1.1       kristaps  909:                pnode_printrefsect(p, pn);
                    910:                break;
1.62      schwarze  911:        case NODE_REPLACEABLE:
1.69      schwarze  912:                macro_open(p, "Ar");
1.13      kristaps  913:                break;
1.62      schwarze  914:        case NODE_SBR:
1.69      schwarze  915:                macro_line(p, "br");
1.19      kristaps  916:                break;
1.62      schwarze  917:        case NODE_SGMLTAG:
1.90      schwarze  918:                macro_open(p, "Ic");
1.25      kristaps  919:                break;
1.62      schwarze  920:        case NODE_TEXT:
1.93      schwarze  921:        case NODE_ESCAPE:
                    922:                pnode_printtext(p, pn);
1.1       kristaps  923:                break;
1.82      schwarze  924:        case NODE_TGROUP:
                    925:                pnode_printtgroup(p, pn);
                    926:                break;
1.62      schwarze  927:        case NODE_TITLE:
1.97      schwarze  928:                if (pn->parent != NULL &&
                    929:                    pn->parent->node == NODE_BOOKINFO) {
1.69      schwarze  930:                        macro_open(p, "Nd");
1.82      schwarze  931:                        break;
                    932:                }
                    933:                pnode_printpara(p, pn);
                    934:                macro_nodeline(p, "Sy", pn, 0);
                    935:                pnode_unlinksub(pn);
1.50      schwarze  936:                break;
1.62      schwarze  937:        case NODE_TYPE:
1.69      schwarze  938:                macro_open(p, "Vt");
1.39      kristaps  939:                break;
1.62      schwarze  940:        case NODE_VARIABLELIST:
1.13      kristaps  941:                pnode_printvariablelist(p, pn);
                    942:                break;
1.62      schwarze  943:        case NODE_VARNAME:
1.69      schwarze  944:                macro_open(p, "Va");
1.23      kristaps  945:                break;
1.1       kristaps  946:        default:
                    947:                break;
                    948:        }
                    949:
                    950:        TAILQ_FOREACH(pp, &pn->childq, child)
                    951:                pnode_print(p, pp);
                    952:
                    953:        switch (pn->node) {
1.62      schwarze  954:        case NODE_INFORMALEQUATION:
1.69      schwarze  955:                macro_line(p, "EN");
1.40      kristaps  956:                break;
1.62      schwarze  957:        case NODE_INLINEEQUATION:
1.43      kristaps  958:                fputs("$ ", stdout);
1.69      schwarze  959:                p->linestate = sv;
1.43      kristaps  960:                break;
1.91      schwarze  961:        case NODE_MEMBER:
                    962:                if ((pp = TAILQ_NEXT(pn, child)) != NULL &&
                    963:                    pp->node != NODE_MEMBER)
                    964:                        pp = NULL;
                    965:                switch (p->linestate) {
                    966:                case LINE_TEXT:
                    967:                        if (pp != NULL)
                    968:                                print_text(p, ",", 0);
                    969:                        break;
                    970:                case LINE_MACRO:
                    971:                        if (pp != NULL)
                    972:                                macro_addarg(p, ",", ARG_SPACE);
                    973:                        macro_close(p);
                    974:                        break;
                    975:                case LINE_NEW:
                    976:                        break;
                    977:                }
                    978:                break;
1.62      schwarze  979:        case NODE_MML_MROW:
                    980:        case NODE_MML_MI:
                    981:        case NODE_MML_MN:
                    982:        case NODE_MML_MO:
1.43      kristaps  983:                if (TAILQ_EMPTY(&pn->childq))
                    984:                        break;
                    985:                fputs(" } ", stdout);
1.40      kristaps  986:                break;
1.62      schwarze  987:        case NODE_APPLICATION:
                    988:        case NODE_ARG:
                    989:        case NODE_AUTHOR:
                    990:        case NODE_CITEREFENTRY:
1.68      schwarze  991:        case NODE_CITETITLE:
1.62      schwarze  992:        case NODE_COMMAND:
                    993:        case NODE_CONSTANT:
                    994:        case NODE_EDITOR:
1.65      schwarze  995:        case NODE_EMAIL:
1.62      schwarze  996:        case NODE_EMPHASIS:
                    997:        case NODE_ENVAR:
1.90      schwarze  998:        case NODE_ERRORNAME:
1.62      schwarze  999:        case NODE_FILENAME:
                   1000:        case NODE_FIRSTTERM:
                   1001:        case NODE_FUNCTION:
                   1002:        case NODE_FUNCSYNOPSISINFO:
1.67      schwarze 1003:        case NODE_KEYSYM:
1.96      schwarze 1004:        case NODE_LINK:
1.62      schwarze 1005:        case NODE_LITERAL:
                   1006:        case NODE_OPTION:
                   1007:        case NODE_PARAMETER:
                   1008:        case NODE_REPLACEABLE:
                   1009:        case NODE_REFPURPOSE:
                   1010:        case NODE_SGMLTAG:
                   1011:        case NODE_TYPE:
                   1012:        case NODE_VARNAME:
1.91      schwarze 1013:                if (sv != LINE_MACRO && p->linestate == LINE_MACRO &&
                   1014:                    (pn->parent == NULL || pn->parent->node != NODE_MEMBER))
1.69      schwarze 1015:                        macro_closepunct(p, pn);
1.28      kristaps 1016:                break;
1.62      schwarze 1017:        case NODE_QUOTE:
1.69      schwarze 1018:                if (sv == LINE_NEW)
                   1019:                        macro_close(p);
                   1020:                sv = p->linestate;
                   1021:                macro_open(p, "Qc");
                   1022:                if (sv == LINE_NEW)
                   1023:                        macro_close(p);
1.10      kristaps 1024:                break;
1.62      schwarze 1025:        case NODE_REFNAME:
1.12      kristaps 1026:                /*
                   1027:                 * If we're in the NAME macro and we have multiple
                   1028:                 * <refname> macros in sequence, then print out a
                   1029:                 * trailing comma before the newline.
                   1030:                 */
1.64      schwarze 1031:                if (pn->parent != NULL &&
                   1032:                    pn->parent->node == NODE_REFNAMEDIV &&
                   1033:                    TAILQ_NEXT(pn, child) != NULL &&
                   1034:                    TAILQ_NEXT(pn, child)->node == NODE_REFNAME)
1.72      schwarze 1035:                        macro_addarg(p, ",", ARG_SPACE);
1.69      schwarze 1036:                if (sv == LINE_NEW)
                   1037:                        macro_close(p);
1.52      schwarze 1038:                break;
1.62      schwarze 1039:        case NODE_PREFACE:
                   1040:        case NODE_SECTION:
                   1041:        case NODE_NOTE:
                   1042:        case NODE_TIP:
                   1043:        case NODE_CAUTION:
                   1044:        case NODE_WARNING:
1.52      schwarze 1045:                p->level--;
1.12      kristaps 1046:                break;
1.98    ! schwarze 1047:        case NODE_BLOCKQUOTE:
1.62      schwarze 1048:        case NODE_LITERALLAYOUT:
                   1049:        case NODE_PROGRAMLISTING:
                   1050:        case NODE_SCREEN:
1.88      schwarze 1051:        case NODE_SYNOPSIS:
1.69      schwarze 1052:                macro_line(p, "Ed");
1.50      schwarze 1053:                break;
1.62      schwarze 1054:        case NODE_TITLE:
1.97      schwarze 1055:                if (pn->parent != NULL &&
                   1056:                    pn->parent->node == NODE_BOOKINFO)
1.69      schwarze 1057:                        macro_line(p, "Sh AUTHORS");
1.1       kristaps 1058:                break;
                   1059:        default:
                   1060:                break;
                   1061:        }
                   1062: }
                   1063:
1.74      schwarze 1064: void
                   1065: ptree_print(struct ptree *tree)
                   1066: {
                   1067:        struct format    formatter;
1.1       kristaps 1068:
1.74      schwarze 1069:        formatter.level = 0;
                   1070:        formatter.linestate = LINE_NEW;
                   1071:        pnode_printprologue(&formatter, tree);
                   1072:        pnode_print(&formatter, tree->root);
                   1073:        if (formatter.linestate != LINE_NEW)
                   1074:                putchar('\n');
1.1       kristaps 1075: }

CVSweb