/************************************************************************ * This program is Copyright (C) 1986 by Jonathan Payne. JOVE is * * provided to you without charge, and with no warranty. You may give * * away copies of JOVE, including sources, provided that this notice is * * included in all the files. * ************************************************************************/ /*+++* * title: msdos.c * abstract: MS-DOS/MSC specific stuff for JOVE * author: T.R.Hageman and G.C.Th.Wierda, Groningen, The Netherlands. * created: september 1989 * modified: october 1989 * 15-Feb-90, add COLOR option; interchange Fn and kn keys. * 22-Feb-90, add VIDEO option to avoid ANSI.SYS * 26-Feb-90, interchange K2 and K3 to follow terminfo def. * 5-Mar-90, debug and optimize VIDEO; make sure ctrl-C check * is off while in JOVE. * 12-Jun-90, add (Microsoft) Mouse and EGA/VGA >25 line support. * 18-Nov-90, add [\/] dir.sep support. * 13-Feb-91, add national keyboard support. * 12-May-91, revise I/O redirection in ShellToBuf * 26-Jun-91, replace ShellToBuf with UnixToBuf to let proc.c * handle the system-independent part. * 01-Aug-91, redefine F10 as "k;" instead of "k0" * 06-Nov-91, save & restore cursor shape. * 19-Mar-92, finish Turbo C port; kludge mouse support in * 43/50 line mode; add DIRECT_VIDEO support. * 26-Mar-92, add SELECTABLE code page support. * 04-Jun-92, add "screen-wide" mode. (VGA only) * description: * this file complements jove.c, proc.c, misc.c and tty.c * and completely replaces fkeys.c and term.c *---*/ #include "tune.h" #ifdef MSDOS /* the rest of this file */ RCS("$Id: msdos.c,v 14.32.0.8 1993/11/06 00:54:07 tom Exp tom $") #include "jove.h" #include "ctype.h" #include "io.h" #include "process.h" #include "screen.h" #include "termcap.h" #include #include #include #ifdef __TURBOC__ unsigned _stklen = 16384; # define Bconin() bioskey(0) # define Bconstat() bioskey(1) # define Kbshift() bioskey(2) #else /* MSC */ # include # define Bconin() _bios_keybrd(_KEYBRD_READ) # define Bconstat() _bios_keybrd(_KEYBRD_READY) # define Kbshift() _bios_keybrd(_KEYBRD_SHIFTSTATUS) #endif #define K_RSHIFT 0x01 #define K_LSHIFT 0x02 #define K_CTRL 0x04 #define K_ALT 0x08 #define K_CAPS 0x40 #define K_SHIFT (K_LSHIFT|K_RSHIFT) #define CALLDOS(i) (regs.h.ah=(i), intdos(®s,®s)) #define CALLDOSx(i) (regs.h.ah=(i), intdosx(®s,®s,&sregs)) #ifndef FP_OFF # define FP_OFF(p) ((unsigned)(p)) #endif /* the next only work in LARGE memory model */ #ifndef FP_SEG # define FP_SEG(p) ((unsigned)((unsigned long)(void far *)(p) >> 16)) #endif #ifndef MK_FP # define MK_FP(seg,off) ((void *)((unsigned long)(seg)<<16|(unsigned)(off))) #endif private union REGS regs; private struct SREGS sregs; #define Crawio(c) (regs.h.dl=(c), CALLDOS(0x6)) private char EGA_present ZERO; #ifdef RESHAPING /* EGA/VGA font switch */ private unsigned org_video_mode; private void set_video_mode __(( unsigned _(mode) )); private unsigned get_video_mode __(( void )); private void font_setup __(( void )); # define FONT_INIT() (org_video_mode = get_video_mode()) # define FONT_EXIT() do { \ if (get_video_mode() != org_video_mode) { \ set_video_mode(org_video_mode), \ ttsize(), curstoLL(), printf("\n"); \ } \ } while (0) #else # define FONT_INIT() # define font_setup() # define FONT_EXIT() #endif /* DOS does not restore the current directory on process exit... */ private const char *org_cwd; /* * DOS video interrupt definitions. */ #define VID_INTR 0x10 #define VID_SET_MODE 0x0 #define VID_SELECT_CURSOR 0x1 #define VID_SET_CURSOR 0x2 #define VID_GET_CURSOR 0x3 #define VID_SET_PAGE 0x5 #define VID_UP_SCROLL 0x6 #define VID_DOWN_SCROLL 0x7 #define VID_GET_CHAR_AND_ATTR 0x8 #define VID_SET_CHAR_AND_ATTR 0x9 #define VID_SET_CHAR 0xA #define VID_DUMB_CHAR 0xE #define VID_GET_MODE 0xF #define VID_X_ERASE (VID_UP_SCROLL<<8) /* assign to AX */ /* (S)VGA extended video modes (for Tulips at least; general I hope.) */ #define VGA_132x43_COLOR 84 #define VGA_132x25_COLOR 85 #define VGA_132x43_MONO 86 #define VGA_132x25_MONO 87 /*======================================================================*/ /* TERM.C */ /*======================================================================*/ /* * Hardwired terminal capabilities, so we don't need termcap database */ void getTERM() { char *term = getenv("TERM"); if (term == NULL) term = "msdos"; TermName = term; MetaKey = ESC; IDline_setup(term); #ifdef COLOR /* Provide a suitable default for "use-color" variable. The real monochrome modes just ignore color, but monochrome emulations do not. So these shouldn't use color mode by default. */ regs.h.ah = VID_GET_MODE; int86(VID_INTR, ®s, ®s); switch (regs.h.al) { case 0: case 2: break; default: UseColor++; } #endif #ifdef VIDEO { void PC_video_init __(( void )); PC_video_init(); } #else /* !VIDEO */ /* check whether ANSI.SYS is installed */ regs.x.ax = 0x0c00, intdos(®s, ®s); /* flush input buffer */ write(1, "\033[6n", sizeof "\033[6n" - 1); /* send Device Status request */ /* if installed, Cursor Position Report is available immediately */ if ((char) Crawio(0xff) != ESC) { printf("\rPlease install ANSI.SYS first.\r\n"); _exit(1); } while ((char) Crawio(0xff) != 'R') /* eat CPR = "ESC[#;#R" */ ; #endif /* VIDEO */ FONT_INIT(); org_cwd = copystr(getwd(genbuf)); _fmode = O_BINARY; } /*======================================================================*/ /* SCREEN.C */ /*======================================================================*/ #ifdef COLOR #define PC_BLACK 0 #define PC_BLUE 1 #define PC_GREEN 2 #define PC_CYAN 3 #define PC_RED 4 #define PC_MAGENTA 5 #define PC_YELLOW 6 #define PC_WHITE 7 private const char colormap[] = { /* ANSI -> DOS color map */ PC_BLACK, PC_RED, PC_GREEN, PC_YELLOW, PC_BLUE, PC_MAGENTA, PC_CYAN, PC_WHITE }; #endif /* ANSI attribute definitions */ #define ANSI_CLEARALL 0 #define ANSI_BOLD 1 #define ANSI_UNDERLINE 4 #define ANSI_BLINK 5 #define ANSI_REVERSE 7 #define ANSI_INVIS 8 #define ANSI_FG(i) (30+i) #define ANSI_BG(i) (40+i) /* PC attribute definitions */ #define PC_BOLD 0x08 #define PC_BLINK 0x80 #define PC_UNDERLINE 0x40 /* monochrome only */ #define PC_FG_MASK 0x07 #define PC_BG_MASK 0x70 #define PC_BG_SHIFT 4 #define PC_REVERSE 0x70 #define PC_NORMAL 0x07 /* default attribute; white on black */ #if ((VIDEO - 0) & 1) # define DIRECT_VIDEO /* for memory-mapped Video */ #endif #define DV_CSPEED (4 * CSPEED) /* rough estimate */ DEF_INT( "use-direct-video", use_direct_video, V_BOOL|V_TTY_RESET) _IF(def MSDOS)_IF(def PRIVATE) #ifdef DIRECT_VIDEO = YES; #else ZERO; #endif #ifdef VIDEO /* emulation of minimal ANSI.SYS */ #if ((VIDEO - 0) & 2) # define FULL /* if you want full implementation */ #endif #ifdef FULL # define MAX_ESC_ARGS 6 /* should be enough... */ #else # define MAX_ESC_ARGS 2 /* minimal version */ #endif private int esc_arg[MAX_ESC_ARGS+1], /* esc_args[0] used as accumulator */ esc_state; /* * escape state: * = 0 outside escape sequence, * > 0 getting argument (index into esc_args), * < 0 intermediate states. */ #define NO_ESC_SEEN 0 #define ESC_SEEN -1 #define ESC_BRACKET_SEEN -2 private char qe_seen; /* set if "ESC [ =" or "ESC [ ?" seen */ private char cursor_invisible; /* true if cursor is "invisible" */ private int org_cursor_type; /* saved on startup, restored on exit */ #ifdef DIRECT_VIDEO private char *VideoBase; #endif private union REGS vregs; #define Vchar vregs.h.al #define Vattr vregs.h.bl #define Vpage vregs.h.bh #define Vcount vregs.x.cx #define Vpos vregs.x.dx #define Vcol vregs.h.dl #define Vrow vregs.h.dh #define Video(code) (vregs.h.ah = code, \ int86(VID_INTR, &vregs, ®s)) #define Ring() (Vchar = '\7', Video(VID_DUMB_CHAR)) #define ClrEol() { \ regs.x.ax = VID_X_ERASE; /* erase */ \ regs.x.cx = Vpos; /* ...from cursor */ \ regs.h.dh = Vrow; \ regs.h.dl = CO-1; /* ...to EOL */ \ regs.h.bh = Vattr; /* ...with current attribute */ \ int86(VID_INTR, ®s, ®s); \ } #define ClrEos() { \ regs.x.ax = VID_X_ERASE; /* erase */ \ regs.x.cx = 0; /* ...from HOME */ \ regs.h.dh = ILI; \ regs.h.dl = CO-1; /* ...to EOL */ \ regs.h.bh = Vattr; /* ...with current attribute */ \ int86(VID_INTR, ®s, ®s); \ Vpos = 0; /* home cursor */ \ } #define CurAbs(row, col) { \ if ((Vrow = row) > ILI) Vrow = ILI; \ if ((Vcol = col) >= CO) Vcol = CO-1; \ } #define CurRight(i) { \ if ((Vcol += i) >= CO) Vcol = CO-1; \ } #define CurLeft(i) { \ if ((signed)(Vcol -= i) < 0) Vcol = 0; \ } #define CurUp(i) { \ if ((signed)(Vrow -= i) < 0) Vrow = 0; \ } #define CurDown(i) { \ if ((Vrow += i) > ILI) Vrow = ILI; \ } #ifdef FULL private int saved_Vpos; #define CurSave() (saved_Vpos = Vpos) #define CurRestore() (Vpos = saved_Vpos) #endif /* FULL */ private char cursor_height = 8; private void SetModes __(( int _(on) )); private void SetModes(on) { if (esc_arg[1] < 7) { vregs.h.al = esc_arg[1]; Video(VID_SET_MODE); } else if (esc_arg[1] == 25) { /* EXTENSION: cursor control */ vregs.x.cx = (cursor_invisible = !on) ? 0x2000 : 0x0000-1 + cursor_height; Video(VID_SELECT_CURSOR); } } private void SetAttrib __(( void )); private void SetAttrib() { #ifdef COLOR static char reversed; #endif register int attr = Vattr; register int i = 0; while (++i < esc_state) switch (esc_arg[i]) { case ANSI_CLEARALL: #ifdef COLOR if (reversed) { reversed = 0; attr = (((attr << PC_BG_SHIFT) & PC_BG_MASK) | ((attr >> PC_BG_SHIFT) & PC_FG_MASK)); } else { attr &= (PC_BG_MASK | PC_FG_MASK); } #else attr = PC_NORMAL; #endif continue; case ANSI_REVERSE: #ifdef COLOR if (reversed) continue; reversed = 1; attr = (attr & ~(PC_FG_MASK|PC_BG_MASK)) | ((attr << PC_BG_SHIFT) & PC_BG_MASK) | ((attr >> PC_BG_SHIFT) & PC_FG_MASK); #else attr = PC_REVERSE; #endif continue; case ANSI_BOLD: attr |= PC_BOLD; continue; #ifdef FULL case ANSI_UNDERLINE: attr |= PC_UNDERLINE; continue; case ANSI_BLINK: attr |= PC_BLINK; continue; case ANSI_INVIS: /* set FG color to BG color */ attr = (attr & ~PC_FG_MASK) | ((attr >> PC_BG_SHIFT) & PC_FG_MASK); continue; #endif #ifdef COLOR case ANSI_FG(0): case ANSI_FG(1): case ANSI_FG(2): case ANSI_FG(3): case ANSI_FG(4): case ANSI_FG(5): case ANSI_FG(6): case ANSI_FG(7): if (reversed) { attr &= ~PC_BG_MASK; attr |= colormap[esc_arg[i] - ANSI_FG(0)] << PC_BG_SHIFT; } else { attr &= ~PC_FG_MASK; attr |= colormap[esc_arg[i] - ANSI_FG(0)]; } continue; case ANSI_BG(0): case ANSI_BG(1): case ANSI_BG(2): case ANSI_BG(3): case ANSI_BG(4): case ANSI_BG(5): case ANSI_BG(6): case ANSI_BG(7): if (reversed) { attr &= ~PC_FG_MASK; attr |= colormap[esc_arg[i] - ANSI_BG(0)]; } else { attr &= ~PC_BG_MASK; attr |= colormap[esc_arg[i] - ANSI_BG(0)] << PC_BG_SHIFT; } continue; #endif } Vattr = attr; } /* initialize */ private char vid_initialized; void PC_video_init() { Video(VID_GET_MODE); Vpos = regs.x.dx; /* cursor position */ Vpage = regs.h.bh; /* video page */ Vattr = PC_NORMAL; /* normal video */ Video(VID_GET_CURSOR); org_cursor_type = regs.x.cx; /* save cursor shape */ #ifdef DIRECT_VIDEO use_direct_video = YES; /* .joverc can turn it off */ #endif vid_initialized = TRUE; } ssize_t write(fd, buf, nbytes) int fd; const void *buf; size_t nbytes; { /* "normal" files are just written out */ if (fd != 1 || !vid_initialized) { #ifdef __TURBOC__ return _write(fd, buf, nbytes); #else /* MSC */ long st; if ((st = _dos_write(fd, buf, nbytes, &nbytes)) < 0) { errno = st; return -1; } return nbytes; #endif } { /* screen output is handled specially */ register const char *p = buf; register const char *end = p + nbytes; /* * We can be left off in the middle of an escape sequence. * The switch brings us back to the "right" place in the loop. */ switch (esc_state) { case NO_ESC_SEEN: for (; p < end; p++) { switch (Vchar = *p) { default: #ifdef DIRECT_VIDEO if (use_direct_video) { register char *vp = VideoBase; const char *base = p; vp += (Vrow * CO + Vcol) << 1; do { *vp++ = *p++; *vp++ = Vattr; } while (p < end && !isctrl(*p)); CurRight(p - base); --p; continue; } #endif Vcount = 1; while (++p < end && *p == Vchar) Vcount++; --p; Video(VID_SET_CURSOR); Video(VID_SET_CHAR_AND_ATTR); CurRight(Vcount); continue; case '\b': CurLeft(1); continue; case '\t': CurRight(8 - (Vcol & 7)); continue; case '\r': Vcol = 0; continue; case '\n': if (Vrow < ILI) { ++Vrow; continue; } /* else scroll screen up */ Video(VID_SET_CURSOR); case '\7': Video(VID_DUMB_CHAR); continue; case ESC: break; } /* here we saw the escape... */ p++; esc_state = ESC_SEEN; case ESC_SEEN: if (p >= end) break; if (*p != '[') { Ring(); esc_state = NO_ESC_SEEN; continue; } p++; esc_state = ESC_BRACKET_SEEN; case ESC_BRACKET_SEEN: if (p >= end) break; qe_seen = 0; if (*p == '?' || *p == '=') p++, qe_seen++; esc_state = 1; do { esc_arg[0] = 0; default: while (p < end && isdigit(*p)) esc_arg[0] = esc_arg[0] * 10 + (*p++ - '0'); if (p >= end) break; if (esc_state <= MAX_ESC_ARGS) esc_arg[esc_state++] = esc_arg[0]; } while (*p == ';' && (p++, TRUE)); if (p >= end) break; /* now, handle the escape codes */ if (qe_seen) { if (*p == 'h') SetModes(1); else if (*p == 'l') SetModes(0); else Ring(); } else switch (*p) { #ifdef FULL case 'f': #endif case 'H': if (--esc_arg[1] < 0) esc_arg[1] = 0; if (esc_state <= 2 || --esc_arg[2] < 0) esc_arg[2] = 0; CurAbs(esc_arg[1], esc_arg[2]); break; case 'A': CurUp(esc_arg[1] ? esc_arg[1] : 1); break; #ifdef FULL case 'B': CurDown(esc_arg[1] ? esc_arg[1] : 1); break; case 'C': CurRight(esc_arg[1] ? esc_arg[1] : 1); break; case 'D': CurLeft(esc_arg[1] ? esc_arg[1] : 1); break; case 's': CurSave(); break; case 'u': CurRestore(); break; #endif /* FULL */ case 'm': SetAttrib(); break; case 'K': ClrEol(); break; case 'J': ClrEos(); break; default: Ring(); break; } /* switch (*p) */ esc_state = NO_ESC_SEEN; /* reset!! */ } /* for ( ; p < end; p++) */ } /* switch (esc_state) */ } /* * Currently we only use the "invisible" cursor flag to determine * whether we should update the hardware cursor or not. */ if (!cursor_invisible) Video(VID_SET_CURSOR); return nbytes; } #endif /* VIDEO */ #ifdef FAST_IDLINE #ifndef VIDEO # ifdef COLOR private char Vattr = PC_NORMAL; # else # define Vattr PC_NORMAL # endif #endif /* VIDEO */ private void PCins_line __(( int _(top), int _(bottom), int _(num) )); private void PCins_line(top, bottom, num) { flusho(); regs.h.ah = VID_DOWN_SCROLL; /* scroll window down */ regs.h.al = num; /* number of lines to scroll */ regs.h.bh = Vattr; /* default attribute */ regs.h.ch = top; /* upper left y */ regs.h.cl = 0; /* upper left x (always 0) */ regs.h.dh = bottom; /* lower right y */ regs.h.dl = CO-1; /* lower right x (always width of screen)*/ int86(VID_INTR, ®s, ®s); } private void PCdel_line __(( int _(top), int _(bottom), int _(num) )); private void PCdel_line(top, bottom, num) { flusho(); regs.h.ah = VID_UP_SCROLL; /* scroll window up */ regs.h.al = num; /* number of line to scroll */ regs.h.bh = Vattr; /* default attribute */ regs.h.ch = top; /* upper left y */ regs.h.cl = 0; /* upper left x (always 0) */ regs.h.dh = bottom; /* lower right y */ regs.h.dl = CO-1; /* lower right x (always width of screen)*/ int86(VID_INTR, ®s, ®s); } #pragma argsused void IDline_setup(tname) const char *tname; { TTins_line = PCins_line; TTdel_line = PCdel_line; ScrollLimit = 100; CanScroll = YES; } #endif /* FAST_IDLINE */ private char Monochrome = FALSE; #ifdef COLOR void set_color(color) { register int bg_color, fg_color; if (color == CurrColor) return; if (False(UseColor)) return; CurrColor = color; if (Monochrome) return; bg_color = BG_COLOR(color); fg_color = FG_COLOR(color); if (fg_color == bg_color) fg_color ^= WHITE; /* choose complementary color */ printf("\033[%d;%dm", ANSI_FG(fg_color), ANSI_BG(bg_color)); # ifdef FAST_IDLINE # ifndef VIDEO Vattr = colormap[fg_color] | (colormap[bg_color] << PC_BG_SHIFT); # endif # endif } #endif /* COLOR */ /*======================================================================*/ /* FKEYS.C */ /*======================================================================*/ /* * character codes >= 0200 are used to define function keys. */ enum FKEYS { ku=0200,kd, kr, kl, k0, k1, k2, k3, k4, k5, k6, k7, k8, k9, K1, K2, K3, K4, K5, kq, kF, kH, kI, kN, kP, kR, kh, F1, F2, F3, F4, F5, F6, F7, F8, F9, F0, kY, kt, kT, ka, kA, kz, kZ, k_, ML, MR }; /* * Key assignments: * * (M-X means Meta-X, i.e if MetaKey enabled, else ) * ([ ] means inactive key) * * FnKey Normal Shift Alt Ctrl * ----- ------ ----- --- ---- * F1 F2 k1 k2 F1 F2 M-k1 M-k2 M-F1 M-F2 * F3 F4 k3 k4 F3 F4 M-k3 M-k4 M-F3 M-F4 * F5 F6 k5 k6 F5 F6 M-k5 M-k6 M-F5 M-F6 * F7 F8 k7 k8 F7 F8 M-k7 M-k8 M-F7 M-F8 * F9 F10 k9 k; F9 F0 M-k9 M-k; M-F9 M-F0 * * Keypad ScanCodes Functions Normal Shift/NumLock * ------ --------- --------- ------ ------------- * NumLk(/) * [ ] (35)37 NumLk (/) * NumLk(/) * NumLk(/) kA * 7 8 9 - 47 48 49 4a Home ^ PgUp - kh ku kP - K1 kP K3 kF * 4 5 6 + 4b 4c 4d 4e <- [ ] -> + kl[ ] kr + kt K2 kT kR * 1 2 3 En- 4f 50 51 [ ] End v PgDn En- kH kd kN ^M K4 kN K5 ^M * 0 . ter 52 53 Ins Del ter kI ^? k0 ka * (vt100-keypad) * For AT keyboards only: * * Cursor Keypad Normal/Shift Ctrl * ------------- ------------ ---- * F11 F12 [ ] [ ] kq kY * Ins Home PgUp kI kh kP [ ] M-kh M-kP * Del End PgDn ^? kH kN [ ] M-kH M-kN * ^ ku [ ] * <- v -> kl kd kr M-kl [ ] M-kr * * Other Meta-keys - on main keyboard: * * Alt A .. Alt Z, Alt 0 .. Alt 9, Alt -, Alt = * * Shift and Ctrl don't affect these Meta-keys */ #define META 0x40 #define M(c) ((unsigned char)(c) | META) /* * The first table is used if ASCII code of key == 0. * Entries marked M are to simulate Alt (or Ctl in some cases) as Meta-key. * NOTE: for 'A'..'Z' META bit is also part of character itself. * This is corrected for in getchar(). {{admittedly a bit of a kludge...}} * * The second table is used if ASCII code != 0 AND "use_function-keys" is * enabled. This is to simulate a vt100 keypad with Shift/NumLock */ private /* deliberately non-const */ unsigned char FKeyTab0[] = { /*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*10*/ M('Q'), M('W'), M('E'), M('R'), M('T'), M('Y'), M('U'), M('I'), M('O'), M('P'), 0, 0, 0, 0, M('A'), M('S'), /*20*/ M('D'), M('F'), M('G'), M('H'), M('J'), M('K'), M('L'), 0, 0, 0, 0, 0, M('Z'), M('X'), M('C'), M('V'), /*30*/ M('B'), M('N'), M('M'), 0, 0, 0, 0, 0, 0, 0, 0, k1, k2, k3, k4, k5, /*40*/ k6, k7, k8, k9, k_, 0, 0, kh, ku, kP, kF, kl, 0, kr, kR, kH, /*50*/ kd, kN, kI, 0177, F1, F2, F3, F4, F5, F6, F7, F8, F9, F0, M(F1), M(F2), /*60*/ M(F3), M(F4), M(F5), M(F6), M(F7), M(F8), M(F9), M(F0), M(k1), M(k2), M(k3), M(k4), M(k5), M(k6), M(k7), M(k8), /*70*/ M(k9), M(k_), 0, M(kl), M(kr), M(kH), M(kN), M(kh), M('1'), M('2'), M('3'), M('4'), M('5'), M('6'), M('7'), M('8'), /*80*/ M('9'), M('0'), M('-'), M('='), M(kP), 0, 0, 0, 0, kq, kY }; private const unsigned char FKeyTab1[] = { /*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*30*/ 0, 0, 0, 0, 0, 0, 0, kA, 0, 0, 0, 0, 0, 0, 0, 0, /*40*/ 0, 0, 0, 0, 0, 0, 0, K1, kP, K3, kF, kt, K2, kT, kR, K4, /*50*/ kN, K5, k0, ka #if 0 /* * We can omit this tail since table 1 is used only when * ascii-value != 0; all keys above this have ascii-value 0. * (and bounds are checked in getchar() just in case...) */ , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*60*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*80*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 #endif }; /* * This is the function key name table. * All (macro) references to function keys are by these names, * to make it independent of the actual code of the function key * (which vary from machine to machine) * {{warning: the byte order in the XX macro is processor-dependent}} */ #define XX(a,b) (a|b<<8) short FKeyMap[NFKEYS] = { XX('k','u'), XX('k','d'), XX('k','r'), XX('k','l'), XX('k','0'), XX('k','1'), XX('k','2'), XX('k','3'), XX('k','4'), XX('k','5'), XX('k','6'), XX('k','7'), XX('k','8'), XX('k','9'), XX('K','1'), XX('K','2'), XX('K','3'), XX('K','4'), XX('K','5'), XX('k','q'), XX('k','F'), XX('k','H'), XX('k','I'), XX('k','N'), XX('k','P'), XX('k','R'), XX('k','h'), XX('F','1'), XX('F','2'), XX('F','3'), XX('F','4'), XX('F','5'), XX('F','6'), XX('F','7'), XX('F','8'), XX('F','9'), XX('F','0'), XX('k','Y'), XX('k','t'), XX('k','T'), XX('k','a'), XX('k','A'), XX('k','z'), XX('k','Z'), XX('k',';'), XX('M','L'), XX('M','R') }; /* * This is to adapt the function key table above for some "foreign" * keyboards. (fortunately the scancodes of [A-Z] are properly * emulated by the system's keyboard driver for German QWERTZ / * French AZERTY type keyboards.) * {{If MSDOS has some system-independent way to obtain either this * keyboard code or the actual scancode translation tables, please let * me know, since I am just a poor soul wandering in the harsh desert of * industry standards. For now, use the environment variable KEYB}} */ #define GET_KEYBOARD() (*(short *)getenv("KEYB")) #ifdef GET_KEYBOARD /* Not unless we found a way to get keyboard code! */ private const struct fkey_patch { char country[2]; unsigned char specials[2]; } LanguageSpecials[] = { /* 0x82 0x83 */ "BR", { M('\''), M('=') }, /* Brazil (??) */ "CZ", { M('='), M('\'') }, /* Czech(oslovakia) ( -)*/ "DK", { M('+'), M('\'') }, /* Denmark ( -) */ "FR", { M(')'), M('=') }, /* France */ "GR", { M('-'), M('\'') }, /* Germany (*-) */ "IT", { M('\''), M('=') }, /* Italy (-*) */ "LA", { M('\''), M('=') }, /* Latin-America (-*) */ "NL", { M('/'), M('\'') }, /* Netherlands ( -) */ "NO", { M('+'), M('\\') }, /* Poland ( -) */ "PO", { M('\''), M('<') }, /* Portugal (- ) */ "SF", { M('`'), M('^') }, /* Switzerland(French) (--) */ "SG", { M('`'), M('^') }, /* Switzerland(German) (--) */ "SL", { M('='), M('\'') }, /* (Czecho)Slovakia ( -) */ "SP", { M('\''), M('|') }, /* Spain (- )*/ "SU", { M('+'), M('\'') }, /* Finland ( -) */ "SV", { M('+'), M('\'') }, /* Sweden ( -) */ "YU", { M('\''), M('+') } /* Yugoslavia (- ) */ }; #define NSPECIALS (sizeof LanguageSpecials / sizeof LanguageSpecials[0]) #define LANG_INIT() \ { \ register const struct fkey_patch *lp = LanguageSpecials; \ register short country = GET_KEYBOARD(); \ do { \ if (*(short *)lp->country == country) { \ FKeyTab0[0x82] = lp->specials[0]; \ FKeyTab0[0x83] = lp->specials[1]; \ break; \ } \ } while (++lp < &LanguageSpecials[NSPECIALS]); \ } #else # define LANG_INIT() #endif /* mouse stuff */ #ifdef MOUSE #define DEF_CHAR_HEIGHT 8 #define DEF_CHAR_WIDTH 8 private char char_height = DEF_CHAR_HEIGHT, /* dimensions of char. cell */ char_width = DEF_CHAR_WIDTH; /* in pixels */ private char mouse_there; /* * Microsoft mouse system calls */ # define MOUSE_INTR 0x33 # define Mouse(code) (regs.x.ax=(code), int86(MOUSE_INTR, ®s, ®s)) /* * Since mouse cursor is centered after Mouse(0), we can determine * the character cell size here. However, some (most?) mouse drivers do not * recognize dense line mode, and always return the same values. * So we have to kludge around this. */ # define INIT_MOUSE() \ { \ if (mouse_there = Mouse(0)) { /* Mouse reset; */ \ Mouse(3), /* get mouse state */ \ char_width = (2 * regs.x.cx) / (CO - 1), \ char_height = (2 * regs.x.dx) / ILI; \ if ((CO / 2) * char_width != regs.x.cx) { \ char_width = DEF_CHAR_WIDTH; \ regs.x.cx = 0, \ regs.x.dx = CO * char_width - 1, \ Mouse(7); /* set hor. bounds */ \ } \ if ((LI / 2) * char_height != regs.x.dx) { \ char_height = DEF_CHAR_HEIGHT; \ regs.x.cx = 0, \ regs.x.dx = LI * char_height - 1, \ Mouse(8); /* set vert. bounds */ \ } \ regs.x.bx = 0, /* Software cursor */ \ regs.x.cx = 0x77ff, \ regs.x.dx = 0x7f00, /* bright inverted */ \ Mouse(10); /* set text cursor */ \ } \ } # define EXIT_MOUSE() mouseoff(); # define SHOW_MOUSE_CURSOR() { if (mouse_there) Mouse(1); } # define HIDE_MOUSE_CURSOR() { if (mouse_there) Mouse(2); } # define GET_MOUSE_STATE(B,X,Y) \ { \ if (!mouse_there) \ return 0; \ Mouse(3); \ *(B) = regs.x.bx; \ *(X) = regs.x.cx; \ *(Y) = regs.x.dx; \ } # define ALT_KEY_DEPRESSED() (Kbshift() & K_ALT) # define LEFT_BUTTON 1 # include "mouse.ci" #endif /* MOUSE */ /*======================================================================*/ /* TTY.C */ /*======================================================================*/ void ttsize() { LI = 25; regs.h.ah = VID_GET_MODE; /* get video mode and active page */ int86(VID_INTR, ®s, ®s); if (regs.h.al == 7 || regs.h.al == VGA_132x25_MONO || regs.h.al == VGA_132x43_MONO) { Monochrome = TRUE; } #if 0 /* to allow extended VGA modes... */ else if (regs.h.al > 3) { printf("\rText modes only\r\n"); flusho(); _exit(-1); } #endif CO = regs.h.ah; #ifdef VIDEO Vpage = regs.h.bh; #endif regs.h.ah = 0x12; /* check presence of EGA/VGA card */ regs.h.bl = 0x10; int86(VID_INTR, ®s, ®s); if (regs.h.bl != 0x10) { /* EGA/VGA present */ EGA_present = YES; if (!Monochrome && regs.h.bl == 0) Monochrome = TRUE; regs.x.ax = 0x1130; /* get textgen. info */ regs.h.bh = 0; int86(VID_INTR, ®s, ®s); LI = regs.h.dl + 1; #ifdef VIDEO cursor_height = regs.x.cx; #endif } #ifdef DIRECT_VIDEO /* {{It would be better if we could obtain this address from the system...}} */ VideoBase = (char *)(Monochrome ? MK_FP(0xB000,0) : MK_FP(0xB800,0)) + ((unsigned)(Vpage * CO * LI) << 1); #endif ILI = LI - 1; } void do_sgtty() { #ifdef SELECTABLE void init_char_tables __(( void )); init_char_tables(); #endif } extern int done_ttinit; private char org_ctrl_C_state; void ttinit() { LANG_INIT(); ttsize(); regs.x.ax = 0x3300; /* get Ctrl-C state */ intdos(®s, ®s); org_ctrl_C_state = regs.h.dl; CharsPerSec = CSPEED; #ifdef DIRECT_VIDEO if (True(use_direct_video)) CharsPerSec = DV_CSPEED; #endif font_setup(); do_sgtty(); done_ttinit = YES; } /* If n is OFF reset to original modes */ void ttyset(on) register int on; { if (!done_ttinit) /* Try to reset before we've set! */ return; if (on) { stdout->f_flags |= F_BINARY; } else { stdout->f_flags &= ~F_BINARY; } regs.x.ax = 0x3301; /* set Ctrl-C state */ regs.h.dl = (on) ? 0 : org_ctrl_C_state; intdos(®s, ®s); } void ttexit() { signal(SIGINT, SIG_DFL); FONT_EXIT(); #ifdef VIDEO vregs.x.cx = org_cursor_type; /* restore cursor shape */ Video(VID_SELECT_CURSOR); #endif chdir(org_cwd); } /* * Emulate alarm() */ private sig_tp (*alarm_proc)__((int _(sig))) = SIG_DFL; private clock_t next_alarm; ALARM_T alarm(seconds) register unsigned seconds; { register clock_t now = clock(), next = next_alarm; next_alarm = (seconds) ? now + seconds * CLK_TCK : 0; return (unsigned)(now >= next ? 0 : (next - now + CLK_TCK - 1) / CLK_TCK); } int CapsLock; /* * check for alarms in a very regularly called routine. * Also monitor CapsLock state from here (for indicator in mode line). */ private int kbhit __(( void )); private int kbhit() { int prev = CapsLock; if ((CapsLock = Kbshift() & K_CAPS) != prev) { updmodline(); redisplay(); } if (next_alarm && (clock() >= next_alarm)) { next_alarm = 0; if (alarm_proc != SIG_DFL && alarm_proc != SIG_IGN) (*alarm_proc)(SIGALRM); } return Bconstat(); } /* * Emulate signal() * (which is in fact #defined as Jsignal, in tune.h) */ sig_tp (*signal(sig, proc))() int sig; sig_tp (*proc)__((int _(sig))); { register sig_tp (*prev)__((int _(sig))); switch (sig) { case SIGALRM: prev = alarm_proc; alarm_proc = proc; break; default: # undef signal /* to un-hide system's signal() */ { extern sig_tp (*signal())(); prev = signal(sig, proc); } # define signal Jsignal } return prev; } private int peekc = -1; int getchar() { register unsigned int rawc; register int c, scancode; /* slowpoke timeout is now handled here. */ extern void (*timeout_proc)__(( void )); clock_t time_out = clock() + ALARM_1_SEC * CLK_TCK; if ((c = peekc) >= 0) { peekc = -1; return c; } while (!kbhit()) { /* wait for character */ if (timeout_proc && clock() >= time_out) (*timeout_proc)(); #ifdef MOUSE switch (mouse()) { /* or mouse click */ case 0: continue; case LEFT_BUTTON: return ML; default: /* right (or middle, if any) button */ return MR; } #endif } #ifdef MOUSE mouseoff(); #endif rawc = Bconin(); scancode = rawc >> 8; if ((rawc &= 0xff) == 0) { if ((c = FKeyTab0[scancode]) != 0177 && (c & META)) { /* * strip META bit from character. * Mind that for 'A'..'Z' META bit is part of character. */ if ((c &= ~META) < ' ') { /* This is a hack. It can easily get out of sync. The real solution is to install a keyboard interrupt handler which stores the shift status along with the character code. Sigh... */ int shift = Kbshift(); if (!(shift & K_CTRL)) { if (shift & K_SHIFT) c |= META; else c |= META + ('a' - 'A'); } } if (MetaKey) peekc = c, c = MetaKey; else peekc = c | 0200, c = QuoteChar; } } else if (False(UseKeyPad) || (c = FKeyTab1[scancode]) == 0 || (scancode >= sizeof FKeyTab1 / sizeof FKeyTab1[0])) { c = rawc; /* * characters with 8th bit set should be quoted lest JOVE * would interpret these as function key codes. */ if (c & 0200) peekc = c, c = QuoteChar; } return c; } /* Returns non-zero if a character waiting */ int charp() { if (inIOread) return NO; if (InJoverc || peekc >= 0) return YES; return kbhit(); } /* * This does the actual pause, without redisplay. */ int DoSit(delay) register int delay; { register clock_t goal = clock() + delay * (CLK_TCK / 10); while (clock() < goal) { if (InputPending = charp()) return YES; } return NO; } /*======================================================================*/ /* PROC.C */ /*======================================================================*/ #include int DEFVARG(UnixToBuf, (const char *bufname, int disp, int wsize, int clobber, const char *infile, ...), (bufname, disp, wsize, clobber, infile, va_alist) const char *bufname; register int disp; int clobber; const char *infile;) { /* emulate a pipe by redirecting output to a temporary file, and then reading that file when the command is finished. */ char tmpfile[FILESIZE]; register const char *pipe = (bufname == DevNull) ? bufname : mktmpe(tmpfile, "jpXXXXXX"); static int org_fd[3] ZERO; register int i; register int status; sig_tp (*old_sig)(); va_list ap; register char **argv; va_begin(ap, infile); argv = (char **) ap; /* i86 has the ``right'' stack direction. */ va_end(ap); /* Expand environment variables, just in case the shell doesn't... */ i = (argv[0] == Shell && argv[1] == ShFlags) ? 2 : 0; env_expand(argv[i] = strcpy(genbuf, argv[i])); exp = 1; if (clobber) isprocbuf(bufname); if (disp) { message("Starting up..."); #ifdef PROC_TYPEOUT if (disp > 0) /* the next comma-separated statement */ #endif pop_wind(bufname, clobber, clobber ? B_PROCESS : B_FILE), set_wsize(wsize); redisplay(); } /* save original file descriptors */ if (!org_fd[0]) { { i = 2; } do { org_fd[i] = dup(i); } while (--i >= 0); } /* create a temporary file as our ``pipe'' */ if ((i = creat(pipe, S_IRUSR|S_IWUSR)) < 0) complain(IOerr("pipe", argv[2])); dup2(i, 1); dup2(i, 2); close(i); /* connect stdin to infile, or ``/dev/null'' */ if ((infile && (i = open(infile, O_RDONLY)) >= 0) || (i = open(DevNull, O_RDONLY)) >= 0) { dup2(i, 0); close(i); } if (disp) message("Crawling along..."), redisplay(); ttyset(OFF); old_sig = signal(SIGINT, SIG_DFL); if ((status = spawnvp(P_WAIT, argv[0], argv)) == -1) status = -ENOEXEC; signal(SIGINT, old_sig); ResetTerm(); /* just to be sure... */ if (disp) f_mess("Chugging along..."); /* restore original affiliation of stdin, stdout, stderr */ { i = 2; } do { close(i); /* necessary? */ dup2(org_fd[i], i); } while (--i >= 0); if ((i = open(pipe, O_RDONLY)) >= 0) read_pipe(bufname, i, disp); unlink(pipe); return status; } /* push a shell (well, not really, actually...) */ void Push() { register const char *cmd = NullStr; register sig_tp (*old_sig)(); static const char unset_message[] = "\ [There are modified buffers]\r\n\ [type C-G to return to JOVE]\r\n"; register const char *mesg_p = unset_message; if (!ModBufs(0)) mesg_p += (sizeof unset_message - 1) / 2; /* {{or spawn an interactive subshell}} */ alarm(0); curstoLL(); putstr(mesg_p); CATCH for (;;) { f_mess(NullStr); UpdModLine = 0; putp(VS); /* may be turned off by some command */ cmd = ask(cmd, "[JOVE] $ "); printf("\r\n"); flusho(); if (*cmd) { minib_add(cmd, YES); /* history */ old_sig = signal(SIGINT, SIG_DFL); system(cmd); signal(SIGINT, old_sig); } } ENDCATCH alarm(UpdFreq); chdir(pwd()); /* might be changed... */ ResetTerm(); ClAndRedraw(); #ifdef RESHAPING win_reshape(); #endif } /*======================================================================*/ /* UTIL.C */ /*======================================================================*/ /* the library routines did not do the complete job, so... */ #define Dgetdrv() (CALLDOS(0x19)) #define Dsetdrv(drv) (regs.h.dl=(drv), CALLDOS(0x0e), regs.x.cflag) #define Dgetpath(p,d) (regs.x.si=FP_OFF(p), sregs.ds=FP_SEG(p), \ regs.h.dl=(d), CALLDOSx(0x47), regs.x.cflag) #define Dsetpath(p) (regs.x.dx=FP_OFF(p), sregs.ds=FP_SEG(p), \ CALLDOSx(0x3b), regs.x.cflag) char * getwd(result) char *result; { char buf[FILESIZE]; register char *p = buf; register int drive = Dgetdrv(); *p++ = drive + 'a'; *p++ = ':'; *p++ = SLASH; Dgetpath(p, 0); return PathParse(buf, result); /* normalize name */ } /* change directory -- this is more hairy than you might think since Dsetpath() does not do the entire job for you */ int chdir(path) register const char *path; { register int cur_drive = Dgetdrv(); char pathbuf[FILESIZE]; if (path[0] == '\0') return 0; if (path[1] == ':') { if (Dsetdrv(tolower(path[0]) - 'a') != 0) return -1; path += 2; } if (!ISDIRSEP(path[0])) { path = strcpy(&pathbuf[1], path); *(char *)--path = SLASH; } if (Dsetpath(path) != 0) { Dsetdrv(cur_drive); return -1; } return 0; } #ifdef stat /* special version of stat tries to generate an unique inode number. */ int stat(filename, st) #ifndef __TURBOC__ /* Sigh... */ const #endif char *filename; register struct stat *st; { #undef stat if (stat(filename, st) < 0) return -1; if (sizeof st->st_ino == sizeof(long)) { st->st_ino = st->st_ctime ^ st->st_size; } else { union { long l; short i[2]; } ino; ino.l = st->st_ctime ^ st->st_size; st->st_ino = ino.i[0] ^ ino.i[1]; } return 0; } #endif /* stat */ /* library abort() and _assert() use stdio */ #ifndef __TURBOC__ void abort() { _exit(3); } #endif #ifdef __TURBOC__ void __assertfail(msg, cond, file, line) char *msg, *cond, *file; { curstoLL(); putp(CE); printf(msg, cond, file, line); finish(QUIT); } #endif #ifndef VIDEO /* * this is to optimize screen output -- necessarily compiler-dependent since it * is a replacement of the write() library routine. Crawio() (or its MSDOS * equivalent actually) cannot be interrupted by Ctrl-C. */ ssize_t write(fd, buf, nbytes) int fd; const void *buf; size_t nbytes; { long st; if (fd == 1) { register int n = nbytes; register const char *p = buf; while (--n >= 0) { Crawio((*p == '\377') ? ' ' : *p); p++; } return nbytes; } #ifdef __TURBOC__ return _write(fd, buf, nbytes); #else /* MSC */ if ((st = _dos_write(fd, buf, nbytes, &nbytes)) < 0) { errno = st; return -1; } return nbytes; #endif } #endif /* VIDEO */ #ifdef __TURBOC__ /* we want binary files anyway */ int read(fd, buf, nbytes) int fd; void *buf; size_t nbytes; { return _read(fd, buf, nbytes); } #endif /* __TURBOC__ */ #undef getpid int getpid() { extern time_t time0; return (*(short *)&time0 ^ *((short *)&time0 + 1)) & 0x7fff; } #ifdef RESHAPING # define DENSE_VIDEO 0x100 private unsigned get_video_mode() { unsigned mode; regs.h.ah = VID_GET_MODE; int86(VID_INTR, ®s, ®s); mode = regs.h.al; regs.x.ax = 0x1130; /* get textgen. info */ regs.h.bh = 0; regs.h.dl = 0; int86(VID_INTR, ®s, ®s); if (regs.h.dl > 25-1) mode |= DENSE_VIDEO; return mode; } private void set_video_mode(mode) unsigned mode; { regs.x.ax = VID_SET_MODE << 8 | (char) mode; # ifdef VIDEO regs.h.bh = Vpage; # else regs.h.bh = 0; # endif int86(VID_INTR, ®s, ®s); /* The next goo falls in the category: ``everybody else does it, but no-one cares to explain why.'', and since it seems to work well enough without it I doubt that it is really necessary. (But then I only use modern PCs. Better safe than sorry.) */ # define INFO (*(unsigned char *) 0x487) INFO &= ~0x01; if ((mode & DENSE_VIDEO) && (unsigned char) mode <= 7 && EGA_present) { regs.x.ax = 0x1112; /* set char.gen. to 8x8 double dot ROM */ regs.h.bl = 0; /* block 0 */ int86(VID_INTR, ®s, ®s); regs.x.ax = 0x1200; /* alt. select function code */ regs.h.bl = 0x20; /* alt. print screen routine */ int86(VID_INTR, ®s, ®s); # if 0 /* from uEmacs.c (NECESSARY?) */ outp(0x3d4, 10); /* fix video bios bug patch?? */ outp(0x3d5, 6); # endif INFO |= 0x01; /* (NECESSARY? see above) */ } # if 0 /* from 4.14/pcscr.c (NECESSARY?) */ # define CRTC (*(short *) 0x463) outp(CRTC, 0x14); outp(CRTC+1, (dense) ? 0x07 : 0x0D); # endif regs.x.ax = 0x1130; /* get textgen. info */ regs.h.bh = 0; int86(VID_INTR, ®s, ®s); /* for cursor height */ regs.x.cx += 0x100-1; regs.h.ah = VID_SELECT_CURSOR; int86(VID_INTR, ®s, ®s); } private unsigned tdim_modes[4]; private void font_setup() { unsigned mode = (unsigned char) get_video_mode(); if (mode <= 3 || mode == 7) { tdim_modes[0] = mode; tdim_modes[2] = (mode == 1 || mode == 3) ? VGA_132x25_COLOR : VGA_132x25_MONO; } else { tdim_modes[0] = (mode == VGA_132x25_MONO || mode == VGA_132x43_MONO) ? 7 : 3; tdim_modes[2] = mode | 1; } tdim_modes[1] = tdim_modes[0] | DENSE_VIDEO; tdim_modes[3] = (tdim_modes[2] & ~1) | DENSE_VIDEO; } private int set_tdim __(( int _(how), int _(which) )); private int set_tdim(how, which) { unsigned new_mode, cur_mode = get_video_mode(); if (how == 0) { new_mode = org_video_mode; } else { /* determine current setting */ int i = sizeof tdim_modes / sizeof tdim_modes[0]; while (tdim_modes[--i] != cur_mode && i > 0) ; (how < 0) ? (i &= ~which) : (i |= which); new_mode = tdim_modes[i]; } if (cur_mode != new_mode) set_video_mode(new_mode); return (get_video_mode() == new_mode); } DEF_CMD( "screen-wide", ScrDim, ARG(2) ); _IF(def MSDOS)_IF(def RESHAPING) DEF_CMD( "screen-narrow", ScrDim, ARG(2)|NEGATE ); _IF(def MSDOS)_IF(def RESHAPING) DEF_CMD( "screen-dense", ScrDim, ARG(1) ); _IF(def MSDOS)_IF(def RESHAPING) DEF_CMD( "screen-normal", ScrDim, ARG(1)|NEGATE ) _IF(def MSDOS)_IF(def RESHAPING) { if (!set_tdim(exp, ObjArg(LastCmd))) ClAndRedraw(), complain("[%f is not supported by this system]"); win_reshape(); # ifdef MOUSE mouseinit(); /* re-init mouse */ # endif } #endif /* RESHAPING */ #ifdef SELECTABLE #include "chartabs/msdossel.inc" /* ...to include the chardiff tables. */ #define Entry(which) { \ which, \ { \ CAT_INDIR(CharTable, which), \ CAT_INDIR(WordTable, which), \ CAT_INDIR(LocTable, which), \ CAT_INDIR(CaseEquiv, which) \ }, \ (int) CAT_INDIR(offset, which), \ sizeof CAT_INDIR(CharTable, which), \ CAT_INDIR(AccentTab, which), \ CAT_INDIR(charset_name, which) \ } private const struct codetable { int codepage; const char *charTables[NCTABLES]; const int offset, size; const char *const *accentTable; const char *name; } CodeTable[] = { #include "chartabs/msdossel.inc" /* ...to generate the table entries. */ /* Catch-all, restores default tables. */ { 0 } }; /* find out the console's active codepage from DOS */ private int GetCodePage __(( void )); private int GetCodePage() { struct { int size, codepage; } cp_parm; ioctl(0, 0xC, &cp_parm, 0x6A); /* generic handle ioctl, request selected codepage */ return cp_parm.codepage; } void init_char_tables() { int codepage = GetCodePage(); register const struct codetable *ctp = CodeTable; while (ctp->codepage && ctp->codepage != codepage) ctp++; set_char_tables(ctp->codepage ? ctp->charTables : NULL, ctp->offset, ctp->size, ctp->accentTable, ctp->name); } #endif /* SELECTABLE */ #endif /* MSDOS */ /*====================================================================== * $Log: msdos.c,v $ * Revision 14.32.0.8 1993/11/06 00:54:07 tom * (CodeTable): replace explicit #include / Entry drudgery with automagically * generated include file. * * Revision 14.32.0.7 1993/10/29 02:43:04 tom * move attribute defs outside conditionals; * SetAttrib(): fix reverse <-> color interaction; * getchar(): bad hack to recognize - and -. * * Revision 14.32.0.6 1993/10/28 00:54:51 tom * UnixToBuf: expand environment variables in shell commands. * * Revision 14.32.0.5 1993/08/04 04:05:10 tom * (ForChar): fix botch in OverWrite mode beyond EOL, introduced in 14.22. * * Revision 14.32 1993/04/05 15:20:46 tom * (LanguageSpecials, LANG_INIT): fix const-ness. * * Revision 14.31.0.1 1993/03/19 15:19:08 tom * - fix getchar() botch for non-standard scancodes; some cleanup. * * Revision 14.31 1993/02/18 01:42:31 tom * use ALARM_T for alarm(); remove (void) casts; lotsa random optimizations. * * Revision 14.30 1993/02/05 00:07:31 tom * cleanup whitespace; some random optimizations. * * Revision 14.27 1992/09/21 13:16:00 tom * replace CTL('Q') with `QuoteChar'; use ssize_t with write(). * * Revision 14.26 1992/08/26 23:57:02 tom * PRIVATE-ized some Variable defs; add RCS directives. * */