Files
oldlinux-files/study/linux-travel/MINIX-1.5/1.5/Source/commands/elvis/cmd2.c
2024-02-19 00:25:23 -05:00

674 lines
12 KiB
C

/* cmd2.c */
/* Author:
* Steve Kirkendall
* 16820 SW Tallac Way
* Beaverton, OR 97006
* kirkenda@jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
*/
/* This file contains some of the commands - mostly ones that change text */
#include "vi.h"
#include "regexp.h"
void cmd_substitute(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra; /* rest of the command line */
{
char *line; /* a line from the file */
regexp *re; /* the compiled search expression */
char *subst; /* the substitution string */
char *opt; /* substitution options */
int optp; /* boolean option: print when done? */
int optg; /* boolean option: substitute globally in line? */
long l; /* a line number */
char *s, *d; /* used during subtitutions */
long chline; /* # of lines changed */
long chsub; /* # of substitutions made */
/* make sure we got a search pattern */
if (*extra != '/' && *extra != '?')
{
msg("Usage: s/regular expression/new text/");
return;
}
/* parse & compile the search pattern */
subst = parseptrn(extra);
re = regcomp(extra + 1);
if (!re)
{
return;
}
/* parse the substitution string & find the option string */
for (opt = subst; *opt && (*opt != *extra || opt[-1] == '\\'); opt++)
{
}
if (*opt)
{
*opt++ = '\0';
}
/* analyse the option string */
optp = optg = 0;
while (*opt)
{
switch (*opt++)
{
case 'p': optp = 1; break;
case 'g': optg = 1; break;
case ' ':
case '\t': break;
default:
msg("Subst options are p and g -- not %c", opt[-1]);
return;
}
}
ChangeText
{
/* reset the change counters */
chline = chsub = 0L;
/* for each selected line */
for (l = markline(frommark); l <= markline(tomark); l++)
{
/* fetch the line */
line = fetchline(l);
/* if it contains the search pattern... */
if (regexec(re, line, TRUE))
{
/* increment the line change counter */
chline++;
/* initialize the pointers */
s = line;
d = tmpblk.c;
/* do once or globally ... */
do
{
/* increment the substitution change counter */
chsub++;
/* this may be the first line to redraw */
redrawrange(l, l + 1L, l + 1L);
/* copy stuff from before the match */
while (s < re->startp[0])
{
*d++ = *s++;
}
/* subtitute for the matched part */
regsub(re, subst, d);
s = re->endp[0];
d += strlen(d);
} while (optg && regexec(re, s, FALSE));
/* copy stuff from after the match */
while (*d++ = *s++) /* yes, ASSIGNMENT! */
{
}
/* replace the old version of the line with the new */
changeline(l, tmpblk.c);
/* if supposed to print it, do so */
if (optp)
{
addstr(tmpblk.c);
addch('\n');
exrefresh();
}
}
}
}
/* report what happened */
if (chsub == 0)
{
msg("Substitution failed");
}
/* tweak for redrawing */
if (chline > 1 || redrawafter && redrawafter != markline(cursor))
{
mustredraw = TRUE;
}
/* free the regexp */
free(re);
/* Reporting */
if (chline >= *o_report)
{
msg("%ld substitutions on %ld lines", chsub, chline);
}
rptlines = 0;
}
void cmd_delete(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra;
{
MARK curs2; /* al altered form of the cursor */
/* choose your cut buffer */
if (*extra == '"')
{
extra++;
}
if (*extra)
{
cutname(*extra);
}
/* make sure we're talking about whole lines here */
frommark = frommark & ~(BLKSIZE - 1);
tomark = (tomark & ~(BLKSIZE - 1)) + BLKSIZE;
/* yank the lines */
cut(frommark, tomark);
/* if CMD_DELETE then delete the lines */
if (cmd != CMD_YANK)
{
curs2 = cursor;
ChangeText
{
/* delete the lines */
delete(frommark, tomark);
}
if (curs2 > tomark)
{
cursor = curs2 - tomark + frommark;
}
else if (curs2 > frommark)
{
cursor = frommark;
}
}
}
void cmd_append(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra;
{
long l; /* line counter */
ChangeText
{
/* if we're doing a change, delete the old version */
if (cmd == CMD_CHANGE)
{
/* delete 'em */
cmd_delete(frommark, tomark, cmd, bang, extra);
}
/* new lines start at the frommark line, or after it */
l = markline(frommark);
if (cmd == CMD_APPEND)
{
l++;
}
/* get lines until no more lines, or "." line, and insert them */
while (vgets('\0', tmpblk.c, BLKSIZE) >= 0)
{
addch('\n');
if (!strcmp(tmpblk.c, "."))
{
break;
}
addline(l, tmpblk.c);
l++;
}
}
/* on the odd chance that we're calling this from vi mode ... */
redraw(MARK_UNSET, FALSE);
}
void cmd_put(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra;
{
/* choose your cut buffer */
if (*extra == '"')
{
extra++;
}
if (*extra)
{
cutname(*extra);
}
/* paste it */
ChangeText
{
cursor = paste(frommark, !bang, FALSE);
}
}
void cmd_join(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra;
{
long l;
char *scan;
int len; /* length of the new line */
/* if only one line is specified, assume the following one joins too */
if (markline(frommark) == nlines)
{
msg("Nothing to join with this line");
return;
}
if (markline(frommark) == markline(tomark))
{
tomark = movedown(tomark, 1L);
}
/* get the first line */
l = markline(frommark);
strcpy(tmpblk.c, fetchline(l++));
len = strlen(tmpblk.c);
/* build the longer line */
while (l <= markline(tomark))
{
/* get the next line */
scan = fetchline(l++);
/* remove any leading whitespace */
while (*scan == '\t' || *scan == ' ')
{
scan++;
}
/* see if the line will fit */
if (strlen(scan) + len + 1 > BLKSIZE)
{
msg("Can't join -- the resulting line would be too long");
return;
}
/* catenate it, with a space in between */
tmpblk.c[len++] = ' ';
strcpy(tmpblk.c + len, scan);
len += strlen(scan);
}
/* make the change */
ChangeText
{
frommark &= ~(BLKSIZE - 1);
tomark &= ~(BLKSIZE - 1);
tomark += BLKSIZE;
delete(frommark, tomark);
addline(markline(frommark), tmpblk.c);
}
}
void cmd_shift(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra;
{
long l; /* line number counter */
int oldidx; /* number of chars previously used for indent */
int newidx; /* number of chars in the new indent string */
int oldcol; /* previous indent amount */
int newcol; /* new indent amount */
char *text; /* pointer to the old line's text */
/* figure out how much of the screen we must redraw (for vi mode) */
if (markline(frommark) != markline(tomark))
{
mustredraw = TRUE;
redrawrange(markline(frommark), markline(tomark) + 1L, markline(tomark) + 1L);
}
ChangeText
{
/* for each line to shift... */
for (l = markline(frommark); l <= markline(tomark); l++)
{
/* get the line - ignore empty lines */
text = fetchline(l);
if (!*text)
continue;
/* calc oldidx and oldcol */
for (oldidx = 0, oldcol = 0;
text[oldidx] == ' ' || text[oldidx] == '\t';
oldidx++)
{
if (text[oldidx] == ' ')
{
oldcol += 1;
}
else
{
oldcol += *o_tabstop - (oldcol % *o_tabstop);
}
}
/* calc newcol */
if (cmd == CMD_SHIFTR)
{
newcol = oldcol + (*o_shiftwidth & 0xff);
}
else
{
newcol = oldcol - (*o_shiftwidth & 0xff);
if (newcol < 0)
newcol = 0;
}
/* if no change, then skip to next line */
if (oldcol == newcol)
continue;
/* build a new indent string */
newidx = 0;
while (newcol >= *o_tabstop)
{
tmpblk.c[newidx++] = '\t';
newcol -= *o_tabstop;
}
while (newcol > 0)
{
tmpblk.c[newidx++] = ' ';
newcol--;
}
tmpblk.c[newidx] = '\0';
/* change the old indent string into the new */
change(MARK_AT_LINE(l), MARK_AT_LINE(l) + oldidx, tmpblk.c);
}
}
/* Reporting... */
rptlines = markline(tomark) - markline(frommark) + 1L;
if (cmd == CMD_SHIFTR)
{
rptlabel = ">ed";
}
else
{
rptlabel = "<ed";
}
}
void cmd_read(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra;
{
long l; /* line number counter - where new lines go */
int fd, rc; /* used while reading from the file */
char *scan; /* used for finding newlines */
char *line; /* points to the start of a line */
int prevrc; /* used to detect abnormal EOF */
/* first line goes after the selected line */
l = markline(frommark) + 1;
/* open the file */
fd = open(extra, O_RDONLY);
if (fd < 0)
{
msg("Can't open \"%s\"", extra);
return;
}
/* get blocks from the file, and add each line in the block */
ChangeText
{
/* NOTE! lint worried needlessly about the order of evaluation
* of the 'rc' expressions in the test clause of this for(;;){}
*/
for (prevrc = rc = 0;
(rc += read(fd, tmpblk.c + rc, BLKSIZE - rc)) > 0;
prevrc = rc)
{
/* if we couldn't read anything, we damn well better have \n */
if (prevrc == rc)
{
if (rc == BLKSIZE)
{
rc--;
}
if (tmpblk.c[rc - 1] != '\n' || rc <= 0)
{
tmpblk.c[rc++] = '\n';
}
}
/* for each complete line in this block, add it */
for (line = scan = tmpblk.c; rc > 0; rc--, scan++)
{
if (*scan == '\n')
{
*scan = '\0';
addline(l, line);
l++;
line = scan + 1;
}
else if (!*scan)
{
/* protect against NUL chars in file */
*scan = 0x80;
}
}
/* any extra chars are shifted to the start of the buffer */
rc = scan - line;
for (scan = tmpblk.c; scan < tmpblk.c + rc; )
{
*scan++ = *line++;
}
}
}
/* close the file */
close(fd);
/* Reporting... */
rptlines = l - markline(frommark) - 1L;
rptlabel = "read";
}
void cmd_list(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra;
{
long l; /* line number counter */
register char *scan; /* used for moving through the line */
for (l = markline(frommark); l <= markline(tomark); l++)
{
/* list the line */
scan = fetchline(l);
while (*scan)
{
/* if the char is non-printable, write it as \000 */
if (*scan < ' ' || *scan > '~')
{
/* build the \000 form & write it */
addch('\\');
addch('0' + ((*scan >> 6) & 3));
addch('0' + ((*scan >> 3) & 7));
addch('0' + (*scan & 7));
}
else
{
addch(*scan);
}
scan++;
}
/* write a $ and a \n */
addstr("$\n");
exrefresh();
}
}
void cmd_undo(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra;
{
undo();
}
/* print the selected lines */
void cmd_print(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra;
{
register char *scan;
register long l;
for (l = markline(frommark); l <= markline(tomark); l++)
{
/* get the next line */
scan = fetchline(l);
addstr(scan);
addch('\n');
exrefresh();
}
}
/* move or copy selected lines */
void cmd_move(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra;
{
MARK destmark;
/* parse the destination linespec. No defaults. Line 0 is okay */
destmark = cursor;
if (!strcmp(extra, "0"))
{
destmark = 0L;
}
else if (linespec(extra, &destmark) == extra || !destmark)
{
msg("invalid destination address");
return;
}
/* flesh the marks out to encompass whole lines */
frommark &= ~(BLKSIZE - 1);
tomark = (tomark & ~(BLKSIZE - 1)) + BLKSIZE;
destmark = (destmark & ~(BLKSIZE - 1)) + BLKSIZE;
/* make sure the destination is valid */
if (cmd == CMD_MOVE && destmark >= frommark && destmark < tomark)
{
msg("invalid destination address");
}
/* Do it */
ChangeText
{
/* save the text to a cut buffer */
cutname('\0');
cut(frommark, tomark);
/* if we're not copying, delete the old text & adjust destmark */
if (cmd != CMD_COPY)
{
delete(frommark, tomark);
if (destmark >= frommark)
{
destmark -= (tomark - frommark);
}
}
/* add the new text */
paste(destmark, FALSE, FALSE);
}
/* move the cursor to the last line of the moved text */
cursor = destmark + (tomark - frommark);
/* Reporting... */
rptlabel = ( (cmd == CMD_COPY) ? "copied" : "moved" );
}
/* execute EX commands from a file */
void cmd_source(frommark, tomark, cmd, bang, extra)
MARK frommark;
MARK tomark;
CMD cmd;
int bang;
char *extra;
{
/* must have a filename */
if (!*extra)
{
msg("\"source\" requires a filename");
return;
}
doexrc(extra);
}