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