]> git.cameronkatri.com Git - mandoc.git/blob - man.c
Add an option -Q (quick) to mandocdb(8)
[mandoc.git] / man.c
1 /* $Id: man.c,v 1.123 2014/01/05 20:26:36 schwarze Exp $ */
2 /*
3 * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4 * Copyright (c) 2013, 2014 Ingo Schwarze <schwarze@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21
22 #include <sys/types.h>
23
24 #include <assert.h>
25 #include <stdarg.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29
30 #include "man.h"
31 #include "mandoc.h"
32 #include "libman.h"
33 #include "libmandoc.h"
34
35 const char *const __man_macronames[MAN_MAX] = {
36 "br", "TH", "SH", "SS",
37 "TP", "LP", "PP", "P",
38 "IP", "HP", "SM", "SB",
39 "BI", "IB", "BR", "RB",
40 "R", "B", "I", "IR",
41 "RI", "na", "sp", "nf",
42 "fi", "RE", "RS", "DT",
43 "UC", "PD", "AT", "in",
44 "ft", "OP", "EX", "EE",
45 "UR", "UE"
46 };
47
48 const char * const *man_macronames = __man_macronames;
49
50 static struct man_node *man_node_alloc(struct man *, int, int,
51 enum man_type, enum mant);
52 static int man_node_append(struct man *,
53 struct man_node *);
54 static void man_node_free(struct man_node *);
55 static void man_node_unlink(struct man *,
56 struct man_node *);
57 static int man_ptext(struct man *, int, char *, int);
58 static int man_pmacro(struct man *, int, char *, int);
59 static void man_free1(struct man *);
60 static void man_alloc1(struct man *);
61 static int man_descope(struct man *, int, int);
62
63
64 const struct man_node *
65 man_node(const struct man *man)
66 {
67
68 assert( ! (MAN_HALT & man->flags));
69 return(man->first);
70 }
71
72
73 const struct man_meta *
74 man_meta(const struct man *man)
75 {
76
77 assert( ! (MAN_HALT & man->flags));
78 return(&man->meta);
79 }
80
81
82 void
83 man_reset(struct man *man)
84 {
85
86 man_free1(man);
87 man_alloc1(man);
88 }
89
90
91 void
92 man_free(struct man *man)
93 {
94
95 man_free1(man);
96 free(man);
97 }
98
99
100 struct man *
101 man_alloc(struct roff *roff, struct mparse *parse, int quick)
102 {
103 struct man *p;
104
105 p = mandoc_calloc(1, sizeof(struct man));
106
107 man_hash_init();
108 p->parse = parse;
109 p->quick = quick;
110 p->roff = roff;
111
112 man_alloc1(p);
113 return(p);
114 }
115
116
117 int
118 man_endparse(struct man *man)
119 {
120
121 assert( ! (MAN_HALT & man->flags));
122 if (man_macroend(man))
123 return(1);
124 man->flags |= MAN_HALT;
125 return(0);
126 }
127
128
129 int
130 man_parseln(struct man *man, int ln, char *buf, int offs)
131 {
132
133 man->flags |= MAN_NEWLINE;
134
135 assert( ! (MAN_HALT & man->flags));
136
137 return (roff_getcontrol(man->roff, buf, &offs) ?
138 man_pmacro(man, ln, buf, offs) :
139 man_ptext(man, ln, buf, offs));
140 }
141
142
143 static void
144 man_free1(struct man *man)
145 {
146
147 if (man->first)
148 man_node_delete(man, man->first);
149 if (man->meta.title)
150 free(man->meta.title);
151 if (man->meta.source)
152 free(man->meta.source);
153 if (man->meta.date)
154 free(man->meta.date);
155 if (man->meta.vol)
156 free(man->meta.vol);
157 if (man->meta.msec)
158 free(man->meta.msec);
159 }
160
161
162 static void
163 man_alloc1(struct man *man)
164 {
165
166 memset(&man->meta, 0, sizeof(struct man_meta));
167 man->flags = 0;
168 man->last = mandoc_calloc(1, sizeof(struct man_node));
169 man->first = man->last;
170 man->last->type = MAN_ROOT;
171 man->last->tok = MAN_MAX;
172 man->next = MAN_NEXT_CHILD;
173 }
174
175
176 static int
177 man_node_append(struct man *man, struct man_node *p)
178 {
179
180 assert(man->last);
181 assert(man->first);
182 assert(MAN_ROOT != p->type);
183
184 switch (man->next) {
185 case (MAN_NEXT_SIBLING):
186 man->last->next = p;
187 p->prev = man->last;
188 p->parent = man->last->parent;
189 break;
190 case (MAN_NEXT_CHILD):
191 man->last->child = p;
192 p->parent = man->last;
193 break;
194 default:
195 abort();
196 /* NOTREACHED */
197 }
198
199 assert(p->parent);
200 p->parent->nchild++;
201
202 if ( ! man_valid_pre(man, p))
203 return(0);
204
205 switch (p->type) {
206 case (MAN_HEAD):
207 assert(MAN_BLOCK == p->parent->type);
208 p->parent->head = p;
209 break;
210 case (MAN_TAIL):
211 assert(MAN_BLOCK == p->parent->type);
212 p->parent->tail = p;
213 break;
214 case (MAN_BODY):
215 assert(MAN_BLOCK == p->parent->type);
216 p->parent->body = p;
217 break;
218 default:
219 break;
220 }
221
222 man->last = p;
223
224 switch (p->type) {
225 case (MAN_TBL):
226 /* FALLTHROUGH */
227 case (MAN_TEXT):
228 if ( ! man_valid_post(man))
229 return(0);
230 break;
231 default:
232 break;
233 }
234
235 return(1);
236 }
237
238
239 static struct man_node *
240 man_node_alloc(struct man *man, int line, int pos,
241 enum man_type type, enum mant tok)
242 {
243 struct man_node *p;
244
245 p = mandoc_calloc(1, sizeof(struct man_node));
246 p->line = line;
247 p->pos = pos;
248 p->type = type;
249 p->tok = tok;
250
251 if (MAN_NEWLINE & man->flags)
252 p->flags |= MAN_LINE;
253 man->flags &= ~MAN_NEWLINE;
254 return(p);
255 }
256
257
258 int
259 man_elem_alloc(struct man *man, int line, int pos, enum mant tok)
260 {
261 struct man_node *p;
262
263 p = man_node_alloc(man, line, pos, MAN_ELEM, tok);
264 if ( ! man_node_append(man, p))
265 return(0);
266 man->next = MAN_NEXT_CHILD;
267 return(1);
268 }
269
270
271 int
272 man_tail_alloc(struct man *man, int line, int pos, enum mant tok)
273 {
274 struct man_node *p;
275
276 p = man_node_alloc(man, line, pos, MAN_TAIL, tok);
277 if ( ! man_node_append(man, p))
278 return(0);
279 man->next = MAN_NEXT_CHILD;
280 return(1);
281 }
282
283
284 int
285 man_head_alloc(struct man *man, int line, int pos, enum mant tok)
286 {
287 struct man_node *p;
288
289 p = man_node_alloc(man, line, pos, MAN_HEAD, tok);
290 if ( ! man_node_append(man, p))
291 return(0);
292 man->next = MAN_NEXT_CHILD;
293 return(1);
294 }
295
296
297 int
298 man_body_alloc(struct man *man, int line, int pos, enum mant tok)
299 {
300 struct man_node *p;
301
302 p = man_node_alloc(man, line, pos, MAN_BODY, tok);
303 if ( ! man_node_append(man, p))
304 return(0);
305 man->next = MAN_NEXT_CHILD;
306 return(1);
307 }
308
309
310 int
311 man_block_alloc(struct man *man, int line, int pos, enum mant tok)
312 {
313 struct man_node *p;
314
315 p = man_node_alloc(man, line, pos, MAN_BLOCK, tok);
316 if ( ! man_node_append(man, p))
317 return(0);
318 man->next = MAN_NEXT_CHILD;
319 return(1);
320 }
321
322 int
323 man_word_alloc(struct man *man, int line, int pos, const char *word)
324 {
325 struct man_node *n;
326
327 n = man_node_alloc(man, line, pos, MAN_TEXT, MAN_MAX);
328 n->string = roff_strdup(man->roff, word);
329
330 if ( ! man_node_append(man, n))
331 return(0);
332
333 man->next = MAN_NEXT_SIBLING;
334 return(1);
335 }
336
337
338 /*
339 * Free all of the resources held by a node. This does NOT unlink a
340 * node from its context; for that, see man_node_unlink().
341 */
342 static void
343 man_node_free(struct man_node *p)
344 {
345
346 if (p->string)
347 free(p->string);
348 free(p);
349 }
350
351
352 void
353 man_node_delete(struct man *man, struct man_node *p)
354 {
355
356 while (p->child)
357 man_node_delete(man, p->child);
358
359 man_node_unlink(man, p);
360 man_node_free(p);
361 }
362
363 int
364 man_addeqn(struct man *man, const struct eqn *ep)
365 {
366 struct man_node *n;
367
368 assert( ! (MAN_HALT & man->flags));
369
370 n = man_node_alloc(man, ep->ln, ep->pos, MAN_EQN, MAN_MAX);
371 n->eqn = ep;
372
373 if ( ! man_node_append(man, n))
374 return(0);
375
376 man->next = MAN_NEXT_SIBLING;
377 return(man_descope(man, ep->ln, ep->pos));
378 }
379
380 int
381 man_addspan(struct man *man, const struct tbl_span *sp)
382 {
383 struct man_node *n;
384
385 assert( ! (MAN_HALT & man->flags));
386
387 n = man_node_alloc(man, sp->line, 0, MAN_TBL, MAN_MAX);
388 n->span = sp;
389
390 if ( ! man_node_append(man, n))
391 return(0);
392
393 man->next = MAN_NEXT_SIBLING;
394 return(man_descope(man, sp->line, 0));
395 }
396
397 static int
398 man_descope(struct man *man, int line, int offs)
399 {
400 /*
401 * Co-ordinate what happens with having a next-line scope open:
402 * first close out the element scope (if applicable), then close
403 * out the block scope (also if applicable).
404 */
405
406 if (MAN_ELINE & man->flags) {
407 man->flags &= ~MAN_ELINE;
408 if ( ! man_unscope(man, man->last->parent, MANDOCERR_MAX))
409 return(0);
410 }
411
412 if ( ! (MAN_BLINE & man->flags))
413 return(1);
414 man->flags &= ~MAN_BLINE;
415
416 if ( ! man_unscope(man, man->last->parent, MANDOCERR_MAX))
417 return(0);
418 return(man_body_alloc(man, line, offs, man->last->tok));
419 }
420
421 static int
422 man_ptext(struct man *man, int line, char *buf, int offs)
423 {
424 int i;
425
426 /* Literal free-form text whitespace is preserved. */
427
428 if (MAN_LITERAL & man->flags) {
429 if ( ! man_word_alloc(man, line, offs, buf + offs))
430 return(0);
431 return(man_descope(man, line, offs));
432 }
433
434 for (i = offs; ' ' == buf[i]; i++)
435 /* Skip leading whitespace. */ ;
436
437 /*
438 * Blank lines are ignored right after headings
439 * but add a single vertical space elsewhere.
440 */
441
442 if ('\0' == buf[i]) {
443 /* Allocate a blank entry. */
444 if (MAN_SH != man->last->tok &&
445 MAN_SS != man->last->tok) {
446 if ( ! man_elem_alloc(man, line, offs, MAN_sp))
447 return(0);
448 man->next = MAN_NEXT_SIBLING;
449 }
450 return(1);
451 }
452
453 /*
454 * Warn if the last un-escaped character is whitespace. Then
455 * strip away the remaining spaces (tabs stay!).
456 */
457
458 i = (int)strlen(buf);
459 assert(i);
460
461 if (' ' == buf[i - 1] || '\t' == buf[i - 1]) {
462 if (i > 1 && '\\' != buf[i - 2])
463 man_pmsg(man, line, i - 1, MANDOCERR_EOLNSPACE);
464
465 for (--i; i && ' ' == buf[i]; i--)
466 /* Spin back to non-space. */ ;
467
468 /* Jump ahead of escaped whitespace. */
469 i += '\\' == buf[i] ? 2 : 1;
470
471 buf[i] = '\0';
472 }
473
474 if ( ! man_word_alloc(man, line, offs, buf + offs))
475 return(0);
476
477 /*
478 * End-of-sentence check. If the last character is an unescaped
479 * EOS character, then flag the node as being the end of a
480 * sentence. The front-end will know how to interpret this.
481 */
482
483 assert(i);
484 if (mandoc_eos(buf, (size_t)i))
485 man->last->flags |= MAN_EOS;
486
487 return(man_descope(man, line, offs));
488 }
489
490 static int
491 man_pmacro(struct man *man, int ln, char *buf, int offs)
492 {
493 int i, ppos;
494 enum mant tok;
495 char mac[5];
496 struct man_node *n;
497
498 if ('"' == buf[offs]) {
499 man_pmsg(man, ln, offs, MANDOCERR_BADCOMMENT);
500 return(1);
501 } else if ('\0' == buf[offs])
502 return(1);
503
504 ppos = offs;
505
506 /*
507 * Copy the first word into a nil-terminated buffer.
508 * Stop copying when a tab, space, or eoln is encountered.
509 */
510
511 i = 0;
512 while (i < 4 && '\0' != buf[offs] &&
513 ' ' != buf[offs] && '\t' != buf[offs])
514 mac[i++] = buf[offs++];
515
516 mac[i] = '\0';
517
518 tok = (i > 0 && i < 4) ? man_hash_find(mac) : MAN_MAX;
519
520 if (MAN_MAX == tok) {
521 mandoc_vmsg(MANDOCERR_MACRO, man->parse, ln,
522 ppos, "%s", buf + ppos - 1);
523 return(1);
524 }
525
526 /* The macro is sane. Jump to the next word. */
527
528 while (buf[offs] && ' ' == buf[offs])
529 offs++;
530
531 /*
532 * Trailing whitespace. Note that tabs are allowed to be passed
533 * into the parser as "text", so we only warn about spaces here.
534 */
535
536 if ('\0' == buf[offs] && ' ' == buf[offs - 1])
537 man_pmsg(man, ln, offs - 1, MANDOCERR_EOLNSPACE);
538
539 /*
540 * Remove prior ELINE macro, as it's being clobbered by a new
541 * macro. Note that NSCOPED macros do not close out ELINE
542 * macros---they don't print text---so we let those slip by.
543 */
544
545 if ( ! (MAN_NSCOPED & man_macros[tok].flags) &&
546 man->flags & MAN_ELINE) {
547 n = man->last;
548 assert(MAN_TEXT != n->type);
549
550 /* Remove repeated NSCOPED macros causing ELINE. */
551
552 if (MAN_NSCOPED & man_macros[n->tok].flags)
553 n = n->parent;
554
555 mandoc_vmsg(MANDOCERR_LINESCOPE, man->parse, n->line,
556 n->pos, "%s breaks %s", man_macronames[tok],
557 man_macronames[n->tok]);
558
559 man_node_delete(man, n);
560 man->flags &= ~MAN_ELINE;
561 }
562
563 /*
564 * Remove prior BLINE macro that is being clobbered.
565 */
566 if ((man->flags & MAN_BLINE) &&
567 (MAN_BSCOPE & man_macros[tok].flags)) {
568 n = man->last;
569
570 /* Might be a text node like 8 in
571 * .TP 8
572 * .SH foo
573 */
574 if (MAN_TEXT == n->type)
575 n = n->parent;
576
577 /* Remove element that didn't end BLINE, if any. */
578 if ( ! (MAN_BSCOPE & man_macros[n->tok].flags))
579 n = n->parent;
580
581 assert(MAN_HEAD == n->type);
582 n = n->parent;
583 assert(MAN_BLOCK == n->type);
584 assert(MAN_SCOPED & man_macros[n->tok].flags);
585
586 mandoc_vmsg(MANDOCERR_LINESCOPE, man->parse, n->line,
587 n->pos, "%s breaks %s", man_macronames[tok],
588 man_macronames[n->tok]);
589
590 man_node_delete(man, n);
591 man->flags &= ~MAN_BLINE;
592 }
593
594 /*
595 * Save the fact that we're in the next-line for a block. In
596 * this way, embedded roff instructions can "remember" state
597 * when they exit.
598 */
599
600 if (MAN_BLINE & man->flags)
601 man->flags |= MAN_BPLINE;
602
603 /* Call to handler... */
604
605 assert(man_macros[tok].fp);
606 if ( ! (*man_macros[tok].fp)(man, tok, ln, ppos, &offs, buf))
607 goto err;
608
609 /* In quick mode (for mandocdb), abort after the NAME section. */
610
611 if (man->quick && MAN_SH == tok &&
612 strcmp(man->last->prev->child->string, "NAME"))
613 return(2);
614
615 /*
616 * We weren't in a block-line scope when entering the
617 * above-parsed macro, so return.
618 */
619
620 if ( ! (MAN_BPLINE & man->flags)) {
621 man->flags &= ~MAN_ILINE;
622 return(1);
623 }
624 man->flags &= ~MAN_BPLINE;
625
626 /*
627 * If we're in a block scope, then allow this macro to slip by
628 * without closing scope around it.
629 */
630
631 if (MAN_ILINE & man->flags) {
632 man->flags &= ~MAN_ILINE;
633 return(1);
634 }
635
636 /*
637 * If we've opened a new next-line element scope, then return
638 * now, as the next line will close out the block scope.
639 */
640
641 if (MAN_ELINE & man->flags)
642 return(1);
643
644 /* Close out the block scope opened in the prior line. */
645
646 assert(MAN_BLINE & man->flags);
647 man->flags &= ~MAN_BLINE;
648
649 if ( ! man_unscope(man, man->last->parent, MANDOCERR_MAX))
650 return(0);
651 return(man_body_alloc(man, ln, ppos, man->last->tok));
652
653 err: /* Error out. */
654
655 man->flags |= MAN_HALT;
656 return(0);
657 }
658
659 /*
660 * Unlink a node from its context. If "man" is provided, the last parse
661 * point will also be adjusted accordingly.
662 */
663 static void
664 man_node_unlink(struct man *man, struct man_node *n)
665 {
666
667 /* Adjust siblings. */
668
669 if (n->prev)
670 n->prev->next = n->next;
671 if (n->next)
672 n->next->prev = n->prev;
673
674 /* Adjust parent. */
675
676 if (n->parent) {
677 n->parent->nchild--;
678 if (n->parent->child == n)
679 n->parent->child = n->prev ? n->prev : n->next;
680 }
681
682 /* Adjust parse point, if applicable. */
683
684 if (man && man->last == n) {
685 /*XXX: this can occur when bailing from validation. */
686 /*assert(NULL == n->next);*/
687 if (n->prev) {
688 man->last = n->prev;
689 man->next = MAN_NEXT_SIBLING;
690 } else {
691 man->last = n->parent;
692 man->next = MAN_NEXT_CHILD;
693 }
694 }
695
696 if (man && man->first == n)
697 man->first = NULL;
698 }
699
700 const struct mparse *
701 man_mparse(const struct man *man)
702 {
703
704 assert(man && man->parse);
705 return(man->parse);
706 }