Annotation of mandoc/macro.c, Revision 1.5
1.5 ! kristaps 1: /* $Id: macro.c,v 1.4 2008/12/15 03:13:01 kristaps Exp $ */
1.1 kristaps 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: */
1.2 kristaps 19: #include <assert.h>
20: #include <ctype.h>
1.1 kristaps 21: #include <stdlib.h>
1.2 kristaps 22: #include <stdio.h>
1.5 ! kristaps 23: #include <string.h>
1.2 kristaps 24:
25: #include "private.h"
26:
1.3 kristaps 27: #define _CC(p) ((const char **)p)
1.2 kristaps 28:
1.5 ! kristaps 29: static int xstrlcat(char *, const char *, size_t);
! 30: static int xstrlcpy(char *, const char *, size_t);
! 31: static int xstrcmp(const char *, const char *);
1.3 kristaps 32: static int append_text(struct mdoc *, int,
33: int, int, char *[]);
34: static int append_scoped(struct mdoc *, int,
35: int, int, char *[]);
36: static int args_next(struct mdoc *, int,
37: int *, char *, char **);
1.1 kristaps 38:
39:
40: static int
1.2 kristaps 41: args_next(struct mdoc *mdoc, int tok,
42: int *pos, char *buf, char **v)
1.1 kristaps 43: {
44:
45: if (0 == buf[*pos])
46: return(0);
47:
1.2 kristaps 48: assert( ! isspace(buf[*pos]));
49:
1.1 kristaps 50: if ('\"' == buf[*pos]) {
1.2 kristaps 51: (void)mdoc_err(mdoc, tok, *pos, ERR_SYNTAX_QUOTE);
1.1 kristaps 52: return(-1);
53: }
54:
55: *v = &buf[*pos];
56:
1.2 kristaps 57: /* Scan ahead to end of token. */
58:
1.1 kristaps 59: while (buf[*pos] && ! isspace(buf[*pos]))
60: (*pos)++;
61:
1.2 kristaps 62: if (buf[*pos] && buf[*pos + 1] && '\\' == buf[*pos]) {
63: (void)mdoc_err(mdoc, tok, *pos, ERR_SYNTAX_WS);
1.1 kristaps 64: return(-1);
65: }
66:
1.2 kristaps 67: if (0 == buf[*pos])
68: return(1);
69:
70: /* Scan ahead over trailing whitespace. */
71:
72: buf[(*pos)++] = 0;
73: while (buf[*pos] && isspace(buf[*pos]))
74: (*pos)++;
75:
76: if (0 == buf[*pos])
77: if ( ! mdoc_warn(mdoc, tok, *pos, WARN_SYNTAX_WS_EOLN))
78: return(-1);
79:
1.1 kristaps 80: return(1);
81: }
82:
1.2 kristaps 83:
84: static int
1.3 kristaps 85: append_scoped(struct mdoc *mdoc, int tok,
86: int pos, int sz, char *args[])
1.2 kristaps 87: {
1.5 ! kristaps 88: enum mdoc_sec sec;
! 89:
! 90: if (0 == sz)
! 91: return(mdoc_err(mdoc, tok, pos, ERR_ARGS_GE1));
1.2 kristaps 92:
1.4 kristaps 93: switch (tok) {
94: /* ======= ADD MORE MACRO CHECKS BELOW. ======= */
95: case (MDOC_Sh):
1.5 ! kristaps 96: sec = mdoc_atosec((size_t)sz, _CC(args));
! 97: if (SEC_CUSTOM != sec && sec < mdoc->sec_lastn)
! 98: if ( ! mdoc_warn(mdoc, tok, pos, WARN_SEC_OO))
! 99: return(0);
! 100:
! 101: if (SEC_BODY == mdoc->sec_last && SEC_NAME != sec)
! 102: return(mdoc_err(mdoc, tok, pos, ERR_SEC_NAME));
! 103:
! 104: if (SEC_CUSTOM != sec)
! 105: mdoc->sec_lastn = sec;
! 106: mdoc->sec_last = sec;
1.4 kristaps 107: break;
108: case (MDOC_Ss):
109: break;
110: /* ======= ADD MORE MACRO CHECKS ABOVE. ======= */
111: default:
112: abort();
113: /* NOTREACHED */
114: }
115:
1.3 kristaps 116: assert(sz >= 0);
1.2 kristaps 117: args[sz] = NULL;
118: mdoc_block_alloc(mdoc, pos, tok, 0, NULL);
1.3 kristaps 119: mdoc_head_alloc(mdoc, pos, tok, (size_t)sz, _CC(args));
1.2 kristaps 120: mdoc_body_alloc(mdoc, pos, tok);
121: return(1);
122: }
123:
124:
1.1 kristaps 125: static int
1.3 kristaps 126: append_text(struct mdoc *mdoc, int tok,
127: int pos, int sz, char *args[])
1.1 kristaps 128: {
129:
1.3 kristaps 130: assert(sz >= 0);
1.2 kristaps 131: args[sz] = NULL;
132:
133: switch (tok) {
1.4 kristaps 134: /* ======= ADD MORE MACRO CHECKS BELOW. ======= */
1.2 kristaps 135: case (MDOC_Ft):
136: /* FALLTHROUGH */
137: case (MDOC_Li):
138: /* FALLTHROUGH */
139: case (MDOC_Ms):
140: /* FALLTHROUGH */
141: case (MDOC_Pa):
142: /* FALLTHROUGH */
143: case (MDOC_Tn):
1.4 kristaps 144: if (0 < sz)
145: break;
146: if ( ! mdoc_warn(mdoc, tok, pos, WARN_ARGS_GE1))
1.1 kristaps 147: return(0);
1.4 kristaps 148: break;
1.2 kristaps 149: case (MDOC_Ar):
150: /* FALLTHROUGH */
151: case (MDOC_Cm):
152: /* FALLTHROUGH */
153: case (MDOC_Fl):
1.4 kristaps 154: break;
1.2 kristaps 155: case (MDOC_Ad):
156: /* FALLTHROUGH */
157: case (MDOC_Em):
158: /* FALLTHROUGH */
159: case (MDOC_Er):
160: /* FALLTHROUGH */
161: case (MDOC_Ev):
162: /* FALLTHROUGH */
163: case (MDOC_Fa):
164: /* FALLTHROUGH */
165: case (MDOC_Dv):
166: /* FALLTHROUGH */
167: case (MDOC_Ic):
168: /* FALLTHROUGH */
169: case (MDOC_Va):
170: /* FALLTHROUGH */
171: case (MDOC_Vt):
1.4 kristaps 172: if (0 < sz)
173: break;
174: return(mdoc_err(mdoc, tok, pos, ERR_ARGS_GE1));
175: /* ======= ADD MORE MACRO CHECKS ABOVE. ======= */
1.2 kristaps 176: default:
1.4 kristaps 177: abort();
178: /* NOTREACHED */
1.2 kristaps 179: }
180:
1.4 kristaps 181: mdoc_elem_alloc(mdoc, pos, tok, 0,
182: NULL, (size_t)sz, _CC(args));
183: return(1);
1.2 kristaps 184: }
185:
1.1 kristaps 186:
1.2 kristaps 187: int
1.5 ! kristaps 188: macro_text(MACRO_PROT_ARGS)
1.2 kristaps 189: {
1.3 kristaps 190: int lastarg, c, lasttok, lastpunct, j;
1.2 kristaps 191: char *args[MDOC_LINEARG_MAX], *p;
1.1 kristaps 192:
1.2 kristaps 193: lasttok = ppos;
194: lastpunct = 0;
195: j = 0;
196:
1.5 ! kristaps 197: if (SEC_PROLOGUE == mdoc->sec_lastn)
! 198: return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE));
! 199:
1.2 kristaps 200: again:
201:
202: lastarg = *pos;
203: c = args_next(mdoc, tok, pos, buf, &args[j]);
204:
205: if (-1 == c)
206: return(0);
207: if (0 == c && ! lastpunct)
208: return(append_text(mdoc, tok, lasttok, j, args));
209: else if (0 == c)
210: return(1);
211:
212: /* Command found. */
213:
214: if (MDOC_MAX != (c = mdoc_find(mdoc, args[j]))) {
215: if ( ! lastpunct)
216: if ( ! append_text(mdoc, tok, lasttok, j, args))
1.1 kristaps 217: return(0);
1.2 kristaps 218: return(mdoc_macro(mdoc, c, lastarg, pos, buf));
219: }
220:
221: /* Word found. */
222:
1.4 kristaps 223: if ( ! mdoc_isdelim(args[j])) {
1.2 kristaps 224: j++;
225: goto again;
226: }
227:
228: /* Punctuation found. */
229:
230: p = args[j]; /* Save argument (NULL-ified in append). */
231:
232: if ( ! lastpunct)
233: if ( ! append_text(mdoc, tok, lasttok, j, args))
234: return(0);
235:
236: args[j] = p;
237:
238: mdoc_word_alloc(mdoc, lastarg, args[j]);
239: lastpunct = 1;
240: j = 0;
241:
242: goto again;
243:
244: /* NOTREACHED */
245: }
1.1 kristaps 246:
247:
1.2 kristaps 248: int
1.5 ! kristaps 249: macro_prologue_dtitle(MACRO_PROT_ARGS)
! 250: {
! 251: int c, lastarg, j;
! 252: char *args[MDOC_LINEARG_MAX];
! 253:
! 254: if (SEC_PROLOGUE != mdoc->sec_lastn)
! 255: return(mdoc_err(mdoc, tok, ppos, ERR_SEC_NPROLOGUE));
! 256: if (0 == mdoc->meta.date)
! 257: return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE_OO));
! 258: if (mdoc->meta.title[0])
! 259: return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE_REP));
! 260:
! 261: j = -1;
! 262:
! 263: again:
! 264: lastarg = *pos;
! 265: c = args_next(mdoc, tok, pos, buf, &args[++j]);
! 266:
! 267: if (0 == c) {
! 268: mdoc->sec_lastn = mdoc->sec_last = SEC_BODY; /* FIXME */
! 269: if (mdoc->meta.title)
! 270: return(1);
! 271: if ( ! mdoc_warn(mdoc, tok, ppos, WARN_ARGS_GE1))
! 272: return(0);
! 273: (void)xstrlcpy(mdoc->meta.title,
! 274: "UNTITLED", META_TITLE_SZ);
! 275: return(1);
! 276: } else if (-1 == c)
! 277: return(0);
! 278:
! 279: if (MDOC_MAX != mdoc_find(mdoc, args[j]) && ! mdoc_warn
! 280: (mdoc, tok, lastarg, WARN_SYNTAX_MACLIKE))
! 281: return(0);
! 282:
! 283: if (0 == j) {
! 284: if (xstrlcpy(mdoc->meta.title, args[0], META_TITLE_SZ))
! 285: goto again;
! 286: return(mdoc_err(mdoc, tok, lastarg, ERR_SYNTAX_ARGS));
! 287:
! 288: } else if (1 == j) {
! 289: mdoc->meta.msec = mdoc_atomsec(args[1]);
! 290: if (MSEC_DEFAULT != mdoc->meta.msec)
! 291: goto again;
! 292: return(mdoc_err(mdoc, tok, -1, ERR_SYNTAX_ARGS));
! 293:
! 294: } else if (2 == j) {
! 295: mdoc->meta.vol = mdoc_atovol(args[2]);
! 296: if (VOL_DEFAULT != mdoc->meta.vol)
! 297: goto again;
! 298: mdoc->meta.arch = mdoc_atoarch(args[2]);
! 299: if (ARCH_DEFAULT != mdoc->meta.arch)
! 300: goto again;
! 301: return(mdoc_err(mdoc, tok, lastarg, ERR_SYNTAX_ARGS));
! 302: }
! 303:
! 304: return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
! 305: }
! 306:
! 307:
! 308: int
! 309: macro_prologue_ddate(MACRO_PROT_ARGS)
! 310: {
! 311: int c, lastarg, j;
! 312: char *args[MDOC_LINEARG_MAX], date[64];
! 313:
! 314: if (SEC_PROLOGUE != mdoc->sec_lastn)
! 315: return(mdoc_err(mdoc, tok, ppos, ERR_SEC_NPROLOGUE));
! 316: if (mdoc->meta.title[0])
! 317: return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE_OO));
! 318: if (mdoc->meta.date)
! 319: return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE_REP));
! 320:
! 321: j = -1;
! 322: date[0] = 0;
! 323:
! 324: again:
! 325:
! 326: lastarg = *pos;
! 327: c = args_next(mdoc, tok, pos, buf, &args[++j]);
! 328: if (0 == c) {
! 329: if (mdoc->meta.date)
! 330: return(1);
! 331: mdoc->meta.date = mdoc_atotime(date);
! 332: if (mdoc->meta.date)
! 333: return(1);
! 334: return(mdoc_err(mdoc, tok, ppos, ERR_SYNTAX_ARGS));
! 335: } else if (-1 == c)
! 336: return(0);
! 337:
! 338: if (MDOC_MAX != mdoc_find(mdoc, args[j]) && ! mdoc_warn
! 339: (mdoc, tok, lastarg, WARN_SYNTAX_MACLIKE))
! 340: return(0);
! 341:
! 342: if (0 == j) {
! 343: if (xstrcmp("$Mdocdate$", args[j])) {
! 344: mdoc->meta.date = time(NULL);
! 345: goto again;
! 346: } else if (xstrcmp("$Mdocdate:", args[j]))
! 347: goto again;
! 348: } else if (4 == j)
! 349: if ( ! xstrcmp("$", args[j]))
! 350: goto again;
! 351:
! 352: if ( ! xstrlcat(date, args[j], sizeof(date)))
! 353: return(mdoc_err(mdoc, tok, lastarg, ERR_SYNTAX_ARGS));
! 354: if ( ! xstrlcat(date, " ", sizeof(date)))
! 355: return(mdoc_err(mdoc, tok, lastarg, ERR_SYNTAX_ARGS));
! 356:
! 357: goto again;
! 358: /* NOTREACHED */
! 359: }
! 360:
! 361:
! 362: int
! 363: macro_scoped_implicit(MACRO_PROT_ARGS)
1.2 kristaps 364: {
1.3 kristaps 365: int t, c, lastarg, j;
1.2 kristaps 366: char *args[MDOC_LINEARG_MAX];
367: struct mdoc_node *n;
368:
1.5 ! kristaps 369: assert( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags));
1.1 kristaps 370:
1.5 ! kristaps 371: if (SEC_PROLOGUE == mdoc->sec_lastn)
! 372: return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE));
1.1 kristaps 373:
1.3 kristaps 374: /* LINTED */
1.2 kristaps 375: for (n = mdoc->last; n; n = n->parent) {
376: if (MDOC_BLOCK != n->type)
377: continue;
378: if (tok == (t = n->data.block.tok))
1.1 kristaps 379: break;
1.2 kristaps 380: if ( ! (MDOC_EXPLICIT & mdoc_macros[t].flags))
381: continue;
382: return(mdoc_err(mdoc, tok, ppos, ERR_SCOPE_BREAK));
383: }
384:
385: if (n) {
386: mdoc->last = n;
387: mdoc_msg(mdoc, ppos, "scope: rewound `%s'",
388: mdoc_macronames[tok]);
389: } else
390: mdoc_msg(mdoc, ppos, "scope: new `%s'",
391: mdoc_macronames[tok]);
392:
393: j = 0;
394:
395: again:
396:
397: lastarg = *pos;
398: c = args_next(mdoc, tok, pos, buf, &args[j]);
399:
400: if (-1 == c)
401: return(0);
402: if (0 == c)
403: return(append_scoped(mdoc, tok, ppos, j, args));
1.1 kristaps 404:
1.2 kristaps 405: /* Command found. */
1.1 kristaps 406:
1.2 kristaps 407: if (MDOC_MAX != (c = mdoc_find(mdoc, args[j])))
1.3 kristaps 408: if ( ! mdoc_warn(mdoc, tok, lastarg, WARN_SYNTAX_MACLIKE))
1.1 kristaps 409: return(0);
410:
1.2 kristaps 411: /* Word found. */
412:
413: j++;
414: goto again;
1.1 kristaps 415:
1.2 kristaps 416: /* NOTREACHED */
1.1 kristaps 417: }
1.5 ! kristaps 418:
! 419:
! 420: static int
! 421: xstrcmp(const char *p1, const char *p2)
! 422: {
! 423:
! 424: return(0 == strcmp(p1, p2));
! 425: }
! 426:
! 427:
! 428: static int
! 429: xstrlcat(char *dst, const char *src, size_t sz)
! 430: {
! 431:
! 432: return(strlcat(dst, src, sz) < sz);
! 433: }
! 434:
! 435:
! 436: static int
! 437: xstrlcpy(char *dst, const char *src, size_t sz)
! 438: {
! 439:
! 440: return(strlcpy(dst, src, sz) < sz);
! 441: }
CVSweb