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

Annotation of docbook2mdoc/macro.c, Revision 1.4

1.4     ! schwarze    1: /* $Id: macro.c,v 1.3 2019/04/02 15:53: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>
                     20:
                     21: #include "node.h"
                     22: #include "macro.h"
                     23:
                     24: /*
                     25:  * The implementation of the macro line formatter,
                     26:  * a part of the mdoc(7) formatter.
                     27:  */
                     28:
                     29: void
                     30: macro_open(struct format *f, const char *name)
                     31: {
                     32:        switch (f->linestate) {
                     33:        case LINE_TEXT:
                     34:                putchar('\n');
                     35:                /* FALLTHROUGH */
                     36:        case LINE_NEW:
                     37:                putchar('.');
                     38:                f->linestate = LINE_MACRO;
                     39:                break;
                     40:        case LINE_MACRO:
                     41:                putchar(' ');
                     42:                break;
                     43:        }
                     44:        fputs(name, stdout);
                     45: }
                     46:
                     47: void
                     48: macro_close(struct format *f)
                     49: {
1.4     ! schwarze   50:        if (f->linestate == LINE_NEW)
        !            51:                return;
1.1       schwarze   52:        putchar('\n');
                     53:        f->linestate = LINE_NEW;
                     54: }
                     55:
                     56: void
                     57: macro_line(struct format *f, const char *name)
                     58: {
                     59:        macro_open(f, name);
                     60:        macro_close(f);
                     61: }
                     62:
                     63: /*
                     64:  * If the next node is a text node starting with closing punctuation,
                     65:  * emit the closing punctuation as a trailing macro argument.
                     66:  */
                     67: void
                     68: macro_closepunct(struct format *f, struct pnode *pn)
                     69: {
                     70:        if ((pn = TAILQ_NEXT(pn, child)) != NULL &&
                     71:            pn->node == NODE_TEXT && pn->bsz > 0 &&
                     72:            (pn->b[0] == ',' || pn->b[0] == '.') &&
                     73:            (pn->bsz == 1 || isspace((unsigned char)pn->b[1]))) {
                     74:                putchar(' ');
                     75:                putchar(pn->b[0]);
                     76:                pn->b++;
                     77:                pn->bsz--;
                     78:        }
                     79:        macro_close(f);
                     80: }
                     81:
                     82: /*
                     83:  * Print an argument string on a macro line, collapsing whitespace.
                     84:  */
                     85: void
                     86: macro_addarg(struct format *f, const char *arg, int flags)
                     87: {
                     88:        const char      *cp;
                     89:
                     90:        assert(f->linestate == LINE_MACRO);
                     91:
                     92:        /* Quote if requested and necessary. */
                     93:
                     94:        if ((flags & (ARG_SINGLE | ARG_QUOTED)) == ARG_SINGLE) {
                     95:                for (cp = arg; *cp != '\0'; cp++)
                     96:                        if (isspace((unsigned char)*cp))
                     97:                                break;
                     98:                if (*cp != '\0') {
                     99:                        if (flags & ARG_SPACE) {
                    100:                                putchar(' ');
                    101:                                flags &= ~ ARG_SPACE;
                    102:                        }
                    103:                        putchar('"');
                    104:                        flags = ARG_QUOTED;
                    105:                }
                    106:        }
                    107:
                    108:        for (cp = arg; *cp != '\0'; cp++) {
                    109:
                    110:                /* Collapse whitespace. */
                    111:
                    112:                if (isspace((unsigned char)*cp)) {
                    113:                        flags |= ARG_SPACE;
                    114:                        continue;
                    115:                } else if (flags & ARG_SPACE) {
                    116:                        putchar(' ');
                    117:                        flags &= ~ ARG_SPACE;
                    118:                }
                    119:
                    120:                /* Escape us if we look like a macro. */
                    121:
                    122:                if ((flags & ARG_QUOTED) == 0 &&
                    123:                    (cp == arg || isspace((unsigned char)cp[-1])) &&
                    124:                    isupper((unsigned char)cp[0]) &&
                    125:                    islower((unsigned char)cp[1]) &&
                    126:                    (cp[2] == '\0' || cp[2] == ' ' ||
                    127:                     (islower((unsigned char)cp[2]) &&
                    128:                      (cp[3] == '\0' || cp[3] == ' '))))
                    129:                        fputs("\\&", stdout);
                    130:
                    131:                if (*cp == '"')
                    132:                        fputs("\\(dq", stdout);
                    133:                else if (flags & ARG_UPPER)
                    134:                        putchar(toupper((unsigned char)*cp));
                    135:                else
                    136:                        putchar(*cp);
                    137:                if (*cp == '\\')
                    138:                        putchar('e');
                    139:        }
                    140: }
                    141:
                    142: void
                    143: macro_argline(struct format *f, const char *name, const char *arg)
                    144: {
                    145:        macro_open(f, name);
                    146:        macro_addarg(f, arg, ARG_SPACE);
                    147:        macro_close(f);
                    148: }
                    149:
                    150: /*
                    151:  * Recursively append text from the children of a node to a macro line.
                    152:  */
                    153: void
                    154: macro_addnode(struct format *f, struct pnode *pn, int flags)
                    155: {
                    156:        int              quote_now;
                    157:
                    158:        assert(f->linestate == LINE_MACRO);
                    159:
                    160:        /*
1.2       schwarze  161:         * If this node or its only child is a text node, just add
                    162:         * that text, letting macro_addarg() decide about quoting.
1.1       schwarze  163:         */
                    164:
1.3       schwarze  165:        if (pn->node == NODE_TEXT || pn->node == NODE_ESCAPE ||
1.2       schwarze  166:            ((pn = TAILQ_FIRST(&pn->childq)) != NULL &&
1.3       schwarze  167:             (pn->node == NODE_TEXT || pn->node == NODE_ESCAPE) &&
                    168:             TAILQ_NEXT(pn, child) == NULL)) {
1.1       schwarze  169:                macro_addarg(f, pn->b, flags);
                    170:                return;
                    171:        }
                    172:
                    173:        /*
                    174:         * If we want the argument quoted and are not already
                    175:         * in a quoted context, quote now.
                    176:         */
                    177:
                    178:        quote_now = 0;
                    179:        if (flags & ARG_SINGLE) {
                    180:                if ((flags & ARG_QUOTED) == 0) {
                    181:                        if (flags & ARG_SPACE) {
                    182:                                putchar(' ');
                    183:                                flags &= ~ARG_SPACE;
                    184:                        }
                    185:                        putchar('"');
                    186:                        flags |= ARG_QUOTED;
                    187:                        quote_now = 1;
                    188:                }
                    189:                flags &= ~ARG_SINGLE;
                    190:        }
                    191:
                    192:        /*
                    193:         * Iterate to child and sibling nodes,
                    194:         * inserting whitespace between nodes.
                    195:         */
                    196:
                    197:        while (pn != NULL) {
1.2       schwarze  198:                macro_addnode(f, pn, flags);
1.1       schwarze  199:                pn = TAILQ_NEXT(pn, child);
                    200:                flags |= ARG_SPACE;
                    201:        }
                    202:        if (quote_now)
                    203:                putchar('"');
                    204: }
                    205:
                    206: void
                    207: macro_nodeline(struct format *f, const char *name, struct pnode *pn, int flags)
                    208: {
                    209:        macro_open(f, name);
                    210:        macro_addnode(f, pn, ARG_SPACE | flags);
                    211:        macro_close(f);
1.2       schwarze  212: }
                    213:
                    214:
                    215: /*
                    216:  * Print a word on the current text line if one is open, or on a new text
                    217:  * line otherwise.  The flag ARG_SPACE inserts spaces between words.
                    218:  */
                    219: void
                    220: print_text(struct format *f, const char *word, int flags) {
                    221:        switch (f->linestate) {
                    222:        case LINE_NEW:
                    223:                break;
                    224:        case LINE_TEXT:
                    225:                if (flags & ARG_SPACE)
                    226:                        putchar(' ');
                    227:                break;
                    228:        case LINE_MACRO:
                    229:                macro_close(f);
                    230:                break;
                    231:        }
                    232:        fputs(word, stdout);
                    233:        f->linestate = LINE_TEXT;
                    234: }
                    235:
                    236: /*
                    237:  * Recursively print the content of a node on a text line.
                    238:  */
                    239: void
                    240: print_textnode(struct format *f, struct pnode *n)
                    241: {
                    242:        struct pnode    *nc;
                    243:
1.3       schwarze  244:        if (n->node == NODE_TEXT || n->node == NODE_ESCAPE)
1.2       schwarze  245:                print_text(f, n->b, ARG_SPACE);
                    246:        else
                    247:                TAILQ_FOREACH(nc, &n->childq, child)
                    248:                        print_textnode(f, nc);
1.1       schwarze  249: }

CVSweb