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

Annotation of docbook2mdoc/docbook2mdoc.c, Revision 1.146

1.146   ! schwarze    1: /* $Id: docbook2mdoc.c,v 1.145 2019/05/01 12:52:05 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>
1.103     schwarze   22: #include <string.h>
1.1       kristaps   23:
1.139     schwarze   24: #include "xmalloc.h"
1.74      schwarze   25: #include "node.h"
1.75      schwarze   26: #include "macro.h"
1.74      schwarze   27: #include "format.h"
                     28:
                     29: /*
                     30:  * The implementation of the mdoc(7) formatter.
                     31:  */
1.12      kristaps   32:
1.74      schwarze   33: static void     pnode_print(struct format *, struct pnode *);
1.25      kristaps   34:
1.37      kristaps   35:
1.54      schwarze   36: static void
1.93      schwarze   37: pnode_printtext(struct format *f, struct pnode *n)
                     38: {
1.94      schwarze   39:        struct pnode    *nn;
1.93      schwarze   40:        char            *cp;
1.103     schwarze   41:        int              accept_arg;
1.93      schwarze   42:
1.103     schwarze   43:        cp = n->b;
                     44:        accept_arg = f->flags & FMT_ARG;
1.138     schwarze   45:        if (f->linestate == LINE_MACRO && !accept_arg &&
                     46:            (n->flags & NFLAG_SPC) == 0) {
1.103     schwarze   47:                for (;;) {
                     48:                        if (*cp == '\0')
                     49:                                return;
                     50:                        if (strchr("!),.:;?]", *cp) == NULL)
                     51:                                break;
                     52:                        printf(" %c", *cp++);
                     53:                }
                     54:                if (isspace((unsigned char)*cp)) {
                     55:                        while (isspace((unsigned char)*cp))
                     56:                                cp++;
                     57:                        macro_close(f);
                     58:                } else {
                     59:                        fputs(" Ns", stdout);
                     60:                        f->flags &= FMT_IMPL;
                     61:                        accept_arg = 1;
                     62:                }
1.94      schwarze   63:        }
1.103     schwarze   64:        if (f->linestate == LINE_MACRO && !accept_arg &&
                     65:            (f->flags & (FMT_CHILD | FMT_IMPL)) == 0)
                     66:                macro_close(f);
1.94      schwarze   67:
                     68:        /*
                     69:         * Text preceding a macro without intervening whitespace
                     70:         * requires a .Pf macro.
                     71:         * Set the spacing flag to avoid a redundant .Ns macro.
                     72:         */
                     73:
                     74:        if (f->linestate != LINE_MACRO &&
1.138     schwarze   75:            (nn = TAILQ_NEXT(n, child)) != NULL &&
                     76:             (nn->flags & NFLAG_SPC) == 0) {
1.113     schwarze   77:                switch (pnode_class(nn->node)) {
                     78:                case CLASS_LINE:
                     79:                case CLASS_ENCL:
                     80:                        macro_open(f, "Pf");
                     81:                        accept_arg = 1;
                     82:                        f->flags |= FMT_CHILD;
1.138     schwarze   83:                        nn->flags |= NFLAG_SPC;
1.113     schwarze   84:                        break;
                     85:                default:
                     86:                        break;
                     87:                }
1.93      schwarze   88:        }
                     89:
1.103     schwarze   90:        switch (f->linestate) {
1.107     schwarze   91:        case LINE_NEW:
                     92:                break;
1.103     schwarze   93:        case LINE_TEXT:
1.138     schwarze   94:                if (n->flags & NFLAG_SPC) {
                     95:                        if (n->flags & NFLAG_LINE &&
                     96:                            pnode_class(n->node) == CLASS_TEXT)
1.107     schwarze   97:                                macro_close(f);
                     98:                        else
                     99:                                putchar(' ');
1.105     schwarze  100:                }
1.103     schwarze  101:                break;
                    102:        case LINE_MACRO:
1.136     schwarze  103:                if (accept_arg == 0)
                    104:                        macro_close(f);
1.138     schwarze  105:                else if (n->flags & NFLAG_SPC ||
                    106:                    (f->flags & FMT_ARG) == 0 ||
1.136     schwarze  107:                    (nn = TAILQ_PREV(n, pnodeq, child)) == NULL ||
                    108:                    pnode_class(nn->node) != CLASS_TEXT)
1.93      schwarze  109:                        putchar(' ');
1.103     schwarze  110:                break;
1.93      schwarze  111:        }
                    112:
                    113:        if (n->node == NODE_ESCAPE) {
                    114:                fputs(n->b, stdout);
1.107     schwarze  115:                if (f->linestate == LINE_NEW)
                    116:                        f->linestate = LINE_TEXT;
1.93      schwarze  117:                return;
                    118:        }
                    119:
                    120:        /*
                    121:         * Remove the prefix '-' from <option> elements
                    122:         * because the arguments of .Fl macros do not need it.
                    123:         */
                    124:
                    125:        if (n->parent != NULL && n->parent->node == NODE_OPTION && *cp == '-')
                    126:                cp++;
                    127:
1.107     schwarze  128:        if (f->linestate == LINE_MACRO)
                    129:                macro_addarg(f, cp, 0);
                    130:        else
                    131:                print_text(f, cp, 0);
1.93      schwarze  132: }
                    133:
                    134: static void
1.126     schwarze  135: pnode_printimagedata(struct format *f, struct pnode *n)
                    136: {
                    137:        const char      *cp;
                    138:
                    139:        if ((cp = pnode_getattr_raw(n, ATTRKEY_FILEREF, NULL)) == NULL)
                    140:                cp = pnode_getattr_raw(n, ATTRKEY_ENTITYREF, NULL);
                    141:        if (cp != NULL) {
                    142:                print_text(f, "[image:", ARG_SPACE);
                    143:                print_text(f, cp, ARG_SPACE);
                    144:                print_text(f, "]", 0);
                    145:        } else
                    146:                print_text(f, "[image]", ARG_SPACE);
                    147: }
                    148:
                    149: static void
1.110     schwarze  150: pnode_printrefnamediv(struct format *f, struct pnode *n)
                    151: {
                    152:        struct pnode    *nc, *nn;
                    153:        int              comma;
                    154:
1.130     schwarze  155:        f->parastate = PARA_HAVE;
1.110     schwarze  156:        macro_line(f, "Sh NAME");
1.130     schwarze  157:        f->parastate = PARA_HAVE;
1.110     schwarze  158:        comma = 0;
                    159:        TAILQ_FOREACH_SAFE(nc, &n->childq, child, nn) {
                    160:                if (nc->node != NODE_REFNAME)
                    161:                        continue;
                    162:                if (comma)
                    163:                        macro_addarg(f, ",", ARG_SPACE);
                    164:                macro_open(f, "Nm");
                    165:                macro_addnode(f, nc, ARG_SPACE);
                    166:                pnode_unlink(nc);
                    167:                comma = 1;
                    168:        }
                    169:        macro_close(f);
                    170: }
                    171:
1.37      kristaps  172: /*
1.10      kristaps  173:  * If the SYNOPSIS macro has a superfluous title, kill it.
1.8       kristaps  174:  */
1.1       kristaps  175: static void
1.101     schwarze  176: pnode_printrefsynopsisdiv(struct format *f, struct pnode *n)
1.6       kristaps  177: {
1.101     schwarze  178:        struct pnode    *nc, *nn;
1.6       kristaps  179:
1.101     schwarze  180:        TAILQ_FOREACH_SAFE(nc, &n->childq, child, nn)
                    181:                if (nc->node == NODE_TITLE)
                    182:                        pnode_unlink(nc);
1.71      schwarze  183:
1.130     schwarze  184:        f->parastate = PARA_HAVE;
1.101     schwarze  185:        macro_line(f, "Sh SYNOPSIS");
1.130     schwarze  186:        f->parastate = PARA_HAVE;
1.6       kristaps  187: }
                    188:
1.8       kristaps  189: /*
                    190:  * Start a hopefully-named `Sh' section.
                    191:  */
