v08i002: Georgia Tech 'se' Screen Editor

sources-request at mirror.UUCP sources-request at mirror.UUCP
Tue Jan 27 07:16:45 AEST 1987


Submitted by: emoryu1!arnold (Arnold D. Robbins)
Mod.sources: Volume 8, Issue 2
Archive-name: se/Part02


Here is the second release of the Georgia Tech Screen Editor, 'se'.
There were enough changes that a whole new posting is warranted.

Major Changes:
	All Georgia Tech specific stuff removed.
	It understands window size changes on 4.3BSD and ATT Unix PC/3B1
	Support for the shared library on the ATT Unix PC/3B1
	Considerable source code reorganization in certain files.

Enjoy,

Arnold Robbins

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	edit.c
#	extern.h
#	m4munge
#	main.c
#	makefile
#	misc.c
export PATH; PATH=/bin:$PATH
echo shar: extracting "'edit.c'" '(26346 characters)'
if test -f 'edit.c'
then
	echo shar: will not over-write existing file "'edit.c'"
else
cat << \SHAR_EOF > 'edit.c'
#ifndef lint
static char RCSid[] = "$Header: edit.c,v 1.3 86/07/11 15:11:34 osadr Exp $";
#endif

/*
 * $Log:	edit.c,v $
 * Revision 1.3  86/07/11  15:11:34  osadr
 * Removed Georgia Tech specific code.
 * 
 * Revision 1.2  86/05/27  17:44:56  osadr
 * Removed flexnames dependancy; PREVLINE[2] --> PREVLN[2].
 * Improved the sysname() routine, particularly to use the nodename
 * member of the utsname structure under System V.
 * 
 * Revision 1.1  86/05/06  13:37:16  osadr
 * Initial revision
 * 
 * 
 */

/*
** edit.c
**
** editor main routine, plus other routines used a lot.
*/

#include "se.h"
#include "extern.h"

static char Savknm = DEFAULTNAME;	/* saved mark name for < and > */

/* edit --- main routine for screen editor */

edit (argc, argv)
int argc;
char *argv[];
{
	int cursav, status, len, cursor;
	int ckglob (), docmd (), doglob (), doread ();
	int getlst (), nextln (), prevln ();
	char lin[MAXLINE], term;

	watch ();       /* display time of day */

#ifdef LOG_USAGE
	log ();		/* log who used the program */
#endif

	serc ();	/* execute commands in ./.serc or $HOME/.serc */

	status = OK;

	while (status == OK && Argno < argc)
	{
		strcpy (lin, argv[Argno]);
		loadstr (lin, Argno, POOPCOL, Ncols);
		if (lin[0] == '-')
		{
			len = strlen (lin) + 1;
			lin[len - 1] = '\n';
			lin[len] = EOS;
			len = 0;
			status = doopt (lin, &len);
		}
		else
		{
			dfltsopt (lin);
			status = doread (Lastln, lin, NO);
		}
		Argno++;
	}

	if (status == ERR)
	{
		if (Errcode == EHANGUP)
			hangup ();
		printverboseerrormessage ();
	}
	else
		Curln = min (1, Lastln);

	Buffer_changed = NO;
	First_affected = 1;     /* maintained by updscreen & commands */
	updscreen ();

	if (status != ERR)	/* leave offending file name or option */
		lin[0] = EOS;
	cursor = 0;

	/* main command loop */
	do {
		intrpt ();	/* discard pending breaks (interrupts) */
		if (Lost_lines > GARB_THRESHOLD
		    && (Lastln + Limcnt) / Lost_lines <= GARB_FACTOR)
			garbage_collect ();

		mswait ();	/* check for pending messages */
		Cmdrow = Botrow + 1;    /* reset the command line location */
		prompt ("cmd>");
		getcmd (lin, 0, &cursor, &term);
		remark ("");	/* clear out any error messages */

		while (term == CURSOR_UP || term == CURSOR_DOWN
		    || term == CURSOR_SAME)
		{
			switch (term) {
			case CURSOR_UP:
				if (Curln > 1)
					Curln--;
				else
					Curln = Lastln;
				break;

			case CURSOR_DOWN:
				if (Curln < Lastln)
					Curln++;
				else
					Curln = min (1, Lastln);
				break;
			}
			adjust_window (Curln, Curln);
			updscreen ();
			getcmd (lin, 0, &cursor, &term);
		}

		prompt ("");	/* remove prompt */

		cursav = Curln;		/* remember it in case of an error */
		Errcode = EEGARB;	/* default error code for garbage at end */

		len = 0;
		if (getlst (lin, &len, &status) == OK)
		{
			if (ckglob (lin, &len, &status) == OK)
				doglob (lin, &len, &cursav, &status);
			else if (status != ERR)
				docmd (lin, len, NO, &status);
		}
		if (status == ERR)
		{
			if (Errcode == EHANGUP)
				hangup ();
			printverboseerrormessage ();
			Curln = min (cursav, Lastln);
		}
		else if (term != FUNNY)
		{
			cursor = 0;
			lin[0] = EOS;
		}

		adjust_window (Curln, Curln);
		updscreen ();

	} while (status != EOF);

	clrscreen ();
	clrbuf ();
	tflush ();

	return;
}


/* getlst --- collect line numbers (if any) at lin[*i], increment i */

int getlst (lin, i, status)
char lin[];
int *i, *status;
{
	int num;
	int getone ();

	Line2 = 0;
	for (Nlines = 0; getone (lin, i, &num, status) == OK; )
	{
		Line1 = Line2;
		Line2 = num;
		Nlines++;
		if (lin[*i] != ',' && lin[*i] != ';')
			break;
		if (lin[*i] == ';')
			Curln = num;
		(*i)++;
	}

	if (Nlines > 2)
		Nlines = 2;

	if (Nlines <= 1)
		Line1 = Line2;

	if (Line1 > Line2)
	{
		*status = ERR;
		Errcode = EBACKWARD;
	}

	if (*status != ERR)
		*status = OK;

	return (*status);
}


/* getnum --- convert one term to line number */

int getnum (lin, i, pnum, status)
char lin[];
register int *i, *pnum, *status;
{
	int j, ret;
	int ctoi (), optpat (), ptscan (), knscan (), getkn ();
	int k;

	ret = OK;
	SKIPBL (lin, *i);
	if (lin[*i] >= Rel_a && lin[*i] <= Rel_z && Absnos == NO)
		*pnum = Topln - Toprow + lin[*i] - Rel_a;
	else if (lin[*i] == CURLINE)
		*pnum = Curln;
	else if (lin[*i] == PREVLN || lin[*i] == PREVLN2)
		*pnum = Curln - 1;
	else if (lin[*i] == LASTLINE)
		*pnum = Lastln;
	else if (lin[*i] == SCAN || lin[*i] == BACKSCAN)
	{
		int missing_delim = YES;

		/* see if trailing delim supplied, since command can follow pattern */
		for (k = *i + 1; lin[k] != EOS; k++)
			if (lin[k] == ESCAPE)
				k++;	/* skip esc, loop will skip escaped char */
			else if (lin[k] == lin[*i])
			{
				missing_delim = NO;
				break;
			}
			/* else
				continue */
		
		if (missing_delim == YES)
		{
			for (; lin[k] != EOS; k++)
				;
			k--;		/* k now at newline */

			/* supply trailing delim */
			lin[k] = lin[*i];
			lin[++k] = '\n';
			lin[++k] = EOS;
			Peekc = SKIP_RIGHT;
		}

		if (optpat (lin, i) == ERR)
			ret = ERR;
		else if (lin[*i] == SCAN)
			ret = ptscan (FORWARD, pnum);
		else 
			ret = ptscan (BACKWARD, pnum);
	}
	else if (lin[*i] == SEARCH || lin[*i] == BACKSEARCH)
	{
		j = *i;
		(*i)++;
		if (getkn (lin, i, &Savknm, Savknm) == ERR)
			ret = ERR;
		else if (lin[j] == SEARCH)
			ret = knscan (FORWARD, pnum);
		else
			ret = knscan (BACKWARD, pnum);
		(*i)--;
	}
	else if (isdigit (lin[*i]))
	{
		*pnum = ctoi (lin, i);
		(*i)--;
	}
	else if (lin[*i] == TOPLINE)
		*pnum = Topln;
	else
		ret = EOF;

	if (ret == OK)
		(*i)++;
	*status = ret;
	return (ret);
}


/* getone --- evaluate one line number expression */

