2199 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2199 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* Copyright 1987 Brian Beattie Rights Reserved.
 | 
						|
 *
 | 
						|
 * Permission to copy and/or distribute granted under the
 | 
						|
 * following conditions:
 | 
						|
 *
 | 
						|
 * 1). No charge may be made other than resonable charges
 | 
						|
 *	for reproduction.
 | 
						|
 *
 | 
						|
 * 2). This notice must remain intact.
 | 
						|
 *
 | 
						|
 * 3). No further restrictions may be added.
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
/*	This program used to be in many little pieces, with this makefile:
 | 
						|
.SUFFIXES:	.c .s
 | 
						|
 | 
						|
CFLAGS = -F
 | 
						|
 | 
						|
OBJS =	append.s catsub.s ckglob.s deflt.s del.s docmd.s doglob.s\
 | 
						|
  doprnt.s doread.s dowrite.s ed.s egets.s find.s getfn.s getlst.s\
 | 
						|
  getnum.s getone.s getptr.s getrhs.s gettxt.s ins.s join.s maksub.s\
 | 
						|
  move.s optpat.s set.s setbuf.s subst.s getpat.s matchs.s amatch.s\
 | 
						|
  unmkpat.s omatch.s makepat.s bitmap.s dodash.s esc.s System.s
 | 
						|
 | 
						|
ed:	$(OBJS)
 | 
						|
  cc -T. -i -o ed $(OBJS)
 | 
						|
*/
 | 
						|
 | 
						|
#include <sys/types.h>
 | 
						|
#include <signal.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <string.h>
 | 
						|
#include <unistd.h>
 | 
						|
#include <sys/wait.h>
 | 
						|
#include <stdio.h>
 | 
						|
 | 
						|
/****************************/
 | 
						|
 | 
						|
/*	tools.h	*/
 | 
						|
/*
 | 
						|
 *	#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 TRUE	1
 | 
						|
#define FALSE	0
 | 
						|
#define ERR	-2
 | 
						|
 | 
						|
 | 
						|
/*	Definitions of meta-characters used in pattern matching
 | 
						|
 *	routines.  LITCHAR & NCCL are only used as token identifiers;
 | 
						|
 *	all the others are also both token identifier and actual symbol
 | 
						|
 *	used in the regular expression.
 | 
						|
 */
 | 
						|
 | 
						|
 | 
						|
#define BOL	'^'
 | 
						|
#define EOL	'$'
 | 
						|
#define ANY	'.'
 | 
						|
#define LITCHAR	'L'
 | 
						|
#define	ESCAPE	'\\'
 | 
						|
#define CCL	'['		/* Character class: [...] */
 | 
						|
#define CCLEND	']'
 | 
						|
#define NEGATE	'^'
 | 
						|
#define NCCL	'!'		/* Negative character class [^...] */
 | 
						|
#define CLOSURE	'*'
 | 
						|
#define OR_SYM	'|'
 | 
						|
#define DITTO	'&'
 | 
						|
#define OPEN	'('
 | 
						|
#define CLOSE	')'
 | 
						|
 | 
						|
/* Largest permitted size for an expanded character class.  (i.e. the class
 | 
						|
 * [a-z] will expand into 26 symbols; [a-z0-9] will expand into 36.)
 | 
						|
 */
 | 
						|
#define CLS_SIZE	128
 | 
						|
 | 
						|
/*
 | 
						|
 *	Tokens are used to hold pattern templates. (see makepat())
 | 
						|
 */
 | 
						|
typedef char BITMAP;
 | 
						|
 | 
						|
typedef struct token {
 | 
						|
  char tok;
 | 
						|
  char lchar;
 | 
						|
  BITMAP *bitmap;
 | 
						|
  struct token *next;
 | 
						|
} TOKEN;
 | 
						|
 | 
						|
#define TOKSIZE sizeof (TOKEN)
 | 
						|
 | 
						|
/*
 | 
						|
 *	An absolute maximun for strings.
 | 
						|
 */
 | 
						|
 | 
						|
#define MAXSTR	132		/* Maximum numbers of characters in a line */
 | 
						|
 | 
						|
 | 
						|
/* Macros */
 | 
						|
#define max(a,b)	((a>b)?a:b)
 | 
						|
#define min(a,b)	((a<b)?a:b)
 | 
						|
#define toupper(c)	(c>='a'&&c<='z'?c-32:c)
 | 
						|
 | 
						|
/*	ed.h	*/
 | 
						|
#define FATAL	(ERR-1)
 | 
						|
struct line {
 | 
						|
  int l_stat;			/* empty, mark */
 | 
						|
  struct line *l_prev;
 | 
						|
  struct line *l_next;
 | 
						|
  char l_buff[1];
 | 
						|
};
 | 
						|
 | 
						|
typedef struct line LINE;
 | 
						|
 | 
						|
#define LINFREE	1		/* entry not in use */
 | 
						|
#define LGLOB	2		/* line marked global */
 | 
						|
 | 
						|
				/* max number of chars per line */
 | 
						|
#define MAXLINE	(sizeof(int) == 2 ? 256 : 8192)
 | 
						|
#define MAXPAT	256		/* max number of chars per replacement
 | 
						|
				 * pattern */
 | 
						|
				/* max file name size */
 | 
						|
#define MAXFNAME (sizeof(int) == 2 ? 256 : 1024)
 | 
						|
 | 
						|
extern LINE line0;
 | 
						|
extern int curln, lastln, line1, line2, nlines;
 | 
						|
extern int nflg;		/* print line number flag */
 | 
						|
extern int lflg;		/* print line in verbose mode */
 | 
						|
extern char *inptr;		/* tty input buffer */
 | 
						|
extern char linbuf[], *linptr;	/* current line */
 | 
						|
extern int truncflg;		/* truncate long line flag */
 | 
						|
extern int eightbit;		/* save eighth bit */
 | 
						|
extern int nonascii;		/* count of non-ascii chars read */
 | 
						|
extern int nullchar;		/* count of null chars read */
 | 
						|
extern int truncated;		/* count of lines truncated */
 | 
						|
extern int fchanged;		/* file changed */
 | 
						|
 | 
						|
#define nextln(l)	((l)+1 > lastln ? 0 : (l)+1)
 | 
						|
#define prevln(l)	((l)-1 < 0 ? lastln : (l)-1)
 | 
						|
 | 
						|
/*	amatch.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
 | 
						|
_PROTOTYPE(int main, (int argc, char **argv));
 | 
						|
_PROTOTYPE(static char *match, (char *lin, TOKEN *pat, char *boln));
 | 
						|
_PROTOTYPE(char *amatch, (char *lin, TOKEN *pat, char *boln));
 | 
						|
_PROTOTYPE(int append, (int line, int glob));
 | 
						|
_PROTOTYPE(BITMAP *makebitmap, (unsigned size));
 | 
						|
_PROTOTYPE(int setbit, (unsigned c, char *map, unsigned val));
 | 
						|
_PROTOTYPE(int testbit, (unsigned c, char *map));
 | 
						|
_PROTOTYPE(char *catsub, (char *from, char *to, char *sub, char *new, char *newend));
 | 
						|
_PROTOTYPE(int ckglob, (void));
 | 
						|
_PROTOTYPE(int deflt, (int def1, int def2));
 | 
						|
_PROTOTYPE(int del, (int from, int to));
 | 
						|
_PROTOTYPE(int docmd, (int glob));
 | 
						|
_PROTOTYPE(int dolst, (int line1, int line2));
 | 
						|
_PROTOTYPE(char *dodash, (int delim, char *src, char *map));
 | 
						|
_PROTOTYPE(int doglob, (void));
 | 
						|
_PROTOTYPE(int doprnt, (int from, int to));
 | 
						|
_PROTOTYPE(void prntln, (char *str, int vflg, int lin));
 | 
						|
_PROTOTYPE(void putcntl, (int c, FILE *stream));
 | 
						|
_PROTOTYPE(int doread, (int lin, char *fname));
 | 
						|
_PROTOTYPE(int dowrite, (int from, int to, char *fname, int apflg));
 | 
						|
_PROTOTYPE(void intr, (int sig));
 | 
						|
_PROTOTYPE(int egets, (char *str, int size, FILE *stream));
 | 
						|
_PROTOTYPE(int esc, (char **s));
 | 
						|
_PROTOTYPE(int find, (TOKEN *pat, int dir));
 | 
						|
_PROTOTYPE(char *getfn, (void));
 | 
						|
_PROTOTYPE(int getlst, (void));
 | 
						|
_PROTOTYPE(int getnum, (int first));
 | 
						|
_PROTOTYPE(int getone, (void));
 | 
						|
_PROTOTYPE(TOKEN *getpat, (char *arg));
 | 
						|
_PROTOTYPE(LINE *getptr, (int num));
 | 
						|
_PROTOTYPE(int getrhs, (char *sub));
 | 
						|
_PROTOTYPE(char *gettxt, (int num));
 | 
						|
_PROTOTYPE(int ins, (char *str));
 | 
						|
_PROTOTYPE(int System, (char *c));
 | 
						|
_PROTOTYPE(int join, (int first, int last));
 | 
						|
_PROTOTYPE(TOKEN *makepat, (char *arg, int delim));
 | 
						|
_PROTOTYPE(char *maksub, (char *sub, int subsz));
 | 
						|
_PROTOTYPE(char *matchs, (char *line, TOKEN *pat, int ret_endp));
 | 
						|
_PROTOTYPE(int move, (int num));
 | 
						|
_PROTOTYPE(int transfer, (int num));
 | 
						|
_PROTOTYPE(int omatch, (char **linp, TOKEN *pat, char *boln));
 | 
						|
_PROTOTYPE(TOKEN *optpat, (void));
 | 
						|
_PROTOTYPE(int set, (void));
 | 
						|
_PROTOTYPE(int show, (void));
 | 
						|
_PROTOTYPE(void relink, (LINE *a, LINE *x, LINE *y, LINE *b));
 | 
						|
_PROTOTYPE(void clrbuf, (void));
 | 
						|
_PROTOTYPE(void set_buf, (void));
 | 
						|
_PROTOTYPE(int subst, (TOKEN *pat, char *sub, int gflg, int pflag));
 | 
						|
_PROTOTYPE(void unmakepat, (TOKEN *head));
 | 
						|
 | 
						|
/*     Scans throught the pattern template looking for a match
 | 
						|
 * with lin.  Each element of lin is compared with the template
 | 
						|
 * until either a mis-match is found or the end of the template
 | 
						|
 * is reached.  In the former case a 0 is returned; in the latter,
 | 
						|
 * a pointer into lin (pointing to the character following the
 | 
						|
 * matched pattern) is returned.
 | 
						|
 *
 | 
						|
 *	"lin"	is a pointer to the line being searched.
 | 
						|
 *	"pat"	is a pointer to a template made by makepat().
 | 
						|
 *	"boln"	is a pointer into "lin" which points at the
 | 
						|
 *			character at the beginning of the line.
 | 
						|
 */
 | 
						|
 | 
						|
