DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

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

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T c

⟦c773c2a3b⟧ TextFile

    Length: 17445 (0x4425)
    Types: TextFile
    Names: »cmds.c«

Derivation

└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit
    └─⟦e7f64e0c0⟧ »EurOpenD3/mail/vmh.tar.Z« 
        └─⟦dcb95597f⟧ 
            └─⟦this⟧ »cmds.c« 

TextFile

#ifndef lint
static char rcsid[] =
	"$Header: cmds.c,v 2.12 88/01/13 18:51:35 deboor Locked $";

static char notice[] =
	"This program is in the public domain and is available for unlimited \
distribution as long as this notice is enclosed.";
#endif

/*
 * The main command processor.
 *
 * $Source: /c/support/deboor/usr/src/old/vmh/RCS/cmds.c,v $
 * $Revision: 2.12 $
 * $Author: deboor $
 * 
 * FUNCTIONS:
 *	Quick		execute "quick" commands using prompter
 *	docmds		main command loop
 *	doit		command processor
 *	initcmds	initialize command table from termcap
 *	longcomm	execute commands with arguments
 *	sim_cmd		simulate the typing of the passed string as a command
 */

#include "vmh.h"

/*
 * constants for doit() for doing it in immediate or non-immediate mode
 */
#define C_IMED		1	/* immediate mode */
#define C_DEF		0	/* deferred mode */


jmp_buf	CommandLevel;	/* quick return to command-input level */
int	bvShowScan;
int	resize_windows = FALSE;	/* windows need resizing */

static	char	cmdline[20];	/* Buffer for current command string */
static	char	*cmd;		/* Ptr into cmdline */

extern struct tchars	chars;	/* For interruptible commands */

typedef struct cmdsR {                 	/* Command table structure (record) */
	char	*cr_str;	/* String of the command */
	char	*cr_name;	/* expansion of command */
	int	cr_type;	/* the type of command */
	int	(*cr_proc)();/* Routine to invoke */
} CMDR;


/*
 * COMMAND FUNCTION DECLARATIONS
 */
int	cmdUp(), cmdDown(), cmdPgplus(), cmdPgminus(), cmdType(), cmdSwitch(),
	cmdPush(), cmdPop(), cmdList_stack(), cmdMove(), cmdLink(), cmdDelete(),
	cmdHelp(), cmdHELP(), cmdReply(), cmdreply(), cmdForward(),
	cmdforward(), cmdCompose(), cmdcompose(), cmdInc(), cmdMore(),
	cmdEdit(), cmdPack(), cmdRedraw(), cmdExpunge(), cmdHome(), cmdTop(),
	cmdBot(), cmdLs(), cmdUnseen(), cmdUndo(), cmdCshcmd(), cmdcshcmd(),
	cmdClrbot(), cmdGripe(), cmdGo(), cmdgo(), cmdQuickreply(),
	cmdQuickcomp(), cmdQuickforward(), cmdPick(), cmdMark(), longcomm(),
	Quick(), cmdOffice(), cmdSet(), cmdExposetop(), cmdExposebot(),
	cmdDist(), cmdVersion(), cmdNext(), cmdHalfup(), cmdHalfdown(),
	cmdDebug(), cmdShowM(), cmdClear(), cmdToMark(), cmdSetMark(),
	cmdFindF(), cmdFindB(), cmdNext_pat(), cmdPrev_pat(), cmdInit(),
	cmdSave();


/*
 * COMMAND TABLE CONSTANTS
 */
#define CT_CURS	  0x01	/* a cursor moving command */
#define CT_FULL	  0x02	/* a full-screen command */
#define CT_HALF	  0x04	/* a half-screen command */
#define CT_MISC	  0x08	/* an other command */
#define CT_UNDO	  0x10	/* can be undone */
#define CT_MARK	  0x20	/* mark old cur when command done */
#define CT_CHECK  0x40	/* check folders upon return */
#define CT_INTR	  0x80	/* command may be interrupted */

				/* Offsets into main command table */
