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