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

Annotation of mandoc/macro.c, Revision 1.5

1.5     ! kristaps    1: /* $Id: macro.c,v 1.4 2008/12/15 03:13:01 kristaps Exp $ */
1.1       kristaps    2: /*
                      3:  * Copyright (c) 2008 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
                      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:  */
1.2       kristaps   19: #include <assert.h>
                     20: #include <ctype.h>
1.1       kristaps   21: #include <stdlib.h>
1.2       kristaps   22: #include <stdio.h>
1.5     ! kristaps   23: #include <string.h>
1.2       kristaps   24:
                     25: #include "private.h"
                     26:
1.3       kristaps   27: #define        _CC(p)  ((const char **)p)
1.2       kristaps   28:
1.5     ! kristaps   29: static int       xstrlcat(char *, const char *, size_t);
        !            30: static int       xstrlcpy(char *, const char *, size_t);
        !            31: static int       xstrcmp(const char *, const char *);
1.3       kristaps   32: static int       append_text(struct mdoc *, int,
                     33:                        int, int, char *[]);
                     34: static int       append_scoped(struct mdoc *, int,
                     35:                        int, int, char *[]);
                     36: static int       args_next(struct mdoc *, int,
                     37:                        int *, char *, char **);
1.1       kristaps   38:
                     39:
                     40: static int
1.2       kristaps   41: args_next(struct mdoc *mdoc, int tok,
                     42:                int *pos, char *buf, char **v)
1.1       kristaps   43: {
                     44:
                     45:        if (0 == buf[*pos])
                     46:                return(0);
                     47:
1.2       kristaps   48:        assert( ! isspace(buf[*pos]));
                     49:
1.1       kristaps   50:        if ('\"' == buf[*pos]) {
1.2       kristaps   51:                (void)mdoc_err(mdoc, tok, *pos, ERR_SYNTAX_QUOTE);
1.1       kristaps   52:                return(-1);
                     53:        }
                     54:
                     55:        *v = &buf[*pos];
                     56:
1.2       kristaps   57:        /* Scan ahead to end of token. */
                     58:
1.1       kristaps   59:        while (buf[*pos] && ! isspace(buf[*pos]))
                     60:                (*pos)++;
                     61:
1.2       kristaps   62:        if (buf[*pos] && buf[*pos + 1] && '\\' == buf[*pos]) {
                     63:                (void)mdoc_err(mdoc, tok, *pos, ERR_SYNTAX_WS);
1.1       kristaps   64:                return(-1);
                     65:        }
                     66:
1.2       kristaps   67:        if (0 == buf[*pos])
                     68:                return(1);
                     69:
                     70:        /* Scan ahead over trailing whitespace. */
                     71:
                     72:        buf[(*pos)++] = 0;
                     73:        while (buf[*pos] && isspace(buf[*pos]))
                     74:                (*pos)++;
                     75:
                     76:        if (0 == buf[*pos])
                     77:                if ( ! mdoc_warn(mdoc, tok, *pos, WARN_SYNTAX_WS_EOLN))
                     78:                        return(-1);
                     79:
1.1       kristaps   80:        return(1);
                     81: }
                     82:
1.2       kristaps   83:
                     84: static int
1.3       kristaps   85: append_scoped(struct mdoc *mdoc, int tok,
                     86:                int pos, int sz, char *args[])
