DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download
Index: ┃ T e

⟦862b138bf⟧ TextFile

    Length: 26346 (0x66ea)
    Types: TextFile
    Names: »edit.c«

Derivation

└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
    └─ ⟦this⟧ »EUUGD11/euug-87hel/sec1/se/edit.c« 

TextFile

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