home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume9
/
ed_ip
/
ed.c
next >
Wrap
C/C++ Source or Header
|
1989-11-26
|
28KB
|
1,561 lines
/*
* ed - standard editor
* ~~
* Authors: Brian Beattie, Kees Bot, and others
*
* Copyright 1987 Brian Beattie Rights Reserved.
* Permission to copy or distribute granted under the following conditions:
* 1). No charge may be made other than reasonable charges for reproduction.
* 2). This notice must remain intact.
* 3). No further restrictions may be added.
* 4). Except meaningless ones.
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* TurboC mods and cleanup 8/17/88 RAMontante.
* Further information (posting headers, etc.) at end of file.
* RE stuff replaced with Spencerian version, sundry other bugfix+speedups
* Ian Phillipps. Version incremented to "5".
* _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
*/
int version = 5; /* used only in the "set" function, for i.d. */
#include <stdio.h>
/* Regexp is Henry Spencer's package. WARNING: regsub is modified to return
* a pointer to the \0 after the destination string, and this program refers
* to the "private" reganch field in the struct regexp.
*/
#include <regexp.h>
#ifdef __TURBOC__
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <ctype.h>
#include <io.h>
#define _cleanup() ;
#endif /* ifdef __TURBOC__ */
/*
* #defines for non-printing ASCII characters
*/
#define NUL 0x00 /* ^@ */
#define EOS 0x00 /* end of string */
#define SOH 0x01 /* ^A */
#define STX 0x02 /* ^B */
#define ETX 0x03 /* ^C */
#define EOT 0x04 /* ^D */
#define ENQ 0x05 /* ^E */
#define ACK 0x06 /* ^F */
#define BEL 0x07 /* ^G */
#define BS 0x08 /* ^H */
#define HT 0x09 /* ^I */
#define LF 0x0a /* ^J */
#define NL '\n'
#define VT 0x0b /* ^K */
#define FF 0x0c /* ^L */
#define CR 0x0d /* ^M */
#define SO 0x0e /* ^N */
#define SI 0x0f /* ^O */
#define DLE 0x10 /* ^P */
#define DC1 0x11 /* ^Q */
#define DC2 0x12 /* ^R */
#define DC3 0x13 /* ^S */
#define DC4 0x14 /* ^T */
#define NAK 0x15 /* ^U */
#define SYN 0x16 /* ^V */
#define ETB 0x17 /* ^W */
#define CAN 0x18 /* ^X */
#define EM 0x19 /* ^Y */
#define SUB 0x1a /* ^Z */
#define ESC 0x1b /* ^[ */
#define FS 0x1c /* ^\ */
#define GS 0x1d /* ^] */
#define RS 0x1e /* ^^ */
#define US 0x1f /* ^_ */
#define SP 0x20 /* space */
#define DEL 0x7f /* DEL*/
#define ESCAPE '\\'
#define TRUE 1
#define FALSE 0
#define ERR -2
#define FATAL (ERR-1)
#define CHANGED (ERR-2)
#define SET_FAIL (ERR-3)
#define SUB_FAIL (ERR-4)
#define MEM_FAIL (ERR-5)
#define BUFFER_SIZE 2048 /* stream-buffer size: == 1 hd cluster */
#define LINFREE 1 /* entry not in use */
#define LGLOB 2 /* line marked global */
#define MAXLINE 512 /* max number of chars per line */
#define MAXPAT 256 /* max number of chars per replacement pattern */
#define MAXFNAME 256 /* max file name size */
/** Global variables **/
struct line {
int l_stat; /* empty, mark */
struct line *l_prev;
struct line *l_next;
char l_buff[1];
};
typedef struct line LINE;
int diag = 1; /* diagnostic-output? flag */
int truncflg = 1; /* truncate long line flag */
int eightbit = 1; /* save eighth bit */
int nonascii; /* count of non-ascii chars read */
int nullchar; /* count of null chars read */
int truncated; /* count of lines truncated */
char fname[MAXFNAME];
int fchanged; /* file-changed? flag */
int nofname;
int mark['z'-'a'+1];
regexp *oldpat;
LINE Line0;
int CurLn = 0;
LINE *CurPtr = &Line0; /* CurLn and CurPtr must be kept in step */
int LastLn = 0;
char inlin[MAXLINE];
int pflag;
int Line1, Line2, nlines;
int nflg; /* print line number flag */
int lflg; /* print line in verbose mode */
int pflg; /* print current line after each command */
char *inptr; /* tty input buffer */
struct tbl {
char *t_str;
int *t_ptr;
int t_val;
} *t, tbl[] = {
"number", &nflg, TRUE,
"nonumber", &nflg, FALSE,
"list", &lflg, TRUE,
"nolist", &lflg, FALSE,
"eightbit", &eightbit, TRUE,
"noeightbit", &eightbit, FALSE,
0
};
/*-------------------------------------------------------------------------*/
#ifdef __TURBOC__ /* prototypes (unneeded?) */
void prntln(char *, int, int);
void putcntl(char , FILE *);
int doprnt(int, int);
LINE *getptr(int);
int del(int, int);
int ins(char *);
int append(int, int);
int deflt(int, int);
regexp *optpat(void);
int egets( char*, int, FILE* );
int ckglob( void );
int doglob( void );
int docmd( int );
int dolst( int, int );
int doread( int, char* );
int dowrite( int, int, char*, int );
int find( regexp*, int );
char* getfn( void );
int getlst( void );
int getnum( int );
int getone( void );
int getrhs( char* );
int join( int, int );
int move( int );
int set( void );
int subst( regexp*, char*, int, int );
int transfer( int );
#else /* !__TURBOC__ */
extern char *strcpy();
extern int *malloc();
extern LINE *getptr();
extern char *gettxt();
extern char *gettxtl();
extern char *catsub();
regexp *optpat();
#endif /* __TURBOC__ */
/*________ Macros ________________________________________________________*/
#ifndef max
# define max(a,b) ((a) > (b) ? (a) : (b))
#endif
#ifndef min
# define min(a,b) ((a) < (b) ? (a) : (b))
#endif
#ifndef toupper
# define toupper(c) ((c >= 'a' && c <= 'z') ? c-32 : c )
#endif
#define nextln(l) ((l)+1 > LastLn ? 0 : (l)+1)
#define prevln(l) ((l)-1 < 0 ? LastLn : (l)-1)
#define gettxtl(lin) ((lin)->l_buff)
#define gettxt(num) (gettxtl( getptr(num) ))
#define getnextptr(p) ((p)->l_next)
#define getprevptr(p) ((p)->l_prev)
#define setCurLn( lin ) ( CurPtr = getptr( CurLn = (lin) ) )
#define nextCurLn() ( CurLn = nextln(CurLn), CurPtr = getnextptr( CurPtr ) )
#define prevCurLn() ( CurLn = prevln(CurLn), CurPtr = getprevptr( CurPtr ) )
#define clrbuf() del(1, LastLn)
#define Skip_White_Space {while (*inptr==SP || *inptr==HT) inptr++;}
#define relink(a, x, y, b) { (x)->l_prev = (a); (y)->l_next = (b); }
/*________ functions ______________________________________________________*/
/* append.c */
append(line, glob)
int line, glob;
{
char lin[MAXLINE];
if(glob)
return(ERR);
setCurLn( line );
for (;;) {
char *p = lin;
if(nflg)
printf("%6d. ",CurLn+1);
while( p < &lin[ MAXLINE ] ) {
int ch = getchar();
if( ch == EOF )
return EOF;
if( ch == '\n' ) {
*p = EOS; break;
}
*p++ = ch;
}
if(lin[0] == '.' && lin[1] == '\0')
return(0);
if( ins(lin) < 0)
return( MEM_FAIL );
}
}
/* ckglob.c */
ckglob()
{
regexp *glbpat;
char c, delim, *lin;
int num;
LINE *ptr;
c = *inptr;
if(c != 'g' && c != 'v')
return(0);
if (deflt(1, LastLn) < 0)
return(ERR);
delim = *++inptr;
if(delim <= ' ')
return(ERR);
glbpat = optpat();
if(*inptr == delim)
inptr++;
ptr = getptr(1);
for (num=1; num<=LastLn; num++) {
ptr->l_stat &= ~LGLOB;
if (Line1 <= num && num <= Line2) {
lin = gettxtl(ptr);
if(regexec(glbpat, lin )) {
if (c=='g') ptr->l_stat |= LGLOB;
} else {
if (c=='v') ptr->l_stat |= LGLOB;
}
ptr = getnextptr(ptr);
}
}
return(1);
}
/* deflt.c
* Set Line1 & Line2 (the command-range delimiters) if the file is
* empty; Test whether they have valid values.
*/
int deflt(def1, def2)
int def1, def2;
{
if(nlines == 0) {
Line1 = def1;
Line2 = def2;
}
return ( (Line1>Line2 || Line1<=0) ? ERR : 0 );
}
/* del.c */
/* One of the calls to this function tests its return value for an error
* condition. But del doesn't return any error value, and it isn't obvious
* to me what errors might be detectable/reportable. To silence a warning
* message, I've added a constant return statement. -- RAM
* ... It could check to<=LastLn ... igp
*/
del(from, to)
int from, to;
{
LINE *first, *last, *next, *tmp;
if(from < 1)
from = 1;
first = getprevptr( getptr( from ) );
last = getnextptr( getptr( to ) );
next = first->l_next;
while(next != last && next != &Line0) {
tmp = next->l_next;
free(next);
next = tmp;
}
relink(first, last, first, last);
LastLn -= (to - from)+1;
setCurLn( prevln(from) );
return(0);
}
int dolst(line1, line2)
int line1, line2;
{
int oldlflg=lflg, p;
lflg = 1;
p = doprnt(line1, line2);
lflg = oldlflg;
return p;
}
/* esc.c
* Map escape sequences into their equivalent symbols. Returns the
* correct ASCII character. If no escape prefix is present then s
* is untouched and *s is returned, otherwise **s is advanced to point
* at the escaped character and the translated character is returned.
*/
esc(s)
char **s;
{
register int rval;
if (**s != ESCAPE) {
rval = **s;
} else {
(*s)++;
switch(toupper(**s)) {
case '\000':
rval = ESCAPE; break;
case 'S':
rval = ' '; break;
case 'N':
rval = '\n'; break;
case 'T':
rval = '\t'; break;
case 'B':
rval = '\b'; break;
case 'R':
rval = '\r'; break;
default:
rval = **s; break;
}
}
return (rval);
}
/* doprnt.c */
int doprnt(from, to)
int from, to;
{
from = (from < 1) ? 1 : from;
to = (to > LastLn) ? LastLn : to;
if(to != 0) {
setCurLn( from );
while( CurLn <= to ) {
prntln( gettxtl( CurPtr ), lflg, (nflg ? CurLn : 0));
if( CurLn == to )
break;
nextCurLn();
}
}
return(0);
}
void prntln(str, vflg, lin)
char *str;
int vflg, lin;
{
if(lin)
printf("%7d ",lin);
while(*str && *str != NL) {
if(*str < ' ' || *str >= 0x7f) {
switch(*str) {
case '\t':
if(vflg)
putcntl(*str, stdout);
else
putc(*str, stdout);
break;
case DEL:
putc('^', stdout);
putc('?', stdout);
break;
default:
putcntl(*str, stdout);
break;
}
} else
putc(*str, stdout);
str++;
}
if(vflg)
putchar('$');
putchar('\n');
}
void putcntl(c, stream)
char c;
FILE *stream;
{
putc('^', stream);
putc((c&31)|'@', stream);
}
/* egets.c */
egets(str,size,stream)
char *str;
int size;
FILE *stream;
{
int c, count;
char *cp;
for(count = 0, cp = str; size > count;) {
c = getc(stream);
if(c == EOF) {
*cp = EOS;
if(count)
puts("[Incomplete last line]");
return(count);
}
else if(c == NL) {
*cp = EOS;
return(++count);
}
else if (c == 0)
nullchar++; /* count nulls */
else {
if(c > 127) {
if(!eightbit) /* if not saving eighth bit */
c = c&127; /* strip eigth bit */
nonascii++; /* count it */
}
*cp++ = c; /* not null, keep it */
count++;
}
}
str[count-1] = EOS;
if(c != NL) {
puts("truncating line");
truncated++;
while((c = getc(stream)) != EOF)
if(c == NL)
break;
}
return(count);
} /* egets */
doread(lin, fname)
int lin;
char *fname;
{
FILE *fp;
int err;
unsigned long bytes;
unsigned int lines;
static char str[MAXLINE];
err = 0;
nonascii = nullchar = truncated = 0;
if (diag) printf("\"%s\" ",fname);
if( (fp = fopen(fname, "r")) == NULL ) {
puts(" isn't readable.");
return( ERR );
}
setvbuf(fp, NULL, _IOFBF, BUFFER_SIZE);
setCurLn( lin );
for(lines = 0, bytes = 0;(err = egets(str,MAXLINE,fp)) > 0;) {
bytes += err;
if(ins(str) < 0) {
err = MEM_FAIL;
break;
}
lines++;
}
fclose(fp);
if(err < 0)
return(err);
if (diag) {
printf("%u lines %u bytes",lines,bytes);
if(nonascii)
printf(" [%d non-ascii]",nonascii);
if(nullchar)
printf(" [%d nul]",nullchar);
if(truncated)
printf(" [%d lines truncated]",truncated);
putchar('\n');
}
return( err );
} /* doread */
int dowrite(from, to, fname, apflg)
int from, to;
char *fname;
int apflg;
{
FILE *fp;
int lin, err;
unsigned int lines;
unsigned long bytes;
char *str;
LINE *lptr;
err = 0;
lines = bytes = 0;
printf("\"%s\" ",fname);
if((fp = fopen(fname,(apflg?"a":"w"))) == NULL) {
puts(" can't be opened for writing!");
return( ERR );
}
setvbuf(fp, NULL, _IOFBF, BUFFER_SIZE);
lptr = getptr(from);
for(lin = from; lin <= to; lin++) {
str = lptr->l_buff;
lines++;
bytes += strlen(str) + 1; /* str + '\n' */
if(fputs(str, fp) == EOF) {
puts("file write error");
err++;
break;
}
fputc('\n', fp);
lptr = lptr->l_next;
}
printf("%u lines %lu bytes\n",lines,bytes);
fclose(fp);
return( err );
} /* dowrite */
/* find.c */
find(pat, dir)
regexp *pat;
int dir;
{
int i, num;
LINE *lin;
num = CurLn;
lin = CurPtr;
for(i=0; i<LastLn; i++ ) {
if(regexec( pat, gettxtl( lin ) ))
return(num);
if( dir )
num = nextln(num), lin = getnextptr(lin);
else
num = prevln(num), lin = getprevptr(lin);
}
return ( ERR );
}
/* getfn.c */
char *getfn()
{
static char file[256];
char *cp;
if(*inptr == NL) {
nofname=TRUE;
strcpy(file, fname);
} else {
nofname=FALSE;
Skip_White_Space;
cp = file;
while(*inptr && *inptr != NL && *inptr != SP && *inptr != HT)
*cp++ = *inptr++;
*cp = '\0';
if(strlen(file) == 0) {
puts("bad file name");
return( NULL );
}
}
if(strlen(file) == 0) {
puts("no file name");
return(NULL);
}
return( file );
} /* getfn */
int getnum(first)
int first;
{
regexp *srchpat;
int num;
char c;
Skip_White_Space;
if(*inptr >= '0' && *inptr <= '9') { /* line number */
for(num = 0; *inptr >= '0' && *inptr <= '9'; ++inptr) {
num = (num * 10) + (*inptr - '0');
}
return num;
}
switch(c = *inptr) {
case '.':
inptr++;
return (CurLn);
case '$':
inptr++;
return (LastLn);
case '/':
case '?':
srchpat = optpat();
if(*inptr == c)
*inptr++;
return(find(srchpat,c == '/'?1:0));
case '-':
case '+':
return(first ? CurLn : 1);
case '\'':
inptr++;
if (*inptr < 'a' || *inptr > 'z')
return(EOF);
return mark[ *inptr++ - 'a' ];
default:
return ( first ? EOF : 1 ); /* unknown address */
}
} /* getnum */
/* getone.c
* Parse a number (or arithmetic expression) off the command line.
*/
#define FIRST 1
#define NOTFIRST 0
int getone()
{
int c, i, num;
if((num = getnum(FIRST)) >= 0) {
for (;;) {
Skip_White_Space;
if(*inptr != '+' && *inptr != '-')
break; /* exit infinite loop */
c = *inptr++;
if((i = getnum(NOTFIRST)) < 0)
return ( i );
if(c == '+')
num += i;
else
num -= i;
}
}
return ( num>LastLn ? ERR : num );
} /* getone */
getlst()
{
int num;
Line2 = 0;
for(nlines = 0; (num = getone()) >= 0;)
{
Line1 = Line2;
Line2 = num;
nlines++;
if(*inptr != ',' && *inptr != ';')
break;
if(*inptr == ';')
setCurLn( num );
inptr++;
}
nlines = min(nlines, 2);
if(nlines == 0)
Line2 = CurLn;
if(nlines <= 1)
Line1 = Line2;
return ( (num == ERR) ? num : nlines );
} /* getlst */
/* getptr.c */
LINE *getptr(num)
int num;
{
LINE *ptr;
int j;
if (2*num>LastLn && num<=LastLn) { /* high line numbers */
ptr = Line0.l_prev;
for (j = LastLn; j>num; j--)
ptr = ptr->l_prev;
} else { /* low line numbers */
ptr = &Line0;
for(j = 0; j < num; j++)
ptr = ptr->l_next;
}
return(ptr);
}
/* getrhs.c */
int getrhs(sub)
char *sub;
{
char delim = *inptr++;
char *outmax = sub + MAXPAT;
if( delim == NL || *inptr == NL) /* check for eol */
return( ERR );
while( *inptr != delim && *inptr != NL ) {
if ( sub > outmax )
return ERR;
if ( *inptr == ESCAPE ) {
switch ( *++inptr ) {
case 'r':
*sub++ = '\r';
inptr++;
break;
case ESCAPE:
*sub++ = ESCAPE;
*sub++ = ESCAPE;
inptr++;
case 'n':
*sub++ = '\n';
inptr++;
break;
case 'b':
*sub++ = '\b';
inptr++;
break;
case '0': {
int i=3;
*sub = 0;
do {
if (*++inptr<'0' || *inptr >'7')
break;
*sub = (*sub<<3) | (*inptr-'0');
} while (--i!=0);
sub++;
} break;
default:
if ( *inptr != delim )
*sub++ = ESCAPE;
*sub++ = *inptr;
if ( *inptr != NL )
inptr++;
}
}
else *sub++ = *inptr++;
}
*sub = '\0';
inptr++; /* skip over delimter */
Skip_White_Space;
if(*inptr == 'g') {
*inptr++;
return( 1 );
}
return( 0 );
}
/* ins.c */
ins(str)
char *str;
{
char *cp;
LINE *new, *nxt;
int len;
do {
for ( cp = str; *cp && *cp != NL; cp++ )
;
len = cp - str;
/* cp now points to end of first or only line */
if((new = (LINE *)malloc(sizeof(LINE)+len)) == NULL)
return( MEM_FAIL ); /* no memory */
new->l_stat=0;
strncpy(new->l_buff,str,len); /* build new line */
new->l_buff[len] = EOS;
nxt = getnextptr(CurPtr); /* get next line */
relink(CurPtr, new, new, nxt); /* add to linked list */
relink(new, nxt, CurPtr, new);
LastLn++;
CurLn++;
CurPtr = new;
str = cp + 1;
}
while( *cp != EOS );
return 1;
}
/* join.c */
int join(first, last)
int first, last;
{
char buf[MAXLINE];
char *cp=buf, *str;
LINE *lin;
int num;
if (first<=0 || first>last || last>LastLn)
return(ERR);
if (first==last) {
setCurLn( first );
return 0;
}
lin = getptr(first);
for (num=first; num<=last; num++) {
str=gettxtl(lin);
while ( *str ) {
if (cp >= buf + MAXLINE-1 ) {
puts("line too long");
return(ERR);
}
*cp++ = *str++;
}
lin = getnextptr(lin);
}
*cp = EOS;
del(first, last);
if( ins(buf) < 0 )
return MEM_FAIL;
fchanged = TRUE;
return 0;
}
/* move.c
* Unlink the block of lines from Line1 to Line2, and relink them
* after line "num".
*/
int move(num)
int num;
{
int range;
LINE *before, *first, *last, *after;
if( Line1 <= num && num <= Line2 )
return( ERR );
range = Line2 - Line1 + 1;
before = getptr(prevln(Line1));
first = getptr(Line1);
last = getptr(Line2);
after = getptr(nextln(Line2));
relink(before, after, before, after);
LastLn -= range; /* per AST's posted patch 2/2/88 */
if (num > Line1)
num -= range;
before = getptr(num);
after = getptr(nextln(num));
relink(before, first, last, after);
relink(last, after, before, first);
LastLn += range; /* per AST's posted patch 2/2/88 */
setCurLn( num + range );
return( 1 );
}
int transfer(num)
int num;
{
int mid, lin, ntrans;
if (Line1<=0 || Line1>Line2)
return(ERR);
mid= num<Line2 ? num : Line2;
setCurLn( num );
ntrans=0;
for (lin=Line1; lin<=mid; lin++) {
if( ins(gettxt(lin)) < 0 )
return MEM_FAIL;
ntrans++;
}
lin+=ntrans;
Line2+=ntrans;
for ( ; lin <= Line2; lin += 2 ) {
if( ins(gettxt(lin)) < 0 )
return MEM_FAIL;
Line2++;
}
return(1);
}
/* optpat.c */
regexp *optpat(void)
{
char delim, str[MAXPAT], *cp;
delim = *inptr++;
cp = str;
while(*inptr != delim && *inptr != NL) {
if(*inptr == ESCAPE && inptr[1] != NL)
*cp++ = *inptr++;
*cp++ = *inptr++;
}
*cp = EOS;
if(*str == EOS)
return(oldpat);
if(oldpat)
free(oldpat);
return oldpat = regcomp(str);
}
/* regerror.c */
void regerror( char *s )
{
fprintf( stderr, "ed: %s\n", s );
}
set()
{
char word[16];
int i;
if(*(++inptr) != 't') {
if(*inptr != SP && *inptr != HT && *inptr != NL)
return(ERR);
} else
inptr++;
if ( (*inptr == NL)
#ifdef __TURBOC__
|| (*inptr == CR)
#endif
)
{
printf("ed version %d.%d\n", version/100, version%100);
printf( "number %s, list %s\n",
nflg?"ON":"OFF",
lflg?"ON":"OFF");
return(0);
}
Skip_White_Space;
for(i = 0; *inptr != SP && *inptr != HT && *inptr != NL;)
word[i++] = *inptr++;
word[i] = EOS;
for(t = tbl; t->t_str; t++) {
if(strcmp(word,t->t_str) == 0) {
*t->t_ptr = t->t_val;
return(0);
}
}
return SET_FAIL;
}
#ifndef relink
void relink(a, x, y, b)
LINE *a, *x, *y, *b;
{
x->l_prev = a;
y->l_next = b;
}
#endif
void set_ed_buf(void)
{
relink(&Line0, &Line0, &Line0, &Line0);
CurLn = LastLn = 0;
CurPtr = &Line0;
}
/* subst.c */
int subst(pat, sub, gflg, pflag)
regexp *pat;
char *sub;
int gflg, pflag;
{
int nchngd = 0;
char *txtptr;
char *new, buf[MAXLINE];
int still_running = 1;
LINE *lastline = getptr( Line2 );
if(Line1 <= 0)
return( SUB_FAIL );
nchngd = 0; /* reset count of lines changed */
for( setCurLn( prevln( Line1 ) ); still_running; ) {
nextCurLn();
new = buf;
if ( CurPtr == lastline )
still_running = 0;
if ( regexec( pat, txtptr = gettxtl( CurPtr ) ) ) {
do
{
/* Copy leading text */
int diff = pat->startp[0] - txtptr;
strncpy( new, txtptr, diff );
new += diff;
/* Do substitution */
new = regsub( pat, sub, new );
txtptr = pat->endp[0];
}
while( gflg && !pat->reganch && regexec( pat, txtptr ));
/* Copy trailing chars */
while( *txtptr ) *new++ = *txtptr++;
if(new >= buf+MAXLINE)
return( SUB_FAIL );
*new++ = EOS;
del(CurLn,CurLn);
if( ins(buf) < 0 )
return MEM_FAIL;
nchngd++;
if(pflag)
doprnt(CurLn, CurLn);
}
}
return (( nchngd == 0 && !gflg ) ? SUB_FAIL : nchngd);
}
/* system.c */
#ifndef __TURBOC__
#define SHELL "/bin/sh"
system(c)
char *c; {
int pid, status;
switch (pid = fork()) {
case -1:
return -1;
case 0:
execl(SHELL, "sh", "-c", c, (char *) 0);
exit(-1);
default:
while (wait(&status) != pid)
;
}
return status;
}
#endif /* ifndef __TURBOC__ */
/* docmd.c
* Perform the command specified in the input buffer, as pointed to
* by inptr. Actually, this finds the command letter first.
*/
int docmd(glob)
int glob;
{
static char rhs[MAXPAT];
regexp *subpat;
int c, err, line3;
int apflg, pflag, gflag;
int nchng;
char *fptr;
pflag = FALSE;
Skip_White_Space;
c = *inptr++;
switch(c) {
case NL:
if( nlines == 0 && (Line2 = nextln(CurLn)) == 0 )
return(ERR);
setCurLn( Line2 );
return (1);
case '=':
printf("%d\n",Line2);
break;
case 'a':
if(*inptr != NL || nlines > 1)
return(ERR);
if(append(Line1, glob) < 0)
return(ERR);
fchanged = TRUE;
break;
case 'c':
if(*inptr != NL)
return(ERR);
if(deflt(CurLn, CurLn) < 0)
return(ERR);
if(del(Line1, Line2) < 0)
return(ERR);
if(append(CurLn, glob) < 0)
return(ERR);
fchanged = TRUE;
break;
case 'd':
if(*inptr != NL)
return(ERR);
if(deflt(CurLn, CurLn) < 0)
return(ERR);
if(del(Line1, Line2) < 0)
return(ERR);
if(nextln(CurLn) != 0)
nextCurLn();
fchanged = TRUE;
break;
case 'e':
if(nlines > 0)
return(ERR);
if(fchanged)
return CHANGED;
/*FALL THROUGH*/
case 'E':
if(nlines > 0)
return(ERR);
if(*inptr != ' ' && *inptr != HT && *inptr != NL)
return(ERR);
if((fptr = getfn()) == NULL)
return(ERR);
clrbuf();
if((err = doread(0, fptr)) < 0)
return(err);
strcpy(fname, fptr);
fchanged = FALSE;
break;
case 'f':
if(nlines > 0)
return(ERR);
if(*inptr != ' ' && *inptr != HT && *inptr != NL)
return(ERR);
if((fptr = getfn()) == NULL)
return(ERR);
if (nofname)
printf("%s\n", fname);
else
strcpy(fname, fptr);
break;
case 'i':
if(*inptr != NL || nlines > 1)
return(ERR);
if(append(prevln(Line1), glob) < 0)
return(ERR);
fchanged = TRUE;
break;
case 'j':
if (*inptr != NL || deflt(CurLn, CurLn+1)<0)
return(ERR);
if (join(Line1, Line2) < 0)
return(ERR);
break;
case 'k':
Skip_White_Space;
if (*inptr < 'a' || *inptr > 'z')
return ERR;
c= *inptr++;
if(*inptr != ' ' && *inptr != HT && *inptr != NL)
return(ERR);
mark[c-'a'] = Line1;
break;
case 'l':
if(*inptr != NL)
return(ERR);
if(deflt(CurLn,CurLn) < 0)
return(ERR);
if (dolst(Line1,Line2) < 0)
return(ERR);
break;
case 'm':
if((line3 = getone()) < 0)
return(ERR);
if(deflt(CurLn,CurLn) < 0)
return(ERR);
if(move(line3) < 0)
return(ERR);
fchanged = TRUE;
break;
case 'P':
case 'p':
if(*inptr != NL)
return(ERR);
if(deflt(CurLn,CurLn) < 0)
return(ERR);
if(doprnt(Line1,Line2) < 0)
return(ERR);
break;
case 'q':
if(fchanged)
return CHANGED;
/*FALL THROUGH*/
case 'Q':
if(*inptr == NL && nlines == 0 && !glob)
return(EOF);
else
return(ERR);
case 'r':
if(nlines > 1)
return(ERR);
if(nlines == 0) /* The original code tested */
Line2 = LastLn; /* if(nlines = 0) */
/* which looks wrong. RAM */
if(*inptr != ' ' && *inptr != HT && *inptr != NL)
return(ERR);
if((fptr = getfn()) == NULL)
return(ERR);
if((err = doread(Line2, fptr)) < 0)
return(err);
fchanged = TRUE;
break;
case 's':
if(*inptr == 'e')
return(set());
Skip_White_Space;
if((subpat = optpat()) == NULL)
return(ERR);
if((gflag = getrhs(rhs)) < 0)
return(ERR);
if(*inptr == 'p')
pflag++;
if(deflt(CurLn, CurLn) < 0)
return(ERR);
if((nchng = subst(subpat, rhs, gflag, pflag)) < 0)
return(ERR);
if(nchng)
fchanged = TRUE;
break;
case 't':
if((line3 = getone()) < 0)
return(ERR);
if(deflt(CurLn,CurLn) < 0)
return(ERR);
if(transfer(line3) < 0)
return(ERR);
fchanged = TRUE;
break;
case 'W':
case 'w':
apflg = (c=='W');
if(*inptr != ' ' && *inptr != HT && *inptr != NL)
return(ERR);
if((fptr = getfn()) == NULL)
return(ERR);
if(deflt(1, LastLn) < 0)
return(ERR);
if(dowrite(Line1, Line2, fptr, apflg) < 0)
return(ERR);
fchanged = FALSE;
break;
case 'x':
if(*inptr == NL && nlines == 0 && !glob) {
if((fptr = getfn()) == NULL)
return(ERR);
if(dowrite(1, LastLn, fptr, 0) >= 0)
return(EOF);
}
return(ERR);
case 'z':
if(deflt(CurLn,CurLn) < 0)
return(ERR);
switch(*inptr) {
case '-':
if(doprnt(Line1-21,Line1) < 0)
return(ERR);
break;
case '.':
if(doprnt(Line1-11,Line1+10) < 0)
return(ERR);
break;
case '+':
case '\n':
if(doprnt(Line1,Line1+21) < 0)
return(ERR);
break;
}
break;
default:
return(ERR);
}
return (0);
} /* docmd */
/* doglob.c */
doglob()
{
int lin, stat;
char *cmd;
LINE *ptr;
cmd = inptr;
for (;;) {
ptr = getptr(1);
for (lin=1; lin<=LastLn; lin++) {
if (ptr->l_stat & LGLOB)
break;
ptr = getnextptr(ptr);
}
if (lin > LastLn)
break;
ptr->l_stat &= ~LGLOB;
CurLn = lin; CurPtr = ptr;
inptr = cmd;
if((stat = getlst()) < 0)
return(stat);
if((stat = docmd(1)) < 0)
return(stat);
}
return(CurLn);
} /* doglob */
/*
* Software signal 2 or SIGINT is caught and the result is to resume
* the main loop at a command prompt.
*/
#include <setjmp.h>
jmp_buf env;
#ifndef __TURBOC__
intr()
{
puts("intr()?");
longjmp(env, 1);
}
#else
void Catcher(void)
{
longjmp(env, 1);
}
#endif /* !__TURBOC__ */
/*-------- main ---------------------------------------------------------*/
#ifndef _Cdecl
# define _Cdecl
#endif
void _Cdecl main(argc,argv)
int argc;
char **argv;
{
int stat, i, doflush;
set_ed_buf();
doflush=isatty(1);
if (argc>1 && argv[1][0]=='-' && argv[1][1]==0) {
diag = 0;
argc--;
argv++;
}
if(argc > 1) {
for(i = 1; i < argc; i++) {
if(doread(0,argv[i])==0) {
setCurLn( 1 );
strcpy(fname, argv[i]);
break;
}
}
}
for (;;) {
setjmp(env);
putchar(':'); /* The command-line prompt */
#ifndef __TURBOC__
signal(2, intr);
#else /* __TURBOC__ */
signal(SIGINT, Catcher);
#endif /* !__TURBOC__ */
if (doflush)
fflush(stdout);
if (fgets(inlin, sizeof(inlin),stdin) == NULL) {
puts("Null input.");
break;
}
if(*inlin == '!') {
for(inptr = inlin; *inptr != NL; inptr++)
;
*inptr = EOS;
system(inlin+1);
continue;
}
inptr = inlin;
if(getlst() >= 0)
if((stat = ckglob()) != 0) {
if(stat >= 0 && (stat = doglob()) >= 0) {
setCurLn( stat );
continue;
}
} else {
if((stat = docmd(0)) >= 0) {
if(stat == 1)
doprnt(CurLn, CurLn);
continue;
}
}
switch (stat) {
case EOF:
_cleanup(); exit(0);
case FATAL:
fputs("FATAL ERROR\n",stderr);
_cleanup(); exit(1);
case CHANGED:
puts("File has been changed.");
break;
case SET_FAIL:
puts("`set' command failed.");
break;
case SUB_FAIL:
puts("string substitution failed.");
break;
case MEM_FAIL:
puts("Out of memory: text may have been lost." );
break;
default:
puts("Oops?");
/* Unrecognized or failed command (this */
/* is SOOOO much better than "?" :-) */
}
}
} /* main */
/*________ end of source code ____________________________________________*/