home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_200 / 259_01 / conio.asm < prev    next >
Assembly Source File  |  1988-02-25  |  18KB  |  350 lines

  1. ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2. ;*                                                                           *
  3. ;*  FILE:  CONIO.ASM                                                         *
  4. ;*                                                                           *
  5. ;*  This file contains library routines for putch(), getch(), getche(),      *
  6. ;*  ungetch(), and kbhit().  Although these routines are included in the     *
  7. ;*  C libraries that come with the Microsoft (R) C compiler, they are        *
  8. ;*  redirectable, which renders them useless.  (kbhit() is not redirectable, *
  9. ;*  but was added to increase functionality; specifically, to indicate what  *
  10. ;*  key was pressed, while still implementing Ctrl-C and Ctrl-S checking.    *
  11. ;*                                                                           *
  12. ;*  Since these five routines are used by cputs(), cgets(), cprintf(), and   *
  13. ;*  cscanf(), these higher-level functions are also useless, unless          *
  14. ;*  correctly working versions of putch(), getch(), getche(), ungetch(),     *
  15. ;*  and kbhit() are installed in the C libraries.                            *
  16. ;*                                                                           *
  17. ;*  (If you WANT your I/O to be redirectable, you can use putchar(),         *
  18. ;*   getchar(), ungetchar(), puts(), gets(), printf(), and scanf() ).        *
  19. ;*                                                                           *
  20. ;*  When assembling, use the -dRNEAR option if assembling for small or       *
  21. ;*  compact models, and the -dRFAR option if assembling for medium, large,   *
  22. ;*  or huge models.  If you are not using masm ver 4.0 or later, you will    *
  23. ;*  have to define either a RNEAR or RFAR label at the top of this program.  *
  24. ;*                                                                           *
  25. ;*  To assemble, use a command like this:                                    *
  26. ;*                                                                           *
  27. ;*     masm -mx -dRFAR conio;                                                *
  28. ;*                                                                           *
  29. ;*  To install these routines into the library, use a command like this:     *
  30. ;*                                                                           *
  31. ;*     lib llibc -putch -getch -getche -ungetch -kbhit +conio;               *
  32. ;*                                                                           *
  33. ;*                                                                           *
  34. ;*  Routines written by Jeff D. Pipkins at Quality Micro Systems, Inc.       *
  35. ;*  This file is hereby declared to be public domain.  Since it is public    *
  36. ;*  domain, QMS (R) is not liable for ANY damages caused by the use or       *
  37. ;*  abuse of this material.  Original release: 03/02/1987                    *
  38. ;*                                                                           *
  39. ;*  NOTE: These routines were written to work with the Microsoft (R)         *
  40. ;*        C compiler (ver 3.0 or later), but they can easily be adapted      *
  41. ;*        to work with other C compilers on any IBM (R) PC compatible.       *
  42. ;*                                                                           *
  43. ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  44. ;*                                                                           *
  45. ;*  Revision 04/16/1987 (JDP):                                               *
  46. ;*     Added code for ungetch() with a one-character buffer.                 *
  47. ;*     See ungetch() and getch() routines for details.                       *
  48. ;*                                                                           *
  49. ;*  Revision 06/09/1987 (JDP):                                               *
  50. ;*     Modified getch() to translate lf to cr (it already translated         *
  51. ;*     cr to lf) so that a discriminating routine can tell the difference    *
  52. ;*     if necessary.                                                         *
  53. ;*     Added kbhit() in response to a quest by The C User's Group for        *
  54. ;*     a standard routine.                                                   *
  55. ;*     Added more documentation in the external .DOC file so that            *
  56. ;*     C programmers who have no assembly-language experience can read       *
  57. ;*     the specs without looking at the assembly code.                       *
  58. ;*                                                                           *
  59. ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  60.  
  61. IF1
  62.  IFNDEF RNEAR
  63.   IFNDEF RFAR
  64.    %OUT FATAL ERROR: You MUST specify either -dRNEAR or -dRFAR on the command line!
  65.    %OUT              (Note: Remember to use the -MX option as well!)
  66.    .ERR
  67.    ERROR EQU TRUE
  68.   ENDIF
  69.  ENDIF
  70.  IFDEF RNEAR
  71.   IFDEF RFAR
  72.    %OUT FATAL ERROR: You CANNOT specify both -dRNEAR and -dRFAR on the command line!
  73.    %OUT              (Note: Remember to use the -MX option as well!)
  74.    .ERR
  75.    ERROR EQU TRUE
  76.   ENDIF
  77.  ENDIF
  78.  IFNDEF ERROR
  79.   IFDEF RNEAR
  80.    %OUT Generating object file for use with small or compact memory models...
  81.   ELSE
  82.    %OUT Generating object file for use with medium, large, or huge memory models...
  83.   ENDIF
  84.  ENDIF
  85. ENDIF
  86.  
  87. _TEXT        Segment      Byte Public 'CODE'
  88.              Assume       CS:_TEXT
  89.  
  90. Parm         Equ          [BP]
  91. ungot_char   DW           0         ; Storage for one keystroke of lookahead
  92. EOF          Equ          -1
  93.  
  94. ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  95. ;*                                                                           *
  96. ;*  void putch(c)                                                            *
  97. ;*     int c;                                                                *
  98. ;*                                                                           *
  99. ;*  Displays the character passed on the screen, regardless of redirection.  *
  100. ;*  NOTE: Any line feeds displayed ('\n') will be preceeded by a cr ('\r').  *
  101. ;*                                                                           *
  102. ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  103.  
  104.              Public       _putch
  105. IFDEF RFAR
  106. _putch       Proc         Far
  107. ELSE
  108. _putch       Proc         Near
  109. ENDIF
  110.  
  111. ;*  Parameters
  112.  
  113. IFDEF RFAR
  114. putch        Struc
  115.              DW           ?         ; Single-word save area for BP
  116.              DD           ?         ; Double-word return address
  117. char         DW           ?         ; Character to put on the console
  118. putch        EndS
  119. ELSE
  120. putch        Struc
  121.              DW           ?         ; Single-word save area for BP
  122.              DW           ?         ; Single-word return address
  123. char         DW           ?         ; Character to put on the console
  124. putch        EndS
  125. ENDIF
  126.  
  127. ;*  Output character to console using video BIOS
  128.  
  129.              Push         BP
  130.              Mov          BP, SP
  131.              Mov          CX, SI    ; Some BIOS clones destroy SI & DI
  132.              Mov          DX, DI    ;   so save them first.
  133.              Mov          AH, 0EH   ; TTY output function
  134.              Mov          BL, 7     ; Attribute
  135.              Mov          AL, Byte Ptr Parm[char]
  136.              Cmp          AL, 0AH   ; Line feed?
  137.              Je           CRLF      ; If so, translate to CRLF sequence
  138.              Int          10H       ; Video BIOS
  139.              Mov          SI, CX    ; Restore SI
  140.              Mov          DI, DX    ;   and DI
  141.              Pop          BP        ; BIOS destroys BP if scrolling occurs.
  142.              Ret
  143. CRLF:
  144.              Mov          AH, 0BH   ; Check keyboard status
  145.              Int          21H       ; Allow Ctrl-C or Ctrl-S
  146.              Mov          AX, 0E0DH
  147.              Int          10H
  148.              Mov          AX, 0E0AH
  149.              Int          10H
  150.              Mov          SI, CX
  151.              Mov          DI, DX
  152.              Pop          BP
  153.              Ret
  154.  
  155. _putch       EndP
  156.  
  157. ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  158. ;*                                                                           *
  159. ;*  int getch();                                                             *
  160. ;*                                                                           *
  161. ;*  Get a keystroke from the keyboard regardless of redirection.  If the     *
  162. ;*  key has an ASCII value, it is returned as an integer.  If the key does   *
  163. ;*  not have an ASCII value (it is a function key, arrow key, etc.), then    *
  164. ;*  the value returned has the low byte zero and the high byte will hold     *
  165. ;*  the scan code for the key pressed.                                       *
  166. ;*                                                                           *
  167. ;*  Example for detecting special keys:                                      *
  168. ;*                                                                           *
  169. ;*  if ((i=getch()) <= 255) {                                                *
  170. ;*     spec_key = FALSE;                                                     *
  171. ;*     mychar = i;                                                           *
  172. ;*  }else{                                                                   *
  173. ;*     spec_key = TRUE;                                                      *
  174. ;*     scan_code = (unsigned) i >> 8;                                        *
  175. ;*  }                                                                        *
  176. ;*                                                                           *
  177. ;*  NOTE: Carriage returns are translated to line feeds, and vice versa.     *
  178. ;*        This is done so that a program can check for the ENTER key by      *
  179. ;*        comparing the character to '\n', as usual.                         *
  180. ;*                                                                           *
  181. ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  182.  
  183.              Public       _getch
  184. IFDEF RFAR
  185. _getch       Proc         Far
  186. ELSE
  187. _getch       Proc         Near
  188. ENDIF
  189.              Mov          AX, CS:[ungot_char] ; Is there a char in buffer?
  190.              Or           AX, AX
  191.              Jz           getch_kbd ; Get from keyboard if buffer empty
  192.              Mov          CS:[ungot_char], Word Ptr 0  ; clear buffer
  193.              Ret          ; ungot character is returned in AX
  194. getch_kbd:
  195.              ; Assume AX is 0 from above code
  196.              Int          16H       ; Keyboard BIOS, read w/wait, no echo
  197.              Or           AL, AL    ; Special key (no ASCII code) ?
  198.              Jz           getch_end ; If so, return full AX
  199.              Xor          AH, AH    ; Else, get rid of scan code
  200.  
  201. ; Translate cr to lf so that a compare with '\n' will be valid.
  202. ; Translate lf to cr so that a discriminating routine can tell the
  203. ; difference if necessary.
  204. ; Note: the technique used below works because:
  205. ;       A xor (A xor D) = (A xor A) xor D = 0 xor D = D
  206. ;       D xor (A xor D) = D xor (D xor A) = (D xor D) xor A = 0 xor A = A
  207.  
  208.              Cmp          AL, 0DH   ; Carriage return?
  209.              Je           getch_xlat
  210.              Cmp          AL, 0AH   ; Line feed?
  211.              Jne          getch_end
  212. getch_xlat:
  213.              Xor          AL, (0AH xor 0DH)   ; cr <=swap=> lf
  214. getch_end:
  215.              Mov          BX, AX    ; Save AX
  216.              Mov          AH, 0BH   ; Check keyboard status
  217.              Int          21H       ; Allow Ctrl-C or Ctrl-S
  218.              Mov          AX, BX    ; Restore AX
  219.              Ret
  220.  
  221. _getch       EndP
  222.  
  223. ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  224. ;*                                                                           *
  225. ;*  int getche()                                                             *
  226. ;*                                                                           *
  227. ;*  {                                                                        *
  228. ;*     register unsigned i;                                                  *
  229. ;*                                                                           *
  230. ;*     if ((i = getch()) <= 255) {                                           *
  231. ;*        putch(i);                                                          *
  232. ;*     }                                                                     *
  233. ;*     return(i);                                                            *
  234. ;*  }                                                                        *
  235. ;*                                                                           *
  236. ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  237.  
  238.              Public       _getche
  239. IFDEF RFAR
  240. _getche      Proc         Far
  241. ELSE
  242. _getche      Proc         Near
  243. ENDIF
  244.              Call         _getch    ; Get character from keyboard
  245.              Or           AL, AL    ; Special key (No ASCII code) ?
  246.              Jz           getche_end ; If not, don't display it.
  247.              Push         AX        ; Pass character as parameter
  248.              Call         _putch    ; Call putch() to echo it.
  249.              Pop          AX        ; Return character in AX
  250. getche_end:
  251.              Ret
  252. _getche      EndP
  253.  
  254. ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  255. ;*                                                                           *
  256. ;*  int ungetch(char)                                                        *
  257. ;*     int char;                                                             *
  258. ;*  { ... }                                                                  *
  259. ;*                                                                           *
  260. ;*  Pushes the character (char) back to the console, causing (char) to be    *
  261. ;*  the next character to be read by getch() or getche().  Returns (char)    *
  262. ;*  if successful, EOF (-1) if error.                                        *
  263. ;*                                                                           *
  264. ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  265.  
  266.              Public       _ungetch
  267. IFDEF RFAR
  268. _ungetch     Proc         Far
  269. ELSE
  270. _ungetch     Proc         Near
  271. ENDIF
  272.              Push         BP
  273.              Mov          BP, SP
  274.  
  275.              Mov          AX, CS:[ungot_char] ; Make sure buffer is empty
  276.              Or           AX, AX              ; Must be zero
  277.              Jnz          ungetch_err         ; Go if buffer full
  278.  
  279.              Mov          AX, Parm[char]      ; Get character to push
  280.              Mov          CS:[ungot_char], AX ; Push it into the buffer
  281.              Jmp Short    ungetch_ok          ; Return value is in AX
  282.  
  283. ungetch_err:
  284.              Mov          AX, EOF   ; Indicate EOF if too many ungetch()s.
  285. ungetch_ok:
  286.              Mov          SP, BP
  287.              Pop          BP
  288.              Ret
  289. _ungetch     EndP
  290.  
  291. ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  292. ;*                                                                           *
  293. ;*  int kbhit();                                                             *
  294. ;*                                                                           *
  295. ;*  This function is identical to getch() with the exception that if there   *
  296. ;*  is no keypress to be processed, kbhit() returns 0 instead of waiting     *
  297. ;*  for one.  (In contrast, getch() will wait for a keypress, and will       *
  298. ;*  never return 0.)  Please see getch() documentation for more info.        *
  299. ;*                                                                           *
  300. ;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  301.  
  302.              Public       _kbhit
  303. IFDEF RFAR
  304. _kbhit       Proc         Far
  305. ELSE
  306. _kbhit       Proc         Near
  307. ENDIF
  308.              Mov          AX, CS:[ungot_char] ; Is there a char in buffer?
  309.              Or           AX, AX
  310.              Jz           kbhit_kbd ; Get from keyboard if buffer empty
  311.              Mov          CS:[ungot_char], Word Ptr 0  ; clear buffer
  312.              Ret          ; ungot character is returned in AX
  313. kbhit_kbd:
  314.              Mov          AH, 1     ; Tell BIOS not to wait on character
  315.              Int          16H       ; Keyboard BIOS read, no wait, no echo
  316.              Jnz          kbhit_hit ; Don't go if no keypress is available
  317.              Xor          AX, AX    ; Return a 0
  318.              Jmp Short    kbhit_end ; Check for break even if no keypress
  319. kbhit_hit:
  320.              Or           AL, AL    ; Special key (no ASCII code) ?
  321.              Jz           kbhit_end ; If so, return full AX
  322.              Xor          AH, AH    ; Else, get rid of scan code
  323.  
  324. ; Translate cr to lf so that a compare with '\n' will be valid.
  325. ; Translate lf to cr so that a discriminating routine can tell the
  326. ; difference if necessary.
  327. ; Note: the technique used below works because:
  328. ;       A xor (A xor D) = (A xor A) xor D = 0 xor D = D
  329. ;       D xor (A xor D) = D xor (D xor A) = (D xor D) xor A = 0 xor A = A
  330.  
  331.              Cmp          AL, 0DH   ; Carriage return?
  332.              Je           kbhit_xlat
  333.              Cmp          AL, 0AH   ; Line feed?
  334.              Jne          kbhit_end
  335. kbhit_xlat:
  336.              Xor          AL, (0AH xor 0DH)   ; cr <=swap=> lf
  337. kbhit_end:
  338.              Mov          BX, AX    ; Save AX
  339.              Mov          AH, 0BH   ; Check keyboard status
  340.              Int          21H       ; Allow Ctrl-C or Ctrl-S
  341.              Mov          AX, BX    ; Restore AX
  342.              Ret
  343.  
  344. _kbhit       EndP
  345.  
  346.  
  347. _TEXT        EndS
  348.              End
  349.  
  350.