1.6       kristaps  192: static void
1.119     schwarze  193: pnode_printsection(struct format *f, struct pnode *n)
1.1       kristaps  194: {
1.115     schwarze  195:        struct pnode    *nc, *ncc;
1.52      schwarze  196:        int              flags, level;
                    197:
1.143     schwarze  198:        if (n->parent == NULL)
1.56      schwarze  199:                return;
                    200:
1.101     schwarze  201:        level = ++f->level;
1.72      schwarze  202:        flags = ARG_SPACE;
1.121     schwarze  203:        switch (n->node) {
                    204:        case NODE_SECTION:
                    205:        case NODE_APPENDIX:
                    206:                if (level == 1)
                    207:                        flags |= ARG_UPPER;
                    208:                break;
                    209:        case NODE_SIMPLESECT:
                    210:                if (level < 2)
                    211:                        level = 2;
                    212:                break;
1.142     schwarze  213:        case NODE_NOTE:
1.121     schwarze  214:                if (level < 3)
1.52      schwarze  215:                        level = 3;
1.121     schwarze  216:                break;
1.142     schwarze  217:        default:
                    218:                abort();
1.52      schwarze  219:        }
1.1       kristaps  220:
1.101     schwarze  221:        TAILQ_FOREACH(nc, &n->childq, child)
                    222:                if (nc->node == NODE_TITLE)
1.1       kristaps  223:                        break;
                    224:
1.52      schwarze  225:        switch (level) {
1.62      schwarze  226:        case 1:
1.101     schwarze  227:                macro_close(f);
1.130     schwarze  228:                f->parastate = PARA_HAVE;
1.101     schwarze  229:                macro_open(f, "Sh");
1.29      kristaps  230:                break;
1.62      schwarze  231:        case 2:
1.101     schwarze  232:                macro_close(f);
1.130     schwarze  233:                f->parastate = PARA_HAVE;
1.101     schwarze  234:                macro_open(f, "Ss");
1.29      kristaps  235:                break;
1.52      schwarze  236:        default:
1.130     schwarze  237:                if (f->parastate == PARA_MID)
                    238:                        f->parastate = PARA_WANT;
1.101     schwarze  239:                macro_open(f, "Sy");
1.29      kristaps  240:                break;
                    241:        }
1.142     schwarze  242:        macro_addnode(f, nc, flags);
1.101     schwarze  243:        macro_close(f);
1.115     schwarze  244:
                    245:        /*
                    246:         * DocBook has no equivalent for -split mode,
                    247:         * so just switch the default in the AUTHORS section.
                    248:         */
                    249:
                    250:        if (nc != NULL) {
1.130     schwarze  251:                if (level == 1 &&
                    252:                    (ncc = TAILQ_FIRST(&nc->childq)) != NULL &&
                    253:                    ncc->node == NODE_TEXT &&
1.115     schwarze  254:                    strcasecmp(ncc->b, "AUTHORS") == 0)
                    255:                        macro_line(f, "An -nosplit");
                    256:                pnode_unlink(nc);
                    257:        }
1.130     schwarze  258:        f->parastate = level > 2 ? PARA_WANT : PARA_HAVE;
1.1       kristaps  259: }
                    260:
1.8       kristaps  261: /*
                    262:  * Start a reference, extracting the title and volume.
                    263:  */
1.1       kristaps  264: static void
1.101     schwarze  265: pnode_printciterefentry(struct format *f, struct pnode *n)
1.1       kristaps  266: {
1.101     schwarze  267:        struct pnode    *nc, *title, *manvol;
1.1       kristaps  268:
                    269:        title = manvol = NULL;
1.101     schwarze  270:        TAILQ_FOREACH(nc, &n->childq, child) {
                    271:                if (nc->node == NODE_MANVOLNUM)
                    272:                        manvol = nc;
                    273:                else if (nc->node == NODE_REFENTRYTITLE)
                    274:                        title = nc;
1.69      schwarze  275:        }
1.101     schwarze  276:        macro_open(f, "Xr");
1.69      schwarze  277:        if (title == NULL)
1.101     schwarze  278:                macro_addarg(f, "unknown", ARG_SPACE);
1.69      schwarze  279:        else
1.101     schwarze  280:                macro_addnode(f, title, ARG_SPACE | ARG_SINGLE);
1.69      schwarze  281:        if (manvol == NULL)
1.101     schwarze  282:                macro_addarg(f, "1", ARG_SPACE);
1.64      schwarze  283:        else
1.101     schwarze  284:                macro_addnode(f, manvol, ARG_SPACE | ARG_SINGLE);
                    285:        pnode_unlinksub(n);
1.1       kristaps  286: }
                    287:
1.40      kristaps  288: /*
1.41      kristaps  289:  * The <mml:mfenced> node is a little peculiar.
                    290:  * First, it can have arbitrary open and closing tokens, which default
                    291:  * to parentheses.
                    292:  * Second, >1 arguments are separated by commas.
                    293:  */
                    294: static void
1.101     schwarze  295: pnode_printmathfenced(struct format *f, struct pnode *n)
1.41      kristaps  296: {
1.101     schwarze  297:        struct pnode    *nc;
1.41      kristaps  298:
1.101     schwarze  299:        printf("left %s ", pnode_getattr_raw(n, ATTRKEY_OPEN, "("));
1.41      kristaps  300:
1.101     schwarze  301:        nc = TAILQ_FIRST(&n->childq);
                    302:        pnode_print(f, nc);
1.41      kristaps  303:
1.101     schwarze  304:        while ((nc = TAILQ_NEXT(nc, child)) != NULL) {
1.41      kristaps  305:                putchar(',');
1.101     schwarze  306:                pnode_print(f, nc);
1.41      kristaps  307:        }
1.101     schwarze  308:        printf("right %s ", pnode_getattr_raw(n, ATTRKEY_CLOSE, ")"));
                    309:        pnode_unlinksub(n);
1.41      kristaps  310: }
                    311:
                    312: /*
1.40      kristaps  313:  * These math nodes require special handling because they have infix
                    314:  * syntax, instead of the usual prefix or prefix.
                    315:  * So we need to break up the first and second child node with a
                    316:  * particular eqn(7) word.
                    317:  */
                    318: static void
1.101     schwarze  319: pnode_printmath(struct format *f, struct pnode *n)
1.40      kristaps  320: {
1.101     schwarze  321:        struct pnode    *nc;
1.40      kristaps  322:
1.101     schwarze  323:        nc = TAILQ_FIRST(&n->childq);
                    324:        pnode_print(f, nc);
1.40      kristaps  325:
1.101     schwarze  326:        switch (n->node) {
1.62      schwarze  327:        case NODE_MML_MSUP:
1.42      kristaps  328:                fputs(" sup ", stdout);
1.40      kristaps  329:                break;
1.62      schwarze  330:        case NODE_MML_MFRAC:
1.42      kristaps  331:                fputs(" over ", stdout);
1.40      kristaps  332:                break;
1.62      schwarze  333:        case NODE_MML_MSUB:
1.42      kristaps  334:                fputs(" sub ", stdout);
1.40      kristaps  335:                break;
                    336:        default:
                    337:                break;
                    338:        }
                    339:
1.101     schwarze  340:        nc = TAILQ_NEXT(nc, child);
                    341:        pnode_print(f, nc);
                    342:        pnode_unlinksub(n);
1.40      kristaps  343: }
                    344:
