VSH sources 3 of 6
Dan Ts'o
dan at rna.UUCP
Fri Jun 28 13:58:13 AEST 1985
# Here is part 3 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/hd.h
sed 's/^X//' > src/hd.h << 'All work and no play makes Jack a dull boy'
X/* Header file for all procedures in Vsh */
X#include "stdio.h"
X
X/* #define PWBTTY 1 /* Some local stuff */
X/* #define USGTTY 1 /* 3.0-5.0 drivers */
X#define V7TTY 1 /* V7 - ?.BSD drivers */
X/* #define V6 1 /* Version 6 stuff */
X#define NDIR 1 /* New 4.2BSD directories */
X#define SYMLINK 1 /* 4.2BSD symbolic links */
X#define VFORK 1 /* Has vfork() */
X/* #define MACMAJOR 1 /* types.h missing major() */
X
X/*
X * Buffer size for backing up more(). This buffer is malloc()'d in page()
X * unless MBUFSTACK is defined. PDP-11's and the like should probably
X * define MBUFSTACK, otherwise less data space will be available for
X * directories. page() will try to malloc() less, if reasonable.
X */
X/*#define MBUFSTACK 1 /* Put more buffer on stack */
X#define MBUFSIZE 7000 /* Used only with MBUFSTACK */
X#define MMAXSIZE "10000" /* To init param moresize */
X
X#define VERSION "4.2"
X
X#define max(arg1,arg2) ((arg1 > arg2) ? arg1 : arg2)
X#define min(arg1,arg2) ((arg1 < arg2) ? arg1 : arg2)
X#define compe(arg1,arg2) (strcmp (arg1, arg2) == 0)
X
X/* Standard file numbers */
X#define infile 0
X#define outfile 1
X#define errorfile 2
X
X/* The values of special keys */
X#define EOT 4
X#define RUBOUT 0177
X#define CR 015
X#define LF 012
X
X/* Directory commands */
X#define CTLF 006
X#define CTLL 014
X#define CTLU 025
X#define TABCMD 011 /* Multi-column shift */
X
X/* Emacs select positioning */
X#define ESUP 020 /* ^P */
X#define ESDN 016 /* ^N */
X#define ESLF 002 /* ^B */
X#define ESRT 006 /* ^F */
X#define ESBS 001 /* ^A back series */
X#define ESFS 005 /* ^E forward series */
X#define ESNP 026 /* ^V next page */
X
X/* Display offsets */
X#define OFFFILE 5
X#define OFFARROW 3
X
X/* Standard file names */
X#define LOGFILE "/usr/adm/vsh.log"
X#define DEBUGGER "/bin/adb"
X
X/* Other parameters */
X#define STRMAX 120 /* Length of string buffers */
X#define CNULL ((char *) 0) /* Null char pointer */
X#define ARGVMAX 20 /* Size of a readarg argv */
X#define PAGEMIN 5 /* Minimum page window */
X#define MAILCLK (1*60) /* Check for mail interval */
X
X#define VSHTOP 2 /* Lines needed at top of display */
X#define VSHBOT 2 /* Lines needed at bottom of display */
X#define VSHLEFT 4 /* Spaces needed at left of display */
X
X/* Parms loadable through .vshrc are accessed through command.h.
X Alter their default values in cmdini.c */
X
X/* Tty_set parameters */
X#define RAWMODE 0
X#define COOKEDMODE 1
X
X/* Functions called by command return the next command to execute. */
X/* In addition, the following bits are returned. */
X
X#define CMDMASK 0x00ff /* Bits of next command */
X#define REPLOT 0x0100 /* Must replot directory */
X#define NOOP 0x0200 /* Return for command not found */
X#define ENTERDIR 0x0400 /* New directory entered */
X
X/* If no special return is necessary, use return REPLOT or NOREPLOT. */
X#define NOREPLOT 0x0000
X
X/* GOOD or BAD returns */
X#define GOOD 1
X#define BAD 0
X
X/* When calling command, indicate type of command: */
X#define DIRCMD 1
X#define SHOWCMD 2
Xextern char dircmds[];
X
X/* Show operates in two modes */
X#define GREPMODE 0
X#define MAKEMODE 1
X
X/* Select or enter mode */
X#define ENTERMODE 0
X#define SELECTMODE 's'
Xextern char selectname[STRMAX];
Xextern int selectcmd;
Xextern int selectpage;
Xextern int selecttype;
X
Xextern char username[];
Xextern char *arrow;
Xextern char *helptext;
X
Xextern int window, owindow, ewindow;
Xextern int xoff; /* Column offset for vary CRT widths */
X
X/*
X * Custom enter text info
X */
X#define ENTEREDIT "$EDITOR" /* Enter $EDITOR for text */
X#define ENTERDISP "display" /* Use internal display() for text */
X
X/* Parameters from .vshrc file. P_name is the parameter name, p_val is
X the parameter's value.
X*/
X
Xstruct parmstruct {
X char *p_name,
X *p_val;
X};
X
Xextern struct parmstruct parmtab[];
X
X/* References to the various parameters */
X
X#define EDITOR parmtab[0].p_val
X#define MAKE parmtab[1].p_val
X#define GREP parmtab[2].p_val
X#define RMHELP parmtab[3].p_val
X#define SHOWHELP parmtab[4].p_val
X#define MAKERROR parmtab[5].p_val
X#define GREPOUT parmtab[6].p_val
X#define VSHMODE (*parmtab[7].p_val)
X#define QUITCHAR (*parmtab[8].p_val)
X#define PAGECHAR (*parmtab[9].p_val)
X#define PATH parmtab[10].p_val
X#define TERM parmtab[11].p_val
X#define HOME parmtab[12].p_val
X#define SHELL parmtab[13].p_val
X#define ENTERTEXT parmtab[14].p_val
X#define WINDOW parmtab[15].p_val
X#define HELPFILE parmtab[16].p_val
X#define COLUMN parmtab[17].p_val
X#define NOARG (*parmtab[18].p_val)
X#define VIMOTION (*parmtab[19].p_val)
X#define MAIL parmtab[20].p_val
X#define MORESIZE parmtab[21].p_val
X#define ENTERPATH parmtab[22].p_val
X
X/* Termcap */
Xextern char *BC, *UP, *CM, *CL, *tgoto();
Xextern char *CE, *SO, *SE;
Xextern short PC;
Xextern int CO, LI;
Xextern char *CS;
X/* A new one, clear to beginning of display */
Xextern char *CB;
Xextern char *BO, *BE;
Xextern char *SR, *CD;
Xextern int AM, XN;
Xextern char *TI, *TE;
All work and no play makes Jack a dull boy
echo src/help.c
sed 's/^X//' > src/help.c << 'All work and no play makes Jack a dull boy'
X#include "hd.h"
X
X/* Help displays a file in paged mode. The parm is the file name. */
X
Xhelp (parm) char *parm;
X{
X FILE *helpfile;
X int flag;
X
X flag = 0;
X helpfile = fopen (parm, "r");
X if (helpfile == NULL)
X {
X myperror (parm);
X return NOREPLOT;
X }
X else
X flag = page (helpfile, parm);
X fclose (helpfile);
X return flag ? REPLOT : NOREPLOT;
X}
X
X/* Display is the command processor's version of help */
Xdisplay (argv) char **argv;
X{
X register char *msg;
X char name [STRMAX];
X
X msg = 0;
X if (*argv == CNULL) {
X if (VSHMODE == SELECTMODE && selecttype == DIRCMD && *selectname)
X return help(selectname);
X msg = "Display: ";
X }
X if (getfname (*argv, name, msg) == BAD) return NOREPLOT;
X else return help (name);
X}
All work and no play makes Jack a dull boy
echo src/main.c
sed 's/^X//' > src/main.c << 'All work and no play makes Jack a dull boy'
X#include "hd.h"
X#include "mydir.h"
X#include <pwd.h>
X#include <signal.h>
X#ifdef PWBTTY
X#include <sys/sgtty.h>
X#endif
X
X#ifdef STOPABLE
X#define sigmask(sig) (1 << ((sig) - 1))
X#define sigunblock(mask) sigsetmask(sigblock(0) & ~(mask))
Xint suspend();
X#include <sgtty.h>
X#endif
X
X/* Extract data about environment */
X#define ENV_COUNT 6
X
Xchar *env_name [ENV_COUNT] = /* Names */
X{
X "SHELL", "HOME", "TERM", "PATH", "EDITOR", "MAIL"
X} ;
X
Xchar **env_dest [ENV_COUNT] = /* Place stored */
X{
X &SHELL, &HOME, &TERM, &PATH, &EDITOR, &MAIL
X} ;
X
X#define USERSIZE 20
Xchar username[USERSIZE] = { "(who are you ?)" };
Xchar *arrow;
X
Xchar *helptext = 0;
X/* HELPSIZE should be plenty */
X#define HELPSIZE 1536
X
X/* Screen parameters, see also setwindow() */
X#define CRTROW 24 /* Standard 24x80 CRT default */
Xint window = CRTROW;
Xint nfpp = (CRTROW-4); /* Two lines of header and footer
X * not greater than maxnfpp == 26
X */
X
Xmain (c, v)
Xchar **v;
X{
X
X/* Initialize everything, then run. */
X
X register int i, j;
X register char *s;
X struct passwd *p, *getpwuid();
X extern leave ();
X extern char *shargv[];
X extern char *getenv();
X
X int fflag;
X int (*oi)(), (*oq)();
X#ifdef PWBTTY
X int tm[3];
X#endif
X
X comein ();
X for (i = 0; i < ENV_COUNT; i++)
X if ((s = getenv(env_name[i])) != NULL)
X *env_dest [i] = s;
X
X *shargv = SHELL;
X#ifdef PWBTTY
X HOME = (char *) logdir();
X#endif
X /* Should we depend on $USER ? */
X p = getpwuid(i = geteuid());
X if (p) {
X strcpy(username, p->pw_name);
X if (*HOME == 0)
X HOME = p->pw_dir;
X }
X /* Give root a different arrow */
X arrow = i ? "->" : "#>";
X
X if (MAIL && *MAIL) {
X i = strlen(MAIL);
X if (MAIL[i-1] == '~') {
X s = (char *) malloc(i+1+USERSIZE);
X if (s != NULL) {
X strcpy(s, MAIL);
X strcpy(&s[i-1], username);
X MAIL = s;
X }
X }
X }
X
X if (signal(SIGHUP, leave) == SIG_IGN)
X signal(SIGHUP, SIG_IGN);
X if (signal(SIGTERM, leave) == SIG_IGN)
X signal(SIGTERM, SIG_IGN);
X oi = signal (SIGINT, SIG_IGN); /* dyt, was leave */
X oq = signal (SIGQUIT, SIG_IGN);
X tty_init ();
X i = curs_init ();
X /*
X * Check if terminal is a CRT
X * if not, check option to chain to /bin/sh
X */
X fflag = 0;
X j = 1;
X if (c > 1 && strcmp(v[j], "-f") == 0) {
X c--;
X j++;
X fflag++;
X }
X#ifdef PWBTTY
X if (i == 0)
X i = gtty(0, tm);
X if (!fflag && (i || (tm[2]&CRT) == 0)) {
X#else
X if (!fflag && i) {
X#endif
X fprintf(stderr, "Not a screen terminal");
X if ((c > 0 && **v == '-')
X || (c > 1 && strcmp(v[j], "-") == 0)) {
X fprintf(stderr, ", exec'ing %s...\r\n", SHELL);
X signal(SIGINT, oi);
X signal(SIGQUIT, oq);
X execl(SHELL, "sh", 0);
X fprintf(stderr, "exec failed");
X }
X fprintf(stderr, "\r\n");
X exit(0);
X }
X
X erase (); printf ("Vsh %s\r\n", VERSION);
X cmdldrc ();
X wdfile = -1;
X if (curdir () || enterdir (DOT) == NOREPLOT)
X leave ();
X#ifdef STOPABLE
X signal(SIGTSTP, suspend);
X#endif
X tty_push (RAWMODE);
X
X /* Read in helpfile once */
X helptext = "";
X if (HELPFILE && *(HELPFILE)) {
X if (stat(HELPFILE, &scr_stb) == 0) {
X#ifdef V6
X i = (scr_stb.st_size1 < HELPSIZE) ? scr_stb.st_size1 :
X#else
X i = (scr_stb.st_size < HELPSIZE) ? scr_stb.st_size :
X#endif
X HELPSIZE;
X if ((helptext = (char *) malloc(i+1)) == NULL) {
X fprintf(stderr, "No memory\n");
X exit(-1);
X }
X j = open(HELPFILE, 0);
X helptext[0] = 0;
X if (j > 0 && (i = read(j, helptext, i)) > 0)
X helptext[i] = 0;
X close(j);
X }
X }
X
X setwindow();
X setcolumn();
X process ();
X}
X
X#ifdef STOPABLE
Xsuspend(signo)
Xint signo;
X{
X int putch();
X
X tty_push(COOKEDMODE);
X /*
X * This is debatable: should we give back a full screen
X * or just the execute window ?
X */
X if (CS && ewindow) {
X tputs(tgoto(CS, LI-1, 0), 0, putch);
X atxy(1, LI);
X }
X#ifdef SIGVTALRM /* Kludge to detect 4.2BSD signal */
X /* stop ourselves */
X sigunblock(sigmask(signo));
X signal(signo, SIG_DFL);
X kill(getpid(), signo);
X sigblock(sigmask(signo));
X#else
X kill(getpid(), signo);
X#endif
X signal(signo, suspend);
X printf("Vsh restarted.\r");
X fflush(stdout);
X tty_pop();
X ioctl(0, TIOCSTI, "\014"); /* Fake an input of ^L */
X}
X#endif
All work and no play makes Jack a dull boy
echo src/make.c
sed 's/^X//' > src/make.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 make. Fmake forks make off and returns. Wmake waits
X for completion. Both cause output to be saved in the file .makerror.
X*/
X
Xfmake ()
X{
X int p; /* Process number */
X int mfile; /* File number of .makerror */
X FILE *mstream; /* Stream of .makerror */
X FILE *showopen (); /* Opener of mstream */
X char inline[STRMAX];
X
X if (getcomment(inline))
X return NOREPLOT;
X
X mstream = showopen ("w", MAKEMODE);
X if (mstream == NULL) return NOREPLOT;
X mfile = fileno (mstream);
X
X if (myfork () == 0)
X {
X if ((p = myfork ()) == 0)
X {
X close (outfile); close (errorfile);
X dup (mfile); dup (mfile);
X close (infile); open ("/dev/null", 0);
X hilite("%s", inline);
X printf("\r\n");
X if(SHELL && *SHELL)
X myexecl (SHELL, "+", "-c", inline, 0);
X else
X myexecl("/bin/sh", "+", "-c", inline, 0);
X }
X else
X {
X p = join (p);
X beep (); sleep (2); beep ();
X if (p) {
X sleep(1);
X beep();
X }
X exit (0);
X }
X }
X else
X {
X fclose (mstream);
X putmsg (MAKE);
X }
X return NOREPLOT;
X}
X
Xwmake ()
X{
X int p; /* Process number */
X FILE *mstream; /* Stream of .makerror */
X FILE *showopen (); /* Opener of mstream */
X register ch; /* Work character */
X char inline[STRMAX];
X
X int pipefile [2]; /* Pipe file numbers */
X# define pipein pipefile [0]
X# define pipeout pipefile [1]
X
X FILE *pipestrm; /* Stream of pipein */
X
X if (getcomment(inline))
X return NOREPLOT;
X
X mstream = showopen ("w", MAKEMODE);
X if (mstream == NULL) return NOREPLOT;
X
X tty_push(COOKEDMODE);
X pipe (pipefile);
X if ((p = myfork ()) == 0)
X {
X close (outfile); close (errorfile);
X dup (pipeout); dup (pipeout);
X hilite("%s", inline);
X printf("\r\n");
X if(SHELL && *SHELL)
X myexecl (SHELL, "+", "-c", inline, 0);
X else
X myexecl("/bin/sh", "+", "-c", inline, 0);
X }
X else
X {
X close (pipeout);
X pipestrm = fdopen (pipein, "r");
X while ((ch = getc (pipestrm)) != EOF)
X {
X putchar (ch); putc (ch, mstream);
X }
X fclose (pipestrm); fclose (mstream);
X join (p);
X }
X tty_pop ();
X return CMD_SE | REPLOT;
X}
X
Xgetcomment(inline) /* get user make parameters */
Xchar *inline;
X{
X register char *s, *t;
X
X /* get user comments for the make command */
X s = inline;
X t = MAKE;
X while (*s++ = *t++);
X --s;
X *s++ = ' ';
X tty_push(COOKEDMODE);
X clearmsg(2);
X putmsg("Make options (quit):");
X printf(" ");
X xgetline(stdin, s, STRMAX);
X tty_pop();
X if (!strcmp("q", s) || *s == (QUITCHAR-'@')
X || !strcmp("quit", s)) {
X hilite("(Aborted)");
X return 1;
X }
X return 0;
X}
All work and no play makes Jack a dull boy
echo src/makefile
sed 's/^X//' > src/makefile << 'All work and no play makes Jack a dull boy'
XCC=cc
XSHELL=/bin/sh
XCFLAGS= -O -DVSH -DSTOPABLE -DVT100ARROW
XLDFLAGS= -g
XLOCALLIB=strlib.a
XLIBS=
XBIN=/usr/local/bin
XDESTDIR=/usr/lib/vsh
XOBJECTS= main.o at.o dir.o xeq.o curdir.o process.o enterf.o \
X help.o page.o dirlist.o tty.o remove.o file.o show.o \
X ascii.o make.o grep.o showopen.o strings.o \
X curses.o account.o cmdrun.o misccmd.o dircmd.o cmdini.o \
X readarg.o cmdload.o classify.o options.o xecute.o find.o system.o
X
X.c.o:
X $(CC) $(CFLAGS) -c $<
X
Xvsh: $(OBJECTS) mydir.h hd.h $(LOCALLIB)
X cc -n -o nvsh $(LDFLAGS) $(OBJECTS) $(LOCALLIB) -ltermlib $(LIBS)
X -mv vsh ovsh
X mv nvsh vsh
X -rm -f ovsh
X size vsh
X
Xinstall: vsh
X mv $(BIN)/vsh /usr/tmp/vsh
X cp vsh $(BIN)/vsh
X chmod 755 $(BIN)/vsh
X -rm -f /usr/tmp/vsh
X echo 'Do make docs to install documentation'
X
Xdocs:
X -mkdir $(DESTDIR)
X cp vshrc.gen ../doc/vshelp ../doc/genhelp* ../doc/rmhelp ../doc/showhelp $(DESTDIR)
X echo 'Look over ../doc/vshrc* and ../doc/genhelp.dan to see a sample of'
X echo 'how to configure VSH for a nicer interface. See ../termcap for'
X echo 'additions to your /etc/termcap for a better display.'
X echo 'A manual page for VSH can be found in ../doc .'
X
Xstrlib.a:
X (cd ../strlib; $(CC) $(CFLAGS) -c str*.c)
X ar rv $(LOCALLIB) ../strlib/str*.o
X -ranlib $(LOCALLIB)
X
Xlint:
X lint -bxac *.c
X
Xoldinstall: vsh
X vshrc.gen
X cp vsh $(BIN)
X cp genhelp $(DESTDIR)
X cp rmhelp $(DESTDIR)
X cp showhelp $(DESTDIR)
X cp dflt.vshrc $(DESTDIR)
X
Xclean:
X rm -f $(OBJECTS) vsh
All work and no play makes Jack a dull boy
echo src/misccmd.c
sed 's/^X//' > src/misccmd.c << 'All work and no play makes Jack a dull boy'
X#include "hd.h"
X
Xdate ()
X{ /* display current date */
X
X long datetime [1];
X
X time (datetime); clearmsg (1);
X printf (" ");
X hilite ("%.24s", ctime (datetime));
X return NOREPLOT;
X}
X
Xcallshell (argv) char **argv;
X{
X if (argv[0])
X {
X mysystem (argv[0]);
X getrtn ();
X }
X else f_exec (SHELL, SHELL, 0);
X return REPLOT;
X}
All work and no play makes Jack a dull boy
echo src/mydir.h
sed 's/^X//' > src/mydir.h << 'All work and no play makes Jack a dull boy'
X/* Global Defines */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/dir.h>
X
X/* This data relates to the working directory and the portion of that
X directory currently displayed on the screen.
X*/
X
Xextern int tfiles; /* Number of files in this directory */
X
X/* The files of a directory are partitioned into pages. Each page
X represents a display on the terminal screen. */
X
X#define maxnfpp 26 /* Maximum number of files per page, a-z */
Xextern int nfpp; /* Number of files per page */
X
Xextern int tpages, /* Total pages this directory */
Xcpage; /* Current page this display */
Xextern int pageoff; /* Page offset for multicolumn display */
Xextern int column, colfield;
X
X/* File information about working dir */
X
Xextern struct stat wd_stb; /* its inode */
X
X/* Path name of working directory */
X#define MPLEN STRMAX - 1 /* Max path len (chars) */
X#define LPLEN STRMAX - 20 /* Limit path len */
X
Xextern int wdfile; /* its file number */
Xextern char wdname [STRMAX]; /* its full path name */
X
X/*#define max_dir_size (sizeof dirbuf - sizeof dirbuf [0]) */
X
X/* extern char *d_namep [mfiles]; /* pointers to all the file names */
X
X#ifndef NDIR
Xextern char **d_namep;
X#endif
X
X/* filename returns a pointer to the file assoc. with arg on cpage */
X#ifndef NDIR
X#define filename(arg) (d_namep [arg + (cpage+pageoff) * nfpp - nfpp])
X#else
Xextern struct direct **d_dirp;
X#define filename(arg) (d_dirp[arg + (cpage+pageoff) * nfpp - nfpp]->d_name)
X#endif
X
Xextern int dir_status; /* its logical status */
X#define loaded 0
X#define unloaded 1
X#define toobig 2
X#define protected 3
X
X/* scratch */
Xextern struct stat scr_stb;
X
X/* Useful macros */
X
X#define DOT "."
X#define DOTDOT ".."
X#define SLASH "/"
X#define dirsize sizeof (struct direct)
X
X#ifndef NDIR
X#define dnamesize DIRSIZ
X#endif
X
X#define ISROOT(arg) (arg [1] == 0)
All work and no play makes Jack a dull boy
echo src/options.c
sed 's/^X//' > src/options.c << 'All work and no play makes Jack a dull boy'
X#include "hd.h"
X#include "command.h"
X
X/* Print and modify command tables interactively */
X
Xoptions (parm) char **parm;
X{
X FILE *vshout;
X int line = 0; /* Current line number */
X register struct cmdstruct *cmdp;
X register struct classstruct *classp;
X register char **argv;
X struct parmstruct *parmp;
X
X /* Print command tab in .vshrc format */
X /* If parm present, dump to file and quit */
X erase ();
X if (*parm)
X {
X vshout = fopen(*parm, "w");
X if (vshout == NULL) {
X printf(" ");
X hilite("%s: Cannot create%s\r\n", *parm);
X return REPLOT;
X }
X line= -9999;
X }
X else {
X vshout = stdout;
X bufout();
X }
X for (;;)
X {
X for (cmdp = cmdtab; cmdp->cmd_char >= 0; cmdp++)
X {
X if (cmdp->cmd_proc)
X {
X for (classp = classtab;
X *classp->cl_name &&
X classp->cl_proc !=
X cmdp->cmd_proc;
X classp++);
X
X fprintf (vshout, "%c\t%s", cmdp->cmd_char,
X classp->cl_name);
X
X for (argv = cmdp->cmd_argv; *argv;)
X fprintf (vshout, " %s", *argv++);
X
X if (optline (&line, vshout) == BAD)
X return REPLOT;
X }
X }
X for (parmp = parmtab; parmp->p_name; parmp++)
X {
X fprintf (vshout, "%s\t%s", parmp->p_name, parmp->p_val);
X if (optline (&line, vshout) == BAD) return REPLOT;
X }
X
X if (*parm) {
X fclose(vshout);
X return REPLOT;
X }
X if (line != 0 && optcmd () == BAD) break;
X erase (); line = 0;
X }
X unbufout();
X return REPLOT;
X}
X/* Processing for end of each line includes:
X 1. Print the newline.
X 2. If the end of the page, prompt for a command.
X*/
Xoptline (line, fd)
Xint *line;
XFILE *fd;
X{
X int ret; /* return from optcmd */
X
X if (fd == stdout)
X putc (CR, fd);
X putc (LF, fd);
X if (++*line < (window-6)) return GOOD;
X
X ret = optcmd (); erase (); *line = 0;
X return ret;
X}
X
Xoptcmd ()
X{
X char cbuf [STRMAX], /* Buffer for input parm */
X *argv [ARGVMAX]; /* Pointers to input parm */
X int argc; /* Number of parm */
X int ret; /* Return from readarg */
X
X int line = 0; /* Current line num of rcstream */
X
X printf ("\r\n");
X hilite ("Type in a new parameter, or\r\n\
XPress ^D to leave. Press -Return- to display more parameters.\r\n\n");
X unbufout();
X tty_push (COOKEDMODE);
X for (;;)
X {
X ret = readarg (stdin, &line, &argc, argv, cbuf);
X if (argc == 0) break;
X if (compe ("quit", argv [0]))
X {
X ret = BAD; break;
X }
X if (ret != BAD) cmdldarg (line, argc, argv);
X /* Reset screen window */
X setwindow();
X /* Reset columns */
X setcolumn();
X }
X tty_pop ();
X erase();
X if (ret != BAD)
X bufout();
X return ret;
X}
All work and no play makes Jack a dull boy
echo src/page.c
sed 's/^X//' > src/page.c << 'All work and no play makes Jack a dull boy'
X#include "hd.h"
X#include "strings.h"
X#include "mydir.h"
X#include <signal.h>
X
X#define PROMPTLINE 1 /* Line count used by prompt */
X#define OVERLAP 2 /* Lines of page overlap */
X#define MMINSIZE 100 /* Tiny more buffer */
X#define topwin() ((ewindow && CS) ? window-PROMPTLINE : 1)
X
Xint nointer;
Xchar *mbegin, *mend, *mbufp;
Xunsigned mbsize;
Xlong maxline, topline, botline;
Xlong omaxline;
Xint curwin;
Xint noprint;
Xint isfile;
Xint putch();
Xchar *oldline();
X
Xpage (stream, name)
XFILE *stream;
Xchar *name;
X{
X#ifdef MBUFSTACK
X char mbuf[MBUFSIZE];
X#else
X char mbuf[MMINSIZE];
X#endif
X register int linelim;
X register ch;
X register int ttych;
X int replot, fwin;
X char *ll;
X char number[20];
X char **v;
X int serror;
X int (*oldsig)(); extern catch();
X
X fwin = replot = 1;
X oldsig = signal (SIGINT, catch); nointer = 1;
X if (name && *name == 0) {
X isfile = 0;
X name = 0;
X }
X else
X isfile = 1;
X
X#ifdef MBUFSTACK
X mbsize = MBUFSIZE;
X mbufp = mbuf;
X#else
X mbsize = atoi(MORESIZE);
X /* If not a pipe, stat the file */
X if (name && stat(name, &scr_stb) == 0
X && (scr_stb.st_mode&S_IFMT) == S_IFREG
X#ifdef V6
X && scr_stb.st_size0 == 0 && scr_stb.st_size1 < mbsize)
X mbsize = scr_stb.st_size1+1;
X#else
X && scr_stb.st_size < mbsize)
X mbsize = scr_stb.st_size+1;
X#endif
X mbsize += mbsize/CO; /* add extra for long lines */
X if (mbsize < MMINSIZE) {
X mbufp = mbuf;
X mbsize = sizeof mbuf;
X }
X else {
X mbufp = (char *)malloc(mbsize);
X if (mbufp == NULL) {
X fprintf(stderr, "No memory for pager\n\r");
X mbufp = mbuf;
X mbsize = sizeof mbuf;
X }
X }
X#endif
X
X bufout ();
X if (ewindow && CS) {
X curwin = LI-(window-VSHBOT)-PROMPTLINE;
X fwin = replot = !ewin();
X }
X else {
X curwin = LI-PROMPTLINE;
X noprint = ewindow;
X ewindow = 0;
X erase ();
X ewindow = noprint;
X }
X if (name)
X hilite("%s\r\n", name);
X
X noprint = 0;
X initmore();
X linelim = curwin-PROMPTLINE;
X do
X {
X ch = more(stream, linelim, &ll);
X if (topline < 0) /* Only if file is short */
X topline = 0;
X if (ch == EOF && linelim >= 0)
X hilite("Done:");
X else {
X ch = '\n';
X hilite("More?");
X }
X fflush (stdout);
X
X ttych = getch ();
X printf("\r \r");
X fflush(stdout);
X /* dyt flush input */
X tty_push(COOKEDMODE);
X tty_pop();
X switch(ttych) {
X case EOT:
X case EOF:
X linelim = curwin / 2;
X break;
X case 020: /* ^P, EMACS style */
X case 'j':
X case '\r':
X case '\n':
X linelim = 1;
X break;
X case 025: /* ^U, VI style */
X linelim = - curwin / 2;
X break;
X case 016: /* ^N, EMACS style */
X case 'k':
X case '-':
X linelim = -1;
X break;
X case '^':
X case 02: /* ^B, VI style */
X case 033: /* ESC, EMACS ESC-v */
X linelim = - (curwin-OVERLAP);
X break;
X case 'e':
X case 'v':
X linelim = 0;
X if (name == 0) {
X putch(07);
X break;
X }
X printf("\r%s %s", EDITOR, name);
X fflush(stdout);
X sprintf(number, "+%ld", (botline+topline)/2);
X replot = nedit(name, number);
X if (replot == NOREPLOT) {
X printf(" : Bad file");
X fflush(stdout);
X sleep(1);
X break;
X }
X case 'q':
X case 'n':
X ttych = 'n';
X break; /* No more */
X case 022: /* ^R, EMACS style */
X case 023: /* ^S, EMACS style */
X case '?':
X case '/':
X ch = '\n';
X linelim = search(stream, ttych, &serror);
X break;
X case 'G':
X case '>':
X linelim = prttail(stream);
X break;
X case '1':
X case '<':
X ch = '\n';
X linelim = prthead(stream);
X break;
X case '!':
X tty_push(COOKEDMODE);
X v = ≪
X ll = CNULL;
X callshell(v);
X replot = REPLOT;
X tty_pop();
X ewin();
X case 014: /* ^L */
X topline += curwin;
X botline += curwin;
X prtback(-curwin, &ll);
X linelim = 0;
X break;
X default:
X linelim = curwin-OVERLAP;
X break;
X }
X
X } while ((ch != EOF || linelim <= 0) && ttych != 'n' && nointer);
X
X unbufout ();
X signal (SIGINT, oldsig);
X if (!fwin)
X vwin();
X#ifndef MBUFSTACK
X if (mbufp != mbuf)
X free(mbufp);
X#endif
X omaxline = 0; /* Reset for oldline() */
X return replot;
X}
X
Xmore(stream, linelim, lastline)
XFILE *stream;
Xregister int linelim;
Xchar **lastline;
X{
X register char *s;
X register int newlines;
X register int col, maxcol;
X int ch;
X
X newlines = 0;
X *lastline = 0;
X ch = '\n';
X if (linelim == 0)
X return ch;
X /* Looking forwards from current botline */
X if (linelim > 0) {
X newlines = botline + linelim - maxline;
X if (newlines < 0)
X newlines = 0;
X /* Number of old lines to fetch forwards */
X linelim -= newlines;
X }
X /* Looking backwards from current topline */
X else {
X if (curwin >= maxline) {
X printf("\r \r\07");
X return EOF;
X }
X if (SR || noprint) {
X if (!noprint)
X atxy(1, topwin());
X while (linelim < 0) {
X if (topline <= 1) {
X putch(07);
X break;
X }
X if ((s = oldline((int)(maxline - topline + 2)))
X == 0)
X break;
X linelim++;
X *lastline = s;
X if (!noprint) {
X tputs(SR, 0, putch);
X putch ('\r');
X prtold(s);
X }
X --topline;
X --botline;
X }
X }
X /* No reverse scroll (sigh...) */
X else
X linelim = prtback(linelim, lastline);
X if (linelim < 0)
X ch = EOF;
X if (!noprint) {
X atxy(1, LI);
X clearline();
X }
X }
X
X while (linelim-- > 0) {
X if ((s = oldline((int)(maxline - botline))) == 0) {
X if (newlines <= 0)
X ch = EOF;
X break;
X }
X *lastline = s;
X if (!noprint) {
X prtold(s);
X printf("\r\n");
X }
X topline++;
X botline++;
X }
X
X col = 0;
X maxcol = CO - (AM && !XN ? 1 : 0);
X while (newlines-- > 0) {
X s = mend;
X while ((ch = getc (stream)) != EOF) {
X /* Put new character in circular buffer (yuck) */
X switch (ch) {
X case '\t':
X col += 8 - (col&7);
X break;
X case '\b':
X if (col > 0)
X col--;
X break;
X case '\r':
X col = 0;
X break;
X case 0177:
X break;
X default:
X if (ch >= ' ')
X col++;
X break;
X }
X /*
X * Fake long lines
X * a kludge, but I don't have time for better
X */
X if (col > maxcol) {
X ungetc(ch, stream);
X ch = '\n';
X }
X *mend++ = ch;
X if (mend >= mbufp+mbsize)
X mend = mbufp;
X if (mend == mbegin) {
X mbegin++;
X if (mbegin >= mbufp+mbsize)
X mbegin = mbufp;
X }
X if (ch == '\n')
X break;
X if (!nointer) {
X ch = EOF;
X break;
X }
X if (!noprint)
X putch (ch);
X }
X col = 0;
X if (ch == EOF)
X break;
X else {
X maxline++;
X botline++;
X topline++;
X *lastline = s;
X }
X if (!noprint) {
X putch ('\n');
X putch ('\r');
X fflush (stdout);
X }
X }
X return ch;
X}
X
X/*
X * Print tail of file
X */
Xprttail(stream)
XFILE *stream;
X{
X char *ll;
X
X /* Skip to end of file */
X noprint = 1;
X while (more(stream, curwin, &ll) != EOF);
X more(stream, -curwin, &ll);
X noprint = 0;
X return curwin;
X}
X
X/*
X * Print head of file (as much as saved)
X */
Xprthead(stream)
XFILE *stream;
X{
X char *ll;
X
X /* If not a pipe, rewind by seeking */
X if (isfile && fseek(stream, 0L, 0) == 0) {
X initmore();
X return curwin;
X }
X else {
X noprint = 1;
X while (more(stream, -curwin, &ll) != EOF);
X more(stream, curwin, &ll);
X noprint = 0;
X return -curwin;
X }
X}
X
X/*
X * Initmore
X */
Xinitmore()
X{
X mbegin = mend = mbufp;
X maxline = botline = 0;
X topline = 1 - curwin;
X}
X
X/*
X * Print -n lines before topline to botline+n
X */
Xprtback(n, lastline)
Xregister int n;
Xchar **lastline;
X{
X register int i, j;
X register int k;
X register char *s;
X int found;
X
X if (!noprint) {
X erasebelow(topwin());
X atxy(1, topwin());
X }
X /*
X * i is the number of lines to print
X * j is the offset (lines into the old buffer)
X * n is the line currently being tried (it may not exist)
X * k becomes the lines left undone (didn't exist)
X */
X i = curwin-PROMPTLINE;
X if (i > maxline-PROMPTLINE)
X i = maxline-PROMPTLINE;
X j = maxline - (n+topline) + 2;
X *lastline = 0;
X found = 0;
X k = 0;
X while (i > 0) {
X if (found)
X i--;
X n++;
X if ((s = oldline(--j)) == 0) {
X k--;
X continue;
X }
X /* First line actually existant */
X if (!found) {
X found++;
X topline += n-1;
X botline += n-1;
X *lastline = s;
X }
X if (n < 0)
X n++;
X if (!noprint) {
X prtold(s);
X putch('\n');
X putch('\r');
X }
X }
X return k;
X}
X
X/*
X * Print an old line
X */
Xprtold(t)
Xregister char *t;
X{
X while (*t != '\n') {
X putchar (*t);
X if (t == mend)
X break;
X if (++t >= mbufp+mbsize)
X t = mbufp;
X }
X}
X
X/*
X * Find the n'th old line
X */
Xchar *oldline(ln)
Xint ln;
X{
X register int n;
X register char *s, *t;
X int i, first;
X static int on;
X static char *os;
X
X n = ln;
X i = 0;
X /* Try to start from previous position (an optimization) */
X if (maxline == omaxline) {
X i = n - on;
X if (i == 0)
X return os;
X if (i == -1 && on > 1) {
X s = t = os;
X for (;;) {
X t++;
X if (t >= mbufp+mbsize)
X t = mbufp;
X if (t == mend)
X break;
X if (*s == '\n')
X goto ret;
X s = t;
X }
X }
X }
X if (i > 0 && os != mbegin) {
X n = i;
X s = os;
X }
X else
X s = mend;
X n++; /* Newline count is one more */
X first = 1;
X while (n-- > 0) {
X for (;;) {
X t = s;
X if (s <= mbufp)
X s = mbufp+mbsize;
X s--;
X if (s == mbegin) {
X /* Just an approximation */
X if (mbegin != mbufp)
X putch(07);
X if (n > 0)
X return 0;
X t = s;
X break;
X }
X if (*s == '\n') {
X first = 0;
X break;
X }
X /*
X * If first char is not a newline,
X * last line in file is without newline
X * adjust n
X */
X if (first) {
X n--;
X first = 0;
X }
X }
X }
X /* Save for future reference */
Xret:
X omaxline = maxline;
X on = ln;
X os = t;
X return t;
X}
X
X/*
X * search string
X */
X#define SFOR -1
X#define SREV -2
X
Xsearch(stream, way, failp)
XFILE *stream;
Xint way;
Xint *failp;
X{
X register int i;
X register int savec;
X register char *s;
X char *ll;
X int serror;
X static char sbuf[STRMAX];
X
X *failp = 0;
X /* Get string to search for */
X if (way == 022)
X way = '?'; /* ^R */
X else if (way == 023)
X way = '/'; /* ^S */
X if (way > 0) {
X tty_push(COOKEDMODE);
X putch(way);
X fflush(stdout);
X savec = sbuf[0];
X i = getline(sbuf);
X /* Adjust for linefeed user just hit */
X tty_pop();
X if (UP)
X tputs(UP, 0, putch);
X clearline();
X fflush(stdout);
X if (i == 0) {
X if (savec == 0) {
X if (botline >= curwin) {
X topline++;
X botline++;
X }
X putch(07);
X *failp = 1;
X return -1;
X }
X sbuf[0] = savec;
X }
X }
X i = 0;
X noprint = 1;
X /* Reverse search, does not wraparound */
X if (way == '?' || way == SREV) {
X while (more(stream, -1, &ll) != EOF) {
X if (ll == 0)
X break;
X i++;
X if (match(sbuf, ll)) {
X noprint = 0;
X prtback(-(curwin/2), &ll);
X return 0;
X }
X }
X /* Not found, try to restore screen */
X if (way == '?')
X while (i-- >= 0)
X more(stream, 1, &ll);
X }
X /* Forward search, which wraps around */
X else {
X while (more(stream, 1, &ll) != EOF) {
X if (ll == 0)
X break;
X i++;
X if (match(sbuf, ll)) {
X more(stream, curwin/2, &ll);
X noprint = 0;
X prtback(0, &ll);
X return 0;
X }
X }
X /* Not found below, try wraparound (slow) */
X if (way > 0) {
X /* Rewind to beginning (yuck) */
X if (isfile && fseek(stream, 0L, 0) == 0) {
X initmore();
X more(stream, curwin, &ll);
X }
X while (more(stream, -curwin, &ll) != EOF);
X topline -= curwin;
X botline -= curwin;
X savec = search(stream, SFOR, &serror);
X if (!serror)
X return savec;
X /* Not found, try to restore screen, seek to end */
X noprint = 1;
X while (more(stream, curwin, &ll) != EOF);
X if (i >= maxline-(curwin+curwin/2)) {
X noprint = 0;
X *failp = 1;
X return prthead(stream);
X }
X else {
X while (--i > 0)
X if (more(stream, -1, &ll) == EOF)
X break;
X if (i && SR) {
X noprint = 0;
X topline += curwin;
X botline += curwin;
X prtback(-curwin, &ll);
X }
X }
X }
X }
X noprint = 0;
X if (way > 0) {
X putch(07);
X /* Adjust for pattern entry */
X if (botline == maxline) {
X topline++;
X botline++;
X }
X }
X *failp = 1;
X return -1;
X}
X
X/*
X * Find a match in the oldlines
X * Limited RE's: ^ . $
X */
Xmatch(a, b)
Xchar *a;
Xregister char *b;
X{
X register char *s, *t;
X int carat;
X
X /* Carat matches beginning of line */
X if (*a == '^') {
X a++;
X if (*a == 0)
X return 1;
X carat = 1;
X }
X else
X carat = 0;
X for (;;) {
X s = a;
X t = b;
X for (;;) {
X if (*t == '\n') {
X /* Dollar matches endline of line */
X if (*s == '$')
X return 1;
X break;
X }
X /* Dot matches any character */
X if (*s == '.') {
X s++;
X t++;
X }
X else if (*s++ != *t++)
X break;
X if (*s == 0)
X return 1;
X if (t >= mbufp+mbsize)
X t = mbufp;
X }
X if (carat)
X break;
X if (*b == '\n')
X break;
X b++;
X if (b >= mbufp+mbsize)
X b = mbufp;
X }
X return 0;
X}
X
Xcatch ()
X{ /* Catch an interrupt */
X nointer = 0;
X signal (SIGINT, catch);
X}
All work and no play makes Jack a dull boy
echo src/process.c
sed 's/^X//' > src/process.c << 'All work and no play makes Jack a dull boy'
X#
X/* This is the main loop of vsh. Each interation processes a command.
X Commands are one character long. They are acquired in raw mode
X and processed without the need to press return. The goal of vsh
X is to minimize keypresses as much as possible.
X*/
X
X#include "hd.h"
X#include "mydir.h"
X
Xprocess ()
X{
X register cmd, next; /* single character command */
X
X next = REPLOT;
X for (;;)
X { /* loop forever */
X if (next & REPLOT)
X dispdir (1);
X atxy (1, window-1);
X printf (" %s", BC);
X if (next & REPLOT)
X chkmail();
X cmd = getch ();
X#ifdef PWBTTY
X /* dyt flush input */
X tty_push(COOKEDMODE);
X tty_pop();
X#endif
X printf ("%s", BC);
X
X next = command (cmd, DIRCMD);
X }
X}
X
Xchkmail()
X{
X static time_t mailtime = 0;
X long clock;
X
X if (*MAIL == 0)
X return;
X time(&clock);
X
X if (clock - mailtime < MAILCLK)
X return;
X
X if (stat(MAIL, &scr_stb) == 0
X#ifdef V6
X && scr_stb.st_size1
X#else
X && scr_stb.st_size
X#endif
X && scr_stb.st_atime <= scr_stb.st_mtime
X && (scr_stb.st_atime > mailtime || scr_stb.st_mtime > mailtime)
X && mailtime)
X putmsg("You have new mail");
X
X mailtime = clock;
X}
All work and no play makes Jack a dull boy
exit
More information about the Comp.sources.unix
mailing list