]> git.cameronkatri.com Git - mandoc.git/blob - man.c
Fixed reading whitespace for man.7 `. TH'.
[mandoc.git] / man.c
1 /* $Id: man.c,v 1.9 2009/03/26 09:55:39 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 <err.h>
22 #include <stdarg.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26
27 #include "libman.h"
28
29 const char *const __man_macronames[MAN_MAX] = {
30 "\\\"", "TH", "SH", "SS",
31 "TP", "LP", "PP", "P",
32 "IP", "HP", "SM", "SB",
33 "BI", "IB", "BR", "RB",
34 "R", "B", "I", "IR"
35 };
36
37 const char * const *man_macronames = __man_macronames;
38
39 static struct man_node *man_node_alloc(int, int, enum man_type);
40 static int man_node_append(struct man *,
41 struct man_node *);
42 static int man_ptext(struct man *, int, char *);
43 static int man_pmacro(struct man *, int, char *);
44 static void man_free1(struct man *);
45 static void man_alloc1(struct man *);
46
47
48 const struct man_node *
49 man_node(const struct man *m)
50 {
51
52 return(MAN_HALT & m->flags ? NULL : m->first);
53 }
54
55
56 const struct man_meta *
57 man_meta(const struct man *m)
58 {
59
60 return(MAN_HALT & m->flags ? NULL : &m->meta);
61 }
62
63
64 void
65 man_reset(struct man *man)
66 {
67
68 man_free1(man);
69 man_alloc1(man);
70 }
71
72
73 void
74 man_free(struct man *man)
75 {
76
77 man_free1(man);
78
79 if (man->htab)
80 man_hash_free(man->htab);
81 free(man);
82 }
83
84
85 struct man *
86 man_alloc(void *data, int pflags, const struct man_cb *cb)
87 {
88 struct man *p;
89
90 p = calloc(1, sizeof(struct man));
91 if (NULL == p)
92 err(1, "calloc");
93
94 man_alloc1(p);
95
96 if (cb)
97 (void)memcpy(&p->cb, cb, sizeof(struct man_cb));
98
99 p->htab = man_hash_alloc();
100 p->data = data;
101 p->pflags = pflags;
102
103 return(p);
104 }
105
106
107 int
108 man_endparse(struct man *m)
109 {
110
111 if (MAN_HALT & m->flags)
112 return(0);
113 else if (man_macroend(m))
114 return(1);
115 m->flags |= MAN_HALT;
116 return(0);
117 }
118
119
120 int
121 man_parseln(struct man *m, int ln, char *buf)
122 {
123
124 return('.' == *buf ?
125 man_pmacro(m, ln, buf) :
126 man_ptext(m, ln, buf));
127 }
128
129
130 static void
131 man_free1(struct man *man)
132 {
133
134 if (man->first)
135 man_node_freelist(man->first);
136 if (man->meta.title)
137 free(man->meta.title);
138 if (man->meta.source)
139 free(man->meta.source);
140 if (man->meta.vol)
141 free(man->meta.vol);
142 }
143
144
145 static void
146 man_alloc1(struct man *m)
147 {
148
149 bzero(&m->meta, sizeof(struct man_meta));
150 m->flags = 0;
151 m->last = calloc(1, sizeof(struct man_node));
152 if (NULL == m->last)
153 err(1, "calloc");
154 m->first = m->last;
155 m->last->type = MAN_ROOT;
156 m->next = MAN_NEXT_CHILD;
157 }
158
159
160 static int
161 man_node_append(struct man *man, struct man_node *p)
162 {
163
164 assert(man->last);
165 assert(man->first);
166 assert(MAN_ROOT != p->type);
167
168 switch (man->next) {
169 case (MAN_NEXT_SIBLING):
170 man->last->next = p;
171 p->prev = man->last;
172 p->parent = man->last->parent;
173 break;
174 case (MAN_NEXT_CHILD):
175 man->last->child = p;
176 p->parent = man->last;
177 break;
178 default:
179 abort();
180 /* NOTREACHED */
181 }
182
183 man->last = p;
184
185 switch (p->type) {
186 case (MAN_TEXT):
187 if ( ! man_valid_post(man))
188 return(0);
189 if ( ! man_action_post(man))
190 return(0);
191 break;
192 default:
193 break;
194 }
195
196 return(1);
197 }
198
199
200 static struct man_node *
201 man_node_alloc(int line, int pos, enum man_type type)
202 {
203 struct man_node *p;
204
205 if (NULL == (p = calloc(1, sizeof(struct man_node))))
206 err(1, "malloc");
207 p->line = line;
208 p->pos = pos;
209 p->type = type;
210
211 return(p);
212 }
213
214
215 int
216 man_elem_alloc(struct man *man, int line, int pos, int tok)
217 {
218 struct man_node *p;
219
220 p = man_node_alloc(line, pos, MAN_ELEM);
221 p->tok = tok;
222
223 return(man_node_append(man, p));
224 }
225
226
227 int
228 man_word_alloc(struct man *man,
229 int line, int pos, const char *word)
230 {
231 struct man_node *p;
232
233 p = man_node_alloc(line, pos, MAN_TEXT);
234 if (NULL == (p->string = strdup(word)))
235 err(1, "strdup");
236
237 return(man_node_append(man, p));
238 }
239
240
241 void
242 man_node_free(struct man_node *p)
243 {
244
245 if (p->string)
246 free(p->string);
247 free(p);
248 }
249
250
251 void
252 man_node_freelist(struct man_node *p)
253 {
254
255 if (p->child)
256 man_node_freelist(p->child);
257 if (p->next)
258 man_node_freelist(p->next);
259
260 man_node_free(p);
261 }
262
263
264 static int
265 man_ptext(struct man *m, int line, char *buf)
266 {
267
268 if ( ! man_word_alloc(m, line, 0, buf))
269 return(0);
270 m->next = MAN_NEXT_SIBLING;
271 return(1);
272 }
273
274
275 int
276 man_pmacro(struct man *m, int ln, char *buf)
277 {
278 int i, j, c;
279 char mac[5];
280
281 /* Comments and empties are quickly ignored. */
282
283 if (0 == buf[1])
284 return(1);
285
286 i = 1;
287
288 if (' ' == buf[i]) {
289 i++;
290 while (buf[i] && ' ' == buf[i])
291 i++;
292 if (0 == buf[i])
293 return(1);
294 }
295
296 if (buf[i] && '\\' == buf[i])
297 if (buf[i + 1] && '\"' == buf[i + 1])
298 return(1);
299
300 /* Copy the first word into a nil-terminated buffer. */
301
302 for (j = 0; j < 4; j++) {
303 if (0 == (mac[j] = buf[j + i]))
304 break;
305 else if (' ' == buf[j + i])
306 break;
307 }
308
309 mac[j] = 0;
310
311 if (j == 4 || j < 1) {
312 if ( ! (MAN_IGN_MACRO & m->pflags)) {
313 (void)man_verr(m, ln, i,
314 "ill-formed macro: %s", mac);
315 goto err;
316 }
317 if ( ! man_vwarn(m, ln, 0, "ill-formed macro: %s", mac))
318 goto err;
319 return(1);
320 }
321
322 if (MAN_MAX == (c = man_hash_find(m->htab, mac))) {
323 if ( ! (MAN_IGN_MACRO & m->pflags)) {
324 (void)man_verr(m, ln, i,
325 "unknown macro: %s", mac);
326 goto err;
327 }
328 if ( ! man_vwarn(m, ln, i, "unknown macro: %s", mac))
329 goto err;
330 return(1);
331 }
332
333 /* The macro is sane. Jump to the next word. */
334
335 while (buf[i] && ' ' == buf[i])
336 i++;
337
338 /* Begin recursive parse sequence. */
339
340 if ( ! man_macro(m, c, ln, 1, &i, buf))
341 goto err;
342
343 return(1);
344
345 err: /* Error out. */
346
347 m->flags |= MAN_HALT;
348 return(0);
349 }
350
351
352 int
353 man_verr(struct man *man, int ln, int pos, const char *fmt, ...)
354 {
355 char buf[256];
356 va_list ap;
357
358 if (NULL == man->cb.man_err)
359 return(0);
360
361 va_start(ap, fmt);
362 (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
363 va_end(ap);
364 return((*man->cb.man_err)(man->data, ln, pos, buf));
365 }
366
367
368 int
369 man_vwarn(struct man *man, int ln, int pos, const char *fmt, ...)
370 {
371 char buf[256];
372 va_list ap;
373
374 if (NULL == man->cb.man_warn)
375 return(0);
376
377 va_start(ap, fmt);
378 (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
379 va_end(ap);
380 return((*man->cb.man_warn)(man->data, ln, pos, buf));
381 }
382
383