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