1.2       kristaps   87: {
1.5     ! kristaps   88:        enum mdoc_sec    sec;
        !            89:
        !            90:        if (0 == sz)
        !            91:                return(mdoc_err(mdoc, tok, pos, ERR_ARGS_GE1));
1.2       kristaps   92:
1.4       kristaps   93:        switch (tok) {
                     94:         /* ======= ADD MORE MACRO CHECKS BELOW. ======= */
                     95:        case (MDOC_Sh):
1.5     ! kristaps   96:                sec = mdoc_atosec((size_t)sz, _CC(args));
        !            97:                if (SEC_CUSTOM != sec && sec < mdoc->sec_lastn)
        !            98:                        if ( ! mdoc_warn(mdoc, tok, pos, WARN_SEC_OO))
        !            99:                                return(0);
        !           100:
        !           101:                if (SEC_BODY == mdoc->sec_last && SEC_NAME != sec)
        !           102:                        return(mdoc_err(mdoc, tok, pos, ERR_SEC_NAME));
        !           103:
        !           104:                if (SEC_CUSTOM != sec)
        !           105:                        mdoc->sec_lastn = sec;
        !           106:                mdoc->sec_last = sec;
1.4       kristaps  107:                break;
                    108:        case (MDOC_Ss):
                    109:                break;
                    110:         /* ======= ADD MORE MACRO CHECKS ABOVE. ======= */
                    111:        default:
                    112:                abort();
                    113:                /* NOTREACHED */
                    114:        }
                    115:
1.3       kristaps  116:        assert(sz >= 0);
1.2       kristaps  117:        args[sz] = NULL;
                    118:        mdoc_block_alloc(mdoc, pos, tok, 0, NULL);
1.3       kristaps  119:        mdoc_head_alloc(mdoc, pos, tok, (size_t)sz, _CC(args));
1.2       kristaps  120:        mdoc_body_alloc(mdoc, pos, tok);
                    121:        return(1);
                    122: }
                    123:
                    124:
1.1       kristaps  125: static int
1.3       kristaps  126: append_text(struct mdoc *mdoc, int tok,
                    127:                int pos, int sz, char *args[])
1.1       kristaps  128: {
                    129:
1.3       kristaps  130:        assert(sz >= 0);
1.2       kristaps  131:        args[sz] = NULL;
                    132:
                    133:        switch (tok) {
1.4       kristaps  134:         /* ======= ADD MORE MACRO CHECKS BELOW. ======= */
1.2       kristaps  135:        case (MDOC_Ft):
                    136:                /* FALLTHROUGH */
                    137:        case (MDOC_Li):
                    138:                /* FALLTHROUGH */
                    139:        case (MDOC_Ms):
                    140:                /* FALLTHROUGH */
                    141:        case (MDOC_Pa):
                    142:                /* FALLTHROUGH */
                    143:        case (MDOC_Tn):
1.4       kristaps  144:                if (0 < sz)
                    145:                        break;
                    146:                if ( ! mdoc_warn(mdoc, tok, pos, WARN_ARGS_GE1))
1.1       kristaps  147:                        return(0);
1.4       kristaps  148:                break;
1.2       kristaps  149:        case (MDOC_Ar):
                    150:                /* FALLTHROUGH */
                    151:        case (MDOC_Cm):
                    152:                /* FALLTHROUGH */
                    153:        case (MDOC_Fl):
1.4       kristaps  154:                break;
1.2       kristaps  155:        case (MDOC_Ad):
                    156:                /* FALLTHROUGH */
                    157:        case (MDOC_Em):
                    158:                /* FALLTHROUGH */
                    159:        case (MDOC_Er):
                    160:                /* FALLTHROUGH */
                    161:        case (MDOC_Ev):
                    162:                /* FALLTHROUGH */
                    163:        case (MDOC_Fa):
                    164:                /* FALLTHROUGH */
                    165:        case (MDOC_Dv):
                    166:                /* FALLTHROUGH */
                    167:        case (MDOC_Ic):
                    168:                /* FALLTHROUGH */
                    169:        case (MDOC_Va):
                    170:                /* FALLTHROUGH */
                    171:        case (MDOC_Vt):
1.4       kristaps  172:                if (0 < sz)
                    173:                        break;
                    174:                return(mdoc_err(mdoc, tok, pos, ERR_ARGS_GE1));
                    175:         /* ======= ADD MORE MACRO CHECKS ABOVE. ======= */
1.2       kristaps  176:        default:
1.4       kristaps  177:                abort();
                    178:                /* NOTREACHED */
1.2       kristaps  179:        }
                    180:
1.4       kristaps  181:        mdoc_elem_alloc(mdoc, pos, tok, 0,
                    182:                        NULL, (size_t)sz, _CC(args));
                    183:        return(1);
1.2       kristaps  184: }
                    185:
1.1       kristaps  186:
1.2       kristaps  187: int
1.5     ! kristaps  188: macro_text(MACRO_PROT_ARGS)
1.2       kristaps  189: {
1.3       kristaps  190:        int               lastarg, c, lasttok, lastpunct, j;
1.2       kristaps  191:        char             *args[MDOC_LINEARG_MAX], *p;
1.1       kristaps  192:
1.2       kristaps  193:        lasttok = ppos;
                    194:        lastpunct = 0;
                    195:        j = 0;
                    196:
1.5     ! kristaps  197:        if (SEC_PROLOGUE == mdoc->sec_lastn)
        !           198:                return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE));
        !           199:
1.2       kristaps  200: again:
                    201:
                    202:        lastarg = *pos;
                    203:        c = args_next(mdoc, tok, pos, buf, &args[j]);
                    204:
                    205:        if (-1 == c)
                    206:                return(0);
                    207:        if (0 == c && ! lastpunct)
                    208:                return(append_text(mdoc, tok, lasttok, j, args));
                    209:        else if (0 == c)
                    210:                return(1);
                    211:
                    212:        /* Command found. */
                    213:
                    214:        if (MDOC_MAX != (c = mdoc_find(mdoc, args[j]))) {
                    215:                if ( ! lastpunct)
                    216:                        if ( ! append_text(mdoc, tok, lasttok, j, args))
1.1       kristaps  217:                                return(0);
1.2       kristaps  218:                return(mdoc_macro(mdoc, c, lastarg, pos, buf));
                    219:        }
                    220:
                    221:        /* Word found. */
                    222:
1.4       kristaps  223:        if ( ! mdoc_isdelim(args[j])) {
1.2       kristaps  224:                j++;
                    225:                goto again;
                    226:        }
                    227:
                    228:        /* Punctuation found.  */
                    229:
                    230:        p = args[j]; /* Save argument (NULL-ified in append). */
                    231:
                    232:        if ( ! lastpunct)
                    233:                if ( ! append_text(mdoc, tok, lasttok, j, args))
                    234:                        return(0);
                    235:
                    236:        args[j] = p;
                    237:
                    238:        mdoc_word_alloc(mdoc, lastarg, args[j]);
                    239:        lastpunct = 1;
                    240:        j = 0;
                    241:
                    242:        goto again;
                    243:
                    244:        /* NOTREACHED */
                    245: }
1.1       kristaps  246:
                    247:
1.2       kristaps  248: int
1.5     ! kristaps  249: macro_prologue_dtitle(MACRO_PROT_ARGS)
        !           250: {
        !           251:        int               c, lastarg, j;
        !           252:        char             *args[MDOC_LINEARG_MAX];
        !           253:
        !           254:        if (SEC_PROLOGUE != mdoc->sec_lastn)
        !           255:                return(mdoc_err(mdoc, tok, ppos, ERR_SEC_NPROLOGUE));
        !           256:        if (0 == mdoc->meta.date)
        !           257:                return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE_OO));
        !           258:        if (mdoc->meta.title[0])
        !           259:                return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE_REP));
        !           260:
        !           261:        j = -1;
        !           262:
        !           263: again:
        !           264:        lastarg = *pos;
        !           265:        c = args_next(mdoc, tok, pos, buf, &args[++j]);
        !           266:
        !           267:        if (0 == c) {
        !           268:                mdoc->sec_lastn = mdoc->sec_last = SEC_BODY; /* FIXME */
        !           269:                if (mdoc->meta.title)
        !           270:                        return(1);
        !           271:                if ( ! mdoc_warn(mdoc, tok, ppos, WARN_ARGS_GE1))
        !           272:                        return(0);
        !           273:                (void)xstrlcpy(mdoc->meta.title,
        !           274:                                "UNTITLED", META_TITLE_SZ);
        !           275:                return(1);
        !           276:        } else if (-1 == c)
        !           277:                return(0);
        !           278:
        !           279:        if (MDOC_MAX != mdoc_find(mdoc, args[j]) && ! mdoc_warn
        !           280:                        (mdoc, tok, lastarg, WARN_SYNTAX_MACLIKE))
        !           281:                return(0);
        !           282:
        !           283:        if (0 == j) {
        !           284:                if (xstrlcpy(mdoc->meta.title, args[0], META_TITLE_SZ))
        !           285:                        goto again;
        !           286:                return(mdoc_err(mdoc, tok, lastarg, ERR_SYNTAX_ARGS));
        !           287:
        !           288:        } else if (1 == j) {
        !           289:                mdoc->meta.msec = mdoc_atomsec(args[1]);
        !           290:                if (MSEC_DEFAULT != mdoc->meta.msec)
        !           291:                        goto again;
        !           292:                return(mdoc_err(mdoc, tok, -1, ERR_SYNTAX_ARGS));
        !           293:
        !           294:        } else if (2 == j) {
        !           295:                mdoc->meta.vol = mdoc_atovol(args[2]);
        !           296:                if (VOL_DEFAULT != mdoc->meta.vol)
        !           297:                        goto again;
        !           298:                mdoc->meta.arch = mdoc_atoarch(args[2]);
        !           299:                if (ARCH_DEFAULT != mdoc->meta.arch)
        !           300:                        goto again;
        !           301:                return(mdoc_err(mdoc, tok, lastarg, ERR_SYNTAX_ARGS));
        !           302:        }
        !           303:
        !           304:        return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
        !           305: }
        !           306:
        !           307:
        !           308: int
        !           309: macro_prologue_ddate(MACRO_PROT_ARGS)
        !           310: {
        !           311:        int               c, lastarg, j;
        !           312:        char             *args[MDOC_LINEARG_MAX], date[64];
        !           313:
        !           314:        if (SEC_PROLOGUE != mdoc->sec_lastn)
        !           315:                return(mdoc_err(mdoc, tok, ppos, ERR_SEC_NPROLOGUE));
        !           316:        if (mdoc->meta.title[0])
        !           317:                return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE_OO));
        !           318:        if (mdoc->meta.date)
        !           319:                return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE_REP));
        !           320:
        !           321:        j = -1;
        !           322:        date[0] = 0;
        !           323:
        !           324: again:
        !           325:
        !           326:        lastarg = *pos;
        !           327:        c = args_next(mdoc, tok, pos, buf, &args[++j]);
        !           328:        if (0 == c) {
        !           329:                if (mdoc->meta.date)
        !           330:                        return(1);
        !           331:                mdoc->meta.date = mdoc_atotime(date);
        !           332:                if (mdoc->meta.date)
        !           333:                        return(1);
        !           334:                return(mdoc_err(mdoc, tok, ppos, ERR_SYNTAX_ARGS));
        !           335:        } else if (-1 == c)
        !           336:                return(0);
        !           337:
        !           338:        if (MDOC_MAX != mdoc_find(mdoc, args[j]) && ! mdoc_warn
        !           339:                        (mdoc, tok, lastarg, WARN_SYNTAX_MACLIKE))
        !           340:                return(0);
        !           341:
        !           342:        if (0 == j) {
        !           343:                if (xstrcmp("$Mdocdate$", args[j])) {
        !           344:                        mdoc->meta.date = time(NULL);
        !           345:                        goto again;
        !           346:                } else if (xstrcmp("$Mdocdate:", args[j]))
        !           347:                        goto again;
        !           348:        } else if (4 == j)
        !           349:                if ( ! xstrcmp("$", args[j]))
        !           350:                        goto again;
        !           351:
        !           352:        if ( ! xstrlcat(date, args[j], sizeof(date)))
        !           353:                return(mdoc_err(mdoc, tok, lastarg, ERR_SYNTAX_ARGS));
        !           354:        if ( ! xstrlcat(date, " ", sizeof(date)))
        !           355:                return(mdoc_err(mdoc, tok, lastarg, ERR_SYNTAX_ARGS));
        !           356:
        !           357:        goto again;
        !           358:        /* NOTREACHED */
        !           359: }
        !           360:
        !           361:
        !           362: int
        !           363: macro_scoped_implicit(MACRO_PROT_ARGS)