int getone (lin, i, num, status)
char lin[];
register int *i, *num, *status;
{
	int pnum, ret;
	int getnum ();
	char porm;	/* "plus or minus" (sic) */

	ret = EOF;	/* assume we won't find anything for now */
	*num = 0;

	if (getnum (lin, i, num, status) == OK)		/* first term */
	{
		ret = OK;	/* to indicate we've seen something */
		do {			/* + or - terms */
			porm = EOS;
			SKIPBL (lin, *i);
			if (lin[*i] == '-' || lin[*i] == '+')
			{
				porm = lin[*i];
				(*i)++;
			}
			if (getnum (lin, i, &pnum, status) == OK)
				if (porm == '-')
					*num -= pnum;
				else
					*num += pnum;
			if (*status == EOF && porm != EOS)	/* trailing + or - */
				*status = ERR;
		} while (*status == OK);
	}

	if (*num < 0 || *num > Lastln)	/* make sure number is in range */
	{
		*status = ERR;
		Errcode = EORANGE;
	}

	if (*status == ERR)
		ret = ERR;
	else
		*status = ret;

	return (ret);
}


#ifndef OLD_SCRATCH
#ifndef OLD_GLOB
static int special_casing = NO;
#endif
#endif

/* ckglob --- if global prefix, mark lines to be affected */

int ckglob (lin, i, status)
char lin[];
int *i, *status;
{
	register int line, tmp;
	int usepat, usemark;
	int defalt (), match (), optpat (), getkn ();
	register LINEDESC *k;
	LINEDESC *gettxt (), *getind ();

	*status = OK;
	usepat = EOF;
	usemark = EOF;

#ifndef OLD_SCRATCH
#ifndef OLD_GLOB
	if (	/* g/^/m0  or g/$/m0 -- special case the pathological */
		/* cases in order to save time */
		(lin[*i] == GLOBAL || lin[*i] == UCGLOBAL)
		&& (lin[*i + 1] == lin[*i + 3])
		&& (lin[*i + 2] == '^' || lin[*i + 2] == '$')
		&& (lin[*i + 4] == MOVECOM || lin[*i + 4] == UCMOVECOM)
		&& (lin[*i + 5] == '0' && lin[*i + 6] == '\n')   )
	{
		special_casing = YES;
		remark ("GLOB");
		return (OK);
	}
#endif
#endif
	if (lin[*i] == GMARK || lin[*i] == XMARK)	/* global markname prefix? */
	{
		if (lin[*i] == GMARK)	/* tag lines with the specified markname */
			usemark = YES;
		else			/* tag lines without the specified markname */
			usemark = NO;
		(*i)++;
		*status = getkn (lin, i, &Savknm, Savknm);
	}

	if (*status == OK)	/* check for a pattern prefix too */
	{
		if (lin[*i] == GLOBAL || lin[*i] == UCGLOBAL)
			usepat = YES;

		if (lin[*i] == EXCLUDE || lin[*i] == UCEXCLUDE)
			usepat = NO;

		if (usepat != EOF)
		{
			(*i)++;
			if (optpat (lin, i) == ERR)
				*status = ERR;
			else
				(*i)++;
		}
	}

	if (*status == OK && usepat == EOF && usemark == EOF)
		*status = EOF;
	else if (*status == OK)
		defalt (1, Lastln);

	if (*status == OK)	/* no errors so far, safe to proceed */
	{
		remark ("GLOB");

		k = Line0;      /* unmark all lines preceeding range */
		for (line = 0; line < Line1; line++)
		{
			k -> Globmark = NO;
			k = NEXTLINE(k);
		}

		for (; line <= Line2; line++)	/* mark lines in range */
		{
			if (intrpt ())
			{
				*status = ERR;
				return (*status);
			}
			tmp = NO;
			if (usemark == EOF
			    || usemark == YES && k -> Markname == Savknm
			    || usemark == NO && k -> Markname != Savknm)
			{
				if (usepat == EOF)	/* no global pattern to look for */
					tmp = YES;
				else	/* there is also a pattern to look for */
				{
					gtxt (k);
					if (match (Txt, Pat) == usepat)
						tmp = YES;
				}
			}

			k -> Globmark = tmp;

			k = NEXTLINE(k);
		}

#ifdef OLD_SCRATCH
		/* mark remaining lines */
		for (; k != Line0; k = k -> Nextline)
			k -> Globmark = NO;
#else
		/* mark remaining lines */
		for (; line <= Lastln; line++)
		{
			k -> Globmark = NO;
			k = NEXTLINE (k);
		}
#endif

		remark ("");
	}

	return (*status);
}


/* doglob --- do command at lin[i] on all marked lines */

int doglob (lin, i, cursav, status)
char lin[];
int *i, *cursav, *status;
{
	register int istart, line;
	int docmd (), getlst (), nextln ();
	register LINEDESC *k;
	LINEDESC *getind ();

#ifndef OLD_SCRATCH
#ifndef OLD_GLOB
	if (special_casing)
	{
		/*
		remark ("Warp 7, Captain!");
		*/
		/* not on the screen too long anyway */
		reverse (1, Lastln);
		Curln = Lastln;
		special_casing = NO;
		Buffer_changed = YES;
		First_affected = min (1, First_affected);
		remark ("");
		adjust_window (Curln, Curln);
		updscreen ();
		return (OK);
	}
#endif
#endif
	*status = OK;
	istart = *i;
	k = Line0;
	line = 0;

	do {
		line++;
		k = NEXTLINE(k);
		if (k -> Globmark == YES)	/* line is marked */
		{
			k -> Globmark = NO;	/* unmark the line */
			Curln = line;
			*cursav = Curln;	/* remember where we are */
			*i = istart;
			if (getlst (lin, i, status) == OK)
				docmd (lin, *i, YES, status);
			line = 0;		/* lines may have been moved */
			k = Line0;
		}
		if (intrpt ())
			*status = ERR;
	} while (line <= Lastln && *status == OK);

	return (*status);
}


/* ckchar --- look for ch or altch on lin at i, set flag if found */

int ckchar (ch, altch, lin, i, flag, status)
char ch, altch, lin[];
int *i, *flag, *status;
{

	if (lin[*i] == ch || lin[*i] == altch)
	{
		(*i)++;
		*flag = YES;
	}
	else
		*flag = NO;

	*status = OK;
	return (OK);
}


/* ckp --- check for "p" after command */

int ckp (lin, i, pflag, status)
char lin[];
int i, *pflag, *status;
{

	if (lin[i] == PRINT || lin[i] == UCPRINT)
	{
		i++;
		*pflag = YES;
	}
	else
		*pflag = NO;

	if (lin[i] == '\n')
		*status = OK;
	else
		*status = ERR;

	return (*status);
}


/* ckupd --- make sure it is ok to destroy the buffer */

int ckupd (lin, i, cmd, status)
char lin[], cmd;
int *i, *status;
{
	int flag;
	int ckchar ();

	*status = ckchar (ANYWAY, ANYWAY, lin, i, &flag, status);
	if (flag == NO && Buffer_changed == YES && Probation != cmd)
	{
		*status = ERR;
		Errcode = ESTUPID;
		Probation = cmd;        /* if same command is repeated, */
	}                       /* we'll keep quiet */

	return (*status);
}


/* defalt --- set defaulted line numbers */

defalt (def1, def2)
int def1, def2;
{

	if (Nlines == 0)        /* no line numbers supplied, use defaults */
	{
		Line1 = def1;
		Line2 = def2;
	}

	return;
}


/* getfn --- get file name from lin[i]... */

int getfn (lin, i, file)
char lin[], file[];
int i;
{
	int j, k, ret;

	ret = ERR;
	if (lin[i + 1] == ' ')
	{
		j = i + 2;      /* get new file name */
		SKIPBL (lin, j);
		for (k = 0; lin[j] != NEWLINE; k++, j++)
			file[k] = lin[j];
		file[k] = EOS;
		if (k > 0)
			ret = OK;
	}
	else if (lin[i + 1] == '\n' && Savfil[0] != EOS)
	{
		strcpy (file, Savfil);	/* or old name */
		ret = OK;
	}
	else 
		if (lin[i + 1] == '\n')
			Errcode = ENOFN;
		else
			Errcode = EFILEN;

	if (ret == OK && Savfil[1] == EOS)
	{
		strcpy (Savfil, file);		/* save if no old one */
		mesg (Savfil, FILE_MSG);
	}

	return (ret);
}


/* getkn --- get mark name from lin[i], increment i */

