home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / UTILITY / BATCH / RING13.ZIP / RING.ASM < prev    next >
Encoding:
Assembly Source File  |  1990-10-28  |  28.8 KB  |  754 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. ;--------------------------------------------------------------------------;
  23.  
  24. ;--------------------------------------------------------------------------;
  25. ;  Author:     George A. Theall                                            ;
  26. ;  Phone:      +1 215 662 0558                                             ;
  27. ;  SnailMail:  TifaWARE                                                    ;
  28. ;              506 South 41st St., #3M                                     ;
  29. ;              Philadelphia, PA.  19104   USA                              ;
  30. ;  E-Mail:     GTHEALL@PENNDRLS.UPENN.EDU (Internet)                       ;
  31. ;--------------------------------------------------------------------------;
  32.  
  33. ;--------------------------------------------------------------------------;
  34. ;                          D I R E C T I V E S                             ;
  35. ;--------------------------------------------------------------------------;
  36. DOSSEG
  37. MODEL     tiny
  38.  
  39. IDEAL
  40. LOCALS
  41. JUMPS
  42.  
  43. ;
  44. ; This section comes from D:\ASM\INCLUDE\Equates.Inc.
  45. ;
  46. EOS                 EQU       0              ; terminates strings
  47. BELL                EQU       7
  48. BS                  EQU       8
  49. TAB                 EQU       9
  50. CR                  EQU       13
  51. LF                  EQU       10
  52. ESCAPE              EQU       27             ; nb: ESC is a TASM keyword
  53. SPACE               EQU       ' '
  54. KEY_F1              EQU       3bh
  55. KEY_F2              EQU       3ch
  56. KEY_F3              EQU       3dh
  57. KEY_F4              EQU       3eh
  58. KEY_F5              EQU       3fh
  59. KEY_F6              EQU       40h
  60. KEY_F7              EQU       41h
  61. KEY_F8              EQU       42h
  62. KEY_F9              EQU       43h
  63. KEY_F10             EQU       44h
  64. KEY_HOME            EQU       47h
  65. KEY_UP              EQU       48h
  66. KEY_PGUP            EQU       49h
  67. KEY_LEFT            EQU       4bh
  68. KEY_RIGHT           EQU       4dh
  69. KEY_END             EQU       4fh
  70. KEY_DOWN            EQU       50h
  71. KEY_PGDN            EQU       51h
  72. KEY_INS             EQU       52h
  73. KEY_DEL             EQU       53h
  74. KEY_C_F1            EQU       5eh
  75. KEY_C_F2            EQU       5fh
  76. KEY_C_F3            EQU       60h
  77. KEY_C_F4            EQU       61h
  78. KEY_C_F5            EQU       62h
  79. KEY_C_F6            EQU       63h
  80. KEY_C_F7            EQU       64h
  81. KEY_C_F8            EQU       65h
  82. KEY_C_F9            EQU       66h
  83. KEY_C_F10           EQU       67h
  84. KEY_C_LEFT          EQU       73h
  85. KEY_C_RIGHT         EQU       74h
  86. KEY_C_END           EQU       75h
  87. KEY_C_PGDN          EQU       76h
  88. KEY_C_HOME          EQU       77h
  89. KEY_C_PGUP          EQU       84h
  90. KEY_F11             EQU       85h
  91. KEY_F12             EQU       86h
  92. KEY_C_F11           EQU       89h
  93. KEY_C_F12           EQU       8ah
  94. DOS                 EQU       21h            ; main MSDOS interrupt
  95. STDIN               EQU       0              ; standard input
  96. STDOUT              EQU       1              ; standard output
  97. STDERR              EQU       2              ; error output
  98. STDAUX              EQU       3              ; COM port
  99. STDPRN              EQU       4              ; printer
  100.  
  101. ;
  102. ; This section comes from D:\ASM\INCLUDE\Macros.Inc.
  103. ;
  104. MACRO    Pop_M    RegList                    ;; Pops registers off stack.
  105.    IRP      Reg, <RegList>
  106.       IFIDNI   <Reg>, <flags>
  107.          popf
  108.       ELSE
  109.          pop      Reg
  110.       ENDIF
  111.    ENDM
  112. ENDM
  113. MACRO    Push_M   RegList                    ;; Pushes registers onto stack.
  114.    IRP      Reg, <RegList>
  115.       IFIDNI   <Reg>, <flags>
  116.          pushf
  117.       ELSE
  118.          push     Reg
  119.       ENDIF
  120.    ENDM
  121. ENDM
  122. MACRO    Zero     Reg                        ;; Zeros any register.
  123.          xor      Reg, Reg
  124. ENDM
  125.  
  126.  
  127. ERRH                 equ      1              ; errorlevel if help given
  128. COUNT_UPP_LIMIT      equ      15             ; upper limit for rep count
  129.                                              ; NB: This limit has also
  130.                                              ;     been coded in HelpMsg
  131.  
  132.  
  133. ;--------------------------------------------------------------------------;
  134. ;                        C O D E    S E G M E N T                          ;
  135. ;--------------------------------------------------------------------------;
  136. CODESEG
  137.  
  138. ORG       80h                                ; commandline
  139. LABEL     CmdLen    BYTE
  140.           db        ?
  141. LABEL     CmdLine   BYTE
  142.           db        127 dup (?)
  143.  
  144. ORG       100h                               ; start of .COM file
  145. STARTUPCODE
  146.           jmp       main                     ; skip over data and stack
  147.  
  148. ;--------------------------------------------------------------------------;
  149. ;                               D A T A                                    ;
  150. ;--------------------------------------------------------------------------;
  151. LABEL     ProgName  BYTE
  152.           db        'ring: ', EOS
  153. LABEL     EOL       BYTE
  154.           db        '.', CR, LF, EOS
  155. LABEL     HelpMsg   BYTE
  156.           db        CR, LF
  157.           db        'TifaWARE RING, v1.3a, ', ??Date
  158.           db        ' - rings the console bell.', CR, LF
  159.           db        'Usage: ring [-options] [count]', CR, LF, LF
  160.           db        'Options:', CR, LF
  161.           db        '  -e = ring bell only if errorlevel is non-zero', CR, LF
  162.           db        '  -? = display this help message', CR, LF, LF
  163.           db        'count denotes a repetition count and must be between'
  164.           db        ' 0 and 15.', CR, LF
  165.           db        'The default value of count is 3.', CR, LF, EOS
  166.  
  167. LABEL     Err1Msg   BYTE
  168.           db        'illegal option -- '
  169. LABEL     OptCh     BYTE
  170.           db        ?
  171.           db        EOS
  172. LABEL     Err2Msg   BYTE
  173.           db        'invalid repetition count -- ', EOS
  174. LABEL     Err3Msg   BYTE
  175.           db        'unable to locate errorlevel', EOS
  176.  
  177. SwitCh    db        '-'                      ; char introducing options
  178. EFlag     db        0                        ; flag for testing errorlevel
  179. HFlag     db        0                        ; flag for on-line help
  180. Count     db        3                        ; default number of rings
  181. RCode     db        0                        ; program return code
  182.  
  183.  
  184. ;--------------------------------------------------------------------------;
  185. ;                          L O C A L   S T A C K                           ;
  186. ;--------------------------------------------------------------------------;
  187.           db        16 dup("STACK   ")       ; 128 bytes for local stack
  188. StackTop  =         $
  189.  
  190.  
  191. ;--------------------------------------------------------------------------;
  192. ;                           P R O C E D U R E S                            ;
  193. ;--------------------------------------------------------------------------;
  194. ;----  get_ErrLvl  --------------------------------------------------------;
  195. ;  Purpose:    Gets errorlevel from previously executed program.           ;
  196. ;  Notes:      Thanks to Josep Fortiana Gregori (D3ESJFG0@EB0UB011) for    ;
  197. ;                 providing a code sample from which this proc was         ;
  198. ;                 derived and to Yan Juras for suggesting at which         ;
  199. ;                 offset to look for this value.                           ;
  200. ;  Requires:   8086-class CPU and DOS v3.30 (as sold in USA).              ;
  201. ;  Entry:      DS = PSP address of program (OK if not changed since        ;
  202. ;                   program started.                                       ;
  203. ;  Exit:       AL = errorlevel,                                            ;
  204. ;              cf = 1 if DOS version is unsupported or DOS not found.      ;
  205. ;  Calls:      getvdos                                                     ;
  206. ;  Changes:    AX,                                                         ;
  207. ;              flags                                                       ;
  208. ;--------------------------------------------------------------------------;
  209. PROC get_ErrLvl
  210.  
  211.           Push_M    <dx, es>
  212.  
  213.           call      getvdos                  ; make sure it's DOS v3.30
  214.           cmp       al, 3
  215.           jnz       SHORT @@NoCanDo
  216.           cmp       ah, 30
  217.           jnz       SHORT @@NoCanDo
  218.  
  219. ;
  220. ; Find the PSP for the version of COMMAND.COM which called us.
  221. ; This approach relies on the observation that COMMAND.COM 
  222. ; assigns its own PSP as the calling PSP at offset 16h.
  223. ;
  224. ;
  225. ; NB: Abort if calling PSP is above current PSP. This happens
  226. ; when running under an alternate shell like MKS Toolkit.
  227. ;
  228.           mov       ax, ds
  229.  
  230. @@LoopBack:
  231.           mov       es, ax
  232.           mov       dx, [es:16h]             ; get caller's PSP (undocumented)
  233.           xchg      ax, dx
  234.           cmp       ax, dx
  235.           jb        @@LoopBack
  236.           ja        SHORT @@NoCanDo          ; avoid infinite loop if no DOS
  237.  
  238.           clc                                ; signal no error
  239.           mov       al, [es:0beah]           ; it works!
  240.           jmp       SHORT @@Fin
  241.  
  242. @@NoCanDo:
  243.           stc                                ; signal an error
  244.  
  245. @@Fin:
  246.           Pop_M     <es, dx>
  247.           ret
  248. ENDP get_ErrLvl
  249.  
  250.  
  251. ;----  skip_Spaces  -------------------------------------------------------;
  252. ;  Purpose:    Skips past spaces in a string.                              ;
  253. ;  Notes:      Scanning stops with either a non-space *OR* CX = 0.         ;
  254. ;  Entry:      DS:SI = start of string to scan.                            ;
  255. ;  Exit:       AL = next non-space character,                              ;
  256. ;              CX is adjusted as necessary,                                ;
  257. ;              DS:SI = pointer to next non-space.                          ;
  258. ;  Calls:      none                                                        ;
  259. ;  Changes:    AL, CX, SI                                                  ;
  260. ;--------------------------------------------------------------------------;
  261. PROC skip_Spaces
  262.  
  263.           jcxz      SHORT @@Fin
  264. @@NextCh:
  265.           lodsb
  266.           cmp       al, ' '
  267.           loopz     @@NextCh
  268.           jz        SHORT @@Fin              ; CX = 0; don't adjust
  269.  
  270.           inc       cx                       ; adjust counters if cx > 0
  271.           dec       si
  272.  
  273. @@Fin:
  274.           ret
  275. ENDP skip_Spaces
  276.  
  277.  
  278. ;----  get_Opt  -----------------------------------------------------------;
  279. ;  Purpose:    Get a commandline option.                                   ;
  280. ;  Notes:      none                                                        ;
  281. ;  Entry:      AL = option character.                                      ;
  282. ;  Exit:       n/a                                                         ;
  283. ;  Calls:      tolower, errmsg, get_ErrLvl                                 ;
  284. ;  Changes:    AX, DX,                                                     ;
  285. ;              [OptCh], [HFlag], [EFlag], [RCode]                          ;
  286. ;--------------------------------------------------------------------------;
  287. PROC get_Opt
  288.  
  289.           mov       [OptCh], al              ; save for later
  290.           call      tolower                  ; use only lowercase in cmp.
  291.           cmp       al, 'e'
  292.           jz        SHORT @@OptE
  293.           cmp       al, '?'
  294.           jz        SHORT @@OptH
  295.           mov       dx, OFFSET Err1Msg       ; unrecognized option
  296.           call      errmsg                   ; then *** DROP THRU *** to OptH
  297.  
  298. ;
  299. ; Various possible options.
  300. ;
  301. @@OptH:
  302.           mov       [HFlag], 1               ; set help flag
  303.           jmp       SHORT @@Fin
  304.  
  305. @@OptE:
  306.           mov       [EFlag], 1               ; conditionally ring bell
  307.           call      get_ErrLvl               ; get earlier errorlevel
  308.           jnc       SHORT @@SaveErrLvl       ; continue; no problems
  309.           mov       dx, OFFSET Err3Msg       ; can't find errorlevel
  310.           call      errmsg
  311.           jmp       @@OptH
  312.  
  313. @@SaveErrLvl:
  314.           mov       [RCode], al              ; use it as our return code
  315.  
  316. @@Fin:
  317.           ret
  318. ENDP get_Opt
  319.  
  320.  
  321. ;----  get_Arg  -----------------------------------------------------------;
  322. ;  Purpose:    Gets a non-option from the set of commandline arguments.    ;
  323. ;  Notes:      Anything left on the commandline is user's message text.    ;
  324. ;  Entry:      CX = count of characters left in commandline,               ;
  325. ;              DS:SI = pointer to argument to process.                     ;
  326. ;  Exit:       CX = count of characters left _after_ processing,           ;
  327. ;              DS:SI = pointer to whitespace _after_ argument.             ;
  328. ;  Calls:      isdigit, fputs, atou                                        ;
  329. ;  Changes:    CX, DX, SI                                                  ;
  330. ;              [HFlag], [Count]                                            ;
  331. ;--------------------------------------------------------------------------;
  332. PROC get_Arg
  333.  
  334.           call      isdigit                  ; if not a digit, trouble!
  335.           jz        SHORT @@GetCount
  336.  
  337.           mov       dx, si                   ; flag arg as bad
  338.           xchg      di, si
  339.           mov       al, ' '
  340.           repne     scasb                    ; find end of argument
  341.           xchg      di, si
  342.           jne       SHORT @@BadCount
  343.           dec       si                       ; overshot so back up 1 char
  344.           inc       cx
  345.           jmp       SHORT @@BadCount         ; tell user it's bad
  346.  
  347. @@GetCount:
  348.           mov       dx, si                   ; save to adjust CX and if error
  349.           call      atou
  350.           pushf                              ; preserve flags
  351.           add       cx, dx                   ; adjust counter
  352.           sub       cx, si
  353.           popf                               ; restore flags
  354.           jc        SHORT @@BadCount         ; error in conversion?
  355.           cmp       ax, COUNT_UPP_LIMIT      ; too big?
  356.           ja        SHORT @@BadCount         ;   yes
  357.           mov       [Count], al
  358.           jmp       SHORT @@Fin
  359.  
  360. @@BadCount:
  361.           push      dx
  362.           mov       bl, STDERR
  363.           mov       dx, OFFSET ProgName
  364.           call      fputs
  365.           mov       dx, OFFSET Err2Msg
  366.           call      fputs
  367.           pop       dx
  368.           mov       al, [si]                 ; save next non-digit
  369.           mov       [BYTE PTR si], EOS       ; replace with EOS
  370.           call      fputs
  371.           mov       [si], al                 ; restore it
  372.           mov       dx, OFFSET EOL
  373.           call      fputs
  374.           mov       [HFlag], 1
  375.           jmp       SHORT @@Fin
  376.  
  377. @@Fin:
  378.           ret
  379. ENDP get_Arg
  380.  
  381.  
  382. ;----  process_CmdLine  ---------------------------------------------------;
  383. ;  Purpose:    Processes commandline arguments.                            ;
  384. ;  Notes:      A switch character by itself is ignored.                    ;
  385. ;              No arguments whatsoever causes help flag to be set.         ;
  386. ;  Entry:      n/a                                                         ;
  387. ;  Exit:       n/a                                                         ;
  388. ;  Calls:      skip_Spaces, get_Opt, get_Arg                               ;
  389. ;  Changes:    AX, CX, SI,                                                 ;
  390. ;              DX (get_Arg),                                               ;
  391. ;              [OptCh], [HFlag], [EFlag] (get_Opt),                        ;
  392. ;              [Count], (get_Arg),                                         ;
  393. ;              Direction flag is cleared.                                  ;
  394. ;--------------------------------------------------------------------------;
  395. PROC process_CmdLine
  396.  
  397.           cld                                ; forward, march!
  398.           Zero      ch, ch
  399.           mov       cl, [CmdLen]             ; length of commandline
  400.           mov       si, OFFSET CmdLine       ; offset to start of commandline
  401.  
  402.           call      skip_Spaces              ; check if any args supplied
  403.           or        cl, cl
  404.           jnz       SHORT @@ArgLoop
  405.           jmp       SHORT @@Fin
  406.  
  407. ;
  408. ; For each blank-delineated argument on the commandline...
  409. ;
  410. @@ArgLoop:
  411.           lodsb                              ; next character
  412.           dec       cl
  413.           cmp       al, [SwitCh]             ; is it the switch character?
  414.           jnz       SHORT @@NonOpt           ;   no
  415.  
  416. ;
  417. ; Isolate each option and process it. Stop when a space is reached.
  418. ;
  419. @@OptLoop:
  420.           jcxz      SHORT @@Fin              ; abort if nothing left
  421.           lodsb
  422.           dec       cl
  423.           cmp       al, ' '
  424.           jz        SHORT @@NextArg          ; abort when space reached
  425.           call      get_Opt
  426.           jmp       @@OptLoop
  427.  
  428. ;
  429. ; Process the current argument, which is *not* an option.
  430. ; Then, *drop thru* to advance to next argument.
  431. ;
  432. @@NonOpt:
  433.           dec       si                       ; back up one character
  434.           inc       cl
  435.           call      get_Arg
  436.  
  437. ;
  438. ; Skip over spaces until next argument is reached.
  439. ;
  440. @@NextArg:
  441.           call      skip_Spaces
  442.           or        cl, cl
  443.           jnz       @@ArgLoop
  444.  
  445. @@Fin:
  446.           ret
  447. ENDP process_CmdLine
  448.  
  449.  
  450. ;--------------------------------------------------------------------------;
  451. ;                         E N T R Y   P O I N T                            ;
  452. ;--------------------------------------------------------------------------;
  453. ;----  main  --------------------------------------------------------------;
  454. ;  Purpose:    Main section of program.                                    ;
  455. ;  Notes:      none                                                        ;
  456. ;  Entry:      Arguments as desired                                        ;
  457. ;  Exit:       Return code as follows:                                     ;
  458. ;                   0 => program ran successfully                          ;
  459. ;                   1 => on-line help requested                            ;
  460. ;              or whatever previous errorlevel was if '-e' option used.    ;
  461. ;  Calls:      process_CmdLine, fputs, putchar                             ;
  462. ;  Changes:    n/a                                                         ;
  463. ;--------------------------------------------------------------------------;
  464. main:
  465.           mov       sp, OFFSET StackTop      ; set up local stack
  466.  
  467. ;
  468. ; Process commandline arguments. If the variable HFlag is set, then
  469. ; on-line help is displayed and the program immediately terminates.
  470. ;
  471.           call      process_CmdLine          ; process commandline args
  472.  
  473.           cmp       [HFlag], 0               ; is help needed?
  474.           jz        SHORT @@NoHelp           ;   no
  475.           mov       [RCode], ERRH            ;   yes, so set return code
  476.           mov       bx, STDERR
  477.           mov       dx, OFFSET HelpMsg       ;     point to help message
  478.           call      fputs                    ;     display it
  479.           jmp       SHORT @@Fin              ;     and jump to end of program
  480.  
  481. ;
  482. ; Figure out whether to ring bell conditionally.
  483. ;
  484. @@NoHelp:
  485.           cmp       [EFlag], 0               ; is it conditional?
  486.           jz        SHORT @@RingBell         ;   no
  487.           cmp       [RCode], 0               ;   yes, was errorlevel 0?
  488.           jz        SHORT @@Fin              ;     yes, no bell
  489.  
  490. ;
  491. ; Determine how many times to ring the bell and do it.
  492. ;
  493. @@RingBell:
  494.           mov       cl, [Count]              ; get the count
  495.           Zero      ch                       ; zero out high byte of word
  496.           jcxz      SHORT @@Fin
  497.           mov       dl, BELL
  498. @@RingLoop:
  499.           call      putchar
  500.           loop      @@RingLoop               ; repeat as necessary
  501.  
  502. ;
  503. ; Ok, let's terminate the program and exit with proper return code.
  504. ;
  505. @@Fin:
  506.           mov       al, [RCode]
  507.           mov       ah, 4ch
  508.           int       DOS
  509.  
  510. EVEN
  511. ;-------------------------------------------------------------------------;
  512. ;  Purpose:    Writes an ASCIIZ string to specified device.
  513. ;  Notes:      A zero-length string doesn't seem to cause problems when
  514. ;                 this output function is used.
  515. ;  Requires:   8086-class CPU and DOS v2.0 or better.
  516. ;  Entry:      BX = device handle,
  517. ;              DS:DX = pointer to string.
  518. ;  Exit:       Carry flag set if EOS wasn't found or handle is invalid.
  519. ;  Calls:      strlen
  520. ;  Changes:    none
  521. ;-------------------------------------------------------------------------;
  522. PROC fputs
  523.  
  524. IF @DataSize EQ 0
  525.    Push_M   <ax, cx, di>
  526. ELSE
  527.    Push_M   <ax, cx, di, es>
  528.    mov      ax, ds
  529.    mov      es, ax
  530. ENDIF
  531.    mov      di, dx
  532.    call     strlen                        ; set CX = length of string
  533.    jc       SHORT @@Fin                   ; abort if problem finding end
  534.    mov      ah, 40h                       ; MS-DOS raw output function
  535.    int      DOS
  536. @@Fin:
  537. IF @DataSize EQ 0
  538.    Pop_M    <di, cx, ax>
  539. ELSE
  540.    Pop_M    <es, di, cx, ax>
  541. ENDIF
  542.    ret
  543.  
  544. ENDP fputs
  545.  
  546.  
  547. EVEN
  548. ;-------------------------------------------------------------------------;
  549. ;  Purpose:    Writes a character to STDOUT device.
  550. ;  Notes:      none
  551. ;  Requires:   8086-class CPU and DOS v1.0 or better.
  552. ;  Entry:      DL = character to display.
  553. ;  Exit:       n/a
  554. ;  Calls:      none
  555. ;  Changes:    none
  556. ;-------------------------------------------------------------------------;
  557. PROC putchar
  558.  
  559.    push     ax
  560.    mov      ah, 2
  561.    int      DOS
  562.    pop      ax
  563.    ret
  564.  
  565. ENDP putchar
  566.  
  567.  
  568. EVEN
  569. ;-------------------------------------------------------------------------;
  570. ;  Purpose:    Writes an error message to stderr.
  571. ;  Notes:      none
  572. ;  Requires:   8086-class CPU and DOS v2.0 or better.
  573. ;  Entry:      DS:DX = pointer to error message.
  574. ;  Exit:       n/a
  575. ;  Calls:      fputs
  576. ;  Changes:    none
  577. ;-------------------------------------------------------------------------;
  578. PROC errmsg
  579.  
  580.    Push_M   <bx, dx>
  581.    push     dx                            ; save again calling parameters
  582.    mov      bx, STDERR
  583.    mov      dx, OFFSET ProgName           ; display program name
  584.    call     fputs
  585.    pop      dx                            ; recover calling parameters
  586.    call     fputs                         ; display error message
  587.    mov      dx, OFFSET EOL
  588.    call     fputs
  589.    Pop_M    <dx, bx>
  590.    ret
  591.  
  592. ENDP errmsg
  593.  
  594.  
  595. EVEN
  596. ;-------------------------------------------------------------------------;
  597. ;  Purpose:    Gets version of DOS currently running.
  598. ;  Notes:      none
  599. ;  Requires:   8086-class CPU and DOS v2.0 or better.
  600. ;  Entry:      n/a
  601. ;  Exit:       AL = major version number,
  602. ;              AH = minor version number (2.1 = 10).
  603. ;  Calls:      none
  604. ;  Changes:    AX
  605. ;-------------------------------------------------------------------------;
  606. PROC getvdos
  607.  
  608.    Push_M   <bx, cx>                      ; DOS destroys bx and cx!
  609.    mov      ah, 30h
  610.    int      DOS
  611.    Pop_M    <cx, bx>
  612.    ret
  613.  
  614. ENDP getvdos
  615.  
  616.  
  617. EVEN
  618. ;-------------------------------------------------------------------------;
  619. ;  Purpose:    Converts string of digits to an *unsigned* integer in
  620. ;              range [0, 65535].
  621. ;  Notes:      Conversion stops with first non-numeric character.
  622. ;  Requires:   8086-class CPU.
  623. ;  Entry:      DS:SI = pointer to string of digits.
  624. ;  Exit:       AX = unsigned integer (garbage if cf = 1),
  625. ;              DS:SI = pointer to first non-digit found,
  626. ;              cf = 1 if number is too big.
  627. ;  Calls:      none
  628. ;  Changes:    AX, SI
  629. ;              flags
  630. ;-------------------------------------------------------------------------;
  631. PROC atou
  632.  
  633.    Push_M   <bx, cx, dx>                  ; DX destroyed by MUL below
  634.    Zero     ax                            ; AX = digit to convert
  635.    Zero     bx                            ; BX = integer word
  636.    mov      cx, 10                        ; CX = conversion factor
  637.  
  638. @@NextCh:
  639.    mov      bl, [si]                      ; get character
  640.    cmp      bl, '0'                       ; test if a digit
  641.    jb       SHORT @@Fin
  642.    cmp      bl, '9'
  643.    ja       SHORT @@Fin
  644.    inc      si                            ; bump up pointer
  645.    mul      cx                            ; multiply old result by 10
  646.    jc       SHORT @@Overflow
  647.    sub      bl, '0'                       ; convert digit
  648.    add      ax, bx                        ; add current value
  649.    jnc      @@NextCh                      ; continue unless result too big
  650.  
  651. @@Overflow:
  652.    Zero     cx                            ; denotes overflow
  653.    jmp      @@NextCh
  654.  
  655. @@Fin:
  656.    cmp      cx, 10                        ; cf = (cx != 10)
  657.    Pop_M    <dx, cx, bx>
  658.    ret
  659.  
  660. ENDP atou
  661.  
  662.  
  663. EVEN
  664. ;-------------------------------------------------------------------------;
  665. ;  Purpose:    Tests if character is a valid ASCII digit.
  666. ;  Notes:      none
  667. ;  Requires:   8086-class CPU.
  668. ;  Entry:      AL = character to be tested.
  669. ;  Exit:       Zero flag set if true, cleared otherwise.
  670. ;  Calls:      none 
  671. ;  Changes:    flags
  672. ;-------------------------------------------------------------------------;
  673. PROC isdigit
  674.  
  675.    cmp      al, '0'                       ; if < '0' zf = 0
  676.    jb       SHORT @@Fin
  677.    cmp      al, '9'                       ; if > '9' zf = 0
  678.    ja       SHORT @@Fin
  679.    cmp      al, al                        ; set Z flag
  680. @@Fin:
  681.    ret
  682.  
  683. ENDP isdigit
  684.  
  685.  
  686. EVEN
  687. ;-------------------------------------------------------------------------;
  688. ;  Purpose:    Converts character to lowercase.
  689. ;  Notes:      none
  690. ;  Requires:   8086-class CPU.
  691. ;  Entry:      AL = character to be converted.
  692. ;  Exit:       AL = converted character.
  693. ;  Calls:      none
  694. ;  Changes:    AL
  695. ;              flags
  696. ;-------------------------------------------------------------------------;
  697. PROC tolower
  698.  
  699.    cmp      al, 'A'                       ; if < 'A' then done
  700.    jb       SHORT @@Fin
  701.    cmp      al, 'Z'                       ; if > 'Z' then done
  702.    ja       SHORT @@Fin
  703.    or       al, 20h                       ; make it lowercase
  704. @@Fin:
  705.    ret
  706.  
  707. ENDP tolower
  708.  
  709.  
  710. EVEN
  711. ;-------------------------------------------------------------------------;
  712. ;  Purpose:    Calculates length of an ASCIIZ string.
  713. ;  Notes:      Terminal char is _not_ included in the count.
  714. ;  Requires:   8086-class CPU.
  715. ;  Entry:      ES:DI = pointer to string.
  716. ;  Exit:       CX = length of string,
  717. ;              cf = 0 and zf = 1 if EOS found,
  718. ;              cf = 1 and zf = 0 if EOS not found within segment.
  719. ;  Calls:      none
  720. ;  Changes:    CX,
  721. ;              flags
  722. ;-------------------------------------------------------------------------;
  723. PROC strlen
  724.  
  725.    Push_M   <ax, di, flags>
  726.    cld                                    ; scan forward only
  727.    mov      al, EOS                       ; character to search for
  728.    mov      cx, di                        ; where are we now
  729.    not      cx                            ; what's left in segment - 1
  730.    push     cx                            ; save char count
  731.    repne    scasb
  732.    je       SHORT @@Done
  733.    scasb                                  ; test final char
  734.    dec      cx                            ; avoids trouble with "not" below
  735.  
  736. @@Done:
  737.    pop      ax                            ; get original count
  738.    sub      cx, ax                        ; subtract current count
  739.    not      cx                            ; and invert it
  740.    popf                                   ; restore df
  741.    dec      di
  742.    cmp      [BYTE PTR es:di], EOS
  743.    je       SHORT @@Fin                   ; cf = 0 if equal
  744.    stc                                    ; set cf => error
  745.  
  746. @@Fin:
  747.    Pop_M    <di, ax>
  748.    ret
  749.  
  750. ENDP strlen
  751.  
  752.  
  753. END
  754.