char *paropen[9], *parclose[9];
 | 
						|
int between, parnum;
 | 
						|
 | 
						|
char *amatch(lin, pat, boln)
 | 
						|
char *lin;
 | 
						|
TOKEN *pat;
 | 
						|
char *boln;
 | 
						|
{
 | 
						|
  between = 0;
 | 
						|
  parnum = 0;
 | 
						|
 | 
						|
  lin = match(lin, pat, boln);
 | 
						|
 | 
						|
  if (between) return 0;
 | 
						|
 | 
						|
  while (parnum < 9) {
 | 
						|
	paropen[parnum] = parclose[parnum] = "";
 | 
						|
	parnum++;
 | 
						|
  }
 | 
						|
  return lin;
 | 
						|
}
 | 
						|
 | 
						|
static char *match(lin, pat, boln)
 | 
						|
char *lin;
 | 
						|
TOKEN *pat;
 | 
						|
char *boln;
 | 
						|
{
 | 
						|
  register char *bocl, *rval, *strstart;
 | 
						|
 | 
						|
  if (pat == 0) return 0;
 | 
						|
 | 
						|
  strstart = lin;
 | 
						|
 | 
						|
  while (pat) {
 | 
						|
	if (pat->tok == CLOSURE && pat->next) {
 | 
						|
		/* Process a closure: first skip over the closure
 | 
						|
		 * token to the object to be repeated.  This object
 | 
						|
		 * can be a character class. */
 | 
						|
 | 
						|
		pat = pat->next;
 | 
						|
 | 
						|
		/* Now match as many occurrences of the closure
 | 
						|
		 * pattern as possible. */
 | 
						|
		bocl = lin;
 | 
						|
 | 
						|
		while (*lin && omatch(&lin, pat, boln));
 | 
						|
 | 
						|
		/* 'Lin' now points to the character that made made
 | 
						|
		 * us fail.  Now go on to process the rest of the
 | 
						|
		 * string.  A problem here is a character following
 | 
						|
		 * the closure which could have been in the closure.
 | 
						|
		 * For example, in the pattern "[a-z]*t" (which
 | 
						|
		 * matches any lower-case word ending in a t), the
 | 
						|
		 * final 't' will be sucked up in the while loop.
 | 
						|
		 * So, if the match fails, we back up a notch and try
 | 
						|
		 * to match the rest of the string again, repeating
 | 
						|
		 * this process recursively until we get back to the
 | 
						|
		 * beginning of the closure.  The recursion goes, at
 | 
						|
		 * most two levels deep. */
 | 
						|
 | 
						|
		if (pat = pat->next) {
 | 
						|
			int savbtwn = between;
 | 
						|
			int savprnm = parnum;
 | 
						|
 | 
						|
			while (bocl <= lin) {
 | 
						|
				if (rval = match(lin, pat, boln)) {
 | 
						|
					/* Success */
 | 
						|
					return(rval);
 | 
						|
				} else {
 | 
						|
					--lin;
 | 
						|
					between = savbtwn;
 | 
						|
					parnum = savprnm;
 | 
						|
				}
 | 
						|
			}
 | 
						|
			return(0);	/* match failed */
 | 
						|
		}
 | 
						|
	} else if (pat->tok == OPEN) {
 | 
						|
		if (between || parnum >= 9) return 0;
 | 
						|
		paropen[parnum] = lin;
 | 
						|
		between = 1;
 | 
						|
		pat = pat->next;
 | 
						|
	} else if (pat->tok == CLOSE) {
 | 
						|
		if (!between) return 0;
 | 
						|
		parclose[parnum++] = lin;
 | 
						|
		between = 0;
 | 
						|
		pat = pat->next;
 | 
						|
	} else if (omatch(&lin, pat, boln)) {
 | 
						|
		pat = pat->next;
 | 
						|
	} else {
 | 
						|
		return(0);
 | 
						|
	}
 | 
						|
  }
 | 
						|
 | 
						|
  /* Note that omatch() advances lin to point at the next character to
 | 
						|
   * be matched.  Consequently, when we reach the end of the template,
 | 
						|
   * lin will be pointing at the character following the last character
 | 
						|
   * matched.  The exceptions are templates containing only a BOLN or
 | 
						|
   * EOLN token.  In these cases omatch doesn't advance.
 | 
						|
   * 
 | 
						|
   * A philosophical point should be mentioned here.  Is $ a position or a
 | 
						|
   * character? (i.e. does $ mean the EOL character itself or does it
 | 
						|
   * mean the character at the end of the line.)  I decided here to
 | 
						|
   * make it mean the former, in order to make the behavior of match()
 | 
						|
   * consistent.  If you give match the pattern ^$ (match all lines
 | 
						|
   * consisting only of an end of line) then, since something has to be
 | 
						|
   * returned, a pointer to the end of line character itself is
 | 
						|
   * returned. */
 | 
						|
 | 
						|
  return((char *) max(strstart, lin));
 | 
						|
}
 | 
						|
 | 
						|
/*	append.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
/* #include "ed.h" */
 | 
						|
 | 
						|
int append(line, glob)
 | 
						|
