|
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 */ }