]> git.cameronkatri.com Git - mandoc.git/blob - mdoc.c
Expanded perfect htab to use 27 * 26 * 3 space.
[mandoc.git] / mdoc.c
1 /* $Id: mdoc.c,v 1.61 2009/03/11 00:39:58 kristaps Exp $ */
2 /*
3 * Copyright (c) 2008 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
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 "private.h"
28
29 /*
30 * Main caller in the libmdoc library. This begins the parsing routine,
31 * handles allocation of data, and so forth. Most of the "work" is done
32 * in macro.c and validate.c.
33 */
34
35 static struct mdoc_node *mdoc_node_alloc(const struct mdoc *);
36 static int mdoc_node_append(struct mdoc *,
37 struct mdoc_node *);
38
39 static int parsetext(struct mdoc *, int, char *);
40 static int parsemacro(struct mdoc *, int, char *);
41 static int macrowarn(struct mdoc *, int, const char *);
42
43
44 const char *const __mdoc_macronames[MDOC_MAX] = {
45 "\\\"", "Dd", "Dt", "Os",
46 "Sh", "Ss", "Pp", "D1",
47 "Dl", "Bd", "Ed", "Bl",
48 "El", "It", "Ad", "An",
49 "Ar", "Cd", "Cm", "Dv",
50 "Er", "Ev", "Ex", "Fa",
51 "Fd", "Fl", "Fn", "Ft",
52 "Ic", "In", "Li", "Nd",
53 "Nm", "Op", "Ot", "Pa",
54 "Rv", "St", "Va", "Vt",
55 /* LINTED */
56 "Xr", "\%A", "\%B", "\%D",
57 /* LINTED */
58 "\%I", "\%J", "\%N", "\%O",
59 /* LINTED */
60 "\%P", "\%R", "\%T", "\%V",
61 "Ac", "Ao", "Aq", "At",
62 "Bc", "Bf", "Bo", "Bq",
63 "Bsx", "Bx", "Db", "Dc",
64 "Do", "Dq", "Ec", "Ef",
65 "Em", "Eo", "Fx", "Ms",
66 "No", "Ns", "Nx", "Ox",
67 "Pc", "Pf", "Po", "Pq",
68 "Qc", "Ql", "Qo", "Qq",
69 "Re", "Rs", "Sc", "So",
70 "Sq", "Sm", "Sx", "Sy",
71 "Tn", "Ux", "Xc", "Xo",
72 "Fo", "Fc", "Oo", "Oc",
73 "Bk", "Ek", "Bt", "Hf",
74 "Fr", "Ud", "Lb", "Ap",
75 "Lp", "Lk", "Mt", "Brq",
76 "Bro", "Brc"
77 };
78
79 const char *const __mdoc_argnames[MDOC_ARG_MAX] = {
80 "split", "nosplit", "ragged",
81 "unfilled", "literal", "file",
82 "offset", "bullet", "dash",
83 "hyphen", "item", "enum",
84 "tag", "diag", "hang",
85 "ohang", "inset", "column",
86 "width", "compact", "std",
87 "filled", "words", "emphasis",
88 "symbolic"
89 };
90
91 const char * const *mdoc_macronames = __mdoc_macronames;
92 const char * const *mdoc_argnames = __mdoc_argnames;
93
94
95 const struct mdoc_node *
96 mdoc_node(const struct mdoc *mdoc)
97 {
98
99 return(mdoc->first);
100 }
101
102
103 const struct mdoc_meta *
104 mdoc_meta(const struct mdoc *mdoc)
105 {
106
107 return(&mdoc->meta);
108 }
109
110
111 void
112 mdoc_free(struct mdoc *mdoc)
113 {
114
115 if (mdoc->first)
116 mdoc_node_freelist(mdoc->first);
117 if (mdoc->htab)
118 mdoc_tokhash_free(mdoc->htab);
119 if (mdoc->meta.title)
120 free(mdoc->meta.title);
121 if (mdoc->meta.os)
122 free(mdoc->meta.os);
123 if (mdoc->meta.name)
124 free(mdoc->meta.name);
125 if (mdoc->meta.arch)
126 free(mdoc->meta.arch);
127 if (mdoc->meta.vol)
128 free(mdoc->meta.vol);
129
130 free(mdoc);
131 }
132
133
134 struct mdoc *
135 mdoc_alloc(void *data, int pflags, const struct mdoc_cb *cb)
136 {
137 struct mdoc *p;
138
139 p = xcalloc(1, sizeof(struct mdoc));
140
141 p->data = data;
142 if (cb)
143 (void)memcpy(&p->cb, cb, sizeof(struct mdoc_cb));
144
145 p->last = xcalloc(1, sizeof(struct mdoc_node));
146 p->last->type = MDOC_ROOT;
147 p->first = p->last;
148 p->pflags = pflags;
149 p->next = MDOC_NEXT_CHILD;
150 p->htab = mdoc_tokhash_alloc();
151
152 return(p);
153 }
154
155
156 int
157 mdoc_endparse(struct mdoc *mdoc)
158 {
159
160 if (MDOC_HALT & mdoc->flags)
161 return(0);
162 if (NULL == mdoc->first)
163 return(1);
164
165 assert(mdoc->last);
166 if ( ! macro_end(mdoc)) {
167 mdoc->flags |= MDOC_HALT;
168 return(0);
169 }
170 return(1);
171 }
172
173
174 /*
175 * Main parse routine. Parses a single line -- really just hands off to
176 * the macro or text parser.
177 */
178 int
179 mdoc_parseln(struct mdoc *m, int ln, char *buf)
180 {
181
182 /* If in error-mode, then we parse no more. */
183
184 if (MDOC_HALT & m->flags)
185 return(0);
186
187 return('.' == *buf ? parsemacro(m, ln, buf) :
188 parsetext(m, ln, buf));
189 }
190
191
192 void
193 mdoc_vmsg(struct mdoc *mdoc, int ln, int pos, const char *fmt, ...)
194 {
195 char buf[256];
196 va_list ap;
197
198 if (NULL == mdoc->cb.mdoc_msg)
199 return;
200
201 va_start(ap, fmt);
202 (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
203 va_end(ap);
204 (*mdoc->cb.mdoc_msg)(mdoc->data, ln, pos, buf);
205 }
206
207
208 int
209 mdoc_verr(struct mdoc *mdoc, int ln, int pos,
210 const char *fmt, ...)
211 {
212 char buf[256];
213 va_list ap;
214
215 if (NULL == mdoc->cb.mdoc_err)
216 return(0);
217
218 va_start(ap, fmt);
219 (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
220 va_end(ap);
221 return((*mdoc->cb.mdoc_err)(mdoc->data, ln, pos, buf));
222 }
223
224
225 int
226 mdoc_vwarn(struct mdoc *mdoc, int ln, int pos,
227 enum mdoc_warn type, const char *fmt, ...)
228 {
229 char buf[256];
230 va_list ap;
231
232 if (NULL == mdoc->cb.mdoc_warn)
233 return(0);
234
235 va_start(ap, fmt);
236 (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
237 va_end(ap);
238 return((*mdoc->cb.mdoc_warn)(mdoc->data, ln, pos, type, buf));
239 }
240
241
242 int
243 mdoc_macro(struct mdoc *m, int tok,
244 int ln, int pp, int *pos, char *buf)
245 {
246
247 /* FIXME - these should happen during validation. */
248
249 if (MDOC_PROLOGUE & mdoc_macros[tok].flags &&
250 SEC_PROLOGUE != m->lastnamed)
251 return(mdoc_perr(m, ln, pp,
252 "disallowed in document body"));
253
254 if ( ! (MDOC_PROLOGUE & mdoc_macros[tok].flags) &&
255 SEC_PROLOGUE == m->lastnamed)
256 return(mdoc_perr(m, ln, pp,
257 "disallowed in prologue"));
258
259 if (1 != pp && ! (MDOC_CALLABLE & mdoc_macros[tok].flags))
260 return(mdoc_perr(m, ln, pp, "not callable"));
261
262 return((*mdoc_macros[tok].fp)(m, tok, ln, pp, pos, buf));
263 }
264
265
266 static int
267 mdoc_node_append(struct mdoc *mdoc, struct mdoc_node *p)
268 {
269
270 assert(mdoc->last);
271 assert(mdoc->first);
272 assert(MDOC_ROOT != p->type);
273
274 switch (mdoc->next) {
275 case (MDOC_NEXT_SIBLING):
276 mdoc->last->next = p;
277 p->prev = mdoc->last;
278 p->parent = mdoc->last->parent;
279 break;
280 case (MDOC_NEXT_CHILD):
281 mdoc->last->child = p;
282 p->parent = mdoc->last;
283 break;
284 default:
285 abort();
286 /* NOTREACHED */
287 }
288
289 if ( ! mdoc_valid_pre(mdoc, p))
290 return(0);
291
292 switch (p->type) {
293 case (MDOC_HEAD):
294 assert(MDOC_BLOCK == p->parent->type);
295 p->parent->head = p;
296 break;
297 case (MDOC_TAIL):
298 assert(MDOC_BLOCK == p->parent->type);
299 p->parent->tail = p;
300 break;
301 case (MDOC_BODY):
302 assert(MDOC_BLOCK == p->parent->type);
303 p->parent->body = p;
304 break;
305 default:
306 break;
307 }
308
309 mdoc->last = p;
310 return(1);
311 }
312
313
314 static struct mdoc_node *
315 mdoc_node_alloc(const struct mdoc *mdoc)
316 {
317 struct mdoc_node *p;
318
319 p = xcalloc(1, sizeof(struct mdoc_node));
320 p->sec = mdoc->lastsec;
321
322 return(p);
323 }
324
325
326 int
327 mdoc_tail_alloc(struct mdoc *mdoc, int line, int pos, int tok)
328 {
329 struct mdoc_node *p;
330
331 assert(mdoc->first);
332 assert(mdoc->last);
333
334 p = mdoc_node_alloc(mdoc);
335
336 p->line = line;
337 p->pos = pos;
338 p->type = MDOC_TAIL;
339 p->tok = tok;
340
341 return(mdoc_node_append(mdoc, p));
342 }
343
344
345 int
346 mdoc_head_alloc(struct mdoc *mdoc, int line, int pos, int tok)
347 {
348 struct mdoc_node *p;
349
350 assert(mdoc->first);
351 assert(mdoc->last);
352
353 p = mdoc_node_alloc(mdoc);
354
355 p->line = line;
356 p->pos = pos;
357 p->type = MDOC_HEAD;
358 p->tok = tok;
359
360 return(mdoc_node_append(mdoc, p));
361 }
362
363
364 int
365 mdoc_body_alloc(struct mdoc *mdoc, int line, int pos, int tok)
366 {
367 struct mdoc_node *p;
368
369 assert(mdoc->first);
370 assert(mdoc->last);
371
372 p = mdoc_node_alloc(mdoc);
373
374 p->line = line;
375 p->pos = pos;
376 p->type = MDOC_BODY;
377 p->tok = tok;
378
379 return(mdoc_node_append(mdoc, p));
380 }
381
382
383 int
384 mdoc_root_alloc(struct mdoc *mdoc)
385 {
386 struct mdoc_node *p;
387
388 p = mdoc_node_alloc(mdoc);
389
390 p->type = MDOC_ROOT;
391
392 return(mdoc_node_append(mdoc, p));
393 }
394
395
396 int
397 mdoc_block_alloc(struct mdoc *mdoc, int line, int pos,
398 int tok, struct mdoc_arg *args)
399 {
400 struct mdoc_node *p;
401
402 p = mdoc_node_alloc(mdoc);
403
404 p->pos = pos;
405 p->line = line;
406 p->type = MDOC_BLOCK;
407 p->tok = tok;
408 p->args = args;
409
410 if (args)
411 (args->refcnt)++;
412
413 return(mdoc_node_append(mdoc, p));
414 }
415
416
417 int
418 mdoc_elem_alloc(struct mdoc *mdoc, int line, int pos,
419 int tok, struct mdoc_arg *args)
420 {
421 struct mdoc_node *p;
422
423 p = mdoc_node_alloc(mdoc);
424
425 p->line = line;
426 p->pos = pos;
427 p->type = MDOC_ELEM;
428 p->tok = tok;
429 p->args = args;
430
431 if (args)
432 (args->refcnt)++;
433
434 return(mdoc_node_append(mdoc, p));
435 }
436
437
438 int
439 mdoc_word_alloc(struct mdoc *mdoc,
440 int line, int pos, const char *word)
441 {
442 struct mdoc_node *p;
443
444 p = mdoc_node_alloc(mdoc);
445
446 p->line = line;
447 p->pos = pos;
448 p->type = MDOC_TEXT;
449 p->string = xstrdup(word);
450
451 return(mdoc_node_append(mdoc, p));
452 }
453
454
455 void
456 mdoc_node_free(struct mdoc_node *p)
457 {
458
459 if (p->string)
460 free(p->string);
461 if (p->args)
462 mdoc_argv_free(p->args);
463 free(p);
464 }
465
466
467 void
468 mdoc_node_freelist(struct mdoc_node *p)
469 {
470
471 if (p->child)
472 mdoc_node_freelist(p->child);
473 if (p->next)
474 mdoc_node_freelist(p->next);
475
476 mdoc_node_free(p);
477 }
478
479
480 /*
481 * Parse free-form text, that is, a line that does not begin with the
482 * control character.
483 */
484 static int
485 parsetext(struct mdoc *mdoc, int line, char *buf)
486 {
487
488 if (SEC_PROLOGUE == mdoc->lastnamed)
489 return(mdoc_perr(mdoc, line, 0,
490 "text disallowed in prologue"));
491
492 if ( ! mdoc_word_alloc(mdoc, line, 0, buf))
493 return(0);
494
495 mdoc->next = MDOC_NEXT_SIBLING;
496 return(1);
497 }
498
499
500 static int
501 macrowarn(struct mdoc *m, int ln, const char *buf)
502 {
503 if ( ! (MDOC_IGN_MACRO & m->pflags))
504 return(mdoc_perr(m, ln, 1, "unknown macro: %s%s",
505 buf, strlen(buf) > 3 ? "..." : ""));
506 return(mdoc_pwarn(m, ln, 1, WARN_SYNTAX,
507 "unknown macro: %s%s",
508 buf, strlen(buf) > 3 ? "..." : ""));
509 }
510
511
512
513 /*
514 * Parse a macro line, that is, a line beginning with the control
515 * character.
516 */
517 int
518 parsemacro(struct mdoc *m, int ln, char *buf)
519 {
520 int i, c;
521 char mac[5];
522
523 /* Comments are quickly ignored. */
524
525 if (buf[1] && '\\' == buf[1])
526 if (buf[2] && '\"' == buf[2])
527 return(1);
528
529 /* Copy the first word into a nil-terminated buffer. */
530
531 for (i = 1; i < 5; i++) {
532 if (0 == (mac[i - 1] = buf[i]))
533 break;
534 else if (isspace((unsigned char)buf[i]))
535 break;
536 }
537
538 /* FIXME: be able to skip unknown macro lines! */
539
540 mac[i - 1] = 0;
541
542 if (i == 5 || i <= 2) {
543 if ( ! macrowarn(m, ln, mac))
544 goto err;
545 return(1);
546 }
547
548 if (MDOC_MAX == (c = mdoc_tokhash_find(m->htab, mac))) {
549 if ( ! macrowarn(m, ln, mac))
550 goto err;
551 return(1);
552 }
553
554 /* The macro is sane. Jump to the next word. */
555
556 while (buf[i] && isspace((unsigned char)buf[i]))
557 i++;
558
559 /* Begin recursive parse sequence. */
560
561 if ( ! mdoc_macro(m, c, ln, 1, &i, buf))
562 goto err;
563
564 return(1);
565
566 err: /* Error out. */
567
568 m->flags |= MDOC_HALT;
569 return(0);
570 }