Annotation of mandoc/man_macro.c, Revision 1.9
1.9 ! kristaps 1: /* $Id: man_macro.c,v 1.8 2009/03/26 11:16:21 kristaps Exp $ */
1.1 kristaps 2: /*
3: * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@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
7: * above copyright notice and this permission notice appear in all
8: * copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11: * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12: * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13: * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14: * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15: * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16: * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17: * PERFORMANCE OF THIS SOFTWARE.
18: */
19: #include <assert.h>
20: #include <ctype.h>
21: #include <stdlib.h>
22: #include <stdio.h>
23: #include <string.h>
24:
25: #include "libman.h"
26:
1.9 ! kristaps 27: #define FL_NLINE (1 << 0)
! 28: #define FL_TLINE (1 << 1)
! 29:
1.3 kristaps 30: static int man_args(struct man *, int,
31: int *, char *, char **);
1.1 kristaps 32:
1.9 ! kristaps 33: static int man_flags[MAN_MAX] = {
! 34: 0, /* __ */
! 35: 0, /* TH */
! 36: 0, /* SH */
! 37: 0, /* SS */
! 38: FL_TLINE, /* TP */
! 39: 0, /* LP */
! 40: 0, /* PP */
! 41: 0, /* P */
! 42: 0, /* IP */
! 43: 0, /* HP */
! 44: FL_NLINE, /* SM */
! 45: FL_NLINE, /* SB */
! 46: FL_NLINE, /* BI */
! 47: FL_NLINE, /* IB */
! 48: FL_NLINE, /* BR */
! 49: FL_NLINE, /* RB */
! 50: FL_NLINE, /* R */
! 51: FL_NLINE, /* B */
! 52: FL_NLINE, /* I */
! 53: FL_NLINE, /* IR */
! 54: FL_NLINE, /* RI */
! 55: };
1.1 kristaps 56:
1.3 kristaps 57: int
58: man_macro(struct man *man, int tok, int line,
59: int ppos, int *pos, char *buf)
1.1 kristaps 60: {
1.3 kristaps 61: int w, la;
62: char *p;
63: struct man_node *n;
1.1 kristaps 64:
1.3 kristaps 65: if ( ! man_elem_alloc(man, line, ppos, tok))
1.1 kristaps 66: return(0);
1.3 kristaps 67: n = man->last;
68: man->next = MAN_NEXT_CHILD;
1.1 kristaps 69:
70: for (;;) {
71: la = *pos;
1.3 kristaps 72: w = man_args(man, line, pos, buf, &p);
1.1 kristaps 73:
1.3 kristaps 74: if (-1 == w)
1.1 kristaps 75: return(0);
1.3 kristaps 76: if (0 == w)
1.1 kristaps 77: break;
78:
1.3 kristaps 79: if ( ! man_word_alloc(man, line, la, p))
80: return(0);
81: man->next = MAN_NEXT_SIBLING;
82: }
1.1 kristaps 83:
1.9 ! kristaps 84: if (n == man->last && (FL_NLINE & man_flags[tok])) {
! 85: if (MAN_NLINE & man->flags)
! 86: return(man_verr(man, line, ppos,
! 87: "next-line scope already open"));
! 88: man->flags |= MAN_NLINE;
! 89: return(1);
! 90: }
! 91:
! 92: if (FL_TLINE & man_flags[tok]) {
! 93: if (MAN_NLINE & man->flags)
! 94: return(man_verr(man, line, ppos,
! 95: "next-line scope already open"));
! 96: man->flags |= MAN_NLINE;
! 97: return(1);
! 98: }
! 99:
1.7 kristaps 100: /*
101: * Note that when TH is pruned, we'll be back at the root, so
102: * make sure that we don't clobber as its sibling.
103: */
104:
105: for ( ; man->last; man->last = man->last->parent) {
106: if (man->last == n)
107: break;
108: if (man->last->type == MAN_ROOT)
109: break;
1.5 kristaps 110: if ( ! man_valid_post(man))
111: return(0);
1.6 kristaps 112: if ( ! man_action_post(man))
113: return(0);
114: }
1.1 kristaps 115:
1.5 kristaps 116: assert(man->last);
1.6 kristaps 117:
1.7 kristaps 118: /*
119: * Same here regarding whether we're back at the root.
120: */
121:
122: if (man->last->type != MAN_ROOT && ! man_valid_post(man))
1.5 kristaps 123: return(0);
1.7 kristaps 124: if (man->last->type != MAN_ROOT && ! man_action_post(man))
1.6 kristaps 125: return(0);
1.7 kristaps 126: if (man->last->type != MAN_ROOT)
127: man->next = MAN_NEXT_SIBLING;
1.1 kristaps 128:
129: return(1);
130: }
131:
1.3 kristaps 132:
1.4 kristaps 133: int
134: man_macroend(struct man *m)
135: {
136:
1.6 kristaps 137: for ( ; m->last && m->last != m->first;
138: m->last = m->last->parent) {
139: if ( ! man_valid_post(m))
140: return(0);
141: if ( ! man_action_post(m))
142: return(0);
143: }
1.7 kristaps 144: assert(m->last == m->first);
1.6 kristaps 145:
146: if ( ! man_valid_post(m))
147: return(0);
148: if ( ! man_action_post(m))
149: return(0);
150:
1.4 kristaps 151: return(1);
152: }
153:
154:
1.3 kristaps 155: /* ARGSUSED */
1.4 kristaps 156: static int
1.8 kristaps 157: man_args(struct man *m, int line,
1.3 kristaps 158: int *pos, char *buf, char **v)
159: {
160:
161: if (0 == buf[*pos])
162: return(0);
163:
164: /* First parse non-quoted strings. */
165:
166: if ('\"' != buf[*pos]) {
167: *v = &buf[*pos];
168:
169: while (buf[*pos]) {
170: if (' ' == buf[*pos])
171: if ('\\' != buf[*pos - 1])
172: break;
173: (*pos)++;
174: }
175:
176: if (0 == buf[*pos])
177: return(1);
178:
179: buf[(*pos)++] = 0;
180:
181: if (0 == buf[*pos])
182: return(1);
183:
184: while (buf[*pos] && ' ' == buf[*pos])
185: (*pos)++;
186:
187: if (buf[*pos])
188: return(1);
189:
1.8 kristaps 190: if ( ! man_vwarn(m, line, *pos, "trailing spaces"))
191: return(-1);
192:
193: return(1);
1.3 kristaps 194: }
195:
196: /*
197: * If we're a quoted string (and quoted strings are allowed),
198: * then parse ahead to the next quote. If none's found, it's an
199: * error. After, parse to the next word.
200: */
201:
202: *v = &buf[++(*pos)];
203:
204: while (buf[*pos] && '\"' != buf[*pos])
205: (*pos)++;
206:
207: if (0 == buf[*pos]) {
1.8 kristaps 208: if ( ! man_vwarn(m, line, *pos, "unterminated quote"))
209: return(-1);
210: return(1);
1.3 kristaps 211: }
212:
213: buf[(*pos)++] = 0;
214: if (0 == buf[*pos])
215: return(1);
216:
217: while (buf[*pos] && ' ' == buf[*pos])
218: (*pos)++;
219:
220: if (buf[*pos])
221: return(1);
222:
1.8 kristaps 223: if ( ! man_vwarn(m, line, *pos, "trailing spaces"))
224: return(-1);
225: return(1);
1.3 kristaps 226: }
CVSweb