int getkn (lin, i, kname, dfltnm)
char lin[], *kname, dfltnm;
int *i;
{

	if (lin[*i] == '\n' || lin[*i] == EOS)
	{
		*kname = dfltnm;
		return (EOF);
	}

	*kname = lin[*i];
	(*i)++;
	return (OK);
}


/* getrange --- get 'from' range for tlit command */

int getrange (array, k, set, size, allbut)
char array[], set[];
int *k, size, *allbut;
{
	int i, j;
	int addset ();

	Errcode = EBADLIST;	/* preset error code */

	i = *k + 1;
	if (array[i] == NOTINCCL)	/* check for negated character class */
	{
		*allbut = YES;
		i++;
	}
	else
		*allbut = NO;

	j = 0;
	filset (array[*k], array, &i, set, &j, size);
	if (array[i] != array[*k])
	{
		set[0] = EOS;
		return (ERR);
	}
	if (set[0] == EOS)
	{
		Errcode = ENOLIST;
		return (ERR);
	}
	if (j > 0 && addset (EOS, set, &j, size) == NO)
	{
		set[0] = EOS;
		return (ERR);
	}

	*k = i;
	Errcode = EEGARB;

	return (OK);
}


/* getrhs --- get substitution string for 's' command */

int getrhs (lin, i, sub, gflag)
char lin[], sub[];
int *i, *gflag;
{
	static char Subs[MAXPAT] = "";	/* saved replacement pattern */
	int j, maksub ();
	/* saved replacement pattern char */


	Errcode = EBADSUB;

	if (lin[*i] == EOS)	/* missing the middle delimeter */
		return (ERR);

	if (lin[*i + 1] == '%' && (lin[*i + 2] == lin[*i]
					|| lin[*i + 2] == '\n'))
	{
	/*
	 * s//%/ --- should mean do the same thing as I did last time, even
	 * s//&/ --- if I deleted something. So we comment out these lines.
	 *
		if (Subs[0] == EOS)
		{
			Errcode = ENOSUB;
			return (ERR);
		}
	 */
		strcpy (sub, Subs);
		*i += 2;
		if (lin[*i] == '\n')
		{
			/* fix it up for pattern matching routines */
			lin[*i] = lin[*i - 2];
			lin[*i + 1] = '\n';
			lin[*i + 2] = EOS;
			Peekc = SKIP_RIGHT;
		}
	}
	else		/* not using saved substitution pattern */
	{
		if (lin[*i + 1] == '\n')
		{
			/* missing the trailing delimiter */
			/* pattern was empty */
			lin[*i + 1] = lin[*i];	/* supply missing delimiter */
			lin[*i + 2] = '\n';
			lin[*i + 3] = EOS;
			Peekc = SKIP_RIGHT;
			/* return (ERR);    /* this is the original action */
		}
		else
		{
			/* stuff in pattern, check end of line */
			for (j = *i; lin[j] != EOS; j++)
				;
			j -= 2;		/* j now points to char before '\n' */

			if (lin[j] == 'p' || lin[j] == 'P')
			{
				--j;
				if (lin[j] == GLOBAL || lin[j] == UCGLOBAL)
				{
					if (j >= *i + 1 && lin[j-1] == lin[*i]
						&& (lin[j-2] != ESCAPE
						    || lin[j-3] == ESCAPE))
						; 	/* leave alone */
					else
					{
						/* \<delim>gp\n is pattern */
						/* supply trailing delim */
						j +=  2;	/* j at \n */
						lin[j] = lin[*i];
						lin[++j] = '\n';
						lin[++j] = EOS;
						Peekc = SKIP_RIGHT;
					}
				}
				else if (j >= *i + 1 && lin[j] == lin[*i] &&
						(lin[j-1] != ESCAPE
						 || lin[j-2] == ESCAPE))
					;	/* leave alone */
				else
				{
					/* \<delim>p\n is pattern */
					/* supply trailing delim */
					j += 2;
					lin[j] = lin[*i];
					lin[++j] = '\n';
					lin[++j] = EOS;
					Peekc = SKIP_RIGHT;
				}
			}
			else if (lin[j] == GLOBAL || lin[j] == UCGLOBAL)
			{
				--j;
				if (j >= *i + 1 && lin[j] == lin[*i] &&
					(lin[j-1] != ESCAPE
					 || lin[j-2] == ESCAPE))
					; 	/* leave alone */
				else
				{
					/* \<delim>g\n is pattern */
					/* supply trailing delim */
					j +=  2;	/* j at \n */
					lin[j] = lin[*i];
					lin[++j] = '\n';
					lin[++j] = EOS;
					Peekc = SKIP_RIGHT;
				}
			}
			else if ((lin[j] != lin[*i]) ||
				(lin[j] == lin[*i] &&
				lin[j-1] == ESCAPE && lin[j-2] != ESCAPE))
			{
				/* simply missing trailing delimeter */
				/* supply it */
				j++;		/* j at \n */
				lin[j] = lin[*i];
				lin[++j] = '\n';
				lin[++j] = EOS;
				Peekc = SKIP_RIGHT;
			}
			/* else
				unescaped delim is there,
				leave well enough alone */
		}

		if ((*i = maksub (lin, *i + 1, lin[*i], sub)) == ERR)
			return (ERR);

		strcpy (Subs, sub);	/* save pattern for later */
	}

	if (lin[*i + 1] == GLOBAL || lin[*i + 1] == UCGLOBAL)
	{
		(*i)++;
		*gflag = YES;
	}
	else
		*gflag = NO;

	Errcode = EEGARB;	/* the default */

	return (OK);

}


/* getstr --- get string from lin at i, copy to dst, bump i */

/*
** NOTE: this routine only called for doing the join command.
** therefore, don't do anything else with it.
*/

int getstr (lin, i, dst, maxdst)
char lin[], dst[];
int *i, maxdst;
{
	char delim;
	char esc ();
	int j, k, d;

	j = *i;
	Errcode = EBADSTR;

	delim = lin[j];

	if (delim == '\n')
	{
		lin[j] = '/';
		lin[++j] = ' ';		/* join with a single blank */
		lin[++j] = '/';
		lin[++j] = '\n';
		lin[++j] = EOS;
		j = *i;
		delim = lin[j];
		Peekc = SKIP_RIGHT;
		/* now fall thru */

		/* return (ERR);	/* old way */
	}
	else if ((delim == 'p' || delim == 'P') && lin[j + 1] == '\n')	/* jp */
	{
		lin[j] = '/';
		lin[++j] = ' ';		/* join with a single blank */
		lin[++j] = '/';
		lin[++j] = delim;	/* 'p' or 'P' */
		lin[++j] = '\n';
		lin[++j] = EOS;
		j = *i;
		delim = lin[j];
		Peekc = SKIP_RIGHT;
		/* now fall thru */
	}

	if (lin[j + 1] == '\n')		/* command was 'j/' */
	{
		dst[0] = EOS;
		Errcode = ENOERR;
		return (OK);
		/* return (ERR);	/* old way */
	}

	/*
	 * otherwise, stuff there in the string, try to allow for
	 * a missing final delimiter.
	 */

	for (k = j + 1; lin[k] != '\n'; k++)
		;	/* find end */
	
	k--;	/* now points to char before newline */

	if (lin[k] == 'p' || lin[k] == 'P')
	{
		k--;
		if (lin[k] == delim &&
			(lin[k-1] != ESCAPE || lin[k-2] == ESCAPE))
			;	/* it's fine, leave it alone */
		else
		{
			/* ESCAPE delim p NEWLINE is the join string */
			/* supply trailing delimiter. */
			k += 2;
			lin[k] = delim;
			lin[++k] = '\n';
			lin[++k] = EOS;
			Peekc = SKIP_RIGHT;
		}
	}
	else if (lin[k] != delim || (lin[k-1] == ESCAPE && lin[k-2] != ESCAPE))
	{
		/* no delim and no p, or last char is escaped delim */
		k++;
		lin[k] = delim;
		lin[++k] = '\n';
		lin[++k] = EOS;
		Peekc = SKIP_RIGHT;
	}
	/* else
		delim is there
		leave well enough alone */

	/* code to actually do the join */

	for (k = j + 1; lin[k] != delim; k++)	/* find end */
	{
		if (lin[k] == '\n' || lin[k] == EOS)
			if (delim == ' ')
				break;
			else
				return (ERR);
		esc (lin, &k);
	}
	if (k - j > maxdst)
		return (ERR);

	for (d = 0, j++; j < k; d++, j++)
		dst[d] = esc (lin, &j);
	dst[d] = EOS;

	*i = j;
	Errcode = EEGARB;	/* the default */

	return (OK);
}


