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