1 /* $Id: man.c,v 1.1 2009/04/06 20:30:40 kristaps Exp $ */ 2 /* 3 * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@openbsd.org> 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 */ 19 #include <assert.h> 20 #include <ctype.h> 21 #include <stdarg.h> 22 #include <stdlib.h> 23 #include <stdio.h> 24 #include <string.h> 25 26 #include "libman.h" 27 28 const char *const __man_macronames[MAN_MAX] = { 29 "\\\"", "TH", "SH", "SS", 30 "TP", "LP", "PP", "P", 31 "IP", "HP", "SM", "SB", 32 "BI", "IB", "BR", "RB", 33 "R", "B", "I", "IR", 34 "RI", "br", "na", "i" 35 }; 36 37 const char * const *man_macronames = __man_macronames; 38 39 static struct man_node *man_node_alloc(int, int, 40 enum man_type, int); 41 static int man_node_append(struct man *, 42 struct man_node *); 43 static int man_ptext(struct man *, int, char *); 44 static int man_pmacro(struct man *, int, char *); 45 static void man_free1(struct man *); 46 static int man_alloc1(struct man *); 47 48 49 const struct man_node * 50 man_node(const struct man *m) 51 { 52 53 return(MAN_HALT & m->flags ? NULL : m->first); 54 } 55 56 57 const struct man_meta * 58 man_meta(const struct man *m) 59 { 60 61 return(MAN_HALT & m->flags ? NULL : &m->meta); 62 } 63 64 65 int 66 man_reset(struct man *man) 67 { 68 69 man_free1(man); 70 return(man_alloc1(man)); 71 } 72 73 74 void 75 man_free(struct man *man) 76 { 77 78 man_free1(man); 79 80 if (man->htab) 81 man_hash_free(man->htab); 82 free(man); 83 } 84 85 86 struct man * 87 man_alloc(void *data, int pflags, const struct man_cb *cb) 88 { 89 struct man *p; 90 91 if (NULL == (p = calloc(1, sizeof(struct man)))) 92 return(NULL); 93 94 if ( ! man_alloc1(p)) { 95 free(p); 96 return(NULL); 97 } 98 99 p->data = data; 100 p->pflags = pflags; 101 (void)memcpy(&p->cb, cb, sizeof(struct man_cb)); 102 103 if (NULL == (p->htab = man_hash_alloc())) { 104 free(p); 105 return(NULL); 106 } 107 return(p); 108 } 109 110 111 int 112 man_endparse(struct man *m) 113 { 114 115 if (MAN_HALT & m->flags) 116 return(0); 117 else if (man_macroend(m)) 118 return(1); 119 m->flags |= MAN_HALT; 120 return(0); 121 } 122 123 124 int 125 man_parseln(struct man *m, int ln, char *buf) 126 { 127 128 return('.' == *buf ? 129 man_pmacro(m, ln, buf) : 130 man_ptext(m, ln, buf)); 131 } 132 133 134 static void 135 man_free1(struct man *man) 136 { 137 138 if (man->first) 139 man_node_freelist(man->first); 140 if (man->meta.title) 141 free(man->meta.title); 142 if (man->meta.source) 143 free(man->meta.source); 144 if (man->meta.vol) 145 free(man->meta.vol); 146 } 147 148 149 static int 150 man_alloc1(struct man *m) 151 { 152 153 bzero(&m->meta, sizeof(struct man_meta)); 154 m->flags = 0; 155 m->last = calloc(1, sizeof(struct man_node)); 156 if (NULL == m->last) 157 return(0); 158 m->first = m->last; 159 m->last->type = MAN_ROOT; 160 m->next = MAN_NEXT_CHILD; 161 return(1); 162 } 163 164 165 static int 166 man_node_append(struct man *man, struct man_node *p) 167 { 168 169 assert(man->last); 170 assert(man->first); 171 assert(MAN_ROOT != p->type); 172 173 switch (man->next) { 174 case (MAN_NEXT_SIBLING): 175 man->last->next = p; 176 p->prev = man->last; 177 p->parent = man->last->parent; 178 break; 179 case (MAN_NEXT_CHILD): 180 man->last->child = p; 181 p->parent = man->last; 182 break; 183 default: 184 abort(); 185 /* NOTREACHED */ 186 } 187 188 man->last = p; 189 190 switch (p->type) { 191 case (MAN_TEXT): 192 if ( ! man_valid_post(man)) 193 return(0); 194 if ( ! man_action_post(man)) 195 return(0); 196 break; 197 default: 198 break; 199 } 200 201 return(1); 202 } 203 204 205 static struct man_node * 206 man_node_alloc(int line, int pos, enum man_type type, int tok) 207 { 208 struct man_node *p; 209 210 p = calloc(1, sizeof(struct man_node)); 211 if (NULL == p) 212 return(NULL); 213 214 p->line = line; 215 p->pos = pos; 216 p->type = type; 217 p->tok = tok; 218 return(p); 219 } 220 221 222 int 223 man_elem_alloc(struct man *man, int line, int pos, int tok) 224 { 225 struct man_node *p; 226 227 p = man_node_alloc(line, pos, MAN_ELEM, tok); 228 if (NULL == p) 229 return(0); 230 return(man_node_append(man, p)); 231 } 232 233 234 int 235 man_word_alloc(struct man *man, 236 int line, int pos, const char *word) 237 { 238 struct man_node *p; 239 240 p = man_node_alloc(line, pos, MAN_TEXT, -1); 241 if (NULL == p) 242 return(0); 243 if (NULL == (p->string = strdup(word))) 244 return(0); 245 return(man_node_append(man, p)); 246 } 247 248 249 void 250 man_node_free(struct man_node *p) 251 { 252 253 if (p->string) 254 free(p->string); 255 free(p); 256 } 257 258 259 void 260 man_node_freelist(struct man_node *p) 261 { 262 263 if (p->child) 264 man_node_freelist(p->child); 265 if (p->next) 266 man_node_freelist(p->next); 267 268 man_node_free(p); 269 } 270 271 272 static int 273 man_ptext(struct man *m, int line, char *buf) 274 { 275 276 if ( ! man_word_alloc(m, line, 0, buf)) 277 return(0); 278 m->next = MAN_NEXT_SIBLING; 279 280 /* 281 * If this is one of the zany NLINE macros that consumes the 282 * next line of input as being influenced, then close out the 283 * existing macro "scope" and continue processing. 284 */ 285 286 if ( ! (MAN_NLINE & m->flags)) 287 return(1); 288 289 m->flags &= ~MAN_NLINE; 290 m->last = m->last->parent; 291 292 assert(MAN_ROOT != m->last->type); 293 if ( ! man_valid_post(m)) 294 return(0); 295 if ( ! man_action_post(m)) 296 return(0); 297 298 return(1); 299 } 300 301 302 int 303 man_pmacro(struct man *m, int ln, char *buf) 304 { 305 int i, j, c, ppos, fl; 306 char mac[5]; 307 struct man_node *n; 308 309 /* Comments and empties are quickly ignored. */ 310 311 n = m->last; 312 fl = MAN_NLINE & m->flags; 313 314 if (0 == buf[1]) 315 goto out; 316 317 i = 1; 318 319 if (' ' == buf[i]) { 320 i++; 321 while (buf[i] && ' ' == buf[i]) 322 i++; 323 if (0 == buf[i]) 324 goto out; 325 } 326 327 ppos = i; 328 329 if (buf[i] && '\\' == buf[i]) 330 if (buf[i + 1] && '\"' == buf[i + 1]) 331 goto out; 332 333 /* Copy the first word into a nil-terminated buffer. */ 334 335 for (j = 0; j < 4; j++, i++) { 336 if (0 == (mac[j] = buf[i])) 337 break; 338 else if (' ' == buf[i]) 339 break; 340 } 341 342 mac[j] = 0; 343 344 if (j == 4 || j < 1) { 345 if ( ! (MAN_IGN_MACRO & m->pflags)) { 346 (void)man_verr(m, ln, ppos, 347 "ill-formed macro: %s", mac); 348 goto err; 349 } 350 if ( ! man_vwarn(m, ln, ppos, 351 "ill-formed macro: %s", mac)) 352 goto err; 353 return(1); 354 } 355 356 if (MAN_MAX == (c = man_hash_find(m->htab, mac))) { 357 if ( ! (MAN_IGN_MACRO & m->pflags)) { 358 (void)man_verr(m, ln, ppos, 359 "unknown macro: %s", mac); 360 goto err; 361 } 362 if ( ! man_vwarn(m, ln, ppos, 363 "unknown macro: %s", mac)) 364 goto err; 365 return(1); 366 } 367 368 /* The macro is sane. Jump to the next word. */ 369 370 while (buf[i] && ' ' == buf[i]) 371 i++; 372 373 /* Begin recursive parse sequence. */ 374 375 if ( ! man_macro(m, c, ln, ppos, &i, buf)) 376 goto err; 377 378 out: 379 if (fl) { 380 /* 381 * A NLINE macro has been immediately followed with 382 * another. Close out the preceeding macro's scope, and 383 * continue. 384 */ 385 assert(MAN_ROOT != m->last->type); 386 assert(m->last->parent); 387 assert(MAN_ROOT != m->last->parent->type); 388 389 if (n != m->last) 390 m->last = m->last->parent; 391 392 if ( ! man_valid_post(m)) 393 return(0); 394 if ( ! man_action_post(m)) 395 return(0); 396 m->next = MAN_NEXT_SIBLING; 397 m->flags &= ~MAN_NLINE; 398 } 399 400 return(1); 401 402 err: /* Error out. */ 403 404 m->flags |= MAN_HALT; 405 return(0); 406 } 407 408 409 int 410 man_verr(struct man *man, int ln, int pos, const char *fmt, ...) 411 { 412 char buf[256]; 413 va_list ap; 414 415 if (NULL == man->cb.man_err) 416 return(0); 417 418 va_start(ap, fmt); 419 (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap); 420 va_end(ap); 421 return((*man->cb.man_err)(man->data, ln, pos, buf)); 422 } 423 424 425 int 426 man_vwarn(struct man *man, int ln, int pos, const char *fmt, ...) 427 { 428 char buf[256]; 429 va_list ap; 430 431 if (NULL == man->cb.man_warn) 432 return(0); 433 434 va_start(ap, fmt); 435 (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap); 436 va_end(ap); 437 return((*man->cb.man_warn)(man->data, ln, pos, buf)); 438 } 439 440 441