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

Annotation of docbook2mdoc/macro.c, Revision 1.17

1.17    ! schwarze    1: /* $Id: macro.c,v 1.16 2019/04/24 18:38:02 schwarze Exp $ */
1.1       schwarze    2: /*
                      3:  * Copyright (c) 2019 Ingo Schwarze <schwarze@openbsd.org>
                      4:  *
                      5:  * Permission to use, copy, modify, and distribute this software for any
                      6:  * purpose with or without fee is hereby granted, provided that the above
                      7:  * copyright notice and this permission notice appear in all copies.
                      8:  *
                      9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
                     10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
                     12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     16:  */
                     17: #include <assert.h>
                     18: #include <ctype.h>
                     19: #include <stdio.h>
1.6       schwarze   20: #include <string.h>
1.1       schwarze   21:
                     22: #include "node.h"
                     23: #include "macro.h"
                     24:
                     25: /*
                     26:  * The implementation of the macro line formatter,
                     27:  * a part of the mdoc(7) formatter.
                     28:  */
                     29:
                     30: void
                     31: macro_open(struct format *f, const char *name)
                     32: {
1.14      schwarze   33:        if (f->parastate == PARA_WANT) {
                     34:                if (f->linestate != LINE_NEW) {
                     35:                        putchar('\n');
                     36:                        f->linestate = LINE_NEW;
                     37:                }
                     38:                puts(".Pp");
                     39:        }
1.1       schwarze   40:        switch (f->linestate) {
1.9       schwarze   41:        case LINE_MACRO:
                     42:                if (f->flags & FMT_NOSPC) {
                     43:                        fputs(" Ns ", stdout);
                     44:                        break;
                     45:                }
                     46:                if (f->flags & (FMT_CHILD | FMT_IMPL)) {
                     47:                        putchar(' ');
                     48:                        break;
                     49:                }
                     50:                /* FALLTHROUGH */
1.1       schwarze   51:        case LINE_TEXT:
1.17    ! schwarze   52:                if (f->nofill)
        !            53:                        fputs(" \\c", stdout);
1.1       schwarze   54:                putchar('\n');
                     55:                /* FALLTHROUGH */
                     56:        case LINE_NEW:
                     57:                putchar('.');
                     58:                f->linestate = LINE_MACRO;
1.9       schwarze   59:                f->flags = 0;
1.1       schwarze   60:                break;
                     61:        }
                     62:        fputs(name, stdout);
1.9       schwarze   63:        f->flags &= FMT_IMPL;
                     64:        f->flags |= FMT_ARG;
1.14      schwarze   65:        f->parastate = PARA_MID;
1.1       schwarze   66: }
                     67:
                     68: void
                     69: macro_close(struct format *f)
                     70: {
1.9       schwarze   71:        if (f->linestate != LINE_NEW)
                     72:                putchar('\n');
1.1       schwarze   73:        f->linestate = LINE_NEW;
1.9       schwarze   74:        f->flags = 0;
1.1       schwarze   75: }
                     76:
                     77: void
                     78: macro_line(struct format *f, const char *name)
                     79: {
1.7       schwarze   80:        macro_close(f);
1.1       schwarze   81:        macro_open(f, name);
                     82:        macro_close(f);
                     83: }
                     84:
                     85: /*
                     86:  * Print an argument string on a macro line, collapsing whitespace.
                     87:  */
                     88: void
                     89: macro_addarg(struct format *f, const char *arg, int flags)
                     90: {
                     91:        const char      *cp;
1.13      schwarze   92:        int              quote_now;
1.1       schwarze   93:
                     94:        assert(f->linestate == LINE_MACRO);
                     95:
                     96:        /* Quote if requested and necessary. */
                     97:
1.13      schwarze   98:        quote_now = 0;
1.1       schwarze   99:        if ((flags & (ARG_SINGLE | ARG_QUOTED)) == ARG_SINGLE) {
                    100:                for (cp = arg; *cp != '\0'; cp++)
                    101:                        if (isspace((unsigned char)*cp))
                    102:                                break;
                    103:                if (*cp != '\0') {
                    104:                        if (flags & ARG_SPACE) {
                    105:                                putchar(' ');
                    106:                                flags &= ~ ARG_SPACE;
                    107:                        }
                    108:                        putchar('"');
                    109:                        flags = ARG_QUOTED;
1.13      schwarze  110:                        quote_now = 1;
1.1       schwarze  111:                }
                    112:        }
                    113:
                    114:        for (cp = arg; *cp != '\0'; cp++) {
                    115:
                    116:                /* Collapse whitespace. */
                    117:
                    118:                if (isspace((unsigned char)*cp)) {
                    119:                        flags |= ARG_SPACE;
                    120:                        continue;
                    121:                } else if (flags & ARG_SPACE) {
                    122:                        putchar(' ');
                    123:                        flags &= ~ ARG_SPACE;
                    124:                }
                    125:
                    126:                /* Escape us if we look like a macro. */
                    127:
1.12      schwarze  128:                if ((flags & (ARG_QUOTED | ARG_UPPER)) == 0 &&
1.1       schwarze  129:                    (cp == arg || isspace((unsigned char)cp[-1])) &&
                    130:                    isupper((unsigned char)cp[0]) &&
                    131:                    islower((unsigned char)cp[1]) &&
                    132:                    (cp[2] == '\0' || cp[2] == ' ' ||
1.12      schwarze  133:                     ((cp[3] == '\0' || cp[3] == ' ') &&
                    134:                      (strncmp(cp, "Brq", 3) == 0 ||
                    135:                       strncmp(cp, "Bro", 3) == 0 ||
                    136:                       strncmp(cp, "Brc", 3) == 0 ||
                    137:                       strncmp(cp, "Bsx", 3) == 0))))
1.1       schwarze  138:                        fputs("\\&", stdout);
                    139:
                    140:                if (*cp == '"')
                    141:                        fputs("\\(dq", stdout);
                    142:                else if (flags & ARG_UPPER)
                    143:                        putchar(toupper((unsigned char)*cp));
                    144:                else
                    145:                        putchar(*cp);
                    146:                if (*cp == '\\')
                    147:                        putchar('e');
                    148:        }
1.13      schwarze  149:        if (quote_now)
                    150:                putchar('"');
1.14      schwarze  151:        f->parastate = PARA_MID;
1.1       schwarze  152: }
                    153:
                    154: void
                    155: macro_argline(struct format *f, const char *name, const char *arg)
                    156: {
                    157:        macro_open(f, name);
                    158:        macro_addarg(f, arg, ARG_SPACE);
                    159:        macro_close(f);
                    160: }
                    161:
                    162: /*
                    163:  * Recursively append text from the children of a node to a macro line.
                    164:  */
                    165: void