/* getwrd --- get next word from line at i; increment i */

int getwrd (line, i, word, size)
char line[], word[];
int *i, size;
{
	int j;

	SKIPBL (line, *i);
	j = 0;
	while (line[*i] != ' ' && line[*i] != '\n' && line[*i] != EOS)
	{
		if (j < size - 1)
		{
			word[j] = line[*i];
			j++;
		}
		(*i)++;
	}
	word[j] = EOS;

	return (j);
}


/* knscan --- scan for a line with a given mark name */

int knscan (way, num)
int way, *num;
{
	int nextln ();
	LINEDESC *k;
	LINEDESC *getind ();

	*num = Curln;
	k = getind (*num);
	do {
		bump (num, &k, way);
		if (k -> Markname == Savknm)
			return (OK);
	} while (*num != Curln && ! intrpt ());

	if (Errcode = EEGARB)
		Errcode = EKNOTFND;
	return (ERR);

}


/* makset --- make set from array[k] in set */

int makset (array, k, set, size)
char array[], set[];
int *k, size;
{
	static char Tset[MAXPAT] = "";	/* saved translit dest range */
	int i, j;
	int l;
	int addset ();

	Errcode = EBADLIST;

	/*
	 * try to allow missing delimiter for translit command.
	 */
	
	if (array[*k] == EOS)
		return (ERR);

	if (array[*k + 1] == '%' && (array[*k + 2] == array[*k]
					   || array[*k + 2] == '\n'))
	{
		strcpy (set, Tset);
		*k += 2;
		if (array[*k] == '\n')
		{
			/* fix it up for rest of the routines */
			array[*k] = array[*k - 2];
			array[*k+ 1] = '\n';
			array[*k+ 2] = EOS;
		}
		Peekc = SKIP_RIGHT;
	}
	else
	{
	
		for (l = *k; array[l] != EOS; l++)
			;
		l -= 2;		/* l now points to char before '\n' */
	
		if (l == *k)	/* "y/.../\n" */
		{
			array[*k + 1] = array[*k];	/* add delimiter */
			array[*k + 2] = '\n';
			array[*k + 3] = EOS;
			Peekc = SKIP_RIGHT;
		}
		else if (array[l] == 'p' || array[l] == 'P')
		{
			--l;
			if (l >= *k + 1 && array[l] == array[*k] &&
				(array[l-1] != ESCAPE || array[l-2] == ESCAPE))
				;	/* leave alone */
			else
			{
				/* \<delim>p\n is set */
				/* supply trailing delim */
				l += 2;
				array[l] = array[*k];
				array[++l] = '\n';
				array[++l] = EOS;
				Peekc = SKIP_RIGHT;
			}
		}
		else if (array[l] != array[*k]	/* no delim, and no p */
		    || (array[l-1] == ESCAPE	/* or last char is escaped delim */
			&& array[l-2] != ESCAPE))
		{
			/* simply missing trailing delimeter */
			/* supply it */
			l++;		/* l now at \n */
			array[l] = array[*k];
			array[++l] = '\n';
			array[++l] = EOS;
			Peekc = SKIP_RIGHT;
		}
		/* else
			delim is there,
			leave well enough alone */

		j = 0;
		i = *k + 1;
		filset (array[*k], array, &i, set, &j, size);

		if (array[i] != array[*k])
			return (ERR);

		if (addset (EOS, set, &j, size) == NO)
			return (ERR);

		strcpy (Tset, set);	/* save for later */
		*k = i;

	}

	Errcode = EEGARB;

	return (OK);
}


/* optpat --- make pattern specified at lin[i] */

int optpat (lin, i)
char lin[];
int *i;
{
	int makpat ();

	if (lin[*i] == EOS)
		*i = ERR;
	else if (lin[*i + 1] == EOS)
		*i = ERR;
	else if (lin[*i + 1] == lin[*i])	/* repeated delimiter */
		(*i)++;		/* leave existing pattern alone */
	else
		*i = makpat (lin, *i + 1, lin[*i], Pat);

	if (Pat [0] == EOS)
	{
		Errcode = ENOPAT;
		return (ERR);
	}
	if (*i == ERR)
	{
		Pat[0] = EOS;
		Errcode = EBADPAT;
		return (ERR);
	}
	return (OK);
}


/* ptscan --- scan for next occurrence of pattern */

int ptscan (way, num)
int way, *num;
{
	LINEDESC *getind ();
	LINEDESC *k;
	int match ();

	*num = Curln;
	k = getind (*num);
	do {
		bump (num, &k, way);
		gtxt (k);
		if (match (Txt, Pat) == YES)
			return (OK);
	} while (*num != Curln && ! intrpt ());

	if (Errcode == EEGARB)
		Errcode = EPNOTFND;

	return (ERR);
}


/* settab --- set tab stops */

int settab (str)
char str[];
{
	int i, j, n, maxstop, last, inc, ret;
	int ctoi ();

	for (i = 0; i < MAXLINE; i++)   /* clear all tab stops */
		Tabstops[i] = NO;

	ret = OK;
	maxstop = 0;
	last = 1;

	i = 0;
	SKIPBL (str, i);
	while (str[i] != EOS && str[i] != '\n')
	{
		if (str[i] == '+')      /* increment */
		{
			i++;
			inc = YES;
		}
		else
			inc = NO;

		n = ctoi (str, &i);

		if (n <= 0 || n >= MAXLINE)
		{
			ret = ERR;
			Errcode = ENONSENSE;
			break;
		}

		if (str[i] != ' ' && str[i] != '+' &&
		    str[i] != '\n' && str[i] != EOS)
		{
			ret = ERR;
			Errcode = EBADTABS;
			break;
		}

		if (inc == YES)
		{
			for (j = last + n; j < MAXLINE; j += n)
			{
				Tabstops[j - 1] = YES;
				maxstop = max (j, maxstop);
			}
		}
		else
		{
			Tabstops[n - 1] = YES;
			last = n;
			maxstop = max (n, maxstop);
		}
		SKIPBL (str, i);
	}       /* while ... */

	if (ret == ERR)
		maxstop = 0;

	if (maxstop == 0)       /* no tab stops specified, use defaults */
	{
		for (i = 4; i < MAXLINE - 1; i += 4)
			Tabstops[i] = YES;
		maxstop = i - 4 + 1;
	}

	Tabstops[0] = YES;      /* always set to YES */

	for (i = maxstop; i < MAXLINE; i++)
		Tabstops[i] = YES;

	return (ret);
}

/* serc --- read in ./.serc or $HOME/.serc and execute the commands in it. */

/*
 * note that se's special control characters are NOT processed,
 * and therefore should NOT be used in one's .serc file.
 */

static serc ()
{
	char file[MAXLINE];
	char lin[MAXLINE];
	char *expand_env ();
	FILE *fp;
	int status = ENOERR;
	int len, cursav;

	strcpy (file, expand_env ("$HOME/.serc"));

	if ((fp = fopen ("./.serc", "r")) == NULL ||
			(fp = fopen (file, "r")) == NULL)
		return;
	
	while (fgets (lin, sizeof lin, fp) != NULL && status != EOF /*??*/)
	{
		if (lin[0] == '#' || lin[0] == '\n')
			continue;	/* comment in .serc file */

		/* most of this code stolen from edit() */
		len = 0;
		cursav = Curln;
		if (getlst (lin, &len, &status) == OK)
		{
			if (ckglob (lin, &len, &status) == OK)
				doglob (lin, &len, &cursav, &status);
			else if (status != ERR)
				docmd (lin, len, NO, &status);
		}
		if (status == ERR)
		{
			if (Errcode == EHANGUP)
				hangup ();
			Curln = min (cursav, Lastln);
		}
	}
	fclose (fp);
}

#ifdef LOG_USAGE

/* log -- log se usage */


static log ()
{
	static char logfile[] = "/usr/tmp/se.log";	/* a public file */
	char logname[MAXLINE], tod[26];		/* tod => time of day */
	long clock;
	FILE *fp;
	char *ctime ();
	long time ();
	int old_umask;
#ifdef BSD
	char *getlogin ();
#else
	char *cuserid ();
#endif

	/* get the login name */
#ifdef BSD
	strcpy (logname, getlogin ());
#else
	cuserid (logname);
#endif

	time (&clock);
	strcpy (tod, ctime (&clock));	/* see the manual on ctime(3C)  */
	tod[24] = EOS;			/* delete the '\n' at the end */

	old_umask = umask (0);		/* allow writes for everyone */
					/* when first call creates the file */

	if ((fp = fopen (logfile, "a")) != NULL)
	{
		/* all ok, write out statistics */
		fprintf (fp, "%s used se on %s.\n", logname, tod);
		fclose (fp);
	}
	/* else
		don't do anything */

	umask (old_umask);

}
#endif

