[BACK]Return to mdoc.c CVS log [TXT][DIR] Up to [cvsweb.bsd.lv] / mandoc

Annotation of mandoc/mdoc.c, Revision 1.88

1.88    ! kristaps    1: /*     $Id: mdoc.c,v 1.87 2009/07/06 09:21:24 kristaps Exp $ */
1.1       kristaps    2: /*
1.76      kristaps    3:  * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
1.1       kristaps    4:  *
                      5:  * Permission to use, copy, modify, and distribute this software for any
1.75      kristaps    6:  * purpose with or without fee is hereby granted, provided that the above
                      7:  * copyright notice and this permission notice appear in all copies.
1.1       kristaps    8:  *
1.75      kristaps    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.
1.1       kristaps   16:  */
                     17: #include <assert.h>
                     18: #include <ctype.h>
                     19: #include <stdarg.h>
1.73      kristaps   20: #include <stdio.h>
1.1       kristaps   21: #include <stdlib.h>
                     22: #include <string.h>
                     23:
1.70      kristaps   24: #include "libmdoc.h"
1.1       kristaps   25:
                     26: const  char *const __mdoc_macronames[MDOC_MAX] = {
1.82      kristaps   27:        "Ap",           "Dd",           "Dt",           "Os",
1.1       kristaps   28:        "Sh",           "Ss",           "Pp",           "D1",
                     29:        "Dl",           "Bd",           "Ed",           "Bl",
                     30:        "El",           "It",           "Ad",           "An",
                     31:        "Ar",           "Cd",           "Cm",           "Dv",
                     32:        "Er",           "Ev",           "Ex",           "Fa",
                     33:        "Fd",           "Fl",           "Fn",           "Ft",
                     34:        "Ic",           "In",           "Li",           "Nd",
                     35:        "Nm",           "Op",           "Ot",           "Pa",
                     36:        "Rv",           "St",           "Va",           "Vt",
                     37:        /* LINTED */
                     38:        "Xr",           "\%A",          "\%B",          "\%D",
                     39:        /* LINTED */
                     40:        "\%I",          "\%J",          "\%N",          "\%O",
                     41:        /* LINTED */
                     42:        "\%P",          "\%R",          "\%T",          "\%V",
                     43:        "Ac",           "Ao",           "Aq",           "At",
                     44:        "Bc",           "Bf",           "Bo",           "Bq",
                     45:        "Bsx",          "Bx",           "Db",           "Dc",
                     46:        "Do",           "Dq",           "Ec",           "Ef",
                     47:        "Em",           "Eo",           "Fx",           "Ms",
                     48:        "No",           "Ns",           "Nx",           "Ox",
                     49:        "Pc",           "Pf",           "Po",           "Pq",
                     50:        "Qc",           "Ql",           "Qo",           "Qq",
                     51:        "Re",           "Rs",           "Sc",           "So",
                     52:        "Sq",           "Sm",           "Sx",           "Sy",
                     53:        "Tn",           "Ux",           "Xc",           "Xo",
                     54:        "Fo",           "Fc",           "Oo",           "Oc",
                     55:        "Bk",           "Ek",           "Bt",           "Hf",
1.82      kristaps   56:        "Fr",           "Ud",           "Lb",           "Lp",
                     57:        "Lk",           "Mt",           "Brq",          "Bro",
1.64      kristaps   58:        /* LINTED */
1.82      kristaps   59:        "Brc",          "\%C",          "Es",           "En",
1.69      kristaps   60:        /* LINTED */
1.82      kristaps   61:        "Dx",           "\%Q"
1.1       kristaps   62:        };
                     63:
                     64: const  char *const __mdoc_argnames[MDOC_ARG_MAX] = {
                     65:        "split",                "nosplit",              "ragged",
                     66:        "unfilled",             "literal",              "file",
                     67:        "offset",               "bullet",               "dash",
                     68:        "hyphen",               "item",                 "enum",
                     69:        "tag",                  "diag",                 "hang",
                     70:        "ohang",                "inset",                "column",
                     71:        "width",                "compact",              "std",
1.52      kristaps   72:        "filled",               "words",                "emphasis",
1.64      kristaps   73:        "symbolic",             "nested"
1.1       kristaps   74:        };
                     75:
                     76: const  char * const *mdoc_macronames = __mdoc_macronames;
                     77: const  char * const *mdoc_argnames = __mdoc_argnames;
                     78:
1.73      kristaps   79: static void              mdoc_free1(struct mdoc *);
                     80: static int               mdoc_alloc1(struct mdoc *);
                     81: static struct mdoc_node *node_alloc(struct mdoc *, int, int,
                     82:                                int, enum mdoc_type);
                     83: static int               node_append(struct mdoc *,
1.71      kristaps   84:                                struct mdoc_node *);
                     85: static int               parsetext(struct mdoc *, int, char *);
                     86: static int               parsemacro(struct mdoc *, int, char *);
                     87: static int               macrowarn(struct mdoc *, int, const char *);
1.88    ! kristaps   88:
1.71      kristaps   89:
1.1       kristaps   90: const struct mdoc_node *
1.71      kristaps   91: mdoc_node(const struct mdoc *m)
1.1       kristaps   92: {
                     93:
1.71      kristaps   94:        return(MDOC_HALT & m->flags ? NULL : m->first);
1.1       kristaps   95: }
                     96:
                     97:
1.37      kristaps   98: const struct mdoc_meta *
1.71      kristaps   99: mdoc_meta(const struct mdoc *m)
1.37      kristaps  100: {
                    101:
1.71      kristaps  102:        return(MDOC_HALT & m->flags ? NULL : &m->meta);
1.37      kristaps  103: }
                    104:
                    105:
1.85      kristaps  106: /*
                    107:  * Frees volatile resources (parse tree, meta-data, fields).
                    108:  */
1.73      kristaps  109: static void
                    110: mdoc_free1(struct mdoc *mdoc)
1.67      kristaps  111: {
                    112:
                    113:        if (mdoc->first)
                    114:                mdoc_node_freelist(mdoc->first);
                    115:        if (mdoc->meta.title)
                    116:                free(mdoc->meta.title);
                    117:        if (mdoc->meta.os)
                    118:                free(mdoc->meta.os);
                    119:        if (mdoc->meta.name)
                    120:                free(mdoc->meta.name);
                    121:        if (mdoc->meta.arch)
                    122:                free(mdoc->meta.arch);
                    123:        if (mdoc->meta.vol)
                    124:                free(mdoc->meta.vol);
1.73      kristaps  125: }
                    126:
                    127:
1.85      kristaps  128: /*
                    129:  * Allocate all volatile resources (parse tree, meta-data, fields).
                    130:  */
1.73      kristaps  131: static int
                    132: mdoc_alloc1(struct mdoc *mdoc)
                    133: {
1.67      kristaps  134:
                    135:        bzero(&mdoc->meta, sizeof(struct mdoc_meta));
                    136:        mdoc->flags = 0;
1.85      kristaps  137:        mdoc->lastnamed = mdoc->lastsec = SEC_NONE;
1.70      kristaps  138:        mdoc->last = calloc(1, sizeof(struct mdoc_node));
                    139:        if (NULL == mdoc->last)
1.73      kristaps  140:                return(0);
                    141:
1.70      kristaps  142:        mdoc->first = mdoc->last;
1.67      kristaps  143:        mdoc->last->type = MDOC_ROOT;
                    144:        mdoc->next = MDOC_NEXT_CHILD;
1.73      kristaps  145:        return(1);
                    146: }
                    147:
                    148:
                    149: /*
1.85      kristaps  150:  * Free up volatile resources (see mdoc_free1()) then re-initialises the
                    151:  * data with mdoc_alloc1().  After invocation, parse data has been reset
                    152:  * and the parser is ready for re-invocation on a new tree; however,
                    153:  * cross-parse non-volatile data is kept intact.
1.73      kristaps  154:  */
                    155: int
                    156: mdoc_reset(struct mdoc *mdoc)
                    157: {
                    158:
                    159:        mdoc_free1(mdoc);
                    160:        return(mdoc_alloc1(mdoc));
1.67      kristaps  161: }
                    162:
                    163:
1.68      kristaps  164: /*
1.85      kristaps  165:  * Completely free up all volatile and non-volatile parse resources.
                    166:  * After invocation, the pointer is no longer usable.
1.68      kristaps  167:  */
1.67      kristaps  168: void
1.38      kristaps  169: mdoc_free(struct mdoc *mdoc)
1.34      kristaps  170: {
                    171:
1.73      kristaps  172:        mdoc_free1(mdoc);
1.68      kristaps  173:        if (mdoc->htab)
1.74      kristaps  174:                mdoc_hash_free(mdoc->htab);
1.1       kristaps  175:        free(mdoc);
                    176: }
                    177:
                    178:
1.85      kristaps  179: /*
                    180:  * Allocate volatile and non-volatile parse resources.
                    181:  */
1.1       kristaps  182: struct mdoc *
1.55      kristaps  183: mdoc_alloc(void *data, int pflags, const struct mdoc_cb *cb)
1.1       kristaps  184: {
                    185:        struct mdoc     *p;
                    186:
1.70      kristaps  187:        if (NULL == (p = calloc(1, sizeof(struct mdoc))))
1.73      kristaps  188:                return(NULL);
1.74      kristaps  189:        if (cb)
                    190:                (void)memcpy(&p->cb, cb, sizeof(struct mdoc_cb));
1.1       kristaps  191:
                    192:        p->data = data;
1.73      kristaps  193:        p->pflags = pflags;
                    194:
1.74      kristaps  195:        if (NULL == (p->htab = mdoc_hash_alloc())) {
                    196:                free(p);
                    197:                return(NULL);
                    198:        } else if (mdoc_alloc1(p))
                    199:                return(p);
1.1       kristaps  200:
1.73      kristaps  201:        free(p);
                    202:        return(NULL);
1.1       kristaps  203: }
                    204:
                    205:
1.68      kristaps  206: /*
                    207:  * Climb back up the parse tree, validating open scopes.  Mostly calls
1.85      kristaps  208:  * through to macro_end() in macro.c.
1.68      kristaps  209:  */
1.1       kristaps  210: int
1.72      kristaps  211: mdoc_endparse(struct mdoc *m)
1.20      kristaps  212: {
                    213:
1.72      kristaps  214:        if (MDOC_HALT & m->flags)
1.20      kristaps  215:                return(0);
1.72      kristaps  216:        else if (mdoc_macroend(m))
1.20      kristaps  217:                return(1);
1.72      kristaps  218:        m->flags |= MDOC_HALT;
                    219:        return(0);
1.20      kristaps  220: }
                    221:
                    222:
1.50      kristaps  223: /*
1.53      kristaps  224:  * Main parse routine.  Parses a single line -- really just hands off to
1.85      kristaps  225:  * the macro (parsemacro()) or text parser (parsetext()).
1.50      kristaps  226:  */
1.20      kristaps  227: int
1.53      kristaps  228: mdoc_parseln(struct mdoc *m, int ln, char *buf)
1.1       kristaps  229: {
                    230:
1.53      kristaps  231:        if (MDOC_HALT & m->flags)
1.20      kristaps  232:                return(0);
1.50      kristaps  233:
1.53      kristaps  234:        return('.' == *buf ? parsemacro(m, ln, buf) :
                    235:                        parsetext(m, ln, buf));
1.1       kristaps  236: }
                    237:
                    238:
                    239: int
1.31      kristaps  240: mdoc_verr(struct mdoc *mdoc, int ln, int pos,
                    241:                const char *fmt, ...)