1.8       schwarze  166: macro_addnode(struct format *f, struct pnode *n, int flags)
1.1       schwarze  167: {
1.5       schwarze  168:        struct pnode    *nc;
1.15      schwarze  169:        int              is_text, quote_now;
1.1       schwarze  170:
                    171:        assert(f->linestate == LINE_MACRO);
                    172:
                    173:        /*
1.2       schwarze  174:         * If this node or its only child is a text node, just add
                    175:         * that text, letting macro_addarg() decide about quoting.
1.1       schwarze  176:         */
                    177:
1.8       schwarze  178:        while ((nc = TAILQ_FIRST(&n->childq)) != NULL &&
1.5       schwarze  179:            TAILQ_NEXT(nc, child) == NULL)
1.8       schwarze  180:                n = nc;
1.5       schwarze  181:
1.8       schwarze  182:        if (n->node == NODE_TEXT || n->node == NODE_ESCAPE) {
                    183:                macro_addarg(f, n->b, flags);
1.14      schwarze  184:                f->parastate = PARA_MID;
1.1       schwarze  185:                return;
                    186:        }
                    187:
                    188:        /*
                    189:         * If we want the argument quoted and are not already
                    190:         * in a quoted context, quote now.
                    191:         */
                    192:
                    193:        quote_now = 0;
                    194:        if (flags & ARG_SINGLE) {
                    195:                if ((flags & ARG_QUOTED) == 0) {
                    196:                        if (flags & ARG_SPACE) {
                    197:                                putchar(' ');
                    198:                                flags &= ~ARG_SPACE;
                    199:                        }
                    200:                        putchar('"');
                    201:                        flags |= ARG_QUOTED;
                    202:                        quote_now = 1;
                    203:                }
                    204:                flags &= ~ARG_SINGLE;
                    205:        }
                    206:
                    207:        /*
                    208:         * Iterate to child and sibling nodes,
                    209:         * inserting whitespace between nodes.
                    210:         */
                    211:
1.5       schwarze  212:        while (nc != NULL) {
                    213:                macro_addnode(f, nc, flags);
1.15      schwarze  214:                is_text = pnode_class(nc->node) == CLASS_TEXT;
1.5       schwarze  215:                nc = TAILQ_NEXT(nc, child);
1.15      schwarze  216:                if (nc == NULL || pnode_class(nc->node) != CLASS_TEXT)
                    217:                        is_text = 0;
1.16      schwarze  218:                if (is_text && (nc->flags & NFLAG_SPC) == 0)
1.15      schwarze  219:                        flags &= ~ARG_SPACE;
                    220:                else
                    221:                        flags |= ARG_SPACE;
1.1       schwarze  222:        }
                    223:        if (quote_now)
                    224:                putchar('"');
1.14      schwarze  225:        f->parastate = PARA_MID;
1.1       schwarze  226: }
                    227:
                    228: void
