#line 2 "osdep/dos" /* * $Id: dos 7281 2004-04-05 01:06:15Z amk $ * * Program: Operating system dependent routines - MS DOS * * * Michael Seibel * Networks and Distributed Computing * Computing and Communications * University of Washington * Administration Builiding, AG-44 * Seattle, Washington, 98195, USA * Internet: mikes@cac.washington.edu * * Please address all bugs and comments to "pine-bugs@cac.washington.edu" * * * Pine and Pico are registered trademarks of the University of Washington. * No commercial use of these trademarks may be made without prior written * permission of the University of Washington. * * Pine, Pico, and Pilot software and its included text are Copyright * 1989-1998 by the University of Washington. * * The full text of our legal notices is contained in the file called * CPYRIGHT, included with this distribution. * * * Notes: * - mouse support added (mss, 921215) * * Portions of this code derived from MicroEMACS 3.10: * * MSDOS.C: Operating specific I/O and Spawning functions * under the MS/PCDOS operating system * for MicroEMACS 3.10 * (C)opyright 1988 by Daniel M. Lawrence * */ #include #include #include "dos_gen.h" /* * Internal functions... */ int enhanced_keybrd PROTO((void)); int dont_interrupt PROTO((void)); int interrupt_ok PROTO((void)); int specialkey PROTO((unsigned int)); char *pfnexpand PROTO((char *, size_t)); int ssleep PROTO((long)); int sleep PROTO((int)); /* * Useful global def's */ int timeo = 0; int (*pcollator)(); static int enhncd = 0; /* keyboard of enhanced variety? */ union REGS rg; struct SREGS segreg; static int oldbut; /* Previous state of mouse buttons */ static unsigned short oldbreak; /* Original state of break key */ static char ptmpfile[128]; /* popen temp file */ /* * Include generic DOS/Windows routines */ /* #include "dos_gen.c" */ /* * DISable ctrl-break interruption */ dont_interrupt() { /* get original value, to be restored later... */ rg.h.ah = 0x33; /* control-break check dos call */ rg.h.al = 0; /* get the current state */ rg.h.dl = 0; /* pre-set it OFF */ intdos(&rg, &rg); /* go for it! */ oldbreak = rg.h.dl; /* kill the ctrl-break interupt */ rg.h.ah = 0x33; /* control-break check dos call */ rg.h.al = 1; /* set the current state */ rg.h.dl = 0; /* set it OFF */ intdos(&rg, &rg); /* go for it! */ } /* * re-enable ctrl-break interruption */ interrupt_ok() { /* restore the ctrl-break interupt */ rg.h.ah = 0x33; /* control-break check dos call */ rg.h.al = 1; /* set to new state */ rg.h.dl = oldbreak; /* set it to its original value */ intdos(&rg, &rg); /* go for it! */ } /* * return true if an enhanced keyboard is present */ enhanced_keybrd() { /* and check for extended keyboard */ rg.h.ah = 0x05; rg.x.cx = 0xffff; int86(BIOS_KEYBRD, &rg, &rg); rg.h.ah = 0x10; int86(BIOS_KEYBRD, &rg, &rg); return(rg.x.ax == 0xffff); } /* * This function is called once to set up the terminal device streams. */ ttopen() { dont_interrupt(); /* don't allow interrupt */ enhncd = enhanced_keybrd(); /* check for extra keys */ #if MOUSE init_mouse(); #else /* !MOUSE */ mexist = 0; #endif /* MOUSE */ return(1); } /* * ttresize - recompute the screen dimensions if necessary, and then * adjust pico's internal buffers accordingly */ void ttresize () { return; } #ifdef MOUSE /* * init_mouse - check for and initialize mouse driver... */ init_mouse() { long miaddr; /* mouse interupt routine address */ if(mexist) return(TRUE); /* check if the mouse drive exists first */ rg.x.ax = 0x3533; /* look at the interrupt 33 address */ intdosx(&rg, &rg, &segreg); miaddr = (((long)segreg.es) << 16) + (long)rg.x.bx; if (miaddr == 0 || *(char *)miaddr == 0xcf) { mexist = FALSE; return(TRUE); } /* and then check for the mouse itself */ rg.x.ax = 0; /* mouse status flag */ int86(BIOS_MOUSE, &rg, &rg); /* check for the mouse interupt */ mexist = (rg.x.ax != 0); nbuttons = rg.x.bx; if (mexist == FALSE) return(TRUE); /* if the mouse exists.. get it in the upper right corner */ rg.x.ax = 4; /* set mouse cursor position */ rg.x.cx = (term.t_ncol/2) << 3; /* Center of display... */ rg.x.dx = 1 << 3; /* Second line down */ int86(BIOS_MOUSE, &rg, &rg); /* and set its attributes */ rg.x.ax = 10; /* set text cursor */ rg.x.bx = 0; /* software text cursor please */ rg.x.cx = 0x77ff; /* screen mask */ rg.x.dx = 0x7700; /* cursor mask */ int86(BIOS_MOUSE, &rg, &rg); return(TRUE); } /* * mouseon - call made available for programs calling pico to turn ON the * mouse cursor. */ void mouseon() { rg.x.ax = 1; /* Show Cursor */ int86(BIOS_MOUSE, &rg, &rg); } /* * mouseon - call made available for programs calling pico to turn OFF the * mouse cursor. */ void mouseoff() { rg.x.ax = 2; /* Hide Cursor */ int86(BIOS_MOUSE, &rg, &rg); } #endif /* * This function gets called just before we go back home to the command * interpreter. */ ttclose() { if(!Pmaster) interrupt_ok(); return(1); } /* * Flush terminal buffer. Does real work where the terminal output is buffered * up. A no-operation on systems where byte at a time terminal I/O is done. */ ttflush() { return(1); } /* * specialkey - return special key definition */ specialkey(kc) unsigned kc; { switch(kc){ case 0x3b00 : return(F1); case 0x3c00 : return(F2); case 0x3d00 : return(F3); case 0x3e00 : return(F4); case 0x3f00 : return(F5); case 0x4000 : return(F6); case 0x4100 : return(F7); case 0x4200 : return(F8); case 0x4300 : return(F9); case 0x4400 : return(F10); case 0x8500 : return(F11); case 0x8600 : return(F12); case 0x4800 : return(KEY_UP); case 0x5000 : return(KEY_DOWN); case 0x4b00 : return(KEY_LEFT); case 0x4d00 : return(KEY_RIGHT); case 0x4700 : return(KEY_HOME); case 0x4f00 : return(KEY_END); case 0x4900 : return(KEY_PGUP); case 0x5100 : return(KEY_PGDN); case 0x5300 : return(KEY_DEL); case 0x48e0 : return(KEY_UP); /* grey key version */ case 0x50e0 : return(KEY_DOWN); /* grey key version */ case 0x4be0 : return(KEY_LEFT); /* grey key version */ case 0x4de0 : return(KEY_RIGHT); /* grey key version */ case 0x47e0 : return(KEY_HOME); /* grey key version */ case 0x4fe0 : return(KEY_END); /* grey key version */ case 0x49e0 : return(KEY_PGUP); /* grey key version */ case 0x51e0 : return(KEY_PGDN); /* grey key version */ case 0x53e0 : return(KEY_DEL); /* grey key version */ default : return(NODATA); } } /* * Read a character from the terminal, performing no editing and doing no echo * at all. Also mouse events are forced into the input stream here. */ int ttgetc(return_on_intr, recorder, bail_handler) int return_on_intr; int (*recorder)(); int (*bail_handler)(); { return(_bios_keybrd(enhncd ? _NKEYBRD_READ : _KEYBRD_READ)); } /* * ctrlkey - used to check if the key hit was a control key. */ ctrlkey() { return(_bios_keybrd(enhncd ? _NKEYBRD_SHIFTSTATUS : _KEYBRD_SHIFTSTATUS) & 0x04); } /* * win_multiplex - give DOS in a window a shot at the CPU */ win_multiplex() { rg.x.ax = 0x1680; int86(DOS_MULTIPLEX, &rg, &rg); } /* * Read in a key. * Do the standard keyboard preprocessing. Convert the keys to the internal * character set. Resolves escape sequences and returns no-op if global * timeout value exceeded. */ GetKey() { unsigned ch = 0, lch, intrupt = 0; long timein; if(mexist || timeo){ timein = time(0L); #ifdef MOUSE if(mexist){ rg.x.ax = 1; /* Show Cursor */ int86(BIOS_MOUSE, &rg, &rg); } #endif while(!_bios_keybrd(enhncd ? _NKEYBRD_READY : _KEYBRD_READY)){ #if MOUSE if(timeo && time(0L) >= timein+timeo){ if(mexist){ rg.x.ax = 2; /* Hide Cursor */ int86(BIOS_MOUSE, &rg, &rg); } return(NODATA); } if(checkmouse(&ch,0,0,0)){ /* something happen ?? */ if(mexist){ rg.x.ax = 2; /* Hide Cursor */ int86(BIOS_MOUSE, &rg, &rg); } curwp->w_flag |= WFHARD; return(ch); } #else if(time(0L) >= timein+timeo) return(NODATA); #endif /* MOUSE */ /* * Surrender the CPU... */ if(!intrupt++) win_multiplex(); } #ifdef MOUSE if(mexist){ rg.x.ax = 2; /* Hide Cursor */ int86(BIOS_MOUSE, &rg, &rg); } #endif /* MOUSE */ } ch = (*term.t_getchar)(0, NULL, NULL); lch = (ch&0xff); if(lch & 0x80 && Pmaster && Pmaster->hibit_entered) *Pmaster->hibit_entered = 1; return((lch && (lch != 0xe0 || !(ch & 0xff00))) ? (lch < ' ') ? (CTRL|(lch + '@')) : (lch == ' ' && ctrlkey()) ? (CTRL|'@') : lch : specialkey(ch)); } #if MOUSE /* * checkmouse - look for mouse events in key menu and return * appropriate value. * NOTE: "down", "xxx", and "yyy" aren't used under DOS. */ int checkmouse(ch, down, xxx, yyy) unsigned *ch; int down, xxx, yyy; { register int k; /* current bit/button of mouse */ int mcol; /* current mouse column */ int mrow; /* current mouse row */ int sstate; /* current shift key status */ int newbut; /* new state of the mouse buttons */ int button; int rv = 0; if(!mexist) return(FALSE); /* check to see if any mouse buttons are different */ rg.x.ax = 3; /* Get button status and mouse position */ int86(BIOS_MOUSE, &rg, &rg); newbut = rg.x.bx; mcol = rg.x.cx >> 3; mrow = (rg.x.dx >> 3); /* only notice changes */ if (oldbut == newbut) return(FALSE); if (mcol < 0) /* only on screen presses are legit! */ mcol = 0; if (mrow < 0) mrow = 0; sstate = 0; /* get the shift key status as well */ rg.h.ah = 2; int86(BIOS_KEYBRD, &rg, &rg); sstate = rg.h.al; button = M_BUTTON_LEFT; for (k=1; k != (1 << nbuttons); k = k<<1) { /* For each button on the mouse */ if ((oldbut&k) != (newbut&k)) { if(k == 1){ static int oindex; int i = 0; MENUITEM *mp; if(newbut&k) /* button down */ oindex = -1; for(mp = mfunc; mp; mp = mp->next) if(mp->action && M_ACTIVE(mrow, mcol, mp)) break; if(mp){ unsigned long r; r = (*mp->action)((newbut&k) ? M_EVENT_DOWN : M_EVENT_UP, mrow, mcol, button, 0); if(r & 0xffff){ *ch = (unsigned)((r>>16)&0xffff); rv = TRUE; } } else{ while(1){ /* see if we understand event */ if(i >= 12){ i = -1; break; } if(M_ACTIVE(mrow, mcol, &menuitems[i])) break; i++; } if(newbut&k){ /* button down */ oindex = i; /* remember where */ if(i != -1) /* invert label */ invert_label(1, &menuitems[i]); } else{ /* button up */ if(oindex != -1){ if(i == oindex){ *ch = menuitems[i].val; rv = 1; } } } } if(!(newbut&k) && oindex != -1) invert_label(0, &menuitems[oindex]); /* restore label */ } oldbut = newbut; return(rv); } ++button; } return(FALSE); } /* * invert_label - highlight the label of the given menu item. */ void invert_label(state, m) int state; MENUITEM *m; { int i, j, r, c, p, col_offset; char *lp; int old_state = getrevstate(); if(m->val == mnoop) return; rg.h.ah = 3; /* get cursor position */ int86(BIOS_VIDEO, &rg, &rg); p = rg.h.bh; c = rg.h.dl; r = rg.h.dh; rg.x.ax = 2; /* Hide Cursor */ int86(BIOS_MOUSE, &rg, &rg); /* * Leave the command name bold */ col_offset = (state || !(lp=strchr(m->label, ' '))) ? 0 : (lp - m->label); (*term.t_move)(m->tl.r, m->tl.c + col_offset); (*term.t_rev)(state); for(i = m->tl.r; i <= m->br.r; i++) for(j = m->tl.c + col_offset; j <= m->br.c; j++) if(i == m->lbl.r && j == m->lbl.c + col_offset){ /* show label?? */ lp = m->label + col_offset; while(*lp && j++ < m->br.c) (*term.t_putchar)(*lp++); continue; } else (*term.t_putchar)(' '); (*term.t_rev)(old_state); rg.h.ah = 2; rg.h.bh = p; rg.h.dh = r; rg.h.dl = c; int86(BIOS_VIDEO, &rg, &rg); /* restore old position */ rg.x.ax = 1; /* Show Cursor */ int86(BIOS_MOUSE, &rg, &rg); } #endif /* MOUSE */ /* * alt_editor - fork off an alternate editor for mail message composition * * NOTE: Not yet used under DOS */ alt_editor(f, n) int f, n; { return(-1); } /* * bktoshell - suspend and wait to be woken up */ int bktoshell() /* suspend MicroEMACS and wait to wake up */ { int i; char *shell; (*term.t_move)(term.t_nrow, 0); if(system((shell = getenv("COMSPEC")) ? shell : "command") == -1) emlwrite("Error loading %s", shell ? shell : "COMMAND.COM"); else pico_refresh(0, 1); /* redraw */ return(1); } /* * P_open - run the given command in a sub-shell returning a file pointer * from which to read the output * * note: * For OS's other than unix, you will have to rewrite this function. * Hopefully it'll be easy to exec the command into a temporary file, * and return a file pointer to that opened file or something. */ FILE *P_open(c) char *c; { char cmdbuf[NLINE]; sprintf(ptmpfile, tmpnam(NULL)); sprintf(cmdbuf, "%s > %s", c, ptmpfile); if(system(cmdbuf) == -1){ unlink(ptmpfile); return(NULL); } return(fopen(ptmpfile, "r")); } /* * P_close - close the given descriptor * */ void P_close(fp) FILE *fp; { fclose(fp); /* doesn't handle return codes */ unlink(ptmpfile); }