[net.sources] VSH source 2 of 6

dan@rna.UUCP (Dan Ts'o) (06/27/85)

# Here is part 2 of the sources to VSH, a visual shell.
#
#
#					Cheers,
#					Dan Ts'o
#					Dept. Neurobiology
#					Rockefeller Univ.
#					1230 York Ave.
#					NY, NY 10021
#					212-570-7671
#					...cmcl2!rna!dan
echo src/account.c
sed 's/^X//' > src/account.c << 'All work and no play makes Jack a dull boy'
X#include "hd.h"
X
X/* This records each usage of Vsh in the file LOGFILE */
X/* Each entry is in the form "User Time(minutes) Date" */
X
Xlong time (), ent_time [1];
Xchar *ctime ();
X
Xcomein () 
X{
X    time (ent_time);
X}
X
Xgoout () 
X{
X
X	long lv_time [1];
X	register char *namep;
X	register char *cp;
X	FILE *logfile;
X
X	if (access(LOGFILE, 2))
X		return;
X	time (lv_time);
X/*
X	for (namep = cp = HOME; *cp; cp++)
X		if (*cp == '/') namep = cp;
X	namep++;
X */	namep = username;
X	logfile = fopen (LOGFILE, "a");
X	if (logfile == NULL)
X		return;
X	fprintf (logfile, "%8.8s %4d %10.10s\n",
X		namep, (int)((*lv_time - *ent_time)/60L), ctime (ent_time));
X	fclose (logfile);
X}
X
Xleave () 
X{			/* exit after resetting tty */
X    int putch();
X
X    tty_cooked ();
X    ewin();
X    window = LI;
X    vwin();		/* reset tty scrolling */
X    atxy(1, LI);
X    if (TE)
X	tputs(TE, 0, putch);
X    goout ();
X    exit (0);
X}
All work and no play makes Jack a dull boy
echo src/ascii.c
sed 's/^X//' > src/ascii.c << 'All work and no play makes Jack a dull boy'
X#include "strings.h"	/* See strings.h for comments */
X
Xchar charclass  [129] = 
X{
X/* -1    */
X    EF,
X/* 00-07 */
X	EF, UD, UD, EF, EF, UD, UD, UD,
X/* 08-0f */
X	UD, WS, EL, UD, UD, EL, UD, UD,
X/* 10-17 */
X	UD, UD, UD, UD, UD, UD, UD, UD,
X/* 18-1f */
X	UD, UD, UD, UD, WS, UD, UD, UD,
X/* 20-27 */
X	WS, SC, SC, SC, SC, SC, SC, SC,
X/* 28-2f */
X	SC, SC, SC, SC, SC, SC, SC, SC,
X/* 30-37 */
X	NU, NU, NU, NU, NU, NU, NU, NU,
X/* 38-3f */
X	NU, NU, SC, SC, SC, SC, SC, SC,
X/* 40-47 */
X	SC, UA, UA, UA, UA, UA, UA, UA,
X/* 48-4f */
X	UA, UA, UA, UA, UA, UA, UA, UA,
X/* 50-57 */
X	UA, UA, UA, UA, UA, UA, UA, UA,
X/* 58-5f */
X	UA, UA, UA, SC, SC, SC, SC, SC,
X/* 60-67 */
X	SC, LA, LA, LA, LA, LA, LA, LA,
X/* 68-6f */
X	LA, LA, LA, LA, LA, LA, LA, LA,
X/* 70-77 */
X	LA, LA, LA, LA, LA, LA, LA, LA,
X/* 78-7f */
X	LA, LA, LA, SC, SC, SC, SC, EF
X} ;
All work and no play makes Jack a dull boy
echo src/asfix
sed 's/^X//' > src/asfix << 'All work and no play makes Jack a dull boy'
Xed - $1.s
X?.globl?a
X.data
X.
X-2,+2s/.data/.text/
Xw
Xq
Xas - -o $1.o $1.s
Xrm -f $1.s
All work and no play makes Jack a dull boy
echo src/at.c
sed 's/^X//' > src/at.c << 'All work and no play makes Jack a dull boy'
X#
X#include "hd.h"
X/*  Display and cursor control routines */
X
X#define BELL	07
X
Xint putch ();
X
X/*  Position cursor at the given (x, y) location.
X	(1, 1) is the top left, (80, 24) is the lower right
X */
X
Xatxy (x, y)  int x, y; 
X{
X
X    tputs (tgoto (CM, x - 1, y - 1), 0, putch);
X}
X
X/*
X * Erase screen or upper directory window
X */
Xerase () 
X{
X    register int i;
X
X    bufout();
X    if (ewindow) {
X	if (CB) {
X		atxy(CO, window);
X		tputs(CB, 0, putch);
X	}
X	else {
X		atxy(1, 1);
X		for (i = 1; i <= window; i++) {
X			if (CE)
X				tputs(CE, 0, putch);
X			else
X				clearline();
X			printf("\r\n");
X		}
X	}
X	atxy(1, 1);
X    }
X    else {
X	tputs(CL, 0, putch);
X	putch(CR);
X    }
X    unbufout();
X}
X
X/*
X * Erase below a line
X */
Xerasebelow(l)
Xregister int l;
X{
X	if (CD) {
X		atxy(1, l);
X		tputs(CD, 0, putch);
X		return;
X	}
X	do {
X		atxy(1, l);
X		clearline();
X	} while (l++ < LI);
X}
X
X/* erase chars on current line */
Xclearline () 
X{
X    bufout ();
X    if (CE) {
X	putch(CR);
X	tputs(CE, 0, putch);
X    }
X    else
X	printf ("%c%80s%s", CR, "", UP);
X    unbufout ();
X}
X
X/* Position cursor at specified file */
Xatfile (file, col) int file, col; 
X{
X
X    atxy (col, 3 + file);
X}
X
X/* buffering subroutines */
X
Xchar outbuf [BUFSIZ];	/* the buffer */
Xint bcount = 0;	/* can buffer only once */
X/* additional attempts ignored */
X
Xbufout () 
X{
X
X    if (bcount++ == 0) setbuf (stdout, outbuf);
X}
X
Xunbufout () 
X{
X
X    fflush (stdout);
X    if (--bcount == 0) setbuf (stdout, CNULL);
X}
X
X/* Clear message lines (23-24) for a pcount line message */
X/* Lastcount keeps track of the lines with characters on them */
X/* Dispdir calls with parameter -1 to reset lastcount */
X
Xclearmsg (pcount) int pcount; 
X{
X
X    static int lastcount;
X
X    atxy(1, window-1);
X    if (pcount == -1) lastcount = 0;
X    else
X    {
X	if (lastcount == 0);
X	else if (lastcount == 1) 
X	{
X	    clearline ();
X	}
X	else 
X	{
X	    bufout ();
X	    if (CE) {
X		putch(CR);
X		tputs(CE, 0, putch);
X		putch(LF);
X		tputs(CE, 0, putch);
X	    }
X	    else
X		printf ("%159s", "");
X	    unbufout ();
X	}
X	lastcount = pcount;
X    }
X    atxy(1, window-1);
X}
X
X/* Putmsg counts the number of lines in its parameter,
X   calls clearmsg with that count, and then displays the message.  */
X
Xputmsg (msg, a0, a1)
Xregister char * msg; 
Xchar *a0, *a1;
X{
X
X    clearmsg (any(LF, msg) == NULL ? 1 : 2);
X    printf ("    ");
X    hilite (msg, a0, a1);
X    /* Cosmetic */
X    if (*msg) {
X    	while (*msg++);
X	if (msg[-2] == ' ')
X		printf("%s  ", BC);
X    }
X}
X
X/* Beep bell on terminal */
Xbeep () 
X{
X    putch (BELL);
X}
X
X/* Print error message about a file */
Xmyperror (parm) char * parm; 
X{
X
X    extern int errno, sys_nerr;
X    extern char *sys_errlist[];
X    register char *c;
X
X    c = "Unknown error";
X    if(errno < sys_nerr)
X	c = sys_errlist[errno];
X    clearmsg (1);
X    printf ("    ");
X    hilite ("%s: %s", parm, c);
X}
All work and no play makes Jack a dull boy
echo src/classify.c
sed 's/^X//' > src/classify.c << 'All work and no play makes Jack a dull boy'
X#include "hd.h"
X#include "classify.h"
X#include "mydir.h"
X#include "strings.h"
X
X#define aout1	0407
X#define aout2	0410
X#define aout3	0411
X#define aout4	0405
X#define	aout5	0413
X#define	cpio	070707
X#define ar	0177545
X#define	packold	017437
X#define	pack	017037
X#define	compact	017777
X#define compress 0116437
X
X/* Classify return the file type of parameter fname */
X
Xclassify (fname) char * fname; 
X{
X    register unsigned mode;
X    register int fdesc, rdlen;
X    unsigned short word;
X    int code;
X    unsigned short wbuf[5];
X    char *cp;
X    char *lastfn();
X
X    if (stat (fname, &scr_stb)) return CL_NULL;
X
X    mode = scr_stb.st_mode & S_IFMT;
X    if (mode == S_IFDIR) return CL_DIR;
X    if (mode != S_IFREG) return CL_SPCL;
X
X    fdesc = open (fname, 0);
X    if (fdesc < 0) return CL_PROTPLN;
X
X    rdlen = read (fdesc, wbuf, sizeof wbuf);
X    if (rdlen < sizeof word)
X	code = CL_TEXT;
X    else {
X	word = wbuf[0];
X	cp = (char *)wbuf;
X	cp[8] = 0;
X	/* Berkeley archive */
X	if (rdlen >= 8 && !strcmp(cp, "!<arch>\n"))
X		word = ar;
X	/* System 5.0 archive (where will it end ?) */
X	else {
X		cp[4] = 0;
X		if (rdlen >= 4 && !strcmp(cp, "<ar>"))
X			word = ar;
X	}
X	switch (word) {
X	case aout1:
X	case aout2:
X	case aout3:
X	case aout4:
X	case aout5:
X		code = CL_AOUT;
X		break;
X	case ar:
X		code = CL_AR;
X		break;
X	case cpio:
X		code = CL_CPIO;
X		break;
X	case pack:
X	case packold:
X		code = CL_PACK;
X		break;
X	case compact:
X		code = CL_COMPACT;
X		break;
X	case compress:
X		code = CL_COMPRESS;
X		break;
X	default:
X		if (compe (lastfn (fname), "core"))
X			code = CL_CORE;
X		else {
X			/* Attempt to protect user from binary files */
X			if (istext(fdesc))
X				code = CL_TEXT;
X			else
X				code = CL_UNKPLN;
X		}
X	}
X    }
X
X    close (fdesc);
X    return code;
X}
X
X/*
X * istext(fd) - test if file contents is text-like
X */
Xistext(fd)
Xint fd;
X{
X	register int i;
X	register char *s;
X	register int cc;
X	char buf[500];
X
X	i = read(fd, buf, 500);
X	cc = 0;
X	for (s = buf; i > 0; i--) {
X		/* Test for NUL, parity bit, control codes */
X		if (*s == 0 || (*s&0200) || (ascii[*s] == UD && *s != '\b'))
X			cc++;
X		s++;
X		if (cc > 50)
X			break;
X	}
X	return (i ? 0 : 1);
X}
X
X/* Lastfn returns a pointer to the last file name in path.  */
X
Xchar *
X    lastfn (path) register char *path; 
X{
X    register char *cp;
X
X    for (cp=path; *cp++;);
X
X    cp--;
X    while (*--cp != '/' && cp >= path);
X
X    return ++cp;
X}
All work and no play makes Jack a dull boy
echo src/classify.h
sed 's/^X//' > src/classify.h << 'All work and no play makes Jack a dull boy'
X/* Vsh will classify a file as one of the following:  */
X
X#define	CL_NULL		0	/* No such file or protected path */
X#define	CL_DIR		1	/* Directory, May NOT be accessable */
X#define CL_SPCL		2	/* Special device file */
X#define CL_PROTPLN	3	/* Plain file protected unknown fmt */
X#define CL_UNKPLN	4	/* Plain file unknown format */
X#define CL_AOUT		5	/* A.out format */
X#define CL_AR		6	/* Ar format */
X#define CL_CPIO		7	/* Cpio format */
X#define CL_CORE		8	/* Core dump */
X#define CL_TEXT		9	/* Ascii text */
X#define	CL_PACK		10	/* Pack/pcat Huffman encoded */
X#define	CL_COMPACT	11	/* compact Huffman encoded */
X#define	CL_COMPRESS	12	/* compress encoded */
All work and no play makes Jack a dull boy
echo src/cmdini.c
sed 's/^X//' > src/cmdini.c << 'All work and no play makes Jack a dull boy'
X#include "hd.h"
X#include "command.h"
X
Xextern date(), showerror(), showgrep(), file(), home(), grep(),
X    wmake(), fmake(), callshell(), longlist(), remove(),
X    create(), exec(), display(), options(), xecute(), xchdir(), rexecute(),
X    chain(), find(), pagexec();
X
Xstruct classstruct classtab[] = 
X{
X	"date",		date,		0, 1,
X	"showerror",	showerror,	0, 1,
X	"showgrep",	showgrep,	0, 1,
X	"file",		file,		-1, 1,
X	"home",		home,		0, 1,
X	"grep",		grep,		0, 1,
X	"wmake",	wmake,		0, 1,
X	"fmake",	fmake,		0, 1,
X	"exec",		exec,		-2, 1,
X	"xecute",	xecute,		-2, 1,
X	"rexecute",	rexecute,	0, 1,
X	"shell",	callshell,	-1, 1,
X	"display",	display,	-1, 1,
X	"create",	create,		0, 1,
X	"longlist",	longlist,	0, 0,
X	"remove",	remove,		0, 0,
X	"options",	options,	-1, 1,
X	"null",		0,		0, 0,
X	"chain",	chain,		-2, 1,
X	"find",		find,		-1, 1,
X	"pexec",	pagexec,	-2, 1,
X	"",		0,		0, 0
X} ;
X
Xstatic char *whoargv[]  = 
X{
X    "/bin/who", 0
X} ;
Xstatic char *rootargv[] = 
X{
X    "/", 0
X} ;
Xstatic char *helpargv[] = 
X{
X    "/usr/lib/vsh/genhelp", 0
X} ;
Xstatic char *psargv[] = 
X{
X    "/bin/ps", 0
X} ;
Xstatic char *bshargv[] = 
X{
X#ifdef	PWBTTY
X    "/bin/v7sh", 0
X#else
X    "/bin/sh", 0
X#endif
X} ;
X
X/* dyt */
Xextern char wdname0[];
Xstatic char *owdargv[] =
X{
X	wdname0, 0
X};
X
Xchar *shargv[] =
X{
X#ifdef	PWBTTY
X	"/bin/sh", 0
X#else
X	"/bin/csh", 0
X#endif
X};
X
Xchar *cnull = 0;
X
Xstruct cmdstruct cmdtab[] = 
X{
X	'C',	create,		&cnull, 1,
X	'D',	date,		&cnull, 1,
X	'E',	showerror,	&cnull, 1,
X	'F',	file,		&cnull, 1,
X	'G',	grep,		&cnull, 1,
X	'L',	longlist,	&cnull, 0,
X	'M',	wmake,		&cnull, 1,
X	'N',	fmake,		&cnull, 1,
X	'O',	options,	&cnull, 1,
X	'P',	exec,		psargv, 1,
X	'R',	remove,		&cnull, 0,
X	'S',	showgrep,	&cnull, 1,
X	'T',	display,	&cnull, 1,
X	'W',	exec,		whoargv, 1,
X	'X',	xecute,		&cnull, 1,
X	'Y',	rexecute,	&cnull, 1,
X	'^',	home,		&cnull, 1,
X	'!',	callshell,	&cnull, 1,
X	'%',	chain,		shargv, 1,
X	'$',	exec,		bshargv, 1,
X	'/',	file,		rootargv, 1,
X	'?',	display,	helpargv, 1,
X/* dyt */
X	'\\',	file,		owdargv, 1,
X	'.',	find,		&cnull, 1,
X
X	'A',0,0,0,'B',0,0,0,
X	'H',0,0,0,'I',0,0,0,'J',0,0,0,'K',0,0,0,
X	'Q',0,0,0, 'U',0,0,0,'V',0,0,0,
X/* dyt */
X	'Z',0,0,0,'#',0,0,0,
X	'&',0,0,0,'(',0,0,0,')',0,0,0,
X	'*',0,0,0,'=',0,0,0,'{',0,0,0,'}',0,0,0,'[',0,0,0,']',0,0,0,
X	'~',0,0,0,',',0,0,0,';',0,0,0,
X	':',0,0,0,'`',0,0,0,'<',0,0,0,'>',0,0,0,'@',0,0,0,'_',0,0,0,
X	'|',0,0,0,
X	'e',0,0,0,'f',0,0,0,'g',0,0,0,'h',0,0,0,'i',0,0,0,'j',0,0,0,
X	'k',0,0,0,'l',0,0,0,'m',0,0,0,'n',0,0,0,'o',0,0,0,'p',0,0,0,
X	'q',0,0,0,'r',0,0,0,'s',0,0,0,'t',0,0,0,
X	'u',0,0,0,'v',0,0,0,'w',0,0,0,'x',0,0,0,'y',0,0,0,'z',0,0,0,
X
X	CMD_DATE, date,		&cnull, 1,
X	CMD_SE,	showerror,	&cnull, 1,
X	CMD_SG,	showgrep,	&cnull, 1,
X	0,0,0,0
X} ;
X
X/* If this is not EX/VI, check out nedit() in show.c
X * It is preferable to leave this alone and change EDITOR in
X * everyone's .vshrc
X */
Xchar stdedit[] = "vi";
X
Xstruct parmstruct parmtab[] = 
X{
X	"EDITOR", stdedit,
X	"make", "/bin/make",
X	"grep", "/bin/grep",
X	"rmhelp", "/usr/lib/vsh/rmhelp",
X	"showhelp", "/usr/lib/vsh/showhelp",
X	"makerror", ".makerror",
X	"grepout", ".grepout",
X	"vshmode", "enter",
X	"quitchar", "D",
X	"pagechar", "{",
X	"PATH", ":/bin:/usr/bin",
X	"TERM",	"unknown",
X	"HOME", "",
X	"SHELL", "/bin/sh",
X	"entertext", ENTEREDIT,
X	"window", "24",
X	"helpfile", "",
X	"column", "1",
X	"noargprompt", "",
X	"VImotion", "",
X#ifdef	V7TTY
X	"MAIL", "/usr/spool/mail/~",
X#else
X	"MAIL", "/usr/mail/~",
X#endif
X	"moresize", MMAXSIZE,
X	"enterpath", ":",
X	0, 0
X} ;
All work and no play makes Jack a dull boy
echo src/cmdload.c
sed 's/^X//' > src/cmdload.c << 'All work and no play makes Jack a dull boy'
X#include "hd.h"
X#include "command.h"
X
X/* This loads the command table from the .vshrc file */
X
Xcmdldrc () 
X{
X    FILE *rcstream,		/* Stream of .vshrc */
X	*fopen();	/* Stdio open proc */
X
X    char cbuf [STRMAX],	/* Buffer for input parm */
X	*argv [ARGVMAX];	/* Pointers to input parm */
X    int argc;	/* Number of parm */
X
X    int line = 1;	/* Current line num of rcstream */
X
X    /* initialize */
X
X    strcpy (cbuf, HOME);
X    strcat (cbuf, "/.vshrc");
X    rcstream = fopen (cbuf, "r");
X    if (rcstream == NULL) return;
X    printf ("Loading .vshrc\r\n");
X
X    while (!feof (rcstream)) 
X    {
X	if (readarg (rcstream, &line, &argc, argv, cbuf) != BAD)
X	    cmdldarg (line-1, argc, argv);
X    }
X}
X
X/* This loads command tables as specified in its arguments */
Xcmdldarg (line, argc, argv)
Xint line, argc; char *argv[]; 
X{
X
X    char *malloc();	/* Standard allocation proc */
X    register i;	/* An index */
X
X    register struct cmdstruct *cmdp;	/* Pointers */
X    register struct classstruct *classp;
X    register struct parmstruct *parmp;
X
X    /* An addressable representation of CNULL (0) */
X    extern char *cnull;
X
X    if (argc <= 0) ;
X    else if (argc == 1) lderror ("Too few args", line);
X
X    else if (strlen (argv [0]) == 1) 
X    {
X	cmdp = cmdloc (*argv [0]);
X	if (cmdp->cmd_char == 0) 
X	{
X	    lderror ("Not a proper command",
X		line);
X	    return;
X	}
X	classp = classloc (argv [1]);
X	if (*classp->cl_name == 0) 
X	{
X	    lderror ("Illegal keyword", line);
X	    return;
X	}
X	if (!(
X	    argc-2 == classp->cl_count ||
X	    (classp->cl_count == -1 && argc <= 3) ||
X	    (classp->cl_count == -2 && argc >= 2)))
X	{
X
X	    lderror
X		("Improper number of parameters", line);
X	    return;
X	}
X	/* All testing over with--store new command */
X
X	cmdp->cmd_proc = classp->cl_proc;
X	cmdp->cmd_xdir = classp->cl_xdir;
X
X	if (argc <= 2) cmdp->cmd_argv = &cnull;
X	else cmdp->cmd_argv  =
X	    (char **) malloc ((argc - 1) * (sizeof *argv));
X
X	for (i=2; i<argc; i++) 
X	{
X	    cmdp->cmd_argv [i-2] =
X		malloc (strlen (argv [i]) + 1);
X	    strcpy (cmdp->cmd_argv[i-2], argv [i]);
X	    cmdp->cmd_argv [i-1] = CNULL;
X	}
X    }
X    else
X    {
X	for (parmp = parmtab;
X	parmp->p_name &&
X	    strcmp (parmp->p_name, argv[0]);
X	parmp++);
X	if (parmp->p_name) 
X	{
X	    parmp->p_val = malloc
X		(strlen (argv[1]) + 1);
X	    strcpy (parmp->p_val, argv[1]);
X	}
X	else lderror ("Bad parameter name", line);
X	if (argc != 2) lderror
X	    ("Too many args", line);
X    }
X}
All work and no play makes Jack a dull boy
echo src/cmdrun.c
sed 's/^X//' > src/cmdrun.c << 'All work and no play makes Jack a dull boy'
X#
X#include "hd.h"
X#include "command.h"
X
X/* Each command called by command.c must return special information.
X   First, the next command to execute is returned in the last eight
X   bits (and can be masked out with CMDMASK).  If no more commands
X   are to be run, these bits are set to 0.  The next bit is the
X   REPLOT bit.  If on, the screen has been altered enough to require
X   a replot.  The NOOP bit indicates a command was not found.
X   Finally, the ENTERDIR bit indicates a new directory has been
X   entered.
X*/
X
Xcommand (cmd, ctype) register cmd; int ctype; 
X{
X
X    register ret; /* return value */
X    int next; /* Temp variable for next command */
X    register struct cmdstruct *cmdp;
X
X    ret = 0;
X    selecttype = ctype;
X    while (cmd) 
X    {
X	if ((ctype == DIRCMD) &&
X	    ((next = dircmd (cmd)) != NOOP)
X	    )
X	    cmd = next;
X	else
X	{
X	    cmdp = cmdloc (cmd);
X	    if (cmdp->cmd_proc && (
X		(cmdp->cmd_xdir)||(ctype == DIRCMD))) 
X	    {
X
X		cmd = (*cmdp->cmd_proc) (cmdp->cmd_argv);
X	    }
X	    else cmd = NOOP;
X	}
X	ret |= cmd & (REPLOT | ENTERDIR | NOOP);
X	cmd &= CMDMASK;
X    }
X    if (ret & NOOP) 
X    {
X	putmsg ("Unknown command.  Press ? for help.  ");
X	if (ret & REPLOT) getrtn ();
X    }
X    return ret;
X}
X
X/* Classloc returns the classtab element corresponding the keyword referenced
X   by cp */
X
Xstruct classstruct *
X    classloc (cp) register char *cp; 
X{
X
X    register struct classstruct *classp;
X
X    for (classp = classtab;
X    *classp->cl_name && strcmp (cp, classp->cl_name);
X    classp++);
X    return classp;
X}
X
X/* Cmdloc returns the cmdtab element corresponding to ch */
X
Xstruct cmdstruct *
X    cmdloc (ch) register char ch; 
X{
X
X    register struct cmdstruct *cmdp;
X
X    for (cmdp = cmdtab;
X    cmdp->cmd_char && cmdp->cmd_char != ch;
X    cmdp++);
X
X    return cmdp;
X}
X
X/* Cmdproc returns a pointer to the procedure which runs the command
X   corresponding to ch.  */
X
Xint (*
X    cmdproc (ch))() char ch; 
X{
X    extern struct cmdstruct *cmdloc();
X
X    return ((*cmdloc)(ch)->cmd_proc);
X}
All work and no play makes Jack a dull boy
echo src/command.h
sed 's/^X//' > src/command.h << 'All work and no play makes Jack a dull boy'
X/* There are two important structures used by the command processor.
X   Cmdtab encodes the current commands.  Each command corresponds to
X   an element in cmdtab and is type struct cmdstruct.  Four fields
X   determine the command.  Cmd_char is the character which, when
X   pressed, calls the command.  Cmd_proc is the procedure which
X   runs the command.  Cmd_argv is used as a parameter to that proc.
X   Cmd_xdir, when on, indicates the command may be run anywhere, and
X   not just on the directory page.
X
X   The classtab is used to map statements from the .vshrc file to
X   cmdtab elements.  The keyword in a .vshrc statement is looked
X   up in classtab, and then the classtab element is used to load
X   the cmdtab element.
X*/
X
Xstruct classstruct {		/* Classification structure */
X	char * cl_name;		/* Name (key word) */
X	int (*cl_proc)();	/* Command procedure */
X	short cl_count;		/* Number of args */
X	char cl_xdir;		/* Is ok outside dir page */
X};
X
Xstruct cmdstruct {		/* Command structure */
X	char cmd_char;		/* Command char */
X	int  (*cmd_proc)();	/* Command procedure */
X	char ** cmd_argv;	/* Array of arguments for command */
X	char cmd_xdir;		/* Is ok outside dir page */
X};
X
Xstruct classstruct *classloc();
Xstruct cmdstruct   *cmdloc  ();
Xextern (*cmdproc ())();
X
Xextern struct classstruct classtab[];
Xextern struct cmdstruct   cmdtab[];
X
X/* Command characters for important commands */
X
X#define	CMD_DATE	0x80
X#define	CMD_SE		0x81
X#define	CMD_SG		0x82
All work and no play makes Jack a dull boy
echo src/curdir.c
sed 's/^X//' > src/curdir.c << 'All work and no play makes Jack a dull boy'
X#
X/*  Curdir finds the name of the working directory and puts in
X    wdname.  This is done by calling on the pwd program.
X*/
X#include "hd.h"
X#include "mydir.h"
Xstatic char pwd[] = 
X{
X    "/bin/pwd"
X} ;
X
Xcurdir () 
X{
X
X    int p, rdlen, pipefile [2];
X#define pipein	pipefile [0]
X#define pipeout	pipefile [1]
X
X    pipe (pipefile);
X    printf ("%s\r\n", pwd);
X    if ((p = myfork ()) == 0) 
X    {
X	close (outfile); dup (pipeout);
X	close (pipein); close (pipeout);
X	execl (pwd, pwd, 0);
X	exit (1);
X    }
X    else 
X    {
X	close (pipeout);
X	join (p);
X	rdlen = read (pipein, wdname, sizeof wdname);
X	if (rdlen < 2 || rdlen == sizeof wdname || wdname [0] != '/') 
X	{
X	    printf ("Cannot find name of working directory\r\n");
X	    return 1;
X	}
X	wdname [rdlen - 1] = 0;
X	close (pipein);
X    }
X    return 0;
X}
All work and no play makes Jack a dull boy
echo src/curses.c
sed 's/^X//' > src/curses.c << 'All work and no play makes Jack a dull boy'
X#include "hd.h"
X#include "mydir.h"
X
Xchar *BC, *UP, *CM, *CL;
X/* dyt */
Xchar *CE;
Xchar *SO, *SE;
Xshort PC;
Xint CO, LI;
Xchar *CS, *CB;
Xchar *BE, *BO;
Xchar *SR, *CD;
Xchar *TI, *TE;
Xint AM, XN;
X
Xchar tspace [512], *atspace;
Xchar *tgetstr ();
Xint putch ();
X
Xint ewindow = 0;		/* Separate exec window */
Xint xoff = 0;			/* Column offset */
X
Xcurs_init () 
X{
X    char bp [1024];
X    char * tgoto ();
X    static char winbuf[10];
X
X    tgetent (bp, TERM);
X    atspace = tspace;
X    PC = *tgetstr ("pc", &atspace);
X    CM = tgetstr ("cm", &atspace);
X    CL = tgetstr ("cl", &atspace);
X    UP = tgetstr ("up", &atspace);
X    BC = tgetstr ("bc", &atspace);
X    CE = tgetstr ("ce", &atspace);
X    CO = tgetnum ("co");
X    LI = tgetnum ("li");
X    CS = tgetstr ("cs", &atspace);
X    /* A new one, clear to beginning of display */
X    CB = tgetstr ("cb", &atspace);
X    /* Blink and blink end */
X    BO = tgetstr ("bo", &atspace);
X    BE = tgetstr ("be", &atspace);
X    if (BC == CNULL || tgetflag("bs"))
X	BC = "\b";
X/*
X * Enables use of reverse video/standout
X */
X    SO = tgetstr ("so", &atspace);
X    SE = tgetstr ("se", &atspace);
X/*
X * Scroll reverse
X */
X    SR = tgetstr ("sr", &atspace);
X    CD = tgetstr ("cd", &atspace);
X    AM = tgetflag ("am");
X    XN = tgetflag ("xn");
X    TI = tgetstr ("ti", &atspace);
X    TE = tgetstr ("te", &atspace);
X
X    if (SO == CNULL)
X	SO = "";
X    if (SE == CNULL)
X	SE = "";
X    if (BO == CNULL)
X	BO = "";
X    if (BE == CNULL)
X	BE = "";
X    if (CM == CNULL) 
X	return 1;
X    if (CO < 80) {
X	fprintf(stderr, "\07Too narrow screen\r\n");
X	CO = 80;
X    }
X    else if (CO > 80)
X	xoff = CO - 80;
X    setcolumn();
X    if (LI < 8)
X	return 1;
X    sprintf(winbuf, "%8d", LI);
X    WINDOW = winbuf;
X    setwindow();
X    return 0;
X}
X
Xsetwindow()
X{
X	register int row;
X	register int owin1, owin2;
X
X	owin1 = window;
X	row = atoi(WINDOW);
X	window = (row > (maxnfpp+VSHTOP+VSHBOT))
X		? (maxnfpp+VSHTOP+VSHBOT) : row;
X	if (window < 8) {
X		putmsg("\07Screen too small");
X		window = 8;
X	}
X	nfpp = window - (VSHTOP+VSHBOT);
X	ewindow = (LI-window > PAGEMIN);
X	if (owin1 != window) {
X		owin2 = window;
X		window = owin1;
X		ewin();
X		window = owin2;
X		vwin();
X		erase();
X	}
X	else
X		vwin();
X}
X
X/* Multi-column listing */
Xsetcolumn()
X{
X	register int i;
X
X	i = (CO-VSHLEFT)/19;			/* Max number of columns */
X	if ((column = atoi(COLUMN)) < 1)
X		column = 1;
X	if (column > i)
X		column = i;
X	colfield = (CO-VSHLEFT)/column;
X	pageoff = 0;
X}
X
Xstatic int ewinf = 0;
Xewin()
X{
X	if (!ewindow)
X		return 0;
X	bufout();
X	if (CS) {
X		tputs(tgoto(CS, LI-1, window-VSHBOT), 0, putch);
X		ewinf = 1;
X	}
X	atxy(1, LI);
X	if (TE)
X		tputs(TE, 0, putch);
X	unbufout();
X	return ewinf;
X}
X
Xvwin()
X{
X	if (!ewinf)
X		return;
X	bufout();
X	if (TI)
X		tputs(TI, 0, putch);
X	if (CS)
X		tputs(tgoto(CS, window-1, 0), 0, putch);
X	atxy(1, window-1);
X	clearline();
X	atxy(1, 1);
X	unbufout();
X	ewinf = 0;
X}
X
Xhilite(a0, a1, a2)
Xchar *a0, *a1, *a2;
X{
X	if ((int)a0 != 0) {
X		tputs(SO, 0, putch);
X		if ((int)a0 == 1)
X			return;
X		printf(a0, a1, a2);
X	}
X	tputs(SE, 0, putch);
X}
All work and no play makes Jack a dull boy
echo src/dflt.vshrc
sed 's/^X//' > src/dflt.vshrc << 'All work and no play makes Jack a dull boy'
XC	create
XD	date
XE	showerror
XF	file
XG	grep
XL	longlist
XM	wmake
XN	fmake
XO	options
XP	exec  /bin/ps
XR	remove
XS	showgrep
XT	display
XW	exec  /bin/who
XX	xecute
XY	rexecute
X^	home
X!	shell
X%	chain  /bin/ksh
X$	exec  /bin/sh
X/	file  /
X?	display  /usr/lib/vsh/genhelp
X\	file  /src/vsh.d/src
X.	find
XEDITOR	vi
Xmake	/bin/make
Xgrep	/bin/grep
Xrmhelp	/usr/lib/vsh/rmhelp
Xshowhelp	/usr/lib/vsh/showhelp
Xmakerror	.makerror
Xgrepout	.grepout
Xvshmode	enter
Xquitchar	D
Xpagechar	{
XPATH	/usr/5bin/graf:/usr/ucb:/bin:/usr/bin:/usr/local/bin:/etc:/usr/hosts:/usr1/dan/bin:/usr/5bin:/usr/games::
XTERM	tvi950
XHOME	nowhere
XSHELL	/bin/ksh
Xentertext	$EDITOR
Xwindow	      24
Xhelpfile	
Xcolumn	1
Xnoargprompt	
XVImotion	
XMAIL	/usr/spool/mail/dan
Xmoresize	10000
Xenterpath	:
All work and no play makes Jack a dull boy
echo src/dir.c
sed 's/^X//' > src/dir.c << 'All work and no play makes Jack a dull boy'
X#include "hd.h"
X#include "mydir.h"
X#ifdef	NDIR
X#include <errno.h>
X#endif
X#define	curmtime	wd_stb.st_mtime
X
X/* See mydir.h for information about these variables */
Xint tfiles, tpages, cpage;
Xint pageoff = 0, column = 1, colfield = 19;
X
Xstruct stat wd_stb;
X
Xint wdfile;
Xchar wdname [MPLEN + 1];
X/* dyt */
Xchar wdname0 [MPLEN + 1];
Xstatic int oldpage = 1;
X
Xchar selectname[STRMAX];
Xint selectcmd;
Xint selectpage;
Xint selecttype;
X
Xint owindow = 0;
X
X#ifndef	NDIR
Xstruct direct *dirbuf;
Xchar **d_namep;
X#else
Xstruct direct **d_dirp;
X#endif
X
Xint dir_status;
Xstruct stat scr_stb;
X
Xchar *dirmsg [] = 
X{
X    "", "(System Error)  ", "(Too big)  ", 
X	"(Unreadable)  "
X} ;
X
X/*  Enterdir -- Enter into new directory.
X    The parameter newdir is the file to change to.  Pass a single
X    element file name or a full path name. "file", "..", or "."
X    are OK.  "../..", "/a/b/..", "a/", or "a/." must be passed
X    to the file procedure instead.
X
X    On success, there is a new current directory, and wdname has been
X    modified to reflect the new path name.  ENTERDIR | REPLOT is the
X    return value.  On failure, NOREPLOT is returned.  Nothing is changed.
X*/
X
Xenterdir (newdir)
Xregister char *newdir;
X{
X    char wdname1 [MPLEN + 1];
X    register int entermode;	/* Type of entry */
X#define	FOREWARD	0	/* Deaper into dir */
X#define	BACKWARD	1	/* Previous dir (..) */
X#define	STOP		2	/* Stay in same place (.) */
X#define LOAD		3	/* Load new path name */
X
X    if (compe (newdir, DOT)) entermode = STOP;
X    else if (compe (newdir, DOTDOT)) entermode = BACKWARD;
X    else if (newdir[0] == '/') entermode = LOAD;
X    else entermode = FOREWARD;
X
X    if (entermode == FOREWARD && strlen (wdname) > LPLEN) 
X    {
X	putmsg ("Cannot chdir -- Pathname too long");
X	return NOREPLOT;
X    }
X
X    if (chdir (newdir)) 
X    {
X	myperror (newdir);
X	return NOREPLOT;
X    }
X
X	/* dyt */
X	*wdname1 = 0;
X	if (strcmp(wdname, newdir) &&
X		(strcmp(DOTDOT, newdir) || strcmp(SLASH, wdname)))
X		strcpy(wdname1, wdname);
X
X    if (entermode == STOP);	/* change to "." */
X    else if (entermode == BACKWARD) 
X    {	/* change to ".." */
X	todotdot (wdname);
X/* This fails for filesystems not mounted directly off root
X	if (ISROOT (wdname)) chdir (SLASH);
X */	if (chdir(wdname)) {
X		myperror(wdname);
X		return NOREPLOT;
X	}
X    }
X    else if (entermode == LOAD) strcpy (wdname, newdir);
X
X    else
X    {
X	if (!ISROOT (wdname)) strcat (wdname, SLASH);
X	strcat (wdname, newdir);	/* go deeper into dir */
X    }
X
X	/* dyt - try to go to old page, save previous directory name */
X	entermode = cpage;
X	cpage = strcmp(wdname0, wdname) ? 1 : oldpage;
X	pageoff = 0;
X	oldpage = entermode;
X	if (*wdname1)
X		strcpy(wdname0, wdname1);
X
X#ifndef	NDIR
X    close (wdfile); wdfile = open (DOT, 0);
X#endif
X    dir_status = unloaded;
X    *selectname = 0;
X
X    return ENTERDIR | REPLOT;
X}
X
X/* loaddir loads dir and sets assoc parameters */
Xloaddir () 
X{
X    register char *s;
X    register unsigned i;
X    char *malloc();
X    static int first=1;
X
X    if (!first) {
X#ifndef	NDIR
X	if (dirbuf != NULL)
X		free (dirbuf);
X	if (d_namep != NULL)
X		free (d_namep);
X#else
X	freedir (d_dirp);
X	d_dirp = NULL;
X#endif
X    }
X    else
X	first = 0;
X    tpages = tfiles = 0;
X
X#ifdef	NDIR
X
X    dir_status = unloaded;
X    if (sortdir())
X	dir_status = loaded;
X
X#else
X
X    if (wdfile < 0) 
X    {
X	dir_status = protected; return;
X    }
X    else dir_status = unloaded;
X
X    fstat (wdfile, &wd_stb);
X
X/* dyt */
X#ifdef	V6
X#define	st_size	st_size1
X#endif
X
X    i = (unsigned)wd_stb.st_size;
X    /* Allocate one extra byte for a null (in case last entry is dirsize) */
X    s = malloc(i + 1);
X    if ((dirbuf = (struct direct *) s) == NULL)
X    {
X	dir_status = toobig;
X	return;
X    }
X    s[i] = 0;
X    lseek (wdfile, 0L, 0);	/* read in entire file */
X    if (read (wdfile, dirbuf, (unsigned) wd_stb.st_size)
X	!= (unsigned) wd_stb.st_size)
X	return;
X
X	/*
X	 * dyt - Alloc name pointer array
X	 *	Note that this array is larger than necessary since there
X	 *	will be empty slots in the directory file. To economize
X	 *	on this array size, one could put this code in sortdir()
X	 *	after it is determined how many files there are. The trade-off
X	 *	is that sortdir() would have to make two passes through
X	 *	dirbuf. The wager here is that most (especially large)
X	 *	directories don't have too many empty slots anyways.
X	 */
X    d_namep = malloc(((unsigned) wd_stb.st_size/dirsize)*sizeof d_namep[0]);
X    if (d_namep == NULL) {
X	printf(" Out of memory");
X	dir_status = toobig;
X	return;
X    }
X
X    sortdir ();
X    dir_status = loaded;
X
X#endif
X
X    tpages = tfiles / nfpp + ((tfiles % nfpp) > 0);
X    return;
X}
X
X#ifndef	NDIR
X/* sortdir sorts the directory entries.  when done, the following is true:
X    1)  tfiles contains the number of files available
X    2)  the d_namep array will contain pointers to the files.
X	these will be sorted assending.
X*/
Xsortdir () 
X{
X    register struct direct *maxent, *dirp;
X    int dircmp ();
X
X    tfiles = 0;
X    maxent = & dirbuf [(unsigned)wd_stb.st_size / dirsize];
X    for (dirp = dirbuf; dirp < maxent; dirp++) 
X    {
X	if (dirp->d_ino) {
X		d_namep [tfiles++] = dirp->d_name;
X	/* Note: this has the effect of providing a null byte at the end */
X		dirp->d_ino = 0;
X	}
X    }
X    qsort (d_namep, tfiles, sizeof d_namep [0], dircmp);
X}
X
Xdircmp (a, b) char **a, **b;
X{
X    return strcmp (*a, *b);
X}
X
X#else
X
X/*
X * For the NDIR version, we set a pointer d_dirp to an array of pointers
X *	to sorted directory entries. The number of entries is also placed in
X *	tfiles
X */
Xsortdir()
X{
X	extern int errno;
X	extern alphasort();
X
X	tfiles = scandir(DOT, &d_dirp, NULL, alphasort);
X	if (tfiles == -1) {
X		dir_status = protected;
X		if (errno == ENOMEM)
X			dir_status = toobig;
X		tfiles = 0;
X		d_dirp = NULL;
X		return NULL;
X	}
X	return 1;
X}
X
X/*
X * Free memory associated with the sorted directory entry array
X */
Xfreedir(p)
Xstruct direct **p;
X{
X	register int i;
X
X	if (p == NULL)
X		return;
X	i = tfiles;
X	while (i-- > 0)
X		free (p[i]);
X	free (p);
X}
X#endif
X
X/*  Dispdir displays a page of the directory.
X    W A R N I N G.  Dispdir modifies global data.  If the dir is not
X    loaded, or is out of date, dispdir will call on loaddir.
X    Cpage can be adjusted to conform to the current dir.
X    An out of date dir is reloaded only if reload is true.
X
X    In general, the goal of dispdir is to make sure the internal
X    representation of the directory is consistent with the real
X    directory, and what is displayed is consistent with the internal
X    directory.
X*/
X
Xdispdir (reload) int reload;
X{
X    register int dirx;		/* index into dirbuf */
X    register int dirchar;	/* char to select file assoc. with dirx */
X    register int mode;
X    int pe, po;
X    extern char username[];
X    struct stat tmpsbuf;
X    extern int didlong;		/* from longlist() */
X
X    long lastmtime;	/* last time dir was modified */
X
X    bufout (); clearmsg (-1);
X
X    dirx = 0;
X    didlong = 0;
X    if (window != owindow) {
X	owindow = window;
X	dirx++;
X    }
X    if (reload) 
X    {
X	lastmtime = curmtime;
X#ifndef	NDIR
X	fstat (wdfile, &wd_stb);
X#else
X	stat(DOT, &wd_stb);
X#endif
X	if (dirx || (lastmtime != curmtime) || dir_status) loaddir ();
X    }
X    else if (dirx)
X	loaddir();
X
X    cpage = max (1, min (cpage, tpages));
X
X    erase ();
X    hilite (1);
X    printf ("Directory: %s  %sUser: %s", wdname, dirmsg [dir_status],
X	username);
X
X    if (VSHMODE == SELECTMODE) {
X	printf("  (Select mode)");
X	mode = 15;
X    }
X    else
X	mode = 0;
X
X    if (tfiles == 0) 
X    {
X	hilite(0);
X	unbufout (); return;
X    }
X
X    if (tpages > 1) 
X    {
X	atxy (66+xoff,
X		(strlen(wdname)+strlen(username)+mode+strlen(dirmsg[dir_status])
X		> 45+xoff) ? 2: 1);
X	if (column > 1 && cpage != tpages) {
X		po = cpage+column-1;
X		if (po > tpages)
X			po = tpages;
X		printf ("Page %d-%d / %d", cpage, po, tpages);
X	}
X	else
X		printf ("Page %d / %d", cpage, tpages);
X    }
X
X    hilite(0);
X    po = pageoff;
X    pageoff = 0;
X
X	do {
X		pe = pgend();
X		for(dirx=0, dirchar='a'; dirx < pe; dirx++, dirchar++) {
X			if (pageoff == 0) {
X				atfile (dirx, 1);
X				printf("%c   ", dirchar);
X			}
X			else
X				atfile (dirx, OFFFILE+(pageoff*colfield));
X			printf("%s", filename(dirx));
X			stat(filename(dirx),&tmpsbuf);
X			mode = tmpsbuf.st_mode;
X			if ((mode&S_IFMT) == S_IFDIR)
X				printf("/");
X			else if (mode&S_IEXEC)
X				printf("*");
X		}
X		pageoff++;
X	} while (pageoff < column && (cpage+pageoff) <= tpages);
X	pageoff = po;
X
X    if (pageoff >= column)
X	pageoff = column - 1;
X    if (cpage+pageoff > tpages)
X	pageoff = tpages - cpage;
X    if (reload && *selectname
X	&& (selectcmd >= pgend()
X	|| strcmp(filename(selectcmd), selectname)))
X	*selectname = 0;
X    if (*selectname) {
X	atfile(selectcmd, OFFARROW+colfield*pageoff);
X	printf(arrow);
X    }
X    if (column > 1)
X	colprompt();
X
X    if (*HELPFILE) {
X	mode = 0;
X	atfile (mode, 24+xoff);
X	for (dirx = 0; dirchar = helptext[dirx]; dirx++) {
X		if (dirchar == '\r')
X			continue;
X		else if (dirchar == '\n')
X			atfile(++mode, 24+xoff);
X		else
X			putch(dirchar);
X	}
X    }
X
X    unbufout ();
X}
X
X/*	Change dir to father of dir  */
Xtodotdot (dir) char *dir;
X{
X
X    register char *cp;
X
X    for (cp = dir; *cp; cp++);	/* Scan to end of name */
X    while (*--cp != '/');	/* Scan back to a slash */
X    if (cp == dir) cp++;	/* Must handle root specially */
X    *cp = 0;
X}
X
X/* Calculate end of current page including offset */
Xpgend()
X{
X	register int pe;
X
X	pe = tfiles % nfpp;
X	if ((cpage+pageoff) != tpages || pe == 0)
X		pe = nfpp;
X	return pe;
X}
All work and no play makes Jack a dull boy
echo src/dircmd.c
sed 's/^X//' > src/dircmd.c << 'All work and no play makes Jack a dull boy'
X#include "hd.h"
X#include "mydir.h"
X
Xdircmd (cmd) register cmd; 
X{
X  static int eotflag;
X  register ret;	/* return value */
X  register int i;
X  int scmd, selflag;
X  int putch();
X  char oldvimotion;
X  extern int didlong;		/* from longlist() */
X
X  ret = REPLOT;
X  scmd = cmd;
X  selflag = (VSHMODE == SELECTMODE);
X  /* Defaults to EOT */
X  if (cmd == (QUITCHAR-'@')) {
X	if (eotflag++) {
X		clearmsg(2);
X		printf("\r\n\n");
X		leave ();
X	}
X	putmsg("(Quit)");
X	return NOREPLOT;
X  }
X  else {
X    eotflag = 0;
X    if ((cmd == '\'' || (cmd == '\r' && cmd != PAGECHAR-'@')) && selflag) {
X	if (*selectname)
X		cmd = 'a'+selectcmd;
X	else {
X		putmsg("Nothing selected");
X		return NOREPLOT;
X	}
X    }
X    else if (VSHMODE == SELECTMODE && VIMOTION)
X	cmd = vi_motion(cmd);
X    if (cmd == LF)
X	ret = enterdir (DOTDOT);
X    else if (tfiles == 0) {
X	putmsg("No files");
X	return NOOP;
X    }
X    else if ((cmd == '+') || (column < 2 && cmd == CTLF)) {
X	cpage += pageoff ? pageoff : 1;
X	if (cpage > tpages)
X		cpage = 1;
X	pageoff = 0;
X    }
X    else if ((cmd == EOT) || (cmd == ESNP) || (cmd == (PAGECHAR-'@'))) {
X	if (cpage == tpages)
X		cpage = 1;
X	else {
X		cpage += column > 1 ? column-1 : 1;
X		if (cpage > tpages)
X			cpage = tpages;
X	}
X	pageoff = 0;
X    }
X    else if (cmd == TABCMD || cmd == ESRT || cmd == ESLF) {
X	if (column > 1) {
X		i = pageoff;
X		/* Cleanup display after longlisting */
X		if (didlong)
X			dispdir(0);
X		if (cmd == ESLF) {
X			if (pageoff == 0) {
X				pageoff = column - 1;
X				if ((cpage+pageoff) >= tpages)
X					pageoff = tpages - cpage;
X			}
X			else
X				pageoff--;
X		}
X		else {
X			if ((cpage+pageoff) >= tpages || pageoff >= (column-1))
X				pageoff = 0;
X			else 
X				pageoff++;
X		}
X		bufout();
X		atxy(OFFFILE+colfield*i, 2);
X		printf(" ");
X		colprompt();
X		/* Fix selected item */
X		if (cpage != tpages && *selectname) {
X			atfile(selectcmd, OFFARROW+colfield*i);
X			printf("  ");
X			*selectname = 0;
X			/* Kludge ! */
X			oldvimotion = VIMOTION;
X			VIMOTION = 0;
X			dircmd(selectcmd+'a');
X			VIMOTION = oldvimotion;
X		}
X		unbufout();
X	}
X	ret = NOREPLOT;
X    }
X    else if ((cmd >= 'a' && cmd <= 'z') || cmd == ESUP || cmd == ESDN)
X    {
X	i = pgend()-1;
X	if (cmd == ESUP) {
X		if (*selectname) {
X			if (i == 0)
X				return NOREPLOT;	
X			cmd = selectcmd-1;
X			if (cmd < 0)
X				cmd = i;
X		}
X		else
X			cmd = selflag ? 0 : i+1;
X	}
X	else if (cmd == ESDN) {
X		if (*selectname) {
X			if (i == 0)
X				return NOREPLOT;
X			cmd = selectcmd+1;
X			if (cmd > i)
X				cmd = 0;
X		}
X		else
X			cmd = selflag ? 0 : i+1;
X	}
X	else
X		cmd -= 'a';
X	if (cmd > i)
X		ret = NOOP;
X	else if (selflag && (*selectname == 0 || selectcmd != cmd)) {
X		if (*selectname) {
X			atfile(selectcmd, OFFARROW+colfield*pageoff);
X			printf("  ");
X		}
X		selectcmd = cmd;
X		selectpage = cpage+pageoff;
X		atfile(cmd, OFFARROW+colfield*pageoff);
X		printf(arrow);
X		strcpy(selectname, filename(cmd));
X		ret = NOREPLOT;
X	}
X	else if (enterfile (filename (cmd)) == NOREPLOT) 
X	{
X/*
X	    atfile(cmd, OFFARROW+colfield*pageoff); printf("  ");
X	    longfile (cmd);
X */
X	    ret = NOREPLOT;
X	}
X    }
X    else if (cmd == ESBS || cmd == ESFS) {
X	/* i is max of window */
X	ret = (cmd == ESFS);
X	if (*selectname)
X		i = *selectname;
X	else {
X		i = ret ? pgend()-1 : 0;
X		i = (filename(i))[0];
X	}
X	if (ret)
X		i++;
X	else
X		i--;
X	ret = findc(i, ret);
X    }
X    else if (cmd > '0' && cmd <= '9') {
X	cpage = cmd - '0';
X	pageoff = 0;
X    }
X    else if (cmd == '0') {
X	cpage = tpages;
X	pageoff = 0;
X    }
X    else if (cmd == '-')
X    {
X	cpage--;
X	if (cpage < 1) cpage = tpages;
X	pageoff = 0;
X    }
X    else if (cmd == CTLU) {
X	if (cpage == 1)
X		cpage = tpages;
X	else {
X		cpage -= column > 1 ? column-1 : 1;
X		if (cpage < 1)
X			cpage = 1;
X	}
X	pageoff = 0;
X    } 
X    else if (cmd == CTLL)
X	*selectname = 0;
X    else
X	ret = NOOP;
X  }
X  /* VI style motion commands */
X  if (scmd != cmd && ret == NOOP && 'h' <= scmd && scmd <= 'l' && scmd != 'i') {
X	ret = dircmd(vi_motion(scmd));
X  }
X  if (cpage+pageoff != selectpage)
X	*selectname = 0;
X  return ret;
X}
X
Xcolprompt()
X{
X	atxy(OFFFILE+colfield*pageoff, 2);
X	tputs(BO, 0, putch);
X	printf("V");
X	tputs(BE, 0, putch);
X}
X
Xvi_motion(cmd)
Xregister int cmd;
X{
X	switch(cmd) {
X	case 'h':
X		cmd = ESLF;
X		break;
X	case 'j':
X		cmd = ESDN;
X		break;
X	case 'k':
X		cmd = ESUP;
X		break;
X	case 'l':
X		cmd = ESRT;
X		break;
X	}
X	return cmd;
X}
All work and no play makes Jack a dull boy
echo src/dirlist.c
sed 's/^X//' > src/dirlist.c << 'All work and no play makes Jack a dull boy'
X#include "hd.h"
X#include "mydir.h"
X#include "command.h"
X#include <pwd.h>
X
X#define SHIFT1	13
X#define SHIFT2	6
X#define SHIFT3	3
X#define MASK	07
X
Xchar *pfstatus (fname) char * fname;
X{
X
X/* long listing of a file */
X    static char *mchar [2] [8] = 
X    {
X	    "---", "--x", "-w-", "-wx",
X	    "r--", "r-x", "rw-", "rwx",
X	    "--s", "--s", "-ws", "-ws",
X	    "r-s", "r-s", "rws", "rws"
X    } ;
X
X    static char fformat [8] = 
X    {
X#ifdef	VENIX
X	'0', '1', '2', '3', ' ', 'c', 'd', 'b'
X#else
X#ifdef	V6
X	'0', '1', '2', '3', ' ', 'c', 'd', 'b'
X#else
X	' ', 'c', 'd', 'b', '-', 'l', 's', '?'
X#endif
X#endif
X    } ;
X
X    register mode;
X    struct passwd *getpwuid();
X    static struct passwd *p;
X#ifdef	SYMLINK
X    static char slink[STRMAX];
X    int sflag;
X
X    sflag = 0;
X    if (lstat (fname, &scr_stb)) 
X#else
X    if (stat (fname, &scr_stb)) 
X#endif
X    {
X	printf ("Cannot Access");
X	return 0;
X    }
X    mode = scr_stb.st_mode;
X
X#ifdef	SYMLINK
X	if ((mode&S_IFLNK) == S_IFLNK) {
X		mode = readlink(fname, slink, STRMAX-1);	
X		if (mode == -1) {
X			printf ("Cannot read link");
X			return 0;
X		}
X		slink[mode] = 0;
X		sflag++;
X		if (stat (fname, &scr_stb)) {
X			printf ("Cannot Access");
X			return 0;
X		}
X		mode = scr_stb.st_mode;
X	}
X#endif
X
X    printf ("%c%s%s%s%s%2d",
X	(mode & S_ISVTX) ? 't' : 
X	fformat [(mode >> SHIFT1) & MASK],
X	mchar [(mode & S_ISUID) != 0] [(mode >> SHIFT2) & MASK],
X	mchar [(mode & S_ISGID) != 0] [(mode >> SHIFT3) & MASK],
X	mchar [0] 		      [mode & MASK],
X	scr_stb.st_nlink > 99 ? "" : " ",
X	scr_stb.st_nlink);
X	/* dyt */
X    if (p == 0 || p->pw_uid != scr_stb.st_uid)
X	p = getpwuid(scr_stb.st_uid);
X    if (p)
X	printf(" %8s", p->pw_name);
X    else
X	printf(" %8d", scr_stb.st_uid);
X    mode &= S_IFMT;
X    if (mode == S_IFCHR || mode == S_IFBLK)
X	printf ("%5d, %3d",
X#ifdef	V6
X	major (scr_stb.st_addr[0]), minor (scr_stb.st_addr[0]));
X#else
X	major (scr_stb.st_rdev), minor (scr_stb.st_rdev));
X#endif
X    else
X#ifdef	V6
X	printf ("%10ld", (((long)scr_stb.st_size0&0377)<<16L)
X		+ (unsigned)scr_stb.st_size1);
X#else
X	printf ("%10ld", scr_stb.st_size);
X#endif
X    printf (" %.24s", ctime (&scr_stb.st_mtime));
X#ifdef	NDIR
X    return (sflag ? slink : 0);
X#endif
X}
X
X/* This prints out the protection modes of the files on the current
X   page.  It knows the page from the global variable cpage.  The
X   value NOREPLOT is always returned, to make globalcmd happy.
X*/
Xint didlong;
X
Xlonglist () 
X{		/* long listing for entire page */
X    register i, j;
X	
X    bufout ();
X    j = pgend();
X    for (i=0; i < j; i++) longfile (i);
X    didlong = j;
X    unbufout ();
X
X    return CMD_DATE;	/* Run date command */
X}
X
Xlongfile (index) int index;
X{
X    register char *s;
X    register int i;
X    int putch();
X
X    if (pageoff) {
X	cpage += pageoff;
X	pageoff = 0;
X	i = column;
X	column = 1;	/* Display only current page */
X	dispdir(0);
X	column = i;
X    }
X    atfile (index, 23);
X    if (CE)
X	tputs(CE, 0, putch);
X    s = pfstatus (filename (index));
X#ifdef	SYMLINK
X    if (s) {
X	if (xoff < 10) {
X		atfile (index, OFFFILE-2);
X		printf(" @");
X	}
X	printf("%-18.18s", s);
X    }
X#endif
X}
X
X/* Warning: some systems have macros which define these in <sys/types.h> */
X#ifdef	 MACMAJOR
Xmajor(i)
Xdev_t i;
X{
X    return (i>>8);
X}
X
Xminor(i)
Xdev_t i;
X{
X    return (i&0377);
X}
X#endif
All work and no play makes Jack a dull boy
echo src/enterf.c
sed 's/^X//' > src/enterf.c << 'All work and no play makes Jack a dull boy'
X#include "hd.h"
X#include "mydir.h"
X#include "classify.h"
X
X/* Enterfile selects its parameter fname;  Fname may either be a single
X   element file name (no slashes) or a full path name.  Enterfile
X   can handle files which look like ".", "..", "file.c", or "/a/b".
X   For files which could look like "/a/b/", "a/b", or "./../../a" use
X   the procedure "file" (file expects an argument in argv format).
X*/
Xenterfile (fname) register char *fname; 
X{
X    register char *s;
X    register int flag;
X    int i;
X
X    flag = classify(fname);
X    /* Protect user against entering binary files */
X    if (flag == CL_UNKPLN) {
X	putmsg(" Binary file, enter ?");
X	i = getch();
X	if (i == 'y' || i == 'Y')
X		flag = CL_TEXT;
X    }
X    switch (flag) 
X    {
X
X      case CL_NULL: 
X      case CL_PROTPLN:
X	myperror (fname); return NOREPLOT;
X
X      case CL_DIR:
X	return enterdir (fname);
X
X      case CL_CORE:
X	f_exec (DEBUGGER, DEBUGGER, fname, 0); return REPLOT;
X
X      case CL_AOUT:
X	p_exec ("nm", "nm", fname, 0); return REPLOT;
X
X      case CL_AR:
X	p_exec ("ar", "ar", "tv", fname, 0); return REPLOT;
X
X      case CL_CPIO:
X	p_exec (0, fname, "cpio", "cpio", "-ivt", 0); return REPLOT;
X
X      case CL_PACK:
X	p_exec ("pcat", "pcat", fname, 0); return REPLOT;
X
X      case CL_COMPACT:
X	p_exec (0, fname, "uncompact", "uncompact", 0); return REPLOT;
X
X      case CL_COMPRESS:
X	p_exec (0, fname, "uncompress", "uncompress", 0); return REPLOT;
X
X      case CL_TEXT:
X	flag = REPLOT;
X	if (strcmp(ENTERTEXT, ENTEREDIT) == 0)
X		f_exec (EDITOR, EDITOR, fname, 0);
X	else if (strcmp(ENTERTEXT, ENTERDISP) == 0)
X		flag = help(fname);
X	else {
X		s = ENTERTEXT;
X		if (*s == ';')
X			s++;
X		f_exec (s, s, fname, 0);
X		if (*ENTERTEXT != ';')
X			getrtn();
X	}
X	return flag;
X
X
X      default:
X	putmsg (fname); printf (":  Vsh cannot handle this file");
X    }
X    return NOREPLOT;
X}
Xhome () 
X{			/* enter home directory */
X
X    return file (&HOME);
X}
All work and no play makes Jack a dull boy
echo src/file.c
sed 's/^X//' > src/file.c << 'All work and no play makes Jack a dull boy'
X#include "hd.h"
X#include "mydir.h"
X#include "strings.h"
X#include "classify.h"
X#include <pwd.h>
X
Xchar *getuser();
X
X/* File gets a file name, converts it into a full path name, and
X   selects that file.  */
X
Xfile (argv) char **argv; 
X{	/* Select specific file */
X    register char *msg;
X    char nname [STRMAX];
X
X    msg = 0;
X    if (*argv == CNULL)
X	/* Flag path searching */
X	msg = "~File: ";
X    if (getfname (*argv, nname, msg) == BAD) return NOREPLOT;
X
X    return (enterfile (nname));
X}
X
X/* Create accepts a file name, creats that file, and then enters it.  */
X
X#define	CRTEXT	'1'
X#define	CRDIR	'2'
X#define	CRCOPY	'3'
X#define	CRLINK	'4'
X#define	CRMOVE	'5'
X
Xstatic char *cr_msgs[3] = {
X	";\rCopy from:", ";\rLink from:", ";\rRename from:"
X};
X
Xstatic int force = 0;
X
Xcreate () 
X{
X
X    char nnamebuf [STRMAX], oname [STRMAX];
X    register char ch, *cp;
X    register int class;
X    char *nname;
X
X    nname = nnamebuf;
X    if (getfname (CNULL, nname, "!Create: ") == BAD) return NOREPLOT;
X
X    if (!access (nname, 0)) 
X    {
X	putmsg (nname); printf (": Already exists");
X	if (force) {
X		printf(", creating anyways");
X		sleep(1);
X	}
X	else {
X		printf(", !filename to overwrite");
X		return NOREPLOT;
X	}
X    }
X    else
X	force = 0;
X
X    /* Can we write-access the directory ? */
X    strcpy(oname, nname);
X    todotdot (oname);
X    class = classify (oname);
X
X    if (class == CL_NULL || access (oname, 3)) 
X    {
X	myperror (oname); return NOREPLOT;
X    }
X    else if (class != CL_DIR) 
X    {
X	putmsg (oname); printf (": Not a directory");
X	return NOREPLOT;
X    }
X
X    erase ();
X    hilite ("Creating");
X
X    printf (" %s\r\n\n1  Text\r\n2  Directory\r\n3  Copy a file\r\n4  Link a file\r\n5  Rename a file or directory\r\n\n", nname);
X    hilite ("Select:");
X
X    ch = getch (); putch (CR); putch (LF);
X    erase();
X    if (ch == CRTEXT) 
X    {
X	f_exec (EDITOR, EDITOR, nname, 0);
X    }
X    else if (ch == CRDIR) 
X    {
X	if (f_exec ("/bin/mkdir", "mkdir", nname, 0))
X		getrtn ();
X	else {
X		hilite("Directory created. Enter new directory?");
X		if (getch() == 'y')
X			return enterdir (nname) | REPLOT;
X		else
X			return REPLOT;
X	}
X    }
X    else if (ch == CRCOPY || ch == CRLINK || ch == CRMOVE) 
X    {
X	if (getfname (CNULL, oname, cr_msgs[ch-CRCOPY]) == BAD) return REPLOT;
X
X	switch (classify (oname)) 
X	{
X
X	  case CL_NULL: 
X	  case CL_PROTPLN:
X	    myperror (oname); break;
X
X	  case CL_DIR:
X	    if (ch != CRMOVE) {
X		hilite ("Cannot copy or link to directories");
X		break;
X	    }
X
X	  default:
X	    if (ch == CRCOPY)
X		f_exec ("/bin/cp", "cp", oname, nname, 0);
X	    else if (ch == CRMOVE)
X		f_exec ("/bin/mv", "mv", oname, nname, 0);
X	    else if (ch == CRLINK) 
X	    {
X		hilite ("Linking\r\n");
X		if (link (oname, nname)) {
X			myperror ("Link failed");
X			break;
X		}
X	    }
X/*
X	    at (1501);
X */
X	    if (!access (nname, 0)) 
X	    {
X		hilite("\r\n\nFile created. Do you wish to examine it?");
X		if (getch() == 'y') 
X		{
X		    putch (CR);
X		    putch (LF);
X		    return enterfile (nname) | REPLOT;
X		}
X		return REPLOT;
X	    }
X	}
X/*
X	at (1501);
X */
X	hilite ("\r\n\nFile not created.");
X	getrtn ();
X    }
X    return REPLOT;
X}
X
X/* Getfname takes two character arrays as parameters.
X   Inname is the partial pathname of a file.  If inname == CNULL,
X   getfname will instead read the partial pathname from the terminal.
X   The full pathname is returned in outname.
X   Getfname has a return value of GOOD or BAD.
X*/
Xgetfname (inname, outname, msg) register char *inname, *outname, *msg; 
X{
X    char inword [STRMAX]; int ilen;
X    int ffind;
X    static oldfile[STRMAX];
X
X    force = 0;
X    ffind = 0;
X    if (msg && *msg == '~') {
X	msg++;
X	ffind++;
X    }
X    if (inname == CNULL) 
X    {
X	tty_push (COOKEDMODE);
X	if (msg && *msg == '!') {
X		msg++;
X		force++;
X	}
X	if (msg) {
X		if (*msg == ';')
X			hilite(++msg);
X		else
X			putmsg(msg);
X	}
X	ilen = getword (inword);
X	tty_pop ();
X	if (ilen <= 0) 
X	{
X	    clearmsg (0);
X	    return BAD;
X	}
X	inname = inword;
X	if (*inname == '!' && force) {
X		inname++;
X		ilen--;
X		if (*inname == 0) {
X			putmsg("No file name");
X			return BAD;
X		}
X	}
X	else
X		force = 0;
X	if (strcmp("!", inname) == 0)
X		strcpy(inname, oldfile);
X	if (inname[ilen-1] == '$') {
X		if (*selectname == 0) {
X			putmsg(" Missing argument");
X			return BAD;
X		}
X		strcpy(inname+ilen-1, selectname);
X		putmsg("%s%s", msg, inname);
X	}
X    }
X
X    /*
X     * Search for file amongst specified directories
X     */
X    if (ffind
X	&& inname[0] != '/'
X	&& (inname[0] != '.' || inname[1] != '/')
X	&& srchfile(inname, outname) == GOOD) {
X	strcpy(oldfile, outname);
X	return GOOD;
X    }
X    if (pathgen(wdname, inname, outname)) {
X	putmsg ("Path name too long");
X	return BAD;
X    }
X    strcpy(oldfile, outname);
X    return GOOD;
X}
X
Xsrchfile(inname, outname)
Xchar *inname, *outname;
X{
X	register char *s, *t;
X	char pbuf[STRMAX];
X
X	s = ENTERPATH;
X	while (*s) {
X		if (*s == ':') {
X			s++;
X			t = wdname;
X		}
X		else {
X			t = s;
X			while (*s)
X				if (*s++ == ':') {
X					if (*s)
X						s[-1] = 0;
X					else
X						*--s = 0;
X					break;
X				}
X		}
X		strcpy(pbuf, t);
X		strcat(pbuf, SLASH);
X		strcat(pbuf, inname);
X		if (pathgen(wdname, pbuf, outname) == 0
X			&& classify(outname) != CL_NULL) {
X			if (*s)
X				s[-1] = ':';
X			return GOOD;
X		}
X		if (*s)
X			s[-1] = ':';
X	}
X	return BAD;
X}
X
X/* If one is in dir with pathname "old", and does a chdir "change",
X   one ends up in directory "new".  Exception: ".." always breaks
X   through to the root.
X*/
Xpathgen (old, change, new) char *old, *change, *new; 
X{
X
X#ifndef	NDIR
X    char element [DIRSIZ + 1];
X#else
X    char element [MAXNAMLEN + 1];
X#endif
X    char chgbuf  [STRMAX];
X    register char *s;
X    register len;
X
X    /* Match a user's login directory, or HOME */
X    if (getuser(change, chgbuf) == 0)
X	strcpy (chgbuf, change);
X    s = chgbuf;
X    if (*s == '/')
X	strcpy(new, SLASH);
X    else
X	strcpy(new, old);
X
X    while (*s) 
X    {
X	extract (element, s);
X	if (compe (DOT, element));
X	else if (compe (DOTDOT, element))
X	    todotdot (new);
X	else
X	{
X	    len = strlen (new);
X	    if (len > LPLEN) return 1;
X	    else if (len > 1) strcat (new, SLASH);
X	    strcat (new, element);
X	}
X    }
X    return 0;
X}
X
Xextract (element, path) char *element, *path; 
X{
X
X    register char *cp;
X    int eltlen;
X
X    for (cp = path; *cp != 0 && *cp != '/'; cp++);
X
X    eltlen = cp - path;
X    if (eltlen == 0) 
X    {
X	strcpy (element, DOT);
X    }
X    else
X    {
X#ifndef	NDIR
X	strncpy (element, path, DIRSIZ);
X	element [min (eltlen, DIRSIZ)] = 0;
X#else
X	strncpy (element, path, MAXNAMLEN);
X	element [min (eltlen, MAXNAMLEN)] = 0;
X#endif
X    }
X    if (*cp) shift (path, eltlen + 1);
X    else path [0] = 0;
X}
X
Xshift (path, length) char *path; int length; 
X{
X
X    register char *cp;
X
X    for (cp = path + length; cp [-1];) *path++ = *cp++;
X}
X	
X/*
X * getuser(spec, pbuf)
X */
Xchar *getuser(spec, pbuf)
Xchar *spec, *pbuf;
X{
X	register char *r, *s, *t;
X	struct passwd *p;
X	struct passwd *getpwnam();
X
X	s = spec;
X	if (*s++ != '~')
X		return 0;
X	t = pbuf;
X	while (*t = *s) {
X		if (*s++ == '/') {
X			*t = 0;
X			break;
X		}
X		t++;
X	}
X	if (t == pbuf)
X		t = HOME;
X	else if (p = getpwnam(pbuf))
X		t = p->pw_dir;
X	else
X		t = spec;
X	r = pbuf;
X	while (*r++ = *t++)
X		if (r >= pbuf+LPLEN)
X			return 0;
X	if (*s) {
X		r[-1] = '/';
X		while (*r++ = *s++)
X			if (r >= pbuf+STRMAX)
X				return 0;
X	}
X	return pbuf;
X}
All work and no play makes Jack a dull boy
echo src/find.c
sed 's/^X//' > src/find.c << 'All work and no play makes Jack a dull boy'
X
X#include "hd.h"
X#include "strings.h"
X#include "command.h"
X#include "classify.h"
X#include "mydir.h"
X
X#ifndef	NDIR
Xextern char **d_namep;
X#else
Xextern struct direct **d_dirp;
X#endif
Xextern char quitcmds[];
X
Xfind(argv)
Xchar **argv;
X{
X	register int c;
X
X	if (*argv == CNULL) {
X		putmsg("Find: ");
X		c = getch();
X		putch(c);
X	}
X	else
X		c = **argv;
X	if (c == 0 || c == EOF || any(c, quitcmds) != NULL) {
X		clearmsg(1);
X		return NOREPLOT;
X	}
X	if (*argv == CNULL)
X		printf("'s");
X	return findc(c, 1);
X}
X
Xfindc(c, forw)
Xregister int c;
Xregister int forw;
X{
X	register int i;
X
X	for (i = 0; i < tfiles; i++)
X#ifndef	NDIR
X		if (c <= d_namep[i][0]) {
X#else
X		if (c <= d_dirp[i]->d_name[0]) {
X#endif
X			if (!forw && i)
X				i--;
X			return findfile(i);
X		}
X	return findfile(tfiles-1);
X}
X
Xfindfile(index)
Xregister int index;
X{
X	register int i, j, f;
X
X	i = (index+nfpp)/nfpp;
X	j = index%nfpp;
X	if ((column < 2 && i != cpage) || i < cpage || i > cpage+column-1) {
X		pageoff = 0;
X		cpage = i;
X		*selectname = 0;
X		dispdir(0);
X		if (VSHMODE == SELECTMODE)
X			dircmd(j+'a');
X	}
X	else {
X		f = (cpage+pageoff > i);
X		while (cpage+pageoff != i)
X			dircmd(f ? ESLF : TABCMD);
X		f = (selectcmd < j);
X		if (VSHMODE == SELECTMODE)
X			while (*selectname == 0 || selectcmd != j)
X				dircmd(f ? ESDN : ESUP);
X	}
X	return NOREPLOT;
X}
All work and no play makes Jack a dull boy
echo src/grep.c
sed 's/^X//' > src/grep.c << 'All work and no play makes Jack a dull boy'
X#include "hd.h"
X#include "strings.h"
X#include "command.h"
X
X/* Interface to grep */
X
X#define GBUFLEN 200
X#define LIM1	(gbuf + 100)
X
X#define QUOTE	'\''
X#define BSLASH	'\\'
X
X#define GSTR1	" -n '"
X#define GSTR2	"' /dev/null "
X
X#define CPSET	{cp = gbuf + strlen (gbuf);}
X
X#define	GREPLEAVE	{tty_pop ();  clearmsg (0);  return NOREPLOT;}
X
X/* User is asked to supply patterns and file names.  Grep is then
X   run with its output directed to .grepout.  If the user changes his
X   mind, and leaves without running grep, NOREPLOT is returned.
X   Else REPLOT | CMD_SG is returned.
X*/
Xgrep () 
X{
X    register char *cp, *clim; register ch;
X    char gbuf [GBUFLEN];
X    char inline [STRMAX]; int inlength; register char *incp;
X
X    FILE *sstream;
X    extern FILE *showopen ();
X
X    int saveout;
X
X    extern char wdname [];
X
X    tty_push (COOKEDMODE);
X    strcpy (gbuf, GREP); strcat (gbuf, GSTR1);
X    clearmsg (2); putmsg("Grep pattern:");
X    printf(" ");
X    CPSET; clim = LIM1;
X
X    inlength = getline (inline); incp = inline;
X    if (inlength == 0) GREPLEAVE;
X
X    while ((ch = *incp++) && cp < clim) 
X    {
X	if (ch == QUOTE) 
X	{
X	    *cp++ = QUOTE; *cp++ = BSLASH;
X	    *cp++ = QUOTE; *cp++ = QUOTE;
X	}
X	else *cp++ = ch;
X    }
X    *cp=0;
X    strcat (gbuf, GSTR2);
X    atxy (20 + inlength, window - 1);
X    hilite ("%sGrep files:", (*SO ? "" : "-- "));
X    printf(" ");
X
X    CPSET;
X
X	ch = inlength;
X	inlength = xgetline (stdin, cp, GBUFLEN - strlen (gbuf));
X	if (inlength == 0) GREPLEAVE;
X	if (strcmp(cp, "$") == 0) {
X		if (VSHMODE == SELECTMODE && selecttype == DIRCMD
X			&& *selectname) {
X			strcpy(cp, selectname);
X			atxy(ch + 32 + (*SO ? 0 : 3), window - 1);
X			printf("%s\r\n", cp);
X		}
X		else {
X			hilite("Nothing selected");
X			GREPLEAVE;
X		}
X	}
X
X    /* Now run the command in gbuf */
X
X    sstream = showopen ("w", GREPMODE);
X    if (sstream == NULL) GREPLEAVE;
X
X    hilite ("Searching");
X
X    saveout = dup (outfile);	/* Set up files */
X    close (outfile); dup (fileno (sstream)); fclose (sstream);
X
X    printf ("%s is search directory\r\n", wdname);
X    mysystem (gbuf);
X    close (outfile); dup (saveout); close (saveout);
X
X
X    tty_pop (); return CMD_SG | REPLOT;
X}
All work and no play makes Jack a dull boy
exit