]> git.cameronkatri.com Git - mandoc.git/blob - man_macro.c
Removed MAN___: moved MAN_br to its index (comments not passed into parser).
[mandoc.git] / man_macro.c
1 /* $Id: man_macro.c,v 1.16 2009/06/16 19:55:28 kristaps Exp $ */
2 /*
3 * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
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 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.
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] = {
31 0, /* br */
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 }