]> git.cameronkatri.com Git - mandoc.git/blob - man.c
f0f5b83c889e434981b0cbba6c80170e97bc63fb
[mandoc.git] / man.c
1 /* $Id: man.c,v 1.12 2009/03/26 14:44:41 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 "RI"
36 };
37
38 const char * const *man_macronames = __man_macronames;
39
40 static struct man_node *man_node_alloc(int, int, enum man_type);
41 static int man_node_append(struct man *,
42 struct man_node *);
43 static int man_ptext(struct man *, int, char *);
44 static int man_pmacro(struct man *, int, char *);
45 static void man_free1(struct man *);
46 static void man_alloc1(struct man *);
47
48
49 const struct man_node *
50 man_node(const struct man *m)
51 {
52
53 return(MAN_HALT & m->flags ? NULL : m->first);
54 }
55
56
57 const struct man_meta *
58 man_meta(const struct man *m)
59 {
60
61 return(MAN_HALT & m->flags ? NULL : &m->meta);
62 }
63
64
65 void
66 man_reset(struct man *man)
67 {
68
69 man_free1(man);
70 man_alloc1(man);
71 }
72
73
74 void
75 man_free(struct man *man)
76 {
77
78 man_free1(man);
79
80 if (man->htab)
81 man_hash_free(man->htab);
82 free(man);
83 }
84
85
86 struct man *
87 man_alloc(void *data, int pflags, const struct man_cb *cb)
88 {
89 struct man *p;
90
91 p = calloc(1, sizeof(struct man));
92 if (NULL == p)
93 err(1, "calloc");
94
95 man_alloc1(p);
96
97 if (cb)
98 (void)memcpy(&p->cb, cb, sizeof(struct man_cb));
99
100 p->htab = man_hash_alloc();
101 p->data = data;
102 p->pflags = pflags;
103
104 return(p);
105 }
106
107
108 int
109 man_endparse(struct man *m)
110 {
111
112 if (MAN_HALT & m->flags)
113 return(0);
114 else if (man_macroend(m))
115 return(1);
116 m->flags |= MAN_HALT;
117 return(0);
118 }
119
120
121 int
122 man_parseln(struct man *m, int ln, char *buf)
123 {
124
125 return('.' == *buf ?
126 man_pmacro(m, ln, buf) :
127 man_ptext(m, ln, buf));
128 }
129
130
131 static void
132 man_free1(struct man *man)
133 {
134
135 if (man->first)
136 man_node_freelist(man->first);
137 if (man->meta.title)
138 free(man->meta.title);
139 if (man->meta.source)
140 free(man->meta.source);
141 if (man->meta.vol)
142 free(man->meta.vol);
143 }
144
145
146 static void
147 man_alloc1(struct man *m)
148 {
149
150 bzero(&m->meta, sizeof(struct man_meta));
151 m->flags = 0;
152 m->last = calloc(1, sizeof(struct man_node));
153 if (NULL == m->last)
154 err(1, "calloc");
155 m->first = m->last;
156 m->last->type = MAN_ROOT;
157 m->next = MAN_NEXT_CHILD;
158 }
159
160
161 static int
162 man_node_append(struct man *man, struct man_node *p)
163 {
164
165 assert(man->last);
166 assert(man->first);
167 assert(MAN_ROOT != p->type);
168
169 switch (man->next) {
170 case (MAN_NEXT_SIBLING):
171 man->last->next = p;
172 p->prev = man->last;
173 p->parent = man->last->parent;
174 break;
175 case (MAN_NEXT_CHILD):
176 man->last->child = p;
177 p->parent = man->last;
178 break;
179 default:
180 abort();
181 /* NOTREACHED */
182 }
183
184 man->last = p;
185
186 switch (p->type) {
187 case (MAN_TEXT):
188 if ( ! man_valid_post(man))
189 return(0);
190 if ( ! man_action_post(man))
191 return(0);
192 break;
193 default:
194 break;
195 }
196
197 return(1);
198 }
199
200
201 static struct man_node *
202 man_node_alloc(int line, int pos, enum man_type type)
203 {
204 struct man_node *p;
205
206 if (NULL == (p = calloc(1, sizeof(struct man_node))))
207 err(1, "malloc");
208 p->line = line;
209 p->pos = pos;
210 p->type = type;
211
212 return(p);
213 }
214
215
216 int
217 man_elem_alloc(struct man *man, int line, int pos, int tok)
218 {
219 struct man_node *p;
220
221 p = man_node_alloc(line, pos, MAN_ELEM);
222 p->tok = tok;
223
224 return(man_node_append(man, p));
225 }
226
227
228 int
229 man_word_alloc(struct man *man,
230 int line, int pos, const char *word)
231 {
232 struct man_node *p;
233
234 p = man_node_alloc(line, pos, MAN_TEXT);
235 if (NULL == (p->string = strdup(word)))
236 err(1, "strdup");
237
238 return(man_node_append(man, p));
239 }
240
241
242 void
243 man_node_free(struct man_node *p)
244 {
245
246 if (p->string)
247 free(p->string);
248 free(p);
249 }
250
251
252 void
253 man_node_freelist(struct man_node *p)
254 {
255
256 if (p->child)
257 man_node_freelist(p->child);
258 if (p->next)
259 man_node_freelist(p->next);
260
261 man_node_free(p);
262 }
263
264
265 static int
266 man_ptext(struct man *m, int line, char *buf)
267 {
268
269 if ( ! man_word_alloc(m, line, 0, buf))
270 return(0);
271 m->next = MAN_NEXT_SIBLING;
272
273 /*
274 * If this is one of the zany NLINE macros that consumes the
275 * next line of input as being influenced, then close out the
276 * existing macro "scope" and continue processing.
277 */
278
279 if ( ! (MAN_NLINE & m->flags))
280 return(1);
281
282 m->flags &= ~MAN_NLINE;
283 m->last = m->last->parent;
284
285 assert(MAN_ROOT != m->last->type);
286 if ( ! man_valid_post(m))
287 return(0);
288 if ( ! man_action_post(m))
289 return(0);
290
291 return(1);
292 }
293
294
295 int
296 man_pmacro(struct man *m, int ln, char *buf)
297 {
298 int i, j, c, ppos, fl;
299 char mac[5];
300 struct man_node *n;
301
302 /* Comments and empties are quickly ignored. */
303
304 n = m->last;
305 fl = MAN_NLINE & m->flags;
306
307 if (0 == buf[1])
308 goto out;
309
310 i = 1;
311
312 if (' ' == buf[i]) {
313 i++;
314 while (buf[i] && ' ' == buf[i])
315 i++;
316 if (0 == buf[i])
317 goto out;
318 }
319
320 ppos = i;
321
322 if (buf[i] && '\\' == buf[i])
323 if (buf[i + 1] && '\"' == buf[i + 1])
324 goto out;
325
326 /* Copy the first word into a nil-terminated buffer. */
327
328 for (j = 0; j < 4; j++, i++) {
329 if (0 == (mac[j] = buf[i]))
330 break;
331 else if (' ' == buf[i])
332 break;
333 }
334
335 mac[j] = 0;
336
337 if (j == 4 || j < 1) {
338 if ( ! (MAN_IGN_MACRO & m->pflags)) {
339 (void)man_verr(m, ln, ppos,
340 "ill-formed macro: %s", mac);
341 goto err;
342 }
343 if ( ! man_vwarn(m, ln, ppos,
344 "ill-formed macro: %s", mac))
345 goto err;
346 return(1);
347 }
348
349 if (MAN_MAX == (c = man_hash_find(m->htab, mac))) {
350 if ( ! (MAN_IGN_MACRO & m->pflags)) {
351 (void)man_verr(m, ln, ppos,
352 "unknown macro: %s", mac);
353 goto err;
354 }
355 if ( ! man_vwarn(m, ln, ppos,
356 "unknown macro: %s", mac))
357 goto err;
358 return(1);
359 }
360
361 /* The macro is sane. Jump to the next word. */
362
363 while (buf[i] && ' ' == buf[i])
364 i++;
365
366 /* Begin recursive parse sequence. */
367
368 if ( ! man_macro(m, c, ln, ppos, &i, buf))
369 goto err;
370
371 out:
372 if (fl) {
373 /*
374 * A NLINE macro has been immediately followed with
375 * another. Close out the preceeding macro's scope, and
376 * continue.
377 */
378 assert(MAN_ROOT != m->last->type);
379 assert(m->last->parent);
380 assert(MAN_ROOT != m->last->parent->type);
381
382 if (n != m->last)
383 m->last = m->last->parent;
384
385 if ( ! man_valid_post(m))
386 return(0);
387 if ( ! man_action_post(m))
388 return(0);
389 m->next = MAN_NEXT_SIBLING;
390 m->flags &= ~MAN_NLINE;
391 }
392
393 return(1);
394
395 err: /* Error out. */
396
397 m->flags |= MAN_HALT;
398 return(0);
399 }
400
401
402 int
403 man_verr(struct man *man, int ln, int pos, const char *fmt, ...)
404 {
405 char buf[256];
406 va_list ap;
407
408 if (NULL == man->cb.man_err)
409 return(0);
410
411 va_start(ap, fmt);
412 (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
413 va_end(ap);
414 return((*man->cb.man_err)(man->data, ln, pos, buf));
415 }
416
417
418 int
419 man_vwarn(struct man *man, int ln, int pos, const char *fmt, ...)
420 {
421 char buf[256];
422 va_list ap;
423
424 if (NULL == man->cb.man_warn)
425 return(0);
426
427 va_start(ap, fmt);
428 (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
429 va_end(ap);
430 return((*man->cb.man_warn)(man->data, ln, pos, buf));
431 }
432
433