allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (06/22/89)
Posting-number: Volume 7, Issue 51 Submitted-by: fox@marlow.UUCP (Paul Fox) Archive-name: crisp1.9/part31 #!/bin/sh # this is part 10 of a multipart archive # do not concatenate these parts, unpack them in order with /bin/sh # file ./tty.c continued # CurArch=10 if test ! -r s2_seq_.tmp then echo "Please unpack part 1 first!" exit 1; fi ( read Scheck if test "$Scheck" != $CurArch then echo "Please unpack part $Scheck next!" exit 1; else exit 0; fi ) < s2_seq_.tmp || exit 1 echo "x - Continuing file ./tty.c" sed 's/^X//' << 'SHAR_EOF' >> ./tty.c X char *bg[16]; X } COLORS; XCOLORS colors = { X {"\033[0;30m", "\033[0;34m", "\033[0;32m", "\033[0;36m", /* Foreground. */ X "\033[0;31m", "\033[0;35m", "\033[0;33m", "\033[0;37m", X "\033[30;1m", "\033[34;1m", "\033[32;1m", "\033[36;1m", X "\033[31;1m", "\033[35;1m", "\033[33;1m", "\033[37;1m"}, X {"\033[40m", "\033[44m", "\033[42m", "\033[46m", /* Background. */ X "\033[41m", "\033[45m", "\033[43m", "\033[47m", X "\033[40;1m", "\033[44;1m", "\033[42;1m", "\033[46;1m", X "\033[41;1m", "\033[45;1m", "\033[43;1m", "\033[47;1m"}, X }; X Xint LI; /* standard # lines */ Xint AM; /* Has auto-margins. */ Xchar X *AL, /* add line */ X *BC, /* Backspace character. */ X *CD, /* Clear to end of display. */ X *CE, /* Clear to end of line. */ X *CL, /* Clear screen */ X *CM, /* Cursor motion */ X *CS, /* set scroll region */ X *DC, /* Delete a character. */ X *DL, /* del line */ X *EI, /* end insert mode */ X *HO, /* Home cursor. */ X *IC, /* insert a single space */ X *IM, /* insert mode */ X *IS, /* Init sequence. */ X *MB, /* Turn on blinking. */ X *MD, /* Make bold */ X *ME, /* Turn off all attributes. */ X *RS, /* Reset sequence. */ X *SE, /* End standout mode. */ X *SO, /* Start standout mode. */ X *SR, /* back index (used with scroll region */ X *TE, /* term end --- end using cursor motion */ X *TI, /* term init -- start using cursor motion */ X *UP, /* Cursor up. */ X *pAL, /* parameterized add line */ X *pDL; /* parameterized delete line */ X Xchar *K[NFKEYS]; /* other function key codes */ Xchar *KS, *KE; /* enter keypad mode, exit keypad mode */ Xint SG; /* number of glitches, 0 for invisable, -1 for none */ Xchar *termcap_strings = X"AL DL al bc cd ce cl cm cs dc dl ei ho ic im is ks ke mb me mr rs se so sr te ti up "; Xchar **termcap_ptrs[] = { X &pAL, &pDL, X &AL, &BC, &CD, &CE, &CL, &CM, &CS, &DC, &DL, &EI, &HO, &IC, X &IM, &IS, &KS, &KE, &MB, &MD, &ME, &RS, &SE, &SO, &SR, &TE, &TI, &UP X }; X X/* X * Initialize the terminal when the editor X * gets started up. X */ Xstatic char tcbuf[TCAPSLEN]; X Xvoid Xttinit() X{ X char *ggetenv(); X char *p, *tgetstr(); X char *tv_stype; X char *tptr; X char ***cptr; X char *cp; X X if ((tv_stype = ggetenv("TERM")) == NULL) X panic("Environment variable TERM not defined!"); X X if((tgetent(tcbuf, tv_stype)) != 1) { X extern char *termcap_dir; X fprintf(stderr, X "Terminal type '%s' not found in %s.\n", X tv_stype, termcap_dir); X exit(1); X } X X p = tcapbuf; X X LI = tgetnum("li"); X AM = tgetflag("am"); X SG = tgetnum("sg"); X X cptr = termcap_ptrs; X for (tptr = termcap_strings; *tptr; tptr += 3) { X char *cp; X char tmpbuf[3]; X tmpbuf[0] = tptr[0]; X tmpbuf[1] = tptr[1]; X tmpbuf[2] = 0; X if ((cp = tgetstr(tmpbuf, &p)) && *cp) X **cptr = cp; X cptr++; X } X /*PC = pc ? *pc : 0;*/ X if (cp = tgetstr("kh", &p)) X K[KEY_HOME - KFIRST] = cp; X if (cp = tgetstr("ku", &p)) X K[KEY_UP - KFIRST] = cp; X if (cp = tgetstr("kd", &p)) X K[KEY_DOWN - KFIRST] = cp; X if (cp = tgetstr("kl", &p)) X K[KEY_LEFT - KFIRST] = cp; X if (cp = tgetstr("kr", &p)) X K[KEY_RIGHT - KFIRST] = cp; X if (cp = tgetstr("EN", &p)) X K[KEY_END - KFIRST] = cp; X if (cp = tgetstr("PU", &p)) X K[KEY_PAGEUP - KFIRST] = cp; X if (cp = tgetstr("PD", &p)) X K[KEY_PAGEDOWN - KFIRST] = cp; X X if (CM == NULL) X panic("No cursor move (cm) capability in termcap."); X if (UP == NULL) X panic("No upline (up) capability in termcap."); X# if defined(SIGWINCH) X {void ttwinch(); X signal(SIGWINCH, ttwinch); X } X# endif X X if(!CE) tceeol = ncol; X else tceeol = charcost(CE); X X /* Estimate cost of inserting a line */ X if (CS && SR) tcinsl = charcost(CS)*2 + charcost(SR); X else if (pAL) tcinsl = charcost(pAL); X else if (AL) tcinsl = charcost(AL); X else tcinsl = HUGE; /* make this cost high enough */ X X /* Estimate cost of deleting a line */ X if (CS) tcdell = charcost(CS)*2 + 1; X else if (pDL) tcdell = charcost(pDL); X else if (DL) tcdell = charcost(DL); X else tcdell = HUGE; /* make this cost high enough */ X X /* Flag to indicate that we can both insert and delete lines */ X insdel = (AL || pAL) && (DL || pDL); X X if (p >= &tcapbuf[TCAPSLEN]) X panic("Terminal description too big!\n"); X X /* tgoto() doesnt work properly with real termcap -- leave * X /* this in for now. */ X# if 1 || defined(MY_TERMCAP) X { X void close_termcap(); X close_termcap(); X } X# endif X} Xttinit1() X{ X ttresize(); /* set nrow & ncol */ X flush_col_cache(); X if (TI) X putpad (TI); /* init the term */ X if (IS) X putpad (IS); /* init the term */ X if (KS) X putpad(KS); X} X/*---------------------------------------- X/* Routine to decypher termcap style strings. X/* Needed by code in set_term_escapes. X/*----------------------------------------*/ X X# define XDIGIT(x) (x <= '9' ? x - '0' : \ X (x >= 'a' && x <= 'z') ? x - 'a' + 10 : \ X (x - 'A' + 10)) Xchar * Xtcopy_string(dp, bp, delim) Xregister char *dp, *bp; X{ register int n; X X while (*bp != delim && *bp) { X if (*bp == '^') { X *dp++ = *++bp & 0x1f; X bp++; X continue; X } X if (*bp != '\\') { X *dp++ = *bp++; X continue; X } X switch (*++bp) { X case 'E': *dp++ = 0x1b; break; X case 'r': *dp++ = '\r'; break; X case 'n': *dp++ = '\n'; break; X case 't': *dp++ = '\t'; break; X case 'b': *dp++ = '\b'; break; X case 'f': *dp++ = '\f'; break; X case '0': case '1': case '2': case '3': X n = 0; X while (*bp >= '0' && *bp <= '7') X n = 8*n + *bp++ - '0'; X bp--; X *dp++ = (char) n; X break; X case 'x': X bp++; X n = XDIGIT(*bp); X bp++; X n = n * 16 + XDIGIT(*bp); X *dp++ = (char) n; X break; X default: *dp++ = *bp; break; X } X bp++; X } X *dp++ = NULL; X return dp; X} X X/* X * Clean up the terminal, in anticipation of X * a return to the command interpreter. This is a no-op X * on the ANSI display. On the SCALD display, it sets the X * window back to half screen scrolling. Perhaps it should X * query the display for the increment, and put it X * back to what it was. X */ Xvoid Xtttidy() X{ X if (RS && *RS) putpad (RS); /* set the term back to normal mode */ X if (TE && *TE) putpad (TE); /* set the term back to normal mode */ X if (KE) X putpad(KE); X} X X/* X * Move the cursor to the specified X * origin 0 row and column position. Try to X * optimize out extra moves; redisplay may X * have left the cursor in the right X * location last time! X */ Xvoid Xttmove(row, col) Xu_int16 row; Xu_int16 col; X{ X char *tgoto(); X extern char *HO; X if (ttrow == row && ttcol == col) X return; X X if (col == 0 && row == 0 && HO) X putpad(HO); X else if (ttcol == col && row == ttrow+1) X ttputpad('\n'); X else if (ttcol == col+1 && row == ttrow+1) { X ttputpad('\n'); X ttputpad('\b'); X } X else if (ttcol-1 == col && row == ttrow) X ttputpad('\b'); X else if (ttrow == row && pt.pt_escC[0] && col > ttcol && ttcol > 1) { X putpad(tgoto(pt.pt_escC, 0, col - ttcol)); X } X else { X char *cp = tgoto(CM, (int) col, (int) row); X/* int len = strlen(cp); X if (row == ttrow && col + len < ttcol) { X int i; X for (i = 0; i++ < ttcol - col; i++) X ttputpad('\b'); X } X else*/ X putpad(cp); X } X ttrow = row; X ttcol = col; X} X/* X * Erase to end of line. X */ Xvoid Xtteeol() X{ X if(CE) putpad(CE); X else { X register int i=ncol-ttcol; X while(i--) ttputc(' '); X ttrow = ttcol = HUGE; X } X} X Xttclear() X{ X if (CL == NULL) { X ttmove((u_int16) 0, (u_int16) 0); X tteeop(); X } X else { X ttrow = 0; X ttcol = 0; X putpad(CL); X } X} X/* X * Erase to end of page. X */ Xvoid Xtteeop() X{ X if(CD) putpad(CD); X else { X putpad(CE); X if (insdel) ttdell(ttrow + 1, LI, LI - ttrow - 1); X else { /* do it by hand */ X register int line; X for (line = ttrow + 1; line <= LI; ++line) { X ttmove((u_int16) line, (u_int16) 0); X tteeol(); X } X } X ttrow = ttcol = HUGE; X } X} X X/* X * Make a noise. X */ Xvoid Xttbeep() X{ X ttputc(BEL); X /*---------------------------------------- X /* Adjust cursor because ttputc() thinks X /* BEL moves the cursor. X /*----------------------------------------*/ X ttcol--; X ttflush(); X} Xbeep() X{ X ttbeep(); X return 0; X} X X/* X * Insert nchunk blank line(s) onto the X * screen, scrolling the last line on the X * screen off the bottom. Use the scrolling X * region if possible for a smoother display. X * If no scrolling region, use a set X * of insert and delete line sequences X */ Xttinsl(row, bot, nchunk) X{ X register int i; X X if (row == bot) { /* Case of one line insert is special */ X ttmove((u_int16) row, (u_int16) 0); X tteeol(); X return TRUE; X } X if (CS && SR) { /* Use scroll region and back index */ X ttwindow(row,bot); X ttmove((u_int16) row, (u_int16) 0); X while (nchunk--) putpad(SR); X /*ttnowindow();*/ X return TRUE; X } X if (insdel) { X ttmove((u_int16) (1+bot-nchunk), (u_int16) 0); X if (pDL) X putpad (tgoto(pDL, 0, nchunk)); X else X for (i=0; i<nchunk; i++)/* For all lines in the chunk */ X putpad(DL); X ttmove((u_int16) row, (u_int16) 0); X if (pAL) X putpad (tgoto(pAL, 0, nchunk)); X else X for (i=0; i<nchunk; i++)/* For all lines in the chunk*/ X putpad(AL); X ttrow = HUGE; X ttcol = HUGE; X return TRUE; X } X return FALSE; X} X X/* X * Delete nchunk line(s) from "row", replacing the X * bottom line on the screen with a blank line. X * Unless we're using the scrolling region, this is X * done with a crafty sequences of insert and delete X * lines. The presence of the echo area makes a X * boundry condition go away. X */ Xttdell(row, bot, nchunk) X{ register int i; X X if (row == bot) { /* One line special case */ X ttmove((u_int16) row, (u_int16) 0); X tteeol(); X return TRUE; X } X if (CS) { /* scrolling region */ X ttwindow(row, bot); X ttmove((u_int16) bot, (u_int16) 0); X while (nchunk--) ttputc(LF); X return TRUE; X } X if(insdel) { X ttmove((u_int16) row, (u_int16) 0); X if (pDL) X putpad (tgoto(pDL, 0, nchunk)); X else X for (i=0; i<nchunk; i++) X putpad(DL); X ttmove((u_int16) (1+bot-nchunk), (u_int16) 0); X if (pAL) X putpad (tgoto(pAL, 0, nchunk)); X else X for (i=0; i<nchunk; i++) X putpad(AL); X ttrow = HUGE; X ttcol = HUGE; X return TRUE; X } X return FALSE; X} X X/* X * This routine sets the scrolling window X * on the display to go from line "top" to line X * "bot" (origin 0, inclusive). The caller checks X * for the pathalogical 1 line scroll window that X * doesn't work right, and avoids it. The "ttrow" X * and "ttcol" variables are set to a crazy value X * to ensure that the next call to "ttmove" does X * not turn into a no-op (the window adjustment X * moves the cursor). X * X */ Xvoid Xttwindow(top, bot) X{ X if (CS && (tttop!=top || ttbot!=bot)) { X putpad(tgoto(CS, bot, top)); X ttrow = HUGE; /* Unknown. */ X ttcol = HUGE; X tttop = top; /* Remember region. */ X ttbot = bot; X } X} X X/* X * Set the current writing color to the X * specified color. Watch for color changes that are X * not going to do anything (the color is already right) X * and don't send anything to the display. X * The rainbow version does this in putline.s on a X * line by line basis, so don't bother sending X * out the color shift. X */ Xstatic int tthue = -1; Xstatic int tt_fg = -1; Xstatic int tt_bg = -1; Xstatic int gso = FALSE; Xvoid Xflush_col_cache() X{ X tthue = tt_fg = tt_bg = -1; X} Xvoid Xttcolor(color) X{ int fg, bg; X X if (tthue == color) X return; X tthue = color; X if (!pt.pt_color) { X if (color == FG(col_table.c_normal) || X color == FG(col_table.c_messages)) { X putpad(SE); X } X else if (color == FG(col_table.c_select) || X color == FG(col_table.c_error)) { X putpad(SE); X putpad(MD); X } X else { X putpad(SO); X } X return; X } X fg = (color & FG_COLOR) >> FG_SHIFT; X bg = (color & BG_COLOR) >> BG_SHIFT; X if (fg != tt_fg) { X putpad(colors.fg[fg]); X tt_fg = fg; X } X if (bg != tt_bg) { X putpad(colors.bg[bg]); X tt_bg = bg; X } X} Xvoid Xttresize() X{ X setttysize(); X if (nrow < 1) X nrow = 1; X if (ncol < 1) X ncol = 1; X} Xvoid Xttwinch() X{ X# if defined(SIGWINCH) X void ttwinch1(); X X int oncol = ncol; X int onrow = nrow; X ttresize(); X signal(SIGWINCH, ttwinch); X update(); X# endif X} Xvoid Xttwinch1(oncol, onrow, ncol, nrow) X{ register WINDOW *wp; X extern int sgarbf; X int diffcol, diffrow; X X vtinit1(); X diffcol = ncol - oncol; X diffrow = nrow - onrow; X for (wp = wheadp; wp; wp = wp->w_wndp) { X int right_edge; X int last_line; X /*---------------------------------------- X /* Adjust window width only if its right X /* hand edge touches the right hand edge X /* of the window. X /*----------------------------------------*/ X right_edge = wp->w_x + wp->w_w; X last_line = wp->w_y + wp->w_h; X if (wp->w_tiled) X right_edge++; X if (right_edge == oncol) X wp->w_w += diffcol; X /*---------------------------------------- X /* Adjust window height if window's X /* bottom line touches bottom of screen. X /*----------------------------------------*/ X if (last_line == onrow - 3) X wp->w_h += diffrow; X } X sgarbf = TRUE; X} X Xstatic int cci; X Xstatic void /* fake char output for charcost() */ Xfakec(c) char c; X{ X#ifdef lint X c++; X#endif X cci++; X} X X/* calculate the cost of doing string s */ Xcharcost (s) char *s; X{ X cci = 0; X X tputs(s, nrow, fakec); X return cci; X} Xvoid Xputpad(str) Xchar *str; X{ X if (str == NULL) X return; X/* if (str == SO) { X if (gso) X return; X gso = TRUE; X } X else if (str == SE) { X if (!gso) X return; X gso = FALSE; X } */ X tputs(str, 1, ttputpad); X} Xvoid Xttspace(n, space, stay) X{ u_int16 oldrow = ttrow; X u_int16 oldcol = ttcol; X X if (n <= 0) X return; X ttputc(space); X if (--n <= 0) X return; X if (pt.pt_space[0]) { X putpad(tgoto(pt.pt_space, 0, n)); X if (!stay) X ttmove(oldrow, oldcol + n + 1); X } X else { X while (n-- > 0) X ttputc(space); X } X if (stay) X ttmove(oldrow, oldcol); X X} Xttrepeat(ch, n) X{ X if (n > 12 && pt.pt_repeat[0]) { X ttputc(ch); X putpad(tgoto(pt.pt_repeat, 0, n-1)); X ttmove(ttrow, ttcol + n - 1); X } X while (n-- > 0) X ttputc(ch); X X X} X SHAR_EOF echo "File ./tty.c is complete" chmod 0444 ./tty.c || echo "restore of ./tty.c fails" mkdir . >/dev/null 2>&1 echo "x - extracting ./ttyio.c (Text)" sed 's/^X//' << 'SHAR_EOF' > ./ttyio.c && X/************************************************************** X * X * CRISP - Custom Reduced Instruction Set Programmers Editor X * X * (C) Paul Fox, 1989 X * 43, Jerome Close Tel: +44 6284 4222 X * Marlow X * Bucks. X * England SL7 1TX X * X * X * Please See COPYRIGHT notice. X * X **************************************************************/ X X# include "list.h" XSCCSID("@(#) ttyio.c 1.15, (C) P. Fox"); X X# if defined(SUN) X# include <sys/time.h> X# include <termio.h> X# endif X# if defined(XENIX) X# include <termio.h> X# endif X X X X# define TTY_FD 0 X# define BIT(x) (1 << (x)) X X# if defined(SELECT) X# include <sys/types.h> X# include <sys/time.h> X X# endif Xlong sel_bits = BIT(TTY_FD); X X# define CENTISECONDS 5 /* x .01 seconds */ Xvoid ttflush(); X X#define NOBUF 136 /* Output buffer size. */ X Xlong st_charout; /* Number of characters output. */ X Xchar obuf[NOBUF+10]; /* Output buffer. */ Xint nobuf; /* buffer count */ Xint timeout_flag = FALSE; /* TRUE when we are in VMIN/VTIME mode.*/ Xint reading_char; Xunsigned char kbdq = 0; Xextern int ega43_flag; Xint old_ega_flag = -1; X Xu_int16 nrow; /* Terminal size, rows. */ Xu_int16 ncol; /* Terminal size, columns. */ X X/* X * This function gets called once, to set up X * the terminal channel. This version turns off flow X * control. This may be wrong for your system, but no X * good solution has really been found (daveb). X */ Xvoid Xttopen() X{ X sys_open(); X ttinit1(); X} Xvoid Xtttimeout(yes) X{ X if (yes == timeout_flag) X return; X timeout_flag = yes; X sys_timeout(yes); X} X/* X * This function gets called just X * before we go back home to the shell. Put all of X * the terminal parameters back. X */ Xvoid Xttclose() X{ X ttflush(); X sys_close(); X old_ega_flag = -1; X} X X/* X * Write character to the display. X * Characters are buffered up, to make things X * a little bit more efficient. X */ Xvoid Xttputpad(c) X{ X if (nobuf >= NOBUF) X ttflush(); X obuf[nobuf++] = (char) c; X} Xvoid Xttputs(str) Xregister char *str; X{ X while (*str) X ttputc(*str++); X} Xvoid Xttputc(c) Xregister int c; X{ X extern int scr_attr; X register int color = c & COLOR_MASK; X extern int AM; X X if (nobuf >= NOBUF) X ttflush(); X X ttcolor(color); X X c &= 0xff; X/* if (c & 0x80 && c < (0x80 + ' ')) {*/ X if (c & 0x80) { X if (c >= CH_MIN && c <= CH_MAX) { X char *cp = "?"; X switch (c) { X case CH_HORIZONTAL: cp = pt.pt_horizontal; break; X case CH_VERTICAL: cp = pt.pt_vertical; break; X case CH_TOP_LEFT: cp = pt.pt_top_left; break; X case CH_TOP_RIGHT: cp = pt.pt_top_right; break; X case CH_BOT_LEFT: cp = pt.pt_bot_left; break; X case CH_BOT_RIGHT: cp = pt.pt_bot_right; break; X case CH_TOP_JOIN: cp = pt.pt_top_join; break; X case CH_BOT_JOIN: cp = pt.pt_bot_join; break; X case CH_LEFT_JOIN: cp = pt.pt_left_join; break; X case CH_RIGHT_JOIN: cp = pt.pt_right_join; break; X case CH_CROSS: cp = pt.pt_cross; break; X } X strcpy(obuf + nobuf, cp); X nobuf += strlen(cp); X } X else if (c >= 0x80 + ' ') X goto hell; X else { X c &= 0x7f; X if (c == 0x1b && pt.pt_escape[0]) X strcpy(obuf+nobuf, pt.pt_escape); X else X sprintf(obuf+nobuf, pt.pt_character, c ? c : 0x80); X nobuf += strlen(obuf+nobuf); X } X goto end_of_function; X } X if (c == 0) X return; Xhell: X obuf[nobuf++] = (char) c; X if (c == '\b') { X ttcol--; X return; X } Xend_of_function: X if (++ttcol >= ncol && AM) { X ttcol = 0; X ttrow++; X } X} X Xvoid Xttflush() X{ extern int background; X X if (nobuf != 0) { X st_charout += nobuf; X if (background == FALSE) X sys_write(1, obuf, nobuf); X nobuf = 0; X } X} XKEY Xgetkey() X{ X int n; X unsigned char ch; X extern int num_pty; X extern long time_last_key_pressed; X KEY key; X static unsigned char buf[32]; /* Buffer for current key being read in */ X static unsigned char *bufptr = NULL; X unsigned char *cp = buf; X int pass2 = FALSE; X extern int push_cnt; X# if defined(SELECT) X struct timeval timeout; X struct timeval *tp = NULL; X X timeout.tv_sec = 0; X timeout.tv_usec = 0; X# endif X X if (push_cnt) X return get_push(); X X if (bufptr) { X ch = *bufptr++; X if (*bufptr == NULL) X bufptr = NULL; X return ch; X } X X while (1) { X extern int child_sig; X extern void proc_wait(); X /*---------------------------------------- X /* Check to see if clock has gone off X /* and we need to call somebody. We can X /* only safely do this whilst we are NOT X /* reading a character from the keyboard. X /*----------------------------------------*/ X clock_check(); X if (kbdq) { X ch = kbdq; X kbdq = 0; X goto got_char; X } X /*---------------------------------------- X /* If SIGCLD gone off then we should be X /* safe here to go and process it. X /*----------------------------------------*/ X if (child_sig) X proc_wait(-1); X X reading_char = TRUE; X# if defined(SELECT) X if (pass2) { X timeout.tv_usec = CENTISECONDS * 100 * 1000; X tp = &timeout; X } X if (tp || num_pty) { X int fd, bits; X long readbits = sel_bits; X long kbd_ready; X long pty_ready; X int nfds = select(32, &readbits, (long *) NULL, (long *) NULL, X tp); X if (nfds < 0) X continue; X kbd_ready = BIT(TTY_FD) & readbits; X pty_ready = FALSE; X /*---------------------------------------- X /* Handle all pty's first. X /*----------------------------------------*/ X for (fd = 0, bits = 0; readbits && bits < 32; X bits++, readbits >>= 1, fd++) { X if (fd == TTY_FD) X continue; X if ((BIT(fd) & readbits) == 0) X continue; X p_poll(); X pty_ready = TRUE; X } X if (kbdq) X continue; X if (!kbd_ready) { X if (tp && pty_ready == FALSE) X goto return_ch; X continue; X } X } X# endif X# if !defined(SELECT) X tttimeout(pass2); X# endif X /*---------------------------------------- X /* Check to see if we have anything in X /* playback buffer, before finally going X /* to the keyboard for a character. X /*----------------------------------------*/ X if ((ch = grab_char()) == 0) { X if (sys_getchar(TTY_FD, &ch, 1) != 1) { X if (pass2) X goto return_ch; X continue; X } X } X Xgot_char: X reading_char = FALSE; X *cp++ = ch; X *cp = NULL; X time_last_key_pressed = time((long *) 0); X key = check_key(buf, cp - buf); X if (key > 0) { X store_char(key); X return key; X } X if (key == 0) { Xreturn_ch: X if (buf[1]) X bufptr = &buf[1]; X store_char (buf[0]); X return buf[0]; X } X pass2 = TRUE; X } X} X Xtypeahead() X{ X if (kbdq) X return kbdq; X X if (kbdq = grab_char()) X return kbdq; X X kbdq = sys_checkc(); X return kbdq; X} X X Xvoid Xpanic(s) Xchar *s; X{ X u_close(); X vttidy(); X fprintf(stderr, "CRISP PANIC: %s\r\n", s); X exit(1); X} X Xdo_ega() X{ int arg = argv[1].l_flags == F_NULL ? 0 : argv[1].l_int; X X accumulator = ega43_flag ? 43 : 25; X if (argv[1].l_flags == F_NULL) X return; X X if (arg == 43) X arg = 1; X else if (arg == 25) X arg = 0; X ega_switch(arg); X} Xvoid Xsetttysize() X{ extern char *ggetenv(); X extern int AM; X X#ifdef TIOCGWINSZ X struct winsize winsize; X X if (ioctl(0, TIOCGWINSZ, (char *) &winsize) == 0) { X nrow = winsize.ws_row; X ncol = winsize.ws_col; X } X if (nrow == 0 || ncol == 0) X#endif X if ((nrow= (u_int16) tgetnum ("li")) == 0 X || (ncol= (u_int16) tgetnum ("co")) == 0) { X nrow = 24; X ncol = 80; X } X# if defined(CONS_GET) X {extern int console_mode; X if (console_mode > 0) { X switch (console_mode) { X case M_ENH_C80x43: X ega_switch(1); X nrow = 43; X break; X case M_ENH_C80x25: X ega_switch(0); X nrow = 25; X break; X } X } X } X# endif X if (ggetenv("LINES")) { X nrow = atoi(ggetenv("LINES")); X AM = FALSE; X } X if (ggetenv("COLUMNS")) { X ncol = atoi(ggetenv("COLUMNS")); X AM = FALSE; X } X} Xega_switch(flag) X{ extern int sgarbf; X extern void ttwinch1(); X int onrow = nrow; X X if (flag) X flag = 1; X X if (old_ega_flag == flag) X return; X X old_ega_flag = ega43_flag = flag; X if (flag) { X# if defined(SW_ENHC80x43) X ioctl(1, SW_ENHC80x43, 1); X nrow = 43; X# endif X ttwinch1(ncol, onrow, ncol, nrow); X } X else { X# if defined(SW_ENHC80x25) X ioctl(1, SW_ENHC80x25, 1); X nrow = 25; X# endif X ttwinch1(ncol, onrow, ncol, nrow); X } X flush_col_cache(); X} X SHAR_EOF chmod 0444 ./ttyio.c || echo "restore of ./ttyio.c fails" mkdir . >/dev/null 2>&1 echo "x - extracting ./ttykbd.c (Text)" sed 's/^X//' << 'SHAR_EOF' > ./ttykbd.c && X/************************************************************** X * X * CRISP - Custom Reduced Instruction Set Programmers Editor X * X * (C) Paul Fox, 1989 X * 43, Jerome Close Tel: +44 6284 4222 X * Marlow X * Bucks. X * England SL7 1TX X * X * X * Please See COPYRIGHT notice. X * X **************************************************************/ X# include "list.h" X# include "alt.h" X XSCCSID("@(#) ttykbd.c 1.11, (C) P. Fox"); X X/* X0x80-0x8b 128-139 F1-F12 X0x8c-0x97 140-151 SHIFT-F1 - SHIFT-F12 X0x98-0xA3 152-163 CTRL-F1 - CTRL-F12 X0xA4-0xAF 164-175 ALT-F1 - ALT-F12 X0xB0-0xC9 176-201 ALT-A - ALT-Z X0xCA-0xD3 202-211 Key-0, Key-9 X 0xCA/202=INS X 0xCB/203=END, 0xCC/204=DOWN, 0xCD/205=PgDn, X 0xCE/206=LEFT, 0xCF/207=5, 0xD0/208=RIGHT, X 0xD1/209=HOME, 0xD2/210=UP, 0xD3/211=PgUp X0xD4/212=DEL, 0xD5/213=+, 0xD6/214=-, 0xD7/215=* X0xD8-0xE5 216-229 CTRL-0 .. CTRL-9, DEL, +, -, * X 0xDF/223=Ctrl-Home 0xD9/217=Ctrl-End X 0xE1/225=Ctrl-PgUp 0xDB/219=Ctrl-Pgdn X 0xDC/220=Ctrl-<- 0xDE/222=Ctrl- -> X0xE6 230 Back-tab X*/ X# define MAX_PUSHBACK 12 X Xint reading_char = FALSE; Xstatic u_char key_buf[16]; Xextern long time_last_key_pressed; Xu_char push_buf[MAX_PUSHBACK]; Xint push_cnt = 0; Xchar user_call[64]; /* Last macro called from keyboard by user*/ X Xchar *aitokey(); Xstatic short akeytoi(); Xtypedef char *KEYBOARD[NKEYS]; Xtypedef struct MAP { X char *m_keys; /* Key sequence. */ X char *m_value; /* String assigned to. */ X int m_flags; /* Tells us whether m_value is a */ X /* string or a list. */ X } MAP; X X# define K_ALLOC 0x01 /* Key has been alloc'ed and should*/ X /* be freed when finished with. */ X# define K_LIST 0x02 /* Key is assigned to a list. */ Xstruct kbd_stk { X int k_id; X int k_ref; /* Reference count for this keyboard. */ X /* When this becomes zero, we may free*/ X /* it. Otherwise, it still exists in */ X /* the keyboard stack. */ X u_char k_flags[NKEYS]; X KEYBOARD k_keys; X Head_p k_maps; /* Multicharacter key combinations. */ X }; X XHead_p hd_kbd; XHead_p hd_kstk; Xstruct kbd_stk *kp; X#define KFIRST 0x0080 /* First special. */ Xextern char *K[]; Xchar character; Xint kid = 1; X Xextern struct k_tbl k_tbl[]; Xvoid Xkey_init() X{ extern char *chk_alloc(); X int i; X struct kbd_stk *kptr; X X hd_kbd = ll_init(); X hd_kstk = ll_init(); X X kptr = (struct kbd_stk *) chk_alloc(sizeof (struct kbd_stk)); X kptr->k_id = kid++; X kptr->k_ref = 1; X kptr->k_maps = ll_init(); X for (i = 0; i < NKEYS; i++) { X kptr->k_keys[i] = NULL; X kptr->k_flags[i] = 0; X } X for (i = 0; k_tbl[i].name; i++) { X kptr->k_keys[k_tbl[i].key] = k_tbl[i].name; X kptr->k_flags[k_tbl[i].key] = 0; X } X ll_push(hd_kbd, (char *) kptr); X kp = kptr; X K[BACK_TAB - KFIRST] = strdup("\033[Z"); X} Xkbd_type() X{ X register int i; X X for (i = 0; i < 127; i++) { X if (kp->k_keys[i] && kp->k_flags[i] & K_ALLOC) X chk_free(kp->k_keys[i]); X kp->k_keys[i] = NULL; X } X X return 0; X} Xpush_back() X{ X push_back1((int) argv[1].l_int); X X return 0; X} Xpush_back1(ch) X{ X if (push_cnt < MAX_PUSHBACK) X push_buf[push_cnt++] = ch; X} Xget_push() X{ int ch; X register int i; X if (push_cnt) { X ch = push_buf[0]; X for (i = 0; i < MAX_PUSHBACK - 1; i++) X push_buf[i] = push_buf[i+1]; X push_cnt--; X return ch; X } X return 0; X} Xassign_to_key() X{ int key; X char *cp; X char *macro_name; X int flags = K_ALLOC; X char buf1[80]; X char buf[BUFSIZ]; X X if ((cp = get_arg1("Enter key: ", buf, sizeof buf)) == NULL) X return; X key = akeytoi(cp); X X if (argc < 3 || argv[2].l_flags == F_NULL) { X if (ereply("Enter macro name to assign: ", buf1, sizeof buf1) X != TRUE) X return; X macro_name = strdup(buf1); X } X else if (argv[2].l_flags == F_LIST) { X LIST *copy_list(); X macro_name = (char *) copy_list(argv[2].l_list); X flags = K_LIST | K_ALLOC; X } X else X macro_name = strdup(get_str(2)); X X if (key >= 0) { X free_key(key); X kp->k_keys[key] = macro_name; X kp->k_flags[key] = flags; X } X else { X MAP *mp = (MAP *) chk_alloc (sizeof (MAP)); X mp->m_keys = strdup(key_buf); X mp->m_value = macro_name; X mp->m_flags = flags; X ll_push(kp->k_maps, (char *) mp); X return; X } X} X Xfree_key(key) X{ X if (kp->k_flags[key] & K_ALLOC) X chk_free(kp->k_keys[key]); X} Xstatic short Xakeytoi(cp) Xregister char *cp; X{ X int width; X X for (width = 0; *cp; width++) { X if (*cp == '<') { X key_buf[width] = (u_char) new_akeytoi(cp); X while (*cp) X if (*cp++ == '>') X break; X } X else if (*cp == '#') { X key_buf[width] = (u_char) atoi(++cp); X while (isdigit(*cp)) X cp++; X } X else { X key_buf[width] = 0; X if (*cp == '%') X cp++; X if (*cp == '\\') X key_buf[width] = (u_char) *++cp; X else if (*cp == '^') X key_buf[width] = (u_char) *++cp & 0x1f; X else X key_buf[width] = (u_char) *cp; X cp++; X } X if (width >= sizeof key_buf) X break; X } X if (width == 1) X return key_buf[0]; X key_buf[width] = 0; X return -1; X} Xkey_to_int() X{ X accumulator = akeytoi(get_str(1)); X return 0; X} Xint_to_key() X{ X strl_acc_assign(aitokey((short) argv[1].l_int)); X return 0; X} Xcheck_key(buf, len) Xchar *buf; X{ X register char **cpp; X List_p lp; X KEY key; X X /*-------------------------------------- X * Check for normal function keys first. X *--------------------------------------*/ X for (cpp = K; cpp < &K[NFKEYS]; cpp++) { X if (*cpp == NULL) X continue; X if (strcmp(*cpp, buf) == 0) X return (KEY) (cpp - K + KFIRST); X if (strncmp(*cpp, buf, len) == 0) X return -1; X } X /*-------------------------------------- X * Check for multiple characters key X * sequences. X *--------------------------------------*/ X for (key = KFIRST + NFKEYS, lp = ll_first(kp->k_maps); lp; X key++, lp = ll_next(lp)) { X MAP *mp = (MAP *) ll_elem(lp); X if (strcmp(buf, mp->m_keys) == 0) X return key; X if (strcmp(buf, mp->m_keys, len) == 0) X return -1; X } X return 0; X} X# if 0 XKEY Xgetkey() X{ register char **cpp; X static unsigned char buf[12]; X static unsigned char *bufptr = NULL; X static unsigned char *cp; X static int l; X int i; X unsigned char ch; X int timeout = FALSE; X List_p lp; X KEY key; X int ambiguous; X X if (push_cnt) { X ch = push_buf[0]; X for (i = 0; i < MAX_PUSHBACK - 1; i++) X push_buf[i] = push_buf[i+1]; X push_cnt--; X return ch; X } X X if (bufptr) { X ch = *bufptr++; X if (*bufptr == NULL) X bufptr = NULL; X return ch; X } X cp = buf; X l = 0; X while (1) { X tttimeout(timeout); X X reading_char = TRUE; X if (ch = *cp = (char) ttgetc()) { X extern long time(); X store_char(*cp++); X *cp = NULL; X l++; X time_last_key_pressed = time((long *) 0); X } X reading_char = FALSE; X /*-------------------------------------- X * Check for normal function keys first. X *--------------------------------------*/ X ambiguous = FALSE; X for (cpp = K; cpp < &K[NFKEYS]; cpp++) { X if (*cpp == NULL) X continue; X if (strcmp(*cpp, buf) == 0) X return (KEY) (cpp - K + KFIRST); X if (strncmp(*cpp, buf, l) == 0) { X ambiguous = TRUE; X break; X } X } X /*-------------------------------------- X * Check for multiple characters key X * sequences. X *--------------------------------------*/ X if (!ambiguous) { X for (key = KFIRST + NFKEYS, lp = ll_first(kp->k_maps); lp; X key++, lp = ll_next(lp)) { X MAP *mp = (MAP *) ll_elem(lp); X if (strcmp(buf, mp->m_keys) == 0) X return key; X if (strncmp(buf, mp->m_keys, l) == 0) { X ambiguous = TRUE; X ch = 1; /* Non-zero. */ X break; X } X } X } X if (ch == 0 || !ambiguous) { X if (buf[1]) X bufptr = &buf[1]; X tttimeout(FALSE); X return buf[0]; X } X timeout = TRUE; X } X X} X# endif Xinq_command() X{ X strl_acc_assign(user_call); X return 0; X} Xexec_key(c) X{ register char *cp; X int list_flag; X char *get_key_assignment(); X X u_chain(); X cp = get_key_assignment(c, &list_flag); X character = (char) c; X X remember_macro(cp, list_flag); X X if (list_flag) { X LISTV result; X eval((LIST *) cp, &result); X return 0; X } X X if (cp[0] != '_') X strcpy(user_call, cp); X trace_log("\nKEY_EXEC: %s\n", cp); X return str_exec(cp); X} Xchar * Xget_key_assignment(c, list_flagp) Xint *list_flagp; X{ X register List_p lp; X register char *cp; X *list_flagp = TRUE; X X if (c >= KFIRST + NFKEYS) { X int i = c - KFIRST - NFKEYS; X MAP *mp; X for (lp = ll_first(kp->k_maps); i-- > 0 && lp; ) X lp = ll_next(lp); X mp = (MAP *) ll_elem(lp); X cp = mp->m_value; X if (mp->m_flags & K_LIST) X return cp; X } X else if (curbp->b_keyboard) { X cp = curbp->b_keyboard->k_keys[c]; X if (curbp->b_keyboard->k_flags[c] & K_LIST) X return cp; X if (cp && strcmp(cp, "nothing") == 0) { X cp = kp->k_keys[c]; X if (kp->k_flags[c] & K_LIST) X return cp; X } X } X else { X cp = kp->k_keys[c]; X if (kp->k_flags[c] & K_LIST) X return cp; X } X *list_flagp = FALSE; X return cp ? cp : "self_insert"; X} Xinq_keyboard() X{ X accumulator = kp->k_id; X return 0; X} Xinq_local_keyboard() X{ X accumulator = curbp->b_keyboard ? curbp->b_keyboard->k_id : 0; X return 0; X} Xkbd_push() X{ register int i = argv[1].l_flags == F_NULL ? 0 : (int) argv[1].l_int; X register int j; X X if (i) { X List_p lp; X for (lp = ll_first(hd_kbd); lp; lp = ll_next(lp)) { X kp = (struct kbd_stk *) ll_elem(lp); X if (kp->k_id == i) { X kp->k_ref++; X break; X } X } X if (lp == NULL) { X for (lp = ll_first(hd_kstk); lp; lp = ll_next(lp)) { X kp = (struct kbd_stk *) ll_elem(lp); X if (kp->k_id == i) { X ll_delete(lp); X break; X } X } X } X if (lp == NULL) X errorf("keyboard_push: %d not found.", i); X } X else { X kp = (struct kbd_stk *) chk_alloc(sizeof (struct kbd_stk)); X kp->k_id = kid++; X kp->k_maps = ll_init(); X for (j = 0; j < NKEYS; j++) { X kp->k_keys[j] = i ? (char *) NULL : "nothing"; X kp->k_flags[j] = 0; X } X } X ll_push(hd_kbd, (char *) kp); X X return 0; X X} Xkbd_pop() X{ int i = argv[1].l_flags == F_NULL ? 0 : (int) argv[1].l_int; X register int j; X List_p lp = ll_first(hd_kbd); X X if (lp == NULL) X return 0; X kp = (struct kbd_stk *) ll_elem(lp); X (void) ll_pop(hd_kbd); X X if (i == 0) { X if (--kp->k_ref <= 0) { X for (j = 0; j < NKEYS; j++) X if (kp->k_keys[j] && kp->k_flags[j] & K_ALLOC) X chk_free(kp->k_keys[j]); X for (lp = ll_first(kp->k_maps); lp; X lp = ll_next(lp)) { X MAP *mp = (MAP *) ll_elem(lp); X chk_free(mp->m_keys); X chk_free(mp->m_value); X } X ll_clear(kp->k_maps); X ll_free(kp->k_maps); X chk_free((char *) kp); X } X } X else { X ll_append(hd_kstk, (char *) kp); X } X lp = ll_first(hd_kbd); X kp = lp ? (struct kbd_stk *) ll_elem(lp) : NULL; X X return 0; X} Xuse_local_keyboard() X{ X struct kbd_stk *kp; X register List_p lp; X X accumulator = 0; X if (argv[1].l_int == 0) { X curbp->b_keyboard = NULL; X return 0; X } X for (lp = ll_first(hd_kstk); lp; lp = ll_next(lp)) { X kp = (struct kbd_stk *) ll_elem(lp); X if (kp->k_id == argv[1].l_int) { X curbp->b_keyboard = kp; X return 0; X } X } X accumulator = -1; X return 0; X} Xinq_assignment() X{ char *cp; X short key; X int from_key = argv[2].l_flags == F_NULL || argv[2].l_int == 0; X X if (from_key) { X if (argv[1].l_flags == F_INT) X key = argv[1].l_int; X else X key = akeytoi(get_str(1)); X if (key >= 0) { X if (curbp->b_keyboard) { X cp = curbp->b_keyboard->k_keys[key]; X if (cp && strcmp(cp, "nothing") == 0) X cp = kp->k_keys[key]; X } X else X cp = kp->k_keys[key]; X } X else X cp = "nothing"; X if (cp == NULL) { X character = (char) key; X cp = "self_insert"; X } X strl_acc_assign(cp); X return 0; X } X str_acc_assign("", 0); X if (curbp->b_keyboard) X find_assignment(curbp->b_keyboard->k_keys); X find_assignment(kp->k_keys); X X if (saccumulator[0] == NULL) X strl_acc_assign("nothing", 7); X return 0; X} Xfind_assignment(cpp) Xregister char **cpp; X{ char buf[BUFSIZ]; X char *sp; X short key; X char *str1 = get_str(1); X X strcpy(buf, saccumulator); X sp = buf + strlen(buf); X X for (key = 0; key < NKEYS; key++, cpp++) { X if (*cpp && strcmp(*cpp, str1) == 0) { X if (sp != buf) { X strcpy(sp, "<-also>"); X sp += 7; X } X strcpy(sp, aitokey(key)); X sp += strlen(sp); X } X } X strl_acc_assign(buf); X} X# undef PLUS X# undef MINUS X# define CTRL 0x0100 X# define SHIFT 0x0200 X# define ALT 0x0400 X# define KEYPAD 0x0800 X X# define ALL (CTRL|SHIFT|ALT|KEYPAD) X X# define UP 210 X# define DOWN 204 X# define LEFT 206 X# define RIGHT 208 X# define HOME 209 X# define END 203 X# define PGUP 211 X# define PGDN 205 X# define STAR 42 X# define MINUS 169 X# define PLUS 168 X# define DEL 152 X# define INS KEY_0 X/* X# define F1 128 X# define F2 129 X# define F3 130 X# define F4 131 X# define F5 132 X# define F6 133 X# define F7 134 X# define F8 135 X# define F9 136 X# define F10 137 X*/ X# define F11 138 X# define F12 139 X# define BACKSPACE 8 X# define ENTER '\r' Xstruct map { X int len; X char *name; X short value; X }; Xstruct map special[] = { X {0, "<Ctrl-Home>", 223}, X {0, "<Ctrl-End>", 217}, X {0, "<Ctrl-PgUp>", 225}, X {0, "<Ctrl-PgDn>", 219}, X {0, "<Ctrl-Left arrow>", 220}, X {0, "<Ctrl-Right arrow>", 222}, X {0, "<Ins>", KEY_0}, X {0, "<Del>", 212}, X {0, "<Delete>", 127}, X {0, "<Keypad-plus>", 213}, X {0, "<Keypad-minus>", 214}, X {0, "<Keypad-star>", 215}, X {0} X }; X Xstruct map stoi[] = { X {3, "ESC", 0x1b}, X {1, "{", '{'}, X {1, "}", '}'}, X {5, "SPACE", ' '}, X {5, "ENTER", ENTER}, X {3, "TAB", 0x09}, X {5, "ARROW", 0}, X {4, "CTRL", CTRL}, X {5, "SHIFT", SHIFT}, X {3, "ALT", ALT}, X {6, "KEYPAD", KEYPAD}, X {4, "GREY", KEYPAD}, X {2, "UP", UP}, X {4, "DOWN", DOWN}, X {4, "LEFT", LEFT}, X {5, "RIGHT", RIGHT}, X {4, "HOME", HOME}, X {3, "END", END}, X {4, "PGUP", PGUP}, X {4, "PGDN", PGDN}, X {4, "STAR", STAR}, X {5, "MINUS", MINUS}, X {4, "PLUS", PLUS}, X {3, "DEL", DEL}, X {3, "INS", INS}, X {3, "F12", F12}, X {3, "F11", F11}, X {3, "F10", F10}, X {2, "F9", F9}, X {2, "F8", F8}, X {2, "F7", F7}, X {2, "F6", F6}, X {2, "F5", F5}, X {2, "F4", F4}, X {2, "F3", F3}, X {2, "F2", F2}, X {2, "F1", F1}, X {9, "BACKSPACE", BACKSPACE}, X 0 X }; Xchar * Xaitokey(key) Xshort key; X{ X struct map *mp; X static char buf[32]; X register char *cp; X int alpha_cnt = 0; X X if (key >= ALT_A && key <= ALT_Z) { X sprintf(buf, "<Alt-%c>", key - ALT_A + 'A'); X return buf; X } X if (key >= SHIFT_F1 && key <= SHIFT_F1+11) { X sprintf(buf, "<Shift-F%d>", key - SHIFT_F1 + 1); X return buf; X } X if (key >= CTRL_F1 && key <= CTRL_F1+11) { X sprintf(buf, "<Ctrl-F%d>", key - CTRL_F1 + 1); X return buf; X } X if (key >= ALT_F1 && key <= ALT_F1+11) { X sprintf(buf, "<Alt-F%d>", key - ALT_F1 + 1); X return buf; X } X if (key >= ALT_0 && key <= ALT_0+9) { X sprintf(buf, "<Alt-%d>", key - ALT_0); X return buf; X } X if (key == BACK_TAB) X return "<Shift-Tab>"; X X for (mp = special; mp->name; mp++) X if (mp->value == key) X return mp->name; X X for (mp = stoi; mp->name; mp++) X if (mp->value == (short) (key & 0xff)) { X sprintf(buf, "<%s>", mp->name); X for (cp = buf; *cp; cp++) X if (*cp >= 'A' && *cp <= 'Z') X if (alpha_cnt++) X *cp += 0x20; X return buf; X } X if (key < ' ') X sprintf(buf, "<Ctrl-%c>", key + 'A' - 1); X else X sprintf(buf, "#%d", key); X return buf; X} X Xnew_akeytoi(string) Xchar *string; X{ char str[80]; X register char *cp; X int flags = 0; X int ch; X register struct map *mp; X X strcpy(str, string+1); X for (cp = str; *cp; cp++) X if (islower(*cp)) X *cp = toupper(*cp); X X for (cp = str; *cp && *cp != '>'; ) { X if (*cp == ' ' || *cp == '-' || *cp == '\t') { X cp++; X continue; X } X for (mp = stoi; mp->name; mp++) X if (strncmp(mp->name, cp, mp->len) == 0) { X cp += mp->len; X flags |= mp->value; X break; X } X if (mp->name == 0) { X flags |= *cp; X break; X } X } X ch = flags & 0xff; X switch (flags & ALL) { X case 0: return ch; X case SHIFT: X if (ch >= F1 && ch <= F12) X return ch + 12; X if (ch >= 'A' && ch <= 'Z') X return ch - 0x20; X if (ch == UP || ch == DOWN || ch == LEFT || ch == RIGHT) X return 0; X if (ch == '\t') X return BACK_TAB; X if (isdigit(ch)) X return 0; X return ch; X case CTRL: X if (ch == ENTER) X return '\n'; X if (ch >= F1 && ch <= F12) X return ch + 24; X if (ch >= 'A' && ch <= 'Z') X return ch & 0x1f; X if (ch == UP || ch == DOWN || ch == LEFT || ch == RIGHT) X return ch + 14; X if (ch == '{' || ch == '}') X return 0; X if (isdigit(ch)) X return 0; X return ch; X case ALT: X if (ch >= F1 && ch <= F12) X return ch + 32; X if (ch >= 'A' && ch <= 'Z') X return (ch - 'A') + ALT_A; X if (isdigit(ch)) X return (ch - '0') + ALT_0; X return ch; X case KEYPAD: X switch (ch) { X case MINUS: return 214; X case PLUS: return 213; X default: X return 0; X } X case SHIFT|KEYPAD: X return 0; X } X ewprintf("Not decoded - %s", string); X return 0; X} SHAR_EOF chmod 0444 ./ttykbd.c || echo "restore of ./ttykbd.c fails" mkdir . >/dev/null 2>&1 echo "x - extracting ./undo.c (Text)" sed 's/^X//' << 'SHAR_EOF' > ./undo.c && X/************************************************************** X * X * CRISP - Custom Reduced Instruction Set Programmers Editor X * X * (C) Paul Fox, 1989 X * 43, Jerome Close Tel: +44 6284 4222 X * Marlow X * Bucks. X * England SL7 1TX X * X * X * Please See COPYRIGHT notice. X * X * Code to implement the undo and redo facilities. X **************************************************************/ X# include "list.h" XSCCSID("@(#) undo.c 1.14, (C) 1989, P. Fox"); Xstatic void re_goto(); Xstatic void u_write(); Xstatic undo_check(); X Xenum undo_opcodes { X GOTO = 0, X INSERT = 1, X DELETE = 2, X RAISE = 3, X DROP = 4, X SCRAP = 5, /* Operation should do an undo on the scrap */ X /* buffer. */ X }; X Xextern long ftell(); Xextern char *mktemp(); Xextern doing_selfinsert; Xstatic read_last_undo(); Xstatic int undoing_scrap = FALSE; /* If TRUE stops us printing */ X /* 'Undone.' twice. */ XFILE *ufp = NULL; Xenum undo_state { X NORMAL, X REDO, X UNDO X } undo_state = NORMAL; X Xstruct undo { X enum undo_opcodes u_opcode; X int u_line; X int u_col; X ANCHOR u_anchor; X RSIZE u_length; X long u_last1; /* Used for backing up over (write_buffer) */ X /* mark. */ X long u_last; /* tell() position of previous undo */ X int u_chain; /* Non-zero if part of a single */ X /* undo. */ X }; Xchar *u_fname; Xint u_atend = FALSE; /* If TRUE dont fseek to eof. */ Xvoid Xu_init() X{ char temp_file[64]; X char *get_tmpdir(); X char *sys_delim(); X X sprintf(temp_file, "%s%sundoXXXXXX", get_tmpdir(), sys_delim()); X u_fname = mktemp(temp_file); X X if ((ufp = fopen(u_fname, "w+")) == NULL) { X printf("Cannot create undo file:\n"); X perror(u_fname); X gr_exit(); X } X /*-------------------------*/ X /* Ensure ftell(ufp) != 0) */ X /*-------------------------*/ X fwrite("Undo", 4, 1, ufp); X unlink(u_fname); X} Xchar * Xget_tmpdir() X{ extern char *ggetenv(); X char *cp; X X if ((cp = ggetenv("BTMP")) != NULL) X return cp; X if ((cp = ggetenv("TMP")) != NULL) X return cp; X# if defined(VMS) X return "[-]"; X# else X return "/tmp"; X# endif X} Xvoid Xu_close() X{ X if (ufp) X unlink(u_fname); X} Xvoid Xu_insert(n) XRSIZE n; X{ register LINE *clp; X register int cbo; X register int line; X struct undo undo_buf; X X if (n == 0 || undo_check()) X return; X X if (undo_state == NORMAL) X curbp->b_nummod++; X undo_buf.u_opcode = INSERT; X undo_buf.u_length = n; X X u_write(&undo_buf); X X line = *cur_line; X cbo = current_offset(*cur_col, FALSE); X for ( ; line < curbp->b_numlines && n > 0; line++, cbo = 0) { X RSIZE x,w; X clp = vm_lock_line(line); X x = llength(clp) - cbo; X w = x; X if (x >= n) X w = n; X fwrite(<ext(clp)[cbo], (int) w, 1, ufp); X vm_unlock(line); X if (n -= w) { X fputc('\n', ufp); X n--; X } X } X X X} Xvoid Xu_delete(n) XRSIZE n; X{ struct undo undo_buf1; X struct undo undo_buf; X undo_info *up; X X if (n == 0 || undo_check()) X return; X up = undo_state == UNDO ? &curbp->b_redo : &curbp->b_undo; X if (doing_selfinsert && up->u_last) { X if (read_last_undo(&undo_buf1, up)) X goto normal; X if (undo_buf1.u_opcode == DELETE) { X extern char character; X# ifdef DEBUG X {char buf[128]; X extern int dflag; X if (dflag & DB_UNDO) { X sprintf(buf, X "undo(COLLAPSING, %d + %d => %d)\n", X undo_buf1.u_length, n, X undo_buf1.u_length + n); X trace_log(buf, (char *) NULL); X } X } X# endif X if ((isalnum(curbp->b_uchar) && isalnum(character)) || X (isspace(curbp->b_uchar) && isspace(character)) || X (curbp->b_uchar == 0x1B || character == 0x1B) || X (ispunct(curbp->b_uchar) && ispunct(character))) { X undo_buf1.u_length += n; X if (!u_atend) X fseek(ufp, up->u_last, 0); X fwrite((char *) &undo_buf1, sizeof undo_buf1, 1, ufp); X fseek(ufp, 0l, 2); X u_atend = TRUE; X return; X } X } X } Xnormal: X if (undo_state == NORMAL) X curbp->b_nummod++; X undo_buf.u_opcode = DELETE; X undo_buf.u_length = n; X u_write(&undo_buf); X X} Xvoid Xu_chain() X{ extern int playing_back; X if (!playing_back) { X curbp->b_undo.u_chain = 0; X curbp->b_redo.u_chain = 0; X } X} Xvoid Xu_terminate() X{ X undo_info *up = undo_state == NORMAL ? &curbp->b_undo : &curbp->b_redo; X X up->u_last1 = up->u_last; X up->u_last = 0; X} Xvoid Xu_dot() X{ struct undo undo_buf; X X if (undo_check()) X return; X undo_buf.u_opcode = GOTO; X u_write(&undo_buf); X} X Xvoid Xu_raise() X{ struct undo undo_buf; X if (undo_check()) X return; X undo_buf.u_opcode = RAISE; X u_write(&undo_buf); X} Xvoid Xu_drop() X{ struct undo undo_buf; X X if (undo_check()) X return; X X undo_buf.u_opcode = DROP; X X undo_buf.u_anchor = *curbp->b_anchor; X u_write(&undo_buf); X} Xvoid Xu_scrap() X{ struct undo undo_buf; X X if (undo_check()) X return; X undo_buf.u_opcode = SCRAP; X u_write(&undo_buf); X X} X/* Undo utility routines. */ Xstatic Xundo_check() X{ X if (/*undo_state == REDO || */curbp->b_system || ufp == NULL) X return TRUE; X /*---------------------------------------- X /* If user isn't undoing an undo X /* then terminate the redo chain so we X /* dont confuse user. X /*----------------------------------------*/ X if (undo_state == NORMAL) X curbp->b_redo.u_last = 0; X return FALSE; X} Xstatic void Xu_write(undop) Xstruct undo *undop; X{ undo_info *up; X X if (undo_state == UNDO) X up = &curbp->b_redo; X else X up = &curbp->b_undo; X X undop->u_line = *cur_line; X undop->u_col = *cur_col; X undop->u_last1 = up->u_last1; X undop->u_last = up->u_last; X undop->u_chain = up->u_chain++; X if (!u_atend) X fseek(ufp, 0l, 2); X up->u_last = ftell(ufp); X X u_debug(undop, undo_state == NORMAL ? "normal" : X undo_state == UNDO ? "undo" : "redo"); X fwrite((char *) undop, sizeof *undop, 1, ufp); X u_atend = TRUE; X} Xu_debug(undop, str) Xstruct undo *undop; Xchar *str; X{ X# ifdef DEBUG X char buf[128]; X extern int dflag; X if (dflag & DB_UNDO) { X sprintf(buf, X "%s(%s, line=%d, col=%d, len=%ld, last=%08lx, chain=%d)\n", str, X undop->u_opcode == GOTO ? "GOTO" : X undop->u_opcode == INSERT ? "INSERT" : X undop->u_opcode == DELETE ? "DELETE" : X undop->u_opcode == RAISE ? "RAISE" : X undop->u_opcode == DROP ? "DROP" : X undop->u_opcode == SCRAP ? "SCRAP" : "??", X undop->u_line, undop->u_col, X undop->u_length, undop->u_last, undop->u_chain); X trace_log(buf, (char *) NULL); X } X# endif X} Xundo() X{ int undo_mod = argv[1].l_flags == F_INT ? argv[1].l_int : 0; X int past_mark = argv[2].l_flags == F_INT ? argv[2].l_int : 0; X long num = -1; X static int sub_undo(); X struct undo undo_buf; X enum undo_state saved_undo_state = undo_state; X int redo = argv[3].l_flags == F_INT; X undo_info *up = redo ? &curbp->b_redo : &curbp->b_undo; Xtrace_log(redo ? "doing redo\n" : "doing undo\n", (char *) NULL); X if (up->u_last == 0 && past_mark) { X up->u_last = up->u_last1; X up->u_last1 = 0; X } X undo_state = redo ? REDO : UNDO; X do { X if (sub_undo(&undo_buf, redo, up)) { X undo_state = NORMAL; X return; X } X if (num < 0 && undo_buf.u_chain > 2) X ewprintf("Undoing command..."); X if (num < 0) X num = undo_buf.u_chain; X else if (num && undo_buf.u_chain) X percentage(num - undo_buf.u_chain, num, "Undoing", "command"); X if (undo_mod && X (undo_buf.u_opcode != INSERT && X undo_buf.u_opcode != DELETE)) X undo_buf.u_chain = 1; X } X while (undo_buf.u_chain); X undo_state = saved_undo_state; X if (!undoing_scrap) X ewprintf(redo ? "Redone." : "Undone."); X return; X} Xstatic Xsub_undo(undop, redo, up) Xstruct undo *undop; Xundo_info *up; X{ long pos; X char buf[64]; X int n; X X if (up->u_last == 0) { X ewprintf("Nothing to %s.", redo ? "redo" : "undo"); X curbp->b_flag &= ~BFCHG; X return -1; X } X if (read_last_undo(undop, up)) X return -1; X u_debug(undop, "UNDOING"); X up->u_last = undop->u_last; X up->u_last1 = undop->u_last1; X switch (undop->u_opcode) { X case INSERT: SHAR_EOF echo "End of part 10" echo "File ./undo.c is continued in part 11" echo "11" > s2_seq_.tmp exit 0 -- ===================== Reuters Ltd PLC, Tel: +44 628 891313 x. 212 Westthorpe House, UUCP: fox%marlow.uucp@idec.stc.co.uk Little Marlow, Bucks, England SL7 3RQ