]> git.cameronkatri.com Git - mandoc.git/blob - man_macro.c
*** empty log message ***
[mandoc.git] / man_macro.c
1 /* $Id: man_macro.c,v 1.12 2009/04/02 06:51:44 kristaps Exp $ */
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 <string.h>
23
24 #include "libman.h"
25
26 #define FL_NLINE (1 << 0)
27 #define FL_TLINE (1 << 1)
28
29 static int man_args(struct man *, int,
30 int *, char *, char **);
31
32 static int man_flags[MAN_MAX] = {
33 0, /* __ */
34 0, /* TH */
35 0, /* SH */
36 0, /* SS */
37 FL_TLINE, /* TP */
38 0, /* LP */
39 0, /* PP */
40 0, /* P */
41 0, /* IP */
42 0, /* HP */
43 FL_NLINE, /* SM */
44 FL_NLINE, /* SB */
45 FL_NLINE, /* BI */
46 FL_NLINE, /* IB */
47 FL_NLINE, /* BR */
48 FL_NLINE, /* RB */
49 FL_NLINE, /* R */
50 FL_NLINE, /* B */
51 FL_NLINE, /* I */
52 FL_NLINE, /* IR */
53 FL_NLINE, /* RI */
54 0, /* br */
55 0, /* na */
56 };
57
58 int
59 man_macro(struct man *man, int tok, int line,
60 int ppos, int *pos, char *buf)
61 {
62 int w, la;
63 char *p;
64 struct man_node *n;
65
66 if ( ! man_elem_alloc(man, line, ppos, tok))
67 return(0);
68 n = man->last;
69 man->next = MAN_NEXT_CHILD;
70
71 for (;;) {
72 la = *pos;
73 w = man_args(man, line, pos, buf, &p);
74
75 if (-1 == w)
76 return(0);
77 if (0 == w)
78 break;
79
80 if ( ! man_word_alloc(man, line, la, p))
81 return(0);
82 man->next = MAN_NEXT_SIBLING;
83 }
84
85 if (n == man->last && (FL_NLINE & man_flags[tok])) {
86 if (MAN_NLINE & man->flags)
87 return(man_verr(man, line, ppos,
88 "next-line scope already open"));
89 man->flags |= MAN_NLINE;
90 return(1);
91 }
92
93 if (FL_TLINE & man_flags[tok]) {
94 if (MAN_NLINE & man->flags)
95 return(man_verr(man, line, ppos,
96 "next-line scope already open"));
97 man->flags |= MAN_NLINE;
98 return(1);
99 }
100
101 /*
102 * Note that when TH is pruned, we'll be back at the root, so
103 * make sure that we don't clobber as its sibling.
104 */
105
106 for ( ; man->last; man->last = man->last->parent) {
107 if (man->last == n)
108 break;
109 if (man->last->type == MAN_ROOT)
110 break;
111 if ( ! man_valid_post(man))
112 return(0);
113 if ( ! man_action_post(man))
114 return(0);
115 }
116
117 assert(man->last);
118
119 /*
120 * Same here regarding whether we're back at the root.
121 */
122
123 if (man->last->type != MAN_ROOT && ! man_valid_post(man))
124 return(0);
125 if (man->last->type != MAN_ROOT && ! man_action_post(man))
126 return(0);
127 if (man->last->type != MAN_ROOT)
128 man->next = MAN_NEXT_SIBLING;
129
130 return(1);
131 }
132
133
134 int
135 man_macroend(struct man *m)
136 {
137
138 for ( ; m->last && m->last != m->first;
139 m->last = m->last->parent) {
140 if ( ! man_valid_post(m))
141 return(0);
142 if ( ! man_action_post(m))
143 return(0);
144 }
145 assert(m->last == m->first);
146
147 if ( ! man_valid_post(m))
148 return(0);
149 if ( ! man_action_post(m))
150 return(0);
151
152 return(1);
153 }
154
155
156 /* ARGSUSED */
157 static int
158 man_args(struct man *m, int line,
159 int *pos, char *buf, char **v)
160 {
161
162 if (0 == buf[*pos])
163 return(0);
164
165 /* First parse non-quoted strings. */
166
167 if ('\"' != buf[*pos]) {
168 *v = &buf[*pos];
169
170 while (buf[*pos]) {
171 if (' ' == buf[*pos])
172 if ('\\' != buf[*pos - 1])
173 break;
174 (*pos)++;
175 }
176
177 if (0 == buf[*pos])
178 return(1);
179
180 buf[(*pos)++] = 0;
181
182 if (0 == buf[*pos])
183 return(1);
184
185 while (buf[*pos] && ' ' == buf[*pos])
186 (*pos)++;
187
188 if (buf[*pos])
189 return(1);
190
191 if ( ! man_vwarn(m, line, *pos, "trailing spaces"))
192 return(-1);
193
194 return(1);
195 }
196
197 /*
198 * If we're a quoted string (and quoted strings are allowed),
199 * then parse ahead to the next quote. If none's found, it's an
200 * error. After, parse to the next word.
201 */
202
203 *v = &buf[++(*pos)];
204
205 while (buf[*pos] && '\"' != buf[*pos])
206 (*pos)++;
207
208 if (0 == buf[*pos]) {
209 if ( ! man_vwarn(m, line, *pos, "unterminated quote"))
210 return(-1);
211 return(1);
212 }
213
214 buf[(*pos)++] = 0;
215 if (0 == buf[*pos])
216 return(1);
217
218 while (buf[*pos] && ' ' == buf[*pos])
219 (*pos)++;
220
221 if (buf[*pos])
222 return(1);
223
224 if ( ! man_vwarn(m, line, *pos, "trailing spaces"))
225 return(-1);
226 return(1);
227 }