1.1       kristaps  242: {
1.31      kristaps  243:        char             buf[256];
                    244:        va_list          ap;
1.1       kristaps  245:
                    246:        if (NULL == mdoc->cb.mdoc_err)
                    247:                return(0);
1.31      kristaps  248:
                    249:        va_start(ap, fmt);
                    250:        (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
                    251:        va_end(ap);
1.88    ! kristaps  252:
1.31      kristaps  253:        return((*mdoc->cb.mdoc_err)(mdoc->data, ln, pos, buf));
1.1       kristaps  254: }
                    255:
                    256:
                    257: int
1.87      kristaps  258: mdoc_vwarn(struct mdoc *mdoc, int ln, int pos, const char *fmt, ...)
1.1       kristaps  259: {
1.31      kristaps  260:        char             buf[256];
                    261:        va_list          ap;
1.1       kristaps  262:
                    263:        if (NULL == mdoc->cb.mdoc_warn)
                    264:                return(0);
1.31      kristaps  265:
                    266:        va_start(ap, fmt);
                    267:        (void)vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
                    268:        va_end(ap);
1.88    ! kristaps  269:
1.87      kristaps  270:        return((*mdoc->cb.mdoc_warn)(mdoc->data, ln, pos, buf));
1.1       kristaps  271: }
                    272:
                    273:
                    274: int
1.88    ! kristaps  275: mdoc_err(struct mdoc *m, int line, int pos, int iserr, enum merr type)
1.78      kristaps  276: {
1.88    ! kristaps  277:        char             *p;
        !           278:
        !           279:        p = NULL;
1.73      kristaps  280:
                    281:        switch (type) {
                    282:        case (ENOCALL):
                    283:                p = "not callable";
                    284:                break;
                    285:        case (EPROLBODY):
                    286:                p = "macro disallowed in document body";
                    287:                break;
                    288:        case (EBODYPROL):
                    289:                p = "macro disallowed in document prologue";
                    290:                break;
                    291:        case (EMALLOC):
                    292:                p = "memory exhausted";
                    293:                break;
                    294:        case (ETEXTPROL):
                    295:                p = "text disallowed in document prologue";
                    296:                break;
                    297:        case (ENOBLANK):
                    298:                p = "blank lines disallowed in non-literal contexts";
                    299:                break;
                    300:        case (ESPACE):
                    301:                p = "whitespace disallowed after delimiter";
                    302:                break;
1.88    ! kristaps  303:        case (ETOOLONG):
        !           304:                p = "text argument too long";
        !           305:                break;
        !           306:        case (EESCAPE):
        !           307:                p = "invalid escape sequence";
        !           308:                break;
        !           309:        case (EPRINT):
        !           310:                p = "invalid character";
        !           311:                break;
        !           312:        case (ENESTDISP):
        !           313:                p = "displays may not be nested";
        !           314:                break;
        !           315:        case (EBOOL):
        !           316:                p = "expected boolean value";
        !           317:                break;
        !           318:        case (EARGREP):
        !           319:                p = "argument repeated";
        !           320:                break;
        !           321:        case (EMULTIDISP):
        !           322:                p = "multiple display types specified";
        !           323:                break;
        !           324:        case (EMULTILIST):
        !           325:                p = "multiple list types specified";
        !           326:                break;
        !           327:        case (ELISTTYPE):
        !           328:                p = "missing list type";
        !           329:                break;
        !           330:        case (EDISPTYPE):
        !           331:                p = "missing display type";
        !           332:                break;
        !           333:        case (ESECNAME):
        !           334:                p = "the NAME section must come first";
        !           335:                break;
        !           336:        case (ELINE):
        !           337:                p = "expected line arguments";
        !           338:                break;
        !           339:        case (ENOPROLOGUE):
        !           340:                p = "document has no prologue";
        !           341:                break;
        !           342:        case (ENODAT):
        !           343:                p = "document has no data";
        !           344:                break;
        !           345:        case (ECOLMIS):
        !           346:                p = "column syntax style mismatch";
        !           347:                break;
        !           348:        case (EATT):
        !           349:                p = "expected valid AT&T symbol";
        !           350:                break;
        !           351:        case (ENAME):
        !           352:                p = "default name not yet set";
        !           353:                break;
        !           354:        case (ENOWIDTH):
        !           355:                p = "superfluous width argument";
        !           356:                break;
        !           357:        case (EMISSWIDTH):
        !           358:                p = "missing width argument";
        !           359:                break;
        !           360:        case (EWRONGMSEC):
        !           361:                p = "document section in wrong manual section";
        !           362:                break;
        !           363:        case (ESECOOO):
        !           364:                p = "document section out of conventional order";
        !           365:                break;
        !           366:        case (ESECREP):
        !           367:                p = "document section repeated";
        !           368:                break;
        !           369:        case (EBADSTAND):
        !           370:                p = "unknown standard";
        !           371:                break;
        !           372:        case (ENAMESECINC):
        !           373:                p = "NAME section contents incomplete/badly-ordered";
        !           374:                break;
        !           375:        case (ENOMULTILINE):
        !           376:                p = "suggested no multi-line arguments";
        !           377:                break;
        !           378:        case (EMULTILINE):
        !           379:                p = "suggested multi-line arguments";
        !           380:                break;
        !           381:        case (ENOLINE):
        !           382:                p = "suggested no line arguments";
        !           383:                break;
        !           384:        case (EPROLOOO):
        !           385:                p = "prologue macros out-of-order";
        !           386:                break;
        !           387:        case (EPROLREP):
        !           388:                p = "prologue macros repeated";
        !           389:                break;
        !           390:        case (EARGVAL):
        !           391:                p = "argument value suggested";
        !           392:                break;
        !           393:        case (EFONT):
        !           394:                p = "invalid font mode";
        !           395:                break;
        !           396:        case (EBADMSEC):
        !           397:                p = "inappropriate manual section";
        !           398:                break;
        !           399:        case (EBADSEC):
        !           400:                p = "inappropriate document section";
        !           401:                break;
        !           402:        case (EQUOTTERM):
        !           403:                p = "unterminated quoted parameter";
        !           404:                break;
        !           405:        case (EQUOTPARM):
        !           406:                p = "unexpected quoted parameter";
        !           407:                break;
        !           408:        case (EARGVPARM):
        !           409:                p = "argument-like parameter";
        !           410:                break;
        !           411:        case (ECOLEMPTY):
        !           412:                p = "last list column is empty";
        !           413:                break;
        !           414:        case (ETAILWS):
        !           415:                p = "trailing whitespace";
        !           416:                break;
        !           417:        case (ENUMFMT):
        !           418:                p = "bad number format";
        !           419:                break;
        !           420:        case (EUTSNAME):
        !           421:                p = "utsname";
        !           422:                break;
        !           423:        case (EBADDATE):
        !           424:                p = "malformed date syntax";
        !           425:                break;
        !           426:        case (EOPEN):
        !           427:                p = "explicit scope still open on exit";
        !           428:                break;
        !           429:        case (EQUOT):
        !           430:                p = "unterminated quotation";
        !           431:                break;
        !           432:        case (ENOCTX):
        !           433:                p = "closure has no prior context";
        !           434:                break;
        !           435:        case (ENOPARMS):
        !           436:                p = "unexpect line arguments";
        !           437:                break;
        !           438:        case (EIGNE):
        !           439:                p = "ignoring empty element";
        !           440:                break;
        !           441:        case (EIMPBRK):
        !           442:                p = "crufty end-of-line scope violation";
        !           443:                break;
        !           444:        case (EMACPARM):
        !           445:                p = "macro-like parameter";
        !           446:                break;
        !           447:        case (EOBS):
        !           448:                p = "macro marked obsolete";
        !           449:                break;
1.73      kristaps  450:        }
1.88    ! kristaps  451:
1.73      kristaps  452:        assert(p);
1.88    ! kristaps  453:
        !           454:        if (iserr)
        !           455:                return(mdoc_verr(m, line, pos, p));
        !           456:
        !           457:        return(mdoc_vwarn(m, line, pos, p));
        !           458: }
        !           459:
        !           460:
        !           461: int
        !           462: mdoc_macro(struct mdoc *m, int tok,
        !           463:                int ln, int pp, int *pos, char *buf)
        !           464: {
        !           465:
        !           466:        if (MDOC_PROLOGUE & mdoc_macros[tok].flags &&
        !           467:                        MDOC_PBODY & m->flags)
        !           468:                return(mdoc_perr(m, ln, pp, EPROLBODY));
        !           469:        if ( ! (MDOC_PROLOGUE & mdoc_macros[tok].flags) &&
        !           470:                        ! (MDOC_PBODY & m->flags))
        !           471:                return(mdoc_perr(m, ln, pp, EBODYPROL));
        !           472:
        !           473:        if (1 != pp && ! (MDOC_CALLABLE & mdoc_macros[tok].flags))
        !           474:                return(mdoc_perr(m, ln, pp, ENOCALL));
        !           475:
        !           476:        return((*mdoc_macros[tok].fp)(m, tok, ln, pp, pos, buf));
1.73      kristaps  477: }
                    478:
                    479:
                    480: static int
                    481: node_append(struct mdoc *mdoc, struct mdoc_node *p)
1.1       kristaps  482: {
                    483:
1.25      kristaps  484:        assert(mdoc->last);
                    485:        assert(mdoc->first);
                    486:        assert(MDOC_ROOT != p->type);
1.1       kristaps  487:
1.13      kristaps  488:        switch (mdoc->next) {
                    489:        case (MDOC_NEXT_SIBLING):
1.6       kristaps  490:                mdoc->last->next = p;
                    491:                p->prev = mdoc->last;
1.13      kristaps  492:                p->parent = mdoc->last->parent;
1.1       kristaps  493:                break;
1.13      kristaps  494:        case (MDOC_NEXT_CHILD):
                    495:                mdoc->last->child = p;
1.1       kristaps  496:                p->parent = mdoc->last;
                    497:                break;
                    498:        default:
1.13      kristaps  499:                abort();
                    500:                /* NOTREACHED */
1.1       kristaps  501:        }
                    502:
1.86      kristaps  503:        p->parent->nchild++;
                    504:
1.23      kristaps  505:        if ( ! mdoc_valid_pre(mdoc, p))
                    506:                return(0);
1.68      kristaps  507:        if ( ! mdoc_action_pre(mdoc, p))
                    508:                return(0);
1.27      kristaps  509:
                    510:        switch (p->type) {
                    511:        case (MDOC_HEAD):
                    512:                assert(MDOC_BLOCK == p->parent->type);
1.53      kristaps  513:                p->parent->head = p;
1.27      kristaps  514:                break;
                    515:        case (MDOC_TAIL):
                    516:                assert(MDOC_BLOCK == p->parent->type);
1.53      kristaps  517:                p->parent->tail = p;
1.27      kristaps  518:                break;
                    519:        case (MDOC_BODY):
                    520:                assert(MDOC_BLOCK == p->parent->type);
1.53      kristaps  521:                p->parent->body = p;
1.27      kristaps  522:                break;
                    523:        default:
                    524:                break;
                    525:        }
                    526:
1.1       kristaps  527:        mdoc->last = p;
1.71      kristaps  528:
                    529:        switch (p->type) {
                    530:        case (MDOC_TEXT):
                    531:                if ( ! mdoc_valid_post(mdoc))
                    532:                        return(0);
                    533:                if ( ! mdoc_action_post(mdoc))
                    534:                        return(0);
                    535:                break;
                    536:        default:
                    537:                break;
                    538:        }
                    539:
1.23      kristaps  540:        return(1);
1.1       kristaps  541: }
                    542:
                    543:
1.45      kristaps  544: static struct mdoc_node *
1.73      kristaps  545: node_alloc(struct mdoc *mdoc, int line,
                    546:                int pos, int tok, enum mdoc_type type)
1.45      kristaps  547: {
1.46      kristaps  548:        struct mdoc_node *p;
                    549:
1.73      kristaps  550:        if (NULL == (p = calloc(1, sizeof(struct mdoc_node)))) {
1.88    ! kristaps  551:                (void)mdoc_nerr(mdoc, mdoc->last, EMALLOC);
1.73      kristaps  552:                return(NULL);
                    553:        }
                    554:
1.46      kristaps  555:        p->sec = mdoc->lastsec;
1.73      kristaps  556:        p->line = line;
                    557:        p->pos = pos;
                    558:        p->tok = tok;
                    559:        if (MDOC_TEXT != (p->type = type))
                    560:                assert(p->tok >= 0);
1.45      kristaps  561:
1.46      kristaps  562:        return(p);
1.45      kristaps  563: }
                    564:
                    565:
1.23      kristaps  566: int
1.22      kristaps  567: mdoc_tail_alloc(struct mdoc *mdoc, int line, int pos, int tok)
1.17      kristaps  568: {
                    569:        struct mdoc_node *p;
                    570:
1.73      kristaps  571:        p = node_alloc(mdoc, line, pos, tok, MDOC_TAIL);
                    572:        if (NULL == p)
                    573:                return(0);
                    574:        return(node_append(mdoc, p));
1.17      kristaps  575: }
                    576:
                    577:
1.23      kristaps  578: int
1.22      kristaps  579: mdoc_head_alloc(struct mdoc *mdoc, int line, int pos, int tok)
1.1       kristaps  580: {
                    581:        struct mdoc_node *p;
                    582:
                    583:        assert(mdoc->first);
                    584:        assert(mdoc->last);
                    585:
1.73      kristaps  586:        p = node_alloc(mdoc, line, pos, tok, MDOC_HEAD);
                    587:        if (NULL == p)
                    588:                return(0);
                    589:        return(node_append(mdoc, p));
1.1       kristaps  590: }
                    591:
                    592:
1.23      kristaps  593: int
1.22      kristaps  594: mdoc_body_alloc(struct mdoc *mdoc, int line, int pos, int tok)
1.1       kristaps  595: {
                    596:        struct mdoc_node *p;
                    597:
1.73      kristaps  598:        p = node_alloc(mdoc, line, pos, tok, MDOC_BODY);
                    599:        if (NULL == p)
                    600:                return(0);
                    601:        return(node_append(mdoc, p));
1.1       kristaps  602: }
                    603:
                    604:
1.23      kristaps  605: int
1.22      kristaps  606: mdoc_block_alloc(struct mdoc *mdoc, int line, int pos,
1.53      kristaps  607:                int tok, struct mdoc_arg *args)
1.1       kristaps  608: {
                    609:        struct mdoc_node *p;
                    610:
1.73      kristaps  611:        p = node_alloc(mdoc, line, pos, tok, MDOC_BLOCK);
                    612:        if (NULL == p)
                    613:                return(0);
1.77      kristaps  614:        p->args = args;
                    615:        if (p->args)
1.53      kristaps  616:                (args->refcnt)++;
1.73      kristaps  617:        return(node_append(mdoc, p));
1.1       kristaps  618: }
                    619:
                    620:
1.23      kristaps  621: int
1.22      kristaps  622: mdoc_elem_alloc(struct mdoc *mdoc, int line, int pos,
1.53      kristaps  623:                int tok, struct mdoc_arg *args)
1.1       kristaps  624: {
                    625:        struct mdoc_node *p;
                    626:
1.73      kristaps  627:        p = node_alloc(mdoc, line, pos, tok, MDOC_ELEM);
                    628:        if (NULL == p)
                    629:                return(0);
1.77      kristaps  630:        p->args = args;
                    631:        if (p->args)
1.53      kristaps  632:                (args->refcnt)++;
1.73      kristaps  633:        return(node_append(mdoc, p));
1.1       kristaps  634: }
                    635:
                    636:
1.23      kristaps  637: int
1.22      kristaps  638: mdoc_word_alloc(struct mdoc *mdoc,
                    639:                int line, int pos, const char *word)
1.1       kristaps  640: {
                    641:        struct mdoc_node *p;
                    642:
1.73      kristaps  643:        p = node_alloc(mdoc, line, pos, -1, MDOC_TEXT);
                    644:        if (NULL == p)
                    645:                return(0);
                    646:        if (NULL == (p->string = strdup(word))) {
1.88    ! kristaps  647:                (void)mdoc_nerr(mdoc, mdoc->last, EMALLOC);
1.73      kristaps  648:                return(0);
                    649:        }
1.88    ! kristaps  650:
1.73      kristaps  651:        return(node_append(mdoc, p));
1.1       kristaps  652: }
                    653:
                    654:
1.53      kristaps  655: void
                    656: mdoc_node_free(struct mdoc_node *p)
1.1       kristaps  657: {
                    658:
1.86      kristaps  659:        if (p->parent)
                    660:                p->parent->nchild--;
1.53      kristaps  661:        if (p->string)
                    662:                free(p->string);
                    663:        if (p->args)
                    664:                mdoc_argv_free(p->args);
1.1       kristaps  665:        free(p);
                    666: }
                    667:
                    668:
1.53      kristaps  669: void
                    670: mdoc_node_freelist(struct mdoc_node *p)
1.1       kristaps  671: {
                    672:
1.53      kristaps  673:        if (p->child)
                    674:                mdoc_node_freelist(p->child);
                    675:        if (p->next)
                    676:                mdoc_node_freelist(p->next);
1.1       kristaps  677:
1.86      kristaps  678:        assert(0 == p->nchild);
1.53      kristaps  679:        mdoc_node_free(p);
1.1       kristaps  680: }
                    681:
                    682:
1.53      kristaps  683: /*
                    684:  * Parse free-form text, that is, a line that does not begin with the
                    685:  * control character.
                    686:  */
                    687: static int
1.68      kristaps  688: parsetext(struct mdoc *m, int line, char *buf)
1.1       kristaps  689: {
                    690:
1.85      kristaps  691:        if (SEC_NONE == m->lastnamed)
1.88    ! kristaps  692:                return(mdoc_perr(m, line, 0, ETEXTPROL));
1.1       kristaps  693:
1.68      kristaps  694:        if (0 == buf[0] && ! (MDOC_LITERAL & m->flags))
1.88    ! kristaps  695:                return(mdoc_perr(m, line, 0, ENOBLANK));
1.68      kristaps  696:
                    697:        if ( ! mdoc_word_alloc(m, line, 0, buf))
1.53      kristaps  698:                return(0);
1.1       kristaps  699:
1.68      kristaps  700:        m->next = MDOC_NEXT_SIBLING;
1.53      kristaps  701:        return(1);
1.1       kristaps  702: }
                    703:
                    704:
1.58      kristaps  705: static int
                    706: macrowarn(struct mdoc *m, int ln, const char *buf)
                    707: {
                    708:        if ( ! (MDOC_IGN_MACRO & m->pflags))
1.88    ! kristaps  709:                return(mdoc_verr(m, ln, 1,
1.73      kristaps  710:                                "unknown macro: %s%s",
1.59      kristaps  711:                                buf, strlen(buf) > 3 ? "..." : ""));
1.88    ! kristaps  712:        return(mdoc_vwarn(m, ln, 1, "unknown macro: %s%s",
1.59      kristaps  713:                                buf, strlen(buf) > 3 ? "..." : ""));
1.58      kristaps  714: }
                    715:
                    716:
1.53      kristaps  717: /*
                    718:  * Parse a macro line, that is, a line beginning with the control
                    719:  * character.
                    720:  */
                    721: int
                    722: parsemacro(struct mdoc *m, int ln, char *buf)
1.1       kristaps  723: {
1.53      kristaps  724:        int               i, c;
                    725:        char              mac[5];
1.1       kristaps  726:
1.81      kristaps  727:        /* Empty lines are ignored. */
1.63      kristaps  728:
                    729:        if (0 == buf[1])
                    730:                return(1);
                    731:
1.65      kristaps  732:        if (' ' == buf[1]) {
1.63      kristaps  733:                i = 2;
1.65      kristaps  734:                while (buf[i] && ' ' == buf[i])
1.63      kristaps  735:                        i++;
                    736:                if (0 == buf[i])
                    737:                        return(1);
1.88    ! kristaps  738:                return(mdoc_perr(m, ln, 1, ESPACE));
1.63      kristaps  739:        }
1.1       kristaps  740:
1.53      kristaps  741:        /* Copy the first word into a nil-terminated buffer. */
1.1       kristaps  742:
1.53      kristaps  743:        for (i = 1; i < 5; i++) {
                    744:                if (0 == (mac[i - 1] = buf[i]))
                    745:                        break;
1.65      kristaps  746:                else if (' ' == buf[i])
1.53      kristaps  747:                        break;
                    748:        }
1.1       kristaps  749:
1.53      kristaps  750:        mac[i - 1] = 0;
1.1       kristaps  751:
1.53      kristaps  752:        if (i == 5 || i <= 2) {
1.58      kristaps  753:                if ( ! macrowarn(m, ln, mac))
                    754:                        goto err;
                    755:                return(1);
1.53      kristaps  756:        }
                    757:
1.74      kristaps  758:        if (MDOC_MAX == (c = mdoc_hash_find(m->htab, mac))) {
1.58      kristaps  759:                if ( ! macrowarn(m, ln, mac))
                    760:                        goto err;
                    761:                return(1);
1.53      kristaps  762:        }
1.1       kristaps  763:
1.53      kristaps  764:        /* The macro is sane.  Jump to the next word. */
1.1       kristaps  765:
1.65      kristaps  766:        while (buf[i] && ' ' == buf[i])
1.53      kristaps  767:                i++;
1.1       kristaps  768:
1.53      kristaps  769:        /* Begin recursive parse sequence. */
1.1       kristaps  770:
1.53      kristaps  771:        if ( ! mdoc_macro(m, c, ln, 1, &i, buf))
                    772:                goto err;
1.1       kristaps  773:
1.53      kristaps  774:        return(1);
1.1       kristaps  775:
1.53      kristaps  776: err:   /* Error out. */
1.1       kristaps  777:
1.53      kristaps  778:        m->flags |= MDOC_HALT;
                    779:        return(0);
1.1       kristaps  780: }

CVSweb