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

Annotation of mandoc/man_macro.c, Revision 1.19

1.19    ! kristaps    1: /*     $Id: man_macro.c,v 1.18 2009/07/24 20:22:24 kristaps Exp $ */
1.1       kristaps    2: /*
1.15      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.14      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.14      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 <stdlib.h>
                     20: #include <string.h>
                     21:
                     22: #include "libman.h"
                     23:
1.19    ! kristaps   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:
        !            31: static int              rew_scope(enum man_type, struct man *, int);
        !            32: static int              rew_dohalt(int, enum man_type,
        !            33:                                const struct man_node *);
        !            34:
        !            35: const  struct man_macro __man_macros[MAN_MAX] = {
        !            36:        { in_line_eoln, 0 }, /* br */
        !            37:        { in_line_eoln, 0 }, /* TH */
        !            38:        { blk_imp, 0 }, /* SH */
        !            39:        { blk_imp, 0 }, /* SS */
        !            40:        { blk_imp, MAN_SCOPED }, /* TP */
        !            41:        { blk_imp, 0 }, /* LP */
        !            42:        { blk_imp, 0 }, /* PP */
        !            43:        { blk_imp, 0 }, /* P */
        !            44:        { blk_imp, 0 }, /* IP */
        !            45:        { blk_imp, 0 }, /* HP */
        !            46:        { in_line_eoln, MAN_SCOPED }, /* SM */
        !            47:        { in_line_eoln, MAN_SCOPED }, /* SB */
        !            48:        { in_line_eoln, 0 }, /* BI */
        !            49:        { in_line_eoln, 0 }, /* IB */
        !            50:        { in_line_eoln, 0 }, /* BR */
        !            51:        { in_line_eoln, 0 }, /* RB */
        !            52:        { in_line_eoln, MAN_SCOPED }, /* R */
        !            53:        { in_line_eoln, MAN_SCOPED }, /* B */
        !            54:        { in_line_eoln, MAN_SCOPED }, /* I */
        !            55:        { in_line_eoln, 0 }, /* IR */
        !            56:        { in_line_eoln, 0 }, /* RI */
        !            57:        { in_line_eoln, 0 }, /* na */
        !            58:        { in_line_eoln, 0 }, /* i */
        !            59:        { in_line_eoln, 0 }, /* sp */
        !            60:        { in_line_eoln, 0 }, /* nf */
        !            61:        { in_line_eoln, 0 }, /* fi */
        !            62:        { in_line_eoln, 0 }, /* r */
        !            63: };
1.9       kristaps   64:
1.19    ! kristaps   65: const  struct man_macro * const man_macros = __man_macros;
1.1       kristaps   66:
                     67:
1.3       kristaps   68: int
1.19    ! kristaps   69: man_unscope(struct man *m, const struct man_node *n)
1.1       kristaps   70: {
                     71:
1.19    ! kristaps   72:        assert(n);
        !            73:        m->next = MAN_NEXT_SIBLING;
        !            74:
        !            75:        /* LINTED */
        !            76:        while (m->last != n) {
        !            77:                if ( ! man_valid_post(m))
        !            78:                        return(0);
        !            79:                if ( ! man_action_post(m))
        !            80:                        return(0);
        !            81:                m->last = m->last->parent;
        !            82:                assert(m->last);
        !            83:        }
        !            84:
        !            85:        if ( ! man_valid_post(m))
1.1       kristaps   86:                return(0);
1.19    ! kristaps   87:        return(man_action_post(m));
        !            88: }
1.1       kristaps   89:
                     90:
1.19    ! kristaps   91: /*
        !            92:  * There are three scope levels: scoped to the root (all), scoped to the
        !            93:  * section (all less sections), and scoped to subsections (all less
        !            94:  * sections and subsections).
        !            95:  */
        !            96: static int
        !            97: rew_dohalt(int tok, enum man_type type, const struct man_node *n)
        !            98: {
1.1       kristaps   99:
1.19    ! kristaps  100:        if (MAN_ROOT == n->type)
        !           101:                return(REW_HALT);
        !           102:        assert(n->parent);
        !           103:        if (MAN_ROOT == n->parent->type)
        !           104:                return(REW_REWIND);
        !           105:        if (MAN_VALID & n->flags)
        !           106:                return(REW_NOHALT);
        !           107:
        !           108:        switch (tok) {
        !           109:        case (MAN_SH):
        !           110:                /* Break at root. */
        !           111:                if (type == n->type && tok == n->tok)
        !           112:                        return(REW_REWIND);
        !           113:                break;
        !           114:        case (MAN_SS):
        !           115:                /* Break at section. */
        !           116:                if (type == n->type && tok == n->tok)
        !           117:                        return(REW_REWIND);
        !           118:                if (MAN_BODY == n->type && MAN_SH == n->tok)
        !           119:                        return(REW_HALT);
        !           120:                break;
        !           121:        default:
        !           122:                /* Break at subsection. */
        !           123:                if (type == n->type && tok == n->tok)
        !           124:                        return(REW_REWIND);
        !           125:                if (MAN_BODY == n->type && MAN_SS == n->tok)
        !           126:                        return(REW_HALT);
        !           127:                if (MAN_BODY == n->type && MAN_SH == n->tok)
        !           128:                        return(REW_HALT);
        !           129:                break;
1.3       kristaps  130:        }
1.1       kristaps  131:
1.19    ! kristaps  132:        return(REW_NOHALT);
        !           133: }
1.9       kristaps  134:
                    135:
1.19    ! kristaps  136: /*
        !           137:  * Rewinding entails ascending the parse tree until a coherent point,
        !           138:  * for example, the `SH' macro will close out any intervening `SS'
        !           139:  * scopes.  When a scope is closed, it must be validated and actioned.
        !           140:  */
        !           141: static int
        !           142: rew_scope(enum man_type type, struct man *m, int tok)
        !           143: {
        !           144:        struct man_node *n;
        !           145:        int              c;
1.7       kristaps  146:
1.19    ! kristaps  147:        /* LINTED */
        !           148:        for (n = m->last; n; n = n->parent) {
        !           149:                /*
        !           150:                 * Whether we should stop immediately (REW_HALT), stop
        !           151:                 * and rewind until this point (REW_REWIND), or keep
        !           152:                 * rewinding (REW_NOHALT).
        !           153:                 */
        !           154:                c = rew_dohalt(tok, type, n);
        !           155:                if (REW_HALT == c)
        !           156:                        return(1);
        !           157:                if (REW_REWIND == c)
1.7       kristaps  158:                        break;
1.6       kristaps  159:        }
1.1       kristaps  160:
1.19    ! kristaps  161:        /* Rewind until the current point. */
        !           162:
        !           163:        assert(n);
        !           164:        return(man_unscope(m, n));
        !           165: }
        !           166:
1.6       kristaps  167:
1.19    ! kristaps  168: /*
        !           169:  * Parse an implicit-block macro.  These contain a MAN_HEAD and a
        !           170:  * MAN_BODY contained within a MAN_BLOCK.  Rules for closing out other
        !           171:  * scopes, such as `SH' closing out an `SS', are defined in the rew
        !           172:  * routines.
        !           173:  */
        !           174: int
        !           175: blk_imp(MACRO_PROT_ARGS)
        !           176: {
        !           177:        int              w, la;
        !           178:        char            *p;
        !           179:
        !           180:        /* Close out prior scopes. */
1.7       kristaps  181:
1.19    ! kristaps  182:        if ( ! rew_scope(MAN_BODY, m, tok))
1.5       kristaps  183:                return(0);
1.19    ! kristaps  184:        if ( ! rew_scope(MAN_BLOCK, m, tok))
1.6       kristaps  185:                return(0);
1.1       kristaps  186:
1.19    ! kristaps  187:        /* Allocate new block & head scope. */
        !           188:
        !           189:        if ( ! man_block_alloc(m, line, ppos, tok))
        !           190:                return(0);
        !           191:        if ( ! man_head_alloc(m, line, ppos, tok))
        !           192:                return(0);
1.1       kristaps  193:
1.19    ! kristaps  194:        /* Add line arguments. */
1.3       kristaps  195:
1.19    ! kristaps  196:        for (;;) {
        !           197:                la = *pos;
        !           198:                w = man_args(m, line, pos, buf, &p);
1.4       kristaps  199:
1.19    ! kristaps  200:                if (-1 == w)
1.6       kristaps  201:                        return(0);
1.19    ! kristaps  202:                if (0 == w)
        !           203:                        break;
        !           204:
        !           205:                if ( ! man_word_alloc(m, line, la, p))
1.6       kristaps  206:                        return(0);
1.19    ! kristaps  207:                m->next = MAN_NEXT_SIBLING;
1.6       kristaps  208:        }
                    209:
1.19    ! kristaps  210:        /* Close out head and open body (unless MAN_SCOPE). */
        !           211:
        !           212:        if (MAN_SCOPED & man_macros[tok].flags) {
        !           213:                m->flags |= MAN_BLINE;
        !           214:                return(1);
        !           215:        } else if ( ! rew_scope(MAN_HEAD, m, tok))
1.6       kristaps  216:                return(0);
                    217:
1.19    ! kristaps  218:        return(man_body_alloc(m, line, ppos, tok));
1.4       kristaps  219: }
                    220:
                    221:
