[comp.os.minix] BSD 'more' for Minix

housel@en.ecn.purdue.edu (Peter S. Housel) (11/29/88)

	The 'more' program distributed with the BSD 4.3-Tahoe Unix
release is marked as freely redistributable, and didn't require much
hacking to adapt for Minix.  Among its advantages:

	- The source is not nearly as large as the 'less' source. (140K of
	  'less' source didn't seem worth the effort to me to transfer it at
	  1200 baud.)
	- It only requires about twice what the Minix 'more' takes up in
	  memory (about 40K).
	- It starts up faster than the Minix 'more'. (Don't know why this is.)
	- All the usual features - percentages, underlining/standout,
	  backing up, regular expression searches, skipping forwards/backwards,
	  next/previous file, starting up 'vi' (if you have such a thing), a
	  help file, etc.
	- I'm used to it. You probably are too.

	The version included here will still compile under BSD, and
will probably work on most V7 or SysV machines. When installing, be
sure to put 'more.help' in /usr/lib.

	Also make sure 'varargs.h' is in /usr/include. Except for the
last two lines, which I added, it is the same as the one in EFTH Minix
report #47. The file 'regcompat.c' will work for any programs using the
BSD regular expression routines when all you have is Henry Spencer's
regexp(3) routines.

	Also included here is a version of 'mkdep' for Minix. This is
actually a merged version based on the Berkeley version and Chris
Torek's 'getdep'. He posted both of these to comp.unix.questions this
summer.

	Enjoy!

-Peter S. Housel-	housel@en.ecn.purdue.edu	...!pur-ee!housel
--------------------------------------------------------------------------
#!/bin/sh
echo 'x - Makefile'
sed 's/^X//' <<'**-Makefile-EOF-**' >Makefile
X#
X# Copyright (c) 1988 Regents of the University of California.
X# All rights reserved.
X#
X# Redistribution and use in source and binary forms are permitted
X# provided that the above copyright notice and this paragraph are
X# duplicated in all such forms and that any documentation,
X# advertising materials, and other materials related to such
X# distribution and use acknowledge that the software was developed
X# by the University of California, Berkeley.  The name of the
X# University may not be used to endorse or promote products derived
X# from this software without specific prior written permission.
X# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X# WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X#
X#	@(#)Makefile	5.5 (Berkeley) 6/29/88
X#
XCFLAGS= -DMINIX
XLIBC=	/usr/lib/libc.a
XSRCS=	more.c regcompat.c tcvars.c
XOBJS=	more.s regcompat.s tcvars.s
X
Xall: more
X
Xmore:	${OBJS} ${LIBC}
X	${CC} -o $@ ${CFLAGS} ${OBJS} -ltermcap
X	chmem =4096 $@
X
Xclean: FRC
X	rm -f ${OBJS} core more
X
Xdepend: FRC
X	mkdep ${CFLAGS} ${SRCS}
X
Xinstall: FRC
X	install -s -o bin -g bin -m 755 more ${DESTDIR}/usr/ucb/more
X	rm -f ${DESTDIR}/usr/ucb/page
X	ln ${DESTDIR}/usr/ucb/more ${DESTDIR}/usr/ucb/page
X	install -c -o bin -g bin -m 644 more.help ${DESTDIR}/usr/lib/more.help
X
Xlint: FRC
X	lint ${CFLAGS} ${SRCS}
X
Xtags: FRC
X	ctags ${SRCS}
X
XFRC:
X
X# DO NOT DELETE THIS LINE -- mkdep uses it.
X# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
X
Xmore.s: /usr/include/a.out.h
Xmore.s: /usr/include/ctype.h
Xmore.s: /usr/include/errno.h
Xmore.s: /usr/include/limits.h
Xmore.s: /usr/include/setjmp.h
Xmore.s: /usr/include/sgtty.h
Xmore.s: /usr/include/signal.h
Xmore.s: /usr/include/stdio.h
Xmore.s: /usr/include/sys/stat.h
Xmore.s: /usr/include/varargs.h
Xmore.s: more.c
Xregcompat.s: /usr/include/regexp.h
Xregcompat.s: /usr/include/stdio.h
Xregcompat.s: regcompat.c
Xtcvars.s: tcvars.c
X
X# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
**-Makefile-EOF-**
echo 'x - Makefile.BSD'
sed 's/^X//' <<'**-Makefile.BSD-EOF-**' >Makefile.BSD
X#
X# Copyright (c) 1988 Regents of the University of California.
X# All rights reserved.
X#
X# Redistribution and use in source and binary forms are permitted
X# provided that the above copyright notice and this paragraph are
X# duplicated in all such forms and that any documentation,
X# advertising materials, and other materials related to such
X# distribution and use acknowledge that the software was developed
X# by the University of California, Berkeley.  The name of the
X# University may not be used to endorse or promote products derived
X# from this software without specific prior written permission.
X# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X# WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X#
X#	@(#)Makefile	5.5 (Berkeley) 6/29/88
X#
XCFLAGS=	-O
XLIBC=	/lib/libc.a
XSRCS=	more.c
XOBJS=	more.o
X
Xall: more
X
Xmore:	${OBJS} ${LIBC}
X	${CC} -o $@ ${CFLAGS} ${OBJS} -ltermcap
X
Xclean: FRC
X	rm -f ${OBJS} core more
X
Xdepend: FRC
X	mkdep ${CFLAGS} ${SRCS}
X
Xinstall: FRC
X	install -s -o bin -g bin -m 755 more ${DESTDIR}/usr/ucb/more
X	rm -f ${DESTDIR}/usr/ucb/page
X	ln ${DESTDIR}/usr/ucb/more ${DESTDIR}/usr/ucb/page
X	install -c -o bin -g bin -m 644 more.help ${DESTDIR}/usr/lib/more.help
X
Xlint: FRC
X	lint ${CFLAGS} ${SRCS}
X
Xtags: FRC
X	ctags ${SRCS}
X
XFRC:
X
X# DO NOT DELETE THIS LINE -- mkdep uses it.
X# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
X
Xmore.o: more.c /usr/include/stdio.h /usr/include/sys/param.h
Xmore.o: /usr/include/sys/types.h /usr/include/signal.h
Xmore.o: /usr/include/machine/trap.h /usr/include/machine/machparam.h
Xmore.o: /usr/include/machine/endian.h /usr/include/ctype.h
Xmore.o: /usr/include/signal.h /usr/include/errno.h /usr/include/sgtty.h
Xmore.o: /usr/include/sys/ioctl.h /usr/include/sys/ttychars.h
Xmore.o: /usr/include/sys/ttydev.h /usr/include/setjmp.h /usr/include/sys/stat.h
Xmore.o: /usr/include/sys/file.h /usr/include/a.out.h /usr/include/sys/exec.h
Xmore.o: /usr/include/varargs.h
X
X# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
**-Makefile.BSD-EOF-**
echo 'x - more.c'
sed 's/^X//' <<'**-more.c-EOF-**' >more.c
X/*
X * Copyright (c) 1980 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by the University of California, Berkeley.  The name of the
X * University may not be used to endorse or promote products derived
X * from this software without specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X
X#ifndef lint
Xchar copyright[] =
X"@(#) Copyright (c) 1980 Regents of the University of California.\n\
X All rights reserved.\n";
X#endif /* not lint */
X
X#ifndef lint
Xstatic char sccsid[] = "@(#)more.c	5.19 (Berkeley) 6/29/88";
X#endif /* not lint */
X
X/*
X** more.c - General purpose tty output filter and file perusal program
X**
X**	by Eric Shienbrood, UC Berkeley
X**
X**	modified by Geoff Peck, UCB to add underlining, single spacing
X**	modified by John Foderaro, UCB to add -c and MORE environment variable
X*/
X
X#include <stdio.h>
X#include <ctype.h>
X#include <signal.h>
X#include <errno.h>
X#include <sgtty.h>
X#include <setjmp.h>
X#include <sys/stat.h>
X#ifndef MINIX
X#include <sys/param.h>
X#include <sys/file.h>
X#endif
X#include <a.out.h>
X#include <varargs.h>
X
X#ifdef MINIX
X#include <limits.h>
X#endif MINIX
X
X#define HELPFILE	"/usr/lib/more.help"
X#define VI		"/usr/ucb/vi"
X
X#define Fopen(s,m)	(Currline = 0,file_pos=0,fopen(s,m))
X#define Ftell(f)	file_pos
X#define Fseek(f,off)	(file_pos=off,fseek(f,off,0))
X#define Getc(f)		(++file_pos, getc(f))
X#define Ungetc(c,f)	(--file_pos, ungetc(c,f))
X
X#ifndef TIOCSETN
X#define TIOCSETN	TIOCSETP	/* Minix doesn't have SETN */
X#endif
X#ifndef TBDELAY
X#define TBDELAY		0006000		/* Minix doesn't have TBDELAY */
X#endif
X
X#define MBIT	CBREAK
X#define stty(fd,argp)	ioctl(fd,TIOCSETN,argp)
X
X#define TBUFSIZ	1024
X#define LINSIZ	256
X#define ctrl(letter)	(letter & 077)
X#define RUBOUT	'\177'
X#define ESC	'\033'
X#define QUIT	'\034'
X
Xstruct sgttyb	otty, savetty;
Xlong		file_pos, file_size;
Xint		fnum, no_intty, no_tty, slow_tty;
Xint		dum_opt, dlines, onquit(), end_it(), chgwinsz();
Xint		onsusp();
Xint		nscroll = 11;	/* Number of lines scrolled by 'd' */
Xint		fold_opt = 1;	/* Fold long lines */
Xint		stop_opt = 1;	/* Stop after form feeds */
Xint		ssp_opt = 0;	/* Suppress white space */
Xint		ul_opt = 1;	/* Underline as best we can */
Xint		promptlen;
Xint		Currline;	/* Line we are currently at */
Xint		startup = 1;
Xint		firstf = 1;
Xint		notell = 1;
Xint		docrterase = 0;
Xint		docrtkill = 0;
Xint		bad_so;	/* True if overwriting does not turn off standout */
Xint		inwait, Pause, errors;
Xint		within;	/* true if we are within a file,
X			false if we are between files */
Xint		hard, dumb, noscroll, hardtabs, clreol, eatnl;
Xint		catch_susp;	/* We should catch the SIGTSTP signal */
Xchar		**fnames;	/* The list of file names */
Xint		nfiles;		/* Number of files left to process */
Xchar		*shell;		/* The name of the shell to use */
Xint		shellp;		/* A previous shell command exists */
Xchar		ch;
Xjmp_buf		restore;
Xchar		Line[LINSIZ];	/* Line buffer */
Xint		Lpp = 24;	/* lines per page */
Xchar		*Clear;		/* clear screen */
Xchar		*eraseln;	/* erase line */
Xchar		*Senter, *Sexit;/* enter and exit standout mode */
Xchar		*ULenter, *ULexit;	/* enter and exit underline mode */
Xchar		*chUL;		/* underline character */
Xchar		*chBS;		/* backspace character */
Xchar		*Home;		/* go to home */
Xchar		*cursorm;	/* cursor movement */
Xchar		cursorhome[40];	/* contains cursor movement to home */
Xchar		*EodClr;	/* clear rest of screen */
Xchar		*tgetstr();
Xint		Mcol = 80;	/* number of columns */
Xint		Wrap = 1;	/* set if automargins */
Xint		soglitch;	/* terminal has standout mode glitch */
Xint		ulglitch;	/* terminal has underline mode glitch */
Xint		pstate = 0;	/* current UL state */
Xlong		fseek();
Xchar		*getenv();
Xstruct {
X    long chrctr, line;
X} context, screen_start;
Xextern char	PC;		/* pad character */
Xextern short	ospeed;
X
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X    register FILE	*f;
X    register char	*s;
X    register char	*p;
X    register char	ch;
X    register int	left;
X    int			prnames = 0;
X    int			initopt = 0;
X    int			srchopt = 0;
X    int			clearit = 0;
X    int			initline;
X    char		initbuf[80];
X    FILE		*checkf();
X
X    nfiles = argc;
X    fnames = argv;
X    initterm ();
X    nscroll = Lpp/2 - 1;
X    if (nscroll <= 0)
X	nscroll = 1;
X    if(s = getenv("MORE")) argscan(s);
X    while (--nfiles > 0) {
X	if ((ch = (*++fnames)[0]) == '-') {
X	    argscan(*fnames+1);
X	}
X	else if (ch == '+') {
X	    s = *fnames;
X	    if (*++s == '/') {
X		srchopt++;
X		for (++s, p = initbuf; p < initbuf + 79 && *s != '\0';)
X		    *p++ = *s++;
X		*p = '\0';
X	    }
X	    else {
X		initopt++;
X		for (initline = 0; *s != '\0'; s++)
X		    if (isdigit (*s))
X			initline = initline*10 + *s -'0';
X		--initline;
X	    }
X	}
X	else break;
X    }
X    /* allow clreol only if Home and eraseln and EodClr strings are
X     *  defined, and in that case, make sure we are in noscroll mode
X     */
X    if(clreol)
X    {
X        if((Home == NULL) || (*Home == '\0') ||
X	   (eraseln == NULL) || (*eraseln == '\0') ||
X           (EodClr == NULL) || (*EodClr == '\0') )
X	      clreol = 0;
X	else noscroll = 1;
X    }
X    if (dlines == 0)
X	dlines = Lpp - (noscroll ? 1 : 2);
X    left = dlines;
X    if (nfiles > 1)
X	prnames++;
X    if (!no_intty && nfiles == 0) {
X	char *rindex();
X
X	p = rindex(argv[0], '/');
X	fputs("usage: ",stderr);
X	fputs(p ? p + 1 : argv[0],stderr);
X	fputs(" [-dfln] [+linenum | +/pattern] name1 name2 ...\n",stderr);
X	exit(1);
X    }
X    else
X	f = stdin;
X    if (!no_tty) {
X	signal(SIGQUIT, onquit);
X	signal(SIGINT, end_it);
X#ifdef SIGWINCH
X	signal(SIGWINCH, chgwinsz);
X#endif
X#ifdef SIGTSTP
X	if (signal (SIGTSTP, SIG_IGN) == SIG_DFL) {
X	    signal(SIGTSTP, onsusp);
X	    catch_susp++;
X	}
X#endif SIGTSTP
X	stty (fileno(stderr), &otty);
X    }
X    if (no_intty) {
X	if (no_tty)
X	    copy_file (stdin);
X	else {
X	    if ((ch = Getc (f)) == '\f')
X		doclear();
X	    else {
X		Ungetc (ch, f);
X		if (noscroll && (ch != EOF)) {
X		    if (clreol)
X			home ();
X		    else
X			doclear ();
X		}
X	    }
X	    if (srchopt)
X	    {
X		search (initbuf, stdin, 1);
X		if (noscroll)
X		    left--;
X	    }
X	    else if (initopt)
X		skiplns (initline, stdin);
X	    screen (stdin, left);
X	}
X	no_intty = 0;
X	prnames++;
X	firstf = 0;
X    }
X
X    while (fnum < nfiles) {
X	if ((f = checkf (fnames[fnum], &clearit)) != NULL) {
X	    context.line = context.chrctr = 0;
X	    Currline = 0;
X	    if (firstf) setjmp (restore);
X	    if (firstf) {
X		firstf = 0;
X		if (srchopt)
X		{
X		    search (initbuf, f, 1);
X		    if (noscroll)
X			left--;
X		}
X		else if (initopt)
X		    skiplns (initline, f);
X	    }
X	    else if (fnum < nfiles && !no_tty) {
X		setjmp (restore);
X		left = command (fnames[fnum], f);
X	    }
X	    if (left != 0) {
X		if ((noscroll || clearit) && (file_size != LONG_MAX))
X		    if (clreol)
X			home ();
X		    else
X			doclear ();
X		if (prnames) {
X		    if (bad_so)
X			erase (0);
X		    if (clreol)
X			cleareol ();
X		    pr("::::::::::::::");
X		    if (promptlen > 14)
X			erase (14);
X		    printf ("\n");
X		    if(clreol) cleareol();
X		    printf("%s\n", fnames[fnum]);
X		    if(clreol) cleareol();
X		    printf("::::::::::::::\n");
X		    if (left > Lpp - 4)
X			left = Lpp - 4;
X		}
X		if (no_tty)
X		    copy_file (f);
X		else {
X		    within++;
X		    screen(f, left);
X		    within = 0;
X		}
X	    }
X	    setjmp (restore);
X	    fflush(stdout);
X	    fclose(f);
X	    screen_start.line = screen_start.chrctr = 0L;
X	    context.line = context.chrctr = 0L;
X	}
X	fnum++;
X	firstf = 0;
X    }
X    reset_tty ();
X    exit(0);
X}
X
Xargscan(s)
Xchar *s;
X{
X	int seen_num = 0;
X
X	while (*s != '\0') {
X		switch (*s) {
X		  case '0': case '1': case '2':
X		  case '3': case '4': case '5':
X		  case '6': case '7': case '8':
X		  case '9':
X			if (!seen_num) {
X				dlines = 0;
X				seen_num = 1;
X			}
X			dlines = dlines*10 + *s - '0';
X			break;
X		  case 'd':
X			dum_opt = 1;
X			break;
X		  case 'l':
X			stop_opt = 0;
X			break;
X		  case 'f':
X			fold_opt = 0;
X			break;
X		  case 'p':
X			noscroll++;
X			break;
X		  case 'c':
X			clreol++;
X			break;
X		  case 's':
X			ssp_opt = 1;
X			break;
X		  case 'u':
X			ul_opt = 0;
X			break;
X		}
X		s++;
X	}
X}
X
X
X/*
X** Check whether the file named by fs is an ASCII file which the user may
X** access.  If it is, return the opened file. Otherwise return NULL.
X*/
X
XFILE *
Xcheckf (fs, clearfirst)
X	register char *fs;
X	int *clearfirst;
X{
X	struct stat stbuf;
X	register FILE *f;
X	char c;
X
X	if (stat (fs, &stbuf) == -1) {
X		(void)fflush(stdout);
X		if (clreol)
X			cleareol ();
X		perror(fs);
X		return((FILE *)NULL);
X	}
X	if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
X		printf("\n*** %s: directory ***\n\n", fs);
X		return((FILE *)NULL);
X	}
X	if ((f = Fopen(fs, "r")) == NULL) {
X		(void)fflush(stdout);
X		perror(fs);
X		return((FILE *)NULL);
X	}
X#ifndef MINIX
X	if (magic(f, fs))
X		return((FILE *)NULL);
X#endif !MINIX
X	c = Getc(f);
X	*clearfirst = c == '\f';
X	Ungetc (c, f);
X	if ((file_size = stbuf.st_size) == 0)
X		file_size = LONG_MAX;
X	return(f);
X}
X
X#ifndef MINIX
X/*
X * magic --
X *	check for file magic numbers.  This code would best be shared with
X *	the file(1) program or, perhaps, more should not try and be so smart?
X */
Xstatic
Xmagic(f, fs)
X	FILE *f;
X	char *fs;
X{
X	struct exec ex;
X
X	if (fread(&ex, sizeof(ex), 1, f) == 1)
X		switch(ex.a_magic) {
X		case OMAGIC:
X		case NMAGIC:
X		case ZMAGIC:
X		case 0405:
X		case 0411:
X		case 0177545:
X			printf("\n******** %s: Not a text file ********\n\n", fs);
X			(void)fclose(f);
X			return(1);
X		}
X	(void)fseek(f, 0L, L_SET);		/* rewind() not necessary */
X	return(0);
X}
X#endif !MINIX
X
X/*
X** A real function, for the tputs routine in termlib
X*/
X
Xputch (ch)
Xchar ch;
X{
X    putchar (ch);
X}
X
X/*
X** Print out the contents of the file f, one screenful at a time.
X*/
X
X#define STOP -10
X
Xscreen (f, num_lines)
Xregister FILE *f;
Xregister int num_lines;
X{
X    register int c;
X    register int nchars;
X    int length;			/* length of current line */
X    static int prev_len = 1;	/* length of previous line */
X
X    for (;;) {
X	while (num_lines > 0 && !Pause) {
X	    if ((nchars = getline (f, &length)) == EOF)
X	    {
X		if (clreol)
X		    clreos();
X		return;
X	    }
X	    if (ssp_opt && length == 0 && prev_len == 0)
X		continue;
X	    prev_len = length;
X	    if (bad_so || (Senter && *Senter == ' ') && promptlen > 0)
X		erase (0);
X	    /* must clear before drawing line since tabs on some terminals
X	     * do not erase what they tab over.
X	     */
X	    if (clreol)
X		cleareol ();
X	    prbuf (Line, length);
X	    if (nchars < promptlen)
X		erase (nchars);	/* erase () sets promptlen to 0 */
X	    else promptlen = 0;
X	    /* is this needed?
X	     * if (clreol)
X	     *	cleareol();	/* must clear again in case we wrapped *
X	     */
X	    if (nchars < Mcol || !fold_opt)
X		prbuf("\n", 1);	/* will turn off UL if necessary */
X	    if (nchars == STOP)
X		break;
X	    num_lines--;
X	}
X	if (pstate) {
X		tputs(ULexit, 1, putch);
X		pstate = 0;
X	}
X	fflush(stdout);
X	if ((c = Getc(f)) == EOF)
X	{
X	    if (clreol)
X		clreos ();
X	    return;
X	}
X
X	if (Pause && clreol)
X	    clreos ();
X	Ungetc (c, f);
X	setjmp (restore);
X	Pause = 0; startup = 0;
X	if ((num_lines = command (NULL, f)) == 0)
X	    return;
X	if (hard && promptlen > 0)
X		erase (0);
X	if (noscroll && num_lines >= dlines)
X	{
X	    if (clreol)
X		home();
X	    else
X		doclear ();
X	}
X	screen_start.line = Currline;
X	screen_start.chrctr = Ftell (f);
X    }
X}
X
X/*
X** Come here if a quit signal is received
X*/
X
Xonquit()
X{
X    signal(SIGQUIT, SIG_IGN);
X    if (!inwait) {
X	putchar ('\n');
X	if (!startup) {
X	    signal(SIGQUIT, onquit);
X	    longjmp (restore, 1);
X	}
X	else
X	    Pause++;
X    }
X    else if (!dum_opt && notell) {
X	write (2, "[Use q or Q to quit]", 20);
X	promptlen += 20;
X	notell = 0;
X    }
X    signal(SIGQUIT, onquit);
X}
X
X#ifdef SIGWINCH
X/*
X** Come here if a signal for a window size change is received
X*/
X
Xchgwinsz()
X{
X    struct winsize win;
X
X    (void) signal(SIGWINCH, SIG_IGN);
X    if (ioctl(fileno(stdout), TIOCGWINSZ, &win) != -1) {
X	if (win.ws_row != 0) {
X	    Lpp = win.ws_row;
X	    nscroll = Lpp/2 - 1;
X	    if (nscroll <= 0)
X		nscroll = 1;
X	    dlines = Lpp - (noscroll ? 1 : 2);
X	}
X	if (win.ws_col != 0)
X	    Mcol = win.ws_col;
X    }
X    (void) signal(SIGWINCH, chgwinsz);
X}
X#endif SIGWINCH
X
X/*
X** Clean up terminal state and exit. Also come here if interrupt signal received
X*/
X
Xend_it ()
X{
X
X    reset_tty ();
X    if (clreol) {
X	putchar ('\r');
X	clreos ();
X	fflush (stdout);
X    }
X    else if (!clreol && (promptlen > 0)) {
X	kill_line ();
X	fflush (stdout);
X    }
X    else
X	write (2, "\n", 1);
X    _exit(0);
X}
X
Xcopy_file(f)
Xregister FILE *f;
X{
X    register int c;
X
X    while ((c = getc(f)) != EOF)
X	putchar(c);
X}
X
X/* Simplified printf function */
X
Xprintf (fmt, va_alist)
Xregister char *fmt;
Xva_dcl
X{
X	va_list ap;
X	register char ch;
X	register int ccount;
X
X	ccount = 0;
X	va_start(ap);
X	while (*fmt) {
X		while ((ch = *fmt++) != '%') {
X			if (ch == '\0')
X				return (ccount);
X			ccount++;
X			putchar (ch);
X		}
X		switch (*fmt++) {
X		case 'd':
X			ccount += printd (va_arg(ap, int));
X			break;
X		case 's':
X			ccount += pr (va_arg(ap, char *));
X			break;
X		case '%':
X			ccount++;
X			putchar ('%');
X			break;
X		case '0':
X			return (ccount);
X		default:
X			break;
X		}
X	}
X	va_end(ap);
X	return (ccount);
X
X}
X
X/*
X** Print an integer as a string of decimal digits,
X** returning the length of the print representation.
X*/
X
Xprintd (n)
Xint n;
X{
X    int a, nchars;
X
X    if (a = n/10)
X	nchars = 1 + printd(a);
X    else
X	nchars = 1;
X    putchar (n % 10 + '0');
X    return (nchars);
X}
X
X/* Put the print representation of an integer into a string */
Xstatic char *sptr;
X
Xscanstr (n, str)
Xint n;
Xchar *str;
X{
X    sptr = str;
X    Sprintf (n);
X    *sptr = '\0';
X}
X
XSprintf (n)
X{
X    int a;
X
X    if (a = n/10)
X	Sprintf (a);
X    *sptr++ = n % 10 + '0';
X}
X
Xstatic char bell = ctrl('G');
X
Xstrlen (s)
Xchar *s;
X{
X    register char *p;
X
X    p = s;
X    while (*p++)
X	;
X    return (p - s - 1);
X}
X
X/* See whether the last component of the path name "path" is equal to the
X** string "string"
X*/
X
Xtailequ (path, string)
Xchar *path;
Xregister char *string;
X{
X	register char *tail;
X
X	tail = path + strlen(path);
X	while (tail >= path)
X		if (*(--tail) == '/')
X			break;
X	++tail;
X	while (*tail++ == *string++)
X		if (*tail == '\0')
X			return(1);
X	return(0);
X}
X
Xprompt (filename)
Xchar *filename;
X{
X    if (clreol)
X	cleareol ();
X    else if (promptlen > 0)
X	kill_line ();
X    if (!hard) {
X	promptlen = 8;
X	if (Senter && Sexit) {
X	    tputs (Senter, 1, putch);
X	    promptlen += (2 * soglitch);
X	}
X	if (clreol)
X	    cleareol ();
X	pr("--More--");
X	if (filename != NULL) {
X	    promptlen += printf ("(Next file: %s)", filename);
X	}
X	else if (!no_intty) {
X	    promptlen += printf ("(%d%%)", (int)((file_pos * 100) / file_size));
X	}
X	if (dum_opt) {
X	    promptlen += pr("[Press space to continue, 'q' to quit.]");
X	}
X	if (Senter && Sexit)
X	    tputs (Sexit, 1, putch);
X	if (clreol)
X	    clreos ();
X	fflush(stdout);
X    }
X    else
X	write (2, &bell, 1);
X    inwait++;
X}
X
X/*
X** Get a logical line
X*/
X
Xgetline(f, length)
Xregister FILE *f;
Xint *length;
X{
X    register int	c;
X    register char	*p;
X    register int	column;
X    static int		colflg;
X
X    p = Line;
X    column = 0;
X    c = Getc (f);
X    if (colflg && c == '\n') {
X	Currline++;
X	c = Getc (f);
X    }
X    while (p < &Line[LINSIZ - 1]) {
X	if (c == EOF) {
X	    if (p > Line) {
X		*p = '\0';
X		*length = p - Line;
X		return (column);
X	    }
X	    *length = p - Line;
X	    return (EOF);
X	}
X	if (c == '\n') {
X	    Currline++;
X	    break;
X	}
X	*p++ = c;
X	if (c == '\t')
X	    if (!hardtabs || column < promptlen && !hard) {
X		if (hardtabs && eraseln && !dumb) {
X		    column = 1 + (column | 7);
X		    tputs (eraseln, 1, putch);
X		    promptlen = 0;
X		}
X		else {
X		    for (--p; p < &Line[LINSIZ - 1];) {
X			*p++ = ' ';
X			if ((++column & 7) == 0)
X			    break;
X		    }
X		    if (column >= promptlen) promptlen = 0;
X		}
X	    }
X	    else
X		column = 1 + (column | 7);
X	else if (c == '\b' && column > 0)
X	    column--;
X	else if (c == '\r')
X	    column = 0;
X	else if (c == '\f' && stop_opt) {
X		p[-1] = '^';
X		*p++ = 'L';
X		column += 2;
X		Pause++;
X	}
X	else if (c == EOF) {
X	    *length = p - Line;
X	    return (column);
X	}
X	else if (c >= ' ' && c != RUBOUT)
X	    column++;
X	if (column >= Mcol && fold_opt) break;
X	c = Getc (f);
X    }
X    if (column >= Mcol && Mcol > 0) {
X	if (!Wrap) {
X	    *p++ = '\n';
X	}
X    }
X    colflg = column == Mcol && fold_opt;
X    if (colflg && eatnl && Wrap) {
X	*p++ = '\n'; /* simulate normal wrap */
X    }
X    *length = p - Line;
X    *p = 0;
X    return (column);
X}
X
X/*
X** Erase the rest of the prompt, assuming we are starting at column col.
X*/
X
Xerase (col)
Xregister int col;
X{
X
X    if (promptlen == 0)
X	return;
X    if (hard) {
X	putchar ('\n');
X    }
X    else {
X	if (col == 0)
X	    putchar ('\r');
X	if (!dumb && eraseln)
X	    tputs (eraseln, 1, putch);
X	else
X	    for (col = promptlen - col; col > 0; col--)
X		putchar (' ');
X    }
X    promptlen = 0;
X}
X
X/*
X** Erase the current line entirely
X*/
X
Xkill_line ()
X{
X    erase (0);
X    if (!eraseln || dumb) putchar ('\r');
X}
X
X/*
X * force clear to end of line
X */
Xcleareol()
X{
X    tputs(eraseln, 1, putch);
X}
X
Xclreos()
X{
X    tputs(EodClr, 1, putch);
X}
X
X/*
X**  Print string and return number of characters
X*/
X
Xpr(s1)
Xchar	*s1;
X{
X    register char	*s;
X    register char	c;
X
X    for (s = s1; c = *s++; )
X	putchar(c);
X    return (s - s1 - 1);
X}
X
X
X/* Print a buffer of n characters */
X
Xprbuf (s, n)
Xregister char *s;
Xregister int n;
X{
X    register char c;			/* next output character */
X    register int state;			/* next output char's UL state */
X#define wouldul(s,n)	((n) >= 2 && (((s)[0] == '_' && (s)[1] == '\b') || ((s)[1] == '\b' && (s)[2] == '_')))
X
X    while (--n >= 0)
X	if (!ul_opt)
X	    putchar (*s++);
X	else {
X	    if (*s == ' ' && pstate == 0 && ulglitch && wouldul(s+1, n-1)) {
X		s++;
X		continue;
X	    }
X	    if (state = wouldul(s, n)) {
X		c = (*s == '_')? s[2] : *s ;
X		n -= 2;
X		s += 3;
X	    } else
X		c = *s++;
X	    if (state != pstate) {
X		if (c == ' ' && state == 0 && ulglitch && wouldul(s, n-1))
X		    state = 1;
X		else
X		    tputs(state ? ULenter : ULexit, 1, putch);
X	    }
X	    if (c != ' ' || pstate == 0 || state != 0 || ulglitch == 0)
X	        putchar(c);
X	    if (state && *chUL) {
X		pr(chBS);
X		tputs(chUL, 1, putch);
X	    }
X	    pstate = state;
X	}
X}
X
X/*
X**  Clear the screen
X*/
X
Xdoclear()
X{
X    if (Clear && !hard) {
X	tputs(Clear, 1, putch);
X
X	/* Put out carriage return so that system doesn't
X	** get confused by escape sequences when expanding tabs
X	*/
X	putchar ('\r');
X	promptlen = 0;
X    }
X}
X
X/*
X * Go to home position
X */
Xhome()
X{
X    tputs(Home,1,putch);
X}
X
Xstatic int lastcmd, lastarg, lastp;
Xstatic int lastcolon;
Xchar shell_line[132];
X
X/*
X** Read a command and do it. A command consists of an optional integer
X** argument followed by the command character.  Return the number of lines
X** to display in the next screenful.  If there is nothing more to display
X** in the current file, zero is returned.
X*/
X
Xcommand (filename, f)
Xchar *filename;
Xregister FILE *f;
X{
X    register int nlines;
X    register int retval;
X    register char c;
X    char colonch;
X    FILE *helpf;
X    int done;
X    char comchar, cmdbuf[80], *p;
X
X#define ret(val) retval=val;done++;break
X
X    done = 0;
X    if (!errors)
X	prompt (filename);
X    else
X	errors = 0;
X    if (MBIT == RAW && slow_tty) {
X	otty.sg_flags |= MBIT;
X	stty(fileno(stderr), &otty);
X    }
X    for (;;) {
X	nlines = number (&comchar);
X	lastp = colonch = 0;
X	if (comchar == '.') {	/* Repeat last command */
X		lastp++;
X		comchar = lastcmd;
X		nlines = lastarg;
X		if (lastcmd == ':')
X			colonch = lastcolon;
X	}
X	lastcmd = comchar;
X	lastarg = nlines;
X	if (comchar == otty.sg_erase) {
X	    kill_line ();
X	    prompt (filename);
X	    continue;
X	}
X	switch (comchar) {
X	case ':':
X	    retval = colon (filename, colonch, nlines);
X	    if (retval >= 0)
X		done++;
X	    break;
X	case 'b':
X	case ctrl('B'):
X	    {
X		register int initline;
X
X		if (no_intty) {
X		    write(2, &bell, 1);
X		    return (-1);
X		}
X
X		if (nlines == 0) nlines++;
X
X		putchar ('\r');
X		erase (0);
X		printf ("\n");
X		if (clreol)
X			cleareol ();
X		printf ("...back %d page", nlines);
X		if (nlines > 1)
X			pr ("s\n");
X		else
X			pr ("\n");
X
X		if (clreol)
X			cleareol ();
X		pr ("\n");
X
X		initline = Currline - dlines * (nlines + 1);
X		if (! noscroll)
X		    --initline;
X		if (initline < 0) initline = 0;
X		Fseek(f, 0L);
X		Currline = 0;	/* skiplns() will make Currline correct */
X		skiplns(initline, f);
X		if (! noscroll) {
X		    ret(dlines + 1);
X		}
X		else {
X		    ret(dlines);
X		}
X	    }
X	case ' ':
X	case 'z':
X	    if (nlines == 0) nlines = dlines;
X	    else if (comchar == 'z') dlines = nlines;
X	    ret (nlines);
X	case 'd':
X	case ctrl('D'):
X	    if (nlines != 0) nscroll = nlines;
X	    ret (nscroll);
X	case 'q':
X	case 'Q':
X	    end_it ();
X	case 's':
X	case 'f':
X	    if (nlines == 0) nlines++;
X	    if (comchar == 'f')
X		nlines *= dlines;
X	    putchar ('\r');
X	    erase (0);
X	    printf ("\n");
X	    if (clreol)
X		cleareol ();
X	    printf ("...skipping %d line", nlines);
X	    if (nlines > 1)
X		pr ("s\n");
X	    else
X		pr ("\n");
X
X	    if (clreol)
X		cleareol ();
X	    pr ("\n");
X
X	    while (nlines > 0) {
X		while ((c = Getc (f)) != '\n')
X		    if (c == EOF) {
X			retval = 0;
X			done++;
X			goto endsw;
X		    }
X		    Currline++;
X		    nlines--;
X	    }
X	    ret (dlines);
X	case '\n':
X	    if (nlines != 0)
X		dlines = nlines;
X	    else
X		nlines = 1;
X	    ret (nlines);
X	case '\f':
X	    if (!no_intty) {
X		doclear ();
X		Fseek (f, screen_start.chrctr);
X		Currline = screen_start.line;
X		ret (dlines);
X	    }
X	    else {
X		write (2, &bell, 1);
X		break;
X	    }
X	case '\'':
X	    if (!no_intty) {
X		kill_line ();
X		pr ("\n***Back***\n\n");
X		Fseek (f, context.chrctr);
X		Currline = context.line;
X		ret (dlines);
X	    }
X	    else {
X		write (2, &bell, 1);
X		break;
X	    }
X	case '=':
X	    kill_line ();
X	    promptlen = printd (Currline);
X	    fflush (stdout);
X	    break;
X	case 'n':
X	    lastp++;
X	case '/':
X	    if (nlines == 0) nlines++;
X	    kill_line ();
X	    pr ("/");
X	    promptlen = 1;
X	    fflush (stdout);
X	    if (lastp) {
X		write (2,"\r", 1);
X		search (NULL, f, nlines);	/* Use previous r.e. */
X	    }
X	    else {
X		ttyin (cmdbuf, 78, '/');
X		write (2, "\r", 1);
X		search (cmdbuf, f, nlines);
X	    }
X	    ret (dlines-1);
X	case '!':
X	    do_shell (filename);
X	    break;
X	case '?':
X	case 'h':
X	    if ((helpf = fopen (HELPFILE, "r")) == NULL)
X		error ("Can't open help file");
X	    if (noscroll) doclear ();
X	    copy_file (helpf);
X	    fclose (helpf);
X	    prompt (filename);
X	    break;
X	case 'v':	/* This case should go right before default */
X	    if (!no_intty) {
X		kill_line ();
X		cmdbuf[0] = '+';
X		scanstr (Currline - dlines < 0 ? 0
X				: Currline - (dlines + 1) / 2, &cmdbuf[1]);
X		pr ("vi "); pr (cmdbuf); putchar (' '); pr (fnames[fnum]);
X		execute (filename, VI, "vi", cmdbuf, fnames[fnum], 0);
X		break;
X	    }
X	default:
X	    if (dum_opt) {
X   		kill_line ();
X		if (Senter && Sexit) {
X		    tputs (Senter, 1, putch);
X		    promptlen = pr ("[Press 'h' for instructions.]") + (2 * soglitch);
X		    tputs (Sexit, 1, putch);
X		}
X		else
X		    promptlen = pr ("[Press 'h' for instructions.]");
X		fflush (stdout);
X	    }
X	    else
X		write (2, &bell, 1);
X	    break;
X	}
X	if (done) break;
X    }
X    putchar ('\r');
Xendsw:
X    inwait = 0;
X    notell++;
X    if (MBIT == RAW && slow_tty) {
X	otty.sg_flags &= ~MBIT;
X	stty(fileno(stderr), &otty);
X    }
X    return (retval);
X}
X
Xchar ch;
X
X/*
X * Execute a colon-prefixed command.
X * Returns <0 if not a command that should cause
X * more of the file to be printed.
X */
X
Xcolon (filename, cmd, nlines)
Xchar *filename;
Xint cmd;
Xint nlines;
X{
X	if (cmd == 0)
X		ch = readch ();
X	else
X		ch = cmd;
X	lastcolon = ch;
X	switch (ch) {
X	case 'f':
X		kill_line ();
X		if (!no_intty)
X			promptlen = printf ("\"%s\" line %d", fnames[fnum], Currline);
X		else
X			promptlen = printf ("[Not a file] line %d", Currline);
X		fflush (stdout);
X		return (-1);
X	case 'n':
X		if (nlines == 0) {
X			if (fnum >= nfiles - 1)
X				end_it ();
X			nlines++;
X		}
X		putchar ('\r');
X		erase (0);
X		skipf (nlines);
X		return (0);
X	case 'p':
X		if (no_intty) {
X			write (2, &bell, 1);
X			return (-1);
X		}
X		putchar ('\r');
X		erase (0);
X		if (nlines == 0)
X			nlines++;
X		skipf (-nlines);
X		return (0);
X	case '!':
X		do_shell (filename);
X		return (-1);
X	case 'q':
X	case 'Q':
X		end_it ();
X	default:
X		write (2, &bell, 1);
X		return (-1);
X	}
X}
X
X/*
X** Read a decimal number from the terminal. Set cmd to the non-digit which
X** terminates the number.
X*/
X
Xnumber(cmd)
Xchar *cmd;
X{
X	register int i;
X
X	i = 0; ch = otty.sg_kill;
X	for (;;) {
X		ch = readch ();
X		if (ch >= '0' && ch <= '9')
X			i = i*10 + ch - '0';
X		else if (ch == otty.sg_kill)
X			i = 0;
X		else {
X			*cmd = ch;
X			break;
X		}
X	}
X	return (i);
X}
X
Xdo_shell (filename)
Xchar *filename;
X{
X	char cmdbuf[80];
X
X	kill_line ();
X	pr ("!");
X	fflush (stdout);
X	promptlen = 1;
X	if (lastp)
X		pr (shell_line);
X	else {
X		ttyin (cmdbuf, 78, '!');
X		if (expand (shell_line, cmdbuf)) {
X			kill_line ();
X			promptlen = printf ("!%s", shell_line);
X		}
X	}
X	fflush (stdout);
X	write (2, "\n", 1);
X	promptlen = 0;
X	shellp = 1;
X	execute (filename, shell, shell, "-c", shell_line, 0);
X}
X
X/*
X** Search for nth ocurrence of regular expression contained in buf in the file
X*/
X
Xsearch (buf, file, n)
Xchar buf[];
XFILE *file;
Xregister int n;
X{
X    long startline = Ftell (file);
X    register long line1 = startline;
X    register long line2 = startline;
X    register long line3 = startline;
X    register int lncount;
X    int saveln, rv, re_exec();
X    char *s, *re_comp();
X
X    context.line = saveln = Currline;
X    context.chrctr = startline;
X    lncount = 0;
X    if ((s = re_comp (buf)) != 0)
X	error (s);
X    while (!feof (file)) {
X	line3 = line2;
X	line2 = line1;
X	line1 = Ftell (file);
X	rdline (file);
X	lncount++;
X	if ((rv = re_exec (Line)) == 1)
X		if (--n == 0) {
X		    if (lncount > 3 || (lncount > 1 && no_intty))
X		    {
X			pr ("\n");
X			if (clreol)
X			    cleareol ();
X			pr("...skipping\n");
X		    }
X		    if (!no_intty) {
X			Currline -= (lncount >= 3 ? 3 : lncount);
X			Fseek (file, line3);
X			if (noscroll)
X			    if (clreol) {
X				home ();
X				cleareol ();
X			    }
X			    else
X				doclear ();
X		    }
X		    else {
X			kill_line ();
X			if (noscroll)
X			    if (clreol) {
X			        home ();
X			        cleareol ();
X			    }
X			    else
X				doclear ();
X			pr (Line);
X			putchar ('\n');
X		    }
X		    break;
X		}
X	else if (rv == -1)
X	    error ("Regular expression botch");
X    }
X    if (feof (file)) {
X	if (!no_intty) {
X	    Currline = saveln;
X	    Fseek (file, startline);
X	}
X	else {
X	    pr ("\nPattern not found\n");
X	    end_it ();
X	}
X	error ("Pattern not found");
X    }
X}
X
X/*VARARGS2*/
Xexecute (filename, cmd, va_alist)
Xchar *filename;
Xchar *cmd;
Xva_dcl
X{
X	int id;
X	int n;
X	va_list argp;
X
X	fflush (stdout);
X	reset_tty ();
X	for (n = 10; (id = fork ()) < 0 && n > 0; n--)
X	    sleep (5);
X	if (id == 0) {
X	    if (!isatty(0)) {
X		close(0);
X		open("/dev/tty", 0);
X	    }
X	    va_start(argp);
X	    execv (cmd, argp);
X	    write (2, "exec failed\n", 12);
X	    exit (1);
X	    va_end(argp);	/* balance {}'s for some UNIX's */
X	}
X	if (id > 0) {
X	    signal (SIGINT, SIG_IGN);
X	    signal (SIGQUIT, SIG_IGN);
X#ifdef SIGTSTP
X	    if (catch_susp)
X		signal(SIGTSTP, SIG_DFL);
X#endif SIGTSTP
X	    while (wait(0) > 0);
X	    signal (SIGINT, end_it);
X	    signal (SIGQUIT, onquit);
X#ifdef SIGTSTP
X	    if (catch_susp)
X		signal(SIGTSTP, onsusp);
X#endif SIGTSTP
X	} else
X	    write(2, "can't fork\n", 11);
X	set_tty ();
X	pr ("------------------------\n");
X	prompt (filename);
X}
X/*
X** Skip n lines in the file f
X*/
X
Xskiplns (n, f)
Xregister int n;
Xregister FILE *f;
X{
X    register char c;
X
X    while (n > 0) {
X	while ((c = Getc (f)) != '\n')
X	    if (c == EOF)
X		return;
X	    n--;
X	    Currline++;
X    }
X}
X
X/*
X** Skip nskip files in the file list (from the command line). Nskip may be
X** negative.
X*/
X
Xskipf (nskip)
Xregister int nskip;
X{
X    if (nskip == 0) return;
X    if (nskip > 0) {
X	if (fnum + nskip > nfiles - 1)
X	    nskip = nfiles - fnum - 1;
X    }
X    else if (within)
X	++fnum;
X    fnum += nskip;
X    if (fnum < 0)
X	fnum = 0;
X    pr ("\n...Skipping ");
X    pr ("\n");
X    if (clreol)
X	cleareol ();
X    pr ("...Skipping ");
X    pr (nskip > 0 ? "to file " : "back to file ");
X    pr (fnames[fnum]);
X    pr ("\n");
X    if (clreol)
X	cleareol ();
X    pr ("\n");
X    --fnum;
X}
X
X/*----------------------------- Terminal I/O -------------------------------*/
X
Xinitterm ()
X{
X    char	buf[TBUFSIZ];
X    static char	clearbuf[TBUFSIZ];
X    char	*clearptr, *padstr;
X    int		ldisc;
X    int		lmode;
X    char	*term;
X    int		tgrp;
X#ifdef TIOCGWINSZ
X    struct winsize win;
X#endif
X
Xretry:
X    if (!(no_tty = gtty(fileno(stdout), &otty))) {
X#ifdef TIOCLGET
X	if (ioctl(fileno(stdout), TIOCLGET, &lmode) < 0) {
X	    perror("TIOCLGET");
X	    exit(1);
X	}
X
X	docrterase = ((lmode & LCRTERA) != 0);
X	docrtkill = ((lmode & LCRTKIL) != 0);
X#endif TIOCLGET
X#ifdef TIOCGPGRP
X	/*
X	 * Wait until we're in the foreground before we save the
X	 * the terminal modes.
X	 */
X	if (ioctl(fileno(stdout), TIOCGPGRP, &tgrp) < 0) {
X	    perror("TIOCGPGRP");
X	    exit(1);
X	}
X	if (tgrp != getpgrp(0)) {
X	    kill(0, SIGTTOU);
X	    goto retry;
X	}
X#endif TIOCGPGRP
X	if ((term = getenv("TERM")) == 0 || tgetent(buf, term) <= 0) {
X	    dumb++; ul_opt = 0;
X	}
X	else {
X#ifdef TIOCGWINSZ
X	    if (ioctl(fileno(stdout), TIOCGWINSZ, &win) < 0) {
X		Lpp = tgetnum("li");
X		Mcol = tgetnum("co");
X	    } else {
X		if ((Lpp = win.ws_row) == 0)
X		    Lpp = tgetnum("li");
X		if ((Mcol = win.ws_col) == 0)
X		    Mcol = tgetnum("co");
X	    }
X#else
X	    Lpp = tgetnum("li");
X	    Mcol = tgetnum("co");
X#endif TIOCGWINSZ
X	    if ((Lpp <= 0) || tgetflag("hc")) {
X		hard++;	/* Hard copy terminal */
X		Lpp = 24;
X	    }
X	    if (tgetflag("xn"))
X		eatnl++; /* Eat newline at last column + 1; dec, concept */
X	    if (Mcol <= 0)
X		Mcol = 80;
X
X	    if (tailequ (fnames[0], "page") || !hard && tgetflag("ns"))
X		noscroll++;
X	    Wrap = tgetflag("am");
X	    bad_so = tgetflag ("xs");
X	    clearptr = clearbuf;
X	    eraseln = tgetstr("ce",&clearptr);
X	    Clear = tgetstr("cl", &clearptr);
X	    Senter = tgetstr("so", &clearptr);
X	    Sexit = tgetstr("se", &clearptr);
X	    if ((soglitch = tgetnum("sg")) < 0)
X		soglitch = 0;
X
X	    /*
X	     *  Set up for underlining:  some terminals don't need it;
X	     *  others have start/stop sequences, still others have an
X	     *  underline char sequence which is assumed to move the
X	     *  cursor forward one character.  If underline sequence
X	     *  isn't available, settle for standout sequence.
X	     */
X
X	    if (tgetflag("ul") || tgetflag("os"))
X		ul_opt = 0;
X	    if ((chUL = tgetstr("uc", &clearptr)) == NULL )
X		chUL = "";
X	    if (((ULenter = tgetstr("us", &clearptr)) == NULL ||
X	         (ULexit = tgetstr("ue", &clearptr)) == NULL) && !*chUL) {
X	        if ((ULenter = Senter) == NULL || (ULexit = Sexit) == NULL) {
X			ULenter = "";
X			ULexit = "";
X		} else
X			ulglitch = soglitch;
X	    } else {
X		if ((ulglitch = tgetnum("ug")) < 0)
X		    ulglitch = 0;
X	    }
X
X	    if (padstr = tgetstr("pc", &clearptr))
X		PC = *padstr;
X	    Home = tgetstr("ho",&clearptr);
X	    if (Home == 0 || *Home == '\0')
X	    {
X		if ((cursorm = tgetstr("cm", &clearptr)) != NULL) {
X		    strcpy(cursorhome, tgoto(cursorm, 0, 0));
X		    Home = cursorhome;
X	       }
X	    }
X	    EodClr = tgetstr("cd", &clearptr);
X	    if ((chBS = tgetstr("bc", &clearptr)) == NULL)
X		chBS = "\b";
X
X	}
X	if ((shell = getenv("SHELL")) == NULL)
X	    shell = "/bin/sh";
X    }
X    no_intty = gtty(fileno(stdin), &otty);
X    gtty(fileno(stderr), &otty);
X    savetty = otty;
X    ospeed = otty.sg_ospeed;
X    slow_tty = ospeed < B1200;
X    hardtabs = (otty.sg_flags & TBDELAY) != XTABS;
X    if (!no_tty) {
X	otty.sg_flags &= ~ECHO;
X	if (MBIT == CBREAK || !slow_tty)
X	    otty.sg_flags |= MBIT;
X    }
X}
X
Xreadch ()
X{
X	char ch;
X	extern int errno;
X
X	errno = 0;
X	if (read (2, &ch, 1) <= 0)
X		if (errno != EINTR)
X			end_it();
X		else
X			ch = otty.sg_kill;
X	return (ch);
X}
X
Xstatic char BS = '\b';
Xstatic char *BSB = "\b \b";
Xstatic char CARAT = '^';
X#define ERASEONECHAR \
X    if (docrterase) \
X	write (2, BSB, sizeof(BSB)); \
X    else \
X	write (2, &BS, sizeof(BS));
X
Xttyin (buf, nmax, pchar)
Xchar buf[];
Xregister int nmax;
Xchar pchar;
X{
X    register char *sptr;
X    register char ch;
X    register int slash = 0;
X    int	maxlen;
X    char cbuf;
X
X    sptr = buf;
X    maxlen = 0;
X    while (sptr - buf < nmax) {
X	if (promptlen > maxlen) maxlen = promptlen;
X	ch = readch ();
X	if (ch == '\\') {
X	    slash++;
X	}
X	else if ((ch == otty.sg_erase) && !slash) {
X	    if (sptr > buf) {
X		--promptlen;
X		ERASEONECHAR
X		--sptr;
X		if ((*sptr < ' ' && *sptr != '\n') || *sptr == RUBOUT) {
X		    --promptlen;
X		    ERASEONECHAR
X		}
X		continue;
X	    }
X	    else {
X		if (!eraseln) promptlen = maxlen;
X		longjmp (restore, 1);
X	    }
X	}
X	else if ((ch == otty.sg_kill) && !slash) {
X	    if (hard) {
X		show (ch);
X		putchar ('\n');
X		putchar (pchar);
X	    }
X	    else {
X		putchar ('\r');
X		putchar (pchar);
X		if (eraseln)
X		    erase (1);
X		else if (docrtkill)
X		    while (promptlen-- > 1)
X			write (2, BSB, sizeof(BSB));
X		promptlen = 1;
X	    }
X	    sptr = buf;
X	    fflush (stdout);
X	    continue;
X	}
X	if (slash && (ch == otty.sg_kill || ch == otty.sg_erase)) {
X	    ERASEONECHAR
X	    --sptr;
X	}
X	if (ch != '\\')
X	    slash = 0;
X	*sptr++ = ch;
X	if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) {
X	    ch += ch == RUBOUT ? -0100 : 0100;
X	    write (2, &CARAT, 1);
X	    promptlen++;
X	}
X	cbuf = ch;
X	if (ch != '\n' && ch != ESC) {
X	    write (2, &cbuf, 1);
X	    promptlen++;
X	}
X	else
X	    break;
X    }
X    *--sptr = '\0';
X    if (!eraseln) promptlen = maxlen;
X    if (sptr - buf >= nmax - 1)
X	error ("Line too long");
X}
X
Xexpand (outbuf, inbuf)
Xchar *outbuf;
Xchar *inbuf;
X{
X    register char *instr;
X    register char *outstr;
X    register char ch;
X    char temp[200];
X    int changed = 0;
X
X    instr = inbuf;
X    outstr = temp;
X    while ((ch = *instr++) != '\0')
X	switch (ch) {
X	case '%':
X	    if (!no_intty) {
X		strcpy (outstr, fnames[fnum]);
X		outstr += strlen (fnames[fnum]);
X		changed++;
X	    }
X	    else
X		*outstr++ = ch;
X	    break;
X	case '!':
X	    if (!shellp)
X		error ("No previous command to substitute for");
X	    strcpy (outstr, shell_line);
X	    outstr += strlen (shell_line);
X	    changed++;
X	    break;
X	case '\\':
X	    if (*instr == '%' || *instr == '!') {
X		*outstr++ = *instr++;
X		break;
X	    }
X	default:
X	    *outstr++ = ch;
X	}
X    *outstr++ = '\0';
X    strcpy (outbuf, temp);
X    return (changed);
X}
X
Xshow (ch)
Xregister char ch;
X{
X    char cbuf;
X
X    if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) {
X	ch += ch == RUBOUT ? -0100 : 0100;
X	write (2, &CARAT, 1);
X	promptlen++;
X    }
X    cbuf = ch;
X    write (2, &cbuf, 1);
X    promptlen++;
X}
X
Xerror (mess)
Xchar *mess;
X{
X    if (clreol)
X	cleareol ();
X    else
X	kill_line ();
X    promptlen += strlen (mess);
X    if (Senter && Sexit) {
X	tputs (Senter, 1, putch);
X	pr(mess);
X	tputs (Sexit, 1, putch);
X    }
X    else
X	pr (mess);
X    fflush(stdout);
X    errors++;
X    longjmp (restore, 1);
X}
X
X
Xset_tty ()
X{
X	otty.sg_flags |= MBIT;
X	otty.sg_flags &= ~ECHO;
X	stty(fileno(stderr), &otty);
X}
X
Xreset_tty ()
X{
X    if (no_tty)
X	return;
X    if (pstate) {
X	tputs(ULexit, 1, putch);
X	fflush(stdout);
X	pstate = 0;
X    }
X    otty.sg_flags |= ECHO;
X    otty.sg_flags &= ~MBIT;
X    stty(fileno(stderr), &savetty);
X}
X
Xrdline (f)
Xregister FILE *f;
X{
X    register char c;
X    register char *p;
X
X    p = Line;
X    while ((c = Getc (f)) != '\n' && c != EOF && p - Line < LINSIZ - 1)
X	*p++ = c;
X    if (c == '\n')
X	Currline++;
X    *p = '\0';
X}
X
X/* Come here when we get a suspend signal from the terminal */
X
X#ifdef SIGTSTP
Xonsusp ()
X{
X    /* ignore SIGTTOU so we don't get stopped if csh grabs the tty */
X    signal(SIGTTOU, SIG_IGN);
X    reset_tty ();
X    fflush (stdout);
X    signal(SIGTTOU, SIG_DFL);
X    /* Send the TSTP signal to suspend our process group */
X    signal(SIGTSTP, SIG_DFL);
X    sigsetmask(0);
X    kill (0, SIGTSTP);
X    /* Pause for station break */
X
X    /* We're back */
X    signal (SIGTSTP, onsusp);
X    set_tty ();
X    if (inwait)
X	    longjmp (restore);
X}
X#endif SIGTSTP
**-more.c-EOF-**
echo 'x - more.help'
sed 's/^X//' <<'**-more.help-EOF-**' >more.help
X
XMost commands optionally preceded by integer argument k.  Defaults in brackets.
XStar (*) indicates argument becomes new default.
X-------------------------------------------------------------------------------
X<space>			Display next k lines of text [current screen size]
Xz			Display next k lines of text [current screen size]*
X<return>		Display next k lines of text [1]*
Xd or ctrl-D		Scroll k lines [current scroll size, initially 11]*
Xq or Q or <interrupt>	Exit from more
Xs			Skip forward k lines of text [1]
Xf			Skip forward k screenfuls of text [1]
Xb or ctrl-B		Skip backwards k screenfuls of text [1]
X'			Go to place where previous search started
X=			Display current line number
X/<regular expression>	Search for kth occurrence of regular expression [1]
Xn			Search for kth occurrence of last r.e [1]
X!<cmd> or :!<cmd>	Execute <cmd> in a subshell
Xv			Start up /usr/ucb/vi at current line
Xctrl-L			Redraw screen
X:n			Go to kth next file [1]
X:p			Go to kth previous file [1]
X:f			Display current file name and line number
X.			Repeat previous command
X-------------------------------------------------------------------------------
**-more.help-EOF-**
echo 'x - regcompat.c'
sed 's/^X//' <<'**-regcompat.c-EOF-**' >regcompat.c
X/* file: regcompat.c
X** author: Peter S. Housel 11/21/88
X** Compatibility routines for regular expressions. more.c uses the
X** re_comp() and re_exec() routines, while Minix only has regcomp() and
X** regexec() (from Henry Spencer's freely redistributable regexp package).
X** Note that the third argument to regexec() is a beginning-of-line flag
X** and was probably added by Andrew Tannenbaum. It will probably be ignored
X** if your copy of the regexp routines only expects two args.
X**/
X
X#include <stdio.h>
X#include <regexp.h>
X
Xstatic regexp *re_exp = NULL;	/* currently compiled regular expression */
Xstatic char *re_err = NULL;	/* current regexp error */
X
Xchar *re_comp(str)
Xchar *str;
X{
X if(str == NULL)
X    return NULL;
X
X if(re_exp != NULL)
X    free(re_exp);
X
X if((re_exp = regcomp(str)) != NULL)
X    return NULL;
X
X return re_err != NULL ? re_err : "string didn't compile";
X}
X
Xint re_exec(str)
Xchar *str;
X{
X if(re_exp == NULL)
X    return -1;
X return regexec(re_exp, str, 1);
X}
X
Xregerror(str)
Xchar *str;
X{
X re_err = str;
X}
**-regcompat.c-EOF-**
echo 'x - tcvars.c'
sed 's/^X//' <<'**-tcvars.c-EOF-**' >tcvars.c
X/*
X * For some reason (probably because it doesn't support padding), the Minix
X * termcap routines don't define these variables.
X */
Xint ospeed;
Xchar PC;
**-tcvars.c-EOF-**
echo 'x - varargs.h'
sed 's/^X//' <<'**-varargs.h-EOF-**' >varargs.h
X/*  varargs.h  */
X
Xtypedef char *va_list;
X
X#define  va_dcl		int va_alist;
X#define  va_start(p)	(p) = (va_list) &va_alist;
X#define  va_arg(p,type)	( (type *) ((p)+=sizeof(type)) )[-1]
X#define  va_end(p)
X
X#define  vfprintf	_doprintf
X#define  vprintf(fmt,args)	vfprintf(stdout,fmt,args)
**-varargs.h-EOF-**
echo 'x - mkdep.sh'
sed 's/^X//' <<'**-mkdep.sh-EOF-**' >mkdep.sh
X#!/bin/sh -
X#
X# Copyright (c) 1987 Regents of the University of California.
X# All rights reserved.
X#
X# Redistribution and use in source and binary forms are permitted
X# provided that the above copyright notice and this paragraph are
X# duplicated in all such forms and that any documentation,
X# advertising materials, and other materials related to such
X# distribution and use acknowledge that the software was developed
X# by the University of California, Berkeley.  The name of the
X# University may not be used to endorse or promote products derived
X# from this software without specific prior written permission.
X# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X# WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X#
X#	@(#)mkdep.sh	5.12 (Berkeley) 6/30/88
X#
XPATH=/bin:/usr/bin:/usr/ucb
Xexport PATH
X
XMAKE=Makefile			# default makefile name is "Makefile"
X
Xopts=""
X
Xwhile :
X	do case "$1" in
X		# -f allows you to select a makefile name
X		-f)
X			MAKE=$2
X			shift; shift ;;
X
X		# the -p flag produces "program: program.c" style dependencies
X		# so .s's don't get produced
X		-p)
X			SED='s/\.s//'
X			shift ;;
X		-D*|-I*|-U*)
X			opts="$opts $1"
X			shift ;;
X		-*)
X			shift;;
X		*)
X			break ;;
X	esac
Xdone
X
Xif test $# = 0 ; then
X	echo 'usage: mkdep [-p] [-f makefile] [flags] file ...'
X	exit 1
Xfi
X
Xif test ! -w $MAKE ; then
X	echo "mkdep: no writeable file \"$MAKE\""
X	exit 1
Xfi
X
XTMP=/tmp/mkdep$$
XTMP1=/tmp/Mkdep$$
X
Xtrap 'rm -f $TMP $TMP1; exit 1' 1 2 3 13 15
X
Xcp $MAKE ${MAKE}.bak
X
Xsed -e '/DO NOT DELETE THIS LINE/,$d' < $MAKE > $TMP
X
Xcat << _EOF_ >> $TMP
X# DO NOT DELETE THIS LINE -- mkdep uses it.
X# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
X
X_EOF_
X
X
Xfor f; do
X	dep=`echo "$f" | sed -e 's,/,\\\\/,g' -e 's/\.c$/.s/'`
X	/lib/cpp $opts "$f" |
X	sed -e '/^#/!d'			\
X	    -e 's/#line [0-9]* //' 	\
X	    -e 's,"\./,",'		\
X	    -e 's/"\(.*\)"/\1/'		\
X	    -e "$SED" > $TMP1
X	sort -u $TMP1 | sed -e "s/^/$dep: /" >> $TMP
Xdone
Xcat << _EOF_ >> $TMP
X
X# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
X_EOF_
X
X# copy to preserve permissions
Xcp $TMP $MAKE
Xrm -f ${MAKE}.bak $TMP $TMP1
Xexit 0
**-mkdep.sh-EOF-**