home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1996 June / Simtel-MSDOS-Jun1996-CD2.iso / disc2 / c / ctrl_c.c < prev    next >
Internet Message Format  |  1988-09-04  |  14KB

  1. Date: Tue, 26 Jul 88 21:04:04 CDT
  2. From: galvin%circle.UUCP@cs.wisc.edu (John Galvin)
  3. Subject: Re: Control-c Trapping Under Msc: The Day After
  4.  
  5.     After I saw your message, I decided to do a bit more
  6. thorough of a job.  The result is included below.  It is made up
  7. of two files: ctrl_c.c and ctrl_c.h.  I have tested these
  8. routines some, and they appear to handle Ctrl-C and Ctrl-Break
  9. with no problem.  This code was written for MS C v5.1.  Some
  10. rewriting *will* be necessary to get it to work under previous
  11. versions of the compiler.  In particular, the do_break() and
  12. do_intcpt() routines would have to be coded in assembler. 
  13. Fortunately, the do_break() and do_intcpt() are merely C
  14. versions of the stuff in intercep.asm.  So if you had to, you
  15. could remove those routines from ctrl_c.c and replace
  16. do_break(INTERCEPT) with intercept() and do_break(RELEASE) with
  17. release().  If you have 5.1 things should work fine.  Have a
  18. nice day :-) !
  19.  
  20.                            --John
  21.  
  22. ------------------------ ctrl_c.h: cut here ---------------------------------
  23. /*
  24. **      ctrl_c.h
  25. **
  26. **      Author:  John Galvin
  27. **      Date:    25-Jul-1988
  28. **      Purpose: trap Ctrl-C and Ctrl-Break without printing anything.
  29. **
  30. **      Note:
  31. **          Use of these routines will prevent Ctrl-C and Ctrl-Break
  32. **          from terminating your program.  They will also prevent
  33. **          Ctrl-P, Ctrl-S, and Ctrl-Z from being interpreted by
  34. **          MS-DOS as they normally are.  Your program will be able
  35. **          to read *all* of these characters, so if you don't want
  36. **          them in your input stream, you will have to do something
  37. **          about them yourself.  This code was written to work in
  38. **          all standard memory models of the Microsoft C compiler
  39. **          version 5.1.  Do not use getch() or getche() with these
  40. **          routines.
  41. **
  42. **      $Id: ctrl_c.h 1.1 88/07/25 22:04:48 galvin Exp $
  43. **
  44. **      Copyright (c) 1988 by John W. Galvin.  All Rights Reserved.
  45. **
  46. **      Permission is hereby granted by the author for anyone to use this
  47. **      code in their own programs provided the following conditions are met:
  48. **      This copyright notice is left intact.  Any changes to this text/code
  49. **      must be commented and credited to the correct author somewhere
  50. **      in this file.
  51. **
  52. **      $Log:   ctrl_c.h $
  53. **      Revision 1.1  88/07/25  22:04:48  galvin
  54. **      Initial revision
  55. **      
  56. **
  57. */
  58.  
  59. #ifndef TRUE
  60. #   define TRUE     1
  61. #endif
  62.  
  63. #ifndef FALSE
  64. #   define FALSE    0
  65. #endif
  66.  
  67. #define INTERCEPT       0
  68. #define RELEASE         1
  69. #define GET             0x00
  70. #define SET             0x01
  71. #define CHKON           0x01
  72. #define CHKOFF          0x00
  73.  
  74.  
  75. #ifdef LINT_ARGS
  76.  
  77. int             ctrl_c(int);
  78. int             get_ctrl_c_chk(void);
  79. int             set_ctrl_c_chk(int);
  80. int             rawio(int, int);
  81. unsigned int    ioctl(int, int, unsigned int);
  82.  
  83. #else
  84.  
  85. extern int          ctrl_c(), get_ctrl_c_chk(), set_ctrl_c_chk(), 
  86. rawio();
  87. extern unsigned int ioctl();
  88.  
  89. #endif
  90.  
  91.  
  92. ------------------------ ctrl_c.c: cut here ---------------------------------
  93. /*
  94. **      ctrl_c.c
  95. **
  96. **      Author:  John Galvin
  97. **      Date:    25-Jul-1988
  98. **      Purpose: trap Ctrl-C and Ctrl-Break without printing anything.
  99. **
  100. **      Note:
  101. **          Use of these routines will prevent Ctrl-C and Ctrl-Break
  102. **          from terminating your program.  They will also prevent
  103. **          Ctrl-P, Ctrl-S, and Ctrl-Z from being interpreted by
  104. **          MS-DOS as they normally are.  Your program will be able
  105. **          to read *all* of these characters, so if you don't want
  106. **          them in your input stream, you will have to do something
  107. **          about them yourself.  This code was written to work in
  108. **          all standard memory models of the Microsoft C compiler
  109. **          version 5.1.  Do not use getch() or getche() with these
  110. **          routines.  See the #ifdef'd section of code below for an
  111. **          example of how to use these functions.
  112. **
  113. **      Copyright (c) 1988 by John W. Galvin.  All Rights Reserved.
  114. **
  115. **      Permission is hereby granted by the author for anyone to use this
  116. **      code in their own programs provided the following conditions are met:
  117. **      This copyright notice is left intact.  Any changes to this text/code
  118. **      must be commented and credited to the correct author somewhere
  119. **      in this file.
  120. **
  121. **      $Log:   ctrl_c.c $
  122. **      Revision 1.1  88/07/25  22:04:46  galvin
  123. **      Initial revision
  124. **      
  125. **
  126. */
  127.  
  128. #ifndef _lint
  129. static char *rcsid = "$Id: ctrl_c.c 1.1 88/07/25 22:04:46 galvin Exp $";
  130. #endif
  131.  
  132. #include <stdio.h>
  133. #include <dos.h>
  134. #include "ctrl_c.h"
  135.  
  136.  
  137. #define BREAKINTR       0x1B
  138. #define DOS             0x21
  139. #define CTRLCCHK        0x33
  140. #define GETVECT         0x35
  141. #define SETVECT         0x25
  142. #define IOCTL           0x44
  143. #define DEVFLAG         0x80
  144. #define RAWFLAG         0x20
  145.  
  146.  
  147.  
  148. /*
  149. **      Name:
  150. **
  151. **          get_ctrl_c_chk() - return status of MS-DOS Ctrl-C checking.
  152. **
  153. **      Synopsis:
  154. **
  155. **          int     get_ctrl_c_chk()
  156. **
  157. **      Description:
  158. **
  159. **          This function determines the current level of Ctrl-C
  160. **          checking being performed by MS-DOS.  The effect of this
  161. **          function is roughly analagous to issuing a "BREAK" command
  162. **          at the MS-DOS command prompt.
  163. **
  164. **      Return Values:
  165. **
  166. **          This function returns FALSE if MS-DOS is only checking for
  167. **          Ctrl-C in the 0x01 - 0x0C group of int 0x21 functions, or
  168. **          if an error occurred.  A return of TRUE indicates that MS-DOS
  169. **          is checking for Ctrl-C before each DOS service is performed.
  170. **
  171. **      Bugs:
  172. **
  173. **          
  174. */
  175. int     get_ctrl_c_chk()
  176. {
  177.     union REGS      regs;
  178.  
  179.     regs.h.ah = CTRLCCHK;
  180.     regs.h.al = GET;
  181.     int86(DOS, ®s, ®s);
  182.  
  183.     if (regs.x.cflag)
  184.         return(FALSE);
  185.  
  186.     return(regs.h.dl);
  187. }
  188.  
  189.  
  190.  
  191. /*
  192. **      Name:
  193. **
  194. **          set_ctrl_c_chk() - set the level of MS-DOS Ctrl-C checking.
  195. **
  196. **      Synopsis:
  197. **
  198. **          int     set_ctrl_c_chk(value)
  199. **          int     value;
  200. **
  201. **      Description:
  202. **
  203. **          This function sets the level of Ctrl-C checking that MS-DOS
  204. **          will perform.  Value should be one of the two manifest
  205. **          constants CHKON or CHKOFF.  Calling set_ctrl_c_chk() with a
  206. **          value of CHKON is equivalent to issuing a "BREAK ON" command
  207. **          at the MS-DOS command line.  Calling set_ctrl_c_chk() with a
  208. **          value of CHKOFF is equivalent to issuing a "BREAK OFF" command
  209. **          at the MS-DOS command line.
  210. **
  211. **      Return Values:
  212. **
  213. **          This function returns FALSE if an error occurred, TRUE otherwise.
  214. **
  215. **      Bugs:
  216. **
  217. **          
  218. */
  219. int     set_ctrl_c_chk(value)
  220. int     value;
  221. {
  222.     union REGS      regs;
  223.  
  224.     regs.h.ah = CTRLCCHK;
  225.     regs.h.al = SET;
  226.     regs.h.dl = value;
  227.     int86(DOS, ®s, ®s);
  228.  
  229.     return(!regs.x.cflag);
  230. }
  231.  
  232.  
  233.  
  234. /*
  235. **      Name:
  236. **
  237. **          ioctl() - MS-DOS i/o control for devices interface.
  238. **
  239. **      Synopsis:
  240. **
  241. **          unsigned int    ioctl(handle, op, value)
  242. **          int             handle;
  243. **          int             op;
  244. **          unsigned int    value;
  245. **
  246. **      Description:
  247. **
  248. **          This routine provides a limited interface to the MS-DOS
  249. **          ioctl functions.  It primarily intended to get/set the
  250. **          device attribute bits for a file handle.  Handle should
  251. **          an open file handle (hopefully for a device).  Op should
  252. **          be one of SET or GET.  If op is SET, the device attribute
  253. **          bits for handle will be set to those specified in value.
  254. **
  255. **      Return Values:
  256. **
  257. **          This function returns FALSE if an error occurred.  Otherwise
  258. **          The new device attribute word will be returned.  The attribute
  259. **          word may possibly be equal to FALSE.
  260. **
  261. **      Bugs:
  262. **
  263. **          
  264. */
  265. unsigned int    ioctl(handle, op, value)
  266. int             handle;
  267. int             op;
  268. unsigned int    value;
  269. {
  270.     union REGS  regs;
  271.  
  272.  
  273.     regs.h.ah = IOCTL;
  274.     regs.h.al = op;
  275.     regs.x.bx = handle;
  276.     regs.x.dx = value & 0xFF;
  277.     int86(DOS, ®s, ®s);
  278.  
  279.     if (regs.x.cflag)
  280.         return(FALSE);
  281.  
  282.     return(regs.x.dx);
  283. }
  284.  
  285.  
  286.  
  287. /*
  288. **      Name:
  289. **
  290. **          rawio() - set/reset a device to/from raw i/o mode.
  291. **
  292. **      Synopsis:
  293. **
  294. **          int     rawio(handle, raw)
  295. **          int     handle;
  296. **          int     raw;
  297. **
  298. **      Description:
  299. **
  300. **          Rawio() uses ioctl() to set/reset a device to/from raw i/o
  301. **          mode.  When a device is in raw mode, and Ctrl-C checking is
  302. **          turned off, Ctrl-C, Ctrl-S, Ctrl-P, and Ctrl-Z may be read
  303. **          as data without having MS-DOS interpret them.  Handle must
  304. **          refer to an open file/device.  If raw is TRUE, the device
  305. **          will be set to raw mode.  Otherwise, the device will be reset
  306. **          from raw mode.
  307. **
  308. **      Return Values:
  309. **
  310. **          This function returns a non-zero value if the device was
  311. **          in raw mode, 0 otherwise.
  312. **
  313. **      Bugs:
  314. **
  315. **          No checks are made for errors from ioctl().
  316. */
  317. int     rawio(handle, raw)
  318. int     handle;
  319. int     raw;
  320. {
  321.     unsigned int    flags;
  322.  
  323.     flags = ioctl(handle, GET, 0);
  324.     if (flags & DEVFLAG) {
  325.         if (raw)
  326.             ioctl(handle, SET, flags | RAWFLAG);
  327.         else
  328.             ioctl(handle, SET, flags & ~RAWFLAG);
  329.     }
  330.  
  331.     return(flags & RAWFLAG);
  332. }
  333.  
  334.  
  335.  
  336. /*
  337. **      Name:
  338. **
  339. **          do_intcpt() - Ctrl-Break Interrupt (0x1B) routine.
  340. **
  341. **      Synopsis:
  342. **
  343. **          void interrupt cdecl far    do_intcpt()
  344. **
  345. **      Description:
  346. **
  347. **          This routine is the dummy interrupt routine which is used
  348. **          to intercept the IBM PC Break interrupt.
  349. **
  350. **      Return Values:
  351. **
  352. **          None.
  353. **
  354. **      Bugs:
  355. **
  356. **          
  357. */
  358. static void interrupt cdecl far do_intcpt()
  359. {
  360.     return;
  361. }
  362.  
  363.  
  364.  
  365. /*
  366. **      Name:
  367. **
  368. **          do_break() - intercept/release the IBM PC Break Interrupt.
  369. **
  370. **      Synopsis:
  371. **
  372. **          static void do_break(op)
  373. **          int         op;
  374. **
  375. **      Description:
  376. **
  377. **          If passed the manifest constant INTERCEPT, this routine
  378. **          will use do_intcpt() to intercept the IBM PC Ctrl-Break
  379. **          interrupt.  If this routine is not used while trapping
  380. **          Ctrl-C and Ctrl-Break, a ^C may turn up *after* the porgram
  381. **          exits.  When passed the manifest constant RELEASE, do_break()
  382. **          will de-install its interrupt handler.
  383. **
  384. **      Return Values:
  385. **
  386. **          None.
  387. **
  388. **      Bugs:
  389. **
  390. **          No error checks are performed on the returns of int86x().
  391. */
  392. static void do_break(op)
  393. int         op;
  394. {
  395.     union REGS          regs;
  396.     struct SREGS        segs;
  397.     static unsigned int oldseg;
  398.     static unsigned int oldofs;
  399.  
  400.     if (op == INTERCEPT) {
  401.         segread(&segs);
  402.         regs.h.ah = GETVECT;
  403.         regs.h.al = BREAKINTR;
  404.         int86x(DOS, ®s, ®s, &segs);
  405.         oldseg = segs.es;
  406.         oldofs = regs.x.bx;
  407.  
  408.         segread(&segs);
  409.         regs.x.dx = (unsigned int) do_intcpt;
  410.         segs.ds   = ((unsigned long) do_intcpt) >> 16;
  411.     }
  412.     else {
  413.         segread(&segs);
  414.         regs.x.dx = oldofs;
  415.         segs.ds   = oldseg;
  416.     }
  417.     regs.h.ah = SETVECT;
  418.     regs.h.al = BREAKINTR;
  419.     int86x(DOS, ®s, ®s, &segs);
  420. }
  421.  
  422.  
  423.  
  424. /*
  425. **      Name:
  426. **
  427. **          ctrl_c() - nullify Ctrl-C and Ctrl-Break.
  428. **
  429. **      Synopsis:
  430. **
  431. **          int     ctrl_c(op)
  432. **          int     op;
  433. **
  434. **      Description:
  435. **
  436. **          If passed the manifest constant INTERCEPT, ctrl_c() will
  437. **          prevent MS-DOS from interpreting Ctrl-C, Ctrl-Break, Ctrl-P,
  438. **          Ctrl-S, and Ctrl-Z as it normally does.  I.E. a Ctrl-C or
  439. **          Ctrl-Break will not cause a ^C to be output and will not
  440. **          abort the program.  Do not use getch(), or getche() while
  441. **          this routine is in effect, they do not properly support
  442. **          this mode.  If passed the manifest constant RELEASE, ctrl_c()
  443. **          will return the Ctrl character interpretation that existed
  444. **          before ctrl_c(INTERCEPT) was called.
  445. **
  446. **      Return Values:
  447. **
  448. **          Ctrl_c() always returns TRUE.
  449. **
  450. **      Bugs:
  451. **
  452. **          No error checking is done.
  453. */
  454. int     ctrl_c(op)
  455. int     op;
  456. {
  457.     static unsigned int outflg;
  458.     static unsigned int inflg;
  459.     static unsigned int ctrlcchk;
  460.  
  461.  
  462.     if (op == INTERCEPT) {
  463.         do_break(INTERCEPT);
  464.         inflg  = rawio(fileno(stdin), TRUE);
  465.         outflg = rawio(fileno(stdout), TRUE);
  466.         if ((ctrlcchk = get_ctrl_c_chk()) == CHKON)
  467.             set_ctrl_c_chk(CHKOFF);
  468.     }
  469.     else {
  470.         set_ctrl_c_chk(ctrlcchk);
  471.         rawio(fileno(stdout), outflg);
  472.         rawio(fileno(stdin), inflg);
  473.         do_break(RELEASE);
  474.     }
  475.  
  476.     return(TRUE);
  477. }
  478.  
  479.  
  480.  
  481. #ifdef CTRL_CDEBUG
  482.  
  483. #include <bios.h>
  484.  
  485. int     main()
  486. {
  487.     int     achar;
  488.  
  489.     ctrl_c(INTERCEPT);
  490.     while ((achar = _bios_keybrd(_KEYBRD_READ) & 0xFF) != ' ')
  491.         putch(achar);
  492.     ctrl_c(RELEASE);
  493.     return(0);
  494. }
  495.  
  496. #endif
  497.  
  498.  
  499. ----------------------------- the end ---------------------------------------
  500.   
  501. --  
  502. John Galvin         ARPA:    galvin@circle.UUCP
  503. 1810 Fordem Ave. #6 UUCP:    ...!uwvax!geowhiz!circle!galvin
  504. Madison, Wi  53704  FidoNet: Sysop of 1:121/0, and 1:121/1.  (608) 249-0275
  505.