1.19    ! kristaps  222: int
        !           223: in_line_eoln(MACRO_PROT_ARGS)
1.3       kristaps  224: {
1.19    ! kristaps  225:        int              w, la;
        !           226:        char            *p;
        !           227:        struct man_node *n;
1.3       kristaps  228:
1.19    ! kristaps  229:        if ( ! man_elem_alloc(m, line, ppos, tok))
1.3       kristaps  230:                return(0);
                    231:
1.19    ! kristaps  232:        n = m->last;
        !           233:        m->next = MAN_NEXT_CHILD;
1.3       kristaps  234:
1.19    ! kristaps  235:        for (;;) {
        !           236:                la = *pos;
        !           237:                w = man_args(m, line, pos, buf, &p);
1.3       kristaps  238:
1.19    ! kristaps  239:                if (-1 == w)
        !           240:                        return(0);
        !           241:                if (0 == w)
        !           242:                        break;
1.3       kristaps  243:
1.19    ! kristaps  244:                if ( ! man_word_alloc(m, line, la, p))
        !           245:                        return(0);
        !           246:                m->next = MAN_NEXT_SIBLING;
        !           247:        }
1.3       kristaps  248:
1.19    ! kristaps  249:        if (n == m->last && (MAN_SCOPED & man_macros[tok].flags)) {
        !           250:                m->flags |= MAN_ELINE;
        !           251:                return(1);
        !           252:        }
1.3       kristaps  253:
1.19    ! kristaps  254:        /*
        !           255:         * Note that when TH is pruned, we'll be back at the root, so
        !           256:         * make sure that we don't clobber as its sibling.
        !           257:         */
1.3       kristaps  258:
1.19    ! kristaps  259:        /* FIXME: clean this to use man_unscope(). */
1.3       kristaps  260:
1.19    ! kristaps  261:        for ( ; m->last; m->last = m->last->parent) {
        !           262:                if (m->last == n)
        !           263:                        break;
        !           264:                if (m->last->type == MAN_ROOT)
        !           265:                        break;
        !           266:                if ( ! man_valid_post(m))
        !           267:                        return(0);
        !           268:                if ( ! man_action_post(m))
        !           269:                        return(0);
        !           270:        }
1.3       kristaps  271:
1.19    ! kristaps  272:        assert(m->last);
1.3       kristaps  273:
                    274:        /*
1.19    ! kristaps  275:         * Same here regarding whether we're back at the root.
1.3       kristaps  276:         */
                    277:
1.19    ! kristaps  278:        if (m->last->type != MAN_ROOT && ! man_valid_post(m))
        !           279:                return(0);
        !           280:        if (m->last->type != MAN_ROOT && ! man_action_post(m))
        !           281:                return(0);
        !           282:        if (m->last->type != MAN_ROOT)
        !           283:                m->next = MAN_NEXT_SIBLING;
1.3       kristaps  284:
1.19    ! kristaps  285:        return(1);
        !           286: }
1.3       kristaps  287:
                    288:
1.19    ! kristaps  289: int
        !           290: man_macroend(struct man *m)
        !           291: {
1.3       kristaps  292:
1.19    ! kristaps  293:        return(man_unscope(m, m->first));
        !           294: }
1.3       kristaps  295:

CVSweb