1.3       kristaps  345: static void
1.101     schwarze  346: pnode_printfuncprototype(struct format *f, struct pnode *n)
1.3       kristaps  347: {
1.145     schwarze  348:        struct pnode    *fdef, *fps, *ftype, *nc, *nn;
1.3       kristaps  349:
1.132     schwarze  350:        /*
                    351:         * Extract <funcdef> child and ignore <void> child.
                    352:         * Leave other children in place, to be treated as parameters.
                    353:         */
                    354:
                    355:        fdef = NULL;
                    356:        TAILQ_FOREACH_SAFE(nc, &n->childq, child, nn) {
                    357:                switch (nc->node) {
                    358:                case NODE_FUNCDEF:
                    359:                        if (fdef == NULL) {
                    360:                                fdef = nc;
                    361:                                TAILQ_REMOVE(&n->childq, nc, child);
                    362:                                nc->parent = NULL;
                    363:                        }
                    364:                        break;
                    365:                case NODE_VOID:
                    366:                        pnode_unlink(nc);
1.3       kristaps  367:                        break;
1.132     schwarze  368:                default:
                    369:                        break;
                    370:                }
                    371:        }
1.3       kristaps  372:
1.132     schwarze  373:        /*
                    374:         * If no children are left, the function is void; use .Fn.
                    375:         * Otherwise, use .Fo.
                    376:         */
                    377:
                    378:        nc = TAILQ_FIRST(&n->childq);
1.86      schwarze  379:        if (fdef != NULL) {
1.132     schwarze  380:                ftype = TAILQ_FIRST(&fdef->childq);
                    381:                if (ftype != NULL && ftype->node == NODE_TEXT) {
                    382:                        macro_argline(f, "Ft", ftype->b);
                    383:                        pnode_unlink(ftype);
                    384:                }
                    385:                if (nc == NULL) {
                    386:                        macro_open(f, "Fn");
                    387:                        macro_addnode(f, fdef, ARG_SPACE | ARG_SINGLE);
                    388:                        macro_addarg(f, "void", ARG_SPACE);
                    389:                        macro_close(f);
                    390:                } else
                    391:                        macro_nodeline(f, "Fo", fdef, ARG_SINGLE);
1.86      schwarze  392:                pnode_unlink(fdef);
1.132     schwarze  393:        } else if (nc == NULL)
                    394:                macro_line(f, "Fn UNKNOWN void");
                    395:        else
1.101     schwarze  396:                macro_line(f, "Fo UNKNOWN");
1.3       kristaps  397:
1.132     schwarze  398:        if (nc == NULL)
                    399:                return;
                    400:
                    401:        while (nc != NULL) {
1.145     schwarze  402:                if ((fps = pnode_takefirst(nc, NODE_FUNCPARAMS)) != NULL) {
                    403:                        macro_open(f, "Fa \"");
                    404:                        macro_addnode(f, nc, ARG_QUOTED);
                    405:                        macro_addarg(f, "(", ARG_QUOTED);
                    406:                        macro_addnode(f, fps, ARG_QUOTED);
                    407:                        macro_addarg(f, ")", ARG_QUOTED);
                    408:                        putchar('"');
                    409:                        macro_close(f);
                    410:                } else
                    411:                        macro_nodeline(f, "Fa", nc, ARG_SINGLE);
1.132     schwarze  412:                pnode_unlink(nc);
                    413:                nc = TAILQ_FIRST(&n->childq);
                    414:        }
1.101     schwarze  415:        macro_line(f, "Fc");
1.3       kristaps  416: }
                    417:
1.44      schwarze  418: /*
1.10      kristaps  419:  * The <arg> element is more complicated than it should be because text
                    420:  * nodes are treated like ".Ar foo", but non-text nodes need to be
                    421:  * re-sent into the printer (i.e., without the preceding ".Ar").
1.12      kristaps  422:  * This also handles the case of "repetition" (or in other words, the
                    423:  * ellipsis following an argument) and optionality.
1.10      kristaps  424:  */
1.4       kristaps  425: static void
1.101     schwarze  426: pnode_printarg(struct format *f, struct pnode *n)
1.4       kristaps  427: {
1.101     schwarze  428:        struct pnode    *nc;
                    429:        struct pattr    *a;
1.103     schwarze  430:        int              isop, isrep, was_impl;
1.12      kristaps  431:
                    432:        isop = 1;
1.103     schwarze  433:        isrep = was_impl = 0;
1.101     schwarze  434:        TAILQ_FOREACH(a, &n->attrq, child) {
                    435:                if (a->key == ATTRKEY_CHOICE &&
                    436:                    (a->val == ATTRVAL_PLAIN || a->val == ATTRVAL_REQ))
1.12      kristaps  437:                        isop = 0;
1.101     schwarze  438:                else if (a->key == ATTRKEY_REP && a->val == ATTRVAL_REPEAT)
1.12      kristaps  439:                        isrep = 1;
                    440:        }
1.103     schwarze  441:        if (isop) {
                    442:                if (f->flags & FMT_IMPL) {
                    443:                        was_impl = 1;
                    444:                        macro_open(f, "Oo");
                    445:                } else {
                    446:                        macro_open(f, "Op");
                    447:                        f->flags |= FMT_IMPL;
                    448:                }
                    449:        }
1.101     schwarze  450:        TAILQ_FOREACH(nc, &n->childq, child) {
                    451:                if (nc->node == NODE_TEXT)
                    452:                        macro_open(f, "Ar");
                    453:                pnode_print(f, nc);
1.10      kristaps  454:        }
1.117     schwarze  455:        if (isrep && f->linestate == LINE_MACRO)
                    456:                macro_addarg(f, "...", ARG_SPACE);
1.103     schwarze  457:        if (isop) {
                    458:                if (was_impl)
                    459:                        macro_open(f, "Oc");
                    460:                else
                    461:                        f->flags &= ~FMT_IMPL;
                    462:        }
1.101     schwarze  463:        pnode_unlinksub(n);
1.4       kristaps  464: }
                    465:
1.24      kristaps  466: static void
1.101     schwarze  467: pnode_printgroup(struct format *f, struct pnode *n)
1.24      kristaps  468: {
1.117     schwarze  469:        struct pnode    *nc;
1.101     schwarze  470:        struct pattr    *a;
1.117     schwarze  471:        int              bar, isop, isrep, was_impl;
1.24      kristaps  472:
                    473:        isop = 1;
1.117     schwarze  474:        isrep = was_impl = 0;
                    475:        TAILQ_FOREACH(a, &n->attrq, child) {
1.101     schwarze  476:                if (a->key == ATTRKEY_CHOICE &&
1.117     schwarze  477:                    (a->val == ATTRVAL_PLAIN || a->val == ATTRVAL_REQ))
1.24      kristaps  478:                        isop = 0;
1.117     schwarze  479:                else if (a->key == ATTRKEY_REP && a->val == ATTRVAL_REPEAT)
                    480:                        isrep = 1;
                    481:        }
                    482:        if (isop) {
                    483:                if (f->flags & FMT_IMPL) {
                    484:                        was_impl = 1;
                    485:                        macro_open(f, "Oo");
                    486:                } else {
                    487:                        macro_open(f, "Op");
                    488:                        f->flags |= FMT_IMPL;
                    489:                }
                    490:        } else if (isrep) {
                    491:                if (f->flags & FMT_IMPL) {
                    492:                        was_impl = 1;
                    493:                        macro_open(f, "Bro");
                    494:                } else {
                    495:                        macro_open(f, "Brq");
                    496:                        f->flags |= FMT_IMPL;
1.24      kristaps  497:                }
1.117     schwarze  498:        }
                    499:        bar = 0;
1.101     schwarze  500:        TAILQ_FOREACH(nc, &n->childq, child) {
1.117     schwarze  501:                if (bar && f->linestate == LINE_MACRO)
                    502:                        macro_addarg(f, "|", ARG_SPACE);
1.101     schwarze  503:                pnode_print(f, nc);
1.117     schwarze  504:                bar = 1;
                    505:        }
                    506:        if (isop) {
                    507:                if (was_impl)
                    508:                        macro_open(f, "Oc");
                    509:                else
                    510:                        f->flags &= ~FMT_IMPL;
                    511:        } else if (isrep) {
                    512:                if (was_impl)
                    513:                        macro_open(f, "Brc");
                    514:                else
                    515:                        f->flags &= ~FMT_IMPL;
1.24      kristaps  516:        }
1.117     schwarze  517:        if (isrep && f->linestate == LINE_MACRO)
                    518:                macro_addarg(f, "...", ARG_SPACE);
1.101     schwarze  519:        pnode_unlinksub(n);
1.24      kristaps  520: }
                    521:
1.7       kristaps  522: static void
1.118     schwarze  523: pnode_printsystemitem(struct format *f, struct pnode *n)
                    524: {
                    525:        switch (pnode_getattr(n, ATTRKEY_CLASS)) {
                    526:        case ATTRVAL_IPADDRESS:
                    527:                break;
                    528:        case ATTRVAL_SYSTEMNAME:
                    529:                macro_open(f, "Pa");
                    530:                break;
                    531:        case ATTRVAL_EVENT:
                    532:        default:
                    533:                macro_open(f, "Sy");
                    534:                break;
                    535:        }
                    536: }
                    537:
                    538: static void
