/* TECO for DOS Copyright (C) 1986-1991 Matt Fichtenbaum */ /* Based on Ultrix TECO (C) 1986-1990 GenRad Inc., Concord, MA 01742 */ /* These programs may be copied if this copyright notice is included and */ /* only on a "not for sale or profit" basis */ /* te_rdcmd.c read in the command string 12/01/90 10.06 */ /* 8-bit version 04/18/91 09.39 */ /* better dly_free_blist 01/12/92 16.08 */ #include "te_defs.h" #include "keyscans.h" #define IMMED_ENABLE 0x10 #define IMMED_INSERT 0x20 #define IMMED_BEGIN 0x40 #define IMMED_CHAIN 0x80 static short find_lasteol(void); static void retype_cmdstr(char); static short do_func_keys(unsigned short c); static short getextqspec(unsigned short c); static long ccount; /* count of chars read in */ struct qh saved_command; /* save current command string during immed. execution */ struct qp saved_cmd_ptr; /* and pointer */ short read_cmdstr() { unsigned short c; /* temporary character */ short do_func_val = 0; /* returned value from do_func_keys */ short i; /* temporary */ if (saved_command.f != 0) /* if immediate command execution made an error */ { free_blist(saved_command.f); /* return the old partial string */ saved_command.f = 0; } display_mouse(MOUSE_RDCMD); goto prompt; restart: /* prompt again: new line */ if (!eisw && !inp_noterm) crlf(); /* if input not from a file */ prompt: /* issue prompt */ if (!eisw && !inp_noterm) type_char('*'); ccount = 0; lastc = ' '; reline: /* continue reading */ for (;;) /* loop to read command string chars */ { if (!eisw && !inp_noterm) /* if terminal input */ { if ((c = gettty()) == CTL('H')) /* process backspace */ { if (!ccount) goto restart; /* if at beginning, ignore */ --ccount; /* decrement char count */ backc(&cmdstr); /* back up the command-string pointer */ /* look at the character just deleted */ if (((c = cmdstr.p->ch[cmdstr.c]) < ' ') && (c != ESC)) /* control chars: set c to char erased */ { if (c == LF) vt(VT_LINEUP); /* line up */ else if ((c == CR) || (c == TAB)) { i = find_lasteol(); /* back up to previous line */ type_char(CR); /* erase current line */ vt(VT_EEOL); if (i == ccount) type_char('*'); /* if this was line with prompt, retype the prompt */ for (; (t_qp.p != cmdstr.p) || (t_qp.c != cmdstr.c); fwdc(&t_qp)) type_char(t_qp.p->ch[t_qp.c]); /* retype line: stop before deleted position */ } else { vt(VT_BS2); /* erase ordinary ctrl chars */ char_count -= 2; } } else { vt(VT_BS1); /* erase printing chars */ char_count--; } lastc = ' '; /* disable dangerous last chars */ continue; } /* end 'rubout' processing */ else if (c == CTL('U')) /* process "erase current line" */ { type_char(CR); /* erase line */ vt(VT_EEOL); if ((ccount -= find_lasteol()) <= 0) goto prompt; /* back up to last eol: if beginning, restart */ cmdstr.p = t_qp.p; /* put command pointer back to this point */ cmdstr.c = t_qp.c; lastc = ' '; continue; /* and read it again */ } else /* not a rubout or ^U */ { if (c >= 0400) /* function key - execute if enabled, and exit if 2 ESCs found */ { if ((ez_val & EZ_EXTQ) != 0 && (do_func_val = do_func_keys(c)) != 0) break; } else if (!ccount) /* if at beginning of line */ { if (c == '*') /* save old command string */ { type_char('*'); /* echo character */ c = gettty(); /* read spec for reg to save */ if (c >= 0400) { i = getextqspec(c); /* func key */ if (ez_val & EZ_EXTQ) qreg[i].v = 16; /* set "execute" bit */ } else { type_char((unsigned char) c); /* echo */ if (c == '`') /* alternative register */ { type_char((unsigned char) (c = gettty())); /* read & echo one more */ if ((c = mapch_l[c]) < 'a' || c > 'y') ERROR(E_IQN); /* not a valid spec */ i = EXTQREGS + c - 'a'; } else i = getqspec(0, (unsigned char) c); } free_blist(qreg[i].f); /* return its previous contents */ qreg[i].f = cbuf.f; /* put the old command string in its place */ if (qreg[i].f) { qreg[i].f->b = (BUFFPTR) &qreg[i]; qreg[i].f->usecount = 1; } qreg[i].z = cbuf.z; cbuf.f = (BUFFPTR) (cbuf.z = 0); /* no old command string */ err = 0; /* no previous error */ goto restart; } else if ((c == '?') && (err)) /* echo previous command string up to error */ { type_char('?'); /* echo ? */ for (aa.p = cptr.p; aa.p->b->b != NULL; aa.p = aa.p->b); /* find beginning */ for (aa.c = 0; (aa.p != cptr.p) || (aa.c < cptr.c); fwdc(&aa)) type_char(aa.p->ch[aa.c]); type_char('?'); /* a final ? */ err = 0; /* reset error switch */ goto restart; } else if ((c == CTL('W')) && (WN_scroll != 0)) /* immediate window redisplay */ { window(WIN_REDRAW); /* redraw full window */ window(WIN_REFR); goto restart; } else /* first real command on a line */ { make_buffer(&cbuf); /* start a command string if need be */ cmdstr.p = cbuf.f; /* set cmdstr to point to start of command string */ cmdstr.c = 0; cbuf.z = 0; /* no chars in command string now */ err = 0; /* clear last error flag */ } } /* end of "if first char on line" */ /* check ^G-something */ if (lastc == CTL('G')) { if (c == CTL('G')) { cbuf.z = ccount; /* save count for possible "save in q-reg" */ goto restart; } if ((c == '*') || (c == ' ')) { backc(&cmdstr); /* remove the previous ^G from buffer */ --ccount; crlf(); retype_cmdstr((unsigned char) c); /* retype appropriate part of command string */ lastc = ' '; continue; } /* end of ^G* and ^G processing */ } /* end of "last char was ^G" */ } /* end of "not rubout or ^U */ } /* end of "if !eisw" */ else /* if input from indirect file or redirected std input */ { if (!ccount) /* first command? */ { if (!cbuf.f) /* start a command string if need be */ { cbuf.f = get_bcell(); cbuf.f->b = (BUFFPTR) &cbuf; } cmdstr.p = cbuf.f; /* point cmdstr to start of command string */ cbuf.z = cmdstr.c = 0; } c = (eisw) ? getc(eisw) : gettty() ; /* get char */ if (eisw && (c == EOF)) /* if this is end of the indirect command file */ { fclose(eisw); /* close the input file */ eisw = 0; /* reset the switch */ lastc = ' '; continue; /* and go read more chars */ } else { if ((c == LF) && (lastc != CR) && !(ez_val & EZ_CRLF)) /* LF: store implied CR first */ { cmdstr.p->ch[cmdstr.c] = CR; ++ccount; fwdcx(&cmdstr); } } } /* end of "if redirected std in or eisw" */ /* store character in command string */ if (c <= char_mask) /* skip spec'l chars */ { cmdstr.p->ch[cmdstr.c] = c; /* store the character */ ++ccount; /* keep count of chars */ if (!eisw && !inp_noterm) type_char((unsigned char) c); /* echo the character */ fwdcx(&cmdstr); /* next char pos'n; extend command string if nec */ } if ((c == ESC) && (lastc == ESC)) break; /* stop on 2nd ESC */ if ((c == CTL('C')) && (lastc == CTL('C'))) return(-1); /* immediate exit */ lastc = c; /* keep track of last char */ } /* end of read-char loop */ cbuf.z = ccount; /* indicate number of chars in command string */ if (!eisw && !inp_noterm) crlf(); /* final new-line */ display_mouse(MOUSE_NORDCMD); return( (do_func_val == -1) ? -1 : 0); } /* end of read_cmdstr() */ /* back up to find most recent CR or LF in entered command string */ /* return number of chars backed up */ static short find_lasteol() { short i; for (i = 0, t_qp.p = cmdstr.p, t_qp.c = cmdstr.c; (backc(&t_qp)) ; i++) /* look for beg. of line */ { if ((t_qp.p->ch[t_qp.c] == CR) || (t_qp.p->ch[t_qp.c] == LF)) { fwdc(&t_qp); /* stop short of previous eol */ break; } } char_count = 0; /* reset tab count */ return(i); } /* retype command string: entirely (arg = '*') or most recent line (arg = ' ') */ static void retype_cmdstr(char c) { short i; if (!inp_noterm) /* if input is really from terminal */ { if (c == ' ') /* look for beginning of this line */ i = ccount - find_lasteol(); /* to last eol, and count char's backed up */ else { t_qp.p = cbuf.f; /* retype whole command string */ i = t_qp.c = 0; } if (!i) type_char('*'); /* if from beginning, retype prompt */ for (; i < ccount; i++) /* type command string from starting point */ { type_char(t_qp.p->ch[t_qp.c]); fwdc(&t_qp); } } } /* process function keys: execute immediate command or copy to command string */ /* if associated q-reg's value is < 0 copy to command string; */ /* if > 0 and (even, or at beginning of cmd string) execute immediately */ /* return 1 if copying to command string and 2 ESCs found, 0 otherwise */ static unsigned char func_key_table[] = /* table of function key codes */ { /* norm shift control alt */ KEY_F1, KEY_F1_S, KEY_F1_C, KEY_F1_A, /* Q`A */ KEY_F2, KEY_F2_S, KEY_F2_C, KEY_F2_A, /* Q`B */ KEY_F3, KEY_F3_S, KEY_F3_C, KEY_F3_A, /* Q`C */ KEY_F4, KEY_F4_S, KEY_F4_C, KEY_F4_A, /* Q`D */ KEY_F5, KEY_F5_S, KEY_F5_C, KEY_F5_A, /* Q`E */ KEY_F6, KEY_F6_S, KEY_F6_C, KEY_F6_A, /* Q`F */ KEY_F7, KEY_F7_S, KEY_F7_C, KEY_F7_A, /* Q`G */ KEY_F8, KEY_F8_S, KEY_F8_C, KEY_F8_A, /* Q`H */ KEY_F9, KEY_F9_S, KEY_F9_C, KEY_F9_A, /* Q`I */ KEY_F10, KEY_F10_S, KEY_F10_C, KEY_F10_A, /* Q`J */ KEY_F11, KEY_F11_S, KEY_F11_C, KEY_F11_A, /* Q`K */ KEY_F12, KEY_F12_S, KEY_F12_C, KEY_F12_A, /* Q`L */ KEY_LEFT, 0, KEY_LEFT_C, KEY_LEFT_A, /* Q`M */ KEY_RIGHT, 0, KEY_RIGHT_C, KEY_RIGHT_A, /* Q`N */ KEY_UP, 0, KEY_UP_C, KEY_UP_A, /* Q`O */ KEY_DOWN, 0, KEY_DOWN_C, KEY_DOWN_A, /* Q`P */ KEY_INS, 0, KEY_INS_C, KEY_INS_A, /* Q`Q */ KEY_DEL, 0, KEY_DEL_C, KEY_DEL_A, /* Q`R */ KEY_HOME, 0, KEY_HOME_C, KEY_HOME_A, /* Q`S */ KEY_END, 0, KEY_END_C, KEY_END_A, /* Q`T */ KEY_PGUP, 0, KEY_PGUP_C, KEY_PGUP_A, /* Q`U */ KEY_PGDN, 0, KEY_PGDN_C, KEY_PGDN_A, /* Q`V */ 0, /* tab */ KEY_TAB_S, KEY_TAB_C, KEY_TAB_A, /* Q`W */ KEY_MOUSEL, KEY_MOUSEL_S, KEY_MOUSEL_C, KEY_MOUSEL_A, /* Q`X */ KEY_MOUSER, KEY_MOUSER_S, KEY_MOUSER_C, KEY_MOUSER_A, /* Q`Y */ KEY_MOUSEM, KEY_MOUSEM_S, KEY_MOUSEM_C, KEY_MOUSEM_A /* Q`Z */ }; /* process function keys */ /* called with key code; func. keys have 0400 bit set */ /* returns 0 normally, +1 if 2 ESCs put into command string, -1 if immed. macro ended with EX */ static short do_func_keys(unsigned short c) { short i, n; /* temporaries */ struct qh *header_p; /* pointer to register's header */ struct qp pointer; /* q-pointer to register being copied */ unsigned char last_c = ' ', this_c; /* char's used in copying command string */ for (i = 0; i < sizeof(func_key_table); i++) /* look up key code */ if (func_key_table[i] == (c & 0x00ff)) { header_p = &qreg[EXTALPHQREGS+(i>>2)]; /* found - point to corresp q-reg header */ func_key_chain: if ((header_p->v & IMMED_ENABLE) && (ccount == 0 || !(header_p->v & IMMED_BEGIN))) { /* if func. keys are enabled */ header_p->v = (header_p->v & ~0x000f) | (c >> 9); /* put in shift bits */ if (header_p->v & IMMED_INSERT) { /* copy register text to command string */ pointer.p = header_p->f; /* initialize pointer */ pointer.c = 0; if (ccount == 0) /* if this is the start of a string... */ { make_buffer(&cbuf); /* start a command string if need be */ cmdstr.p = cbuf.f; /* set cmdstr to point to start of command string */ cmdstr.c = 0; cbuf.z = 0; /* no chars in command string now */ } for (n = 0; n < header_p->z; n++) /* copy characters */ { this_c = cmdstr.p->ch[cmdstr.c] = pointer.p->ch[pointer.c]; /* copy */ fwdc(&pointer); /* increment pointers */ fwdcx(&cmdstr); ++ccount; /* lengthen command string */ type_char(this_c); /* echo */ if (this_c == ESC && last_c == ESC) return(1); /* 2 ESCs found - exit */ last_c = this_c; } } else /* execute? */ { saved_command = cbuf; /* save current command string in progress */ saved_cmd_ptr = cmdstr; /* save current pointer */ cbuf.f = get_bcell(); /* make a new buffer */ cbuf.f->b = (BUFFPTR) &cbuf.f; cbuf.f->ch[0] = 'm'; /* make up a macro call */ cbuf.f->ch[1] = '`'; cbuf.f->ch[2] = 'a'+ (i >> 2); cbuf.f->ch[4] = cbuf.f->ch[3] = ESC; cbuf.z = 5; display_mouse(MOUSE_NORDCMD); /* remove mouse pointer */ exec_cmdstr(); /* execute */ free_blist(cbuf.f); /* flush temp. command string */ cmdstr = saved_cmd_ptr; /* restore */ cbuf = saved_command; saved_command.f = 0; /* set to "no command string saved" */ if (exitflag == -1) return(-1); window(WIN_REFR); /* refresh display */ display_mouse(MOUSE_RDCMD); /* replace mouse pointer */ if (header_p->v & IMMED_CHAIN) /* chain to Q`0? */ { header_p = &qreg[EXTQREGS]; /* yes, point to that header */ goto func_key_chain; /* and do it again */ } } } break; /* get out of character lookup loop */ } return(0); /* normal return */ } /* get q spec corresponding to function key */ static short getextqspec(unsigned short c) { unsigned short i; for (i = 0; i < sizeof(func_key_table); i++) /* look up key code */ if (func_key_table[i] == (c & 0xff)) return(EXTALPHQREGS+(i>>2)); ERROR(E_IQN); /* no match found */ } /* get q-register letter corresponding to function key */ /* (built-in for interpreting function key codes */ /* called with scan code in esp->val1, returns letter code in esp->val1 */ void do_fq(void) { unsigned short i; if (!esp->flag1) esp->val1 = 0; /* missing value */ for (i = 0; i < sizeof(func_key_table); i++) if (func_key_table[i] == (unsigned char) (esp->val1 & 0xff)) { esp->val1 = (i >> 2) + 'a'; /* esp->flag1 still set */ return; } esp->val1 = 0; }