home *** CD-ROM | disk | FTP | other *** search
- /*--- raw.c --------------------------------------------------------------
- MS-DOS routines to set and reset raw mode, enable or disable break checking,
- and check for characters on stdin.
- Written by Dan Kegel (dank@moc.jpl.nasa.gov). Enjoy.
- $Log: raw.c $
- * Revision 1.5 91/11/29 14:35:28 dan_kegel
- * Changed name of function to not clash with Turbo C fn of same name.
- * Turbo's getchar() still annoyingly ignores Enter when in RAW mode;
- * Turbo C users should use getch() rather than getchar(). Blech.
- *
- * Revision 1.4 91/11/29 14:31:30 dan_kegel
- * Added call to setmode to avoid ^Z returning EOF forever.
- *
- * Revision 1.3 90/07/14 09:02:03 dan_kegel
- * Added raw_set_stdio(), which should make it easy to use RAW mode.
- *
- * Revision 1.2 90/07/09 23:18:15 dan_kegel
- * Compiles with /w3 now.
- *
- * Revision 1.1 90/07/09 23:11:13 dan_kegel
- * Initial revision
- *
-
- QUICK SUMMARY:
-
- For fast screen output, call
- raw_set_stdio(1);
- at the beginning of your program, and
- raw_set_stdio(0);
- at the end, and use getchar() to grab keystrokes from the keyboard.
- Your screen updates will be much faster (assuming you use stdout, and
- have installed NANSI.SYS or FANSI-CONSOLE), and
- getchar() will treat Backspace, Enter, ^S, ^C, ^P, and ESC as normal
- keystrokes rather than as editing characters.
-
- DETAILS and extra goodies:
-
- To maximize display speed, applications should set the stdout device to
- raw mode when they start up, and clear it when they exit or start up a
- subshell.
- It is the device associated with a file handle that has a RAW mode, not
- the file handle itself. Thus, if stdin and stdout both refer to CON:,
- raw_get(fileno(stdin)) will always equal raw_get(fileno(stdout)).
-
- The stdin device should not be in RAW mode during normal operation
- because this disables normal command-line editing. For example,
- COPY CON: NUL: will never exit if stdin is in RAW mode.
- Because RAW mode is dangerous, applications that use it should prevent
- DOS from checking for Control-C or Control-Break. This can be done by
- calling break_set(0).
-
- To check for an input char without waiting, call raw_kbhit().
- Be sure to turn off break checking before you call, unless you want
- the user to be able to break out of your program!
-
- To use getchar() while the console is in RAW mode, you must first disable
- input buffering by executing
- setbuf(stdin, NULL);
- or else getchar() will simply hang.
- When stdin is in RAW mode, getchar() will not check for control-C,
- control-S, or control-P; it will also not echo.
- (The ideas here are all UNIX-compatible, but the following code would
- need changes to compile under UNIX. Under UNIX, the only reason to
- use RAW mode is to cause getchar() to not check for ^C, ^S, etc.)
-
- If you tend to do lots of single-character outputting to the screen,
- you may need to use output buffering before you see any speed benefits from
- RAW mode. If you use putchar() to do your outputs, you can enable output
- buffering by executing
- static char stdoutbuf[BUFSIZ];
- setbuf(stdout, stdoutbuf);
- but then you you have to fflush(stdout) each time you want to be sure your
- output has made it out of the buffer onto the screen.
- --------------------------------------------------------------------------*/
- #include <dos.h>
- #include <stdio.h>
- #include <fcntl.h>
- #include <io.h>
- #include "raw.h"
-
- /* IOCTL GETBITS/SETBITS bits. */
- #define DEVICE 0x80
- #define RAW 0x20
-
- /* IOCTL operations */
- #define GETBITS 0
- #define SETBITS 1
- #define GETINSTATUS 6
-
- /* DOS function numbers. */
- #define BREAKCHECK 0x33
- #define IOCTL 0x44
-
- /* A nice way to call the DOS IOCTL function */
- static int
- dos_ioctl(int handle, int mode, unsigned setvalue)
- {
- union REGS regs;
-
- regs.h.ah = IOCTL;
- regs.h.al = (char) mode;
- regs.x.bx = handle;
- regs.h.dl = (char) setvalue;
- regs.h.dh = 0; /* Zero out dh */
- intdos(®s, ®s);
- return (regs.x.dx);
- }
-
- /*--------------------------------------------------------------------------
- Call this routine to determinte whether the device associated with
- the given file is in RAW mode.
- Returns FALSE if not in raw mode, TRUE if in raw mode.
- Example: old_raw = raw_get(fileno(stdin));
- --------------------------------------------------------------------------*/
- int
- raw_get(fd)
- int fd;
- {
- return ( RAW == (RAW & dos_ioctl(fd, GETBITS, 0)));
- }
-
- /*--------------------------------------------------------------------------
- Call this routine to set or clear RAW mode for the device associated with
- the given file.
- Example: raw_set(fileno(stdout), TRUE);
- --------------------------------------------------------------------------*/
- void
- raw_set(fd, raw)
- int fd;
- int raw;
- {
- int bits;
- bits = dos_ioctl(fd, GETBITS, 0);
- if (DEVICE & bits) {
- if (raw)
- bits |= RAW;
- else
- bits &= ~RAW;
- (void) dos_ioctl(fd, SETBITS, bits);
- }
- }
-
- /*--------------------------------------------------------------------------
- If any input is ready on stdin, return a nonzero value.
- Else return zero.
- This works for both input files and devices.
- In RAW mode, if break checking is turned off, does not check for ^C.
- (The kbhit() that comes with Microsoft C seems to always check for ^C.)
- ----------------------------------------------------------------------------*/
- int
- raw_kbhit()
- {
- union REGS regs;
-
- regs.h.ah = IOCTL;
- regs.h.al = GETINSTATUS;
- regs.x.bx = fileno(stdin);
- intdos(®s, ®s);
- return (0xff & regs.h.al);
- }
-
-
- /* A nice way to call the DOS BREAKCHECK function */
- static int
- breakctl(int mode, int setvalue)
- {
- union REGS regs;
-
- regs.h.ah = BREAKCHECK;
- regs.h.al = (char) mode;
- regs.h.dl = (char) setvalue;
- intdos(®s, ®s);
- return (regs.x.dx & 0xff);
- }
-
- /*--------------------------------------------------------------------------
- Call this routine to determine whether DOS is checking for break (Control-C)
- before it executes any DOS function call.
- Return value is FALSE if it only checks before console I/O function calls,
- TRUE if it checks before any function call.
- --------------------------------------------------------------------------*/
- int
- break_get(void)
- {
- return ( 0 != breakctl(GETBITS, 0));
- }
-
- /*--------------------------------------------------------------------------
- Call this routine with TRUE to tell DOS to check for break (Control-C)
- before it executes any DOS function call.
- Call this routine with FALSE to tell DOS to only check for break before
- it executes console I/O function calls.
- --------------------------------------------------------------------------*/
- void
- break_set(check)
- int check;
- {
- (void) breakctl(SETBITS, check);
- }
-
- /*--------------------------------------------------------------------------
- One routine to set (or clear) raw mode on stdin and stdout,
- clear (or restore) break checking, and turn off input buffering on stdin.
- This is the most common configuration; under MS-DOS, since setting raw mode
- on stdout sometimes sets it on stdin, it's best to set it on both & be done
- with it.
- --------------------------------------------------------------------------*/
- void
- raw_set_stdio(raw)
- int raw; /* TRUE -> set raw mode; FALSE -> clear raw mode */
- {
- static int was_break_checking = 0;
-
- raw_set(fileno(stdin), raw);
- raw_set(fileno(stdout), raw);
- if (raw) {
- setbuf(stdin, NULL); /* so getchar() won't hang */
- setmode(fileno(stdin), O_BINARY); /* so ^Z won't end */
- was_break_checking = break_get();
- break_set(0);
- } else {
- break_set(was_break_checking);
- setmode(fileno(stdin), O_TEXT); /* so ^Z will be EOF */
- }
- }
-
-