summaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/mg/Makefile4
-rw-r--r--usr.bin/mg/cmode.c327
-rw-r--r--usr.bin/mg/def.h8
-rw-r--r--usr.bin/mg/main.c4
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 &&