1.8       schwarze  229: macro_nodeline(struct format *f, const char *name, struct pnode *n, int flags)
1.1       schwarze  230: {
                    231:        macro_open(f, name);
1.8       schwarze  232:        macro_addnode(f, n, ARG_SPACE | flags);
1.1       schwarze  233:        macro_close(f);
1.2       schwarze  234: }
                    235:
                    236:
                    237: /*
                    238:  * Print a word on the current text line if one is open, or on a new text
                    239:  * line otherwise.  The flag ARG_SPACE inserts spaces between words.
                    240:  */
                    241: void
1.10      schwarze  242: print_text(struct format *f, const char *word, int flags)
                    243: {
1.14      schwarze  244:        if (f->parastate == PARA_WANT) {
                    245:                if (f->linestate != LINE_NEW) {
                    246:                        putchar('\n');
                    247:                        f->linestate = LINE_NEW;
                    248:                }
                    249:                puts(".Pp");
                    250:        }
1.2       schwarze  251:        switch (f->linestate) {
                    252:        case LINE_NEW:
                    253:                break;
                    254:        case LINE_TEXT:
                    255:                if (flags & ARG_SPACE)
                    256:                        putchar(' ');
                    257:                break;
                    258:        case LINE_MACRO:
                    259:                macro_close(f);
                    260:                break;
                    261:        }
1.11      schwarze  262:        if (f->linestate == LINE_NEW && (*word == '.' || *word == '\''))
                    263:                fputs("\\&", stdout);
1.10      schwarze  264:        while (*word != '\0') {
                    265:                putchar(*word);
                    266:                if (*word++ == '\\')
                    267:                        putchar('e');
                    268:        }
1.2       schwarze  269:        f->linestate = LINE_TEXT;
1.14      schwarze  270:        f->parastate = PARA_MID;
1.9       schwarze  271:        f->flags = 0;
1.2       schwarze  272: }
                    273:
                    274: /*
                    275:  * Recursively print the content of a node on a text line.
                    276:  */
                    277: void
                    278: print_textnode(struct format *f, struct pnode *n)
                    279: {
                    280:        struct pnode    *nc;
                    281:
1.3       schwarze  282:        if (n->node == NODE_TEXT || n->node == NODE_ESCAPE)
1.2       schwarze  283:                print_text(f, n->b, ARG_SPACE);
                    284:        else
                    285:                TAILQ_FOREACH(nc, &n->childq, child)
                    286:                        print_textnode(f, nc);
1.1       schwarze  287: }

CVSweb