/* sysname --- return a string telling us who we are */

#ifdef USG
#include <sys/utsname.h>	/* stuff to find out who we are */
#endif

char *sysname ()
{
	int i, j, k;
	char c;
	static char buf[MAXLINE] = "";
	FILE *fp;
	static char unknown[] = "unknown";

#ifdef USG	/* System V */
	static struct utsname whoarewe;

	uname (& whoarewe);
	return (whoarewe.nodename);
#else
#ifdef BSD4_2	/* Berkeley 4.2 */
	if (buf[0] != EOS)
		return (buf);

	j = sizeof (buf);
	k = gethostname (buf, & j);
	if (k != 0)
		return (unknown);
	else
		return (buf);
#else		/* Berkeley 4.1 */
	if (buf[0] != EOS)
		return (buf);

	if ((fp = fopen ("/usr/include/whoami.h", "r")) == NULL)
		return (unknown);
	else
	{
		auto char *cp;
		/*
		 * file should contain a single line:
		 * #define sysname "......"
		 */
		while ((c = getc (fp)) != '"' && c != EOF)
			;
		if (c == EOF)
			cp = unknown;
		else
		{
			for (i = 0; (c = getc (fp)) != '"' && c != EOF; i++)
				buf[i] = c;
			buf[i] = EOS;
			if (c == EOF && i == 0)
				cp = unknown;
			else
				cp = buf;
		}
		fclose (fp);
		return (cp);
	}
#endif
#endif
}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'extern.h'" '(4770 characters)'
if test -f 'extern.h'
then
	echo shar: will not over-write existing file "'extern.h'"
else
cat << \SHAR_EOF > 'extern.h'
/*
 * $Header: extern.h,v 1.2 86/07/14 16:44:30 arnold Exp $
 */

/*
 * $Log:	extern.h,v $
 * Revision 1.2  86/07/14  16:44:30  arnold
 * Removed stuff that was Georgia Tech specific.
 * 
 * Revision 1.1  86/05/06  13:36:05  osadr
 * Initial revision
 * 
 * 
 */

/*
** extern.h
**
** external data definitions
** for the screen editor
*/

/* Concerning line numbers: */
extern int Line1;		/* first line number on command */
extern int Line2;		/* second line number on command */
extern int Nlines;		/* number of line numbers specified */
extern int Curln;		/* current line; value of dot */
extern int Lastln;		/* last line; value of dollar */


/* Concerning patterns: */
extern char Pat[MAXPAT];	/* saved pattern */


/* Concerning the text of lines: */
extern char Txt[MAXLINE];	/* text of current line */


/* Concerning file names: */
extern char Savfil[MAXLINE];	/* remembered file name */


/* Concerning line descriptors: */
extern LINEDESC Buf[MAXBUF];
#ifdef OLD_SCRATCH
extern LINEDESC *Lastbf;	/* last pointer used in Buf */
extern LINEDESC *Free;		/* head of free list */
#endif
extern LINEDESC *Line0;		/* head of list of line descriptors */


/* Concerning the 'undo' command: */
extern LINEDESC *Limbo;		/* head of limbo list for undo */
extern int Limcnt;		/* number of lines in limbo list */


/* Concerning the scratch file: */
extern filedes Scr;		/* scratch file descriptor */
extern unsigned Scrend;		/* end of info on scratch file */
extern char Scrname[MAXLINE];	/* name of scratch file */
extern int Lost_lines;		/* number of garbage lines in scratch file */


/* Concerning miscellaneous variables */
extern int Buffer_changed;	/* YES if buffer changed since last write */
extern int Errcode;		/* cause of most recent error */
extern int Saverrcode;		/* cause of previous error */
extern int Probation;		/* YES if unsaved buffer can be destroyed */
extern int Argno;		/* command line argument pointer */
extern char Last_char_scanned;	/* last char scanned with ctl-s or -l */
#ifdef HARD_TERMS
extern int Tspeed;		/* terminal speed in characters/second */
#endif
extern char Peekc;		/* push a SKIP_RIGHT if adding delimiters */
#ifdef BSD4_2
extern int Reading;		/* are we doing terminal input? */
#endif


/* Concerning options: */
extern int Tabstops[MAXLINE];	/* array of tab stops */
extern char Unprintable;	/* char to print for unprintable chars */
extern int Absnos;		/* use absolute numbers in margin */
extern int Nchoise;		/* choice of line number for cont. display */
extern int Overlay_col;		/* initial cursor column for 'v' command */
extern int Warncol;		/* where to turn on column warning */
extern int Firstcol;		/* leftmost column to display */
extern int Indent;		/* indent col; 0=same as previous line */
extern int Notify;		/* notify user if he has mail in mail file */
extern int Globals;		/* substitutes in a global don't fail */
extern int No_hardware;		/* never use hardware insert/delete */


#ifdef HARD_TERMS
/* Concerning the terminal type */
extern int Term_type;          /* terminal type */
#endif


/* Concerning the screen format: */
extern char Screen_image[MAXROWS][MAXCOLS];
extern char Msgalloc[MAXCOLS];	/* column allocation of status line */
extern int Nrows;		/* number of rows on screen */
extern int Ncols;		/* number of columns on screen */
extern int Currow;		/* vertical cursor coordinate */
extern int Curcol;		/* horizontal cursor coordinate */
extern int Toprow;		/* top row of window field on screen */
extern int Botrow;		/* bottom row of window field on screen */
extern int Cmdrow;		/* row number of command line */
extern int Topln;		/* line number of first line on screen */
extern int Insert_mode;		/* flag to specify character insertion */
extern int Invert_case;		/* flag to specify case mapping on input */
extern int First_affected;	/* number of first line affected by cmd */
extern int Rel_a;		/* char to use for first alpha line number */
extern int Rel_z;		/* char to use for last alpha line number */
extern int Scline[MAXROWS];	/* lines currently on screen (rel to Sctop) */
extern int Sctop;		/* first line currently on screen */
extern int Sclen;		/* number of lines currently on screen */
extern char Blanks[MAXCOLS];	/* all blanks for filling in lines on screen */
extern char Tobuf[MAXTOBUF];	/* buffer for collecting terminal output */
extern char *Tobp;		/* pointer to last used part of Tobuf */


/* Concerning interrupts: */
extern int Int_caught;		/* caught a SIGINT from user */
extern int Hup_caught;		/* caught a SIGHUP when phone line dropped */
#ifdef SIGTSTP
extern int Catching_stops;	/* catching or ignoring SIGTSTP's? */
#endif

/* Concerning file encryption: */
extern int Crypting;		/* doing file encryption? */
extern char Key[KEYSIZE];	/* encryption key */
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'m4munge'" '(704 characters)'
if test -f 'm4munge'
then
	echo shar: will not over-write existing file "'m4munge'"
else
cat << \SHAR_EOF > 'm4munge'
#! /bin/sh
# m4munge --- take what the 'where' command produces, and change it for m4
# 
# $Header: m4munge,v 1.2 86/07/11 15:13:56 osadr Exp $
# 
# $Log:	m4munge,v $
# Revision 1.2  86/07/11  15:13:56  osadr
# Removed Georgia Tech specific items.
# 
# Revision 1.1  86/05/06  13:35:02  osadr
# Initial revision
# 
# 
# 

for i in $*
do
	case $i in
	-DUSG)		echo 'define(USG,YES)'		;;
	-UUSG)		echo 'define(USG,NO)'		;;
	-DBSD)		echo 'define(BSD,YES)'		;;
	-UBSD)		echo 'define(BSD,NO)'		;;
	-DBSD4_2)	echo 'define(BSD4_2,YES)'	;;
	-UBSD4_2)	echo 'define(BSD4_2,NO)'	;;
	-DS5R2)		echo 'define(S5R2,YES)'		;;
	-US5R2)		echo 'define(S5R2,NO)'		;;
	-DHARD_TERMS)	echo 'define(HARD_TERMS,YES)'	;;
	esac
