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

Annotation of docbook2mdoc/docbook2mdoc.c, Revision 1.148

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

CVSweb