[BACK]Return to cmode.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mg

Annotation of src/usr.bin/mg/cmode.c, Revision 1.1

1.1     ! kjell       1: /* $OpenBSD$ */
        !             2: /*
        !             3:  * This file is in the public domain.
        !             4:  *
        !             5:  * Author: Kjell Wooding <kjell@openbsd.org>
        !             6:  */
        !             7:
        !             8: /*
        !             9:  * Implement an non-irritating KNF-compliant mode for editing
        !            10:  * C code.
        !            11:  */
        !            12: #include <ctype.h>
        !            13:
        !            14: #include "def.h"
        !            15: #include "kbd.h"
        !            16: #include "funmap.h"
        !            17:
        !            18: /* Pull in from modes.c */
        !            19: extern int changemode(int, int, char *);
        !            20:
        !            21: static int cc_strip_trailp = TRUE;     /* Delete Trailing space? */
        !            22: static int cc_basic_indent = 8;                /* Basic Indent multiple */
        !            23: static int cc_cont_indent = 4;         /* Continued line indent */
        !            24: static int cc_colon_indent = -8;       /* Label / case indent */
        !            25:
        !            26: static int getmatch(int, int);
        !            27: static int getindent(const struct line *, int *);
        !            28:
        !            29: /* Keymaps */
        !            30:
        !            31: static PF cmode_brace[] = {
        !            32:        cc_char,        /* } */
        !            33: };
        !            34:
        !            35: static PF cmode_ci[] = {
        !            36:        cc_tab,         /* ^I */
        !            37:        rescan,         /* ^J */
        !            38:        rescan,         /* ^K */
        !            39:        rescan,         /* ^L */
        !            40:        cc_lfindent,    /* ^M */
        !            41: };
        !            42:
        !            43: static PF cmode_colon[] = {
        !            44:        cc_char,        /* : */
        !            45:        rescan,         /* ; */
        !            46: };
        !            47:
        !            48: static struct KEYMAPE (3 + IMAPEXT) cmodemap = {
        !            49:        3,
        !            50:        3 + IMAPEXT,
        !            51:        rescan,
        !            52:        {
        !            53:                { CCHR('I'), CCHR('M'), cmode_ci, NULL },
        !            54:                { ':', ';', cmode_colon, NULL },
        !            55:                { '}', '}', cmode_brace, NULL }
        !            56:        }
        !            57: };
        !            58:
        !            59: /* Funtion, Mode hooks */
        !            60:
        !            61: void
        !            62: cmode_init(void)
        !            63: {
        !            64:        funmap_add(cmode, "c-mode");
        !            65:        funmap_add(cc_char, "c-handle-special-char");
        !            66:        funmap_add(cc_tab, "c-tab-or-indent");
        !            67:        funmap_add(cc_indent, "c-indent");
        !            68:        funmap_add(cc_lfindent, "c-indent-and-newline");
        !            69:        maps_add((KEYMAP *)&cmodemap, "c-mode");
        !            70: }
        !            71:
        !            72: /*
        !            73:  * Enable/toggle c-mode
        !            74:  */
        !            75: int
        !            76: cmode(int f, int n)
        !            77: {
        !            78:        return(changemode(f, n, "c-mode"));
        !            79: }
        !            80:
        !            81: /*
        !            82:  * Handle special C character - selfinsert then indent.
        !            83:  */
        !            84: int
        !            85: cc_char(int f, int n)
        !            86: {
        !            87:        if (n < 0)
        !            88:                return (FALSE);
        !            89:        if (selfinsert(FFRAND, n) == FALSE)
        !            90:                return (FALSE);
        !            91:        return (cc_indent(FFRAND, n));
        !            92: }
        !            93:
        !            94: /*
        !            95:  * If we are in the whitespace at the beginning of the line,
        !            96:  * simply act as a regular tab. If we are not, indent
        !            97:  * current line according to whitespace rules.
        !            98:  */
        !            99: int
        !           100: cc_tab(int f, int n)
        !           101: {
        !           102:        int lo;
        !           103:        int inwhitep = FALSE;   /* In leading whitespace? */
        !           104:
        !           105:        for (lo = 0; lo < llength(curwp->w_dotp); lo++) {
        !           106:                if (!isspace(lgetc(curwp->w_dotp, lo)))
        !           107:                        break;
        !           108:                if (lo == curwp->w_doto)
        !           109:                        inwhitep = TRUE;
        !           110:        }
        !           111:
        !           112:        /* Special case: we could be at the end of a whitespace line */
        !           113:        if (lo == llength(curwp->w_dotp) && curwp->w_doto == lo)
        !           114:                inwhitep = TRUE;
        !           115:
        !           116:        /* If empty line, or in whitespace */
        !           117:        if (llength(curwp->w_dotp) == 0 || inwhitep)
        !           118:                return (selfinsert(f, n));
        !           119:
        !           120:        return (cc_indent(FFRAND, 1));
        !           121: }
        !           122:
        !           123: /*
        !           124:  * Attempt to indent current line according to KNF rules.
        !           125:  */
        !           126: int
        !           127: cc_indent(int f, int n)
        !           128: {
        !           129:        int pi, mi;                     /* Previous indents */
        !           130:        int ci, dci;                    /* current indent, don't care */
        !           131:        int lo;
        !           132:        int c;
        !           133:        int nonblankp;
        !           134:        struct line *lp;
        !           135:
        !           136:        if (n < 0)
        !           137:                return (FALSE);
        !           138:
        !           139:        if (cc_strip_trailp)
        !           140:                deltrailwhite(FFRAND, 1);
        !           141:
        !           142:        /* Search backwards for a nonblank, non preprocessor line */
        !           143:        lp = curwp->w_dotp;
        !           144:        nonblankp = FALSE;
        !           145:        while (lback(lp) != curbp->b_headp && !nonblankp) {
        !           146:                lp = lback(lp);
        !           147:                for (lo = 0; lo < llength(lp); lo++) {
        !           148:                        if (!isspace(c = lgetc(lp, lo))) {
        !           149:                                /* Leading # is a blank */
        !           150:                                if (c != '#')
        !           151:                                        nonblankp = TRUE;
        !           152:                                break;
        !           153:                        }
        !           154:                }
        !           155:        }
        !           156:
        !           157:        pi = getindent(lp, &mi);
        !           158:
        !           159:        /* Strip leading space on current line */
        !           160:        delleadwhite(FFRAND, 1);
        !           161:        /* current indent is computed only to current position */
        !           162:        dci = getindent(curwp->w_dotp, &ci);
        !           163:
        !           164:        if (pi + ci < 0)
        !           165:                return(indent(FFOTHARG, 0));
        !           166:        else
        !           167:                return(indent(FFOTHARG, pi + ci));
        !           168: }
        !           169:
        !           170: /*
        !           171:  * Indent-and-newline (technically, newline then indent)
        !           172:  */
        !           173: int
        !           174: cc_lfindent(int f, int n)
        !           175: {
        !           176:        if (n < 0)
        !           177:                return (FALSE);
        !           178:        if (newline(FFRAND, 1) == FALSE)
        !           179:                return (FALSE);
        !           180:        return (cc_indent(FFRAND, n));
        !           181: }
        !           182:
        !           183: /*
        !           184:  * Get the level of indention after line lp is processed
        !           185:  * Note getindent has two returns: curi, nexti.
        !           186:  * curi = value if indenting current line.
        !           187:  * return value = value affecting subsequent lines.
        !           188:  * note, we only process up to offset op.
        !           189:  * set to llength(lp) for the whole line.
        !           190:  */
        !           191: static int
        !           192: getindent(const struct line *lp, int *curi)
        !           193: {
        !           194:        int lo, co;             /* leading space,  current offset*/
        !           195:        int nicol = 0;          /* position count */
        !           196:        int c = '\0';           /* current char */
        !           197:        int newind = 0;         /* new index value */
        !           198:        int stringp = FALSE;    /* in string? */
        !           199:        int escp = FALSE;       /* Escape char? */
        !           200:        int lastc = '\0';       /* Last matched string delimeter */
        !           201:        int nparen = 0;         /* paren count */
        !           202:        int obrace = 0;         /* open brace count */
        !           203:        int cbrace = 0;         /* close brace count */
        !           204:        int contp = FALSE;      /* Continue? */
        !           205:        int firstseenp = FALSE; /* First nonspace encountered? */
        !           206:        int colonp = FALSE;     /* Did we see a colon? */
        !           207:        int questionp = FALSE;  /* Did we see a question mark? */
        !           208:
        !           209:        *curi = 0;
        !           210:
        !           211:        /* Compute leading space */
        !           212:        for (lo = 0; lo < llength(lp); lo++) {
        !           213:                if (!isspace(c = lgetc(lp, lo)))
        !           214:                        break;
        !           215:                if (c == '\t'
        !           216: #ifdef NOTAB
        !           217:                    && !(curbp-b_flag & BFNOTAB)
        !           218: #endif /* NOTAB */
        !           219:                    ) {
        !           220:                        nicol |= 0x07;
        !           221:                }
        !           222:                nicol++;
        !           223:        }
        !           224:
        !           225:        /* If last line was blank, choose 0 */
        !           226:        if (lo == llength(lp))
        !           227:                nicol = 0;
        !           228:
        !           229:        if (c == '#')
        !           230:                return (0);
        !           231:
        !           232:        newind = 0;
        !           233:        /* Compute modifiers */
        !           234:        for (co = lo; co < llength(lp); co++) {
        !           235:                c = lgetc(lp, co);
        !           236:                /* We have a non-whitespace char */
        !           237:                if (!firstseenp && !isspace(c)) {
        !           238:                        contp = TRUE;
        !           239:                        firstseenp = TRUE;
        !           240:                }
        !           241:                if (c == '\\')
        !           242:                        escp = !escp;
        !           243:                else if (stringp) {
        !           244:                        if (!escp && (c == '"' || c == '\'')) {
        !           245:                                /* unescaped string char */
        !           246:                                if (getmatch(c, lastc))
        !           247:                                        stringp = FALSE;
        !           248:                        }
        !           249:                } else if (c == '"' || c == '\'') {
        !           250:                        stringp = TRUE;
        !           251:                        lastc = c;
        !           252:                } else if (c == '(') {
        !           253:                        nparen++;
        !           254:                } else if (c == ')') {
        !           255:                        nparen--;
        !           256:                } else if (c == '{') {
        !           257:                        obrace++;
        !           258:                        firstseenp = FALSE;
        !           259:                        contp = FALSE;
        !           260:                } else if (c == '}') {
        !           261:                        cbrace++;
        !           262:                } else if (c == '?') {
        !           263:                        questionp = TRUE;
        !           264:                } else if (c == ':') {
        !           265:                        /* ignore (foo ? bar : baz) construct */
        !           266:                        if (!questionp)
        !           267:                                colonp = TRUE;
        !           268:                } else if (c == ';') {
        !           269:                        if (nparen > 0)
        !           270:                                contp = FALSE;
        !           271:                }
        !           272:
        !           273:                /* Reset escape character match */
        !           274:                if (c != '\\')
        !           275:                        escp = FALSE;
        !           276:        }
        !           277:        /*
        !           278:         * If not terminated with a semicolon, and brace or paren open.
        !           279:         * we continue
        !           280:         */
        !           281:        if (colonp) {
        !           282:                *curi += cc_colon_indent;
        !           283:                newind -= cc_colon_indent;
        !           284:        }
        !           285:
        !           286:        *curi -= (cbrace) * cc_basic_indent;
        !           287:        newind += obrace * cc_basic_indent;
        !           288:
        !           289:        if (nparen < 0)
        !           290:                newind -= cc_cont_indent;
        !           291:        else if (nparen > 0)
        !           292:                newind += cc_cont_indent;
        !           293:        newind += nicol;
        !           294:        *curi += nicol;
        !           295:
        !           296:        return (newind);
        !           297: }
        !           298:
        !           299: /*
        !           300:  * Given a delimeter and its purported mate, tell us if they
        !           301:  * match.
        !           302:  */
        !           303: static int
        !           304: getmatch(int c, int mc)
        !           305: {
        !           306:        int match = FALSE;
        !           307:
        !           308:        switch (c) {
        !           309:        case '"':
        !           310:                match = (mc == '"');
        !           311:                break;
        !           312:        case '\'':
        !           313:                match = (mc == '\'');
        !           314:                break;
        !           315:        case '(':
        !           316:                match = (mc == ')');
        !           317:                break;
        !           318:        case '[':
        !           319:                match = (mc == ']');
        !           320:                break;
        !           321:        case '{':
        !           322:                match = (mc == '}');
        !           323:                break;
        !           324:        }
        !           325:
        !           326:        return (match);
        !           327: }