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