Annotation of mandoc/man.c, Revision 1.1
1.1 ! kristaps 1: /* $Id: mdoc.c,v 1.69 2009/03/21 09:42:07 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 <err.h>
! 22: #include <stdarg.h>
! 23: #include <stdlib.h>
! 24: #include <stdio.h>
! 25: #include <string.h>
! 26:
! 27: #include "libman.h"
! 28:
! 29: const char *const __man_macronames[MAN_MAX] = {
! 30: "\\\"", "TH", "SH", "SS",
! 31: "TP", "LP", "PP", "P",
! 32: "IP", "HP", "SM", "SB",
! 33: "BI", "IB", "BR", "RB",
! 34: "R", "B", "I"
! 35: };
! 36:
! 37: const char * const *man_macronames = __man_macronames;
! 38:
! 39: static struct man_node *man_node_alloc(int, int, enum man_type);
! 40: static int man_node_append(struct man *,
! 41: struct man_node *);
! 42: static int man_ptext(struct man *, int, char *);
! 43: static int man_pmacro(struct man *, int, char *);
! 44:
! 45:
! 46: const struct man_node *
! 47: man_node(const struct man *man)
! 48: {
! 49:
! 50: return(man->first);
! 51: }
! 52:
! 53:
! 54: const struct man_meta *
! 55: man_meta(const struct man *man)
! 56: {
! 57:
! 58: return(&man->meta);
! 59: }
! 60:
! 61:
! 62: void
! 63: man_reset(struct man *man)
! 64: {
! 65:
! 66: if (man->first)
! 67: man_node_freelist(man->first);
! 68: if (man->meta.title)
! 69: free(man->meta.title);
! 70: if (man->meta.os)
! 71: free(man->meta.os);
! 72: if (man->meta.vol)
! 73: free(man->meta.vol);
! 74:
! 75: bzero(&man->meta, sizeof(struct man_meta));
! 76: man->flags = 0;
! 77: if (NULL == (man->last = calloc(1, sizeof(struct man_node))))
! 78: err(1, "malloc");
! 79: man->first = man->last;
! 80: man->last->type = MAN_ROOT;
! 81: man->next = MAN_NEXT_CHILD;
! 82: }
! 83:
! 84:
! 85: void
! 86: man_free(struct man *man)
! 87: {
! 88:
! 89: if (man->first)
! 90: man_node_freelist(man->first);
! 91: if (man->meta.title)
! 92: free(man->meta.title);
! 93: if (man->meta.os)
! 94: free(man->meta.os);
! 95: if (man->meta.vol)
! 96: free(man->meta.vol);
! 97: if (man->htab)
! 98: man_hash_free(man->htab);
! 99: free(man);
! 100: }
! 101:
! 102:
! 103: struct man *
! 104: man_alloc(void)
! 105: {
! 106: struct man *p;
! 107:
! 108: if (NULL == (p = calloc(1, sizeof(struct man))))
! 109: err(1, "malloc");
! 110: if (NULL == (p->last = calloc(1, sizeof(struct man_node))))
! 111: err(1, "malloc");
! 112:
! 113: p->first = p->last;
! 114: p->last->type = MAN_ROOT;
! 115: p->next = MAN_NEXT_CHILD;
! 116: p->htab = man_hash_alloc();
! 117: return(p);
! 118: }
! 119:
! 120:
! 121: int
! 122: man_endparse(struct man *m)
! 123: {
! 124:
! 125: return(1);
! 126: }
! 127:
! 128:
! 129: int
! 130: man_parseln(struct man *m, int ln, char *buf)
! 131: {
! 132:
! 133: return('.' == *buf ?
! 134: man_pmacro(m, ln, buf) :
! 135: man_ptext(m, ln, buf));
! 136: }
! 137:
! 138:
! 139: static int
! 140: man_node_append(struct man *man, struct man_node *p)
! 141: {
! 142:
! 143: assert(man->last);
! 144: assert(man->first);
! 145: assert(MAN_ROOT != p->type);
! 146:
! 147: switch (man->next) {
! 148: case (MAN_NEXT_SIBLING):
! 149: man->last->next = p;
! 150: p->prev = man->last;
! 151: p->parent = man->last->parent;
! 152: break;
! 153: case (MAN_NEXT_CHILD):
! 154: man->last->child = p;
! 155: p->parent = man->last;
! 156: break;
! 157: default:
! 158: abort();
! 159: /* NOTREACHED */
! 160: }
! 161:
! 162: #if 0
! 163: if ( ! man_valid_pre(man, p))
! 164: return(0);
! 165: if ( ! man_action_pre(man, p))
! 166: return(0);
! 167: #endif
! 168:
! 169: switch (p->type) {
! 170: case (MAN_HEAD):
! 171: assert(MAN_BLOCK == p->parent->type);
! 172: p->parent->head = p;
! 173: break;
! 174: case (MAN_BODY):
! 175: assert(MAN_BLOCK == p->parent->type);
! 176: p->parent->body = p;
! 177: break;
! 178: default:
! 179: break;
! 180: }
! 181:
! 182: man->last = p;
! 183: return(1);
! 184: }
! 185:
! 186:
! 187: static struct man_node *
! 188: man_node_alloc(int line, int pos, enum man_type type)
! 189: {
! 190: struct man_node *p;
! 191:
! 192: if (NULL == (p = calloc(1, sizeof(struct man_node))))
! 193: err(1, "malloc");
! 194: p->line = line;
! 195: p->pos = pos;
! 196: p->type = type;
! 197:
! 198: return(p);
! 199: }
! 200:
! 201:
! 202: int
! 203: man_head_alloc(struct man *man, int line, int pos, int tok)
! 204: {
! 205: struct man_node *p;
! 206:
! 207: p = man_node_alloc(line, pos, MAN_HEAD);
! 208: p->tok = tok;
! 209:
! 210: return(man_node_append(man, p));
! 211: }
! 212:
! 213:
! 214: int
! 215: man_body_alloc(struct man *man, int line, int pos, int tok)
! 216: {
! 217: struct man_node *p;
! 218:
! 219: p = man_node_alloc(line, pos, MAN_BODY);
! 220: p->tok = tok;
! 221:
! 222: return(man_node_append(man, p));
! 223: }
! 224:
! 225:
! 226: int
! 227: man_block_alloc(struct man *man, int line, int pos, int tok)
! 228: {
! 229: struct man_node *p;
! 230:
! 231: p = man_node_alloc(line, pos, MAN_BLOCK);
! 232: p->tok = tok;
! 233:
! 234: return(man_node_append(man, p));
! 235: }
! 236:
! 237:
! 238: int
! 239: man_elem_alloc(struct man *man, int line, int pos, int tok)
! 240: {
! 241: struct man_node *p;
! 242:
! 243: p = man_node_alloc(line, pos, MAN_ELEM);
! 244: p->tok = tok;
! 245:
! 246: return(man_node_append(man, p));
! 247: }
! 248:
! 249:
! 250: int
! 251: man_word_alloc(struct man *man,
! 252: int line, int pos, const char *word)
! 253: {
! 254: struct man_node *p;
! 255:
! 256: p = man_node_alloc(line, pos, MAN_TEXT);
! 257: if (NULL == (p->string = strdup(word)))
! 258: err(1, "strdup");
! 259:
! 260: return(man_node_append(man, p));
! 261: }
! 262:
! 263:
! 264: void
! 265: man_node_free(struct man_node *p)
! 266: {
! 267:
! 268: if (p->string)
! 269: free(p->string);
! 270: free(p);
! 271: }
! 272:
! 273:
! 274: void
! 275: man_node_freelist(struct man_node *p)
! 276: {
! 277:
! 278: if (p->child)
! 279: man_node_freelist(p->child);
! 280: if (p->next)
! 281: man_node_freelist(p->next);
! 282:
! 283: man_node_free(p);
! 284: }
! 285:
! 286:
! 287: static int
! 288: man_ptext(struct man *m, int line, char *buf)
! 289: {
! 290:
! 291: if (0 == buf[0]) {
! 292: warnx("blank line!");
! 293: return(1);
! 294: }
! 295:
! 296: if ( ! man_word_alloc(m, line, 0, buf))
! 297: return(0);
! 298:
! 299: m->next = MAN_NEXT_SIBLING;
! 300: return(1);
! 301: }
! 302:
! 303:
! 304: int
! 305: man_pmacro(struct man *m, int ln, char *buf)
! 306: {
! 307: int i, c;
! 308: char mac[5];
! 309:
! 310: /* Comments and empties are quickly ignored. */
! 311:
! 312: if (0 == buf[1])
! 313: return(1);
! 314:
! 315: if (' ' == buf[1]) {
! 316: i = 2;
! 317: while (buf[i] && ' ' == buf[i])
! 318: i++;
! 319: if (0 == buf[i])
! 320: return(1);
! 321: warnx("invalid syntax");
! 322: return(0);
! 323: }
! 324:
! 325: if (buf[1] && '\\' == buf[1])
! 326: if (buf[2] && '\"' == buf[2])
! 327: return(1);
! 328:
! 329: /* Copy the first word into a nil-terminated buffer. */
! 330:
! 331: for (i = 1; i < 5; i++) {
! 332: if (0 == (mac[i - 1] = buf[i]))
! 333: break;
! 334: else if (' ' == buf[i])
! 335: break;
! 336: }
! 337:
! 338: mac[i - 1] = 0;
! 339:
! 340: if (i == 5 || i <= 1) {
! 341: warnx("unknown macro: %s", mac);
! 342: goto err;
! 343: }
! 344:
! 345: if (MAN_MAX == (c = man_hash_find(m->htab, mac))) {
! 346: warnx("unknown macro: %s", mac);
! 347: goto err;
! 348: }
! 349:
! 350: /* The macro is sane. Jump to the next word. */
! 351:
! 352: while (buf[i] && ' ' == buf[i])
! 353: i++;
! 354:
! 355: /* Begin recursive parse sequence. */
! 356:
! 357: if ( ! (*man_macros[c].fp)(m, c, ln, 1, &i, buf))
! 358: goto err;
! 359:
! 360: return(1);
! 361:
! 362: err: /* Error out. */
! 363:
! 364: #if 0
! 365: m->flags |= MDOC_HALT;
! 366: #endif
! 367: return(0);
! 368: }
CVSweb