#define Ku      0               /* Up key */
#define Kd      1               /* Down key */
#define Kl      2               /* Left key */
#define Kr      3               /* Right key */
#define Kh      4               /* Home key */


/*
 * THE COMMAND TABLES. YEA!!!!!
 */
struct cmdsR quickTbl[] = {
"c",	"compose",	CT_FULL|CT_CHECK,	cmdQuickcomp,
"r",	"reply",	CT_FULL|CT_CHECK,	cmdQuickreply,
"f",	"forward",	CT_FULL|CT_CHECK,	cmdQuickforward,
"q",	"quit",		CT_MISC,	    	goodbye,
 0, 	0,	  	0,		    	(int (*)())0,
};

struct cmdsR mainTbl[] =  {
			     /* Termcap (keypad) arrows */
"",	"up",		CT_CURS,	    	cmdUp,          /* KU */
"",	"down",	  	CT_CURS,	    	cmdDown,        /* KD */
"",	"page back",	CT_CURS,	    	cmdPgminus,     /* KL */
"",	"page forward",	CT_CURS,	    	cmdPgplus,      /* KR */
"",	"home",	  	CT_CURS,	    	cmdHome,        /* KH */

			     /* Vi (rogue) arrows */
"j",	"down",		CT_CURS,	    	cmdDown,
"k",	"up",		CT_CURS,	    	cmdUp,
"\012",	"page forward",	CT_CURS,	    	cmdPgplus,
"\013", "page back",	CT_CURS,	    	cmdPgminus,
"\006",	"page forward",	CT_CURS,	    	cmdPgplus,
"\002",	"page back",	CT_CURS,	    	cmdPgminus,
"\005",	"expose bot",	CT_CURS,	    	cmdExposebot,
"\031",	"expose top",	CT_CURS,	    	cmdExposetop,
"\004",	"half up",	CT_CURS,	    	cmdHalfup,
"\025",	"half down",	CT_CURS,	    	cmdHalfdown,

			     /* Emacs arrows */
"\020",	"up",		CT_CURS,	    	cmdUp,
"\016", "down",		CT_CURS,	    	cmdDown,
"\026",	"page forward",	CT_CURS,	    	cmdPgplus,
"\033v","page back",	CT_CURS,	    	cmdPgminus,
"\033V","page back",	CT_CURS,	    	cmdPgminus,
"\033<","top of file",	CT_CURS|CT_MARK,    	cmdTop,
"\033>","end of file",	CT_CURS|CT_MARK,    	cmdBot,
"\033,","home",		CT_CURS|CT_MARK,    	cmdHome,
"\033.","office",	CT_CURS|CT_MARK,    	cmdOffice,

"G",	"Go",		CT_MISC|CT_MARK,    	cmdGo,
"g",	"go",		CT_MISC|CT_MARK,    	cmdgo,
"'",	"",		CT_MISC|CT_MARK,    	cmdToMark,
"M",	"",		CT_MISC,	    	cmdSetMark,

			      /* folder-oriented commands */
"s",	"switch",	CT_MISC,	    	cmdSwitch,
"p",	"push",		CT_MISC,	    	cmdPush,
"P",	"pop",		CT_MISC,	    	cmdPop,
"L",	"list folders",	CT_HALF,	    	cmdLs,
"S",	"stack",	CT_HALF,	    	cmdList_stack,
"\011",	"build",	CT_MISC,	    	cmdInit,
"K",	"pack",		CT_MISC,	    	cmdPack,
"x",	"expunge",	CT_MISC,	    	cmdExpunge,

