/* 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_chario.c character I/O routines 02/05/91 21.45 */ /* 8-bit version 04/18/91 10.02 */ /* modified for real ctrl/break trap 09/16/91 08.00 */ #include #include #include #include #include "te_defs.h" #define CTL_BRK 0x1b static short lf_sw; /* nonzero: make up a LF following an entered CR */ short inp_noterm = 0; /* nonzero if standard input is not a terminal */ short out_noterm = 0; /* nonzero if standard output is not a terminal */ void out_char(unsigned char c); static void stdout_char(unsigned char); /* routine for writing to std out */ void (*output_ptr)(unsigned char) = out_char; /* output routine pointer */ static unsigned char get_keyboard_shift(void); /* set up ctrl/break handler, determine whether stdin and/or stdout have been */ /* remapped, etc. TTY_ON & TTY_OFF called at program entrance and exit, while */ /* TTY_SUSPEND and TTY_RESUME surround system calls (EQ). */ static void (_interrupt _far *old_vec)(void); static void _interrupt _far _loadds int_handler(void); void setup_tty(short arg) { static long mouse_status = 0L; /* save mouse over "suspend" */ switch (arg) { case TTY_ON: /* initial call */ if (inp_noterm = (isatty(fileno(stdin)) == 0)) et_val |= ET_INP_REDIR; if (out_noterm = (isatty(fileno(stdout)) == 0)) et_val |= ET_OUT_REDIR; goto grab_interrupt; case TTY_RESUME: /* resume after suspension */ if (mouse_status > 0) /* redisplay mouse if enabled */ (void) setup_mouse(mouse_status); grab_interrupt: old_vec = _dos_getvect(CTL_BRK); /* save Ctl/Brk handler */ _dos_setvect(CTL_BRK, int_handler); /* and substitute ours */ break; case TTY_SUSP: /* suspend for system call */ mouse_status = fm_ctrl; /* disable and hide mouse */ if (mouse_status > 0) (void) setup_mouse(0L); goto restore_interrupt; case TTY_OFF: /* exit */ out_flush(); /* force out last screen output */ if (fm_ctrl != 0) reset_mouse(); /* reset mouse */ restore_interrupt: _dos_setvect(CTL_BRK, old_vec); /* restore theirs */ break; } } /* routines to handle keyboard input */ /* normal routine to get a character */ static short stdin_esc_count = 2; short gettty() { unsigned short c, cc; if (lf_sw) { lf_sw = 0; return(LF); /* if switch set, make up a line feed */ } if (inp_noterm) /* redirection: use stdin */ { if ((c = getchar()) == CR) ++lf_sw; else if (c == EOF) { if (stdin_esc_count-- > 0) c = 033; /* first two ESCs are free */ else ERROR(E_EFI); /* end-of-file from standard input */ } } else /* use keyboard */ { out_flush(); for(; ;) /* wait for character, or mouse event */ { if (fm_ctrl <= 0 || _bios_keybrd(_NKEYBRD_READY)) /* if char present or mouse not active */ { cc = _bios_keybrd(_NKEYBRD_READ); /* read character, (or wait if mouse not active) */ c = cc & 0xff; /* trim scan code */ if (c == 0377) continue; /* skip ctrl/break code */ if (c == 0 || c == 0340) /* if special, keep scan code, mark spcl shift code & flags */ c = (cc >> 8) | (get_keyboard_shift() << 9) | (c == 0340 ? 0x1100 : 0x100); if (c == CR) ++lf_sw; /* CR: set switch to make up a LF */ break; } if (mouse_event_flag != 0) /* mouse interrupt */ { mouse_event_flag = 0; if ((c = do_mouse_event()) != 0) /* return mouse character */ { c |= (get_keyboard_shift() << 9) | 0x100; /* add shift bits */ break; } } } } return ( (short) c); } /* routine to get a character without waiting, used by ^T when ET & 64 is set */ /* if lf_sw is nonzero, return the LF; else use the FNDELAY fcntl to inquire of the input */ /* if input is not a terminal don't switch modes */ short gettty_nowait() { unsigned short c; short gettty(); if (inp_noterm) c = gettty(); /* redirected input - use stdin via gettty */ else if (lf_sw) { lf_sw = 0; return(LF); /* LF to be sent: return it */ } else /* use keyboard */ { out_flush(); if (!_bios_keybrd(_NKEYBRD_READY)) c = (EOF); /* if no term, or char wtg */ else c = (gettty()); /* char waiting: read it */ if (c == CR) ++lf_sw; } return (c); } /* routine to handle interrupt signal */ #pragma check_stack(off) void _interrupt _far _loadds int_handler(void) { if (exitflag <= 0) /* if executing commands */ { if (et_val & ET_CTRLC) et_val &= ~ET_CTRLC; /* if "trap ^C" set, clear it and ignore */ else exitflag = -2; /* else set flag to stop execution */ redraw_sw = 1; } } #pragma check_stack() /* routine to type one character */ void type_char(unsigned char c) { if (et_val & (ET_GRAPH | ET_OUT_REDIR)) output_ptr = stdout_char; if ((char_count >= WN_width) && (c != CR) && !(spec_chars[c] & A_L)) /* spacing char beyond end of line */ { if (et_val & ET_TRUNC) return; /* truncate output to line width */ else crlf(); /* otherwise do automatic new line (note recursive call to type_char) */ } if ((c & char_mask & 0340) == 0) /* control char? */ { switch (c & char_mask) { case CR: (*output_ptr)(c); char_count = 0; break; case LF: (*output_ptr)(c); break; case ESC: if ((et_val & ET_IMAGE) && !exitflag) (*output_ptr)(c); else { (*output_ptr)('$'); char_count++; } break; case TAB: if ((et_val & ET_IMAGE) && !exitflag) (*output_ptr)(c); else for (type_char(' '); (char_count & tabmask) != 0; type_char(' ')); break; default: if ((et_val & ET_IMAGE) && !exitflag) (*output_ptr)(c); else { (*output_ptr)('^'); (*output_ptr)((unsigned char)(c + 'A'-1)); char_count += 2; } break; } } else { (*output_ptr)(c); char_count++; } } /* routine to get keyboard shift/alt/ctrl status */ /* returns 0 if none down, 1 (shift bit), 2 (ctrl bit), 4 (alt bit) */ unsigned char kbd_shifts[16] = /* convert kbd flags to ret'd value */ { 0, 1, 1, 1, 2, 3, 3, 3, 4, 5, 5, 5, 6, 7, 7, 7 } ; static unsigned char get_keyboard_shift(void) { union REGS r; unsigned char return_val; r.h.ah = 0x12; /* use int 16 call */ int86(0x16, &r, &r); return(kbd_shifts[r.h.al & 0x0f]); } /* type a crlf */ void crlf(void) { type_char(CR); type_char(LF); } /* write a character to std output */ void stdout_char(unsigned char c) { putchar(c); }