int line, glob;
 | 
						|
{
 | 
						|
  int stat;
 | 
						|
  char lin[MAXLINE];
 | 
						|
 | 
						|
  if (glob) return(ERR);
 | 
						|
  curln = line;
 | 
						|
  while (1) {
 | 
						|
	if (nflg) printf("%6d. ", curln + 1);
 | 
						|
 | 
						|
	if (fgets(lin, MAXLINE, stdin) == NULL) return(EOF);
 | 
						|
	if (lin[0] == '.' && lin[1] == '\n') return (0);
 | 
						|
	stat = ins(lin);
 | 
						|
	if (stat < 0) return(ERR);
 | 
						|
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/*	bitmap.c	*/
 | 
						|
/*
 | 
						|
 *	BITMAP.C -	makebitmap, setbit, testbit
 | 
						|
 *			bit-map manipulation routines.
 | 
						|
 *
 | 
						|
 *	Copyright (c) Allen I. Holub, all rights reserved.  This program may
 | 
						|
 *		for copied for personal, non-profit use only.
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
/* #include <stdio.h> */
 | 
						|
#endif
 | 
						|
 | 
						|
/* #include "tools.h" */
 | 
						|
 | 
						|
 | 
						|
BITMAP *makebitmap(size)
 | 
						|
unsigned size;
 | 
						|
{
 | 
						|
  /* Make a bit map with "size" bits.  The first entry in the map is an
 | 
						|
   * "unsigned int" representing the maximum bit.  The map itself is
 | 
						|
   * concatenated to this integer. Return a pointer to a map on
 | 
						|
   * success, 0 if there's not enough memory. */
 | 
						|
 | 
						|
  unsigned *map, numbytes;
 | 
						|
 | 
						|
  numbytes = (size >> 3) + ((size & 0x07) ? 1 : 0);
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
  printf("Making a %d bit map (%d bytes required)\n", size, numbytes);
 | 
						|
#endif
 | 
						|
 | 
						|
  if (map = (unsigned *) malloc(numbytes + sizeof(unsigned))) {
 | 
						|
	*map = size;
 | 
						|
	memset(map + 1, 0, numbytes);
 | 
						|
  }
 | 
						|
 | 
						|
  return((BITMAP *) map);
 | 
						|
}
 | 
						|
 | 
						|
int setbit(c, map, val)
 | 
						|
unsigned c, val;
 | 
						|
char *map;
 | 
						|
{
 | 
						|
  /* Set bit c in the map to val. If c > map-size, 0 is returned, else
 | 
						|
   * 1 is returned. */
 | 
						|
 | 
						|
  if (c >= *(unsigned *) map)	/* if c >= map size */
 | 
						|
	return 0;
 | 
						|
 | 
						|
  map += sizeof(unsigned);	/* skip past size */
 | 
						|
 | 
						|
  if (val)
 | 
						|
	map[c >> 3] |= 1 << (c & 0x07);
 | 
						|
  else
 | 
						|
	map[c >> 3] &= ~(1 << (c & 0x07));
 | 
						|
 | 
						|
  return 1;
 | 
						|
}
 | 
						|
 | 
						|
int testbit(c, map)
 | 
						|
unsigned c;
 | 
						|
char *map;
 | 
						|
{
 | 
						|
  /* Return 1 if the bit corresponding to c in map is set. 0 if it is not. */
 | 
						|
 | 
						|
  if (c >= *(unsigned *) map) return 0;
 | 
						|
 | 
						|
  map += sizeof(unsigned);
 | 
						|
 | 
						|
  return(map[c >> 3] & (1 << (c & 0x07)));
 | 
						|
}
 | 
						|
 | 
						|
/*	catsub.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
/* #include "ed.h" */
 | 
						|
 | 
						|
extern char *paropen[9], *parclose[9];
 | 
						|
 | 
						|
char *catsub(from, to, sub, new, newend)
 | 
						|
char *from, *to, *sub, *new, *newend;
 | 
						|
{
 | 
						|
  char *cp, *cp2;
 | 
						|
 | 
						|
  for (cp = new; *sub != EOS && cp < newend;) {
 | 
						|
	if (*sub == DITTO) for (cp2 = from; cp2 < to;) {
 | 
						|
			*cp++ = *cp2++;
 | 
						|
			if (cp >= newend) break;
 | 
						|
		}
 | 
						|
	else if (*sub == ESCAPE) {
 | 
						|
		sub++;
 | 
						|
		if ('1' <= *sub && *sub <= '9') {
 | 
						|
			char *parcl = parclose[*sub - '1'];
 | 
						|
 | 
						|
			for (cp2 = paropen[*sub - '1']; cp2 < parcl;) {
 | 
						|
				*cp++ = *cp2++;
 | 
						|
				if (cp >= newend) break;
 | 
						|
			}
 | 
						|
		} else
 | 
						|
			*cp++ = *sub;
 | 
						|
	} else
 | 
						|
		*cp++ = *sub;
 | 
						|
 | 
						|
	sub++;
 | 
						|
  }
 | 
						|
 | 
						|
  return(cp);
 | 
						|
}
 | 
						|
 | 
						|
/*	ckglob.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
/* #include "ed.h" */
 | 
						|
 | 
						|
int ckglob()
 | 
						|
{
 | 
						|
  TOKEN *glbpat;
 | 
						|
  char c, delim;
 | 
						|
  char lin[MAXLINE];
 | 
						|
  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) {
 | 
						|
		strcpy(lin, ptr->l_buff);
 | 
						|
		strcat(lin, "\n");
 | 
						|
		if (matchs(lin, glbpat, 0)) {
 | 
						|
			if (c == 'g') ptr->l_stat |= LGLOB;
 | 
						|
		} else {
 | 
						|
			if (c == 'v') ptr->l_stat |= LGLOB;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	ptr = ptr->l_next;
 | 
						|
  }
 | 
						|
  return(1);
 | 
						|
}
 | 
						|
 | 
						|
/*	deflt.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
/* #include "ed.h" */
 | 
						|
 | 
						|
int deflt(def1, def2)
 | 
						|
int def1, def2;
 | 
						|
{
 | 
						|
  if (nlines == 0) {
 | 
						|
	line1 = def1;
 | 
						|
	line2 = def2;
 | 
						|
  }
 | 
						|
  if (line1 > line2 || line1 <= 0) return(ERR);
 | 
						|
  return(0);
 | 
						|
}
 | 
						|
 | 
						|
/*	del.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
/* #include "ed.h" */
 | 
						|
 | 
						|
int del(from, to)
 | 
						|
int from, to;
 | 
						|
{
 | 
						|
  LINE *first, *last, *next, *tmp;
 | 
						|
 | 
						|
  if (from < 1) from = 1;
 | 
						|
  first = getptr(prevln(from));
 | 
						|
  last = getptr(nextln(to));
 | 
						|
  next = first->l_next;
 | 
						|
  while (next != last && next != &line0) {
 | 
						|
	tmp = next->l_next;
 | 
						|
	free((char *) next);
 | 
						|
	next = tmp;
 | 
						|
  }
 | 
						|
  relink(first, last, first, last);
 | 
						|
  lastln -= (to - from) + 1;
 | 
						|
  curln = prevln(from);
 | 
						|
  return(0);
 | 
						|
}
 | 
						|
 | 
						|
/*	docmd.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
/* #include "ed.h" */
 | 
						|
 | 
						|
char fname[MAXFNAME];
 | 
						|
int fchanged;
 | 
						|
extern int nofname;
 | 
						|
 | 
						|
extern int mark[];
 | 
						|
 | 
						|
int docmd(glob)
 | 
						|
int glob;
 | 
						|
{
 | 
						|
  static char rhs[MAXPAT];
 | 
						|
  TOKEN *subpat;
 | 
						|
  int c, err, line3;
 | 
						|
  int apflg, pflag, gflag;
 | 
						|
  int nchng;
 | 
						|
  char *fptr;
 | 
						|
 | 
						|
  pflag = FALSE;
 | 
						|
  while (*inptr == SP && *inptr == HT) inptr++;
 | 
						|
 | 
						|
  c = *inptr++;
 | 
						|
 | 
						|
  switch (c) {
 | 
						|
      case NL:
 | 
						|
	if (nlines == 0) {
 | 
						|
		if ((line2 = nextln(curln)) == 0) return(ERR);
 | 
						|
	}
 | 
						|
	curln = line2;
 | 
						|
	return(1);
 | 
						|
	break;
 | 
						|
 | 
						|
      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) curln = nextln(curln);
 | 
						|
	fchanged = TRUE;
 | 
						|
	break;
 | 
						|
 | 
						|
      case 'e':
 | 
						|
	if (nlines > 0) return(ERR);
 | 
						|
	if (fchanged) {
 | 
						|
		fchanged = FALSE;
 | 
						|
		return(ERR);
 | 
						|
	}
 | 
						|
 | 
						|
	/* 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':
 | 
						|
	while (*inptr == ' ' || *inptr == HT) inptr++;
 | 
						|
 | 
						|
	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) {
 | 
						|
		fchanged = FALSE;
 | 
						|
		return(ERR);
 | 
						|
	}
 | 
						|
 | 
						|
	/* 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) line2 = lastln;
 | 
						|
 | 
						|
	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());
 | 
						|
	while (*inptr == SP || *inptr == HT) inptr++;
 | 
						|
	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);
 | 
						|
}
 | 
						|
 | 
						|
int dolst(line1, line2)
 | 
						|
int line1, line2;
 | 
						|
{
 | 
						|
  int oldlflg = lflg, p;
 | 
						|
 | 
						|
  lflg = 1;
 | 
						|
  p = doprnt(line1, line2);
 | 
						|
  lflg = oldlflg;
 | 
						|
 | 
						|
  return p;
 | 
						|
}
 | 
						|
 | 
						|
/*	dodash.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
 | 
						|
/*	Expand the set pointed to by *src into dest.
 | 
						|
 *	Stop at delim.  Return 0 on error or size of
 | 
						|
 *	character class on success.  Update *src to
 | 
						|
 *	point at delim.  A set can have one element
 | 
						|
 *	{x} or several elements ( {abcdefghijklmnopqrstuvwxyz}
 | 
						|
 *	and {a-z} are equivalent ).  Note that the dash
 | 
						|
 *	notation is expanded as sequential numbers.
 | 
						|
 *	This means (since we are using the ASCII character
 | 
						|
 *	set) that a-Z will contain the entire alphabet
 | 
						|
 *	plus the symbols: [\]^_`.  The maximum number of
 | 
						|
 *	characters in a character class is defined by maxccl.
 | 
						|
 */
 | 
						|
char *dodash(delim, src, map)
 | 
						|
int delim;
 | 
						|
char *src, *map;
 | 
						|
{
 | 
						|
 | 
						|
  register int first, last;
 | 
						|
  char *start;
 | 
						|
 | 
						|
  start = src;
 | 
						|
 | 
						|
  while (*src && *src != delim) {
 | 
						|
	if (*src != '-') setbit(esc(&src), map, 1);
 | 
						|
 | 
						|
	else if (src == start || *(src + 1) == delim)
 | 
						|
		setbit('-', map, 1);
 | 
						|
	else {
 | 
						|
		src++;
 | 
						|
 | 
						|
		if (*src < *(src - 2)) {
 | 
						|
			first = *src;
 | 
						|
			last = *(src - 2);
 | 
						|
		} else {
 | 
						|
			first = *(src - 2);
 | 
						|
			last = *src;
 | 
						|
		}
 | 
						|
 | 
						|
		while (++first <= last) setbit(first, map, 1);
 | 
						|
 | 
						|
	}
 | 
						|
	src++;
 | 
						|
  }
 | 
						|
  return(src);
 | 
						|
}
 | 
						|
 | 
						|
/*	doglob.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
/* #include "ed.h" */
 | 
						|
 | 
						|
int doglob()
 | 
						|
{
 | 
						|
  int lin, stat;
 | 
						|
  char *cmd;
 | 
						|
  LINE *ptr;
 | 
						|
 | 
						|
  cmd = inptr;
 | 
						|
 | 
						|
  while (1) {
 | 
						|
	ptr = getptr(1);
 | 
						|
	for (lin = 1; lin <= lastln; lin++) {
 | 
						|
		if (ptr->l_stat & LGLOB) break;
 | 
						|
		ptr = ptr->l_next;
 | 
						|
	}
 | 
						|
	if (lin > lastln) break;
 | 
						|
 | 
						|
	ptr->l_stat &= ~LGLOB;
 | 
						|
	curln = lin;
 | 
						|
	inptr = cmd;
 | 
						|
	if ((stat = getlst()) < 0) return(stat);
 | 
						|
	if ((stat = docmd(1)) < 0) return (stat);
 | 
						|
  }
 | 
						|
  return(curln);
 | 
						|
}
 | 
						|
 | 
						|
/*	doprnt.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
/* #include "ed.h" */
 | 
						|
 | 
						|
int doprnt(from, to)
 | 
						|
int from, to;
 | 
						|
{
 | 
						|
  int i;
 | 
						|
  LINE *lptr;
 | 
						|
 | 
						|
  from = from < 1 ? 1 : from;
 | 
						|
  to = to > lastln ? lastln : to;
 | 
						|
 | 
						|
  if (to != 0) {
 | 
						|
	lptr = getptr(from);
 | 
						|
	for (i = from; i <= to; i++) {
 | 
						|
		prntln(lptr->l_buff, lflg, (nflg ? i : 0));
 | 
						|
		lptr = lptr->l_next;
 | 
						|
	}
 | 
						|
	curln = to;
 | 
						|
  }
 | 
						|
  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) putc('$', stdout);
 | 
						|
  putc('\n', stdout);
 | 
						|
}
 | 
						|
 | 
						|
void putcntl(c, stream)
 | 
						|
char c;
 | 
						|
FILE *stream;
 | 
						|
{
 | 
						|
  putc('^', stream);
 | 
						|
  putc((c & 31) | '@', stream);
 | 
						|
}
 | 
						|
 | 
						|
/*	doread.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
/* #include "ed.h" */
 | 
						|
 | 
						|
extern int diag;
 | 
						|
 | 
						|
int doread(lin, fname)
 | 
						|
int lin;
 | 
						|
char *fname;
 | 
						|
{
 | 
						|
  FILE *fp;
 | 
						|
  int err;
 | 
						|
  long bytes;
 | 
						|
  int lines;
 | 
						|
  static char str[MAXLINE];
 | 
						|
 | 
						|
  err = 0;
 | 
						|
  nonascii = nullchar = truncated = 0;
 | 
						|
 | 
						|
  if (diag) printf("\"%s\" ", fname);
 | 
						|
  if ((fp = fopen(fname, "r")) == NULL) {
 | 
						|
	printf("file open err\n");
 | 
						|
	return(ERR);
 | 
						|
  }
 | 
						|
  curln = lin;
 | 
						|
  for (lines = 0, bytes = 0; (err = egets(str, MAXLINE, fp)) > 0;) {
 | 
						|
	bytes += strlen(str);
 | 
						|
	if (ins(str) < 0) {
 | 
						|
		printf("file insert error\n");
 | 
						|
		err++;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
	lines++;
 | 
						|
  }
 | 
						|
  fclose(fp);
 | 
						|
  if (err < 0) return(err);
 | 
						|
  if (diag) {
 | 
						|
	printf("%d lines %ld bytes", lines, bytes);
 | 
						|
	if (nonascii) printf(" [%d non-ascii]", nonascii);
 | 
						|
	if (nullchar) printf(" [%d nul]", nullchar);
 | 
						|
	if (truncated) printf(" [%d lines truncated]", truncated);
 | 
						|
	printf("\n");
 | 
						|
  }
 | 
						|
  return(err);
 | 
						|
}
 | 
						|
 | 
						|
/*	dowrite.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
/* #include "ed.h" */
 | 
						|
 | 
						|
int dowrite(from, to, fname, apflg)
 | 
						|
int from, to;
 | 
						|
char *fname;
 | 
						|
int apflg;
 | 
						|
{
 | 
						|
  FILE *fp;
 | 
						|
  int lin, err;
 | 
						|
  int lines;
 | 
						|
  long bytes;
 | 
						|
  char *str;
 | 
						|
  LINE *lptr;
 | 
						|
 | 
						|
  err = 0;
 | 
						|
 | 
						|
  lines = bytes = 0;
 | 
						|
  if (diag) printf("\"%s\" ", fname);
 | 
						|
  if ((fp = fopen(fname, (apflg ? "a" : "w"))) == NULL) {
 | 
						|
	printf("file open error\n");
 | 
						|
	return(ERR);
 | 
						|
  }
 | 
						|
  lptr = getptr(from);
 | 
						|
  for (lin = from; lin <= to; lin++) {
 | 
						|
	str = lptr->l_buff;
 | 
						|
	lines++;
 | 
						|
	bytes += strlen(str) + 1;
 | 
						|
	if (fputs(str, fp) == EOF) {
 | 
						|
		printf("file write error\n");
 | 
						|
		err++;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
	fputc('\n', fp);
 | 
						|
	lptr = lptr->l_next;
 | 
						|
  }
 | 
						|
  if (diag) printf("%d lines %ld bytes\n", lines, bytes);
 | 
						|
  fclose(fp);
 | 
						|
  return(err);
 | 
						|
}
 | 
						|
 | 
						|
/*	ed.c	*/
 | 
						|
/* Copyright 1987 Brian Beattie Rights Reserved.
 | 
						|
 *
 | 
						|
 * Permission to copy and/or distribute granted under the
 | 
						|
 * following conditions:
 | 
						|
 *
 | 
						|
 * 1). No charge may be made other than resonable charges
 | 
						|
 *	for reproduction.
 | 
						|
 *
 | 
						|
 * 2). This notice must remain intact.
 | 
						|
 *
 | 
						|
 * 3). No further restrictions may be added.
 | 
						|
 *
 | 
						|
 */
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include <signal.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
/* #include "ed.h" */
 | 
						|
#include <setjmp.h>
 | 
						|
jmp_buf env;
 | 
						|
 | 
						|
LINE line0;
 | 
						|
int curln = 0;
 | 
						|
int lastln = 0;
 | 
						|
char *inptr;
 | 
						|
static char inlin[MAXLINE];
 | 
						|
int nflg, lflg;
 | 
						|
int line1, line2, nlines;
 | 
						|
extern char fname[];
 | 
						|
int version = 1;
 | 
						|
int diag = 1;
 | 
						|
 | 
						|
void intr(sig)
 | 
						|
int sig;
 | 
						|
{
 | 
						|
  printf("?\n");
 | 
						|
  longjmp(env, 1);
 | 
						|
}
 | 
						|
 | 
						|
int main(argc, argv)
 | 
						|
int argc;
 | 
						|
char **argv;
 | 
						|
{
 | 
						|
  int stat, i, doflush;
 | 
						|
 | 
						|
  set_buf();
 | 
						|
  doflush = isatty(1);
 | 
						|
 | 
						|
  if (argc > 1 && (strcmp(argv[1], "-") == 0 || strcmp(argv[1], "-s") == 0)) {
 | 
						|
	diag = 0;
 | 
						|
	argc--;
 | 
						|
	argv++;
 | 
						|
  }
 | 
						|
  if (argc > 1) {
 | 
						|
	for (i = 1; i < argc; i++) {
 | 
						|
		if (doread(0, argv[i]) == 0) {
 | 
						|
			curln = 1;
 | 
						|
			strcpy(fname, argv[i]);
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
  }
 | 
						|
  while (1) {
 | 
						|
	setjmp(env);
 | 
						|
	if (signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, intr);
 | 
						|
 | 
						|
	if (doflush) fflush(stdout);
 | 
						|
 | 
						|
	if (fgets(inlin, sizeof(inlin), stdin) == NULL) {
 | 
						|
		break;
 | 
						|
	}
 | 
						|
	for (;;) {
 | 
						|
		inptr = strchr(inlin, EOS);
 | 
						|
		if (inptr >= inlin+2 && inptr[-2] == '\\' && inptr[-1] == NL) {
 | 
						|
			inptr[-1] = 'n';
 | 
						|
			if (fgets(inptr, sizeof(inlin) - (inptr - inlin),
 | 
						|
						stdin) == NULL) break;
 | 
						|
		} else {
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (*inlin == '!') {
 | 
						|
		if ((inptr = strchr(inlin, NL)) != NULL) *inptr = EOS;
 | 
						|
		System(inlin + 1);
 | 
						|
		continue;
 | 
						|
	}
 | 
						|
	inptr = inlin;
 | 
						|
	if (getlst() >= 0)
 | 
						|
		if ((stat = ckglob()) != 0) {
 | 
						|
			if (stat >= 0 && (stat = doglob()) >= 0) {
 | 
						|
				curln = stat;
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			if ((stat = docmd(0)) >= 0) {
 | 
						|
				if (stat == 1) doprnt(curln, curln);
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	if (stat == EOF) {
 | 
						|
		exit(0);
 | 
						|
	}
 | 
						|
	if (stat == FATAL) {
 | 
						|
		fputs("FATAL ERROR\n", stderr);
 | 
						|
		exit(1);
 | 
						|
	}
 | 
						|
	printf("?\n");
 | 
						|
  }
 | 
						|
  return(0);
 | 
						|
}
 | 
						|
 | 
						|
/*	egets.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
/* #include "ed.h" */
 | 
						|
 | 
						|
int eightbit = 1;		/* save eight bit */
 | 
						|
int nonascii, nullchar, truncated;
 | 
						|
int 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++ = '\n';
 | 
						|
		*cp = EOS;
 | 
						|
		if (count) {
 | 
						|
			printf("[Incomplete last line]\n");
 | 
						|
		}
 | 
						|
		return(count);
 | 
						|
	}
 | 
						|
	if (c == NL) {
 | 
						|
		*cp++ = c;
 | 
						|
		*cp = EOS;
 | 
						|
		return(++count);
 | 
						|
	}
 | 
						|
	if (c > 127) {
 | 
						|
		if (!eightbit)	/* if not saving eighth bit */
 | 
						|
			c = c & 127;	/* strip eigth bit */
 | 
						|
		nonascii++;	/* count it */
 | 
						|
	}
 | 
						|
	if (c) {
 | 
						|
		*cp++ = c;	/* not null, keep it */
 | 
						|
		count++;
 | 
						|
	} else
 | 
						|
		nullchar++;	/* count nulls */
 | 
						|
  }
 | 
						|
  str[count - 1] = EOS;
 | 
						|
  if (c != NL) {
 | 
						|
	printf("truncating line\n");
 | 
						|
	truncated++;
 | 
						|
	while ((c = getc(stream)) != EOF)
 | 
						|
		if (c == NL) break;
 | 
						|
  }
 | 
						|
  return(count);
 | 
						|
}
 | 
						|
 | 
						|
/*	esc.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
 | 
						|
/* 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.
 | 
						|
 */
 | 
						|
int 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);
 | 
						|
}
 | 
						|
 | 
						|
/*	find.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
/* #include "ed.h" */
 | 
						|
 | 
						|
int find(pat, dir)
 | 
						|
TOKEN *pat;
 | 
						|
int dir;
 | 
						|
{
 | 
						|
  int i, num;
 | 
						|
  char lin[MAXLINE];
 | 
						|
  LINE *ptr;
 | 
						|
 | 
						|
  num = curln;
 | 
						|
  ptr = getptr(curln);
 | 
						|
  num = (dir ? nextln(num) : prevln(num));
 | 
						|
  ptr = (dir ? ptr->l_next : ptr->l_prev);
 | 
						|
  for (i = 0; i < lastln; i++) {
 | 
						|
	if (num == 0) {
 | 
						|
		num = (dir ? nextln(num) : prevln(num));
 | 
						|
		ptr = (dir ? ptr->l_next : ptr->l_prev);
 | 
						|
	}
 | 
						|
	strcpy(lin, ptr->l_buff);
 | 
						|
	strcat(lin, "\n");
 | 
						|
	if (matchs(lin, pat, 0)) {
 | 
						|
		return(num);
 | 
						|
	}
 | 
						|
	num = (dir ? nextln(num) : prevln(num));
 | 
						|
	ptr = (dir ? ptr->l_next : ptr->l_prev);
 | 
						|
  }
 | 
						|
  return(ERR);
 | 
						|
}
 | 
						|
 | 
						|
/*	getfn.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
/* #include "ed.h" */
 | 
						|
 | 
						|
extern char fname[MAXFNAME];
 | 
						|
int nofname;
 | 
						|
 | 
						|
char *getfn()
 | 
						|
{
 | 
						|
  static char file[256];
 | 
						|
  char *cp;
 | 
						|
 | 
						|
  if (*inptr == NL) {
 | 
						|
	nofname = TRUE;
 | 
						|
	strcpy(file, fname);
 | 
						|
  } else {
 | 
						|
	nofname = FALSE;
 | 
						|
	while (*inptr == SP || *inptr == HT) inptr++;
 | 
						|
 | 
						|
	cp = file;
 | 
						|
	while (*inptr && *inptr != NL && *inptr != SP && *inptr != HT) {
 | 
						|
		*cp++ = *inptr++;
 | 
						|
	}
 | 
						|
	*cp = '\0';
 | 
						|
 | 
						|
	if (strlen(file) == 0) {
 | 
						|
		printf("bad file name\n");
 | 
						|
		return(NULL);
 | 
						|
	}
 | 
						|
  }
 | 
						|
 | 
						|
  if (strlen(file) == 0) {
 | 
						|
	printf("no file name\n");
 | 
						|
	return(NULL);
 | 
						|
  }
 | 
						|
  return(file);
 | 
						|
}
 | 
						|
 | 
						|
/*	getlst.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
/* #include "ed.h" */
 | 
						|
 | 
						|
int getlst()
 | 
						|
{
 | 
						|
  int num;
 | 
						|
 | 
						|
  line2 = 0;
 | 
						|
  for (nlines = 0; (num = getone()) >= 0;) {
 | 
						|
	line1 = line2;
 | 
						|
	line2 = num;
 | 
						|
	nlines++;
 | 
						|
	if (*inptr != ',' && *inptr != ';') break;
 | 
						|
	if (*inptr == ';') curln = num;
 | 
						|
	inptr++;
 | 
						|
  }
 | 
						|
  nlines = min(nlines, 2);
 | 
						|
  if (nlines == 0) line2 = curln;
 | 
						|
  if (nlines <= 1) line1 = line2;
 | 
						|
 | 
						|
  if (num == ERR)
 | 
						|
	return(num);
 | 
						|
  else
 | 
						|
	return(nlines);
 | 
						|
}
 | 
						|
 | 
						|
/*	getnum.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
/* #include "ed.h" */
 | 
						|
 | 
						|
int mark['z' - 'a' + 1];
 | 
						|
 | 
						|
int getnum(first)
 | 
						|
int first;
 | 
						|
{
 | 
						|
  TOKEN *srchpat;
 | 
						|
  int num;
 | 
						|
  char c;
 | 
						|
 | 
						|
  while (*inptr == SP || *inptr == HT) inptr++;
 | 
						|
 | 
						|
  if (*inptr >= '0' && *inptr <= '9') {	/* line number */
 | 
						|
	for (num = 0; *inptr >= '0' && *inptr <= '9';) {
 | 
						|
		num = (num * 10) + *inptr - '0';
 | 
						|
		inptr++;
 | 
						|
	}
 | 
						|
	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 */
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/*	getone.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
/* #include "ed.h" */
 | 
						|
 | 
						|
#define FIRST 1
 | 
						|
#define NOTFIRST 0
 | 
						|
 | 
						|
int getone()
 | 
						|
{
 | 
						|
  int c, i, num;
 | 
						|
 | 
						|
  if ((num = getnum(FIRST)) >= 0) {
 | 
						|
	while (1) {
 | 
						|
		while (*inptr == SP || *inptr == HT) inptr++;
 | 
						|
 | 
						|
		if (*inptr != '+' && *inptr != '-') break;
 | 
						|
		c = *inptr++;
 | 
						|
 | 
						|
		if ((i = getnum(NOTFIRST)) < 0) return(i);
 | 
						|
 | 
						|
		if (c == '+') {
 | 
						|
			num += i;
 | 
						|
		} else {
 | 
						|
			num -= i;
 | 
						|
		}
 | 
						|
	}
 | 
						|
  }
 | 
						|
  return(num > lastln ? ERR : num);
 | 
						|
}
 | 
						|
 | 
						|
/*	getpat.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
 | 
						|
/* Translate arg into a TOKEN string */
 | 
						|
TOKEN *
 | 
						|
 getpat(arg)
 | 
						|
char *arg;
 | 
						|
{
 | 
						|
 | 
						|
  return(makepat(arg, '\000'));
 | 
						|
}
 | 
						|
 | 
						|
/*	getptr.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
/* #include "ed.h" */
 | 
						|
 | 
						|
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	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
/* #include "ed.h" */
 | 
						|
 | 
						|
int getrhs(sub)
 | 
						|
char *sub;
 | 
						|
{
 | 
						|
  if (inptr[0] == NL || inptr[1] == NL)	/* check for eol */
 | 
						|
	return(ERR);
 | 
						|
 | 
						|
  if (maksub(sub, MAXPAT) == NULL) return(ERR);
 | 
						|
 | 
						|
  inptr++;			/* skip over delimter */
 | 
						|
  while (*inptr == SP || *inptr == HT) inptr++;
 | 
						|
  if (*inptr == 'g') {
 | 
						|
	inptr++;
 | 
						|
	return(1);
 | 
						|
  }
 | 
						|
  return(0);
 | 
						|
}
 | 
						|
 | 
						|
/*	gettxt.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
/* #include "ed.h" */
 | 
						|
 | 
						|
char *
 | 
						|
 gettxt(num)
 | 
						|
int num;
 | 
						|
{
 | 
						|
  LINE *lin;
 | 
						|
  static char txtbuf[MAXLINE];
 | 
						|
 | 
						|
  lin = getptr(num);
 | 
						|
  strcpy(txtbuf, lin->l_buff);
 | 
						|
  strcat(txtbuf, "\n");
 | 
						|
  return(txtbuf);
 | 
						|
}
 | 
						|
 | 
						|
/*	ins.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
/* #include "ed.h" */
 | 
						|
 | 
						|
int ins(str)
 | 
						|
char *str;
 | 
						|
{
 | 
						|
  char buf[MAXLINE], *cp;
 | 
						|
  LINE *new, *cur, *nxt;
 | 
						|
 | 
						|
  cp = buf;
 | 
						|
  while (1) {
 | 
						|
	if ((*cp = *str++) == NL) *cp = EOS;
 | 
						|
	if (*cp) {
 | 
						|
		cp++;
 | 
						|
		continue;
 | 
						|
	}
 | 
						|
	if ((new = (LINE *) malloc(sizeof(LINE) + strlen(buf))) == NULL)
 | 
						|
		return(ERR);	/* no memory */
 | 
						|
 | 
						|
	new->l_stat = 0;
 | 
						|
	strcpy(new->l_buff, buf);	/* build new line */
 | 
						|
	cur = getptr(curln);	/* get current line */
 | 
						|
	nxt = cur->l_next;	/* get next line */
 | 
						|
	relink(cur, new, new, nxt);	/* add to linked list */
 | 
						|
	relink(new, nxt, cur, new);
 | 
						|
	lastln++;
 | 
						|
	curln++;
 | 
						|
 | 
						|
	if (*str == EOS)	/* end of line ? */
 | 
						|
		return(1);
 | 
						|
 | 
						|
	cp = buf;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/*	join.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
/* #include "ed.h" */
 | 
						|
 | 
						|
extern int fchanged;
 | 
						|
 | 
						|
int join(first, last)
 | 
						|
int first, last;
 | 
						|
{
 | 
						|
  char buf[MAXLINE];
 | 
						|
  char *cp = buf, *str;
 | 
						|
  int num;
 | 
						|
 | 
						|
  if (first <= 0 || first > last || last > lastln) return(ERR);
 | 
						|
  if (first == last) {
 | 
						|
	curln = first;
 | 
						|
	return 0;
 | 
						|
  }
 | 
						|
  for (num = first; num <= last; num++) {
 | 
						|
	str = gettxt(num);
 | 
						|
 | 
						|
	while (*str != NL && cp < buf + MAXLINE - 1) *cp++ = *str++;
 | 
						|
 | 
						|
	if (cp == buf + MAXLINE - 1) {
 | 
						|
		printf("line too long\n");
 | 
						|
		return(ERR);
 | 
						|
	}
 | 
						|
  }
 | 
						|
  *cp++ = NL;
 | 
						|
  *cp = EOS;
 | 
						|
  del(first, last);
 | 
						|
  curln = first - 1;
 | 
						|
  ins(buf);
 | 
						|
  fchanged = TRUE;
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
/*	makepat.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
 | 
						|
/* Make a pattern template from the strinng pointed to by arg.  Stop
 | 
						|
 * when delim or '\000' or '\n' is found in arg.  Return a pointer to
 | 
						|
 * the pattern template.
 | 
						|
 *
 | 
						|
 * The pattern template used here are somewhat different than those
 | 
						|
 * used in the "Software Tools" book; each token is a structure of
 | 
						|
 * the form TOKEN (see tools.h).  A token consists of an identifier,
 | 
						|
 * a pointer to a string, a literal character and a pointer to another
 | 
						|
 * token.  This last is 0 if there is no subsequent token.
 | 
						|
 *
 | 
						|
 * The one strangeness here is caused (again) by CLOSURE which has
 | 
						|
 * to be put in front of the previous token.  To make this insertion a
 | 
						|
 * little easier, the 'next' field of the last to point at the chain
 | 
						|
 * (the one pointed to by 'tail) is made to point at the previous node.
 | 
						|
 * When we are finished, tail->next is set to 0.
 | 
						|
 */
 | 
						|
TOKEN *
 | 
						|
 makepat(arg, delim)
 | 
						|
char *arg;
 | 
						|
int delim;
 | 
						|
{
 | 
						|
  TOKEN *head, *tail, *ntok;
 | 
						|
  int error;
 | 
						|
 | 
						|
  /* Check for characters that aren't legal at the beginning of a template. */
 | 
						|
 | 
						|
  if (*arg == '\0' || *arg == delim || *arg == '\n' || *arg == CLOSURE)
 | 
						|
	return(0);
 | 
						|
 | 
						|
  error = 0;
 | 
						|
  tail = head = NULL;
 | 
						|
 | 
						|
  while (*arg && *arg != delim && *arg != '\n' && !error) {
 | 
						|
	ntok = (TOKEN *) malloc(TOKSIZE);
 | 
						|
	ntok->lchar = '\000';
 | 
						|
	ntok->next = 0;
 | 
						|
 | 
						|
	switch (*arg) {
 | 
						|
	    case ANY:	ntok->tok = ANY;	break;
 | 
						|
 | 
						|
	    case BOL:
 | 
						|
		if (head == 0)	/* then this is the first symbol */
 | 
						|
			ntok->tok = BOL;
 | 
						|
		else
 | 
						|
			ntok->tok = LITCHAR;
 | 
						|
		ntok->lchar = BOL;
 | 
						|
		break;
 | 
						|
 | 
						|
	    case EOL:
 | 
						|
		if (*(arg + 1) == delim || *(arg + 1) == '\000' ||
 | 
						|
		    *(arg + 1) == '\n') {
 | 
						|
			ntok->tok = EOL;
 | 
						|
		} else {
 | 
						|
			ntok->tok = LITCHAR;
 | 
						|
			ntok->lchar = EOL;
 | 
						|
		}
 | 
						|
		break;
 | 
						|
 | 
						|
	    case CLOSURE:
 | 
						|
		if (head != 0) {
 | 
						|
			switch (tail->tok) {
 | 
						|
			    case BOL:
 | 
						|
			    case EOL:
 | 
						|
			    case CLOSURE:
 | 
						|
				return(0);
 | 
						|
 | 
						|
			    default:
 | 
						|
				ntok->tok = CLOSURE;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		break;
 | 
						|
 | 
						|
	    case CCL:
 | 
						|
 | 
						|
		if (*(arg + 1) == NEGATE) {
 | 
						|
			ntok->tok = NCCL;
 | 
						|
			arg += 2;
 | 
						|
		} else {
 | 
						|
			ntok->tok = CCL;
 | 
						|
			arg++;
 | 
						|
		}
 | 
						|
 | 
						|
		if (ntok->bitmap = makebitmap(CLS_SIZE))
 | 
						|
			arg = dodash(CCLEND, arg, ntok->bitmap);
 | 
						|
		else {
 | 
						|
			fprintf(stderr, "Not enough memory for pat\n");
 | 
						|
			error = 1;
 | 
						|
		}
 | 
						|
		break;
 | 
						|
 | 
						|
	    default:
 | 
						|
		if (*arg == ESCAPE && *(arg + 1) == OPEN) {
 | 
						|
			ntok->tok = OPEN;
 | 
						|
			arg++;
 | 
						|
		} else if (*arg == ESCAPE && *(arg + 1) == CLOSE) {
 | 
						|
			ntok->tok = CLOSE;
 | 
						|
			arg++;
 | 
						|
		} else {
 | 
						|
			ntok->tok = LITCHAR;
 | 
						|
			ntok->lchar = esc(&arg);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (error || ntok == 0) {
 | 
						|
		unmakepat(head);
 | 
						|
		return(0);
 | 
						|
	} else if (head == 0) {
 | 
						|
		/* This is the first node in the chain. */
 | 
						|
 | 
						|
		ntok->next = 0;
 | 
						|
		head = tail = ntok;
 | 
						|
	} else if (ntok->tok != CLOSURE) {
 | 
						|
		/* Insert at end of list (after tail) */
 | 
						|
 | 
						|
		tail->next = ntok;
 | 
						|
		ntok->next = tail;
 | 
						|
		tail = ntok;
 | 
						|
	} else if (head != tail) {
 | 
						|
		/* More than one node in the chain.  Insert the
 | 
						|
		 * CLOSURE node immediately in front of tail. */
 | 
						|
 | 
						|
		(tail->next)->next = ntok;
 | 
						|
		ntok->next = tail;
 | 
						|
	} else {
 | 
						|
		/* Only one node in the chain,  Insert the CLOSURE
 | 
						|
		 * node at the head of the linked list. */
 | 
						|
 | 
						|
		ntok->next = head;
 | 
						|
		tail->next = ntok;
 | 
						|
		head = ntok;
 | 
						|
	}
 | 
						|
	arg++;
 | 
						|
  }
 | 
						|
 | 
						|
  tail->next = 0;
 | 
						|
  return(head);
 | 
						|
}
 | 
						|
 | 
						|
/*	maksub.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
/* #include "ed.h" */
 | 
						|
 | 
						|
char *
 | 
						|
 maksub(sub, subsz)
 | 
						|
char *sub;
 | 
						|
int subsz;
 | 
						|
{
 | 
						|
  int size;
 | 
						|
  char delim, *cp;
 | 
						|
 | 
						|
  size = 0;
 | 
						|
  cp = sub;
 | 
						|
 | 
						|
  delim = *inptr++;
 | 
						|
  for (size = 0; *inptr != delim && *inptr != NL && size < subsz; size++) {
 | 
						|
	if (*inptr == '&') {
 | 
						|
		*cp++ = DITTO;
 | 
						|
		inptr++;
 | 
						|
	} else if ((*cp++ = *inptr++) == ESCAPE) {
 | 
						|
		if (size >= subsz) return(NULL);
 | 
						|
 | 
						|
		switch (toupper(*inptr)) {
 | 
						|
		    case NL:	*cp++ = ESCAPE;		break;
 | 
						|
			break;
 | 
						|
		    case 'S':
 | 
						|
			*cp++ = SP;
 | 
						|
			inptr++;
 | 
						|
			break;
 | 
						|
		    case 'N':
 | 
						|
			*cp++ = NL;
 | 
						|
			inptr++;
 | 
						|
			break;
 | 
						|
		    case 'T':
 | 
						|
			*cp++ = HT;
 | 
						|
			inptr++;
 | 
						|
			break;
 | 
						|
		    case 'B':
 | 
						|
			*cp++ = BS;
 | 
						|
			inptr++;
 | 
						|
			break;
 | 
						|
		    case 'R':
 | 
						|
			*cp++ = CR;
 | 
						|
			inptr++;
 | 
						|
			break;
 | 
						|
		    case '0':{
 | 
						|
				int i = 3;
 | 
						|
				*cp = 0;
 | 
						|
				do {
 | 
						|
					if (*++inptr < '0' || *inptr > '7')
 | 
						|
						break;
 | 
						|
 | 
						|
					*cp = (*cp << 3) | (*inptr - '0');
 | 
						|
				} while (--i != 0);
 | 
						|
				cp++;
 | 
						|
			} break;
 | 
						|
		    default:	*cp++ = *inptr++;	break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
  }
 | 
						|
  if (size >= subsz) return(NULL);
 | 
						|
 | 
						|
  *cp = EOS;
 | 
						|
  return(sub);
 | 
						|
}
 | 
						|
 | 
						|
/*	matchs.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
 | 
						|
/* Compares line and pattern.  Line is a character string while pat
 | 
						|
 * is a pattern template made by getpat().
 | 
						|
 * Returns:
 | 
						|
 *	1. A zero if no match was found.
 | 
						|
 *
 | 
						|
 *	2. A pointer to the last character satisfing the match
 | 
						|
 *	   if ret_endp is non-zero.
 | 
						|
 *
 | 
						|
 *	3. A pointer to the beginning of the matched string if
 | 
						|
 *	   ret_endp is zero.
 | 
						|
 *
 | 
						|
 * e.g.:
 | 
						|
 *
 | 
						|
 *	matchs ("1234567890", getpat("4[0-9]*7), 0);
 | 
						|
 * will return a pointer to the '4', while:
 | 
						|
 *
 | 
						|
 *	matchs ("1234567890", getpat("4[0-9]*7), 1);
 | 
						|
 * will return a pointer to the '7'.
 | 
						|
 */
 | 
						|
char *
 | 
						|
 matchs(line, pat, ret_endp)
 | 
						|
char *line;
 | 
						|
TOKEN *pat;
 | 
						|
int ret_endp;
 | 
						|
{
 | 
						|
 | 
						|
  char *rval, *bptr;
 | 
						|
  char *line2;
 | 
						|
  TOKEN *pat2;
 | 
						|
  char c;
 | 
						|
  short ok;
 | 
						|
 | 
						|
  bptr = line;
 | 
						|
 | 
						|
  while (*line) {
 | 
						|
 | 
						|
	if (pat && pat->tok == LITCHAR) {
 | 
						|
		while (*line) {
 | 
						|
			pat2 = pat;
 | 
						|
			line2 = line;
 | 
						|
			if (*line2 != pat2->lchar) {
 | 
						|
				c = pat2->lchar;
 | 
						|
				while (*line2 && *line2 != c) ++line2;
 | 
						|
				line = line2;
 | 
						|
				if (*line2 == '\0') break;
 | 
						|
			}
 | 
						|
			ok = 1;
 | 
						|
			++line2;
 | 
						|
			pat2 = pat2->next;
 | 
						|
			while (pat2 && pat2->tok == LITCHAR) {
 | 
						|
				if (*line2 != pat2->lchar) {
 | 
						|
					ok = 0;
 | 
						|
					break;
 | 
						|
				}
 | 
						|
				++line2;
 | 
						|
				pat2 = pat2->next;
 | 
						|
			}
 | 
						|
			if (!pat2) {
 | 
						|
				if (ret_endp)
 | 
						|
					return(--line2);
 | 
						|
				else
 | 
						|
					return(line);
 | 
						|
			} else if (ok)
 | 
						|
				break;
 | 
						|
			++line;
 | 
						|
		}
 | 
						|
		if (*line == '\0') return(0);
 | 
						|
	} else {
 | 
						|
		line2 = line;
 | 
						|
		pat2 = pat;
 | 
						|
	}
 | 
						|
	if ((rval = amatch(line2, pat2, bptr)) == 0) {
 | 
						|
		if (pat && pat->tok == BOL) break;
 | 
						|
		line++;
 | 
						|
	} else {
 | 
						|
		if (rval > bptr && rval > line)
 | 
						|
			rval--;	/* point to last char matched */
 | 
						|
		rval = ret_endp ? rval : line;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
  }
 | 
						|
  return(rval);
 | 
						|
}
 | 
						|
 | 
						|
/*	move.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
/* #include "ed.h" */
 | 
						|
 | 
						|
int move(num)
 | 
						|
int num;
 | 
						|
{
 | 
						|
  LINE *k0, *k1, *k2, *k3;
 | 
						|
 | 
						|
  if (line1 <= 0 || line2 < line1 || (line1 <= num && num <= line2))
 | 
						|
	return(ERR);
 | 
						|
  k0 = getptr(prevln(line1));
 | 
						|
  k1 = getptr(line1);
 | 
						|
  k2 = getptr(line2);
 | 
						|
  k3 = getptr(nextln(line2));
 | 
						|
 | 
						|
  relink(k0, k3, k0, k3);
 | 
						|
  lastln -= line2 - line1 + 1;
 | 
						|
 | 
						|
  if (num > line1) num -= line2 - line1 + 1;
 | 
						|
 | 
						|
  curln = num + (line2 - line1 + 1);
 | 
						|
 | 
						|
  k0 = getptr(num);
 | 
						|
  k3 = getptr(nextln(num));
 | 
						|
 | 
						|
  relink(k0, k1, k2, k3);
 | 
						|
  relink(k2, k3, k0, k1);
 | 
						|
  lastln += line2 - line1 + 1;
 | 
						|
 | 
						|
  return(1);
 | 
						|
}
 | 
						|
 | 
						|
int transfer(num)
 | 
						|
int num;
 | 
						|
{
 | 
						|
  int mid, lin, ntrans;
 | 
						|
 | 
						|
  if (line1 <= 0 || line1 > line2) return(ERR);
 | 
						|
 | 
						|
  mid = num < line2 ? num : line2;
 | 
						|
 | 
						|
  curln = num;
 | 
						|
  ntrans = 0;
 | 
						|
 | 
						|
  for (lin = line1; lin <= mid; lin++) {
 | 
						|
	ins(gettxt(lin));
 | 
						|
	ntrans++;
 | 
						|
  }
 | 
						|
  lin += ntrans;
 | 
						|
  line2 += ntrans;
 | 
						|
 | 
						|
  for (; lin <= line2; lin += 2) {
 | 
						|
	ins(gettxt(lin));
 | 
						|
	line2++;
 | 
						|
  }
 | 
						|
  return(1);
 | 
						|
}
 | 
						|
 | 
						|
/*	omatch.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
 | 
						|
/* Match one pattern element, pointed at by pat, with the character at
 | 
						|
 * **linp.  Return non-zero on match.  Otherwise, return 0.  *Linp is
 | 
						|
 * advanced to skip over the matched character; it is not advanced on
 | 
						|
 * failure.  The amount of advance is 0 for patterns that match null
 | 
						|
 * strings, 1 otherwise.  "boln" should point at the position that will
 | 
						|
 * match a BOL token.
 | 
						|
 */
 | 
						|
int omatch(linp, pat, boln)
 | 
						|
char **linp;
 | 
						|
TOKEN *pat;
 | 
						|
char *boln;
 | 
						|
{
 | 
						|
 | 
						|
  register int advance;
 | 
						|
 | 
						|
  advance = -1;
 | 
						|
 | 
						|
  if (**linp) {
 | 
						|
	switch (pat->tok) {
 | 
						|
	    case LITCHAR:
 | 
						|
		if (**linp == pat->lchar) advance = 1;
 | 
						|
		break;
 | 
						|
 | 
						|
	    case BOL:
 | 
						|
		if (*linp == boln) advance = 0;
 | 
						|
		break;
 | 
						|
 | 
						|
	    case ANY:
 | 
						|
		if (**linp != '\n') advance = 1;
 | 
						|
		break;
 | 
						|
 | 
						|
	    case EOL:
 | 
						|
		if (**linp == '\n') advance = 0;
 | 
						|
		break;
 | 
						|
 | 
						|
	    case CCL:
 | 
						|
		if (testbit(**linp, pat->bitmap)) advance = 1;
 | 
						|
		break;
 | 
						|
 | 
						|
	    case NCCL:
 | 
						|
		if (!testbit(**linp, pat->bitmap)) advance = 1;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
  }
 | 
						|
  if (advance >= 0) *linp += advance;
 | 
						|
 | 
						|
  return(++advance);
 | 
						|
}
 | 
						|
 | 
						|
/*	optpat.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
/* #include "ed.h" */
 | 
						|
 | 
						|
TOKEN *oldpat;
 | 
						|
 | 
						|
TOKEN *
 | 
						|
 optpat()
 | 
						|
{
 | 
						|
  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) unmakepat(oldpat);
 | 
						|
  oldpat = getpat(str);
 | 
						|
  return(oldpat);
 | 
						|
}
 | 
						|
 | 
						|
/*	set.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
/* #include "ed.h" */
 | 
						|
 | 
						|
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
 | 
						|
};
 | 
						|
 | 
						|
int set()
 | 
						|
{
 | 
						|
  char word[16];
 | 
						|
  int i;
 | 
						|
 | 
						|
  inptr++;
 | 
						|
  if (*inptr != 't') {
 | 
						|
	if (*inptr != SP && *inptr != HT && *inptr != NL) return(ERR);
 | 
						|
  } else
 | 
						|
	inptr++;
 | 
						|
 | 
						|
  if (*inptr == NL) return(show());
 | 
						|
  /* Skip white space */
 | 
						|
  while (*inptr == SP || *inptr == HT) inptr++;
 | 
						|
 | 
						|
  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(0);
 | 
						|
}
 | 
						|
 | 
						|
int show()
 | 
						|
{
 | 
						|
  extern int version;
 | 
						|
 | 
						|
  printf("ed version %d.%d\n", version / 100, version % 100);
 | 
						|
  printf("number %s, list %s\n", nflg ? "ON" : "OFF", lflg ? "ON" : "OFF");
 | 
						|
  return(0);
 | 
						|
}
 | 
						|
 | 
						|
/*	setbuf.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
/* #include "ed.h" */
 | 
						|
 | 
						|
void relink(a, x, y, b)
 | 
						|
LINE *a, *x, *y, *b;
 | 
						|
{
 | 
						|
  x->l_prev = a;
 | 
						|
  y->l_next = b;
 | 
						|
}
 | 
						|
 | 
						|
void clrbuf()
 | 
						|
{
 | 
						|
  del(1, lastln);
 | 
						|
}
 | 
						|
 | 
						|
void set_buf()
 | 
						|
{
 | 
						|
  relink(&line0, &line0, &line0, &line0);
 | 
						|
  curln = lastln = 0;
 | 
						|
}
 | 
						|
 | 
						|
/*	subst.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
/* #include "ed.h" */
 | 
						|
 | 
						|
int subst(pat, sub, gflg, pflag)
 | 
						|
TOKEN *pat;
 | 
						|
char *sub;
 | 
						|
int gflg, pflag;
 | 
						|
{
 | 
						|
  int lin, chngd, nchngd;
 | 
						|
  char *txtptr, *txt;
 | 
						|
  char *lastm, *m, *new, buf[MAXLINE];
 | 
						|
 | 
						|
  if (line1 <= 0) return(ERR);
 | 
						|
  nchngd = 0;			/* reset count of lines changed */
 | 
						|
  for (lin = line1; lin <= line2; lin++) {
 | 
						|
	txt = txtptr = gettxt(lin);
 | 
						|
	new = buf;
 | 
						|
	chngd = 0;
 | 
						|
	lastm = NULL;
 | 
						|
	while (*txtptr) {
 | 
						|
		if (gflg || !chngd)
 | 
						|
			m = amatch(txtptr, pat, txt);
 | 
						|
		else
 | 
						|
			m = NULL;
 | 
						|
		if (m != NULL && lastm != m) {
 | 
						|
			chngd++;
 | 
						|
			new = catsub(txtptr, m, sub, new,
 | 
						|
				     buf + MAXLINE);
 | 
						|
			lastm = m;
 | 
						|
		}
 | 
						|
		if (m == NULL || m == txtptr) {
 | 
						|
			*new++ = *txtptr++;
 | 
						|
		} else {
 | 
						|
			txtptr = m;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (chngd) {
 | 
						|
		if (new >= buf + MAXLINE) return(ERR);
 | 
						|
		*new++ = EOS;
 | 
						|
		del(lin, lin);
 | 
						|
		ins(buf);
 | 
						|
		nchngd++;
 | 
						|
		if (pflag) doprnt(curln, curln);
 | 
						|
	}
 | 
						|
  }
 | 
						|
  if (nchngd == 0 && !gflg) {
 | 
						|
	return(ERR);
 | 
						|
  }
 | 
						|
  return(nchngd);
 | 
						|
}
 | 
						|
 | 
						|
/*	System.c	*/
 | 
						|
#define SHELL	"/bin/sh"
 | 
						|
#define SHELL2	"/usr/bin/sh"
 | 
						|
 | 
						|
int System(c)
 | 
						|
char *c;
 | 
						|
{
 | 
						|
  int pid, status;
 | 
						|
 | 
						|
  switch (pid = fork()) {
 | 
						|
      case -1:
 | 
						|
	return -1;
 | 
						|
      case 0:
 | 
						|
	execl(SHELL, "sh", "-c", c, (char *) 0);
 | 
						|
	execl(SHELL2, "sh", "-c", c, (char *) 0);
 | 
						|
	exit(-1);
 | 
						|
      default:	while (wait(&status) != pid);
 | 
						|
}
 | 
						|
  return status;
 | 
						|
}
 | 
						|
 | 
						|
/*	unmkpat.c	*/
 | 
						|
/* #include <stdio.h> */
 | 
						|
/* #include "tools.h" */
 | 
						|
 | 
						|
/* Free up the memory usde for token string */
 | 
						|
void unmakepat(head)
 | 
						|
TOKEN *head;
 | 
						|
{
 | 
						|
 | 
						|
  register TOKEN *old_head;
 | 
						|
 | 
						|
  while (head) {
 | 
						|
	switch (head->tok) {
 | 
						|
	    case CCL:
 | 
						|
	    case NCCL:
 | 
						|
		free(head->bitmap);
 | 
						|
		/* Fall through to default */
 | 
						|
 | 
						|
	    default:
 | 
						|
		old_head = head;
 | 
						|
		head = head->next;
 | 
						|
		free((char *) old_head);
 | 
						|
		break;
 | 
						|
	}
 | 
						|
  }
 | 
						|
}
 |