 	    	  	    /* message-oriented commands */
"\r",	"next",		CT_CURS,	    	cmdNext,
".",	"type",		CT_HALF|CT_UNDO,    	cmdType,
"t",	"type",		CT_HALF|CT_UNDO,    	cmdType,
"T",	"show",		CT_FULL|CT_UNDO,    	cmdMore,

"m",	"move",		CT_MISC|CT_UNDO,    	cmdMove,
"l",	"link",		CT_MISC|CT_UNDO,    	cmdLink,
"d",	"delete",	CT_MISC|CT_UNDO,    	cmdDelete,
"D",	"dist",		CT_FULL|CT_CHECK,    	cmdDist,
"e",	"edit",		CT_FULL|CT_CHECK,	cmdEdit,
"v",	"edit",		CT_FULL|CT_CHECK,	cmdEdit,
"r",	"reply",	CT_FULL|CT_CHECK,	cmdReply,
"R",	"Reply",	CT_FULL|CT_CHECK,	cmdreply,
"c",	"compose",	CT_FULL|CT_CHECK,	cmdCompose,
"C",	"Compose",	CT_FULL|CT_CHECK,	cmdcompose,
"i",	"inc",		CT_MISC|CT_MARK,    	cmdInc,
"f",	"forward",	CT_FULL|CT_CHECK,	cmdForward,
"F",	"Forward",	CT_FULL|CT_CHECK,	cmdforward,
"U",	"unsee",	CT_MISC,	    	cmdUnseen,
"\030\023", "save",	CT_MISC,		cmdSave,

 	    	  	    /* Random commands */
"h",	"help",		CT_HALF,	    	cmdHelp,
"H",	"Help",		CT_FULL,	    	cmdHELP,
"u",	"undo",		CT_MISC,	    	cmdUndo,
"Q",	"quit",		CT_MISC,	    	goodbye,
"ZZ",	"quit",		CT_MISC,	    	goodbye,
"y",	"yell",		CT_FULL,	    	cmdGripe,
"$",	"set",		CT_MISC,	    	cmdSet,
"V",	"version",	CT_MISC,	    	cmdVersion,

"b",	"clear",	CT_FULL,	    	cmdClear,
"B",	"clear bottom",	CT_MISC,	    	cmdClrbot,
"\014",	"",		CT_MISC,	    	cmdRedraw,
"\022",	"",		CT_MISC,	    	cmdRedraw,

 	    	  	    /* Searching... */
"\030p","pick",		CT_MISC|CT_INTR,    	cmdPick,
"/",	"search",	CT_MISC|CT_INTR,   	cmdFindF,
"?",	"search",	CT_MISC|CT_INTR,    	cmdFindB,
"n",	"next",		CT_MISC|CT_INTR,    	cmdNext_pat,
"N",	"prev",		CT_MISC|CT_INTR,    	cmdPrev_pat,

 	    	  	    /* Debugging */
"\030M","mark",		CT_MISC,	    	cmdMark,
"\030m","show msgs",	CT_MISC,	    	cmdShowM,
"\030d","debug",	CT_MISC,	    	cmdDebug,

 	    	  	    /* Shell escapes... */
"!",	"shell",	CT_HALF|CT_CHECK,	cmdCshcmd,
",",	"shell",	CT_HALF|CT_CHECK,	cmdCshcmd,
"#",	"Shell",	CT_FULL|CT_CHECK,	cmdcshcmd,

 	    	  	    /* Prefix commands */
":",	"",		CT_MISC,	    	longcomm,
"q",	"quick",	CT_FULL,	    	Quick,

 	    	  	/* end-of-table */
0,	0,		0,	    	    	(int (*)()) 0,

};

int debug = 0;          /* Debug toggle */

static	char	tbuf[2048];
static	char	linetoys[2048];	/* room for add/delete line things and cursor
				 * control keys */

char	*KS,
	*KE;