1.78      schwarze  539: pnode_printauthor(struct format *f, struct pnode *n)
                    540: {
1.101     schwarze  541:        struct pnode    *nc, *nn;
1.78      schwarze  542:        int              have_contrib, have_name;
                    543:
                    544:        /*
                    545:         * Print <contrib> children up front, before the .An scope,
                    546:         * and figure out whether we a name of a person.
                    547:         */
                    548:
                    549:        have_contrib = have_name = 0;
1.101     schwarze  550:        TAILQ_FOREACH_SAFE(nc, &n->childq, child, nn) {
1.78      schwarze  551:                switch (nc->node) {
                    552:                case NODE_CONTRIB:
                    553:                        if (have_contrib)
                    554:                                print_text(f, ",", 0);
                    555:                        print_textnode(f, nc);
                    556:                        pnode_unlink(nc);
                    557:                        have_contrib = 1;
                    558:                        break;
                    559:                case NODE_PERSONNAME:
                    560:                        have_name = 1;
                    561:                        break;
                    562:                default:
                    563:                        break;
                    564:                }
                    565:        }
                    566:        if (TAILQ_FIRST(&n->childq) == NULL)
                    567:                return;
                    568:
                    569:        if (have_contrib)
                    570:                print_text(f, ":", 0);
                    571:
                    572:        /*
                    573:          * If we have a name, print it in the .An scope and leave
                    574:          * all other content for child handlers, to print after the
                    575:          * scope.  Otherwise, print everything in the scope.
                    576:         */
                    577:
                    578:        macro_open(f, "An");
1.101     schwarze  579:        TAILQ_FOREACH_SAFE(nc, &n->childq, child, nn) {
1.78      schwarze  580:                if (nc->node == NODE_PERSONNAME || have_name == 0) {
                    581:                        macro_addnode(f, nc, ARG_SPACE);
                    582:                        pnode_unlink(nc);
                    583:                }
1.80      schwarze  584:        }
                    585:
                    586:        /*
                    587:         * If there is an email address,
                    588:         * print it on the same macro line.
                    589:         */
                    590:
                    591:        if ((nc = pnode_findfirst(n, NODE_EMAIL)) != NULL) {
1.103     schwarze  592:                f->flags |= FMT_CHILD;
1.115     schwarze  593:                macro_open(f, "Aq Mt");
                    594:                macro_addnode(f, nc, ARG_SPACE);
1.80      schwarze  595:                pnode_unlink(nc);
1.78      schwarze  596:        }
                    597:
                    598:        /*
                    599:         * If there are still unprinted children, end the scope
                    600:         * with a comma.  Otherwise, leave the scope open in case
                    601:         * a text node follows that starts with closing punctuation.
                    602:         */
                    603:
                    604:        if (TAILQ_FIRST(&n->childq) != NULL) {
                    605:                macro_addarg(f, ",", ARG_SPACE);
                    606:                macro_close(f);
                    607:        }
                    608: }
                    609:
                    610: static void
1.129     schwarze  611: pnode_printxref(struct format *f, struct pnode *n)
                    612: {
                    613:        const char      *linkend;
                    614:
                    615:        linkend = pnode_getattr_raw(n, ATTRKEY_LINKEND, NULL);
                    616:        if (linkend != NULL) {
                    617:                macro_open(f, "Sx");
                    618:                macro_addarg(f, linkend, ARG_SPACE);
                    619:        }
                    620: }
                    621:
                    622: static void
1.96      schwarze  623: pnode_printlink(struct format *f, struct pnode *n)
                    624: {
1.109     schwarze  625:        struct pnode    *nc;
1.96      schwarze  626:        const char      *uri, *text;
                    627:
                    628:        uri = pnode_getattr_raw(n, ATTRKEY_LINKEND, NULL);
                    629:        if (uri != NULL) {
                    630:                if (TAILQ_FIRST(&n->childq) != NULL) {
1.109     schwarze  631:                        TAILQ_FOREACH(nc, &n->childq, child)
                    632:                                pnode_print(f, nc);
1.96      schwarze  633:                        text = "";
1.109     schwarze  634:                } else if ((text = pnode_getattr_raw(n,
                    635:                    ATTRKEY_ENDTERM, NULL)) != NULL) {
                    636:                        if (f->linestate == LINE_MACRO && f->flags & FMT_ARG)
                    637:                                macro_addarg(f, text, ARG_SPACE);
                    638:                        else
1.96      schwarze  639:                                print_text(f, text, ARG_SPACE);
                    640:                }
1.103     schwarze  641:                if (text != NULL) {
1.109     schwarze  642:                        if (f->flags & FMT_IMPL)
                    643:                                macro_open(f, "Po");
                    644:                        else {
                    645:                                macro_open(f, "Pq");
                    646:                                f->flags |= FMT_CHILD;
                    647:                        }
1.103     schwarze  648:                }
1.96      schwarze  649:                macro_open(f, "Sx");
                    650:                macro_addarg(f, uri, ARG_SPACE);
1.109     schwarze  651:                if (text != NULL && f->flags & FMT_IMPL)
                    652:                        macro_open(f, "Pc");
1.96      schwarze  653:                pnode_unlinksub(n);
                    654:                return;
                    655:        }
                    656:        uri = pnode_getattr_raw(n, ATTRKEY_XLINK_HREF, NULL);
                    657:        if (uri == NULL)
                    658:                uri = pnode_getattr_raw(n, ATTRKEY_URL, NULL);
                    659:        if (uri != NULL) {
                    660:                macro_open(f, "Lk");
                    661:                macro_addarg(f, uri, ARG_SPACE | ARG_SINGLE);
                    662:                if (TAILQ_FIRST(&n->childq) != NULL)
                    663:                        macro_addnode(f, n, ARG_SPACE | ARG_SINGLE);
                    664:                pnode_unlinksub(n);
1.128     schwarze  665:        }
                    666: }
                    667:
                    668: static void
                    669: pnode_printolink(struct format *f, struct pnode *n)
                    670: {
                    671:        const char      *uri, *ptr, *local;
                    672:
                    673:        uri = pnode_getattr_raw(n, ATTRKEY_TARGETDOC, NULL);
                    674:        ptr = pnode_getattr_raw(n, ATTRKEY_TARGETPTR, NULL);
                    675:        local = pnode_getattr_raw(n, ATTRKEY_LOCALINFO, NULL);
                    676:        if (uri == NULL) {
                    677:                uri = ptr;
                    678:                ptr = NULL;
                    679:        }
                    680:        if (uri == NULL) {
                    681:                uri = local;
                    682:                local = NULL;
                    683:        }
                    684:        if (uri == NULL)
1.96      schwarze  685:                return;
1.128     schwarze  686:
                    687:        macro_open(f, "Lk");
                    688:        macro_addarg(f, uri, ARG_SPACE | ARG_SINGLE);
                    689:        macro_addnode(f, n, ARG_SPACE | ARG_SINGLE);
                    690:        if (ptr != NULL || local != NULL) {
                    691:                macro_close(f);
                    692:                macro_open(f, "Pq");
                    693:                if (ptr != NULL)
                    694:                        macro_addarg(f, ptr, ARG_SPACE);
                    695:                if (local != NULL)
                    696:                        macro_addarg(f, local, ARG_SPACE);
1.96      schwarze  697:        }
1.128     schwarze  698:        pnode_unlinksub(n);
1.96      schwarze  699: }
                    700:
                    701: static void
1.116     schwarze  702: pnode_printprologue(struct format *f, struct pnode *root)
1.7       kristaps  703: {
1.141     schwarze  704:        struct pnode    *name, *nc;
1.7       kristaps  705:
1.141     schwarze  706:        nc = TAILQ_FIRST(&root->childq);
                    707:        assert(nc->node == NODE_DATE);
                    708:        macro_nodeline(f, "Dd", nc, 0);
                    709:        pnode_unlink(nc);
1.116     schwarze  710:
                    711:        macro_open(f, "Dt");
1.141     schwarze  712:        name = TAILQ_FIRST(&root->childq);
                    713:        assert(name->node == NODE_REFENTRYTITLE);
                    714:        macro_addnode(f, name, ARG_SPACE | ARG_SINGLE | ARG_UPPER);
                    715:        TAILQ_REMOVE(&root->childq, name, child);
                    716:        name->parent = NULL;
                    717:        nc = TAILQ_FIRST(&root->childq);
                    718:        assert (nc->node == NODE_MANVOLNUM);
                    719:        macro_addnode(f, nc, ARG_SPACE | ARG_SINGLE);
                    720:        pnode_unlink(nc);
1.116     schwarze  721:
1.101     schwarze  722:        macro_line(f, "Os");
1.116     schwarze  723:
1.141     schwarze  724:        nc = TAILQ_FIRST(&root->childq);
                    725:        if (nc != NULL && nc->node == NODE_TITLE) {
1.116     schwarze  726:                macro_line(f, "Sh NAME");
1.141     schwarze  727:                macro_nodeline(f, "Nm", name, ARG_SINGLE);
                    728:                macro_nodeline(f, "Nd", nc, 0);
                    729:                pnode_unlink(nc);
1.116     schwarze  730:        }
1.119     schwarze  731:        pnode_unlink(name);
1.130     schwarze  732:        f->parastate = PARA_HAVE;
1.7       kristaps  733: }
                    734:
1.42      kristaps  735: /*
                    736:  * We can have multiple <term> elements within a <varlistentry>, which
                    737:  * we should comma-separate as list headers.
                    738:  */
1.13      kristaps  739: static void
1.101     schwarze  740: pnode_printvarlistentry(struct format *f, struct pnode *n)
1.13      kristaps  741: {
1.133     schwarze  742:        struct pnode    *nc, *nn, *ncc;
                    743:        int              comma;
1.13      kristaps  744:
1.101     schwarze  745:        macro_open(f, "It");
1.130     schwarze  746:        f->parastate = PARA_HAVE;
1.103     schwarze  747:        f->flags |= FMT_IMPL;
1.133     schwarze  748:        comma = -1;
1.108     schwarze  749:        TAILQ_FOREACH_SAFE(nc, &n->childq, child, nn) {
1.101     schwarze  750:                if (nc->node != NODE_TERM && nc->node != NODE_GLOSSTERM)
1.69      schwarze  751:                        continue;
1.133     schwarze  752:                if (comma != -1) {
1.108     schwarze  753:                        switch (f->linestate) {
                    754:                        case LINE_NEW:
                    755:                                break;
                    756:                        case LINE_TEXT:
                    757:                                print_text(f, ",", 0);
                    758:                                break;
                    759:                        case LINE_MACRO:
1.133     schwarze  760:                                macro_addarg(f, ",", comma);
1.108     schwarze  761:                                break;
                    762:                        }
                    763:                }
1.130     schwarze  764:                f->parastate = PARA_HAVE;
1.133     schwarze  765:                comma = (ncc = TAILQ_FIRST(&nc->childq)) == NULL ||
                    766:                    pnode_class(ncc->node) == CLASS_TEXT ? 0 : ARG_SPACE;
1.101     schwarze  767:                pnode_print(f, nc);
1.108     schwarze  768:                pnode_unlink(nc);
1.69      schwarze  769:        }
1.101     schwarze  770:        macro_close(f);
1.130     schwarze  771:        f->parastate = PARA_HAVE;
1.108     schwarze  772:        while ((nc = TAILQ_FIRST(&n->childq)) != NULL) {
                    773:                pnode_print(f, nc);
                    774:                pnode_unlink(nc);
                    775:        }
                    776:        macro_close(f);
1.130     schwarze  777:        f->parastate = PARA_HAVE;
1.71      schwarze  778: }
                    779:
                    780: static void
1.101     schwarze  781: pnode_printtitle(struct format *f, struct pnode *n)
1.71      schwarze  782: {
1.101     schwarze  783:        struct pnode    *nc, *nn;
1.71      schwarze  784:
1.101     schwarze  785:        TAILQ_FOREACH_SAFE(nc, &n->childq, child, nn) {
                    786:                if (nc->node == NODE_TITLE) {
1.130     schwarze  787:                        if (f->parastate == PARA_MID)
                    788:                                f->parastate = PARA_WANT;
                    789:                        macro_nodeline(f, "Sy", nc, 0);
1.101     schwarze  790:                        pnode_unlink(nc);
1.71      schwarze  791:                }
                    792:        }
1.13      kristaps  793: }
                    794:
                    795: static void
1.101     schwarze  796: pnode_printrow(struct format *f, struct pnode *n)
1.25      kristaps  797: {
1.101     schwarze  798:        struct pnode    *nc;
1.25      kristaps  799:
1.101     schwarze  800:        macro_line(f, "Bl -dash -compact");
                    801:        TAILQ_FOREACH(nc, &n->childq, child) {
                    802:                macro_line(f, "It");
                    803:                pnode_print(f, nc);
1.25      kristaps  804:        }
1.101     schwarze  805:        macro_line(f, "El");
                    806:        pnode_unlink(n);
1.25      kristaps  807: }
                    808:
                    809: static void
1.83      schwarze  810: pnode_printtgroup1(struct format *f, struct pnode *n)
1.16      kristaps  811: {
1.82      schwarze  812:        struct pnode    *nc;
                    813:
1.83      schwarze  814:        macro_line(f, "Bl -bullet -compact");
1.82      schwarze  815:        while ((nc = pnode_findfirst(n, NODE_ENTRY)) != NULL) {
1.83      schwarze  816:                macro_line(f, "It");
1.130     schwarze  817:                f->parastate = PARA_HAVE;
1.83      schwarze  818:                pnode_print(f, nc);
1.130     schwarze  819:                f->parastate = PARA_HAVE;
1.82      schwarze  820:                pnode_unlink(nc);
                    821:        }
1.83      schwarze  822:        macro_line(f, "El");
                    823:        pnode_unlinksub(n);
                    824: }
                    825:
                    826: static void
                    827: pnode_printtgroup2(struct format *f, struct pnode *n)
                    828: {
                    829:        struct pnode    *nr, *ne;
                    830:
1.130     schwarze  831:        f->parastate = PARA_HAVE;
1.83      schwarze  832:        macro_line(f, "Bl -tag -width Ds");
                    833:        while ((nr = pnode_findfirst(n, NODE_ROW)) != NULL) {
                    834:                if ((ne = pnode_findfirst(n, NODE_ENTRY)) == NULL)
                    835:                        break;
                    836:                macro_open(f, "It");
1.103     schwarze  837:                f->flags |= FMT_IMPL;
1.130     schwarze  838:                f->parastate = PARA_HAVE;
1.83      schwarze  839:                pnode_print(f, ne);
1.84      schwarze  840:                macro_close(f);
1.83      schwarze  841:                pnode_unlink(ne);
1.130     schwarze  842:                f->parastate = PARA_HAVE;
1.83      schwarze  843:                pnode_print(f, nr);
1.130     schwarze  844:                f->parastate = PARA_HAVE;
1.83      schwarze  845:                pnode_unlink(nr);
                    846:        }
                    847:        macro_line(f, "El");
1.135     schwarze  848:        f->parastate = PARA_WANT;
1.82      schwarze  849:        pnode_unlinksub(n);
                    850: }
                    851:
                    852: static void
1.83      schwarze  853: pnode_printtgroup(struct format *f, struct pnode *n)
1.82      schwarze  854: {
                    855:        struct pnode    *nc;
                    856:
                    857:        switch (atoi(pnode_getattr_raw(n, ATTRKEY_COLS, "0"))) {
                    858:        case 1:
1.83      schwarze  859:                pnode_printtgroup1(f, n);
                    860:                return;
                    861:        case 2:
                    862:                pnode_printtgroup2(f, n);
1.82      schwarze  863:                return;
                    864:        default:
                    865:                break;
                    866:        }
1.16      kristaps  867:
1.130     schwarze  868:        f->parastate = PARA_HAVE;
1.83      schwarze  869:        macro_line(f, "Bl -ohang");
1.82      schwarze  870:        while ((nc = pnode_findfirst(n, NODE_ROW)) != NULL) {
1.83      schwarze  871:                macro_line(f, "It Table Row");
                    872:                pnode_printrow(f, nc);
1.25      kristaps  873:        }
1.83      schwarze  874:        macro_line(f, "El");
1.135     schwarze  875:        f->parastate = PARA_WANT;
1.82      schwarze  876:        pnode_unlinksub(n);
1.25      kristaps  877: }
                    878:
                    879: static void
