Added regex(3) support.

The syntax:
:!!text
should now append `text' to the last :command.
This commit is contained in:
alm 1993-11-08 05:05:44 +00:00
parent ed4933867f
commit 723804e46a
10 changed files with 303 additions and 32 deletions

View File

@ -1,10 +1,9 @@
# $Id: Makefile,v 1.4 1993/09/04 02:29:29 jtc Exp $
CFLAGS += -DBSD
DPADD= ${LIBTERM}
LDADD= -ltermcap
# $Id: Makefile,v 1.5 1993/11/08 05:05:44 alm Exp $
PROG= elvis
CFLAGS+=-DBSD -DREGEX
DPADD= ${LIBTERM}
LDADD= -ltermcap -lgnuregex
SRCS= blk.c cmd1.c cmd2.c ctype.c curses.c cut.c ex.c input.c main.c misc.c \
modify.c move1.c move2.c move3.c move4.c move5.c opts.c recycle.c \
redraw.c regexp.c regsub.c system.c tio.c tmp.c unix.c vars.c vcmd.c vi.c

View File

@ -13,13 +13,17 @@
*/
#ifndef lint
static char rcsid[] = "$Id: cmd1.c,v 1.3 1993/08/02 17:53:43 mycroft Exp $";
static char rcsid[] = "$Id: cmd1.c,v 1.4 1993/11/08 05:06:00 alm Exp $";
#endif /* not lint */
#include "config.h"
#include "ctype.h"
#include "vi.h"
#include "regexp.h"
#ifdef REGEX
# include <regex.h>
#else
# include "regexp.h"
#endif /* REGEX */
#ifndef NO_TAGSTACK
/* These describe the current state of the tag related commands */
@ -274,7 +278,11 @@ void cmd_shell(frommark, tomark, cmd, bang, extra)
int bang;
char *extra;
{
#ifdef BSD
static char *prevextra = NULL;
#else
static char prevextra[80];
#endif
/* special case: ":sh" means ":!sh" */
if (cmd == CMD_SHELL)
@ -286,14 +294,32 @@ void cmd_shell(frommark, tomark, cmd, bang, extra)
/* if extra is "!", substitute previous command */
if (*extra == '!')
{
if (!*prevextra)
#ifdef BSD
if (prevextra == NULL)
#else
if (*prevextra == '\0')
#endif
{
msg("No previous shell command to substitute for '!'");
return;
}
#ifdef BSD
else if ((prevextra = (char *) realloc(prevextra,
strlen(prevextra) + strlen(extra))) != NULL) {
strcat(prevextra, extra + 1);
extra = prevextra;
}
#else
extra = prevextra;
#endif
}
else if (cmd == CMD_BANG && strlen(extra) < sizeof(prevextra) - 1)
else if (cmd == CMD_BANG &&
#ifdef BSD
(prevextra = (char *) realloc(prevextra, strlen(extra) + 1)) != NULL)
#else
strlen(extra) < sizeof(prevextra) - 1)
#endif
{
strcpy(prevextra, extra);
}
@ -337,7 +363,11 @@ void cmd_global(frommark, tomark, cmd, bang, extra)
long l; /* used as a counter to move through lines */
long lqty; /* quantity of lines to be scanned */
long nchanged; /* number of lines changed */
#ifdef REGEX
regex_t *re, *optpat();
#else
regexp *re; /* the compiled search expression */
#endif
/* can't nest global commands */
if (doingglobal)
@ -367,13 +397,16 @@ void cmd_global(frommark, tomark, cmd, bang, extra)
msg("Can't use empty regular expression with '%c' command", cmd == CMD_GLOBAL ? 'g' : 'v');
return;
}
#ifdef REGEX
re = optpat(extra + 1);
#else
re = regcomp(extra + 1);
#endif
if (!re)
{
/* regcomp found & described an error */
return;
}
/* for each line in the range */
doingglobal = TRUE;
ChangeText
@ -394,7 +427,11 @@ void cmd_global(frommark, tomark, cmd, bang, extra)
line = fetchline(nlines - l);
/* if it contains the search pattern... */
#ifdef REGEX
if ((!regexec(re, line, 0, NULL, 0)) == (cmd == CMD_GLOBAL))
#else
if ((!regexec(re, line, 1)) == (cmd != CMD_GLOBAL))
#endif
{
/* move the cursor to that line */
cursor = MARK_AT_LINE(nlines - l);
@ -411,8 +448,10 @@ void cmd_global(frommark, tomark, cmd, bang, extra)
}
doingglobal = FALSE;
#ifndef REGEX
/* free the regexp */
_free_(re);
#endif
/* Reporting...*/
rptlines = nchanged;

View File

@ -11,13 +11,17 @@
/* This file contains some of the commands - mostly ones that change text */
#ifndef lint
static char rcsid[] = "$Id: cmd2.c,v 1.3 1993/08/02 17:53:45 mycroft Exp $";
static char rcsid[] = "$Id: cmd2.c,v 1.4 1993/11/08 05:06:08 alm Exp $";
#endif /* not lint */
#include "config.h"
#include "ctype.h"
#include "vi.h"
#include "regexp.h"
#ifdef REGEX
# include <regex.h>
#else
# include "regexp.h"
#endif
#if TOS
# include <stat.h>
#else
@ -32,6 +36,9 @@ static char rcsid[] = "$Id: cmd2.c,v 1.3 1993/08/02 17:53:45 mycroft Exp $";
# endif
#endif
#ifdef REGEX
int patlock = 0; /* lock substitute pattern */
#endif
/*ARGSUSED*/
void cmd_substitute(frommark, tomark, cmd, bang, extra)
@ -42,8 +49,19 @@ void cmd_substitute(frommark, tomark, cmd, bang, extra)
char *extra; /* rest of the command line */
{
char *line; /* a line from the file */
#ifdef REGEX
static regex_t *ore = NULL; /* old regex */
regex_t *optpat();
regex_t *re = NULL;
regmatch_t rm[SE_MAX];
char *startp, *endp;
int n;
#else
regexp *re; /* the compiled search expression */
#endif
char *eol;
char *subst; /* the substitution string */
static char *osubst;
char *opt; /* substitution options */
long l; /* a line number */
char *s, *d; /* used during subtitutions */
@ -61,7 +79,7 @@ void cmd_substitute(frommark, tomark, cmd, bang, extra)
/* for now, assume this will fail */
rptlines = -1L;
if (cmd == CMD_SUBAGAIN)
if (cmd == CMD_SUBAGAIN || !*extra)
{
#ifndef NO_MAGIC
if (*o_magic)
@ -69,7 +87,15 @@ void cmd_substitute(frommark, tomark, cmd, bang, extra)
else
#endif
subst = "\\~";
#ifdef REGEX
/* get the previous substitute pattern; not necessarily
* the previous pattern.
*/
if ((re = ore) == NULL)
msg("RE error: no previous pattern");
#else
re = regcomp("");
#endif
/* if visual "&", then turn off the "p" and "c" options */
if (bang)
@ -88,7 +114,19 @@ void cmd_substitute(frommark, tomark, cmd, bang, extra)
/* parse & compile the search pattern */
subst = parseptrn(extra);
#ifdef REGEX
if (re = optpat(extra + 1))
patlock = 1;
else
return;
if (re != ore && ore) {
regfree(ore);
free(ore);
}
ore = re;
#else
re = regcomp(extra + 1);
#endif
}
/* abort if RE error -- error message already given by regcomp() */
@ -150,9 +188,14 @@ void cmd_substitute(frommark, tomark, cmd, bang, extra)
{
/* fetch the line */
line = fetchline(l);
eol = line + strlen(line);
/* if it contains the search pattern... */
#ifdef REGEX
if (!regexec(re, line, SE_MAX, rm, 0))
#else
if (regexec(re, line, TRUE))
#endif
{
/* increment the line change counter */
chline++;
@ -164,14 +207,26 @@ void cmd_substitute(frommark, tomark, cmd, bang, extra)
/* do once or globally ... */
do
{
#ifdef REGEX
startp = s + rm[0].rm_so;
endp = s + rm[0].rm_eo;
#endif
#ifndef CRUNCH
/* confirm, if necessary */
if (optc)
{
#ifdef REGEX
for (conf = line; conf < startp; conf++)
#else
for (conf = line; conf < re->startp[0]; conf++)
#endif
addch(*conf);
standout();
#ifdef REGEX
for ( ; conf < endp; conf++)
#else
for ( ; conf < re->endp[0]; conf++)
#endif
addch(*conf);
standend();
for (; *conf; conf++)
@ -181,7 +236,11 @@ void cmd_substitute(frommark, tomark, cmd, bang, extra)
if (getkey(0) != 'y')
{
/* copy accross the original chars */
#ifdef REGEX
while (s < endp)
#else
while (s < re->endp[0])
#endif
*d++ = *s++;
/* skip to next match on this line, if any */
@ -194,17 +253,31 @@ void cmd_substitute(frommark, tomark, cmd, bang, extra)
chsub++;
/* copy stuff from before the match */
#ifdef REGEX
while (s < startp)
#else
while (s < re->startp[0])
#endif
{
*d++ = *s++;
}
/* substitute for the matched part */
#ifdef REGEX
regsub(rm, startp, endp, subst, d);
#else
regsub(re, subst, d);
#endif
#ifdef REGEX
s = endp;
#else
s = re->endp[0];
#endif
d += strlen(d);
Continue:
;
#ifndef REGEX
/* if this regexp could conceivably match
* a zero-length string, then require at
* least 1 unmatched character between
@ -216,8 +289,18 @@ Continue:
break;
*d++ = *s++;
}
#endif
} while (optg && regexec(re, s, FALSE));
}
#ifdef REGEX
while (*s && optg && rm[0].rm_eo && !regexec(re, s, SE_MAX, rm, REG_NOTBOL));
if (eol - s > 0 && !rm[0].rm_eo && optg) {
msg("RE error: line too long");
return;
}
#else
while (optg && regexec(re, s, FALSE));
#endif
/* copy stuff from after the match */
while (*d++ = *s++) /* yes, ASSIGNMENT! */
@ -257,7 +340,9 @@ Continue:
}
/* free the regexp */
#ifndef REGEX
_free_(re);
#endif
/* if done from within a ":g" command, then finish silently */
if (doingglobal)

View File

@ -15,7 +15,7 @@
*/
#ifndef lint
static char rcsid[] = "$Id: curses.c,v 1.3 1993/08/02 17:53:49 mycroft Exp $";
static char rcsid[] = "$Id: curses.c,v 1.4 1993/11/08 05:06:13 alm Exp $";
#endif /* not lint */
@ -759,7 +759,7 @@ int getsize(signo)
#ifdef SIGWINCH
/* reset the signal vector */
signal(SIGWINCH, getsize);
signal(SIGWINCH, (void *)getsize);
#endif
/* get the window size, one way or another. */

View File

@ -11,7 +11,7 @@
/* This file contains functions which didn't seem happy anywhere else */
#ifndef lint
static char rcsid[] = "$Id: misc.c,v 1.2 1993/08/02 17:53:56 mycroft Exp $";
static char rcsid[] = "$Id: misc.c,v 1.3 1993/11/08 05:06:17 alm Exp $";
#endif /* not lint */
@ -88,7 +88,7 @@ char *fetchline(line)
/* error message from the regexp code */
void regerror(txt)
void regerr(txt)
char *txt; /* an error message */
{
msg("RE error: %s", txt);

View File

@ -11,17 +11,25 @@
/* This function contains the movement functions that perform RE searching */
#ifndef lint
static char rcsid[] = "$Id: move2.c,v 1.3 1993/08/02 17:53:59 mycroft Exp $";
static char rcsid[] = "$Id: move2.c,v 1.4 1993/11/08 05:06:20 alm Exp $";
#endif /* not lint */
#include "config.h"
#include "vi.h"
#include "regexp.h"
#ifdef REGEX
# include <regex.h>
#else
# include "regexp.h"
#endif
extern long atol();
#ifdef REGEX
static regex_t *re = NULL; /* compiled version of the pattern to search for */
#else
static regexp *re; /* compiled version of the pattern to search for */
#endif
static prevsf; /* boolean: previous search direction was forward? */
#ifndef NO_EXTENSIONS
@ -102,6 +110,11 @@ MARK m_fsrch(m, ptrn)
char *line; /* text of line to be searched */
int wrapped;/* boolean: has our search wrapped yet? */
int pos; /* where we are in the line */
#ifdef REGEX
regex_t *optpat();
regmatch_t rm[SE_MAX];
int n;
#endif
#ifndef CRUNCH
long delta = INFINITY;/* line offset, for things like "/foo/+1" */
#endif
@ -121,11 +134,17 @@ MARK m_fsrch(m, ptrn)
#endif
ptrn++;
#ifdef REGEX
/* XXX where to free re? */
re = optpat(ptrn);
#else
/* free the previous pattern */
if (re) _free_(re);
/* compile the pattern */
re = regcomp(ptrn);
#endif
if (!re)
{
return MARK_UNSET;
@ -174,7 +193,11 @@ MARK m_fsrch(m, ptrn)
line = fetchline(l);
/* check this line */
#ifdef REGEX
if (!regexec(re, &line[pos], SE_MAX, rm, (pos == 0) ? 0 : REG_NOTBOL))
#else
if (regexec(re, &line[pos], (pos == 0)))
#endif
{
/* match! */
if (wrapped && *o_warn)
@ -192,7 +215,11 @@ MARK m_fsrch(m, ptrn)
return MARK_AT_LINE(l);
}
#endif
#ifdef REGEX
return MARK_AT_LINE(l) + pos + rm[0].rm_so;
#else
return MARK_AT_LINE(l) + (int)(re->startp[0] - line);
#endif
}
pos = 0;
}
@ -212,6 +239,11 @@ MARK m_bsrch(m, ptrn)
int pos; /* last acceptable idx for a match on this line */
int last; /* remembered idx of the last acceptable match on this line */
int try; /* an idx at which we strat searching for another match */
#ifdef REGEX
regex_t *optpat();
regmatch_t rm[SE_MAX];
int n;
#endif
#ifndef CRUNCH
long delta = INFINITY;/* line offset, for things like "/foo/+1" */
#endif
@ -231,11 +263,16 @@ MARK m_bsrch(m, ptrn)
#endif
ptrn++;
#ifdef REGEX
/* XXX where to free re? */
re = optpat(ptrn);
#else
/* free the previous pattern, if any */
if (re) _free_(re);
/* compile the pattern */
re = regcomp(ptrn);
#endif
if (!re)
{
return MARK_UNSET;
@ -271,16 +308,31 @@ MARK m_bsrch(m, ptrn)
line = fetchline(l);
/* check this line */
#ifdef REGEX
if (!regexec(re, line, SE_MAX, rm, 0) && rm[0].rm_so < pos)
#else
if (regexec(re, line, 1) && (int)(re->startp[0] - line) < pos)
#endif
{
try = 0;
/* match! now find the last acceptable one in this line */
do
{
#ifdef REGEX
last = try + rm[0].rm_so;
try += rm[0].rm_eo;
#else
last = (int)(re->startp[0] - line);
try = (int)(re->endp[0] - line);
#endif
} while (try > 0
#ifdef REGEX
&& !regexec(re, &line[try], SE_MAX, rm, REG_NOTBOL)
&& try + rm[0].rm_so < pos);
#else
&& regexec(re, &line[try], FALSE)
&& (int)(re->startp[0] - line) < pos);
#endif
if (wrapped && *o_warn)
msg("(wrapped)");

View File

@ -30,7 +30,7 @@
*/
#ifndef lint
static char rcsid[] = "$Id: regexp.c,v 1.3 1993/08/02 17:54:06 mycroft Exp $";
static char rcsid[] = "$Id: regexp.c,v 1.4 1993/11/08 05:06:24 alm Exp $";
#endif /* not lint */
@ -38,10 +38,69 @@ static char rcsid[] = "$Id: regexp.c,v 1.3 1993/08/02 17:54:06 mycroft Exp $";
#include "config.h"
#include "ctype.h"
#include "vi.h"
#include "regexp.h"
#ifdef REGEX
# include <regex.h>
#else
# include "regexp.h"
#endif
#ifdef REGEX
extern int patlock; /* from cmd_substitute() module */
static regex_t *previous = NULL; /* the previous regexp, used when null regexp is given */
regex_t *
optpat(s)
char *s;
{
static char *neuter();
int n;
if (*s == '\0') {
if (!previous) regerr("RE error: no previous pattern");
return previous;
} else if (previous && !patlock)
regfree(previous);
else if ((previous = (regex_t *) malloc(sizeof(regex_t))) == NULL) {
regerr("RE error: out of memory");
return previous;
}
patlock = 0;
if (n = regcomp(previous, *o_magic ? s : neuter(s),
*o_ignorecase ? REG_ICASE : 0)) {
regerr("RE error: %d", n);
free(previous);
return previous = NULL;
}
return previous;
}
/* escape BRE meta-characters in a string */
static char *
neuter(s)
char *s;
{
static char *hd = NULL;
char *t;
int n = strlen(s);
free(hd);
if ((hd = t = (char *) malloc(n + n + 1)) == NULL)
return NULL;
if (*s == '^')
*t++ = *s++;
while (*s) {
if (*s == '.' || *s == '\\' || *s == '[' || *s == '*')
*t++ = '\\';
*t++ = *s++;
}
*t = '\0';
return hd;
}
#else
static char *previous; /* the previous regexp, used when null regexp is given */
@ -83,7 +142,7 @@ static char *retext; /* points to the text being compiled */
/* error-handling stuff */
jmp_buf errorhandler;
#define FAIL(why) regerror(why); longjmp(errorhandler, 1)
#define FAIL(why) regerr(why); longjmp(errorhandler, 1)
@ -844,7 +903,7 @@ regexp *regcomp(exp)
#endif
if (!re)
{
regerror("Could not malloc a regexp structure");
regerr("Could not malloc a regexp structure");
return (regexp *)0;
}
@ -894,7 +953,7 @@ regexp *regcomp(exp)
}
else
{
regerror("extra \\ at end of regular expression");
regerr("extra \\ at end of regular expression");
}
break;
@ -974,3 +1033,4 @@ int regexec(prog, string, bolflag)
return rc == 1;
}
#endif
#endif /* !REGEX */

View File

@ -4,7 +4,7 @@
* Caveat: this is V8 regexp(3) [actually, a reimplementation thereof],
* not the System V one.
*
* $Id: regexp.h,v 1.2 1993/08/02 17:54:07 mycroft Exp $
* $Id: regexp.h,v 1.3 1993/11/08 05:06:29 alm Exp $
*/
#define NSUBEXP 10
@ -20,4 +20,4 @@ typedef struct regexp {
extern regexp *regcomp();
extern int regexec();
extern void regsub();
extern void regerror();
extern void regerr();

View File

@ -5,21 +5,33 @@
*/
#ifndef lint
static char rcsid[] = "$Id: regsub.c,v 1.3 1993/08/02 17:54:07 mycroft Exp $";
static char rcsid[] = "$Id: regsub.c,v 1.4 1993/11/08 05:06:32 alm Exp $";
#endif /* not lint */
#include "config.h"
#include "ctype.h"
#include "vi.h"
#include "regexp.h"
#ifdef REGEX
# include <regex.h>
#else
# include "regexp.h"
#endif
/* perform substitutions after a regexp match */
#ifdef REGEX
void regsub(rm, startp, endp, src, dst)
regmatch_t *rm; /* the regexp with pointers into matched text */
char *startp, *endp;
REG char *src; /* the replacement string */
REG char *dst; /* where to put the result of the subst */
#else
void regsub(re, src, dst)
regexp *re; /* the regexp with pointers into matched text */
REG char *src; /* the replacement string */
REG char *dst; /* where to put the result of the subst */
#endif
{
REG char *cpy; /* pointer to start of text to copy */
REG char *end; /* pointer to end of text to copy */
@ -43,7 +55,8 @@ void regsub(re, src, dst)
{
if (!prev)
{
regerror("No prev text to substitute for ~");
regerr("No prev text to substitute for ~");
return;
}
len += strlen(prev) - 1;
@ -65,7 +78,7 @@ void regsub(re, src, dst)
start = cpy = (char *)malloc((unsigned)(len + 1));
if (!cpy)
{
regerror("Not enough memory for ~ expansion");
regerr("Not enough memory for ~ expansion");
return;
}
@ -116,8 +129,13 @@ void regsub(re, src, dst)
/* recognize any meta characters */
if (c == '&' && *o_magic)
{
#ifdef REGEX
cpy = startp;
end = endp;
#else
cpy = re->startp[0];
end = re->endp[0];
#endif
}
else
#endif /* not NO_MAGIC */
@ -139,8 +157,13 @@ void regsub(re, src, dst)
case '9':
/* \0 thru \9 mean "copy subexpression" */
c -= '0';
#ifdef REGEX
cpy = startp + (rm[c].rm_so - rm[0].rm_so);
end = endp + (rm[c].rm_eo - rm[0].rm_eo);
#else
cpy = re->startp[c];
end = re->endp[c];
#endif
break;
# ifndef CRUNCH
case 'U':
@ -164,15 +187,25 @@ void regsub(re, src, dst)
*dst++ = c;
continue;
}
#ifdef REGEX
cpy = startp;
end = endp;
#else
cpy = re->startp[0];
end = re->endp[0];
#endif
break;
#else /* NO_MAGIC */
case '&':
/* "\&" means "original text" */
#ifdef REGEX
cpy = startp;
end = endp;
#else
cpy = re->startp[0];
end = re->endp[0];
#endif
break;
#endif /* NO_MAGIC */
default:

View File

@ -6,7 +6,7 @@
* Beaverton, OR 97005
* kirkenda@cs.pdx.edu
*
* $Id: vi.h,v 1.4 1993/11/03 08:27:19 cgd Exp $
* $Id: vi.h,v 1.5 1993/11/08 05:06:35 alm Exp $
*/
#define VERSION "ELVIS 1.7, by Steve Kirkendall (30 December 1992)"
@ -68,6 +68,9 @@
/*------------------------------------------------------------------------*/
/* Miscellaneous constants. */
#ifdef REGEX
# define SE_MAX 30 /* max number of subexpressions */
#endif
#define INFINITY 2000000001L /* a very large integer */
#define LONGKEY 10 /* longest possible raw :map key */
#ifndef MAXRCLEN