initcmds()
{
	char	*cp;

	/*
	 * sigh. need to do this 'cause terminals like vt220's have
	 * save/restore cursor entries and a change scrolling region
	 * entry. for some reason, curses decides that it should,
	 * therefore, nuke any add-line and delete-line entries.
	 * can't figure it, myself, but there it is
	 */
#ifdef BSD4_3
	mainTbl[Ku].cr_str = KU;  	/* read & copy the specific */
	mainTbl[Kd].cr_str = KD;  	/* strings that are of any */
	mainTbl[Kl].cr_str = KL;  	/* interest to me */
	mainTbl[Kr].cr_str = KR;  	/* up/down/left/right keys */
	mainTbl[Kh].cr_str = KH;  	/* home key */

#ifdef GETCAP_OK
	alstring = getcap ("al");	/* Insert line command */
	dlstring = getcap ("dl");	/* Delete line command */
	clstring = getcap ("cl");	/* Clear screen command */
#else /* !GETCAP_OK */
	/*
	 * getcap() messes things up, but the terminal buffer is still
	 * declared static, so we don't need to fetch it all over again...
	 */
	cp = linetoys;
	alstring = tgetstr("al", &cp);
	dlstring = tgetstr("dl", &cp);
	clstring = tgetstr("cl", &cp);
#endif GETCAP_OK

#else /* !BSD4_3 */
	tgetent (tbuf, ttytype);	
	cp = linetoys;

	alstring = tgetstr("al", &cp);		     /* Insert line command */
	dlstring = tgetstr("dl", &cp); 		     /* Delete line command */
	clstring = tgetstr("cl", &cp);  	     /* Clear screen command */
	mainTbl[Ku].cr_str = tgetstr ("ku", &cp);    /* read & copy the spe- */
	mainTbl[Kd].cr_str = tgetstr ("kd", &cp);    /* cific strings that */
	mainTbl[Kl].cr_str = tgetstr ("kl", &cp);    /* are of any interest */
	mainTbl[Kr].cr_str = tgetstr ("kr", &cp);    /* to me: up, down, left */
	mainTbl[Kh].cr_str = tgetstr ("kh", &cp);    /* right and home keys */
	KS = tgetstr ("ks", &cp);
	KE = tgetstr ("ke", &cp);
#endif BSD4_3
}


/*
 * The command structures for undoing last command
 */
CMD		lastcomm,		/* the last command */
		thiscomm;		/* the current command */

/*
 * simulates the command 'command' having been typed at the keyboard
 */
sim_cmd(command)
	char *command;
{
	(void) strcpy (cmdline, command);	/*put the command in the array*/
	cmd = cmdline + strlen (cmdline);	/* set cmd to final chr$ */
	(void) ungetc (*--cmd, stdin);		/* put the last chr$ back in */
						/* the stream */
	thiscomm.c_count = 1;			/* initialize count */
	thiscomm.c_argc = 0;
	doit (mainTbl, topWin, C_IMED);		/* 'read' the command */
}

/*
 * sigwinch()
 *	note that the windows need to be rebuilt when a SIGWINCH is received
 */
sigwinch()
{
	resize_windows = TRUE;
}

/*
 * docmds()
 *	the main command loop. calls doit after initializing things.
 */
docmds()                                /* Main loop */
{
	int	oldcur;

	lastcomm.c_seq = (int *) 0;	/* make sure don't free anything */
	lastcomm.c_flags = 0;	/* make sure can't undo */

	if (newmailflag && autoinc) {	/* incorporate new mail if auto-inc */
		setMark ('\'', CurrentMsgNum());
		cmdInc (1, 0, 0, (char **) 0); /* and any there */
	}

	for ( ; ; ) {
			/* INITIALIZATION */
		cmd = &cmdline[0];      /* init string */
		*cmd = 0;
		thiscomm.c_count = 1;	/* default initial count to 1 */
		thiscomm.c_argc = 0;	/* and no extra arguments */
		CurSequence = (int *) 0;
		UseSequence = 0;

		if (fempty(stdin)) {      /* If no more type-ahead then */
			if (!resize_windows) {
				putupmcount();
				updatetop();    /* update the top screen */
			} else {
				wclear(curscr);
				rebuild_windows();
				resize_windows = FALSE;
			}

		}

		oldcur = CurrentMsgNum();

		if (! setjmp (CommandLevel))
		/* do a command in top window in immediate mode */
			if (doit(mainTbl, topWin, C_IMED)) {

				/*
				 * if command was undo-able, keep track of it
				 */
				if (thiscomm.c_flags & CT_UNDO) {
					/* free any argument sequence left */
					if (lastcomm.c_seq) {
						Free ((char *)lastcomm.c_seq);
					}
					lastcomm = thiscomm;
				}

				/*
				 * mark previous place if command calls for it
				 */
				if (thiscomm.c_flags & CT_MARK)
					setMark ('\'', oldcur);
			}

		if (debug) {              /* If debug toggle */
			int fdNext = open("/", 0);
			if (fdNext >= 0)
				(void) close(fdNext);

			wmove(botHdr, 0, 0);
			wprintw(botHdr,
			     "-- top:%d  bot:%d cur:%d last:%d fd: %d ------",
			     F->f_top->i_mnum, F->f_bot->i_mnum,
			     F->f_cur->i_mnum, F->f_tail->i_mnum, fdNext);
			wrefresh(botHdr);
		}
		if (thiscomm.c_flags & CT_CHECK) {
		    /*
		     * If the command might have done something to the
		     * folders, make sure they're all up-to-date
		     */
		    checkfcc();
		}
	}
}

