[PATCH] basic modelines for contrib/nvi

José de Paula espinafre at gmail.com
Wed Jul 14 19:51:52 PDT 2004


I hacked together this little patch to contrib/nvi to make it support
simple modelines. The original author of nvi (Keith Bostic) says in
the sources that modelines are not to be implemented because of
security concerns, but I believe that implementing them after vim's
style (i.e., only allowing arguments to the 'set' option in modelines)
doesn't pose any security threat. Besides, I find them quite useful
when editing some specific files, for which I want specific settings.
Acceptable modelines are in the form: (ex/vi regex)
.*[[:blank:]]\+\(vi\)\|\(ex\):options
where 'options' are space- or colon-separated arguments to 'set'.

Well, please tell me what you think about it, and whether I should
file a PR to get this included. Without further ado, here is the
patch:

diff -Nru a/common/exf.c b/common/exf.c
--- a/common/exf.c	Wed Jul 14 22:22:19 2004
+++ b/common/exf.c	Wed Jul 14 23:33:17 2004
@@ -42,6 +42,83 @@
 
 #include "common.h"
 
+char * parse_modeline(sp, line, size)
+	SCR *sp;
+	char *line;
+	int size;
+{
+	char *cmd, *ex;
+	int i;
+
+	cmd = malloc(sizeof (*cmd) * size);
+
+	if ( !(ex = strstr(line, "vi:")) && !(ex = strstr(line, "ex:")) )
+		return NULL; /* no modelines here */
+	if ( (ex != line) && !isblank(*(ex - 1)))
+		return NULL; /* no modelines here either */
+
+	/* What we have to do is initialize *cmd with 'set ',
+	 * change colons to spaces and append the resulting mess
+	 * to cmd.
+	 */
+	strcpy(cmd, "set ");
+	i = strlen(cmd);
+	ex += 3;
+	while(*ex != '\n' && *ex != '\r' && i < size) /* run till end of line */
+	{
+		if(*ex == ':')
+			cmd[i] = ' ';
+		else
+			cmd[i] = *ex;
+		i++;
+		ex++;
+	}
+	cmd[i] = '\0';
+
+	return cmd;
+}
+
+/* 
+ * We look for a modeline, and return a cooked string ready to be
+ * run by ex_run_str.
+ * the first one is found; if there is no modeline, return NULL.
+ */
+char * get_modeline(sp)
+	SCR * sp;
+{
+	char *cmd, *line;
+	int i, lnop, linesz, lineempty;
+
+	line = malloc(sizeof(*line) * 255); /* shall we have a modeline
longer than that? */
+
+	if (db_last(sp, &lnop))
+		return NULL;
+	if (lnop == 0)
+		return NULL;
+
+	for (i = 1; i <= lnop && i <= 5; i++)
+	{
+		db_eget(sp, i, &line, &linesz, &lineempty);
+		if(lineempty)
+			continue;
+		if ( (cmd = parse_modeline(sp, line, linesz)) != NULL)
+			return cmd;
+	}
+
+	/* just like before, but counting lines from bottom up */
+	for (i = lnop; i > 0 && i >= (lnop - 5); i--)
+	{
+		db_eget(sp, i, &line, &linesz, &lineempty);
+		if(lineempty)
+			continue;
+		if ( (cmd = parse_modeline(sp, line, linesz)) != NULL)
+			return cmd;
+	}
+
+	/* If we reached this point, there is nothing to return. Therefore, */
+	return NULL;
+}
+
 static int	file_backup __P((SCR *, char *, char *));
 static void	file_cinit __P((SCR *));
 static void	file_comment __P((SCR *));
@@ -520,6 +597,7 @@
 	MARK m;
 	size_t len;
 	int nb;
+	char *cmd;
 
 	/* Set some basic defaults. */
 	sp->lno = 1;
@@ -612,6 +690,14 @@
 	 */
 	m.lno = sp->lno;
 	m.cno = sp->cno;
+
+	if (O_ISSET(sp, O_MODELINE)) { 
+		cmd = get_modeline(sp); 
+		if (cmd != NULL)
+			if (ex_run_str(sp, "modeline", cmd, strlen(cmd), 0, 0)) 
+				return;
+	}
+
 	(void)mark_set(sp, ABSMARK1, &m, 0);
 }
 
diff -Nru a/common/options.c b/common/options.c
--- a/common/options.c	Wed Jul 14 22:22:19 2004
+++ b/common/options.c	Wed Jul 14 22:32:54 2004
@@ -124,7 +124,7 @@
  *	example of what your intro CS professor referred to as the perils of
  *	mixing code and data.  Don't add it, or I will kill you.
  */
-	{"modeline",	NULL,		OPT_0BOOL,	OPT_NOSET},
+	{"modeline",	NULL,		OPT_0BOOL,	0},
 /* O_MSGCAT	  4.4BSD */
 	{"msgcat",	f_msgcat,	OPT_STR,	0},
 /* O_NOPRINT	  4.4BSD */


More information about the freebsd-hackers mailing list