done
SHAR_EOF
chmod +x 'm4munge'
fi # end of overwriting check
echo shar: extracting "'main.c'" '(13208 characters)'
if test -f 'main.c'
then
	echo shar: will not over-write existing file "'main.c'"
else
cat << \SHAR_EOF > 'main.c'
#ifndef lint
static char RCSid[] = "$Header: main.c,v 1.4 86/10/07 14:50:17 arnold Exp $";
#endif

/*
 * $Log:	main.c,v $
 * Revision 1.4  86/10/07  14:50:17  arnold
 * Changed setterm to set_term, to avoid Unix/PC shared library conflict.
 * 
 * Revision 1.3  86/07/17  17:20:58  arnold
 * Terminal initialization code cleaned up considerably.
 * 
 * Revision 1.2  86/07/11  15:12:26  osadr
 * Removed code that was Georgia Tech specific
 * 
 * Revision 1.1  86/05/06  13:37:38  osadr
 * Initial revision
 * 
 * 
 */

/*
** main.c
**
** main program and lots of other routines
** for the se screen editor.
*/

#include "se.h"

/* declare global variables */

/* Concerning line numbers: */
int Line1;		/* first line number on command */
int Line2;		/* second line number on command */
int Nlines;		/* number of line numbers specified */
int Curln;		/* current line; value of dot */
int Lastln;		/* last line; value of dollar */


/* Concerning patterns: */
char Pat[MAXPAT] = "";	/* saved pattern */


/* Concerning the text of lines: */
char Txt[MAXLINE];	/* text of current line */


/* Concerning file names: */
char Savfil[MAXLINE] = "";	/* remembered file name */


/* Concerning line descriptors: */
LINEDESC Buf[MAXBUF];
LINEDESC *Line0;	/* head of list of line descriptors */
#ifdef OLD_SCRATCH
LINEDESC *Lastbf;	/* last pointer used in Buf */
LINEDESC *Free;		/* head of free list */
#endif


/* Concerning the 'undo' command: */
LINEDESC *Limbo;	/* head of limbo list for undo */
int Limcnt;		/* number of lines in limbo list */


/* Concerning the scratch file: */
filedes Scr;		/* scratch file descriptor */
unsigned Scrend;	/* end of info on scratch file */
char Scrname[MAXLINE];	/* name of scratch file */
int Lost_lines;		/* number of garbage lines in scratch file */


/* Concerning miscellaneous variables */
int Buffer_changed = NO;/* YES if buffer changed since last write */
int Errcode = ENOERR;	/* cause of most recent error */
int Saverrcode = ENOERR;/* cause of previous error */
int Probation = NO;	/* YES if unsaved buffer can be destroyed */
int Argno;		/* command line argument pointer */
char Last_char_scanned = 0;	/* last char scanned w/ctl-[sl], init illegal  */
char Peekc = EOS;	/* push a SKIP_RIGHT if adding delimiters */
#ifdef HARD_TERMS
int Tspeed;		/* terminal speed in characters/second */
#endif
#ifdef BSD4_2
int Reading = NO;	/* are we doing terminal input? */
#endif


/* Concerning options: */
int Tabstops[MAXLINE];	/* array of tab stops */
char Unprintable = ' ';	/* char to print for unprintable chars */
int Absnos = NO;	/* use absolute numbers in margin */
int Nchoise = EOS;	/* choice of line number for cont. display */
int Overlay_col = 0;	/* initial cursor column for 'v' command */
int Warncol;		/* where to turn on column warning, set in dosopt() */
int Firstcol = 0;	/* leftmost column to display */
int Indent = 1;		/* indent col; 0=same as previous line */
int Notify = YES;	/* notify user if he has mail in mail file */
int Globals = NO;	/* substitutes in a global don't fail */
int No_hardware;	/* never use hardware insert/delete */


#ifdef HARD_TERMS
/* Concerning the terminal type */
int Term_type;		/* terminal type */
#endif


/* Concerning the screen format: */
char Screen_image[MAXROWS][MAXCOLS];
char Msgalloc[MAXCOLS];	/* column allocation of status line */
int Nrows;		/* number of rows on screen */
int Ncols;		/* number of columns on screen */
int Currow;		/* vertical cursor coordinate */
int Curcol;		/* horizontal cursor coordinate */
int Toprow;		/* top row of window field on screen */
int Botrow;		/* bottom row of window field on screen */
int Cmdrow;		/* row number of command line */
int Topln;		/* line number of first line on screen */
int Insert_mode;	/* flag to specify character insertion */
int Invert_case;	/* flag to specify case mapping on input */
int First_affected;	/* number of first line affected by cmd */
int Rel_a;		/* char to use for first alpha line number */
int Rel_z;		/* char to use for last alpha line number */
int Scline[MAXROWS];	/* lines currently on screen (rel to Sctop) */
int Sctop;		/* first line currently on screen */
int Sclen;		/* number of lines currently on screen */
char Blanks[MAXCOLS];	/* all blanks for filling in lines on screen */
char Tobuf[MAXTOBUF];	/* buffer for collecting terminal output */
char *Tobp = Tobuf - 1;	/* pointer to last used part of Tobuf */


/* Concerning interrupts: */
int Int_caught = 0;	/* caught a SIGINT from user */
int Hup_caught = 0;	/* caught a SIGHUP when phone line dropped */
#ifdef BSD
int Catching_stops;	/* catching or ignoring SIGTSTP's? */
#endif

/* Concerning file encryption: */
int Crypting = NO;	/* doing file encryption? */
char Key[KEYSIZE] = "";	/* saved encryption key */

extern char *getenv ();

/* main --- main program for screen editor */

main (argc, argv)
int argc;
char *argv[];
{
	char *basename ();
	int int_hdlr (), hup_hdlr ();
	int (*old_int)(), (*old_quit)();
#ifdef BSD
	int stop_hdlr (), (*old_stop)();
#endif
	/* catch quit and hangup signals */
	/*
	 * In the terminal driver munging routines, we set Control-P
	 * to generate an interrupt, and turn off generating Quits from
	 * the terminal.  Now we just ignore them if sent from elsewhere.
	 */

	signal (SIGHUP, hup_hdlr);

	old_int = signal (SIGINT, int_hdlr);
	old_quit = signal (SIGQUIT, SIG_IGN);

#ifdef notdef
/*
 * This is commented out so that se can be run from the news
 * software.  Commenting it out will also allow you to put it
 * in the background, which could give you trouble. So beware.
 */

	if (old_int == SIG_IGN || old_quit == SIG_IGN)
	{
		/* fired off into the background, refuse to run */
		if (isatty (fileno (stdin)))
		{
			fprintf (stderr, "%s: I refuse to run in the background.\n",
				basename (argv[0]));
			exit (2);
		}
		/* else
			assume input is a script */
	}
#endif

#ifdef BSD
	old_stop = signal (SIGTSTP, stop_hdlr);

	if (old_stop == SIG_IGN)	/* running bourne shell */
	{
		signal (SIGTSTP, SIG_IGN);	/* restore it */
		Catching_stops = NO;
	}
	else
		Catching_stops = YES;
		/* running C-shell or BRL sh, catch Control-Z's */
#endif

	/* set terminal to no echo, no output processing, break enabled */
	ttyedit ();

#ifdef HARD_TERMS
	Tspeed = getspeed (1);		/* speed of stdout */
#endif

	initialize (argc, argv);

	edit (argc, argv);

#ifndef HARD_TERMS
	t_exit ();
#endif

	/* reset the terminal mode */
	ttynormal ();
}

/* error --- print error message and die semi-gracefully */

error (coredump, msg)
int coredump;
char *msg;
{
	/*
	 * You might think we want to try and save the buffer,
	 * BUT, fatal errors can be caused by buffer problems,
	 * which would end up putting us into a non-ending recursion.
	 */

	ttynormal ();
	fprintf (stderr, "%s\n", msg);
	signal (SIGQUIT, SIG_DFL);	/* restore normal quit handling */
	if (coredump)
		kill (getpid (), SIGQUIT);	/* dump memory */
	else
		exit (1);
}

/* initialize --- set up global data areas, get terminal type */

