diff options
Diffstat (limited to 'usr.bin')
-rw-r--r-- | usr.bin/mg/Makefile | 4 | ||||
-rw-r--r-- | usr.bin/mg/cmode.c | 327 | ||||
-rw-r--r-- | usr.bin/mg/def.h | 8 | ||||
-rw-r--r-- | usr.bin/mg/main.c | 4 |
4 files changed, 339 insertions, 4 deletions
diff --git a/usr.bin/mg/Makefile b/usr.bin/mg/Makefile index 2af8c742be7..8b610342043 100644 --- a/usr.bin/mg/Makefile +++ b/usr.bin/mg/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.19 2006/12/16 17:00:03 kjell Exp $ +# $OpenBSD: Makefile,v 1.20 2008/06/12 01:58:44 kjell Exp $ PROG= mg @@ -25,6 +25,6 @@ SRCS= cinfo.c fileio.c spawn.c ttyio.c tty.c ttykbd.c \ # # More or less standalone extensions. # -SRCS+= grep.c theo.c mail.c +SRCS+= grep.c theo.c mail.c cmode.c .include <bsd.prog.mk> diff --git a/usr.bin/mg/cmode.c b/usr.bin/mg/cmode.c new file mode 100644 index 00000000000..e2660f96337 --- /dev/null +++ b/usr.bin/mg/cmode.c @@ -0,0 +1,327 @@ +/* $OpenBSD: cmode.c,v 1.1 2008/06/12 01:58:44 kjell Exp $ */ +/* + * This file is in the public domain. + * + * Author: Kjell Wooding <kjell@openbsd.org> + */ + +/* + * Implement an non-irritating KNF-compliant mode for editing + * C code. + */ +#include <ctype.h> + +#include "def.h" +#include "kbd.h" +#include "funmap.h" + +/* Pull in from modes.c */ +extern int changemode(int, int, char *); + +static int cc_strip_trailp = TRUE; /* Delete Trailing space? */ +static int cc_basic_indent = 8; /* Basic Indent multiple */ +static int cc_cont_indent = 4; /* Continued line indent */ +static int cc_colon_indent = -8; /* Label / case indent */ + +static int getmatch(int, int); +static int getindent(const struct line *, int *); + +/* Keymaps */ + +static PF cmode_brace[] = { + cc_char, /* } */ +}; + +static PF cmode_ci[] = { + cc_tab, /* ^I */ + rescan, /* ^J */ + rescan, /* ^K */ + rescan, /* ^L */ + cc_lfindent, /* ^M */ +}; + +static PF cmode_colon[] = { + cc_char, /* : */ + rescan, /* ; */ +}; + +static struct KEYMAPE (3 + IMAPEXT) cmodemap = { + 3, + 3 + IMAPEXT, + rescan, + { + { CCHR('I'), CCHR('M'), cmode_ci, NULL }, + { ':', ';', cmode_colon, NULL }, + { '}', '}', cmode_brace, NULL } + } +}; + +/* Funtion, Mode hooks */ + +void +cmode_init(void) +{ + funmap_add(cmode, "c-mode"); + funmap_add(cc_char, "c-handle-special-char"); + funmap_add(cc_tab, "c-tab-or-indent"); + funmap_add(cc_indent, "c-indent"); + funmap_add(cc_lfindent, "c-indent-and-newline"); + maps_add((KEYMAP *)&cmodemap, "c-mode"); +} + +/* + * Enable/toggle c-mode + */ +int +cmode(int f, int n) +{ + return(changemode(f, n, "c-mode")); +} + +/* + * Handle special C character - selfinsert then indent. + */ +int +cc_char(int f, int n) +{ + if (n < 0) + return (FALSE); + if (selfinsert(FFRAND, n) == FALSE) + return (FALSE); + return (cc_indent(FFRAND, n)); +} + +/* + * If we are in the whitespace at the beginning of the line, + * simply act as a regular tab. If we are not, indent + * current line according to whitespace rules. + */ +int +cc_tab(int f, int n) +{ + int lo; + int inwhitep = FALSE; /* In leading whitespace? */ + + for (lo = 0; lo < llength(curwp->w_dotp); lo++) { + if (!isspace(lgetc(curwp->w_dotp, lo))) + break; + if (lo == curwp->w_doto) + inwhitep = TRUE; + } + + /* Special case: we could be at the end of a whitespace line */ + if (lo == llength(curwp->w_dotp) && curwp->w_doto == lo) + inwhitep = TRUE; + + /* If empty line, or in whitespace */ + if (llength(curwp->w_dotp) == 0 || inwhitep) + return (selfinsert(f, n)); + + return (cc_indent(FFRAND, 1)); +} + +/* + * Attempt to indent current line according to KNF rules. + */ +int +cc_indent(int f, int n) +{ + int pi, mi; /* Previous indents */ + int ci, dci; /* current indent, don't care */ + int lo; + int c; + int nonblankp; + struct line *lp; + + if (n < 0) + return (FALSE); + + if (cc_strip_trailp) + deltrailwhite(FFRAND, 1); + + /* Search backwards for a nonblank, non preprocessor line */ + lp = curwp->w_dotp; + nonblankp = FALSE; + while (lback(lp) != curbp->b_headp && !nonblankp) { + lp = lback(lp); + for (lo = 0; lo < llength(lp); lo++) { + if (!isspace(c = lgetc(lp, lo))) { + /* Leading # is a blank */ + if (c != '#') + nonblankp = TRUE; + break; + } + } + } + + pi = getindent(lp, &mi); + + /* Strip leading space on current line */ + delleadwhite(FFRAND, 1); + /* current indent is computed only to current position */ + dci = getindent(curwp->w_dotp, &ci); + + if (pi + ci < 0) + return(indent(FFOTHARG, 0)); + else + return(indent(FFOTHARG, pi + ci)); +} + +/* + * Indent-and-newline (technically, newline then indent) + */ +int +cc_lfindent(int f, int n) +{ + if (n < 0) + return (FALSE); + if (newline(FFRAND, 1) == FALSE) + return (FALSE); + return (cc_indent(FFRAND, n)); +} + +/* + * Get the level of indention after line lp is processed + * Note getindent has two returns: curi, nexti. + * curi = value if indenting current line. + * return value = value affecting subsequent lines. + * note, we only process up to offset op. + * set to llength(lp) for the whole line. + */ +static int +getindent(const struct line *lp, int *curi) +{ + int lo, co; /* leading space, current offset*/ + int nicol = 0; /* position count */ + int c = '\0'; /* current char */ + int newind = 0; /* new index value */ + int stringp = FALSE; /* in string? */ + int escp = FALSE; /* Escape char? */ + int lastc = '\0'; /* Last matched string delimeter */ + int nparen = 0; /* paren count */ + int obrace = 0; /* open brace count */ + int cbrace = 0; /* close brace count */ + int contp = FALSE; /* Continue? */ + int firstseenp = FALSE; /* First nonspace encountered? */ + int colonp = FALSE; /* Did we see a colon? */ + int questionp = FALSE; /* Did we see a question mark? */ + + *curi = 0; + + /* Compute leading space */ + for (lo = 0; lo < llength(lp); lo++) { + if (!isspace(c = lgetc(lp, lo))) + break; + if (c == '\t' +#ifdef NOTAB + && !(curbp-b_flag & BFNOTAB) +#endif /* NOTAB */ + ) { + nicol |= 0x07; + } + nicol++; + } + + /* If last line was blank, choose 0 */ + if (lo == llength(lp)) + nicol = 0; + + if (c == '#') + return (0); + + newind = 0; + /* Compute modifiers */ + for (co = lo; co < llength(lp); co++) { + c = lgetc(lp, co); + /* We have a non-whitespace char */ + if (!firstseenp && !isspace(c)) { + contp = TRUE; + firstseenp = TRUE; + } + if (c == '\\') + escp = !escp; + else if (stringp) { + if (!escp && (c == '"' || c == '\'')) { + /* unescaped string char */ + if (getmatch(c, lastc)) + stringp = FALSE; + } + } else if (c == '"' || c == '\'') { + stringp = TRUE; + lastc = c; + } else if (c == '(') { + nparen++; + } else if (c == ')') { + nparen--; + } else if (c == '{') { + obrace++; + firstseenp = FALSE; + contp = FALSE; + } else if (c == '}') { + cbrace++; + } else if (c == '?') { + questionp = TRUE; + } else if (c == ':') { + /* ignore (foo ? bar : baz) construct */ + if (!questionp) + colonp = TRUE; + } else if (c == ';') { + if (nparen > 0) + contp = FALSE; + } + + /* Reset escape character match */ + if (c != '\\') + escp = FALSE; + } + /* + * If not terminated with a semicolon, and brace or paren open. + * we continue + */ + if (colonp) { + *curi += cc_colon_indent; + newind -= cc_colon_indent; + } + + *curi -= (cbrace) * cc_basic_indent; + newind += obrace * cc_basic_indent; + + if (nparen < 0) + newind -= cc_cont_indent; + else if (nparen > 0) + newind += cc_cont_indent; + newind += nicol; + *curi += nicol; + + return (newind); +} + +/* + * Given a delimeter and its purported mate, tell us if they + * match. + */ +static int +getmatch(int c, int mc) +{ + int match = FALSE; + + switch (c) { + case '"': + match = (mc == '"'); + break; + case '\'': + match = (mc == '\''); + break; + case '(': + match = (mc == ')'); + break; + case '[': + match = (mc == ']'); + break; + case '{': + match = (mc == '}'); + break; + } + + return (match); +} diff --git a/usr.bin/mg/def.h b/usr.bin/mg/def.h index 0aa9de7b4b2..da4e15853a1 100644 --- a/usr.bin/mg/def.h +++ b/usr.bin/mg/def.h @@ -1,4 +1,4 @@ -/* $OpenBSD: def.h,v 1.102 2008/06/11 23:18:33 kjell Exp $ */ +/* $OpenBSD: def.h,v 1.103 2008/06/12 01:58:44 kjell Exp $ */ /* This file is in the public domain. */ @@ -620,6 +620,12 @@ int add_autoexec(const char *, const char *); /* mail.c X */ void mail_init(void); +/* cmode.c X */ +int cmode(int, int); +int cc_char(int, int); +int cc_tab(int, int); +int cc_indent(int, int); +int cc_lfindent(int, int); /* grep.c X */ int next_error(int, int); diff --git a/usr.bin/mg/main.c b/usr.bin/mg/main.c index 2238a39757a..b67c08b53ad 100644 --- a/usr.bin/mg/main.c +++ b/usr.bin/mg/main.c @@ -1,4 +1,4 @@ -/* $OpenBSD: main.c,v 1.57 2008/05/29 19:58:15 sobrado Exp $ */ +/* $OpenBSD: main.c,v 1.58 2008/06/12 01:58:44 kjell Exp $ */ /* This file is in the public domain. */ @@ -75,12 +75,14 @@ main(int argc, char **argv) extern void grep_init(void); extern void theo_init(void); extern void mail_init(void); + extern void cmode_init(void); extern void dired_init(void); dired_init(); grep_init(); theo_init(); mail_init(); + cmode_init(); } if (init_fcn_name && |