1.2       kristaps  364: {
1.3       kristaps  365:        int               t, c, lastarg, j;
1.2       kristaps  366:        char             *args[MDOC_LINEARG_MAX];
                    367:        struct mdoc_node *n;
                    368:
1.5     ! kristaps  369:        assert( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags));
1.1       kristaps  370:
1.5     ! kristaps  371:        if (SEC_PROLOGUE == mdoc->sec_lastn)
        !           372:                return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE));
1.1       kristaps  373:
1.3       kristaps  374:        /* LINTED */
1.2       kristaps  375:        for (n = mdoc->last; n; n = n->parent) {
                    376:                if (MDOC_BLOCK != n->type)
                    377:                        continue;
                    378:                if (tok == (t = n->data.block.tok))
1.1       kristaps  379:                        break;
1.2       kristaps  380:                if ( ! (MDOC_EXPLICIT & mdoc_macros[t].flags))
                    381:                        continue;
                    382:                return(mdoc_err(mdoc, tok, ppos, ERR_SCOPE_BREAK));
                    383:        }
                    384:
                    385:        if (n) {
                    386:                mdoc->last = n;
                    387:                mdoc_msg(mdoc, ppos, "scope: rewound `%s'",
                    388:                                mdoc_macronames[tok]);
                    389:        } else
                    390:                mdoc_msg(mdoc, ppos, "scope: new `%s'",
                    391:                                mdoc_macronames[tok]);
                    392:
                    393:        j = 0;
                    394:
                    395: again:
                    396:
                    397:        lastarg = *pos;
                    398:        c = args_next(mdoc, tok, pos, buf, &args[j]);
                    399:
                    400:        if (-1 == c)
                    401:                return(0);
                    402:        if (0 == c)
                    403:                return(append_scoped(mdoc, tok, ppos, j, args));
1.1       kristaps  404:
1.2       kristaps  405:        /* Command found. */
1.1       kristaps  406:
1.2       kristaps  407:        if (MDOC_MAX != (c = mdoc_find(mdoc, args[j])))
1.3       kristaps  408:                if ( ! mdoc_warn(mdoc, tok, lastarg, WARN_SYNTAX_MACLIKE))
1.1       kristaps  409:                        return(0);
                    410:
1.2       kristaps  411:        /* Word found. */
                    412:
                    413:        j++;
                    414:        goto again;
1.1       kristaps  415:
1.2       kristaps  416:        /* NOTREACHED */
1.1       kristaps  417: }
1.5     ! kristaps  418:
        !           419:
        !           420: static int
        !           421: xstrcmp(const char *p1, const char *p2)
        !           422: {
        !           423:
        !           424:        return(0 == strcmp(p1, p2));
        !           425: }
        !           426:
        !           427:
        !           428: static int
        !           429: xstrlcat(char *dst, const char *src, size_t sz)
        !           430: {
        !           431:
        !           432:        return(strlcat(dst, src, sz) < sz);
        !           433: }
        !           434:
        !           435:
        !           436: static int
        !           437: xstrlcpy(char *dst, const char *src, size_t sz)
        !           438: {
        !           439:
        !           440:        return(strlcpy(dst, src, sz) < sz);
        !           441: }

CVSweb