home *** CD-ROM | disk | FTP | other *** search
/ The Unsorted BBS Collection / thegreatunsorted.tar / thegreatunsorted / programming / asm_programming / GET.ASM < prev    next >
Assembly Source File  |  1989-06-04  |  42KB  |  1,211 lines

  1.           TITLE   GET
  2.  
  3. ; Program SDL_GET.ASM (or just GET)
  4. ; Purpose Batch file enhancer for use with MASDIR
  5. ; Input      Command line consisting of:
  6. ;         Command letter (with optional E for extended)
  7. ;         Optional prompt enclosed in double    quotes
  8. ;         Optional argument
  9. ; Output  Number in DOS ERRORLEVEL and string in GET environment variable
  10. BIOS_DATA       SEGMENT AT 40H
  11.         ORG     84H
  12. CRT_ROWS DB     ?
  13.         ORG     87H
  14. EGA_INFO DB     ?
  15. BIOS_DATA       ENDS
  16.  
  17.  
  18.       DOSSEG
  19.       .MODEL  small
  20.       PAGE      60,120
  21.           INCLUDE DOS.INC
  22.  
  23.       .STACK  100h
  24.  
  25.       .DATA
  26.  
  27. S1      SIZESTR @Filename               ; If the name of this file is GET
  28. S2      INSTR @Filename,<get>           ; then the $ option will be omitted.
  29. S3      INSTR @Filename,<GET>           ; Any other file name will cause the
  30. IF S1 eq 3 AND S2 eq 1 OR S3 eq 1       ; $ option to be assembled in.
  31. GET equ <TRUE>
  32. ENDIF
  33. cr       equ      "}"                     ; Surrogate for CR
  34. esc_s    equ      "~"                     ; Surrogate for Esc
  35. ext      equ      "`"  ; grave accent indicates that extended keys can be used
  36. MaxSize  equ      1000h                 ; MaxSize of moving text prompt.
  37.  
  38. help1      LABEL      BYTE
  39. DB 13,10
  40. DB "  GET -- Bob Stephan's Batch file enhancer -- a public domain utility",13,10
  41. DB "         Syntax:  GET command argument",13,10
  42. DB "Purpose             Command       Argument   Environment Errorlevel  Extended",13,10
  43. DB "---------           -------       --------   --(GET=)--- --(Exit)--  --[E]---",13,10
  44. DB 'Get character       C[E] ["prompt"] [chars]  Character   ASCII dec.  No Echo',13,10
  45. DB 'Get yes/no aNswer   N[E] ["prompt"]  None    Character   ASCII dec.  No Echo',13,10
  46. DB 'Get string          S[E] ["prompt"]  None    String      Length      No Echo',13,10
  47. DB 'Moving Text(GetaKey)T[E] "Filespec" [chars]  Character   ASCII dec.  No Echo',13,10
  48. DB "Get DOS version     D[E]             None    Major Vers. MajorMinor  MinorEnv",13,10
  49. DB "Get environment left    E[E]         None    Bytes left  Bytes left  Bytes/10",13,10
  50. DB "Get file size (DIR=0)   F[E]  Filespec       Hex bytes   Kilobytes   Kb/10",13,10
  51. DB "Get disk space          K[E] [driveletter]   Kilobytes   Kilobytes   Kb/10",13,10
  52. DB "Get memory free         M[E]         None    Kilobytes   Kilobytes   Kb/10",13,10
  53. DB "Clear (Blank) Screen    B[E] [New attribute] Current or last attr.   HexAttr",13,10
  54. DB "Check for printer       P            None    1=yes,0=no  1=yes,0=no  None",13,10
  55. DB "Get/set video mode      V   [New mode]       Current or last mode    None",13,10
  56. DB "Check coprocessor       7            None    1=yes,0=no  1=yes,0=no  None",13,10
  57. DB "Check for ANSI.SYS      A            None    1=yes,0=no  1=yes,0=no  None",13,10
  58. DB "Get current directory   Y[E]         None    Directory   Level/Drive Drive",13,10
  59. ;DB "Hex clock since 1/1/80  $            None    Days        Days/255    None",13,10
  60. DB "Surrogate [char] args: ",cr," is Carriage Return, "
  61. DB esc_s," is Escape, ",ext," is Extended.$",13,10
  62.  
  63.  
  64. guess     DB      80             ; Prompt for string
  65. actual    DB      0
  66. string    DB      80 DUP (0)
  67.  
  68. extend      DB      0         ; Flag    for extended command
  69. vid      DB      3         ; Video mode
  70. ans      DB      27,"[6n$"     ; ANSI    string to get current position
  71. overwrt      DB      8,8,8,8,"    $"; Overwrite ANSI characters
  72. delete      DB      8,8,8,"$"     ; Delete ANSI characters
  73.  
  74. what      DB      "GET="        ; Variable name
  75. lwhat     EQU     $-what
  76.  
  77. prompt      DW      0         ; Pointer to prompt
  78. lprompt      DW      0         ; Length of prompt
  79. arg      DW      0         ; Pointer to argument
  80. larg      DW      0         ; Length of argument
  81. EGA_L     DB      0
  82. clock     DB      'CLOCK$',00H
  83. ; Command table
  84. IFNDEF GET
  85. cmds      DB      "BCSVDMEKFP7AY$NT" ; Command character list
  86. ELSE
  87. cmds      DB      "BCSVDMEKFP7AYNT" ; Command character list (omit $ for GET)
  88. ENDIF
  89. lcmds      EQU      $-cmds     ;   and length    of list
  90.       EVEN
  91. table     DW      BlankScreen
  92.           DW      GetChar        ; Command procedure table
  93.       DW      GetStr
  94.       DW      DoVid
  95.       DW      GetDOS
  96.       DW      GetMem
  97.       DW      GetEnvSz
  98.       DW      GetDskSz
  99.       DW      GetFilSz
  100.       DW      VeriPrint
  101.       DW      VeriCop
  102.       DW      VerAnsi
  103.           DW      GetDir
  104. IFNDEF GET
  105.           DW      Clock$                ; This calls the $ option.
  106. ENDIF
  107.           DW      aNswer                ; Yes/No answer--CR=Yes,Esc gives 126
  108.           DW      Moving
  109.           DW      Help
  110.           ;DW      NoCmd
  111.  
  112. err1      DB      "Invalid command",7,13,10,"$"
  113. err2      DB      "Out of environment space",7,13,10,"$"
  114. err3      DB      "Must have DOS Version 2.0 or higher",7,13,10,"$"
  115.  
  116.       .CODE
  117. start:      mov      ax,@DATA        ; Starting execution address
  118.       mov      ds,ax            ; Initialize data segment
  119.  
  120.       @GetVer            ; Get DOS version
  121.       or      al,al            ; Is it    0?
  122.       jne      DOSOK            ; No? Continue
  123.       @DispStr err3            ; Yes? Quit for    1.x
  124.       int      20h
  125.  
  126. DOSOK:      mov      si,83h        ; Starting point in PSP
  127.       mov      ax,WORD PTR es:[5Dh]    ; Load command characters
  128.       cmp      al,' '        ; Is it    space?
  129.       jne      isarg            ; If no    argument, show help
  130.       call      Help
  131.  
  132. isarg:      cmp      ah,'E'        ; Extend flag?
  133.       jne      noextend        ; No? Continue
  134.       inc      extend        ; Yes? Turn on flag and    adjust pointer
  135.       inc      si
  136.  
  137. noextend: call      GetArg        ; Get argument from command line
  138.  
  139.       push      es            ; Save and load    DS into    ES
  140.       mov      bx,ds
  141.       mov      es,bx
  142.       mov      di,OFFSET cmds    ; Load pointer to command table
  143.       mov      cx,lcmds+1        ; Load length
  144.           repne   scasb                 ; Find position of command character
  145.       pop      es
  146.       sub      di,(OFFSET cmds)+1    ; Point    to procedure
  147.       shl      di,1            ; Adjust for word addresses
  148.       call      table[di]        ; Call the selected procedure
  149.  
  150.       push      ax            ; Save
  151.       push      es
  152.       call      DoEnviron        ; Put result in    environment string
  153.       or      ax,ax            ; Test for 0 before
  154.       pop      es            ;   restore
  155.       pop      ax
  156.       jz      done
  157.  
  158.       cmp      BYTE PTR es:[5Dh],'E'    ; Is it    Environment command
  159.       je      done            ; Yes? Skip message
  160.  
  161. error2:   @DispStr err2         ; Error message
  162.       mov    al,0
  163. done:      @Exit                ; Quit with AL as return code
  164.  
  165. ; End of program - Start of procedures
  166.  
  167. ; Procedure Blank Screen without changing color or attribute or number of lines
  168.  
  169. BlankScreen PROC
  170.         PUSH    DS                      ; See if the number of active rows
  171.     MOV    AX,BIOS_DATA        ; is available in the BIOS data area.
  172.     MOV    DS,AX            ; This is the address of the segment.
  173.     ASSUME    DS:BIOS_DATA        ; Tell the assembler
  174.     MOV    DH,CRT_ROWS        ; Good only in later versions of DOS,
  175.     POP    DS            ; else it will be 0 (I hope).
  176.         ASSUME  DS:@data               ; Tell MASM we are back home.
  177.     CMP    DH,18H            ; 25 rows?
  178.     JLE    ROWS_OK         ; If less, don't use it.
  179.     SUB    DH,18H            ; Else get the difference from 25,
  180.     MOV    BYTE PTR EGA_L,DH    ; and save it for later use.
  181. ROWS_OK:
  182.         MOV     BH,0                    ; Page number for setting cursor
  183.         MOV     AH,8                   ; Function to read attribute
  184.         INT     10H                     ; Read attribute in AH (char in al)
  185.           xor   al,al                   ; This code borrowed from video proc
  186.           push    ax                    ; Save last attribute
  187.           ;cmp     larg,1                ; How many digits in mode?
  188.           ;jl      gotattr               ; None? Get out
  189.           MOV   CX,LARG
  190.           JCXZ  GOTATTR
  191.           mov     bx,arg                ; Load address of argument string
  192.           mov     ax,es:WORD PTR [bx]   ; Get address of mode string
  193.           DEC   CX
  194.           JCXZ  ONEDIG
  195.           DEC   CX
  196.           JCXZ  TWODIG
  197.           ;je      onedig                ; One digit - skip the reverse
  198.           INC     BX                    ; Load address of argument string
  199.           mov     ax,es:WORD PTR [bx]   ; Get address of mode string
  200. TWODIG:   xchg    ah,al                 ; Reverse for two digits
  201.           sub     ax,'00'               ; Adjust from ASCII to numeric
  202.           cmp   ah,09
  203.           jle   InHex
  204.           sub   ah,07
  205.           and   ah,0Fh
  206. InHex:  cmp     al,09
  207.         jle     HexOk
  208.         sub     al,07
  209.         and     al,0Fh
  210. HexOk:  cmp     extend,0
  211.         je      NotHex
  212.         mov     cl,4
  213.         shl     ah,cl
  214.         add     ah,al
  215.         jmp     SHORT gotattr
  216. NotHex: aad                           ; Convert to binary
  217.         JCXZ  setattr
  218.         ;SUB     CX,CX
  219.         MOV     CL,ES:BYTE PTR [BX-1]
  220.         MOV     AH,CL
  221.         SUB     CL,'0'
  222.         MOV     CH,2
  223.         SUB     CH,CL
  224.         ADD     AH,CH
  225.         SHL     AH,CL
  226.         ADD     AH,AL
  227.          jmp     SHORT GOTattr
  228. onedig:   sub     al,'0'                ; Convert to numeric
  229.         cmp     al,09
  230.         jle     setattr
  231.         sub     al,7                    ; Must be Hex
  232.         and   al,0Fh
  233. setattr:
  234.           xchg    ah,al                 ; Attribute in AH
  235. gotattr:SUB     DX,DX                   ; Position for cursor
  236.         MOV     CX,AX                   ; Attribute in AH, save in CX
  237.         MOV     AH,2                    ; Function for setting cursor, BH=page
  238.         INT     10H                     ; Set cursor position
  239.         MOV     BX,CX                   ; Need attribute in BH
  240.         SUB     CX,CX                   ; Position for scroll
  241.         MOV     DX,184FH                ; Lower right row, col to scroll
  242.         ADD     DH,EGA_L                ; Are there extra lines?
  243.         MOV     AX,600H                 ; Function to clear(scroll) screen
  244.         INT     10H                     ; Bios call
  245.         pop     ax                      ; Last or current attribute
  246.         xchg    al,ah                   ; Set return to attribute
  247.         cmp     extend,0
  248.         jne     IsHex
  249.         call    bintodec                ; Put attribute in enviroment
  250.         jmp     SHORT BlankEnd
  251. IsHex:  call    BinToHex
  252. BlankEnd:RET
  253. BlankScreen     ENDP
  254.  
  255. IFNDEF GET
  256.  
  257. ; Procedure Clock$                      ; Assembled only if filename not GET.
  258. ; Purpose   Get days since 1-1-80 from CLOCK$ device (DOS).
  259. ; Input     None
  260.  
  261. Clock$      PROC
  262.  
  263.             mov   ax,3d00h              ; Call DOS to open a file
  264.             mov   dx,offset Clock      ; ASCIIZ name of CLOCK$ device
  265.             int   21h                   ; Call DOS
  266.             jc    QuietExit             ; If error, exit...else...
  267.             mov   bx,ax                 ; Handle in AX, need in BX
  268.             mov   dx,offset string      ; Location of output
  269.             mov   cx,0001               ; Length of output expected
  270.             mov   ax,3f00h              ; Function to read device
  271.             int   21h                   ; Call DOS
  272.             jc    QuietExit             ; If error, exit...else...
  273.             mov   ax,word ptr string    ; Number of days since 1-1-80
  274.             cmp   ax,300                ; Take all dates except 300 in 1980.
  275.             ;cmp   ax,0D00h             ; 1989 is early enough, else clock is
  276.             jle   QuietExit             ; not set, so don't use.
  277.             xchg  al,ah                 ; Get digits in proper order, and
  278.             call  BinToHex              ; Convert number in AX to hex digits.
  279.             xor   bx,bx             ; Now have hex in string, length in actual
  280.             mov   bl,byte ptr actual    ; Number of hex digits, no leading 0's?
  281.             mov   actual,5              ; If more than 2 bytes we want to split
  282.             mov   si,bx                 ; it into two hex numbers for use by
  283.             mov   bx,4
  284. ByteLoop:
  285.             dec   si                    ; DEBUG.  We will make 5 bytes out of
  286.             mov   ah,string[si]         ; it, 2 and 2 separated by a space.
  287.             mov   string[bx],ah         ; We are now moving the 4th to the
  288.             cmp   si,0                  ; fifth place, and the third to the 4th.
  289.             jz    DoneLoop
  290.             dec   bx
  291.             cmp   bx,2                  ; Need to put space in 3rd positon
  292.             jne   ByteLoop
  293.             mov   string[bx],' '
  294.             dec   si
  295. DoneLoop:                               ; si is either 0 or 1.
  296.             dec   bx                    ; if si is 0, bx is 3, 2, or 1 after dec
  297.             cmp   bx,si                 ; if bx is 1, si is either 0 or 1
  298.             jz    ClockEnd              ; if bx is 2 or 3, si must be 0
  299.             cmp   bx,2                  ;
  300.             jne   ZeroLoop              ; either bx=3,si=0 or bx=1,si=0
  301.             mov   string[bx],' '
  302. Zero_1:     dec   bx                    ; We know that bx is 2
  303. ZeroLoop:                               ; Now have to fill with leading zeros
  304.             mov   string[bx],'0'
  305.             cmp   bx,3                  ; If 3, we still have to do ' '
  306.             jz    DoneLoop              ; so go back up there.
  307.             cmp   bx,0                  ; If not yet 0, do it again.
  308.             jg    Zero_1
  309.  
  310. ClockEnd:   ret
  311. QuietExit:  mov   ax,4c00h              ; Quietly exit with a zero return code.
  312.             int 21h
  313. Clock$          ENDP
  314.  
  315. ENDIF
  316.  
  317. ; Procedure aNswer
  318. ; Purpose   get and answer to a yes/no type question.
  319. ; Input        Allowable characters pointed to by "arg" (optional)
  320. ;        Prompt pointed to by "prompt" (optional)
  321. ; Output    Character in AX and in "string"
  322.  
  323. aNswer  PROC
  324.         ;mov     bx,offset prompt        ; Simulate the valid characters
  325.         ;add     bx,lprompt              ; Length of prompt to find end.
  326.         MOV     BX,60H                  ; Use DOS PSP FCB area for this???
  327.         mov     arg,bx              ; Tell GetChar where the args are,
  328.         mov     larg,4              ; and how many...
  329.         mov     word ptr es:[bx],'NY' ; Set up Y(es), N(o) characters
  330.         mov     word ptr es:[bx+2],"}~" ; Set up CR and Esc surrogates
  331.         call    GetChar                 ; Now use existing code
  332.         ret
  333. aNswer  ENDP
  334.  
  335. ; Procedure GetChar
  336. ; Purpose   Get    a character from user
  337. ; Input        Allowable characters pointed to by "arg" (optional)
  338. ;        Prompt pointed to by "prompt" (optional)
  339. ; Output    Character in AX and    in "string"
  340.  
  341. GetChar      PROC
  342.  
  343.       call      ShowPrmpt        ; Display prompt if there is one
  344.  
  345. readkey:  @GetKey 0,1                   ; Get a key
  346.         CALL    CheckChar
  347.         cmp     al,0
  348.         jz      readkey
  349.  
  350. charend:  push      AX
  351.           @DispCh 13,10                 ; Better put in cr,lf...
  352.       pop      AX
  353.       ret
  354. GetChar      ENDP
  355.  
  356. ; Procedure CheckChar
  357. ; Purpose   Check character from user
  358. ; Input        Allowable characters pointed to by "arg" (optional)
  359. ;           Character to check in AL
  360. ; Output    Character in AX(al) and in "string"
  361. ;           If AL is 0, bad character.
  362.  
  363. CheckChar  PROC
  364.       cmp      al,13            ; Is it    carriage return?
  365.       jne      notcr            ; Yes? Continue
  366.           mov     al,cr                ; Call it whatever is in cr
  367.                                         ;   (use surrogate in character list
  368.                     ;    if    you want to accept CR)
  369. notcr:      cmp      al,27         ; Is it Escape?
  370.       jne      notesc        ; Yes? Continue
  371.           mov     al,Esc_s                ; Call it tilde
  372.  
  373. notesc:   or      al,al         ; Is it 0 for extended key?
  374.       je      exkey            ; Special case
  375.  
  376.       mov      bl,al            ; Save a copy and swap
  377.       xchg      ah,al
  378.  
  379.       call      UpCase        ; Uppercase it
  380.  
  381.       xchg      ah,al            ; Swap back
  382.       mov      si,arg        ; Load pointer and length of argument
  383.       mov      cx,larg
  384.       jcxz      gotchar        ; If no    argument, quit early
  385.  
  386. ; Compare character to argument    to see if it's valid
  387.  
  388. argcheck: mov      ah,BYTE PTR es:[si]    ; Get character
  389.       inc      si            ; Increment index
  390.  
  391.       call      UpCase        ; Convert to uppercase
  392.  
  393.       cmp      ah,al            ; Is it    in argument?
  394.       je      gotchar        ; Yes? We're done
  395.       loop      argcheck        ;   else check another
  396.           jmp     SHORT BadChar         ;   and get another character
  397.  
  398. gotchar:  push      ax
  399.       cmp      extend,0        ; Is extend flag set?
  400.       jne      noecho        ; Yes? Don't echo
  401.           cmp     bl,cr                 ; Don't echo ~ (alias for CR)
  402.       je      noecho
  403.           cmp     bl,Esc_s              ; Don't echo ~ (alias for Esc)
  404.       je      noecho
  405.       @DispCh bl            ; Display valid    character
  406. noecho:      pop      ax
  407.       mov      string,al        ; Put the character in string
  408.           mov     actual,1              ; Length is one
  409.           jmp    SHORT EndCheck
  410.  
  411. exkey:      @GetKey 0,1            ; Get second key in AL
  412.       mov      si,arg        ; Load pointer to argument
  413.           cmp     BYTE PTR es:[si],Ext  ; Is argument grave accent?
  414.                     ;   (use grave in character list if
  415.                     ;    you want to accept    extended keys)
  416.       je      gotext        ; Yes? Extended    character
  417. BadChar:  @DispCh 7                     ; No? Illegal, so ring bell
  418.           mov     al,0                  ;   and get another
  419.           jmp   short EndCheck
  420. gotext:   mov     string[0],'`'         ; Extended flag value is "`<char>"
  421.       mov      string[1],al
  422.       mov      actual,2        ; Length is 2
  423. EndCheck: ret
  424. CheckChar   ENDP
  425.  
  426. ; Procedure GetStr
  427. ; Purpose   Get    a string
  428. ; Input        Prompt pointed to by prompt    (optional)
  429. ; Output    String in "string";    length to AX
  430.  
  431. GetStr      PROC
  432.  
  433.       call      ShowPrmpt        ; Display prompt if there is one
  434.  
  435.       cmp      extend,1        ; Extend flag true?
  436.       je      password        ; Yes? Then don't echo
  437.  
  438.       @GetStr guess,0        ; Get string (null-terminated)
  439.       jmp      SHORT    gotstr        ; Done
  440.  
  441. password: mov      bx,OFFSET string    ; Load offset of string    buffer
  442.       mov      cx,80            ; Maximum count
  443. nextkey:  @GetKey 0,1            ; Get key, no echo
  444.       cmp      al,13            ; Is it    carriage return
  445.       je      gotpass        ; Yes? Done
  446.       mov      [bx],al        ; No? Put key in buffer
  447.       inc      bx            ; Point    to next
  448.       loop      nextkey
  449.  
  450. gotpass:  sub      bx,OFFSET string    ; Adjust pointer to get    count
  451.       mov      actual,bl        ; Save count
  452.  
  453. gotstr:      @DispCh 13,10
  454.       mov      ax,bx            ; Save string length
  455.       ret
  456. GetStr      ENDP
  457.  
  458. ; Procedure GetDOS
  459. ; Purpose   Get    DOS version
  460. ; Input        None
  461. ; Output    Major or minor version in "string";    (major *10)+minor in AX
  462.  
  463. GetDOS      PROC
  464.       @GetVer            ; Get DOS version
  465.       mov      string,al        ; Put major in string
  466.       mov      bh,al            ; Save copy
  467.       mov      al,ah            ; Divide minor to get one digit
  468.       sub      ah,ah            ; Clear    top
  469.       mov      cl,10            ; Divide by 10
  470.       div      cl
  471.       xchg      al,bh            ; Exchange major and minor
  472.       mul      cl            ; Multiply major by 10
  473.       add      al,bh            ; (Major*10)+Minor - 3.2 is now    32
  474.       cmp      extend,1        ; Extend?
  475.       jne      gotver        ; No? Already got it
  476.       mov      string,bh        ; Save number
  477. gotver:      mov      actual,1        ; Save length 1
  478.       add      string,30h        ; Convert to ASCII
  479.       ret
  480. GetDOS      ENDP
  481.  
  482. ; Procedure GetEnvSz
  483. ; Purpose   Get    environment bytes available
  484. ; Input        None
  485. ; Output    Environment    bytes available
  486.  
  487. GetEnvSz  PROC
  488.       push      es            ; Save ES
  489.       call      GetEnv        ; Get the environment size
  490.       pop      es            ; Restore
  491.       sub      ax,cx            ; Subtract length used from total
  492.                     ;   length to get length remaining
  493.       call      BinToDec        ; Convert to string
  494.       call      Byticize        ; Handle values    too large for byte
  495.       ret
  496. GetEnvSz  ENDP
  497.  
  498.  
  499. ; Procedure GetFilSz
  500. ; Purpose   Get    the size of a specified    file
  501. ; Input        Filespec pointed to    by "arg"
  502. ; Output    File size in AX and String(Hex)
  503.  
  504. GetFilSz  PROC
  505.           mov     di,arg                ; Point to start and end of arg
  506.           mov     bx,larg
  507.           Call    Open_Size             ; Returns size in DX:AX, handle in BX
  508.           JC      gotsize
  509.           ;mov     actual,0             ; Initial def is 0
  510.           PUSH    DX
  511.           or      dx,dx
  512.           jz      just_ax
  513.           push    ax
  514.           mov     ax,dx
  515.           call    BinToHex
  516.           pop     ax
  517. just_ax:  call    BinToHex
  518.           POP     DX
  519.           or      dx,dx
  520.           jnz     @F
  521.           or      ax,ax
  522.           jz      gotsize2
  523. @@:       mov     cX,10                ; Convert to kilobytes
  524. floop:    rcr     dx,1
  525.           rcr     ax,1
  526.           loop    floop
  527.           ;shr     ax,cl
  528.           ;or      dx,dx
  529.           ;jz      gotsize2
  530.       inc      ax            ; Round    up
  531.           jmp     SHORT gotsize2
  532.  
  533. gotsize:  call    BinToDec              ; Convert to string (decimal)
  534. gotsize2:
  535.           call    Byticize              ; Handle large values
  536.       ret
  537. GetFilSz  ENDP
  538.  
  539. ; Procedure Open_Size
  540. ; Purpose   Get the size of a specified file and open for reading
  541. ;           Called by GetFilSz and Moving
  542. ; Input        Filespec pointed to    by "arg"
  543. ; Output    File size in DX:AX, Handle in BX
  544.  
  545. Open_Size PROC
  546.           ;cmp     arg,0                 ; File name argument?
  547.           cmp     di,0                 ; File name argument?
  548.       jne      isfile
  549.           call    NoCmd
  550.                         ; Must be called with these args!
  551. isfile:  ; mov     di,arg                ; Point to start and end of arg
  552.          ; mov     bx,larg
  553.       mov      BYTE PTR es:[bx+di],0    ; Make null-terminated
  554.  
  555.       push      ds
  556.           ;@OpenFil arg,0,es             ; Open file for reading
  557.           @OpenFil di,0,es             ; Open file for reading
  558.           pop     ds                    ; Handle now in AX unless error
  559.           jc      ferror                ; Error if carry
  560.  
  561.  
  562. ;notdir:
  563.           mov   si,ax                   ; Save handle in SI for Moving
  564.           @GetFilSz ax                  ; Size in DX:AX
  565.           jc      ferror                ; Error if carry
  566.           ret
  567. ferror:   ;cmp     ax,5                  ; Access denied? Probably a directory
  568.           ;jne     nofile                ; No file or some other error
  569.           ;mov     ax,0FFh               ; Call directory size 255
  570.           ;jmp     SHORT gotsize        ; DIR and error return size 0!
  571. ;nofile:
  572.           sub     ax,ax                 ; Size of nothing is 0
  573.           stc
  574.           ret
  575. Open_Size ENDP
  576.  
  577. ; Procedure GetDskSz
  578. ; Purpose   Get    K remaining on specified disk
  579. ; Input        Drive letter pointed to by "arg"
  580. ; Output    Disk space remaining
  581.  
  582. GetDskSz  PROC
  583.           ;sub     ax,ax                 ; Assume default drive
  584.           ;cmp     arg,0                 ; Was there an argument?
  585.           MOV   AX,ARG
  586.           OR    AX,AX
  587.           je      defdrive              ; No? Got drive
  588.           MOV   BX,AX
  589.           MOV   AL,ES:BYTE PTR [BX ]
  590.           AND   AL,5FH
  591.           ;mov     al,BYTE PTR es:6Dh    ; Yes? Get drive letter
  592.       sub      al,'A'-1        ; Convert to binary
  593. defdrive: @ChkDrv al            ; Get disk space
  594.       cmp      ax,0FFFFh        ; Is drive valid?
  595.       jne      valid
  596.       call      NoCmd
  597. valid:      mul      bx            ; Sectors = sectors/cluster * clusters
  598.           shr     ax,1
  599.           ;mul     cx                    ; Bytes = bytes/sector * sectors
  600.           ;mov     cl,10                 ; Convert to kilobytes
  601.           ;shr     ax,cl
  602.           ;inc     ax                    ; Round up
  603.       call      BinToDec        ; Convert to string
  604.       call      Byticize        ; Handle large values
  605.  
  606.       ret
  607. GetDskSz  ENDP
  608.  
  609. ; Procedure GetMem
  610. ; Purpose   Get    memory available
  611. ; Input        None
  612. ; Output    Available memory
  613.  
  614. GetMem      PROC
  615.       int      12h            ; Get memory available in K
  616.       mov      bx,es            ; Get memory used
  617.       mov      cx,6            ; Convert to K
  618.       shr      bx,cl
  619.           sub     ax,bx                 ; Calculate how much is left
  620.           DEC     AX                    ; Seems like we need 1 less???
  621.           ;sub     dx,dx                 ; Clear DX
  622.           ;mov     cx,1024               ; Multiply to get bytes
  623.           ;mul     cx
  624.           ;mov     cx,1000               ; Divide to get thousands (not K)
  625.           ;div     cx
  626.       call      BinToDec        ; Convert to string
  627.       call      Byticize        ; Handle large values
  628.       ret
  629. GetMem      ENDP
  630.  
  631. ; Procedure VeriPrint
  632. ; Purpose   See    if LPT1    (PRN) is available
  633. ; Input        None
  634. ; Output    1 for yes or 0 for no
  635.  
  636. VeriPrint PROC
  637.       mov      ax,200h        ; Check    printer    status
  638.       sub      dx,dx            ;   for    main parallel printer (port 0)
  639.       int      17h
  640.       xchg      dx,ax            ; Put 0    (for error) in AX
  641.       test      dh,00101001b        ; Are any error    bits on?
  642.       jne      printerr        ; Yes? Leave 0
  643.       test      dh,10010000b        ; Are both operation bits on?
  644.       jz      printerr        ; No? Leave 0
  645.       inc      ax            ; Yes? Return 1
  646. printerr: call      BinToDec        ; Convert to string
  647.       ret
  648. VeriPrint ENDP
  649.  
  650. ; Procedure DoVid
  651. ; Purpose   Get    current    video mode and optionally set a    new mode
  652. ; Input        New    video mode pointed to by "arg" (optional)
  653. ; Output    Current video mode (before change)
  654.  
  655. DoVid      PROC
  656.       mov      ah,0Fh        ; Get video mode
  657.       int      10h
  658.  
  659.       cmp      larg,1        ; How many digits in mode?
  660.       jl      gotmode        ; None?    Get out
  661.       push      ax            ; Some?    Save mode
  662.       mov      bx,arg        ; Load address of argument string
  663.       mov      ax,es:WORD PTR [bx]    ; Get address of mode string
  664.       je      one            ; One digit - skip the reverse
  665.       xchg      ah,al            ; Reverse for two digits
  666.       sub      ax,'00'        ; Adjust from ASCII to numeric
  667.       aad                ; Convert to binary
  668.       jmp      SHORT    setmode
  669. one:      sub      al,'0'        ; Convert to numeric
  670. setmode:  sub      ah,ah            ; Set mode
  671.       int      10h
  672.       pop      ax            ; Restore
  673. gotmode:  cbw                ; Extend to AX
  674.       call      BinToDec        ; Convert to string
  675.       ret
  676. DoVid      ENDP
  677.  
  678. ; Procedure VeriCop
  679. ; Purpose   Check for coprocessor
  680. ; Input        None
  681. ; Output    1 for yes or 0 for no
  682.  
  683. VeriCop      PROC
  684.       int      11h            ; Check    peripherals
  685.       test      al,10b        ; Coprocessor
  686.       mov      ax,0            ; Assume no (don't change flags)
  687.       jz      no87            ; No? Done
  688.       inc      ax            ; Yes? Set to 1
  689. no87:      call      BinToDec        ; Convert to string
  690.       ret
  691. VeriCop      ENDP
  692.  
  693. ; Procedure VerAnsi
  694. ; Purpose   Check for ANSI driver
  695. ; Input        None
  696. ; Output    1 for yes or 0 for no
  697.  
  698. VerAnsi      PROC
  699.  
  700.       @DispStr ans            ; Print    ANSI string to get
  701.                     ;   cursor position
  702.       mov      ah,6            ; Check    for key
  703.       mov      dl,0FFh        ;   in buffer
  704.       int      21h
  705.       jnz      ansi            ; Done if ANSI
  706.       @DispStr overwrt        ; Overwrite ANSI string
  707.       sub      ax,ax            ; 0 if not ANSI
  708.       jmp      SHORT    gotansi
  709. ansi:      mov      ax,0C06h        ; Clear    returned ANSI keys
  710.       mov      dl,0FFh        ;   out    of buffer
  711.       int      21h
  712.       @DispStr delete        ; Delete ANSI string
  713.       mov      ax,1            ; Set 1    for true
  714. gotansi:  call      BinToDec        ; Convert to string
  715.       ret
  716. VerAnsi      ENDP
  717.  
  718. ; Procedure GetDir
  719. ; Purpose   Get    the current directory or drive
  720. ; Input        None
  721. ; Output    Current directory or drive in "string"; level or drive number in AX
  722.  
  723. GetDir      PROC      NEAR
  724.       cmp      extend,1        ; Extend flag true?
  725.       jne      directry        ; No? Get directory
  726.  
  727.       @GetDrv            ; Yes? Get drive
  728.       mov      ah,al            ; Copy
  729.       add      ah,'A'        ; Convert to drive letter
  730.       mov      string,ah        ; Put character    in string
  731.       inc      actual        ; Length 1
  732.       cbw
  733.       ret
  734.  
  735. directry: mov      si,OFFSET string    ; Load address for string
  736.       mov      BYTE PTR [si],"\"    ; Insert backslash (DOS    doesn't)
  737.       inc      si            ; Point    to next
  738.       @GetDir si
  739.       sub      cx,cx            ; Count    is zero
  740.       dec      si            ; Move pointer back to start
  741. findback: lodsb                ; Load
  742.       cmp      al,"\"        ; Is it    backslash?
  743.       jne      notslash        ; No? Continue
  744.       inc      dx            ; Yes? Increment level counter
  745. notslash: or      al,al            ; Is it    0?
  746.       loopne  findback        ; No? Repeat
  747.  
  748.       neg      cx            ; Negate to get    positive count
  749.       mov      actual,cl        ; Put level in variable
  750.       xchg      ax,dx
  751.       ret
  752. GetDir      ENDP
  753.  
  754. ; Procedure NoCmd
  755. ; Purpose   Return error for invalid command
  756. ; Input        None
  757. ; Output    None
  758.  
  759. NoCmd      PROC
  760.       @DispStr err1            ; Display error    and quit
  761.       @Exit      0
  762. NoCmd      ENDP
  763.  
  764. ; Procedure Byticize
  765. ; Purpose   Adjust word    values to fit in a byte
  766. ; Input        Value in AX
  767. ; Output    255    for word values, else value (no    extend)    or value*10 (extend)
  768.  
  769. Byticize  PROC
  770.       cmp      extend,0        ; Is extend flag set?
  771.       je      sizechk        ; No? Check size
  772.       sub      dx,dx            ; Yes? Clear DX
  773.       mov      bx,10            ; Divide by 10 to get 10-unit chunks
  774.       div      bx
  775.  
  776. sizechk:  or      ah,ah            ; Is it    255 or less?
  777.       je      byteOK
  778.       mov      al,0FFh        ; No? Call it 255
  779. byteok:      ret
  780. Byticize  ENDP
  781.  
  782. ; Procedure GetArg
  783. ; Purpose   Parse command line for argument and    prompt strings
  784. ; Input        Command line
  785. ; Output    Pointer to argument    in "arg"; length (or 0 if none)    in "larg"
  786. ;        Pointer to prompt in "prompt"; length (or 0    if none) in "lprompt"
  787.  
  788. GetArg      PROC
  789.       push      ax
  790.       push      es            ; Swap ES and DS
  791.       push      ds
  792.       pop      es
  793.       pop      ds
  794.  
  795. white:      lodsb                ; Load while white space
  796.       cmp      al,' '        ; Is it    space?
  797.       je      white            ; Throw    away
  798.       cmp      al,9            ; Is it    tab?
  799.       je      white            ; Throw    away
  800.       cmp      al,'"'                ; Is it quote?
  801.       je      promptit        ; Process
  802.       cmp      al,13            ; Is it    carriage return?
  803.       je      gotarg        ; Done
  804.  
  805.       sub      cx,cx
  806. qdone:      dec      si            ; Adjust
  807.       mov      es:arg,si        ; Save pointer to argument start
  808.  
  809. chars:      lodsb                ; Load while not white
  810.       cmp      al,' '        ; Is it    space?
  811.       je      nomore        ; Done
  812.       cmp      al,9            ; Is it    tab?
  813.       je      nomore        ; Done
  814.       cmp      al,13            ; Is it    carriage return?
  815.       loopne  chars            ; Throw    away
  816. nomore:      not      cx            ; Adjust count
  817.       mov      es:larg,cx        ; Save length
  818.       jmp      SHORT    gotarg
  819.  
  820. promptit: mov      di,si            ; Save pointer to start
  821.       sub      cx,cx            ; Clear    count
  822. inprompt: lodsb                ; Another
  823.       cmp      al,13            ; Is it    carriage return?
  824.       je      oneq            ; Yes? Treat one quote like character
  825.       cmp      al,'"'                ; Is it quote?
  826.       loopne  inprompt        ; No? Throw away
  827.       mov      es:prompt,di        ; Save prompt pointer
  828.       not      cx
  829.       mov      es:lprompt,cx        ;   and    length
  830.       jmp      SHORT    white        ; Get the argument
  831.  
  832. oneq:      mov      si,di            ; Restore
  833.       mov      cx,-1            ; Set count to -1
  834.       jmp      SHORT    qdone
  835.  
  836. gotarg:      push      es            ; Swap ES and DS back
  837.       push      ds
  838.       pop      es
  839.       pop      ds
  840.  
  841.       pop      ax
  842.       ret
  843. GetArg      ENDP
  844.  
  845. ; Procedure ShowPrmpt
  846. ; Purpose   If prompt, display it
  847. ; Input        Pointer to prompt
  848. ; Output    Prompt to screen
  849.  
  850. ShowPrmpt PROC
  851.       cmp      prompt,0        ; Is there a prompt?
  852.       je      noshow        ; If not, continue
  853.       push      ds            ; Save and restore DS
  854.       @Write  prompt,lprompt,,es    ; DOS Write function
  855.       pop      ds
  856.  
  857. noshow:      ret
  858. ShowPrmpt ENDP
  859.  
  860. ; Procedure DoEnviron
  861. ; Purpose   Convert a string to    an environment variable
  862. ; Input     String in "string", length in "actual"
  863. ; Output    String in "GET" environment variable;
  864. ;          AX has 0 for success, nonzero for    failure
  865.  
  866. DoEnviron PROC
  867.       call      GetEnv        ; Get environment size,    length,    address
  868.       mov      dx,ax            ; Save size and    length
  869.       mov      bx,cx
  870.  
  871. ; Find "GET="
  872.  
  873.       sub      di,di            ; Point    to start
  874.       sub      al,al            ; Search for zero
  875.           mov     si, OFFSET what       ; Point source at "GET="
  876. findwh:      repne      scasb            ; Search
  877.       cmp      BYTE PTR es:[di],0    ; If double null, end of environment
  878.       je      gotend
  879.       jcxz      noroom        ; Error    if not found
  880.       push      di            ; Save
  881.       push      cx
  882.       mov      si,OFFSET what    ; Load address and length of "what"
  883.       mov      cx,lwhat        ;   for    comparison
  884.       repe      cmpsb            ; Compare
  885.       mov      si,di            ; Make copy
  886.       pop      cx            ; Restore
  887.       pop      di
  888.       jnz      findwh
  889.  
  890. ; Find end of "GET" variable
  891.  
  892.       xchg      di,si
  893.       repne      scasb            ; Find end of environment variable
  894.       xchg      si,di            ; Point    source to next variable
  895.  
  896. ; Calculate characters left to write
  897.  
  898.       mov      cx,bx            ; Load total characters
  899.       sub      cx,si            ; Subtract finished to get left
  900.  
  901. ; Move everything back to overwrite "GET="
  902.  
  903. movenv:      push      ds            ; Save DS
  904.       mov      ax,es            ; Copy to ES
  905.       mov      ds,ax
  906.       rep      movsb            ; Copy
  907.       mov      BYTE PTR es:[di],0    ; Put null at end in case of error
  908.       pop      ds            ; Restore
  909.  
  910. ; Check    environment space
  911.  
  912. gotend:      mov      al,actual        ; Load length of string
  913.       sub      ah,ah            ; Clear    top
  914.       add      ax,lwhat        ; Add length of    name
  915.       add      ax,di            ; Add position to get final length
  916.       cmp      ax,dx            ; Is it    longer than environment?
  917.       jge      noroom        ; Yes? Quit
  918.  
  919. ; Put GET= at end
  920.  
  921.       mov      si,OFFSET what    ; Load address and length of what
  922.       mov      cx,lwhat
  923.       rep      movsb
  924.  
  925. ; Put new string at end
  926.  
  927.       mov      si,OFFSET string    ; Load address and length of string
  928.       mov      cl,actual
  929.       rep      movsb
  930.       mov      WORD PTR es:[di],0    ; Put double null at end
  931.       sub      ax,ax            ; Return 0 for success
  932.       ret
  933.  
  934. noroom:      inc      ax            ; Return nonzero for fail
  935.       ret
  936. DoEnviron ENDP
  937.  
  938. ; Procedure GetEnv
  939. ; Purpose   Find and measure the environment
  940. ; Input        None
  941. ; Output    Segment of environment in ES, size in AX, length in    CX
  942.  
  943. GetEnv      PROC
  944.       mov      dx,es:10h        ; Load segment of COMMAND.COM
  945.       mov      es,dx            ;   into ES
  946.       mov      ax,es:2Ch        ; Load COMMAND.COM's environment
  947.       or      ax,ax            ; Is it    0?
  948.       jnz      secondry        ; No? This is a    secondary command
  949.                     ;   and    we have    its environment    in AX
  950.       dec      dx            ; Yes? This is original    COMMAND.COM
  951.       mov      es,dx            ;   so point ES    to paragraph before PSP
  952.       add      dx,es:03        ; Offset of environment    is 3 bytes in
  953.       add      dx,2            ; Adjust it back to PSP
  954.       mov      ax,dx            ; Put it in AX
  955. secondry:
  956.  
  957. ; Note:
  958. ; CodeView cannot debug    the previous section of    code, because the PSP
  959. ; addresses checked by the code    are those passed from DOS to CodeView,
  960. ; not addresses    passed from DOS    to the program.    To debug with CodeView,
  961. ; find the actual address of the environment:
  962.  
  963. ;     S    500:0 L    FFFF "COMSPEC="
  964.  
  965. ; When you find    the actual address, hard code it into your program:
  966.  
  967. ;      mov      ax,110Ch        ; Debug    line
  968.  
  969. ; Comment the line out for final assembly after    debugging.
  970.  
  971.       mov      si,ax            ; Save a copy
  972.       sub      dx,dx            ; Clear    DX for multiply
  973.       dec      ax            ; Get paragaraph before    environment
  974.       mov      es,ax            ; Load into DS
  975.       mov      ax,es:03        ; Size in paragraphs is    at byte    4
  976.       mov      cx,16            ; Multiply by 16
  977.       mul      cx
  978.       mov      es,si            ; Restore environment address
  979.       sub      di,di            ; Point    to start
  980.       mov      cx,ax            ; Load maximum count (size of
  981.       mov      bx,ax            ;   environment) and save a copy
  982.       sub      ax,ax            ; Search for double null
  983. null2:      repne      scasb            ; Look for null
  984.       jz      noerr            ; If not out of    space, continue
  985.       sub      ax,ax            ;   else error (return 0)
  986.       jmp      error2
  987. noerr:      cmp      BYTE PTR es:[di],0    ; Is it    double null?
  988.       jne      null2            ; No? Look again
  989.       mov      cx,di            ; Yes? Save length in CX
  990.       mov      ax,bx            ; Reload size to AX
  991.  
  992.       ret
  993. GetEnv      ENDP
  994.  
  995. ; Procedure BinToDec
  996. ; Purpose   Convert binary number in AX    to string
  997. ; Input        Value in AX
  998. ; Output    Value string in "string"; length of    string in "actual"
  999.  
  1000. ; AX contains number to be converted
  1001.  
  1002. BinToDec  PROC
  1003.       push      ax
  1004.       push      es
  1005.       sub      cx,cx            ; Clear    counter
  1006.       mov      bx,10            ; Get ready to divide by 10
  1007.  
  1008. getdigit: sub      dx,dx            ; Clear    top
  1009.       div      bx            ; Remainder is last digit
  1010.       add      dl,'0'        ; Convert to ASCII
  1011.       push      dx            ; Put on stack
  1012.       inc      cx            ; Count    character
  1013.       or      ax,ax            ; Is quotient 0?
  1014.       jnz      getdigit        ; No? Get another
  1015.  
  1016.       mov      actual,cl        ; Save number of digits
  1017.       mov      ax,ds            ; Load DS to ES
  1018.       mov      es,ax
  1019.       mov      di,OFFSET string    ; Load source
  1020.  
  1021. putdigit: pop      ax            ; Get a    digit off stack
  1022.       stosb                ; Store    it to string
  1023.       loop      putdigit
  1024.  
  1025.       pop      es
  1026.       pop      ax
  1027.       ret
  1028. BinToDec  ENDP
  1029.  
  1030. ; Procedure BinToHex
  1031. ; Purpose   Convert binary number in AX to string in HEX
  1032. ; Input        Value in AX
  1033. ; Output    Value string in "string"; length of    string in "actual"
  1034.  
  1035. ; AX contains number to be converted
  1036.  
  1037. BinToHex PROC
  1038.       push      ax
  1039.       push      es
  1040.       sub      cx,cx            ; Clear    counter
  1041.       mov      bx,16         ; Get ready to divide by 16
  1042.  
  1043. hexdigit: sub      dx,dx         ; Clear top
  1044.       div      bx            ; Remainder is last digit
  1045.       add      dl,'0'        ; Convert to ASCII
  1046.       cmp      dl,58         ; May be ABCDEF
  1047.       jb      isnum
  1048.       add      dl,7
  1049. isnum:      push      dx            ; Put on stack
  1050.       inc      cx            ; Count    character
  1051.       or      ax,ax            ; Is quotient 0?
  1052.           jnz     hexdigit              ; No? Get another
  1053.           xor     dh,dh
  1054.           mov     dl,actual             ; Save number in string already, if any
  1055.           add     actual,cl             ; Save number of digits
  1056.       mov      ax,ds            ; Load DS to ES
  1057.       mov      es,ax
  1058.       mov      di,OFFSET string    ; Load source
  1059.           add     di,dx
  1060. putdigith: pop       ax             ; Get a digit off stack
  1061.       stosb                ; Store    it to string
  1062.       loop      putdigith
  1063.  
  1064.       pop      es
  1065.       pop      ax
  1066.       ret
  1067. BinToHex  ENDP
  1068.  
  1069. ; Procedure UpCase
  1070. ; Purpose   Convert a character    to uppercase
  1071. ; Input        Character in AH
  1072. ; Output    Converted character    in AH
  1073.  
  1074. UpCase      PROC
  1075.  
  1076.       cmp      ah,"a"        ; Is character below lowercase?
  1077.       jl      ok            ; If so, continue
  1078.                     ;   else
  1079.       cmp      ah,"z"        ; Is character above lowercase?
  1080.       jg      ok            ; If so, continue
  1081.                     ;   else
  1082.           sub     ah,20h                ; Make it uppercase
  1083. ok:      ret
  1084. UpCase      ENDP
  1085.  
  1086. ; Procedure Help
  1087. ; Purpose   Display syntax screens
  1088. ; Input        None
  1089. ; Output    Help to screen
  1090.  
  1091. Help      PROC
  1092.           mov   larg,0
  1093.           call BlankScreen
  1094.       @DispStr help1        ; First    screen
  1095.       ;@GetKey             ; Pause
  1096.       ;@DispStr help2         ; Second screen
  1097.       @Exit      0
  1098. Help      ENDP
  1099.  
  1100. ; Procedure Moving
  1101. ; Purpose   Display text in file in a moving display
  1102. ; Input        Filespec pointed to    by "arg"
  1103. ; Output    User input character
  1104.  
  1105. Moving    PROC
  1106.           ;cmp     prompt,0              ; Is there a prompt?
  1107.           ;je      BadFile               ; If not, continue
  1108.           mov     di,prompt             ; Point to start and end of arg
  1109.           mov     bx,lprompt
  1110.           Call    Open_Size             ; Leaves handle in bx
  1111.         or      dx,dx                   ; Size in DX:AX
  1112.         jz      @f
  1113.         mov     ax,MaxSize                ; Max size
  1114. @@:     mov     dx,offset moving_buffer ;
  1115.         mov     cx,ax                   ; File size from AX (<64k)
  1116.         cmp     cx,MaxSize
  1117.         jle     @f
  1118.         mov     cx,MaxSize
  1119. @@:     mov     ax,3f00h                ; Read file bx, (cx chars)
  1120.         int     21h
  1121.         jc      BadFile
  1122.         cmp     ax,0
  1123.         jz      BadFile
  1124.         cmp     ax,80
  1125.         jb      BadFile
  1126.         mov     bp,offset moving_buffer
  1127.         add     bp,ax
  1128.         sub     bp,79                   ; offset of last line.
  1129. again:  CALL    GET_A_KEY               ; This puts up moving message.
  1130.         mov     actual,0
  1131.         call    CheckChar               ; Char in AL
  1132.         sub     ah,ah
  1133.         CMP     AL,0                    ; Is there a key in AL?
  1134.         JZ      again                  ; If so, we are done here...
  1135.         ;jmp     short got_a_key
  1136.         ret
  1137. badfile:  sub     ax,ax                 ; Size of nothing is 0
  1138.  
  1139. ;got_a_key:  ;call    BinToDec              ; Convert to string
  1140.       ret
  1141. Moving    ENDP
  1142.  
  1143. ; Procedure get_a_key
  1144. ; Purpose   Display moving message until a key is pressed
  1145. ; Input        None
  1146. ; Output    None
  1147.  
  1148. GET_A_KEY PROC
  1149.         MOV     DL,0FFH                 ; Indicat console input.
  1150.         MOV     AX,0C06H                ; Clear keyboard buffer
  1151.         INT     21H                     ; Executes function 06, console input
  1152.         MOV     DX,1800H                ; Fixed cursor position 24,0
  1153.         ;SUB     DH,1                    ; Move the cursor up 1 row
  1154.         ;SUB     DL,DL                   ; and to the left margin
  1155.         PUSH    CX
  1156.         PUSH    DX
  1157.  
  1158. SHARE_AGAIN:
  1159.         MOV     SI,OFFSET moving_buffer ; Output a line of message
  1160. SHARE_LOOP:                             ; starting at this location
  1161.         POP     DX                      ; DX has cursor position2
  1162.         PUSH    DX                      ; so save it each time.
  1163.  
  1164.         MOV     AH,02                   ; using BIOS function 2
  1165.         INT     10H                     ; Call BIOS
  1166.         MOV     DX,SI
  1167.         MOV     CX,79
  1168.         mov     bx,2
  1169.         MOV     AH,40H                  ; This does the writing.
  1170.         INT     21H                     ; Call DOS standard error
  1171.         PUSH    DX
  1172.         MOV     DL,0FFH                 ; This checks for a key every char.
  1173.         MOV     AH,06H                  ; Now check the input status
  1174.         INT     21H                     ; Is there a key pressed?
  1175.         POP     DX                      ; If so, AL will have key and
  1176.         JNZ     THATS_ALL               ; zero flag will be clear.
  1177.         INC     DX                      ; else, show another line...
  1178.         MOV     SI,DX                   ; Save the location pointer
  1179.         MOV     AH,2CH                  ; Start timing loop...
  1180.         INT     21H                     ; Hundredths of seconds in DL,
  1181. XCHG_LOOP:
  1182.         XCHG    DX,DI                   ; So save it for comparison.
  1183. TIME_LOOP:
  1184.         MOV     AH,2CH                  ; and get the time again.
  1185.         INT     21H
  1186.         CMP     DX,DI
  1187.         JB      XCHG_LOOP
  1188.         SUB     DX,DI
  1189.         CMP     DX,15
  1190.         JB      TIME_LOOP
  1191.         CMP     SI,bp                   ; bp has the offset of the last segment
  1192.         JB      SHARE_LOOP              ; of text, so start over if there.
  1193.                                         ; This is the slow way to get a key.
  1194. ;        MOV     AH,0BH                  ; Now check the input status
  1195. ;        INT     21H                     ; Is there a key pressed?
  1196. ;        OR      AL,AL                   ; If so, AL will be FFh
  1197. ;        JNZ     THATS_ALL               ; so we are done,
  1198.                                         ; But this doesn't actually get the key.
  1199.         JMP SHORT SHARE_AGAIN
  1200. THATS_ALL:                              ; Function to get key (INKEY)
  1201.         POP     DX                      ; using DOS interrupt will be
  1202.         POP     CX                      ; handled by calling function.
  1203. KEYOK:  RET
  1204. GET_A_KEY ENDP
  1205.         .DATA
  1206. ;guess     DB      80             ; Prompt for string
  1207. ;actual    DB      0
  1208. ;string    DB      0,0
  1209. Moving_buffer db  MaxSize dup(0)
  1210.           END    start                  ; End assembly
  1211.