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