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;
 | |
| 	}
 | |
|   }
 | |
| }
 | 