initialize (argc, argv)
int argc;
char *argv[];
{
	int i, dosopt ();

	Argno = 1;
#ifdef HARD_TERMS
	/* Determine what type of terminal we're on */
	if (Argno < argc && argv[Argno][0] == '-' && argv[Argno][2] == EOS
	    && (argv[Argno][1] == 't' || argv[Argno][1] == 'T'))
	{
		Argno = 2;
		if (Argno < argc)
		{
			strmap (argv[Argno], 'l');
			if (set_term (argv[Argno]) == ERR)
				usage ();
			else
				Argno++;
		}
		else
			usage ();
	}
	else
		/* fall through to the if, below */
#endif
		if (set_term (getenv ("TERM")) == ERR)
			usage ();

	/* Initialize the scratch file: */
	mkbuf ();

	/* Initialize screen format parameters: */
	setscreen ();

	/* Initialize the array of blanks to blanks */
	for (i = 0; i < Ncols; i++)
		Blanks[i] = ' ';
	Blanks[i] = '\0';

	if (dosopt ("") == ERR)
		error ("in initialize: can't happen");
}

/* intrpt --- see if there has been an interrupt or hangup */

int intrpt ()
{
	if (Int_caught)
	{
		Errcode = EBREAK;
		Int_caught = 0;
		return (1);
	}
	else if (Hup_caught)
	{
		Errcode = EHANGUP;
		Hup_caught = 0;
		return (1);
	}
	return (0);
}

/* int_hdlr --- handle an interrupt signal */

int_hdlr ()
{
#ifndef BSD4_2
	signal (SIGINT, int_hdlr);
#endif
	Int_caught = 1;
}

/* hup_hdlr --- handle a hangup signal */

hup_hdlr ()
{
#ifndef BSD4_2
	signal (SIGHUP, hup_hdlr);
	Hup_caught = 1;
#else
	/* do things different cause of 4.2 (sigh) */
	Hup_caught = 1;
	if (Reading)	/* doing tty i/o, and that is where hup came from */
		hangup ();
#endif
}

#ifdef BSD
/* stop_hdlr --- handle the berkeley stop/suspend signal */

int stop_hdlr ()
{
	clrscreen ();
	tflush ();
	ttynormal ();
#ifdef BSD4_2
	/* this handler remains in effect, use uncatchable signal */
	kill (getpid(), SIGSTOP);
#else
	/* action was reset to default when we caught it */
	kill (getpid(), SIGTSTP);
#endif
	/*
	 * user does a "fg"
	 */
#ifndef BSD4_2
	signal (SIGTSTP, stop_hdlr);	/* reset stop catching */
#endif
	ttyedit ();
	restore_screen ();
}
#endif

/* hangup --- dump contents of edit buffer if SIGHUP occurs */

hangup ()
{
	/* close terminal to avoid hanging on any accidental I/O: */
	close (0);
	close (1);
	close (2);

	signal (SIGHUP, SIG_IGN);
	signal (SIGINT, SIG_IGN);
	signal (SIGQUIT, SIG_IGN);
	Hup_caught = 0;
	Crypting = NO;		/* force buffer to be clear text */
	dowrit (1, Lastln, "se.hangup", NO, YES, NO);
	clrbuf ();
	exit (1);
}

/* mswait --- message waiting subroutine */

/* if the user wants to be notified, and the mail file is readable, */
/* and there is something in it, then he is given the message. */
/* the om command toggles Notify, controlling notification. */

#include <sys/types.h>
#include <sys/stat.h>

mswait ()
{
	int access ();
	struct stat buf;
	static char *mbox = NULL;
	static int first = YES;
	static unsigned long mtime = 0L;

	if (! Notify)
		return;

	if (first) 
	{
		first = NO;
		if ((mbox = getenv ("MAIL")) != NULL && access (mbox, 4) == 0)
		{
			if (stat (mbox, &buf) >= 0)
			{
				mtime = buf.st_mtime;
				if (buf.st_size > 0)
					remark ("You have mail");
			}
		}
	}
	else if (mbox && stat (mbox, &buf) >= 0 && buf.st_mtime > mtime)
	{
		mtime = buf.st_mtime;
		remark ("You have new mail");
		twrite (1, "\007", 1);	/* Bell */
	}
}

/* printverboseerrormessage --- print verbose error message */

printverboseerrormessage ()
{
	switch (Errcode) {
	case EBACKWARD:
		remark ("Line numbers in backward order"); 
		break;
	case ENOPAT:
		remark ("No saved pattern -- sorry"); 
		break;
	case EBADPAT:
		remark ("Bad syntax in pattern"); 
		break;
	case EBADSTR:
		remark ("Bad syntax in string parameter"); 
		break;
	case EBADSUB:
		remark ("Bad syntax in substitution string"); 
		break;
	case ECANTREAD:
		remark ("File is not readable"); 
		break;
	case EEGARB:
		remark ("Garbage after your command"); 
		break;
	case EFILEN:
		remark ("Bad syntax in file name"); 
		break;
	case EBADTABS:
		remark ("Bad tabstop syntax"); 
		break;
	case EINSIDEOUT:
		remark ("Can't move a group into itself"); 
		break;
	case EKNOTFND:
		remark ("No line has that mark name"); 
		break;
	case ELINE1:
		remark (""); 
		break;
	case E2LONG:
		remark ("Resultant line too long to handle"); 
		break;
	case ENOERR:
		remark ("No error to report"); 
		break;
	case ENOLIMBO:
		remark ("No lines in limbo"); 
		break;
	case EODLSSGTR:
		remark ("Expected '<', '>', or nothing after 'od'"); 
		break;
	case EORANGE:
		remark ("Line number out of range"); 
		break;
	case EOWHAT:
		remark ("Can't recognize option"); 
		break;
	case EPNOTFND:
		remark ("No line contains that pattern"); 
		break;
	case ESTUPID:
		remark ("Buffer hasn't been saved"); 
		break;
	case EWHATZAT:
		remark ("No command recognized"); 
		break;
	case EBREAK:
		remark ("You interrupted me"); 
		break;
	case ELINE2:
		remark ("Last line number beyond end of file"); 
		break;
	case ECANTWRITE:
		remark ("File is not writeable"); 
		break;
	case ECANTINJECT:
		remark ("No room for any more lines!"); 
		break;
	case ENOMATCH:
		remark ("No match for pattern"); 
		break;
	case ENOFN:
		remark ("No saved filename"); 
		break;
	case EBADLIST:
		remark ("Bad syntax in character list"); 
		break;
	case ENOLIST:
		remark ("No saved character list -- sorry"); 
		break;
	case ENONSENSE:
		remark ("Unreasonable value"); 
		break;
	case ENOHELP:
		remark ("No help available"); 
		break;
	case EBADLNR:
		remark ("Line numbers not allowed"); 
		break;
	case EFEXISTS:
		remark ("File already exists"); 
		break;
	case EBADCOL:
		remark ("Improper column number specification"); 
		break;
	case ENOLANG:
		remark ("Unknown source language"); 
		break;
	case ETRUNC:
		remark ("Lines were truncated"); 
		break;
	case ENOSHELL:
		remark ("Type control-q to rebuild screen"); 
		break;
	case ECANTFORK:
		remark ("Can't fork --- get help!"); 
		break;
	case ENOSUB:
		remark ("No saved replacement --- sorry"); 
		break;
	case ENOCMD:
		remark ("No saved shell command --- sorry");
		break;
	default:
		remark ("?"); 
		break;
	}
	Errcode = ENOERR;
}

/* usage --- print usage diagnostic and die */

usage ()
{
	ttynormal ();
	fprintf (stderr, "Usage: se%s%s\n",
#ifdef HARD_TERMS
	" [ -t <terminal> ] ",
#else
	" ",
#endif
	"[ --acdfghiklmstuvwxyz ] [ file ... ]");
	exit (1);
}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'makefile'" '(3680 characters)'
if test -f 'makefile'
then
	echo shar: will not over-write existing file "'makefile'"
else
cat << \SHAR_EOF > 'makefile'
# 
# $Header: makefile,v 1.3 86/09/19 12:16:19 arnold Exp $
# 
# $Log:	makefile,v $
# Revision 1.3  86/09/19  12:16:19  arnold
# Fixed to ignore return code from shell if statement.
# 
# Revision 1.2  86/05/27  17:47:50  osadr
# Changes to support the Unix PC (no egrep, shared library), and
# to support making if . is not in the search path.
# 
# Revision 1.1  86/05/06  13:39:18  osadr
# Initial revision
# 
# 
# 
# makefile for the Georgia Tech Screen Editor, 'se'

HEADERS= ascii.h constdefs.h extern.h se.h

SRCS= docmd1.c docmd2.c edit.c main.c misc.c scratch.c screen.c term.c
OBJS= docmd1.o docmd2.o edit.o main.o misc.o scratch.o screen.o term.o

LIBRARIES= libchangetty/libchangetty.a pat/libpat.a

