Annotation of src/usr.bin/mandoc/man_macro.c, Revision 1.2
1.2 ! schwarze 1: /* $Id: man_macro.c,v 1.15 2009/06/10 20:18:43 kristaps Exp $ */
1.1 kristaps 2: /*
1.2 ! schwarze 3: * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
1.1 kristaps 4: *
5: * Permission to use, copy, modify, and distribute this software for any
1.2 ! schwarze 6: * purpose with or without fee is hereby granted, provided that the above
! 7: * copyright notice and this permission notice appear in all copies.
1.1 kristaps 8: *
1.2 ! schwarze 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.
1.1 kristaps 16: */
17: #include <assert.h>
18: #include <ctype.h>
19: #include <stdlib.h>
20: #include <string.h>
21:
22: #include "libman.h"
23:
24: #define FL_NLINE (1 << 0)
25: #define FL_TLINE (1 << 1)
26:
27: static int man_args(struct man *, int,
28: int *, char *, char **);
29:
30: static int man_flags[MAN_MAX] = {
31: 0, /* __ */
32: 0, /* TH */
33: 0, /* SH */
34: 0, /* SS */
35: FL_TLINE, /* TP */
36: 0, /* LP */
37: 0, /* PP */
38: 0, /* P */
39: 0, /* IP */
40: 0, /* HP */
41: FL_NLINE, /* SM */
42: FL_NLINE, /* SB */
43: FL_NLINE, /* BI */
44: FL_NLINE, /* IB */
45: FL_NLINE, /* BR */
46: FL_NLINE, /* RB */
47: FL_NLINE, /* R */
48: FL_NLINE, /* B */
49: FL_NLINE, /* I */
50: FL_NLINE, /* IR */
51: FL_NLINE, /* RI */
52: 0, /* br */
53: 0, /* na */
54: FL_NLINE, /* i */
55: };
56:
57: int
58: man_macro(struct man *man, int tok, int line,
59: int ppos, int *pos, char *buf)
60: {
61: int w, la;
62: char *p;
63: struct man_node *n;
64:
65: if ( ! man_elem_alloc(man, line, ppos, tok))
66: return(0);
67: n = man->last;
68: man->next = MAN_NEXT_CHILD;
69:
70: for (;;) {
71: la = *pos;
72: w = man_args(man, line, pos, buf, &p);
73:
74: if (-1 == w)
75: return(0);
76: if (0 == w)
77: break;
78:
79: if ( ! man_word_alloc(man, line, la, p))
80: return(0);
81: man->next = MAN_NEXT_SIBLING;
82: }
83:
84: if (n == man->last && (FL_NLINE & man_flags[tok])) {
85: if (MAN_NLINE & man->flags)
86: return(man_verr(man, line, ppos,
87: "next-line scope already open"));
88: man->flags |= MAN_NLINE;
89: return(1);
90: }
91:
92: if (FL_TLINE & man_flags[tok]) {
93: if (MAN_NLINE & man->flags)
94: return(man_verr(man, line, ppos,
95: "next-line scope already open"));
96: man->flags |= MAN_NLINE;
97: return(1);
98: }
99:
100: /*
101: * Note that when TH is pruned, we'll be back at the root, so
102: * make sure that we don't clobber as its sibling.
103: */
104:
105: for ( ; man->last; man->last = man->last->parent) {
106: if (man->last == n)
107: break;
108: if (man->last->type == MAN_ROOT)
109: break;
110: if ( ! man_valid_post(man))
111: return(0);
112: if ( ! man_action_post(man))
113: return(0);
114: }
115:
116: assert(man->last);
117:
118: /*
119: * Same here regarding whether we're back at the root.
120: */
121:
122: if (man->last->type != MAN_ROOT && ! man_valid_post(man))
123: return(0);
124: if (man->last->type != MAN_ROOT && ! man_action_post(man))
125: return(0);
126: if (man->last->type != MAN_ROOT)
127: man->next = MAN_NEXT_SIBLING;
128:
129: return(1);
130: }
131:
132:
133: int
134: man_macroend(struct man *m)
135: {
136:
137: for ( ; m->last && m->last != m->first;
138: m->last = m->last->parent) {
139: if ( ! man_valid_post(m))
140: return(0);
141: if ( ! man_action_post(m))
142: return(0);
143: }
144: assert(m->last == m->first);
145:
146: if ( ! man_valid_post(m))
147: return(0);
148: if ( ! man_action_post(m))
149: return(0);
150:
151: return(1);
152: }
153:
154:
155: /* ARGSUSED */
156: static int
157: man_args(struct man *m, int line,
158: int *pos, char *buf, char **v)
159: {
160:
161: if (0 == buf[*pos])
162: return(0);
163:
164: /* First parse non-quoted strings. */
165:
166: if ('\"' != buf[*pos]) {
167: *v = &buf[*pos];
168:
169: while (buf[*pos]) {
170: if (' ' == buf[*pos])
171: if ('\\' != buf[*pos - 1])
172: break;
173: (*pos)++;
174: }
175:
176: if (0 == buf[*pos])
177: return(1);
178:
179: buf[(*pos)++] = 0;
180:
181: if (0 == buf[*pos])
182: return(1);
183:
184: while (buf[*pos] && ' ' == buf[*pos])
185: (*pos)++;
186:
187: if (buf[*pos])
188: return(1);
189:
190: if ( ! man_vwarn(m, line, *pos, "trailing spaces"))
191: return(-1);
192:
193: return(1);
194: }
195:
196: /*
197: * If we're a quoted string (and quoted strings are allowed),
198: * then parse ahead to the next quote. If none's found, it's an
199: * error. After, parse to the next word.
200: */
201:
202: *v = &buf[++(*pos)];
203:
204: while (buf[*pos] && '\"' != buf[*pos])
205: (*pos)++;
206:
207: if (0 == buf[*pos]) {
208: if ( ! man_vwarn(m, line, *pos, "unterminated quote"))
209: return(-1);
210: return(1);
211: }
212:
213: buf[(*pos)++] = 0;
214: if (0 == buf[*pos])
215: return(1);
216:
217: while (buf[*pos] && ' ' == buf[*pos])
218: (*pos)++;
219:
220: if (buf[*pos])
221: return(1);
222:
223: if ( ! man_vwarn(m, line, *pos, "trailing spaces"))
224: return(-1);
225: return(1);
226: }