1.101     schwarze  880: pnode_printlist(struct format *f, struct pnode *n)
1.25      kristaps  881: {
1.101     schwarze  882:        struct pnode    *nc;
1.16      kristaps  883:
1.101     schwarze  884:        pnode_printtitle(f, n);
1.130     schwarze  885:        f->parastate = PARA_HAVE;
1.101     schwarze  886:        macro_argline(f, "Bl",
                    887:            n->node == NODE_ORDEREDLIST ? "-enum" : "-bullet");
                    888:        TAILQ_FOREACH(nc, &n->childq, child) {
                    889:                macro_line(f, "It");
1.130     schwarze  890:                f->parastate = PARA_HAVE;
1.101     schwarze  891:                pnode_print(f, nc);
1.130     schwarze  892:                f->parastate = PARA_HAVE;
1.16      kristaps  893:        }
1.101     schwarze  894:        macro_line(f, "El");
1.135     schwarze  895:        f->parastate = PARA_WANT;
1.101     schwarze  896:        pnode_unlinksub(n);
1.16      kristaps  897: }
                    898:
                    899: static void
1.101     schwarze  900: pnode_printvariablelist(struct format *f, struct pnode *n)
1.13      kristaps  901: {
1.101     schwarze  902:        struct pnode    *nc;
1.13      kristaps  903:
1.101     schwarze  904:        pnode_printtitle(f, n);
1.130     schwarze  905:        f->parastate = PARA_HAVE;
1.101     schwarze  906:        macro_line(f, "Bl -tag -width Ds");
                    907:        TAILQ_FOREACH(nc, &n->childq, child) {
                    908:                if (nc->node == NODE_VARLISTENTRY)
                    909:                        pnode_printvarlistentry(f, nc);
1.69      schwarze  910:                else
1.101     schwarze  911:                        macro_nodeline(f, "It", nc, 0);
1.69      schwarze  912:        }
1.101     schwarze  913:        macro_line(f, "El");
1.135     schwarze  914:        f->parastate = PARA_WANT;
1.101     schwarze  915:        pnode_unlinksub(n);
1.13      kristaps  916: }
                    917:
1.1       kristaps  918: /*
                    919:  * Print a parsed node (or ignore it--whatever).
                    920:  * This is a recursive function.
1.23      kristaps  921:  * FIXME: if we're in a literal context (<screen> or <programlisting> or
                    922:  * whatever), don't print inline macros.
1.1       kristaps  923:  */
                    924: static void
