home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / UTILITY / BATCH / RING14.ZIP / RING.ASM < prev    next >
Encoding:
Assembly Source File  |  1991-10-15  |  36.6 KB  |  995 lines

  1. ;--------------------------------------------------------------------------;
  2. ;  Program:    Ring    .Asm                                                ;
  3. ;  Purpose:    Rings the console bell.                                     ;
  4. ;  Notes:      Compiles under TURBO Assembler, v2.0. Should work on any    ;
  5. ;                 machine running MS-DOS, v2.xx or higher.                 ;
  6. ;  Status:     Released into the public domain. Enjoy! If you use it,      ;
  7. ;                 let me know what you think. You don't have to send       ;
  8. ;                 any money, just comments and suggestions.                ;
  9. ;  Updates:    23-Apr-89, v1.0, GAT                                        ;
  10. ;                 - initial version.                                       ;
  11. ;              22-Apr-90, v1.1, GAT                                        ;
  12. ;                 - revised all procedures based on work on ASK.           ;
  13. ;              05-May-90, GAT                                              ;
  14. ;                 - fixed bug in handling of non-zero return codes.        ;
  15. ;              13-May-90, v1.2, GAT                                        ;
  16. ;                 - added '-e' option to test for nonzero errorlevels.     ;
  17. ;              08-Jul-90, GAT                                              ;
  18. ;                 - added macros to push/pop registers.                    ;
  19. ;              28-Aug-90, v1.3a, GAT                                       ;
  20. ;                 - put equates and macros in separate files.              ;
  21. ;                 - put common routines in libs.                           ;
  22. ;              28-Dec-90, v1.4a, GAT                                       ;
  23. ;                 - added support under DOS v4.0 for '-e' option.          ;
  24. ;              15-Oct-91, v1.4b, GAT                                       ;
  25. ;                 - revised include file names.                            ;
  26. ;                 - added support for DOS v5.0.                            ;
  27. ;--------------------------------------------------------------------------;
  28.  
  29. ;--------------------------------------------------------------------------;
  30. ;  Author:     George A. Theall                                            ;
  31. ;  Phone:      +1 215 662 0558                                             ;
  32. ;  SnailMail:  TifaWARE                                                    ;
  33. ;              506 South 41st St., #3M                                     ;
  34. ;              Philadelphia, PA.  19104   USA                              ;
  35. ;  E-Mail:     theall@gdalsrv.sas.upenn.edu (Internet)                     ;
  36. ;--------------------------------------------------------------------------;
  37.  
  38. %NEWPAGE
  39. ;--------------------------------------------------------------------------;
  40. ;                          D I R E C T I V E S                             ;
  41. ;--------------------------------------------------------------------------;
  42. DOSSEG
  43. MODEL     tiny
  44.  
  45. IDEAL
  46. LOCALS
  47. JUMPS
  48.  
  49. ;
  50. ; This section comes from Misc.Inc.
  51. ;
  52. @16BIT              EQU       (@CPU AND 8) EQ 0
  53. @32BIT              EQU       (@CPU AND 8)
  54. MACRO    ZERO     RegList                    ;; Zeros registers
  55.    IRP      Reg, <RegList>
  56.          xor      Reg, Reg
  57.    ENDM
  58. ENDM
  59.  
  60. ;
  61. ; This section comes from DOS.Inc.
  62. ;
  63. BELL                EQU       7
  64. BS                  EQU       8
  65. TAB                 EQU       9
  66. CR                  EQU       13
  67. LF                  EQU       10
  68. ESCAPE              EQU       27             ; nb: ESC is a TASM keyword
  69. SPACE               EQU       ' '
  70. KEY_F1              EQU       3bh
  71. KEY_F2              EQU       3ch
  72. KEY_F3              EQU       3dh
  73. KEY_F4              EQU       3eh
  74. KEY_F5              EQU       3fh
  75. KEY_F6              EQU       40h
  76. KEY_F7              EQU       41h
  77. KEY_F8              EQU       42h
  78. KEY_F9              EQU       43h
  79. KEY_F10             EQU       44h
  80. KEY_HOME            EQU       47h
  81. KEY_UP              EQU       48h
  82. KEY_PGUP            EQU       49h
  83. KEY_LEFT            EQU       4bh
  84. KEY_RIGHT           EQU       4dh
  85. KEY_END             EQU       4fh
  86. KEY_DOWN            EQU       50h
  87. KEY_PGDN            EQU       51h
  88. KEY_INS             EQU       52h
  89. KEY_DEL             EQU       53h
  90. KEY_C_F1            EQU       5eh
  91. KEY_C_F2            EQU       5fh
  92. KEY_C_F3            EQU       60h
  93. KEY_C_F4            EQU       61h
  94. KEY_C_F5            EQU       62h
  95. KEY_C_F6            EQU       63h
  96. KEY_C_F7            EQU       64h
  97. KEY_C_F8            EQU       65h
  98. KEY_C_F9            EQU       66h
  99. KEY_C_F10           EQU       67h
  100. KEY_C_LEFT          EQU       73h
  101. KEY_C_RIGHT         EQU       74h
  102. KEY_C_END           EQU       75h
  103. KEY_C_PGDN          EQU       76h
  104. KEY_C_HOME          EQU       77h
  105. KEY_C_PGUP          EQU       84h
  106. KEY_F11             EQU       85h
  107. KEY_F12             EQU       86h
  108. KEY_C_F11           EQU       89h
  109. KEY_C_F12           EQU       8ah
  110. DOS                 EQU       21h            ; main MSDOS interrupt
  111. STDIN               EQU       0              ; standard input
  112. STDOUT              EQU       1              ; standard output
  113. STDERR              EQU       2              ; error output
  114. STDAUX              EQU       3              ; COM port
  115. STDPRN              EQU       4              ; printer
  116. STRUC     HOOK
  117.           Vector    DB        ?              ; vector hooked into
  118.           OldISR    DD        ?              ; entry point to old ISR
  119.           NewISR    DD        ?              ; entry point to new ISR
  120. ENDS
  121. GLOBAL at : PROC
  122. GLOBAL errmsg : PROC
  123.    GLOBAL ProgName : BYTE                    ; needed for errmsg()
  124.    GLOBAL EOL : BYTE                         ; ditto
  125. GLOBAL fgetc : PROC
  126. GLOBAL fputc : PROC
  127. GLOBAL fputs : PROC
  128. GLOBAL getchar : PROC
  129. GLOBAL getdate : PROC
  130. GLOBAL getswtch : PROC
  131. GLOBAL gettime : PROC
  132. GLOBAL getvdos : PROC
  133. GLOBAL getvect : PROC
  134. GLOBAL isatty : PROC
  135. GLOBAL kbhit : PROC
  136. GLOBAL pause : PROC
  137. GLOBAL putchar : PROC
  138. GLOBAL setvect : PROC
  139. GLOBAL sleep : PROC
  140. GLOBAL fake_Env : PROC
  141. GLOBAL install_TSR : PROC
  142. GLOBAL uninstall_TSR : PROC
  143.  
  144. ;
  145. ; This section comes from Math.Inc.
  146. ;
  147. GLOBAL atoi : PROC
  148. GLOBAL atou : PROC
  149. GLOBAL utoa : PROC
  150.  
  151. ;
  152. ; This section comes from String.Inc.
  153. ;
  154. EOS                 EQU       0              ; terminates strings
  155. GLOBAL isdigit : PROC
  156. GLOBAL islower : PROC
  157. GLOBAL isupper : PROC
  158. GLOBAL iswhite : PROC
  159. GLOBAL strchr : PROC
  160. GLOBAL strcmp : PROC
  161. GLOBAL strlen : PROC
  162. GLOBAL tolower : PROC
  163. GLOBAL toupper : PROC
  164.  
  165.  
  166. VERSION   equ       '1.4b'                   ; current version of program
  167. ERRH      equ       1                        ; errorlevel if help given
  168. COUNT_UPP_LIMIT     equ       15             ; upper limit for rep count
  169.                                              ; NB: This limit has also
  170.                                              ;     been coded in HelpMsg
  171.  
  172.  
  173. %NEWPAGE
  174. ;--------------------------------------------------------------------------;
  175. ;                        C O D E    S E G M E N T                          ;
  176. ;--------------------------------------------------------------------------;
  177. CODESEG
  178.  
  179. ORG       80h                                ; commandline
  180. LABEL     CmdLen    BYTE
  181.           db        ?
  182. LABEL     CmdLine   BYTE
  183.           db        127 dup (?)
  184.  
  185. ORG       100h                               ; start of .COM file
  186. STARTUPCODE
  187.           jmp       main                     ; skip over data and stack
  188.  
  189. %NEWPAGE
  190. ;--------------------------------------------------------------------------;
  191. ;                               D A T A                                    ;
  192. ;--------------------------------------------------------------------------;
  193. LABEL     ProgName  BYTE
  194.           db        'ring: ', EOS
  195. LABEL     EOL       BYTE
  196.           db        '.', CR, LF, EOS
  197. LABEL     HelpMsg   BYTE
  198.           db        CR, LF
  199.           DB        'TifaWARE RING, v', VERSION, ', ', ??Date
  200.           db        ' - rings the console bell.', CR, LF
  201.           db        'Usage: ring [-options] [count]', CR, LF, LF
  202.           db        'Options:', CR, LF
  203.           db        '  -e = ring bell only if errorlevel is non-zero', CR, LF
  204.           db        '  -? = display this help message', CR, LF, LF
  205.           db        'count denotes a repetition count and must be between'
  206.           db        ' 0 and 15.', CR, LF
  207.           db        'The default value of count is 3.', CR, LF, EOS
  208.  
  209. LABEL     Err1Msg   BYTE
  210.           db        'illegal option -- '
  211. LABEL     OptCh     BYTE
  212.           db        ?
  213.           db        EOS
  214. LABEL     Err2Msg   BYTE
  215.           db        'invalid repetition count -- ', EOS
  216. LABEL     Err3Msg   BYTE
  217.           db        'unable to locate errorlevel', EOS
  218.  
  219. STRUC     ERRLOC                             ; structure holding addresses
  220.           vDos      DW        ?              ;    minor SHL 8 + major
  221.           Loc       DW        ?              ;    offset within segment
  222. ENDS
  223. ErrLocTbl ERRLOC    <30 SHL 8 + 3, 0beaH>    ; for DOS v3.30
  224.           ERRLOC    <00 SHL 8 + 4, 0f2bH>    ; for DOS v4.0
  225.           ERRLOC    <00 SHL 8 + 5, 02a3H>    ; for DOS v5.0
  226.           ERRLOC    <0, 0>                   ; >>>must be last<<<
  227.  
  228. SwitCh    db        '-'                      ; char introducing options
  229. EFlag     db        0                        ; flag for testing errorlevel
  230. HFlag     db        0                        ; flag for on-line help
  231. Count     db        3                        ; default number of rings
  232. RCode     db        0                        ; program return code
  233.  
  234.  
  235. %NEWPAGE
  236. ;--------------------------------------------------------------------------;
  237. ;                           P R O C E D U R E S                            ;
  238. ;--------------------------------------------------------------------------;
  239. ;----  get_ErrLvl  --------------------------------------------------------;
  240. ;  Purpose:    Gets errorlevel from previously executed program.           ;
  241. ;  Notes:      Thanks to Josep Fortiana Gregori (D3ESJFG0@EB0UB011) for    ;
  242. ;                 providing a code sample from which this proc was         ;
  243. ;                 derived and to Yan Juras for suggesting at which         ;
  244. ;                 offset to look for this value.                           ;
  245. ;  Requires:   8086-class CPU and DOS v3.30 or v4.0 (as sold in USA).      ;
  246. ;  Entry:      DS = PSP address of program (OK if not changed since        ;
  247. ;                   program started.                                       ;
  248. ;  Exit:       AL = errorlevel,                                            ;
  249. ;              cf = 1 if DOS version is unsupported or DOS not found.      ;
  250. ;  Calls:      getvdos                                                     ;
  251. ;  Changes:    AX,                                                         ;
  252. ;              flags                                                       ;
  253. ;--------------------------------------------------------------------------;
  254. PROC get_ErrLvl
  255.  
  256.           push      bp dx es
  257.  
  258. ; Make sure a supported version of DOS is being used.
  259.           call      getvdos                        ; AL = major version
  260.           mov       bp, OFFSET ErrLocTbl
  261.  
  262. @@NextVer:
  263.           cmp       [(ERRLOC PTR bp).vDOS], ax     ; supported version?
  264.           je        SHORT @@FindPSP                ;   yes
  265.           add       bp, SIZE ErrLocTbl             ;   no
  266.           cmp       [(ERRLOC PTR bp).vDOS], 0      ;     at end of table?
  267.           je        SHORT @@NoCanDo                ;       yes
  268.           jmp       SHORT @@NextVer                ;       no
  269.  
  270. ; Find the PSP for the version of COMMAND.COM which called us.
  271. ; This approach relies on the observation that COMMAND.COM 
  272. ; assigns its own PSP as the calling PSP at offset 16h.
  273. ;
  274. ;
  275. ; NB: Abort if calling PSP is above current PSP. This happens
  276. ; when running under an alternate shell like MKS Toolkit.
  277. @@FindPSP:
  278.           mov       ax, ds
  279.  
  280. @@LoopBack:
  281.           mov       es, ax
  282.           mov       dx, [es:16h]             ; get caller's PSP (undocumented)
  283.           xchg      ax, dx
  284.           cmp       ax, dx
  285.           jb        @@LoopBack
  286.           ja        SHORT @@NoCanDo          ; avoid infinite loop if no DOS
  287.  
  288.           clc                                ; signal no error
  289.           mov       bp, [(ERRLOC PTR bp).Loc]
  290.           mov       al, [es:bp]
  291.           jmp       SHORT @@Fin
  292.  
  293. @@NoCanDo:
  294.           stc                                ; signal an error
  295.  
  296. @@Fin:
  297.           pop       es dx bp
  298.           ret
  299. ENDP get_ErrLvl
  300.  
  301.  
  302. ;----  skip_Spaces  -------------------------------------------------------;
  303. ;  Purpose:    Skips past spaces in a string.                              ;
  304. ;  Notes:      Scanning stops with either a non-space *OR* CX = 0.         ;
  305. ;  Entry:      DS:SI = start of string to scan.                            ;
  306. ;  Exit:       AL = next non-space character,                              ;
  307. ;              CX is adjusted as necessary,                                ;
  308. ;              DS:SI = pointer to next non-space.                          ;
  309. ;  Calls:      none                                                        ;
  310. ;  Changes:    AL, CX, SI                                                  ;
  311. ;--------------------------------------------------------------------------;
  312. PROC skip_Spaces
  313.  
  314.           jcxz      SHORT @@Fin
  315. @@NextCh:
  316.           lodsb
  317.           cmp       al, ' '
  318.           loopz     @@NextCh
  319.           jz        SHORT @@Fin              ; CX = 0; don't adjust
  320.  
  321.           inc       cx                       ; adjust counters if cx > 0
  322.           dec       si
  323.  
  324. @@Fin:
  325.           ret
  326. ENDP skip_Spaces
  327.  
  328.  
  329. ;----  get_Opt  -----------------------------------------------------------;
  330. ;  Purpose:    Get a commandline option.                                   ;
  331. ;  Notes:      none                                                        ;
  332. ;  Entry:      AL = option character.                                      ;
  333. ;  Exit:       n/a                                                         ;
  334. ;  Calls:      tolower, errmsg, get_ErrLvl                                 ;
  335. ;  Changes:    AX, DX,                                                     ;
  336. ;              [OptCh], [HFlag], [EFlag], [RCode]                          ;
  337. ;--------------------------------------------------------------------------;
  338. PROC get_Opt
  339.  
  340.           mov       [OptCh], al              ; save for later
  341.           call      tolower                  ; use only lowercase in cmp.
  342.           cmp       al, 'e'
  343.           jz        SHORT @@OptE
  344.           cmp       al, '?'
  345.           jz        SHORT @@OptH
  346.           mov       dx, OFFSET Err1Msg       ; unrecognized option
  347.           call      errmsg                   ; then *** DROP THRU *** to OptH
  348.  
  349. ; Various possible options.
  350. @@OptH:
  351.           mov       [HFlag], 1               ; set help flag
  352.           jmp       SHORT @@Fin
  353.  
  354. @@OptE:
  355.           mov       [EFlag], 1               ; conditionally ring bell
  356.           call      get_ErrLvl               ; get earlier errorlevel
  357.           jnc       SHORT @@SaveErrLvl       ; continue; no problems
  358.           mov       dx, OFFSET Err3Msg       ; can't find errorlevel
  359.           call      errmsg
  360.           jmp       @@OptH
  361.  
  362. @@SaveErrLvl:
  363.           mov       [RCode], al              ; use it as our return code
  364.  
  365. @@Fin:
  366.           ret
  367. ENDP get_Opt
  368.  
  369.  
  370. ;----  get_Arg  -----------------------------------------------------------;
  371. ;  Purpose:    Gets a non-option from the set of commandline arguments.    ;
  372. ;  Notes:      Anything left on the commandline is user's message text.    ;
  373. ;  Entry:      CX = count of characters left in commandline,               ;
  374. ;              DS:SI = pointer to argument to process.                     ;
  375. ;  Exit:       CX = count of characters left _after_ processing,           ;
  376. ;              DS:SI = pointer to whitespace _after_ argument.             ;
  377. ;  Calls:      isdigit, fputs, atou                                        ;
  378. ;  Changes:    CX, DX, SI                                                  ;
  379. ;              [HFlag], [Count]                                            ;
  380. ;--------------------------------------------------------------------------;
  381. PROC get_Arg
  382.  
  383.           call      isdigit                  ; if not a digit, trouble!
  384.           jz        SHORT @@GetCount
  385.  
  386.           mov       dx, si                   ; flag arg as bad
  387.           xchg      di, si
  388.           mov       al, ' '
  389.           repne     scasb                    ; find end of argument
  390.           xchg      di, si
  391.           jne       SHORT @@BadCount
  392.           dec       si                       ; overshot so back up 1 char
  393.           inc       cx
  394.           jmp       SHORT @@BadCount         ; tell user it's bad
  395.  
  396. @@GetCount:
  397.           mov       dx, si                   ; save to adjust CX and if error
  398.           call      atou
  399.           pushf                              ; preserve flags
  400.           add       cx, dx                   ; adjust counter
  401.           sub       cx, si
  402.           popf                               ; restore flags
  403.           jc        SHORT @@BadCount         ; error in conversion?
  404.           cmp       ax, COUNT_UPP_LIMIT      ; too big?
  405.           ja        SHORT @@BadCount         ;   yes
  406.           mov       [Count], al
  407.           jmp       SHORT @@Fin
  408.  
  409. @@BadCount:
  410.           push      dx
  411.           mov       bl, STDERR
  412.           mov       dx, OFFSET ProgName
  413.           call      fputs
  414.           mov       dx, OFFSET Err2Msg
  415.           call      fputs
  416.           pop       dx
  417.           mov       al, [si]                 ; save next non-digit
  418.           mov       [BYTE PTR si], EOS       ; replace with EOS
  419.           call      fputs
  420.           mov       [si], al                 ; restore it
  421.           mov       dx, OFFSET EOL
  422.           call      fputs
  423.           mov       [HFlag], 1
  424.           jmp       SHORT @@Fin
  425.  
  426. @@Fin:
  427.           ret
  428. ENDP get_Arg
  429.  
  430.  
  431. ;----  process_CmdLine  ---------------------------------------------------;
  432. ;  Purpose:    Processes commandline arguments.                            ;
  433. ;  Notes:      A switch character by itself is ignored.                    ;
  434. ;              No arguments whatsoever causes help flag to be set.         ;
  435. ;  Entry:      n/a                                                         ;
  436. ;  Exit:       n/a                                                         ;
  437. ;  Calls:      skip_Spaces, get_Opt, get_Arg                               ;
  438. ;  Changes:    AX, CX, SI,                                                 ;
  439. ;              DX (get_Arg),                                               ;
  440. ;              [OptCh], [HFlag], [EFlag] (get_Opt),                        ;
  441. ;              [Count], (get_Arg),                                         ;
  442. ;              Direction flag is cleared.                                  ;
  443. ;--------------------------------------------------------------------------;
  444. PROC process_CmdLine
  445.  
  446.           cld                                ; forward, march!
  447.           ZERO      ch
  448.           mov       cl, [CmdLen]             ; length of commandline
  449.           mov       si, OFFSET CmdLine       ; offset to start of commandline
  450.  
  451.           call      skip_Spaces              ; check if any args supplied
  452.           or        cl, cl
  453.           jnz       SHORT @@ArgLoop
  454.           jmp       SHORT @@Fin
  455.  
  456. ; For each blank-delineated argument on the commandline...
  457. @@ArgLoop:
  458.           lodsb                              ; next character
  459.           dec       cl
  460.           cmp       al, [SwitCh]             ; is it the switch character?
  461.           jnz       SHORT @@NonOpt           ;   no
  462.  
  463. ; Isolate each option and process it. Stop when a space is reached.
  464. @@OptLoop:
  465.           jcxz      SHORT @@Fin              ; abort if nothing left
  466.           lodsb
  467.           dec       cl
  468.           cmp       al, ' '
  469.           jz        SHORT @@NextArg          ; abort when space reached
  470.           call      get_Opt
  471.           jmp       @@OptLoop
  472.  
  473. ; Process the current argument, which is *not* an option.
  474. ; Then, *drop thru* to advance to next argument.
  475. @@NonOpt:
  476.           dec       si                       ; back up one character
  477.           inc       cl
  478.           call      get_Arg
  479.  
  480. ; Skip over spaces until next argument is reached.
  481. @@NextArg:
  482.           call      skip_Spaces
  483.           or        cl, cl
  484.           jnz       @@ArgLoop
  485.  
  486. @@Fin:
  487.           ret
  488. ENDP process_CmdLine
  489.  
  490.  
  491. ;--------------------------------------------------------------------------;
  492. ;                         E N T R Y   P O I N T                            ;
  493. ;--------------------------------------------------------------------------;
  494. ;----  main  --------------------------------------------------------------;
  495. ;  Purpose:    Main section of program.                                    ;
  496. ;  Notes:      none                                                        ;
  497. ;  Entry:      Arguments as desired                                        ;
  498. ;  Exit:       Return code as follows:                                     ;
  499. ;                   0 => program ran successfully                          ;
  500. ;                   1 => on-line help requested                            ;
  501. ;              or whatever previous errorlevel was if '-e' option used.    ;
  502. ;  Calls:      process_CmdLine, fputs, putchar                             ;
  503. ;  Changes:    n/a                                                         ;
  504. ;--------------------------------------------------------------------------;
  505. main:
  506.  
  507. ; Process commandline arguments. If the variable HFlag is set, then
  508. ; on-line help is displayed and the program immediately terminates.
  509.           call      process_CmdLine          ; process commandline args
  510.  
  511.           cmp       [HFlag], 0               ; is help needed?
  512.           jz        SHORT @@NoHelp           ;   no
  513.           mov       [RCode], ERRH            ;   yes, so set return code
  514.           mov       bx, STDERR
  515.           mov       dx, OFFSET HelpMsg       ;     point to help message
  516.           call      fputs                    ;     display it
  517.           jmp       SHORT @@Fin              ;     and jump to end of program
  518.  
  519. ; Figure out whether to ring bell conditionally.
  520. @@NoHelp:
  521.           cmp       [EFlag], 0               ; is it conditional?
  522.           jz        SHORT @@RingBell         ;   no
  523.           cmp       [RCode], 0               ;   yes, was errorlevel 0?
  524.           jz        SHORT @@Fin              ;     yes, no bell
  525.  
  526. ; Determine how many times to ring the bell and do it.
  527. @@RingBell:
  528.           mov       cl, [Count]              ; get the count
  529.           ZERO      ch                       ; zero out high byte of word
  530.           jcxz      SHORT @@Fin
  531.           mov       dl, BELL
  532. @@RingLoop:
  533.           call      putchar
  534.           loop      @@RingLoop               ; repeat as necessary
  535.  
  536. ; Ok, let's terminate the program and exit with proper return code.
  537. @@Fin:
  538.           mov       al, [RCode]
  539.           mov       ah, 4ch
  540.           int       DOS
  541.  
  542. EVEN
  543. Buffer   db    ?                          ; space for single character
  544.                                           ; nb: shared by fgetc() & fputc()
  545.  
  546.  
  547. ;-------------------------------------------------------------------------;
  548. ;  Purpose:    Reads a character from specified device.
  549. ;  Notes:      No checks are done on BX's validity.
  550. ;              Buffer is shared by fputc(). Do *NOT* use in a 
  551. ;                 multitasking environment like DESQview.
  552. ;  Requires:   8086-class CPU and DOS v2.0 or better.
  553. ;  Entry:      BX = device handle.
  554. ;  Exit:       AL = character,
  555. ;              Carry flag set on error (AX holds error code).
  556. ;  Calls:      none
  557. ;  Changes:    AX
  558. ;              flags
  559. ;-------------------------------------------------------------------------;
  560. PROC fgetc
  561.  
  562.    push     cx dx
  563. IF @DataSize NE 0
  564.    push     ds
  565.    mov      ax, @data
  566.    mov      ds, ax
  567. ENDIF
  568.  
  569.    mov      dx, OFFSET Buffer             ; point to storage
  570.    mov      cx, 1                         ; only need 1 char
  571.    mov      ah, 3fh
  572.    int      DOS                           ; get it
  573.    jc       SHORT @@Fin                   ; abort on error
  574.    mov      al, [Buffer]
  575.  
  576. @@Fin:
  577. IF @DataSize NE 0
  578.    pop      ds
  579. ENDIF
  580.    pop      dx cx
  581.    ret
  582.  
  583. ENDP fgetc
  584.  
  585.  
  586. ;-------------------------------------------------------------------------;
  587. ;  Purpose:    Writes a character to specified device.
  588. ;  Notes:      No checks are done on BX's validity.
  589. ;              Buffer is shared by fputc(). Do *NOT* use in a 
  590. ;                 multitasking environment like DESQview.
  591. ;  Requires:   8086-class CPU and DOS v2.0 or better.
  592. ;  Entry:      AL = character to display,
  593. ;              BX = device handle.
  594. ;  Exit:       AL = 1 if successful,
  595. ;              Carry flag set on error (AX holds error code).
  596. ;  Calls:      none
  597. ;  Changes:    AX
  598. ;-------------------------------------------------------------------------;
  599. PROC fputc
  600.  
  601.    push     cx dx
  602. IF @DataSize NE 0
  603.    push     ds
  604.    mov      dx, @data
  605.    mov      ds, ax
  606. ENDIF
  607.  
  608.    mov      dx, OFFSET Buffer             ; point to storage
  609.    mov      [Buffer], al                  ; save char
  610.    mov      cx, 1                         ; only write 1 char
  611.    mov      ah, 40h
  612.    int      DOS
  613.  
  614. IF @DataSize NE 0
  615.    pop      ds
  616. ENDIF
  617.    pop      dx cx
  618.    ret
  619.  
  620. ENDP fputc
  621.  
  622.  
  623. ;-------------------------------------------------------------------------;
  624. ;  Purpose:    Reads a character from STDIN.
  625. ;  Notes:      Character is echoed to display.
  626. ;  Requires:   8086-class CPU and DOS v1.0 or better.
  627. ;  Entry:      n/a
  628. ;  Exit:       AL = character.
  629. ;  Calls:      none
  630. ;  Changes:    AX
  631. ;-------------------------------------------------------------------------;
  632. PROC getchar
  633.  
  634.    mov      ah, 1
  635.    int      DOS
  636.    ret
  637.  
  638. ENDP getchar
  639.  
  640.  
  641. ;-------------------------------------------------------------------------;
  642. ;  Purpose:    Writes a character to STDOUT device.
  643. ;  Notes:      none
  644. ;  Requires:   8086-class CPU and DOS v1.0 or better.
  645. ;  Entry:      DL = character to display.
  646. ;  Exit:       n/a
  647. ;  Calls:      none
  648. ;  Changes:    none
  649. ;-------------------------------------------------------------------------;
  650. PROC putchar
  651.  
  652.    push     ax
  653.    mov      ah, 2
  654.    int      DOS
  655.    pop      ax
  656.    ret
  657.  
  658. ENDP putchar
  659.  
  660.  
  661. ;-------------------------------------------------------------------------;
  662. ;  Purpose:    Checks if a character is ready for input from STDIN.
  663. ;  Notes:      none
  664. ;  Requires:   8086-class CPU and DOS v1.0 or better.
  665. ;  Entry:      n/a
  666. ;  Exit:       zf = 1 if character available.
  667. ;  Calls:      none
  668. ;  Changes:    flags
  669. ;-------------------------------------------------------------------------;
  670. PROC kbhit
  671.  
  672.    push     ax
  673.    mov      ah, 0bh
  674.    int      DOS
  675.    cmp      al, 0ffh                      ; AL = FFh if character ready
  676.    pop      ax
  677.    ret
  678.  
  679. ENDP kbhit
  680.  
  681.  
  682. EVEN
  683. ;-------------------------------------------------------------------------;
  684. ;  Purpose:    Writes an ASCIIZ string to specified device.
  685. ;  Notes:      A zero-length string doesn't seem to cause problems when
  686. ;                 this output function is used.
  687. ;  Requires:   8086-class CPU and DOS v2.0 or better.
  688. ;  Entry:      BX = device handle,
  689. ;              DS:DX = pointer to string.
  690. ;  Exit:       Carry flag set if EOS wasn't found or handle is invalid.
  691. ;  Calls:      strlen
  692. ;  Changes:    none
  693. ;-------------------------------------------------------------------------;
  694. PROC fputs
  695.  
  696.    push     ax cx di
  697. IF @DataSize NE 0
  698.    push     es
  699.    mov      ax, ds
  700.    mov      es, ax
  701. ENDIF
  702.    mov      di, dx
  703.    call     strlen                        ; set CX = length of string
  704.    jc       SHORT @@Fin                   ; abort if problem finding end
  705.    mov      ah, 40h                       ; MS-DOS raw output function
  706.    int      DOS
  707. @@Fin:
  708. IF @DataSize NE 0
  709.    pop      es
  710. ENDIF
  711.    pop      di cx ax
  712.    ret
  713.  
  714. ENDP fputs
  715.  
  716.  
  717. EVEN
  718. ;-------------------------------------------------------------------------;
  719. ;  Purpose:    Writes an error message to stderr.
  720. ;  Notes:      none
  721. ;  Requires:   8086-class CPU and DOS v2.0 or better.
  722. ;  Entry:      DS:DX = pointer to error message.
  723. ;  Exit:       n/a
  724. ;  Calls:      fputs
  725. ;  Changes:    none
  726. ;-------------------------------------------------------------------------;
  727. PROC errmsg
  728.  
  729.    push     bx dx
  730.    mov      bx, STDERR
  731.    mov      dx, OFFSET ProgName           ; display program name
  732.    call     fputs
  733.    pop      dx                            ; recover calling parameters
  734.    push     dx                            ; and save again to avoid change
  735.    call     fputs                         ; display error message
  736.    mov      dx, OFFSET EOL
  737.    call     fputs
  738.    pop      dx bx
  739.    ret
  740.  
  741. ENDP errmsg
  742.  
  743.  
  744. EVEN
  745. ;-------------------------------------------------------------------------;
  746. ;  Purpose:    Gets version of DOS currently running.
  747. ;  Notes:      none
  748. ;  Requires:   8086-class CPU and DOS v2.0 or better.
  749. ;  Entry:      n/a
  750. ;  Exit:       AL = major version number,
  751. ;              AH = minor version number (2.1 = 10).
  752. ;  Calls:      none
  753. ;  Changes:    AX
  754. ;-------------------------------------------------------------------------;
  755. PROC getvdos
  756.  
  757.    push     bx cx                         ; DOS destroys bx and cx!
  758.    mov      ah, 30h
  759.    int      DOS
  760.    pop      cx bx
  761.    ret
  762.  
  763. ENDP getvdos
  764.  
  765.  
  766. EVEN
  767. ;-------------------------------------------------------------------------;
  768. ;  Purpose:    Converts string of digits to an *unsigned* integer in
  769. ;              range [0, 65535].
  770. ;  Notes:      Conversion stops with first non-numeric character.
  771. ;  Requires:   8086-class CPU.
  772. ;  Entry:      DS:SI = pointer to string of digits.
  773. ;  Exit:       AX = unsigned integer (garbage if cf = 1),
  774. ;              DS:SI = pointer to first non-digit found,
  775. ;              cf = 1 if number is too big.
  776. ;  Calls:      none
  777. ;  Changes:    AX, SI
  778. ;              flags
  779. ;-------------------------------------------------------------------------;
  780. PROC atou
  781.  
  782.    push     bx cx dx                      ; DX destroyed by MUL below
  783.    ZERO     ax                            ; AX = digit to convert
  784.    ZERO     bx                            ; BX = integer word
  785.    mov      cx, 10                        ; CX = conversion factor
  786.  
  787. @@NextCh:
  788.    mov      bl, [si]                      ; get character
  789.    cmp      bl, '0'                       ; test if a digit
  790.    jb       SHORT @@Fin
  791.    cmp      bl, '9'
  792.    ja       SHORT @@Fin
  793.    inc      si                            ; bump up pointer
  794.    mul      cx                            ; multiply old result by 10
  795.    jc       SHORT @@Overflow
  796.    sub      bl, '0'                       ; convert digit
  797.    add      ax, bx                        ; add current value
  798.    jnc      @@NextCh                      ; continue unless result too big
  799.  
  800. @@Overflow:
  801.    ZERO     cx                            ; denotes overflow
  802.    jmp      @@NextCh
  803.  
  804. @@Fin:
  805.    cmp      cx, 10                        ; cf = (cx != 10)
  806.    pop      dx cx bx
  807.    ret
  808.  
  809. ENDP atou
  810.  
  811.  
  812. EVEN
  813. ;-------------------------------------------------------------------------;
  814. ;  Purpose:    Tests if character is a valid ASCII digit.
  815. ;  Notes:      none
  816. ;  Requires:   8086-class CPU.
  817. ;  Entry:      AL = character to be tested.
  818. ;  Exit:       Zero flag set if true, cleared otherwise.
  819. ;  Calls:      none 
  820. ;  Changes:    flags
  821. ;-------------------------------------------------------------------------;
  822. PROC isdigit
  823.  
  824.    cmp      al, '0'                       ; if < '0' zf = 0
  825.    jb       SHORT @@Fin
  826.    cmp      al, '9'                       ; if > '9' zf = 0
  827.    ja       SHORT @@Fin
  828.    cmp      al, al                        ; set Z flag
  829. @@Fin:
  830.    ret
  831.  
  832. ENDP isdigit
  833.  
  834.  
  835. ;-------------------------------------------------------------------------;
  836. ;  Purpose:    Tests if character is lowercase.
  837. ;  Notes:      none
  838. ;  Requires:   8086-class CPU.
  839. ;  Entry:      AL = character to be tested.
  840. ;  Exit:       Zero flag set if true, cleared otherwise.
  841. ;  Calls:      none 
  842. ;  Changes:    flags
  843. ;-------------------------------------------------------------------------;
  844. PROC islower
  845.  
  846.    cmp      al, 'a'                       ; if < 'a' zf = 0
  847.    jb       SHORT @@Fin
  848.    cmp      al, 'z'                       ; if > 'z' zf = 0
  849.    ja       SHORT @@Fin
  850.    cmp      al, al                        ; set Z flag
  851. @@Fin:
  852.    ret
  853.  
  854. ENDP islower
  855.  
  856.  
  857. ;-------------------------------------------------------------------------;
  858. ;  Purpose:    Tests if character is uppercase.
  859. ;  Notes:      none
  860. ;  Requires:   8086-class CPU.
  861. ;  Entry:      AL = character to be tested.
  862. ;  Exit:       Zero flag set if true, cleared otherwise.
  863. ;  Calls:      none 
  864. ;  Changes:    flags
  865. ;-------------------------------------------------------------------------;
  866. PROC isupper
  867.  
  868.    cmp      al, 'A'                       ; if < 'A' zf = 0
  869.    jb       SHORT @@Fin
  870.    cmp      al, 'Z'                       ; if > 'Z' zf = 0
  871.    ja       SHORT @@Fin
  872.    cmp      al, al                        ; set Z flag
  873. @@Fin:
  874.    ret
  875.  
  876. ENDP isupper
  877.  
  878.  
  879. ;-------------------------------------------------------------------------;
  880. ;  Purpose:    Tests if character is an ASCII whitespace.
  881. ;  Notes:      none
  882. ;  Requires:   8086-class CPU.
  883. ;  Entry:      AL = character to be tested.
  884. ;  Exit:       Zero flag set if true, cleared otherwise.
  885. ;  Calls:      none 
  886. ;  Changes:    flags
  887. ;-------------------------------------------------------------------------;
  888. PROC iswhite
  889.  
  890.    cmp      al, SPACE                     ; if == SPACE then zf = 1
  891.    jz       SHORT @@Fin
  892.    cmp      al, TAB                       ; if == TAB then zf = 1
  893.    jz       SHORT @@Fin
  894.    cmp      al, LF                        ; if == LF then zf = 1
  895.    jz       SHORT @@Fin
  896.    cmp      al, CR                        ; if == CR then zf = 1
  897. @@Fin:
  898.    ret
  899.  
  900. ENDP iswhite
  901.  
  902.  
  903. EVEN
  904. ;-------------------------------------------------------------------------;
  905. ;  Purpose:    Converts character to lowercase.
  906. ;  Notes:      none
  907. ;  Requires:   8086-class CPU.
  908. ;  Entry:      AL = character to be converted.
  909. ;  Exit:       AL = converted character.
  910. ;  Calls:      none
  911. ;  Changes:    AL
  912. ;              flags
  913. ;-------------------------------------------------------------------------;
  914. PROC tolower
  915.  
  916.    cmp      al, 'A'                       ; if < 'A' then done
  917.    jb       SHORT @@Fin
  918.    cmp      al, 'Z'                       ; if > 'Z' then done
  919.    ja       SHORT @@Fin
  920.    or       al, 20h                       ; make it lowercase
  921. @@Fin:
  922.    ret
  923.  
  924. ENDP tolower
  925.  
  926.  
  927. ;-------------------------------------------------------------------------;
  928. ;  Purpose:    Converts character to uppercase.
  929. ;  Notes:      none
  930. ;  Requires:   8086-class CPU.
  931. ;  Entry:      AL = character to be converted.
  932. ;  Exit:       AL = converted character.
  933. ;  Calls:      none
  934. ;  Changes:    AL
  935. ;              flags
  936. ;-------------------------------------------------------------------------;
  937. PROC toupper
  938.  
  939.    cmp      al, 'a'                       ; if < 'a' then done
  940.    jb       SHORT @@Fin
  941.    cmp      al, 'z'                       ; if > 'z' then done
  942.    ja       SHORT @@Fin
  943.    and      al, not 20h                   ; make it lowercase
  944. @@Fin:
  945.    ret
  946.  
  947. ENDP toupper
  948.  
  949.  
  950. EVEN
  951. ;-------------------------------------------------------------------------;
  952. ;  Purpose:    Calculates length of an ASCIIZ string.
  953. ;  Notes:      Terminal char is _not_ included in the count.
  954. ;  Requires:   8086-class CPU.
  955. ;  Entry:      ES:DI = pointer to string.
  956. ;  Exit:       CX = length of string,
  957. ;              cf = 0 and zf = 1 if EOS found,
  958. ;              cf = 1 and zf = 0 if EOS not found within segment.
  959. ;  Calls:      none
  960. ;  Changes:    CX,
  961. ;              flags
  962. ;-------------------------------------------------------------------------;
  963. PROC strlen
  964.  
  965.    push     ax di
  966.    pushf
  967.    cld                                    ; scan forward only
  968.    mov      al, EOS                       ; character to search for
  969.    mov      cx, di                        ; where are we now
  970.    not      cx                            ; what's left in segment - 1
  971.    push     cx                            ; save char count
  972.    repne    scasb
  973.    je       SHORT @@Done
  974.    scasb                                  ; test final char
  975.    dec      cx                            ; avoids trouble with "not" below
  976.  
  977. @@Done:
  978.    pop      ax                            ; get original count
  979.    sub      cx, ax                        ; subtract current count
  980.    not      cx                            ; and invert it
  981.    popf                                   ; restore df
  982.    dec      di
  983.    cmp      [BYTE PTR es:di], EOS
  984.    je       SHORT @@Fin                   ; cf = 0 if equal
  985.    stc                                    ; set cf => error
  986.  
  987. @@Fin:
  988.    pop      di ax
  989.    ret
  990.  
  991. ENDP strlen
  992.  
  993.  
  994. END
  995.