]> git.cameronkatri.com Git - mandoc.git/blob - man.c
`IP' and `TP' correctly handle width arguments.
[mandoc.git] / man.c
1 /* $Id: man.c,v 1.29 2009/08/13 11:45:29 kristaps Exp $ */
2 /*
3 * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
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_merrnames[WERRMAX] = {
27 "invalid character", /* WNPRINT */
28 "system: malloc error", /* WNMEM */
29 "invalid manual section", /* WMSEC */
30 "invalid date format", /* WDATE */
31 "scope of prior line violated", /* WLNSCOPE */
32 "trailing whitespace", /* WTSPACE */
33 "unterminated quoted parameter", /* WTQUOTE */
34 "document has no body", /* WNODATA */
35 "document has no title/section", /* WNOTITLE */
36 "invalid escape sequence", /* WESCAPE */
37 "invalid number format", /* WNUMFMT */
38 "expected block head arguments", /* WHEADARGS */
39 "expected block body arguments", /* WBODYARGS */
40 "expected empty block head", /* WNHEADARGS */
41 "unknown macro", /* WMACRO */
42 "ill-formed macro", /* WMACROFORM */
43 "scope open on exit" /* WEXITSCOPE */
44 };
45
46 const char *const __man_macronames[MAN_MAX] = {
47 "br", "TH", "SH", "SS",
48 "TP", "LP", "PP", "P",
49 "IP", "HP", "SM", "SB",
50 "BI", "IB", "BR", "RB",
51 "R", "B", "I", "IR",
52 "RI", "na", "i", "sp",
53 "nf", "fi", "r"
54 };
55
56 const char * const *man_macronames = __man_macronames;
57
58 static struct man_node *man_node_alloc(int, int,
59 enum man_type, int);
60 static int man_node_append(struct man *,
61 struct man_node *);
62 static int man_ptext(struct man *, int, char *);
63 static int man_pmacro(struct man *, int, char *);
64 static void man_free1(struct man *);
65 static int man_alloc1(struct man *);
66
67
68 const struct man_node *
69 man_node(const struct man *m)
70 {
71
72 return(MAN_HALT & m->flags ? NULL : m->first);
73 }
74
75
76 const struct man_meta *
77 man_meta(const struct man *m)
78 {
79
80 return(MAN_HALT & m->flags ? NULL : &m->meta);
81 }
82
83
84 int
85 man_reset(struct man *man)
86 {
87
88 man_free1(man);
89 return(man_alloc1(man));
90 }
91
92
93 void
94 man_free(struct man *man)
95 {
96
97 man_free1(man);
98
99 if (man->htab)
100 man_hash_free(man->htab);
101 free(man);
102 }
103
104
105 struct man *
106 man_alloc(void *data, int pflags, const struct man_cb *cb)
107 {
108 struct man *p;
109
110 if (NULL == (p = calloc(1, sizeof(struct man))))
111 return(NULL);
112
113 if ( ! man_alloc1(p)) {
114 free(p);
115 return(NULL);
116 }
117
118 p->data = data;
119 p->pflags = pflags;
120 (void)memcpy(&p->cb, cb, sizeof(struct man_cb));
121
122 if (NULL == (p->htab = man_hash_alloc())) {
123 free(p);
124 return(NULL);
125 }
126 return(p);
127 }
128
129
130 int
131 man_endparse(struct man *m)
132 {
133
134 if (MAN_HALT & m->flags)
135 return(0);
136 else if (man_macroend(m))
137 return(1);
138 m->flags |= MAN_HALT;
139 return(0);
140 }
141
142
143 int
144 man_parseln(struct man *m, int ln, char *buf)
145 {
146
147 return('.' == *buf ?
148 man_pmacro(m, ln, buf) :
149 man_ptext(m, ln, buf));
150 }
151
152
153 static void
154 man_free1(struct man *man)
155 {
156
157 if (man->first)
158 man_node_freelist(man->first);
159 if (man->meta.title)
160 free(man->meta.title);
161 if (man->meta.source)
162 free(man->meta.source);
163 if (man->meta.vol)
164 free(man->meta.vol);
165 }
166
167
168 static int
169 man_alloc1(struct man *m)
170 {
171
172 bzero(&m->meta, sizeof(struct man_meta));
173 m->flags = 0;
174 m->last = calloc(1, sizeof(struct man_node));
175 if (NULL == m->last)
176 return(0);
177 m->first = m->last;
178 m->last->type = MAN_ROOT;
179 m->next = MAN_NEXT_CHILD;
180 return(1);
181 }
182
183
184 static int
185 man_node_append(struct man *man, struct man_node *p)
186 {
187
188 assert(man->last);
189 assert(man->first);
190 assert(MAN_ROOT != p->type);
191
192 switch (man->next) {
193 case (MAN_NEXT_SIBLING):
194 man->last->next = p;
195 p->prev = man->last;
196 p->parent = man->last->parent;
197 break;
198 case (MAN_NEXT_CHILD):
199 man->last->child = p;
200 p->parent = man->last;
201 break;
202 default:
203 abort();
204 /* NOTREACHED */
205 }
206
207 p->parent->nchild++;
208
209 if ( ! man_valid_pre(man, p))
210 return(0);
211
212 switch (p->type) {
213 case (MAN_HEAD):
214 assert(MAN_BLOCK == p->parent->type);
215 p->parent->head = p;
216 break;
217 case (MAN_BODY):
218 assert(MAN_BLOCK == p->parent->type);
219 p->parent->body = p;
220 break;
221 default:
222 break;
223 }
224
225 man->last = p;
226
227 switch (p->type) {
228 case (MAN_TEXT):
229 if ( ! man_valid_post(man))
230 return(0);
231 if ( ! man_action_post(man))
232 return(0);
233 break;
234 default:
235 break;
236 }
237
238 return(1);
239 }
240
241
242 static struct man_node *
243 man_node_alloc(int line, int pos, enum man_type type, int tok)
244 {
245 struct man_node *p;
246
247 p = calloc(1, sizeof(struct man_node));
248 if (NULL == p)
249 return(NULL);
250
251 p->line = line;
252 p->pos = pos;
253 p->type = type;
254 p->tok = tok;
255 return(p);
256 }
257
258
259 int
260 man_elem_alloc(struct man *man, int line, int pos, int tok)
261 {
262 struct man_node *p;
263
264 p = man_node_alloc(line, pos, MAN_ELEM, tok);
265 if (NULL == p)
266 return(0);
267 return(man_node_append(man, p));
268 }
269
270
271 int
272 man_head_alloc(struct man *m, int line, int pos, int tok)
273 {
274 struct man_node *p;
275
276 p = man_node_alloc(line, pos, MAN_HEAD, tok);
277 if (NULL == p)
278 return(0);
279 if ( ! man_node_append(m, p))
280 return(0);
281 m->next = MAN_NEXT_CHILD;
282 return(1);
283 }
284
285
286 int
287 man_body_alloc(struct man *m, int line, int pos, int tok)
288 {
289 struct man_node *p;
290
291 p = man_node_alloc(line, pos, MAN_BODY, tok);
292 if (NULL == p)
293 return(0);
294 if ( ! man_node_append(m, p))
295 return(0);
296 m->next = MAN_NEXT_CHILD;
297 return(1);
298 }
299
300
301 int
302 man_block_alloc(struct man *m, int line, int pos, int tok)
303 {
304 struct man_node *p;
305
306 p = man_node_alloc(line, pos, MAN_BLOCK, tok);
307 if (NULL == p)
308 return(0);
309 if ( ! man_node_append(m, p))
310 return(0);
311 m->next = MAN_NEXT_CHILD;
312 return(1);
313 }
314
315
316 int
317 man_word_alloc(struct man *man,
318 int line, int pos, const char *word)
319 {
320 struct man_node *p;
321
322 p = man_node_alloc(line, pos, MAN_TEXT, -1);
323 if (NULL == p)
324 return(0);
325 if (NULL == (p->string = strdup(word)))
326 return(0);
327 return(man_node_append(man, p));
328 }
329
330
331 void
332 man_node_free(struct man_node *p)
333 {
334
335 if (p->string)
336 free(p->string);
337 if (p->parent)
338 p->parent->nchild--;
339 free(p);
340 }
341
342
343 void
344 man_node_freelist(struct man_node *p)
345 {
346
347 if (p->child)
348 man_node_freelist(p->child);
349 if (p->next)
350 man_node_freelist(p->next);
351
352 assert(0 == p->nchild);
353 man_node_free(p);
354 }
355
356
357 static int
358 man_ptext(struct man *m, int line, char *buf)
359 {
360
361 /* First allocate word. */
362
363 if ( ! man_word_alloc(m, line, 0, buf))
364 return(0);
365 m->next = MAN_NEXT_SIBLING;
366
367 /*
368 * Co-ordinate what happens with having a next-line scope open:
369 * first close out the element scope (if applicable), then close
370 * out the block scope (also if applicable).
371 */
372
373 /* XXX - this should be in man_action.c. */
374
375 if (MAN_ELINE & m->flags) {
376 m->flags &= ~MAN_ELINE;
377 if ( ! man_unscope(m, m->last->parent))
378 return(0);
379 }
380
381 if ( ! (MAN_BLINE & m->flags))
382 return(1);
383 m->flags &= ~MAN_BLINE;
384
385 if ( ! man_unscope(m, m->last->parent))
386 return(0);
387 return(man_body_alloc(m, line, 0, m->last->tok));
388 }
389
390
391 int
392 man_pmacro(struct man *m, int ln, char *buf)
393 {
394 int i, j, c, ppos, fl;
395 char mac[5];
396
397 /* Comments and empties are quickly ignored. */
398
399 fl = m->flags;
400
401 if (0 == buf[1])
402 goto out;
403
404 i = 1;
405
406 if (' ' == buf[i]) {
407 i++;
408 while (buf[i] && ' ' == buf[i])
409 i++;
410 if (0 == buf[i])
411 goto out;
412 }
413
414 ppos = i;
415
416 /* Copy the first word into a nil-terminated buffer. */
417
418 for (j = 0; j < 4; j++, i++) {
419 if (0 == (mac[j] = buf[i]))
420 break;
421 else if (' ' == buf[i])
422 break;
423 }
424
425 mac[j] = 0;
426
427 if (j == 4 || j < 1) {
428 if ( ! (MAN_IGN_MACRO & m->pflags)) {
429 (void)man_perr(m, ln, ppos, WMACROFORM);
430 goto err;
431 }
432 if ( ! man_pwarn(m, ln, ppos, WMACROFORM))
433 goto err;
434 return(1);
435 }
436
437 if (MAN_MAX == (c = man_hash_find(m->htab, mac))) {
438 if ( ! (MAN_IGN_MACRO & m->pflags)) {
439 (void)man_perr(m, ln, ppos, WMACRO);
440 goto err;
441 }
442 if ( ! man_pwarn(m, ln, ppos, WMACRO))
443 goto err;
444 return(1);
445 }
446
447 /* The macro is sane. Jump to the next word. */
448
449 while (buf[i] && ' ' == buf[i])
450 i++;
451
452 /* Begin recursive parse sequence. */
453
454 assert(man_macros[c].fp);
455
456 if ( ! (*man_macros[c].fp)(m, c, ln, ppos, &i, buf))
457 goto err;
458
459 out:
460 if ( ! (MAN_BLINE & fl))
461 return(1);
462
463 /*
464 * If we've opened a new next-line element scope, then return
465 * now, as the next line will close out the block scope.
466 */
467
468 if (MAN_ELINE & m->flags)
469 return(1);
470
471 /* Close out the block scope opened in the prior line. */
472
473 /* XXX - this should be in man_action.c. */
474
475 assert(MAN_BLINE & m->flags);
476 m->flags &= ~MAN_BLINE;
477
478 if ( ! man_unscope(m, m->last->parent))
479 return(0);
480 return(man_body_alloc(m, ln, 0, m->last->tok));
481
482 err: /* Error out. */
483
484 m->flags |= MAN_HALT;
485 return(0);
486 }
487
488
489 int
490 man_verr(struct man *man, int ln, int pos, const char *fmt, ...)
491 {
492 char buf[256];
493 va_list ap;
494
495 if (NULL == man->cb.man_err)
496 return(0);
497
498 va_start(ap, fmt);
499 (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
500 va_end(ap);
501 return((*man->cb.man_err)(man->data, ln, pos, buf));
502 }
503
504
505 int
506 man_vwarn(struct man *man, int ln, int pos, const char *fmt, ...)
507 {
508 char buf[256];
509 va_list ap;
510
511 if (NULL == man->cb.man_warn)
512 return(0);
513
514 va_start(ap, fmt);
515 (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
516 va_end(ap);
517 return((*man->cb.man_warn)(man->data, ln, pos, buf));
518 }
519
520
521 int
522 man_err(struct man *m, int line, int pos, int iserr, enum merr type)
523 {
524 const char *p;
525
526 p = __man_merrnames[(int)type];
527 assert(p);
528
529 if (iserr)
530 return(man_verr(m, line, pos, p));
531
532 return(man_vwarn(m, line, pos, p));
533 }