/*
 * for handling backgrounding correctly. sheesh!
 */
int	do_refresh();
int	wait_for_tty();

#ifdef BSD4_3
struct	sigvec cont = { do_refresh, 0, SV_INTERRUPT };
#else
struct	sigvec cont = { do_refresh, 0, 0 };
#endif

struct	sigvec ttin = { wait_for_tty, 0, 0 };

static
wait_for_tty ()
{
	/*
	 * if we have no tty, don't try to read anything.
	 * just print something so the user knows we're ready and have
	 * do_refresh called when s/he fore/backgrounds us. If we
	 * still don't have a tty after all that, loop again.
	 */
	while (no_tty) {		/* print something to stop us */
		(void) sigvec (SIGCONT, &cont, (struct sigvec *) 0);
		(void) write (_tty_ch, "!", 1);
		signal (SIGCONT, SIG_DFL);
	}
}

/*
 * interrupt()
 *	catch a keyboard interrupt and return to main command level.
 */
interrupt()
{
    signal(SIGINT, SIG_IGN);
    chars.t_intrc = -1;
    Ioctl(_tty_ch, TIOCSETC, &chars);
    infomsg("*** command aborted", TRUE);
    updatetop();
    longjmp(CommandLevel, 1);
}

/*
 * doit()
 *	the workhorse of the command input world
 */

doit(cmdtbl, win, imed)
    CMDR	cmdtbl[];
    WINDOW	*win;
    int	imed;
{
    register int	i;		/* for command table traversal */
    int		partial;	/* number of partial command matches */
    char		getnum();	/* routine to read a number (count) */
    int		cur = CurrentMsgNum();
    
    /* go into loop if get TTIN on read */
    (void) sigvec (SIGTTIN, &ttin, (struct sigvec *) 0);
    
    for ( ; ; ) {     /* Loop till get a valid/invalid command */
	*cmd++ = mygetch(win) & 0177;      /* Get me a keypush */
	if (mvwinch(cmdWin,0,1) != ' ') {
	    wclear (cmdWin);
	    wrefresh(cmdWin);
	}
	*cmd = '\0';
	
	/* digit or +/- indicates count coming */
	if (isdigit (cmd[-1]) || cmd[-1] == '-' || cmd[-1] == '+')
	    cmd[-1] = getnum(win, cmd[-1]);
	
	partial = 0;            /* Number of partial matches */
	for (i = 0; cmdtbl[i].cr_proc; i++)
	{
	    switch(mystrcmp(&cmdline[0], cmdtbl[i].cr_str))
	    {
		case -1:                  /* Partial match */
		    partial++;
		    break;
		case 0:                   /* Exact match */
#ifdef DEBUG
		    DeBuG("command: %s\n", cmdtbl[i].cr_name);
#endif DEBUG
		    thiscomm.c_fun = cmdtbl[i].cr_proc;
		    thiscomm.c_flags = cmdtbl[i].cr_type;
		    
		    if (!(cmdtbl[i].cr_type & CT_CURS))
			if (!terse && imed)
			    infomsg (cmdtbl[i].cr_name, 1);
			else if (! terse && !imed)
			    waddstr (win, cmdtbl[i].cr_name);
			else if (terse && !imed)
			    wprintw (win, "%s ", cmdline);
		    if (! imed ) {
			if (read_args())
			    return 1;
		    }
		    
		    if (thiscomm.c_flags & CT_INTR) {
			signal(SIGINT, interrupt);
			chars.t_intrc = quit;
			Ioctl(_tty_ch, TIOCSETC, &chars);
		    }
		    (*thiscomm.c_fun)(thiscomm.c_count, FALSE, /* FALSE => not undoing */
				      thiscomm.c_argc, thiscomm.c_argv);
		    
		    if (thiscomm.c_flags & CT_INTR) {
			signal(SIGINT, SIG_IGN);
			chars.t_intrc = -1;
			Ioctl(_tty_ch, TIOCSETC, &chars);
		    }

		    thiscomm.c_seq = CurSequence;
		    
		    return 1;
	    }
	}
	
	if (partial == 0) {
	    (void) putchar('\007');
	    (void) fflush(stdout);
	    return 0;
	}
    }
}