1.101     schwarze  925: pnode_print(struct format *f, struct pnode *n)
1.1       kristaps  926: {
1.102     schwarze  927:        struct pnode    *nc, *nn;
1.112     schwarze  928:        int              was_impl;
1.1       kristaps  929:
1.101     schwarze  930:        if (n == NULL)
1.1       kristaps  931:                return;
                    932:
1.146   ! schwarze  933:        if (f->nofill && n->flags & NFLAG_LINE)
        !           934:                macro_close(f);
        !           935:
1.112     schwarze  936:        was_impl = f->flags & FMT_IMPL;
1.138     schwarze  937:        if (n->flags & NFLAG_SPC)
1.103     schwarze  938:                f->flags &= ~FMT_NOSPC;
                    939:        else
                    940:                f->flags |= FMT_NOSPC;
1.1       kristaps  941:
1.101     schwarze  942:        switch (n->node) {
1.62      schwarze  943:        case NODE_ARG:
1.101     schwarze  944:                pnode_printarg(f, n);
1.4       kristaps  945:                break;
1.62      schwarze  946:        case NODE_AUTHOR:
1.101     schwarze  947:                pnode_printauthor(f, n);
1.50      schwarze  948:                break;
1.62      schwarze  949:        case NODE_AUTHORGROUP:
1.101     schwarze  950:                macro_line(f, "An -split");
1.50      schwarze  951:                break;
1.98      schwarze  952:        case NODE_BLOCKQUOTE:
1.130     schwarze  953:                f->parastate = PARA_HAVE;
1.101     schwarze  954:                macro_line(f, "Bd -ragged -offset indent");
1.130     schwarze  955:                f->parastate = PARA_HAVE;
1.98      schwarze  956:                break;
1.62      schwarze  957:        case NODE_CITEREFENTRY:
1.101     schwarze  958:                pnode_printciterefentry(f, n);
1.1       kristaps  959:                break;
1.68      schwarze  960:        case NODE_CITETITLE:
1.101     schwarze  961:                macro_open(f, "%T");
1.68      schwarze  962:                break;
1.62      schwarze  963:        case NODE_COMMAND:
1.101     schwarze  964:                macro_open(f, "Nm");
1.13      kristaps  965:                break;
1.62      schwarze  966:        case NODE_CONSTANT:
1.101     schwarze  967:                macro_open(f, "Dv");
1.33      kristaps  968:                break;
1.121     schwarze  969:        case NODE_COPYRIGHT:
                    970:                print_text(f, "Copyright", ARG_SPACE);
                    971:                fputs(" \\(co", stdout);
                    972:                break;
1.62      schwarze  973:        case NODE_EDITOR:
1.101     schwarze  974:                print_text(f, "editor:", ARG_SPACE);
1.121     schwarze  975:                pnode_printauthor(f, n);
1.50      schwarze  976:                break;
1.65      schwarze  977:        case NODE_EMAIL:
1.115     schwarze  978:                if (was_impl)
                    979:                        macro_open(f, "Ao Mt");
                    980:                else {
                    981:                        macro_open(f, "Aq Mt");
                    982:                        f->flags |= FMT_IMPL;
                    983:                }
1.65      schwarze  984:                break;
1.62      schwarze  985:        case NODE_EMPHASIS:
                    986:        case NODE_FIRSTTERM:
1.99      schwarze  987:        case NODE_GLOSSTERM:
1.123     schwarze  988:                if ((nc = TAILQ_FIRST(&n->childq)) != NULL &&
                    989:                    pnode_class(nc->node) < CLASS_LINE)
                    990:                        macro_open(f, "Em");
1.130     schwarze  991:                if (n->node == NODE_GLOSSTERM)
                    992:                        f->parastate = PARA_HAVE;
1.1       kristaps  993:                break;
1.62      schwarze  994:        case NODE_ENVAR:
1.101     schwarze  995:                macro_open(f, "Ev");
1.79      schwarze  996:                break;
1.90      schwarze  997:        case NODE_ERRORNAME:
1.101     schwarze  998:                macro_open(f, "Er");
1.90      schwarze  999:                break;
1.62      schwarze 1000:        case NODE_FILENAME:
1.101     schwarze 1001:                macro_open(f, "Pa");
1.17      kristaps 1002:                break;
1.125     schwarze 1003:        case NODE_FOOTNOTE:
                   1004:                macro_line(f, "Bo");
1.130     schwarze 1005:                f->parastate = PARA_HAVE;
1.125     schwarze 1006:                break;
1.62      schwarze 1007:        case NODE_FUNCTION:
1.101     schwarze 1008:                macro_open(f, "Fn");
1.3       kristaps 1009:                break;
1.62      schwarze 1010:        case NODE_FUNCPROTOTYPE:
1.101     schwarze 1011:                pnode_printfuncprototype(f, n);
1.3       kristaps 1012:                break;
1.62      schwarze 1013:        case NODE_FUNCSYNOPSISINFO:
1.101     schwarze 1014:                macro_open(f, "Fd");
1.126     schwarze 1015:                break;
                   1016:        case NODE_IMAGEDATA:
                   1017:                pnode_printimagedata(f, n);
1.16      kristaps 1018:                break;
1.62      schwarze 1019:        case NODE_INFORMALEQUATION:
1.130     schwarze 1020:                f->parastate = PARA_HAVE;
1.111     schwarze 1021:                macro_line(f, "Bd -ragged -offset indent");
1.130     schwarze 1022:                f->parastate = PARA_HAVE;
1.111     schwarze 1023:                /* FALLTHROUGH */
                   1024:        case NODE_INLINEEQUATION:
1.101     schwarze 1025:                macro_line(f, "EQ");
1.43      kristaps 1026:                break;
1.62      schwarze 1027:        case NODE_ITEMIZEDLIST:
1.101     schwarze 1028:                pnode_printlist(f, n);
1.24      kristaps 1029:                break;
1.62      schwarze 1030:        case NODE_GROUP:
1.101     schwarze 1031:                pnode_printgroup(f, n);
1.10      kristaps 1032:                break;
1.67      schwarze 1033:        case NODE_KEYSYM:
1.131     schwarze 1034:        case NODE_PRODUCTNAME:
1.101     schwarze 1035:                macro_open(f, "Sy");
1.67      schwarze 1036:                break;
1.62      schwarze 1037:        case NODE_LINK:
1.101     schwarze 1038:                pnode_printlink(f, n);
1.96      schwarze 1039:                break;
1.62      schwarze 1040:        case NODE_LITERAL:
1.122     schwarze 1041:                if (n->parent != NULL && n->parent->node == NODE_QUOTE)
                   1042:                        macro_open(f, "Li");
                   1043:                else if (was_impl)
                   1044:                        macro_open(f, "So Li");
1.112     schwarze 1045:                else {
                   1046:                        macro_open(f, "Ql");
                   1047:                        f->flags |= FMT_IMPL;
                   1048:                }
1.19      kristaps 1049:                break;
1.62      schwarze 1050:        case NODE_LITERALLAYOUT:
1.101     schwarze 1051:                macro_close(f);
1.130     schwarze 1052:                f->parastate = PARA_HAVE;
1.101     schwarze 1053:                macro_argline(f, "Bd", pnode_getattr(n, ATTRKEY_CLASS) ==
1.66      schwarze 1054:                    ATTRVAL_MONOSPACED ? "-literal" : "-unfilled");
1.130     schwarze 1055:                f->parastate = PARA_HAVE;
1.60      schwarze 1056:                break;
1.106     schwarze 1057:        case NODE_MARKUP:
                   1058:                macro_open(f, "Ic");
                   1059:                break;
1.62      schwarze 1060:        case NODE_MML_MFENCED:
1.101     schwarze 1061:                pnode_printmathfenced(f, n);
1.40      kristaps 1062:                break;
1.62      schwarze 1063:        case NODE_MML_MROW:
                   1064:        case NODE_MML_MI:
                   1065:        case NODE_MML_MN:
                   1066:        case NODE_MML_MO:
1.101     schwarze 1067:                if (TAILQ_EMPTY(&n->childq))
1.43      kristaps 1068:                        break;
                   1069:                fputs(" { ", stdout);
1.40      kristaps 1070:                break;
1.62      schwarze 1071:        case NODE_MML_MFRAC:
                   1072:        case NODE_MML_MSUB:
                   1073:        case NODE_MML_MSUP:
1.101     schwarze 1074:                pnode_printmath(f, n);
1.128     schwarze 1075:                break;
                   1076:        case NODE_OLINK:
                   1077:                pnode_printolink(f, n);
1.40      kristaps 1078:                break;
1.62      schwarze 1079:        case NODE_OPTION:
1.123     schwarze 1080:                if ((nc = TAILQ_FIRST(&n->childq)) != NULL &&
                   1081:                    pnode_class(nc->node) < CLASS_LINE)
                   1082:                        macro_open(f, "Fl");
1.1       kristaps 1083:                break;
1.62      schwarze 1084:        case NODE_ORDEREDLIST:
1.101     schwarze 1085:                pnode_printlist(f, n);
1.25      kristaps 1086:                break;
1.62      schwarze 1087:        case NODE_PARA:
1.130     schwarze 1088:                if (f->parastate == PARA_MID)
                   1089:                        f->parastate = PARA_WANT;
1.3       kristaps 1090:                break;
1.87      schwarze 1091:        case NODE_PARAMDEF:
1.62      schwarze 1092:        case NODE_PARAMETER:
1.104     schwarze 1093:                /* More often, these appear inside NODE_FUNCPROTOTYPE. */
                   1094:                macro_open(f, "Fa");
                   1095:                macro_addnode(f, n, ARG_SPACE | ARG_SINGLE);
1.101     schwarze 1096:                pnode_unlinksub(n);
1.1       kristaps 1097:                break;
1.62      schwarze 1098:        case NODE_QUOTE:
1.127     schwarze 1099:                if ((nc = TAILQ_FIRST(&n->childq)) != NULL &&
                   1100:                    nc->node == NODE_FILENAME &&
                   1101:                    TAILQ_NEXT(nc, child) == NULL) {
1.138     schwarze 1102:                        if (n->flags & NFLAG_SPC)
                   1103:                                nc->flags |= NFLAG_SPC;
1.127     schwarze 1104:                } else if (was_impl)
1.112     schwarze 1105:                        macro_open(f, "Do");
                   1106:                else {
                   1107:                        macro_open(f, "Dq");
                   1108:                        f->flags |= FMT_IMPL;
                   1109:                }
1.28      kristaps 1110:                break;
1.62      schwarze 1111:        case NODE_PROGRAMLISTING:
                   1112:        case NODE_SCREEN:
1.88      schwarze 1113:        case NODE_SYNOPSIS:
1.130     schwarze 1114:                f->parastate = PARA_HAVE;
1.101     schwarze 1115:                macro_line(f, "Bd -literal");
1.130     schwarze 1116:                f->parastate = PARA_HAVE;
1.118     schwarze 1117:                break;
                   1118:        case NODE_SYSTEMITEM:
                   1119:                pnode_printsystemitem(f, n);
1.15      kristaps 1120:                break;
1.62      schwarze 1121:        case NODE_REFNAME:
1.110     schwarze 1122:                /* More often, these appear inside NODE_REFNAMEDIV. */
1.101     schwarze 1123:                macro_open(f, "Nm");
1.10      kristaps 1124:                break;
1.62      schwarze 1125:        case NODE_REFNAMEDIV:
1.110     schwarze 1126:                pnode_printrefnamediv(f, n);
1.1       kristaps 1127:                break;
1.62      schwarze 1128:        case NODE_REFPURPOSE:
1.101     schwarze 1129:                macro_open(f, "Nd");
1.10      kristaps 1130:                break;
1.62      schwarze 1131:        case NODE_REFSYNOPSISDIV:
1.101     schwarze 1132:                pnode_printrefsynopsisdiv(f, n);
1.1       kristaps 1133:                break;
1.62      schwarze 1134:        case NODE_SECTION:
1.121     schwarze 1135:        case NODE_SIMPLESECT:
1.100     schwarze 1136:        case NODE_APPENDIX:
1.62      schwarze 1137:        case NODE_NOTE:
1.119     schwarze 1138:                pnode_printsection(f, n);
1.1       kristaps 1139:                break;
1.62      schwarze 1140:        case NODE_REPLACEABLE:
1.101     schwarze 1141:                macro_open(f, "Ar");
1.13      kristaps 1142:                break;
1.62      schwarze 1143:        case NODE_SBR:
1.130     schwarze 1144:                if (f->parastate == PARA_MID)
                   1145:                        macro_line(f, "br");
1.124     schwarze 1146:                break;
                   1147:        case NODE_SUBSCRIPT:
                   1148:                if (f->linestate == LINE_MACRO)
                   1149:                        macro_addarg(f, "_", 0);
                   1150:                else
                   1151:                        print_text(f, "_", 0);
                   1152:                if ((nc = TAILQ_FIRST(&n->childq)) != NULL)
1.138     schwarze 1153:                        nc->flags &= ~(NFLAG_LINE | NFLAG_SPC);
1.124     schwarze 1154:                break;
                   1155:        case NODE_SUPERSCRIPT:
                   1156:                fputs("\\(ha", stdout);
                   1157:                if ((nc = TAILQ_FIRST(&n->childq)) != NULL)
1.138     schwarze 1158:                        nc->flags &= ~(NFLAG_LINE | NFLAG_SPC);
1.25      kristaps 1159:                break;
1.62      schwarze 1160:        case NODE_TEXT:
1.93      schwarze 1161:        case NODE_ESCAPE:
1.101     schwarze 1162:                pnode_printtext(f, n);
1.1       kristaps 1163:                break;
1.82      schwarze 1164:        case NODE_TGROUP:
1.101     schwarze 1165:                pnode_printtgroup(f, n);
1.82      schwarze 1166:                break;
1.62      schwarze 1167:        case NODE_TITLE:
1.121     schwarze 1168:        case NODE_SUBTITLE:
1.130     schwarze 1169:                if (f->parastate == PARA_MID)
                   1170:                        f->parastate = PARA_WANT;
1.101     schwarze 1171:                macro_nodeline(f, "Sy", n, 0);
                   1172:                pnode_unlinksub(n);
1.50      schwarze 1173:                break;
1.62      schwarze 1174:        case NODE_TYPE:
1.101     schwarze 1175:                macro_open(f, "Vt");
1.39      kristaps 1176:                break;
1.62      schwarze 1177:        case NODE_VARIABLELIST:
1.101     schwarze 1178:                pnode_printvariablelist(f, n);
1.13      kristaps 1179:                break;
1.62      schwarze 1180:        case NODE_VARNAME:
1.101     schwarze 1181:                macro_open(f, "Va");
1.132     schwarze 1182:                break;
                   1183:        case NODE_VOID:
                   1184:                print_text(f, "void", ARG_SPACE);
1.129     schwarze 1185:                break;
                   1186:        case NODE_XREF:
                   1187:                pnode_printxref(f, n);
1.23      kristaps 1188:                break;
1.142     schwarze 1189:        case NODE_CAUTION:
                   1190:        case NODE_LEGALNOTICE:
                   1191:        case NODE_PREFACE:
                   1192:        case NODE_TIP:
                   1193:        case NODE_WARNING:
                   1194:                abort();
1.1       kristaps 1195:        default:
                   1196:                break;
                   1197:        }
                   1198:
1.146   ! schwarze 1199:        if (pnode_class(n->node) == CLASS_NOFILL)
        !          1200:                f->nofill++;
        !          1201:
1.102     schwarze 1202:        TAILQ_FOREACH(nc, &n->childq, child)
                   1203:                pnode_print(f, nc);
1.1       kristaps 1204:
1.101     schwarze 1205:        switch (n->node) {
1.115     schwarze 1206:        case NODE_EMAIL:
                   1207:                if (was_impl) {
                   1208:                        f->flags &= ~FMT_NOSPC;
                   1209:                        macro_open(f, "Ac");
                   1210:                } else
                   1211:                        f->flags &= ~FMT_IMPL;
                   1212:                break;
1.103     schwarze 1213:        case NODE_ESCAPE:
                   1214:        case NODE_TERM:
                   1215:        case NODE_TEXT:
                   1216:                /* Accept more arguments to the previous macro. */
                   1217:                return;
1.125     schwarze 1218:        case NODE_FOOTNOTE:
1.130     schwarze 1219:                f->parastate = PARA_HAVE;
1.125     schwarze 1220:                macro_line(f, "Bc");
                   1221:                break;
1.130     schwarze 1222:        case NODE_GLOSSTERM:
                   1223:                f->parastate = PARA_HAVE;
                   1224:                break;
1.62      schwarze 1225:        case NODE_INFORMALEQUATION:
1.101     schwarze 1226:                macro_line(f, "EN");
1.111     schwarze 1227:                macro_line(f, "Ed");
1.40      kristaps 1228:                break;
1.62      schwarze 1229:        case NODE_INLINEEQUATION:
1.111     schwarze 1230:                macro_line(f, "EN");
1.43      kristaps 1231:                break;
1.112     schwarze 1232:        case NODE_LITERAL:
1.122     schwarze 1233:                if (n->parent != NULL && n->parent->node == NODE_QUOTE)
                   1234:                        /* nothing */;
                   1235:                else if (was_impl) {
1.115     schwarze 1236:                        f->flags &= ~FMT_NOSPC;
1.112     schwarze 1237:                        macro_open(f, "Sc");
1.115     schwarze 1238:                } else
1.112     schwarze 1239:                        f->flags &= ~FMT_IMPL;
                   1240:                break;
1.91      schwarze 1241:        case NODE_MEMBER:
1.102     schwarze 1242:                if ((nn = TAILQ_NEXT(n, child)) != NULL &&
                   1243:                    nn->node != NODE_MEMBER)
                   1244:                        nn = NULL;
1.101     schwarze 1245:                switch (f->linestate) {
1.91      schwarze 1246:                case LINE_TEXT:
1.102     schwarze 1247:                        if (nn != NULL)
1.101     schwarze 1248:                                print_text(f, ",", 0);
1.91      schwarze 1249:                        break;
                   1250:                case LINE_MACRO:
1.102     schwarze 1251:                        if (nn != NULL)
1.101     schwarze 1252:                                macro_addarg(f, ",", ARG_SPACE);
                   1253:                        macro_close(f);
1.91      schwarze 1254:                        break;
                   1255:                case LINE_NEW:
                   1256:                        break;
                   1257:                }
                   1258:                break;
1.62      schwarze 1259:        case NODE_MML_MROW:
                   1260:        case NODE_MML_MI:
                   1261:        case NODE_MML_MN:
                   1262:        case NODE_MML_MO:
1.101     schwarze 1263:                if (TAILQ_EMPTY(&n->childq))
1.43      kristaps 1264:                        break;
                   1265:                fputs(" } ", stdout);
1.40      kristaps 1266:                break;
1.130     schwarze 1267:        case NODE_PARA:
                   1268:                if (f->parastate == PARA_MID)
                   1269:                        f->parastate = PARA_WANT;
                   1270:                break;
1.62      schwarze 1271:        case NODE_QUOTE:
1.127     schwarze 1272:                if ((nc = TAILQ_FIRST(&n->childq)) != NULL &&
                   1273:                    nc->node == NODE_FILENAME &&
                   1274:                    TAILQ_NEXT(nc, child) == NULL)
                   1275:                        /* nothing */;
                   1276:                else if (was_impl) {
1.115     schwarze 1277:                        f->flags &= ~FMT_NOSPC;
1.112     schwarze 1278:                        macro_open(f, "Dc");
1.115     schwarze 1279:                } else
1.112     schwarze 1280:                        f->flags &= ~FMT_IMPL;
1.52      schwarze 1281:                break;
1.62      schwarze 1282:        case NODE_SECTION:
1.142     schwarze 1283:        case NODE_SIMPLESECT:
1.100     schwarze 1284:        case NODE_APPENDIX:
1.62      schwarze 1285:        case NODE_NOTE:
1.143     schwarze 1286:                if (n->parent != NULL)
                   1287:                        f->level--;
1.12      kristaps 1288:                break;
1.98      schwarze 1289:        case NODE_BLOCKQUOTE:
1.62      schwarze 1290:        case NODE_LITERALLAYOUT:
                   1291:        case NODE_PROGRAMLISTING:
                   1292:        case NODE_SCREEN:
1.88      schwarze 1293:        case NODE_SYNOPSIS:
1.130     schwarze 1294:                f->parastate = PARA_HAVE;
1.101     schwarze 1295:                macro_line(f, "Ed");
1.135     schwarze 1296:                f->parastate = PARA_WANT;
1.50      schwarze 1297:                break;
1.130     schwarze 1298:        case NODE_TITLE:
                   1299:        case NODE_SUBTITLE:
                   1300:                f->parastate = PARA_WANT;
                   1301:                break;
1.144     schwarze 1302:        case NODE_YEAR:
                   1303:                if ((nn = TAILQ_NEXT(n, child)) != NULL &&
                   1304:                    nn->node == NODE_YEAR &&
                   1305:                    f->linestate == LINE_TEXT) {
                   1306:                        print_text(f, ",", 0);
                   1307:                        nn->flags |= NFLAG_SPC;
                   1308:                        if ((nc = TAILQ_FIRST(&nn->childq)) != NULL)
                   1309:                                nc->flags |= NFLAG_SPC;
                   1310:                }
1.1       kristaps 1311:        default:
                   1312:                break;
                   1313:        }
1.103     schwarze 1314:        f->flags &= ~FMT_ARG;
1.146   ! schwarze 1315:        if (pnode_class(n->node) == CLASS_NOFILL)
        !          1316:                f->nofill--;
1.1       kristaps 1317: }
                   1318:
1.74      schwarze 1319: void
1.114     schwarze 1320: ptree_print_mdoc(struct ptree *tree)
1.74      schwarze 1321: {
                   1322:        struct format    formatter;
1.1       kristaps 1323:
1.146   ! schwarze 1324:        formatter.level = formatter.nofill = 0;
1.74      schwarze 1325:        formatter.linestate = LINE_NEW;
1.130     schwarze 1326:        formatter.parastate = PARA_HAVE;
1.116     schwarze 1327:        pnode_printprologue(&formatter, tree->root);
1.74      schwarze 1328:        pnode_print(&formatter, tree->root);
                   1329:        if (formatter.linestate != LINE_NEW)
                   1330:                putchar('\n');
1.1       kristaps 1331: }

CVSweb