DOCS= makefile README
MANS= scriptse.1 se.1

CFLAGS= -O `cat flags`
LDFLAGS=

# On BSD systems, force make to use the right shell for commands
SHELL=/bin/sh

###########################################################################
# Begin system dependant macro definitions

# PR is to print the files nicely.  Use pr -n if available, or else just pr
# I use a private utility called 'prt'
PR=pr

# NROFF is for nroffing.  we use the System V nroff. 
NROFF=/usr/5bin/nroff

# MANSEC is where to put the manual pages. Use 'l' for local, otherwise '1'.
MANSEC=l

# DESTBIN is where se and scriptse will go
DESTBIN= /usr/local/bin

# OWNER and GROUP are the owner and group respectively
OWNER= root
GROUP= sys

# INSTALL is the program to do the installation, use cp for real work
INSTALL= cp

# CHOWN changes the owner.
CHOWN= /etc/chown

# CHGRP changes the group.
CHGRP= chgrp

# CHMOD will change permissions.
CHMOD= chmod

########
# other things to change:
#
# on non-BSD systems, change the 'lpr' below to 'lp'
########

# Begin list of dependencies

all: se scriptse se.1
	@echo all done

se: $(OBJS) $(LIBRARIES)
	if grep DBSD flags > /dev/null || grep US5R2 flags > /dev/null; \
	then	echo -ltermlib > libs; \
	else	echo -lcurses > libs ; \
	fi
	-if [ -f /lib/shlib.ifile ] ; \
	then	ld /lib/crt0s.o /lib/shlib.ifile $(OBJS) $(LIBRARIES) -o $@ ; \
	else	$(CC) $(LDFLAGS) $(OBJS) $(LIBRARIES) `cat libs` -o $@ ; \
	fi
	rm libs

$(OBJS): $(HEADERS) flags

flags: where
	./where > flags

libchangetty/libchangetty.a: libchangetty/changetty.c
	cd libchangetty; make

pat/libpat.a: pat/pat.c
	cd pat; make

scriptse: scriptse.c
	$(CC) -O scriptse.c -o scriptse

se.1: se.m4 flags
	(./m4munge $(CFLAGS) ; cat se.m4) | m4 | sed '/^$$/d' > se.1

install: all $(MANS)
	$(INSTALL) se $(DESTBIN)
	$(CHOWN) $(OWNER) $(DESTBIN)/se
	$(CHGRP) $(GROUP) $(DESTBIN)/se
	$(CHMOD) 711 $(DESTBIN)/se 
	$(INSTALL) scriptse $(DESTBIN)
	$(CHOWN) $(OWNER) $(DESTBIN)/scriptse
	$(CHGRP) $(GROUP) $(DESTBIN)/scriptse
	$(CHMOD) 711 $(DESTBIN)/scriptse 
	$(INSTALL) se.1 /usr/man/man$(MANSEC)/se.$(MANSEC)
	$(CHOWN) $(OWNER) /usr/man/man$(MANSEC)/se.$(MANSEC)
	$(CHGRP) $(GROUP) /usr/man/man$(MANSEC)/se.$(MANSEC)
	$(CHMOD) 644 /usr/man/man$(MANSEC)/se.$(MANSEC)
	$(INSTALL) scriptse.1 /usr/man/man$(MANSEC)/scriptse.$(MANSEC)
	$(CHOWN) $(OWNER) /usr/man/man$(MANSEC)/scriptse.$(MANSEC)
	$(CHGRP) $(GROUP) /usr/man/man$(MANSEC)/scriptse.$(MANSEC)
	$(CHMOD) 644 /usr/man/man$(MANSEC)/scriptse.$(MANSEC)
	cd se_h; make install
	
print:
	$(PR) $(HEADERS) $(SRCS) $(DOCS) $(MANS) | lpr

printman: $(MANS)
	$(NROFF) -man $(MANS) | col | lpr

print2:	$(HEADERS) $(SRCS) $(DOCS) $(MANS)
	$(PR) $? | lpr

printall: printman print
	cd pat; make print
	cd libchangetty; make print
	cd se_h; make print

clean:
	rm -f *.o print2
	cd pat; make clean
	cd libchangetty; make clean

clobber: clean
	rm -f se scriptse flags se.1
	cd pat; make clobber
	cd libchangetty; make clobber
	cd se_h; make clobber
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'misc.c'" '(3315 characters)'
if test -f 'misc.c'
then
	echo shar: will not over-write existing file "'misc.c'"
else
cat << \SHAR_EOF > 'misc.c'
#ifndef lint
static char RCSid[] = "$Header: misc.c,v 1.1 86/05/06 13:37:51 osadr Exp $";
#endif

/*
 * $Log:	misc.c,v $
 * Revision 1.1  86/05/06  13:37:51  osadr
 * Initial revision
 * 
 * 
 */

/*
** misc.c
**
** lots of miscellanious routines for the screen editor.
*/

#include "se.h"
#include "extern.h"

/* cprow --- copy from one row to another for append */

cprow (from, to)
register int from, to;
{
	register int col;

	for (col = 0; col < Ncols; col++)
		load (Screen_image[from][col], to, col);
}

/* index --- return position of character in string */

int index (str, c)
register char str[], c;
{
	register int i;

	for (i = 0; str[i] != EOS; i++)
		if (str[i] == c)
			return (i);
	return (-1);
}

/* strbsr --- binary search stab for an entry equal to str */

int strbsr (stab, tsize, esize, str)
char *stab, str[];
int tsize, esize;
{
	/* stab should have been declared like this:

	static struct {
	    char *s;
	    ...
	    } stab[] = {
		"string1",      ...
		"string2",      ...
		...             ...
		};

    The call to strbsr should look like this:

	i = strbsr (stab, sizeof (stab), sizeof (stab[0]), str);
    */

	register int i, j, k, x;
	int strcmp ();

	i = 0;
	j = tsize / esize - 1;
	do {
		k = (i + j) / 2;
		if ((x = strcmp (str, *(char **)(stab + esize * k))) < 0)
			j = k - 1;              /* GREATER */
		else if (x == 0)
			return (k);             /* EQUAL */
		else
			i = k + 1;              /* LESS */
	} while (i <= j);

	return (EOF);
}

/* strmap --- map a string to upper/lower case */

int strmap (str, ul)
register char str[];
int ul;
{
	register int i;

	if (isupper (ul))
		for (i = 0; str[i] != '0'; i++)
			str[i] = islower (str[i]) ? toupper (str[i]) : str[i];
	else
		for (i = 0; str[i] == EOS; i++)
			str[i] = isupper (str[i]) ? tolower (str[i]) : str[i];
	return (i);
}


/* xindex --- invert condition returned by index */

int xindex (array, c, allbut, lastto)
char array[], c;
int allbut, lastto;
{
	int index ();

	if (c == EOS)
		return (-1);
	if (allbut == NO)
		return (index (array, c));
	if (index (array, c) > -1)
		return (-1);
	return (lastto + 1);
}


/* ctoi --- convert decimal string to a single precision integer */

int ctoi (str, i)
register char str[];
register int *i;
{
	register int ret;

	SKIPBL (str, *i);
	for (ret = 0; isdigit (str[*i]); (*i)++)
		ret = ret * 10 + (str[*i] - '0');
	return (ret);
}


/* move_ --- move l bytes from here to there */

move_ (here, there, l)
register char *here, *there;
register int l;
{
	while (l--)
		*there++ = *here++;
}


/* twrite --- stuff characters into the terminal output buffer */

twrite (fd, buf, len)
register int fd, len;
register char *buf;
{

	if ((Tobp - Tobuf) + 1 + len > MAXTOBUF)
		tflush ();

	if (fd != 1 || len > MAXTOBUF)
	{
		write (fd, buf, len);
		return;
	}

	while (len--)
		*++Tobp = *buf++;
}


/* tflush --- clear out the terminal output buffer */

tflush ()
{
	write (1, Tobuf, (int)(Tobp - Tobuf + 1));
	Tobp = Tobuf - 1;
}



/* basename -- return last portion of a pathname */

char *basename (str)
register char *str;
{
	register char *cp;
#ifdef USG
#define rindex	strrchr
#endif
	char *rindex ();

	if ((cp = rindex(str, '/')) == NULL)
		return (str);	/* no '/' found, return whole name */
	else
		return (++cp);	/* skip over slash to name after it */
}
SHAR_EOF
fi # end of overwriting check
#	End of shell archive
exit 0



More information about the Mod.sources mailing list