/*
 * char
 * getnum (firstchar) char firstchar;
 *	reads a number from cmdWin (until a non-numeric character is given).
 *	the number is placed in thiscomm.c_count and the non-numeric character
 *	is returned.
 */
static char
getnum (win, firstchar)
	Reg2	WINDOW *win;
	Reg3	char firstchar;
{
	Reg1	int	curnum = 0;
	Reg4	int	isneg = 0;

	if (firstchar == '-') {
		isneg = 1;
		firstchar = '0';
	} else if (firstchar == '+') {
		firstchar = '0';
	}
	do {
		curnum = curnum * 10 + firstchar - '0';
		firstchar = mygetch(win);
	} while (isdigit (firstchar));

	if (isneg)
		curnum = -curnum;
	thiscomm.c_count = curnum;
	return (firstchar);
}

/*
 * Compare strings:
 *
 *      s1 == s2, but s1 shorter than s2 --> return -1
 *      s1 == s2, equal lengths  --> return 0
 *      s1 != s2, (no len info) --> return 1
 *
 *      s1 or s2 == 0, return 1
 */

mystrcmp(s1, s2)
	register char	*s1,
			*s2;
{
	if (!s1 || !s2) return(1);      /* Check for NULL */

	while (*s1 == *s2++)    /* While they match . . . */
	    if (*s1++ == '\0') return(0);   /* If both done, return 0 */

	if (*s1 == '\0') return(-1);    /* s1 ended before s2 */
	return(1);                      /* mismatch (or s2 ended first) */
}
	

			/* COMMAND TABLE EXTENSIOONS */
/*
 * longcomm()
 *	called from doit(). calls it back to do commands with arguments.
 */
longcomm ()
{
	wclear(cmdWin);
	wrefresh(cmdWin);
	wmove (cmdWin, 0, 0);
	if (! terse)
		waddstr (cmdWin, "args: ");
	else
		waddstr (cmdWin, ": ");
	if (!terse) {
		infomsg (" Type command ", 1);
	}
	cmd = &cmdline[0];	/* re-initialize command input line */
	*cmd = '\0';
	return (doit (mainTbl, cmdWin, C_DEF));	/* go back not in immediate mode */
}

/*
 * Quick()
 *	called from doit(). calls doit() again to perform the various `quick'
 *	commands. (i.e. one's using 'prompter' rather than vi)
 */
Quick()
{
	cmd = &cmdline[0];	/* re-initialize command line */
	*cmd = '\0';
	return(doit (quickTbl, topWin, TRUE));
}
/*
 * THIS ONE WILL BE A BITCH TO DO
 *	HA! --ardeb 12/3/85
 */
cmdUndo()
{
	thiscomm = lastcomm;	/* not *really* nec'y, but maybe later */
	if (thiscomm.c_flags & CT_UNDO) {
		CurSequence = thiscomm.c_seq;
		UseSequence = TRUE;
		(*thiscomm.c_fun)(thiscomm.c_count, TRUE,
			thiscomm.c_argc, thiscomm.c_argv);
	} else {
		errormsg (" Last command can't be undone ", 1);
	}
	lastcomm.c_seq = NULL;	/* so no double-free's */
}