1 /* $Id: man_macro.c,v 1.8 2009/09/18 22:46:14 schwarze 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 <stdlib.h> 20 #include <string.h> 21 22 #include "libman.h" 23 24 #define REW_REWIND (0) /* See rew_scope(). */ 25 #define REW_NOHALT (1) /* See rew_scope(). */ 26 #define REW_HALT (2) /* See rew_scope(). */ 27 28 static int in_line_eoln(MACRO_PROT_ARGS); 29 static int blk_imp(MACRO_PROT_ARGS); 30 static int blk_close(MACRO_PROT_ARGS); 31 32 static int rew_scope(enum man_type, struct man *, int); 33 static int rew_dohalt(int, enum man_type, 34 const struct man_node *); 35 static int rew_block(int, enum man_type, 36 const struct man_node *); 37 38 const struct man_macro __man_macros[MAN_MAX] = { 39 { in_line_eoln, 0 }, /* br */ 40 { in_line_eoln, 0 }, /* TH */ 41 { blk_imp, MAN_SCOPED }, /* SH */ 42 { blk_imp, MAN_SCOPED }, /* SS */ 43 { blk_imp, MAN_SCOPED | MAN_FSCOPED }, /* TP */ 44 { blk_imp, 0 }, /* LP */ 45 { blk_imp, 0 }, /* PP */ 46 { blk_imp, 0 }, /* P */ 47 { blk_imp, 0 }, /* IP */ 48 { blk_imp, 0 }, /* HP */ 49 { in_line_eoln, MAN_SCOPED }, /* SM */ 50 { in_line_eoln, MAN_SCOPED }, /* SB */ 51 { in_line_eoln, 0 }, /* BI */ 52 { in_line_eoln, 0 }, /* IB */ 53 { in_line_eoln, 0 }, /* BR */ 54 { in_line_eoln, 0 }, /* RB */ 55 { in_line_eoln, MAN_SCOPED }, /* R */ 56 { in_line_eoln, MAN_SCOPED }, /* B */ 57 { in_line_eoln, MAN_SCOPED }, /* I */ 58 { in_line_eoln, 0 }, /* IR */ 59 { in_line_eoln, 0 }, /* RI */ 60 { in_line_eoln, 0 }, /* na */ 61 { in_line_eoln, 0 }, /* i */ 62 { in_line_eoln, 0 }, /* sp */ 63 { in_line_eoln, 0 }, /* nf */ 64 { in_line_eoln, 0 }, /* fi */ 65 { in_line_eoln, 0 }, /* r */ 66 { blk_close, 0 }, /* RE */ 67 { blk_imp, MAN_EXPLICIT }, /* RS */ 68 { in_line_eoln, 0 }, /* DT */ 69 { in_line_eoln, 0 }, /* UC */ 70 }; 71 72 const struct man_macro * const man_macros = __man_macros; 73 74 75 int 76 man_unscope(struct man *m, const struct man_node *n) 77 { 78 79 assert(n); 80 m->next = MAN_NEXT_SIBLING; 81 82 /* LINTED */ 83 while (m->last != n) { 84 if ( ! man_valid_post(m)) 85 return(0); 86 if ( ! man_action_post(m)) 87 return(0); 88 m->last = m->last->parent; 89 assert(m->last); 90 } 91 92 if ( ! man_valid_post(m)) 93 return(0); 94 return(man_action_post(m)); 95 } 96 97 98 static int 99 rew_block(int ntok, enum man_type type, const struct man_node *n) 100 { 101 102 if (MAN_BLOCK == type && ntok == n->parent->tok && 103 MAN_BODY == n->parent->type) 104 return(REW_REWIND); 105 return(ntok == n->tok ? REW_HALT : REW_NOHALT); 106 } 107 108 109 /* 110 * There are three scope levels: scoped to the root (all), scoped to the 111 * section (all less sections), and scoped to subsections (all less 112 * sections and subsections). 113 */ 114 static int 115 rew_dohalt(int tok, enum man_type type, const struct man_node *n) 116 { 117 int c; 118 119 if (MAN_ROOT == n->type) 120 return(REW_HALT); 121 assert(n->parent); 122 if (MAN_ROOT == n->parent->type) 123 return(REW_REWIND); 124 if (MAN_VALID & n->flags) 125 return(REW_NOHALT); 126 127 /* Rewind to ourselves, first. */ 128 if (type == n->type && tok == n->tok) 129 return(REW_REWIND); 130 131 switch (tok) { 132 case (MAN_SH): 133 break; 134 case (MAN_SS): 135 /* Rewind to a section, if a block. */ 136 if (REW_NOHALT != (c = rew_block(MAN_SH, type, n))) 137 return(c); 138 break; 139 case (MAN_RS): 140 /* Rewind to a subsection, if a block. */ 141 if (REW_NOHALT != (c = rew_block(MAN_SS, type, n))) 142 return(c); 143 /* Rewind to a section, if a block. */ 144 if (REW_NOHALT != (c = rew_block(MAN_SH, type, n))) 145 return(c); 146 break; 147 default: 148 /* Rewind to an offsetter, if a block. */ 149 if (REW_NOHALT != (c = rew_block(MAN_RS, type, n))) 150 return(c); 151 /* Rewind to a subsection, if a block. */ 152 if (REW_NOHALT != (c = rew_block(MAN_SS, type, n))) 153 return(c); 154 /* Rewind to a section, if a block. */ 155 if (REW_NOHALT != (c = rew_block(MAN_SH, type, n))) 156 return(c); 157 break; 158 } 159 160 return(REW_NOHALT); 161 } 162 163 164 /* 165 * Rewinding entails ascending the parse tree until a coherent point, 166 * for example, the `SH' macro will close out any intervening `SS' 167 * scopes. When a scope is closed, it must be validated and actioned. 168 */ 169 static int 170 rew_scope(enum man_type type, struct man *m, int tok) 171 { 172 struct man_node *n; 173 int c; 174 175 /* LINTED */ 176 for (n = m->last; n; n = n->parent) { 177 /* 178 * Whether we should stop immediately (REW_HALT), stop 179 * and rewind until this point (REW_REWIND), or keep 180 * rewinding (REW_NOHALT). 181 */ 182 c = rew_dohalt(tok, type, n); 183 if (REW_HALT == c) 184 return(1); 185 if (REW_REWIND == c) 186 break; 187 } 188 189 /* Rewind until the current point. */ 190 191 assert(n); 192 return(man_unscope(m, n)); 193 } 194 195 196 /* ARGSUSED */ 197 int 198 blk_close(MACRO_PROT_ARGS) 199 { 200 int ntok; 201 const struct man_node *nn; 202 203 switch (tok) { 204 case (MAN_RE): 205 ntok = MAN_RS; 206 break; 207 default: 208 abort(); 209 /* NOTREACHED */ 210 } 211 212 for (nn = m->last->parent; nn; nn = nn->parent) 213 if (ntok == nn->tok) 214 break; 215 216 if (NULL == nn) 217 if ( ! man_pwarn(m, line, ppos, WNOSCOPE)) 218 return(0); 219 220 if ( ! rew_scope(MAN_BODY, m, ntok)) 221 return(0); 222 if ( ! rew_scope(MAN_BLOCK, m, ntok)) 223 return(0); 224 m->next = MAN_NEXT_SIBLING; 225 return(1); 226 } 227 228 229 /* 230 * Parse an implicit-block macro. These contain a MAN_HEAD and a 231 * MAN_BODY contained within a MAN_BLOCK. Rules for closing out other 232 * scopes, such as `SH' closing out an `SS', are defined in the rew 233 * routines. 234 */ 235 int 236 blk_imp(MACRO_PROT_ARGS) 237 { 238 int w, la; 239 char *p; 240 struct man_node *n; 241 242 /* Close out prior scopes. */ 243 244 if ( ! rew_scope(MAN_BODY, m, tok)) 245 return(0); 246 if ( ! rew_scope(MAN_BLOCK, m, tok)) 247 return(0); 248 249 /* Allocate new block & head scope. */ 250 251 if ( ! man_block_alloc(m, line, ppos, tok)) 252 return(0); 253 if ( ! man_head_alloc(m, line, ppos, tok)) 254 return(0); 255 256 n = m->last; 257 258 /* Add line arguments. */ 259 260 for (;;) { 261 la = *pos; 262 w = man_args(m, line, pos, buf, &p); 263 264 if (-1 == w) 265 return(0); 266 if (0 == w) 267 break; 268 269 if ( ! man_word_alloc(m, line, la, p)) 270 return(0); 271 } 272 273 /* Close out head and open body (unless MAN_SCOPE). */ 274 275 if (MAN_SCOPED & man_macros[tok].flags) { 276 /* If we're forcing scope (`TP'), keep it open. */ 277 if (MAN_FSCOPED & man_macros[tok].flags) { 278 m->flags |= MAN_BLINE; 279 return(1); 280 } else if (n == m->last) { 281 m->flags |= MAN_BLINE; 282 return(1); 283 } 284 } 285 286 if ( ! rew_scope(MAN_HEAD, m, tok)) 287 return(0); 288 289 return(man_body_alloc(m, line, ppos, tok)); 290 } 291 292 293 int 294 in_line_eoln(MACRO_PROT_ARGS) 295 { 296 int w, la; 297 char *p; 298 struct man_node *n; 299 300 if ( ! man_elem_alloc(m, line, ppos, tok)) 301 return(0); 302 303 n = m->last; 304 305 for (;;) { 306 la = *pos; 307 w = man_args(m, line, pos, buf, &p); 308 309 if (-1 == w) 310 return(0); 311 if (0 == w) 312 break; 313 314 if ( ! man_word_alloc(m, line, la, p)) 315 return(0); 316 } 317 318 if (n == m->last && MAN_SCOPED & man_macros[tok].flags) { 319 m->flags |= MAN_ELINE; 320 return(1); 321 } 322 323 /* 324 * Note that when TH is pruned, we'll be back at the root, so 325 * make sure that we don't clobber as its sibling. 326 */ 327 328 for ( ; m->last; m->last = m->last->parent) { 329 if (m->last == n) 330 break; 331 if (m->last->type == MAN_ROOT) 332 break; 333 if ( ! man_valid_post(m)) 334 return(0); 335 if ( ! man_action_post(m)) 336 return(0); 337 } 338 339 assert(m->last); 340 341 /* 342 * Same here regarding whether we're back at the root. 343 */ 344 345 if (m->last->type != MAN_ROOT && ! man_valid_post(m)) 346 return(0); 347 if (m->last->type != MAN_ROOT && ! man_action_post(m)) 348 return(0); 349 if (m->last->type != MAN_ROOT) 350 m->next = MAN_NEXT_SIBLING; 351 352 return(1); 353 } 354 355 356 int 357 man_macroend(struct man *m) 358 { 359 struct man_node *n; 360 361 n = MAN_VALID & m->last->flags ? 362 m->last->parent : m->last; 363 364 for ( ; n; n = n->parent) { 365 if (MAN_BLOCK != n->type) 366 continue; 367 if ( ! (MAN_EXPLICIT & man_macros[n->tok].flags)) 368 continue; 369 if ( ! man_nwarn(m, n, WEXITSCOPE)) 370 return(0); 371 } 372 373 return(man_unscope(m, m->first)); 374 } 375 376