Annotation of docbook2mdoc/macro.c, Revision 1.1
1.1 ! schwarze 1: /* $Id$ */
! 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: {
! 50: assert(f->linestate == LINE_MACRO);
! 51: putchar('\n');
! 52: f->linestate = LINE_NEW;
! 53: }
! 54:
! 55: void
! 56: macro_line(struct format *f, const char *name)
! 57: {
! 58: macro_open(f, name);
! 59: macro_close(f);
! 60: }
! 61:
! 62: /*
! 63: * If the next node is a text node starting with closing punctuation,
! 64: * emit the closing punctuation as a trailing macro argument.
! 65: */
! 66: void
! 67: macro_closepunct(struct format *f, struct pnode *pn)
! 68: {
! 69: if ((pn = TAILQ_NEXT(pn, child)) != NULL &&
! 70: pn->node == NODE_TEXT && pn->bsz > 0 &&
! 71: (pn->b[0] == ',' || pn->b[0] == '.') &&
! 72: (pn->bsz == 1 || isspace((unsigned char)pn->b[1]))) {
! 73: putchar(' ');
! 74: putchar(pn->b[0]);
! 75: pn->b++;
! 76: pn->bsz--;
! 77: }
! 78: macro_close(f);
! 79: }
! 80:
! 81: /*
! 82: * Print an argument string on a macro line, collapsing whitespace.
! 83: */
! 84: void
! 85: macro_addarg(struct format *f, const char *arg, int flags)
! 86: {
! 87: const char *cp;
! 88:
! 89: assert(f->linestate == LINE_MACRO);
! 90:
! 91: /* Quote if requested and necessary. */
! 92:
! 93: if ((flags & (ARG_SINGLE | ARG_QUOTED)) == ARG_SINGLE) {
! 94: for (cp = arg; *cp != '\0'; cp++)
! 95: if (isspace((unsigned char)*cp))
! 96: break;
! 97: if (*cp != '\0') {
! 98: if (flags & ARG_SPACE) {
! 99: putchar(' ');
! 100: flags &= ~ ARG_SPACE;
! 101: }
! 102: putchar('"');
! 103: flags = ARG_QUOTED;
! 104: }
! 105: }
! 106:
! 107: for (cp = arg; *cp != '\0'; cp++) {
! 108:
! 109: /* Collapse whitespace. */
! 110:
! 111: if (isspace((unsigned char)*cp)) {
! 112: flags |= ARG_SPACE;
! 113: continue;
! 114: } else if (flags & ARG_SPACE) {
! 115: putchar(' ');
! 116: flags &= ~ ARG_SPACE;
! 117: }
! 118:
! 119: /* Escape us if we look like a macro. */
! 120:
! 121: if ((flags & ARG_QUOTED) == 0 &&
! 122: (cp == arg || isspace((unsigned char)cp[-1])) &&
! 123: isupper((unsigned char)cp[0]) &&
! 124: islower((unsigned char)cp[1]) &&
! 125: (cp[2] == '\0' || cp[2] == ' ' ||
! 126: (islower((unsigned char)cp[2]) &&
! 127: (cp[3] == '\0' || cp[3] == ' '))))
! 128: fputs("\\&", stdout);
! 129:
! 130: if (*cp == '"')
! 131: fputs("\\(dq", stdout);
! 132: else if (flags & ARG_UPPER)
! 133: putchar(toupper((unsigned char)*cp));
! 134: else
! 135: putchar(*cp);
! 136: if (*cp == '\\')
! 137: putchar('e');
! 138: }
! 139: }
! 140:
! 141: void
! 142: macro_argline(struct format *f, const char *name, const char *arg)
! 143: {
! 144: macro_open(f, name);
! 145: macro_addarg(f, arg, ARG_SPACE);
! 146: macro_close(f);
! 147: }
! 148:
! 149: /*
! 150: * Recursively append text from the children of a node to a macro line.
! 151: */
! 152: void
! 153: macro_addnode(struct format *f, struct pnode *pn, int flags)
! 154: {
! 155: int quote_now;
! 156:
! 157: assert(f->linestate == LINE_MACRO);
! 158:
! 159: /*
! 160: * If the only child is a text node, just add that text,
! 161: * letting macro_addarg() decide about quoting.
! 162: */
! 163:
! 164: pn = TAILQ_FIRST(&pn->childq);
! 165: if (pn != NULL && pn->node == NODE_TEXT &&
! 166: TAILQ_NEXT(pn, child) == NULL) {
! 167: macro_addarg(f, pn->b, flags);
! 168: return;
! 169: }
! 170:
! 171: /*
! 172: * If we want the argument quoted and are not already
! 173: * in a quoted context, quote now.
! 174: */
! 175:
! 176: quote_now = 0;
! 177: if (flags & ARG_SINGLE) {
! 178: if ((flags & ARG_QUOTED) == 0) {
! 179: if (flags & ARG_SPACE) {
! 180: putchar(' ');
! 181: flags &= ~ARG_SPACE;
! 182: }
! 183: putchar('"');
! 184: flags |= ARG_QUOTED;
! 185: quote_now = 1;
! 186: }
! 187: flags &= ~ARG_SINGLE;
! 188: }
! 189:
! 190: /*
! 191: * Iterate to child and sibling nodes,
! 192: * inserting whitespace between nodes.
! 193: */
! 194:
! 195: while (pn != NULL) {
! 196: if (pn->node == NODE_TEXT)
! 197: macro_addarg(f, pn->b, flags);
! 198: else
! 199: macro_addnode(f, pn, flags);
! 200: pn = TAILQ_NEXT(pn, child);
! 201: flags |= ARG_SPACE;
! 202: }
! 203: if (quote_now)
! 204: putchar('"');
! 205: }
! 206:
! 207: void
! 208: macro_nodeline(struct format *f, const char *name, struct pnode *pn, int flags)
! 209: {
! 210: macro_open(f, name);
! 211: macro_addnode(f, pn, ARG_SPACE | flags);
! 212: macro_close(f);
! 213: }
CVSweb