|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T c
Length: 17445 (0x4425)
Types: TextFile
Names: »cmds.c«
└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit
└─⟦e7f64e0c0⟧ »EurOpenD3/mail/vmh.tar.Z«
└─⟦dcb95597f⟧
└─⟦this⟧ »cmds.c«
#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 */
}