home *** CD-ROM | disk | FTP | other *** search
/ Frostbyte's 1980s DOS Shareware Collection / floppyshareware.zip / floppyshareware / APOG / ASM2.ZIP / DIRMATCH.ASM < prev    next >
Encoding:
Assembly Source File  |  1990-01-30  |  92.2 KB  |  1,877 lines

  1. ;----------------------------------------------------------------------;
  2. ;  DIRMATCH version 1.1           PC Magazine * Michael J. Mefford     ;
  3. ;  Points out the similarity and differences of two directories        ;
  4. ;  and then lets you update the target directory with specific         ;
  5. ;  source directory files.                                             ;
  6. ;                                                                      ;
  7. ;  Update 9/14/89  --  Fix for ROWS retrieval on pre-EGA systems.      ;
  8. ;                                                                      ;
  9. ;----------------------------------------------------------------------;
  10. _TEXT          SEGMENT PUBLIC 'CODE'
  11.                ASSUME  CS:_TEXT,DS:_TEXT,ES:_TEXT,SS:_TEXT
  12.                ORG     100H
  13. START:         JMP     MAIN
  14.  
  15. ;              DATA AREA
  16. ;              ---------
  17. SIGNATURE      DB      CR,SPACE,SPACE,SPACE,CR,LF
  18. COPYRIGHT      DB      "DIRMATCH 1.1 (C) 1989 Ziff Communications Co. ",CR,LF
  19. PROGRAMMER     DB      "PC Magazine ",BOX," Michael J. Mefford",CR,LF,LF
  20.  
  21. DB             "Syntax:  DIRMATCH source target [/D][/A]",CR,LF,LF
  22. DB             "/D = Different files",CR,LF
  23. DB             "/A = Alike files$",CTRL_Z
  24.  
  25. TAB            EQU     9
  26. CR             EQU     13
  27. LF             EQU     10
  28. CTRL_Z         EQU     26
  29. SPACE          EQU     32
  30. BOX            EQU     254
  31. VERT_LINE      EQU     179
  32. FF             EQU     12
  33. SHIFT_KEYS     EQU     3
  34. LITTLE_ARROW   EQU     26
  35. ESC_SCAN       EQU     1
  36. Y_SCAN         EQU     15H
  37. N_SCAN         EQU     31H
  38. NOTE           EQU     1046                    ; C
  39. SPEC_LENGTH    EQU     66 + 12
  40.  
  41. MENU           LABEL BYTE
  42. DB "F1 ",0, "All files  ",0, "Different files  ",0, "Alike files  ",0
  43. DB "F2 Mark all  F3 Clear marks  F4 CopyF5 Move   F6 Print   "
  44. DB "Use: ",24,32,25," PgUp PgDn Home End   +/- Mark/Unmark   Esc to Exit",0
  45.  
  46. ALL            EQU     0
  47. UNIQUE         EQU     2
  48. ALIKE          EQU     4
  49.  
  50. FILES_MODE     DB      ALL
  51. MODES          DW      DO_ALL, DO_UNIQUE, DO_ALIKE
  52.  
  53. CRT_MODE       EQU     49H
  54. CRT_ROWS       EQU     84H
  55. STATUS_REG     DW      3BAH
  56. VIDEO_SEG      DW      0B000H
  57. ROWS           DB      24
  58. SYNTAX_FLAG    DB      0
  59.  
  60. HEADING_ATTR   DB      70H
  61. ACTIVE_ATTR    DB      0FH
  62. BODY_ATTR      DB      07H
  63. HIGHLIGHT_ATTR DB      0FH
  64. MENU_ATTR      DB      07H
  65. BAR_ATTR       DB      70H
  66. INTENSE        EQU     7FH
  67. INTENSE_BLUE   EQU     1FH
  68. BLUE           EQU     17H
  69. INVERSE_BLUE   EQU     71H
  70. CYAN           EQU     31H
  71.  
  72. TOP_MEMORY     DW      ?
  73. DEFAULT_DRIVE  DB      ?
  74. SOURCE_SEG     DW      ?
  75. TARGET_SEG     DW      ?
  76. BUFFER_SEG     DW      ?
  77. BUFFER_SIZE    DW      0FFFFH
  78. SOURCE_END     DW      ?
  79. TARGET_END     DW      ?
  80. LISTING_LINE   DW      0
  81. BAR_LINE       DW      0
  82. LAST_BAR       DW      ?
  83. PAGE_LENGTH    DW      ?
  84. SOURCE_COUNT   DW      ?
  85. TARGET_COUNT   DW      ?
  86. MARKED_COUNT   DW      ?
  87. RESPONSE       DW      ?
  88.  
  89. OUT_OF_MEMORY  DB      "Not enough memory ",0,"$"
  90. TOO_MANY       DB      "Too many files ",0,"$"
  91. SOURCE_PROMPT  DB      CR,LF,LF,"Source$"
  92. TARGET_PROMPT  DB      CR,LF,LF,"Target$"
  93. NOT_FOUND      DB      " filespec not found",CR,LF
  94.                DB      "Enter filespec: $"
  95.  
  96. PRESS_MSG      DB      "Error; Press any key",0
  97. SOURCE_MSG     DB      " Source",0
  98. DIRECTORY_MSG  DB      " Directory",0
  99. FILES_MSG      DB      " files",0
  100. GAP            EQU     4
  101. DIRECTORY_LEN  EQU     $ - SOURCE_MSG + GAP - 3
  102. TO_MSG         DB      " to"
  103. TARGET_MSG     DB      " Target",0
  104. COPY_MSG       DB      "Copy ",0
  105. MOVE_MSG       DB      "Move ",0
  106. MARKED_MSG     DB      " marked files",0
  107. QUERY_MSG      DB      "?  Y/N ",0
  108. STAR_DOT_STAR  DB      "*.*",0
  109.  
  110. RECENT         DB      ">",   6 DUP (?)
  111. NOT_RECENT     DB      SPACE, 6 DUP (?)
  112.  
  113. DISPATCH_KEY   DB      48H,   50H,   49H,   51H,   47H,   4FH
  114.                DB      3BH,   54H,   3CH,   3DH,   3EH,   3FH
  115.                DB      40H,   01H,   0DH,   4EH,   0CH,   4AH
  116. DISPATCH_CNT   EQU     $ - DISPATCH_KEY
  117.  
  118. DISPATCH_TABLE DW      UP,    DOWN,  PGUP,  PGDN,  HOME,  END_KEY
  119.                DW      F1,    S_F1,  F2,    F3,    F4,    F5
  120.                DW      F6,    EXIT,  PLUS,  PLUS,  MINUS, MINUS
  121. DISPATCH_END   EQU     $ - 2
  122.  
  123. MATCHING       STRUC
  124. RESERVED       DB      21 DUP (?)
  125. ATTRIBUTE      DB              ?
  126. FILE_TIME      DW              ?
  127. FILE_DATE      DW              ?
  128. SIZE_LOW       DW              ?
  129. SIZE_HIGH      DW              ?
  130. FILE_NAME      DB      13 DUP (?)
  131. MATCHING       ENDS
  132.  
  133. FILE_RECORD    STRUC
  134. LIST_NAME      DB      12 DUP (?)
  135. LIST_BYTES     DB       9 DUP (?)
  136. LIST_DATE      DB      10 DUP (?)
  137. LIST_TIME      DB       8 DUP (?)
  138. MARK           DB              ?
  139. DOS_DATE       DW              ?
  140. DOS_TIME       DW              ?
  141. DISP_ORDER     DW              ?
  142. FILE_RECORD    ENDS
  143.  
  144. ;              CODE AREA
  145. ;              ---------
  146. MAIN           PROC    NEAR
  147.                CLD                             ;String instructions forward.
  148.                MOV     BX,0FFFFH               ;Memory allocation request will
  149.                MOV     AH,4AH                  ; fail and BX will return with
  150.                INT     21H                     ; available memory in paragraphs.
  151.                CMP     BX,64 * (1024 / 16)     ;At least 64K paragraphs?
  152.                JAE     ALLOCATE
  153.                MOV     DX,OFFSET OUT_OF_MEMORY
  154.                JMP     ERROR_EXIT              ;If no, exit.
  155. ALLOCATE:      MOV     AH,4AH                  ;Else, allocate all available.
  156.                INT     21H
  157.                MOV     AX,DS                   ;Get our segment;
  158.                ADD     AX,BX                   ; add to available and
  159.                MOV     TOP_MEMORY,AX           ; save as segment of memory top.
  160.  
  161.                MOV     SP,OFFSET STACK_POINTER ;Set up stack.
  162.  
  163.                MOV     DX,OFFSET DTA           ;Set up Disk Transfer Address.
  164.                MOV     AH,1AH
  165.                INT     21H
  166.  
  167.                MOV     AH,19H                  ;Get default drive so can
  168.                INT     21H                     ; restore after we change it.
  169.                MOV     DEFAULT_DRIVE,AL
  170.  
  171. ;----------------------------------------------;
  172. CK_SWITCH:     MOV     SI,81H                  ;Point to command line.
  173. NEXT_SWITCH:   LODSB                           ;Get a byte.
  174.                CMP     AL,CR                   ;Is it carriage return?
  175.                JZ      PARSE_SOURCE            ;If yes, done here.
  176.                CMP     AL,"/"                  ;Is it switch delimiter?
  177.                JNZ     NEXT_SWITCH             ;If no, next byte.
  178.                LODSB                           ;Get the switch character.
  179.                CMP     AL,CR                   ;Make sure it's not CR
  180.                JZ      PARSE_SOURCE            ; so we don't go past end.
  181.                AND     AL,5FH                  ;Capitalize.
  182. CK_UNIQUE:     CMP     AL,"D"                  ;If "D", then Different files.
  183.                JNZ     CK_ALIKE
  184.                MOV     FILES_MODE,UNIQUE
  185. CK_ALIKE:      CMP     AL,"A"                  ;If "A", then Alike files.
  186.                JNZ     NEXT_SWITCH             ;If none of these, next byte.
  187.                MOV     FILES_MODE,ALIKE
  188.                JMP     NEXT_SWITCH
  189.  
  190. ;---------------------------------------------------------------;
  191. ; Parse the command line for filespecs.  If one or both missing ;
  192. ; or file can't be opened, prompt the user for filespec.        ;
  193. ;---------------------------------------------------------------;
  194. PARSE_SOURCE:  MOV     SI,81H                  ;Point to command line again.
  195.                CALL    PARSE_SPEC              ;Parse a filespec.
  196.                PUSH    [SI]                    ;Save ending byte
  197.                PUSH    SI                      ; and the pointer.
  198.                JNZ     SOURCE_PATH             ;If filespec found, check path.
  199. PROMPT1:       XOR     DI,DI                   ;Else, ask user for first
  200.                CALL    PROMPT_USER             ; filespec.
  201.                CALL    PARSE_SPEC              ;Parse it.
  202.                JZ      PROMPT1                 ;If null string, prompt again.
  203. SOURCE_PATH:   MOV     DI,OFFSET SOURCE_SPEC   ;Storage for complete filespec.
  204.                CALL    FIND_PATH               ;Parse the path from filespec.
  205.                JC      PROMPT1                 ;If not found, prompt user.
  206.                MOV     SOURCE_END,SI           ;Else, store source path end.
  207.                MOV     BP,ES                   ;Calculate the segment to save
  208.                MOV     DI,OFFSET SOURCE_OFFSET ; first batch of filenames.
  209.                CALL    CALC_SEG
  210.                MOV     SOURCE_SEG,BP           ;Save it.
  211.                CALL    SOURCE_DIR
  212.                JC      ERROR_EXIT              ;If ran out of memory, exit.
  213.                POP     SI                      ;Recover command line pointer
  214.                POP     [SI]                    ; and restore string terminator.
  215.  
  216. PARSE_TARGET:  CALL    PARSE_SPEC              ;Parse for second filespec.
  217.                JNZ     TARGET_PATH             ;If not null string, check path.
  218. PROMPT2:       MOV     DI,1                    ;Else, prompt user for second
  219.                CALL    PROMPT_USER             ; filespec and
  220.                JMP     PARSE_TARGET            ; then parse it.
  221. TARGET_PATH:   MOV     DI,OFFSET TARGET_SPEC   ;Storage for complete filespec.
  222.                CALL    FIND_PATH               ;Parse path from filespec.
  223.                JC      PROMPT2                 ;If not found, prompt user.
  224.                MOV     TARGET_END,SI           ;Else, save target path end.
  225.                CALL    TARGET_DIR              ;Get target files.
  226.                JC      ERROR_EXIT
  227.  
  228. DO_SETUP:      CALL    VIDEO_SETUP             ;Prepare for video environment.
  229.                CALL    MATCH                   ;Match the filenames.
  230.  
  231. ;----------------------------------------------------------;
  232. ; Loop here processing user commands and updating display. ;
  233. ;----------------------------------------------------------;
  234. INPUT:         CALL    DISP_LISTINGS           ;Update the display.
  235.                CALL    GET_KEY
  236.                MOV     DI,OFFSET DISPATCH_KEY  ;Check dispatch table.
  237.                MOV     CX,DISPATCH_CNT
  238.                REPNZ   SCASB
  239.                JNZ     INPUT                   ;If no match, ignore.
  240.                SHL     CX,1                    ;Else, look up subroutine
  241.                MOV     DI,OFFSET DISPATCH_END
  242.                SUB     DI,CX
  243.                MOV     BP,BAR_LINE             ;Paging commands need line
  244.                MOV     BX,LISTING_LINE         ; page data.
  245.                MOV     CX,LAST_BAR
  246.                MOV     DX,PAGE_LENGTH
  247.                CALL    [DI]                    ;Process the command.
  248.                JMP     INPUT                   ;Next input.
  249.  
  250. ;----------------------------------------------;
  251. ERROR_EXIT:    CALL    PRINT_STRING            ;Print error message.
  252. ERROR:         MOV     AL,1                    ;Exit with ERRORLEVEL one.
  253.                JMP     SHORT TERMINATE
  254.  
  255. EXIT:          MOV     DH,ROWS                 ;Clear last two lines.
  256.                MOV     CH,DH
  257.                DEC     CH
  258.                XOR     CL,CL
  259.                MOV     DL,80 - 1
  260.                MOV     BH,MENU_ATTR
  261.                MOV     AX,600H                 ; by scrolling active page.
  262.                INT     10H
  263.  
  264.                XOR     BX,BX                   ;Border back to black.
  265.                MOV     AH,0BH
  266.                INT     10H
  267.  
  268.                MOV     DH,CH                   ;Place cursor on next
  269.                DEC     DH                      ; to last line.
  270.                XOR     DL,DL
  271.                CALL    SET_CURSOR
  272.                XOR     AL,AL                   ;ERRORLEVEL zero.
  273. TERMINATE:     MOV     AH,4CH                  ;Terminate.
  274.                INT     21H
  275. MAIN           ENDP
  276.  
  277. ;              ***************
  278. ;              * SUBROUTINES *
  279. ;              ***************
  280. ;-------------------------------------------------;
  281. SOURCE_DIR:    MOV     BP,SOURCE_SEG
  282.                MOV     DX,OFFSET SOURCE_SPEC
  283.                CALL    FIND_FILES              ;Find the filenames.
  284.                JC      GET_END1
  285.                CALL    CALC_SEG                ;If successful, calculate segment
  286.                MOV     TARGET_SEG,BP           ; of target DIR filename storage.
  287.                CLC
  288. GET_END1:      RET
  289.  
  290. ;-------------------------------------------------;
  291. ; OUTPUT: CY = 1 if failed;  DX -> Error message. ;
  292. ;-------------------------------------------------;
  293. TARGET_DIR:    MOV     BP,TARGET_SEG           ;Retrieve segment for filenames.
  294.                MOV     DX,OFFSET TARGET_SPEC
  295.                CALL    FIND_FILES              ;Find the filenames.
  296.                JC      GET_END2                ;If ran out of memory, exit.
  297.                CALL    CALC_SEG                ;If successful, calculate segment
  298.                MOV     BUFFER_SEG,BP           ; of copy buffer.
  299.                MOV     AX,TOP_MEMORY           ;Retrieve top of memory segment.
  300.                SUB     AX,BP                   ;Paragraphs available for buffer.
  301.                MOV     DX,OFFSET OUT_OF_MEMORY
  302.                JBE     GET_END2                ;If none, exit.
  303.                CMP     AX,80H                  ;If less than practical minimum
  304.                JB      GET_END2                ; of 2K bytes (128 para), exit.
  305.                CMP     AX,1000H                ;If more than 4K paragraphs
  306.                JAE     GET_END2                ; (64K bytes), then use default.
  307.                MOV     CL,4                    ;Else, convert paragraphs to
  308.                SHL     AX,CL                   ; bytes and save as buffer size.
  309.                MOV     BUFFER_SIZE,AX
  310.                CLC
  311. GET_END2:      RET
  312.  
  313. ;----------------------------------------------;
  314. MATCH:         MOV     BAR_LINE,0
  315.                MOV     LISTING_LINE,0          ;Move listing to top.
  316. DO_MATCH:      PUSH    DS                      ;Preserve segments.
  317.                PUSH    ES
  318.                MOV     SOURCE_COUNT,0
  319.                MOV     TARGET_COUNT,0          ;Initialize file counts to zero.
  320.  
  321.                MOV     DL,FILES_MODE           ;Get offset of current
  322.                XOR     DH,DH                   ; file display mode.
  323.                ADD     DX,OFFSET MODES
  324.                MOV     ES,TARGET_SEG           ;Target listing segment.
  325.                MOV     DS,SOURCE_SEG           ;Source listing segment.
  326.                XOR     BX,BX                   ;DS:BX -> source.
  327.                XOR     BP,BP                   ;ES:BP -> target.
  328.                XOR     AX,AX                   ;Counter.
  329. NEXT_MATCH:    CMP     BYTE PTR ES:LIST_NAME[BP],-1   ;End of listing 2?
  330.                JNZ     COMPARE                        ;If no, compare filenames.
  331.                CMP     BYTE PTR LIST_NAME[BX],-1      ;Else, end of listing 1?
  332.                JZ      MATCH_END                      ;If yes, done here.
  333.  
  334. COMPARE:       MOV     SI,BX                   ;Get pointers to filenames.
  335.                MOV     DI,BP
  336.                MOV     CX,SIZE LIST_NAME
  337.                REP     CMPSB                   ;Compare the names.
  338.                MOV     DI,DX
  339.                CALL    CS:[DI]                 ;Process.
  340.                JMP     NEXT_MATCH              ;Do next match.
  341.  
  342. MATCH_END:     POP     ES                      ;Restore segments.
  343.                POP     DS
  344.                DEC     AX                      ;Adjust counter.
  345.                JGE     STORE_BAR               ;If non-zero, OK.
  346.                XOR     AX,AX                   ;Else, use zero.
  347. STORE_BAR:     MOV     LAST_BAR,AX             ;Last bar location = count.
  348.                CALL    DISPLAY_DIRS            ;Update the directory file count.
  349.                RET
  350.  
  351. ;----------------------------------------------;
  352. DO_ALL:        MOV     SI,AX                   ;Current counter.
  353.                MOV     DI,AX
  354.                JZ      ALL_MATCH               ;If name same, check date.
  355.                JB      ALL_LEFT2               ;Else, update the one
  356.                CALL    UPDATE_LIST2            ; earlier in the alphabet
  357.                JMP     SHORT ALL_END           ; with current display order.
  358.  
  359. ALL_MATCH:     CALL    DO_DATE
  360.                JB      ALL_LEFT1
  361.                JA      ALL_RIGHT1
  362.                OR      DI,8000H                ;Highlight flag.
  363. ALL_RIGHT1:    OR      SI,8000H
  364.                JMP     SHORT ALL_UPDATE
  365. ALL_LEFT1:     OR      DI,8000H
  366. ALL_UPDATE:    CALL    UPDATE_LIST2
  367.  
  368. ALL_LEFT2:     CALL    UPDATE_LIST1
  369. ALL_END:       INC     AX                      ;Increment counter.
  370.                RET
  371.  
  372. ;----------------------------------------------;
  373. DO_UNIQUE:     MOV     SI,AX
  374.                MOV     DI,AX
  375.                JZ      UNIQUE_MATCH            ;If match, check date.
  376.                JA      UNIQUE_RIGHT            ;Else, update the one
  377.                INC     AX                      ; earlier in the alphabetic
  378.                JMP     SHORT UNIQUE_LEFT       ; with current display order.
  379. UNIQUE_RIGHT:  INC     AX
  380.                CALL    UPDATE_LIST2
  381.                JMP     SHORT UNIQUE_END
  382.  
  383. UNIQUE_MATCH:  CALL    DO_DATE
  384.                JB      UNIQUE_LEFT1
  385.                JA      UNIQUE_RIGHT1
  386.                MOV     SI,-1                   ;Non-display flag.
  387.                MOV     DI,-1
  388.                JMP     SHORT UNIQUE_UPDATE
  389. UNIQUE_RIGHT1: OR      SI,8000H                ;Highlight flag.
  390.                JMP     SHORT UNIQUE_DATE
  391. UNIQUE_LEFT1:  OR      DI,8000H
  392. UNIQUE_DATE:   INC     AX
  393.  
  394. UNIQUE_UPDATE: CALL    UPDATE_LIST2
  395. UNIQUE_LEFT:   CALL    UPDATE_LIST1
  396. UNIQUE_END:    RET
  397.  
  398. ;----------------------------------------------;
  399. DO_ALIKE:      MOV     SI,AX
  400.                MOV     DI,AX
  401.                JZ      ALIKE_MATCH             ;If match, then check date.
  402.                MOV     SI,-1
  403.                JB      ALIKE_LEFT
  404.                MOV     DI,-1                   ;Else, update the one earlier
  405.                CALL    UPDATE_LIST2            ; in the alphabet with a -1
  406.                JMP     SHORT ALIKE_END         ; non-display flag.
  407.  
  408. ALIKE_MATCH:   INC     AX
  409.                CALL    DO_DATE
  410.                JB      ALIKE_LEFT1
  411.                JA      ALIKE_RIGHT1
  412.                OR      DI,8000H
  413. ALIKE_RIGHT1:  OR      SI,8000H
  414.                JMP     SHORT ALIKE_UPDATE
  415. ALIKE_LEFT1:   OR      DI,8000H
  416.  
  417. ALIKE_UPDATE:  CALL    UPDATE_LIST2
  418. ALIKE_LEFT:    CALL    UPDATE_LIST1
  419. ALIKE_END:     RET
  420.  
  421. ;------------------------------------------------------------------------------;
  422. ; INPUT: BX -> Source name; BP -> target name; OUTPUT: ZF = 1 if date matched. ;
  423. ;------------------------------------------------------------------------------;
  424. DO_DATE:       PUSH    SI
  425.                PUSH    DI
  426.                MOV     SI,BX                   ;Get filename pointers again.
  427.                MOV     DI,BP
  428.                ADD     SI,DOS_DATE             ;Point to date/time in DOS
  429.                ADD     DI,DOS_DATE             ; format and compare.
  430.                MOV     CX,(SIZE DOS_DATE + SIZE DOS_TIME) / 2
  431.                REP     CMPSW
  432.                POP     DI
  433.                POP     SI
  434.                RET
  435.  
  436. ;----------------------------------------------;
  437. UPDATE_LIST1:  MOV     DISP_ORDER[BX],SI       ;Store the display order value.
  438.                ADD     BX,SIZE FILE_RECORD     ;Point to next filename.
  439.                INC     SI                      ;Is it -1, non-display marker?
  440.                JZ      LIST1_END               ;If yes, done here.
  441.                INC     CS:SOURCE_COUNT         ;Else, increment file count.
  442. LIST1_END:     RET
  443.  
  444. UPDATE_LIST2:  MOV     ES:DISP_ORDER[BP],DI    ;Same for the second batch of
  445.                ADD     BP,SIZE FILE_RECORD     ; of filenames.
  446.                INC     DI                      ;Is it -1, non-display marker?
  447.                JZ      LIST2_END               ;If yes, done here.
  448.                INC     CS:TARGET_COUNT         ;Else, increment file count.
  449. LIST2_END:     RET
  450.  
  451. ;----------------------------------------------;
  452. DISP_LISTINGS: PUSH    DS                      ;Preserve data segment.
  453.                PUSH    SI
  454.                MOV     BP,LISTING_LINE         ;1st line of listing to display.
  455.                MOV     CX,PAGE_LENGTH          ;No. of lines to display.
  456.                XOR     SI,SI                   ;SI -> start of source.
  457.                XOR     DX,DX                   ;DX -> start of target.
  458.                MOV     DI,(3 * 160)            ;Start display row 2; column 1.
  459. NEXT_LIST:     PUSH    CX                      ;Preserve lines to display.
  460.                MOV     DS,CS:SOURCE_SEG        ;1st in left half of screen.
  461.                MOV     CX,40                   ;39 chars in filename plus mark.
  462.                PUSH    DX                      ;Preserve DX.
  463.                CALL    DO_LIST                 ;Display the left half of line.
  464.                POP     DX                      ;Restore DX.
  465.                XCHG    SI,DX                   ;Now point to target filename.
  466.                MOV     DS,CS:TARGET_SEG        ;Also need the segment.
  467.                INC     DI                      ;Bump pointer to next line.
  468.                INC     DI
  469.                MOV     CX,39                   ;It is 39 chars too.
  470.                PUSH    DX                      ;Preserve DX.
  471.                CALL    DO_LIST                 ;Display the right half of line.
  472.                POP     DX                      ;Restore DX.
  473.                XCHG    SI,DX                   ;Restore pointers.
  474.                INC     BP                      ;Next order counter.
  475.                POP     CX                      ;Retrieve line counter.
  476.                LOOP    NEXT_LIST               ;Do all lines.
  477.                POP     SI
  478.                POP     DS                      ;Restore data segment.
  479.                RET                             ;Done here.
  480.  
  481. ;---------------------------------------------------------------;
  482. ; INPUT: DS:SI -> filename to display; Entry point at DO_LIST.  ;
  483. ;---------------------------------------------------------------;
  484. NEXT_REC1:     ADD     SI,SIZE FILE_RECORD     ;Next filename.
  485. DO_LIST:       MOV     BH,CS:BODY_ATTR         ;Assume body attribute.
  486.                CMP     LIST_NAME[SI],-1        ;Is this end of listing?
  487.                JZ      PAD_LINE                ;If yes, pad line with spaces.
  488.                MOV     AX,DISP_ORDER[SI]       ;Retrieve display order.
  489.                CMP     AX,-1                   ;Should it be displayed?
  490.                JZ      NEXT_REC1               ;If no, next record.
  491.                TEST    AX,8000H                ;Highlight bit?
  492.                JZ      COMPARE_ORDER           ;If no, use body attribute.
  493.                MOV     BH,CS:HIGHLIGHT_ATTR    ;Else, highlight.
  494.                AND     AX,NOT 8000H            ;Strip highlight bit.
  495. COMPARE_ORDER: CMP     AX,BP                   ;Else, entry less than order?
  496.                JB      NEXT_REC1               ;If yes, next record.
  497.                JA      PAD_LINE                ;If above, pad with spaces.
  498.  
  499.                CMP     CX,40                   ;Is this the source directory?
  500.                JNZ     DO_CHAR2                ;If no, skip mark field.
  501.                MOV     AL,MARK[SI]             ;Else, retrieve mark.
  502.                CALL    WRITE_SCREEN            ;Write it to display.
  503.                DEC     CX                      ;Adjust count which acted as flag
  504.                CMP     CS:BAR_LINE,BP          ;Is this the bar line?
  505.                JNZ     DO_CHAR2                ;If no, write the line.
  506.                PUSH    BX                      ;Else, preserve attribute.
  507.                MOV     BH,CS:BAR_ATTR          ;Retrieve bar attribute.
  508.                MOV     CX,SIZE LIST_NAME       ;Write name with bar attribute.
  509. DO_CHAR1:      LODSB
  510.                CALL    WRITE_SCREEN
  511.                LOOP    DO_CHAR1
  512.                POP     BX                      ;Retrieve display attribute.
  513.                MOV     CX,39 - SIZE LIST_NAME  ;Rest of name.
  514. DO_CHAR2:      LODSB                           ;Display the filename.
  515.                CALL    WRITE_SCREEN
  516.                LOOP    DO_CHAR2
  517.                ADD     SI,7                    ;Past date/time/order/mark fields
  518.                JMP     SHORT DO_LIST_END
  519.  
  520. PAD_LINE:      CMP     CX,40                   ;Is this source directory?
  521.                JNZ     DO_PAD2                 ;If no, just write spaces.
  522.                MOV     AL,SPACE                ;Else, write one space as mark.
  523.                CALL    WRITE_SCREEN
  524.                DEC     CX                      ;Adjust counter flag.
  525.                CMP     CS:BAR_LINE,BP          ;Is this the bar line?
  526.                JNZ     DO_PAD2                 ;If no, write line.
  527.                PUSH    BX                      ;Else, display bar and
  528.                MOV     BH,CS:BAR_ATTR          ; then rest of blank line.
  529.                MOV     CX,SIZE LIST_NAME
  530. DO_PAD1:       MOV     AL,SPACE
  531.                CALL    WRITE_SCREEN
  532.                LOOP    DO_PAD1
  533.                POP     BX
  534.                MOV     CX,39 - SIZE LIST_NAME
  535. DO_PAD2:       MOV     AL,SPACE
  536.                CALL    WRITE_SCREEN
  537.                LOOP    DO_PAD2
  538. DO_LIST_END:   RET
  539.  
  540. ;-------------------------------------------------------------------------;
  541. ; INPUT:  SI -> string to parse.                                          ;
  542. ; OUTPUT: BP -> filespec start; SI -> filespec end; BX -> filename start. ;
  543. ;         ZF = 1 if null string.                                          ;
  544. ;-------------------------------------------------------------------------;
  545. PARSE_SPEC:    LODSB                           ;Get a byte.
  546.                CMP     AL,SPACE                ;Is it a space char or below?
  547.                JA      LEADING_END             ;If no, found start.
  548.                CMP     AL,CR                   ;Is it carriage return?
  549.                JNZ     PARSE_SPEC              ;If no, get next byte.
  550. LEADING_END:   DEC     SI                      ;Adjust pointer to string start.
  551.                MOV     BP,SI                   ;Save start of filespec.
  552.                MOV     BX,SI                   ;Use BX as filename start pointer
  553.  
  554. FIND_END:      LODSB                           ;Get a byte.
  555.                CMP     AL,":"                  ;Is it a drive delimiter?
  556.                JNZ     CK_SLASH                ;If no, check path delimiter.
  557.                MOV     DL,[SI-2]               ;Else, retrieve drive specifier.
  558.                AND     DL,5FH                  ;Capitalize.
  559.                SUB     DL,"A"                  ;Convert to DOS format.
  560.                MOV     AH,0EH                  ;Change drive.
  561.                INT     21H
  562.                MOV     BX,SI                   ;Save as filename start.
  563.                MOV     AH,19H                  ;Get current disk.
  564.                INT     21H
  565.                CMP     AL,DL                   ;Was it a valid disk request?
  566.                JZ      FIND_END                ;If yes, continue parsing.
  567. FIND_DELIMIT:  LODSB                           ;Else, find delimiter
  568.                CMP     AL,SPACE
  569.                JA      FIND_DELIMIT
  570.                DEC     SI
  571.                MOV     BP,SI                   ; and emulate null string.
  572.                JMP     SHORT PARSE_END
  573.  
  574. CK_SLASH:      CMP     AL,"\"                  ;Is it a path delimiter?
  575.                JNZ     CK_DELIMITER            ;If no, check switch character.
  576.                MOV     BX,SI                   ;Else, save as filename start.
  577. CK_DELIMITER:  CMP     AL,"/"                  ;Is it a switch delimiter?
  578.                JZ      FOUND_END               ;If yes, end of filespec.
  579.                CMP     AL,SPACE                ;Is it above space character?
  580.                JA      FIND_END                ;If yes, continue until find end.
  581.  
  582. FOUND_END:     DEC     SI                      ;Adjust.
  583.                PUSH    SI
  584.                MOV     SI,OFFSET CURRENT_DIR   ;Get default directory.
  585.                CALL    GET_DIR
  586.                POP     SI
  587. PARSE_END:     CMP     BP,SI                   ;Any filespec?
  588.                RET                             ;Return result to caller.
  589.  
  590. ;-----------------------------------------------------------;
  591. ; INPUT:  DI = 0 for first prompt, DI = 1 for second prompt ;
  592. ; OUTPUT: SI -> string start.                               ;
  593. ;-----------------------------------------------------------;
  594. PROMPT_USER:   CMP     SYNTAX_FLAG,1           ;If first time through, display
  595.                JZ      PROMPT                  ; syntax message.
  596.                MOV     SYNTAX_FLAG,1
  597.                CALL    CLS
  598.                XOR     DX,DX
  599.                CALL    SET_CURSOR
  600.                MOV     DX,OFFSET SIGNATURE
  601.                CALL    PRINT_STRING
  602.  
  603. PROMPT:        MOV     DX,OFFSET SOURCE_PROMPT ;Point to appropriate prompt
  604.                OR      DI,DI
  605.                JZ      DISP_PROMPT
  606.                MOV     DX,OFFSET TARGET_PROMPT
  607. DISP_PROMPT:   CALL    PRINT_STRING            ; and display it.
  608.                MOV     DX,OFFSET NOT_FOUND
  609.                CALL    PRINT_STRING
  610.                MOV     SI,OFFSET USER_INPUT    ;User input storage.
  611.                MOV     BYTE PTR [SI],65        ;Maximum of 65 characters.
  612.                MOV     DX,SI
  613.                MOV     AH,0AH
  614.                INT     21H                     ;Buffered Keyboard Input.
  615.                INC     SI
  616.                MOV     BYTE PTR [SI],SPACE     ;Emulate command line entry.
  617.                INC     SI                      ;SI -> string.
  618.                RET
  619.  
  620. ;-------------------------------------------------------------------------;
  621. ; INPUT:  BP -> filespec start; SI -> filespec end; BX -> filename start. ;
  622. ;         DI -> filespec storage;                                         ;
  623. ; OUTPUT: SI -> path end; CY = 0 if filespec exist; CY = 1 if not exist.  ;
  624. ;-------------------------------------------------------------------------;
  625. FIND_PATH:     MOV     BYTE PTR [SI],0         ;ASCIIZ the string.
  626.                CMP     BYTE PTR [SI - 1],":"   ;Drive-only?
  627.                JZ      DO_GLOBAL               ;If yes, use global.
  628. CK_ROOT:       MOV     CX,1                    ;CX=1:"\"not=root; CX=0:"\"=root.
  629.                CMP     BYTE PTR [BX - 1],"\"   ;Filespec start path delimiter?
  630.                JNZ     CK_PATH                 ;If no, not root.
  631.                CMP     BYTE PTR [BX - 2],":"   ;Else, is it prefaced with colon?
  632.                JZ      ROOT                    ;If yes, then root.
  633.                CMP     BYTE PTR [BX - 2],SPACE ;Is it prefaced with white space?
  634.                JA      CK_TRAILING             ;If no, then trailing slash?
  635. ROOT:          DEC     CX                      ;Else, root; CX=0 for root flag.
  636.                JMP     SHORT CK_PATH           ;Change default path.
  637.  
  638. CK_TRAILING:   CMP     BX,SI                   ;Filename start = filespec end?
  639.                JNZ     CK_PATH                 ;If no, not trailing slash.
  640.                MOV     BYTE PTR [BX - 1],0     ;Else, zero out trailing slash
  641.                MOV     BX,OFFSET STAR_DOT_STAR ; and use global filespec.
  642.  
  643. CK_PATH:       MOV     DX,BP                   ;See if filespec is a path
  644.                CALL    CHANGE_DIR              ; by changing directory.
  645.                JC      CK_FILESPEC             ;If failed, remove filename.
  646. DO_GLOBAL:     MOV     BX,OFFSET STAR_DOT_STAR ;Else, use global for filename.
  647.                JMP     SHORT GOT_FILESPEC      ;Done here.
  648.  
  649. CK_FILESPEC:   JCXZ    SAVE_DELIMIT            ;Is path root?; If yes leave "\".
  650.                DEC     BX                      ;Else, point to slash.
  651. SAVE_DELIMIT:  PUSH    [BX]                    ;Preserve filename start.
  652.                MOV     BYTE PTR [BX],0         ;Temp ASCIIZ twixt path and name.
  653.                CALL    CHANGE_DIR              ;Change directory.
  654.                POP     [BX]                    ;Restore first byte of filename.
  655.                PUSHF                           ;Save CHDIR status.
  656.                JCXZ    CK_FILENAME             ;If root, done here.
  657.                INC     BX                      ;Else, readjust filename pointer.
  658. CK_FILENAME:   POPF                            ;Retrieve CHDIR status.
  659.                JNC     GOT_FILESPEC            ;If successful, got filespec.
  660.                CALL    FIND_FIRST              ;Else, check if filename.
  661.                JC      RESTORE_DRIVE           ;If not, invalid filespec.
  662.  
  663. GOT_FILESPEC:  MOV     AH,19H                  ;Get current drive.
  664.                INT     21H
  665.                ADD     AL,"A"                  ;Convert to ASCII.
  666.                MOV     [DI + SPEC_LENGTH],AL   ;Make a copy.
  667.                STOSB                           ;Store it.
  668.                MOV     AL,":"                  ;Add colon delimiter.
  669.                MOV     [DI + SPEC_LENGTH],AL   ;Make a copy.
  670.                STOSB
  671.                MOV     SI,DI
  672.                ADD     DI,SPEC_LENGTH
  673.                CALL    GET_DIR                 ;Add complete path via DOS.
  674.                DEC     SI                      ;Point to "\".
  675. PATH_END:      LODSB                           ;Make a copy and at the same
  676.                STOSB                           ; time find end of path.
  677.                OR      AL,AL
  678.                JNZ     PATH_END
  679.                DEC     DI                      ;Point to end of path.
  680.                PUSH    DI                      ;Add save it.
  681.                DEC     SI                      ;Adjust spec path pointer also.
  682.                MOV     DI,SI
  683.                MOV     SI,BX
  684.                CALL    ADD_NAME                ;Add spec to end of path.
  685.  
  686.                MOV     DX,OFFSET CURRENT_DIR   ;Restore default directory.
  687.                CALL    CHANGE_DIR
  688.                POP     SI                      ;Return path end pointer.
  689.                CLC                             ;Successful.
  690.  
  691. RESTORE_DRIVE: PUSHF
  692.                MOV     DL,DEFAULT_DRIVE        ;Restore default drive.
  693.                MOV     AH,0EH
  694.                INT     21H
  695.                POPF
  696.                RET
  697.  
  698. ;------------------------------------------------------------------------------;
  699. ; INPUT:  DX -> Complete filespec;  BP -> Seg name storage.                    ;
  700. ; OUTPUT: BP:DI -> Storage end;  CY = 0 if successful                          ;
  701. ;         CY = 1 if segment full or ran out of memory and DX -> Error message. ;
  702. ;------------------------------------------------------------------------------;
  703. FIND_FILES:    PUSH    ES                      ;Preserve extra segment.
  704.                MOV     ES,BP                   ;ES:DI -> filename storage.
  705.                XOR     DI,DI
  706.                MOV     WORD PTR ES:[DI],-1     ;Assume empty directory.
  707.                CALL    FIND_FIRST              ;Any files?
  708.                JC      FILES_DONE              ;If no, assumed right.
  709.  
  710. FIND_NEXT:     CALL    STORE_NAME              ;Store a filename.
  711.                CALL    CK_AVAIL                ;Make sure we not out of memory.
  712.                JC      FILES_END               ;If not enough, exit.
  713.                MOV     AH,4FH                  ;Find Next Matching.
  714.                INT     21H
  715.                JNC     FIND_NEXT               ;If successful store filename.
  716.                MOV     AX,-1                   ;Else, mark the end with -1.
  717.                STOSW
  718.                CALL    SORT                    ;Sort 'em.
  719. FILES_DONE:    CLC                             ;No error so CY = 0.
  720. FILES_END:     POP     ES                      ;Restore extra segment.
  721.                RET
  722.  
  723. ;---------------------------------------------------------------------;
  724. ; INPUT: ES segment of filenames to sort;  Selection sort algorithm.  ;
  725. ;---------------------------------------------------------------------;
  726. SORT:          PUSH    DS                      ;Preserve couple registers.
  727.                PUSH    DI
  728.                PUSH    ES
  729.                POP     DS                      ;DS = ES.
  730.                XOR     SI,SI                   ;SI = first record.
  731.  
  732. NEXT_SORT:     MOV     AX,SI                   ;Carry source pointer in AX.
  733.                MOV     BX,SI                   ;Carry destination pointer in DX.
  734.                ADD     BX,SIZE FILE_RECORD
  735.                CMP     WORD PTR [BX],-1        ;Sort is done when last record.
  736.                JZ      SORT_END
  737.  
  738.                PUSH    SI                      ;Save record pointer.
  739. NEXT_RECORD:   MOV     SI,AX                   ;Restore inside loop pointers.
  740.                MOV     DI,BX
  741.                MOV     CX,SIZE LIST_NAME       ;Filename length.
  742.                REPZ    CMPSB                   ;Compare the name fields.
  743.                JB      NO_SWITCH               ;If below, no switch.
  744. SWAP:          MOV     AX,BX                   ;Else, AX = selected record.
  745.  
  746. NO_SWITCH:     ADD     BX,SIZE FILE_RECORD     ;Move to next record in list.
  747.                CMP     WORD PTR [BX],-1        ;End of list?
  748.                JNZ     NEXT_RECORD             ;If no, continue.
  749.  
  750.                POP     SI                      ;Else, restore outside loop ptr.
  751.                CMP     SI,BX                   ;Did we make a selection?
  752.                JZ      SELECT_LOOP             ;If no, go to next list.
  753.  
  754.                PUSH    SI                      ;Else, save pointer.
  755.                MOV     CX,(SIZE FILE_RECORD - 2) / 2
  756.                MOV     DI,AX
  757. NEXT_SWAP:     MOV     AX,[DI]                 ;Swap the selection into place.
  758.                MOVSW
  759.                MOV     [SI - 2],AX
  760.                LOOP    NEXT_SWAP
  761.                POP     SI
  762.  
  763. SELECT_LOOP:   ADD     SI,SIZE FILE_RECORD     ;Next record.
  764.                JMP     NEXT_SORT
  765.  
  766. SORT_END:      POP     DI                      ;Restore registers.
  767.                POP     DS
  768.                RET
  769.  
  770. ;----------------------------------------------------------------------------;
  771. ; INPUT: ES:DI pointer; OUTPUT: CY = 1 if segment full or ran out of memory  ;
  772. ;----------------------------------------------------------------------------;
  773. CK_AVAIL:      CMP     DI,65535 - (2 * SIZE FILE_RECORD)   ;End of segment?
  774.                MOV     DX,OFFSET TOO_MANY
  775.                JA      AVAIL_END               ;If yes, too many files.
  776.                MOV     AX,DI                   ;Else, calculate the pointer
  777.                ADD     AX,16 + 15              ; in paragraphs.
  778.                MOV     CL,4
  779.                SHR     AX,CL
  780.                MOV     BX,ES
  781.                ADD     AX,BX
  782.                CMP     AX,TOP_MEMORY           ;Top of memory?
  783.                MOV     DX,OFFSET OUT_OF_MEMORY ;If yes, not enough memory.
  784.                JA      AVAIL_END
  785.                STC
  786. AVAIL_END:     CMC                             ;Complement the carry status.
  787.                RET
  788.  
  789. ;----------------------------------------------------------------------;
  790. ; INPUT: BP:DI = current seg:off;  OUTPUT: BP = start of new segment.  ;
  791. ;----------------------------------------------------------------------;
  792. CALC_SEG:      ADD     DI,SIZE FILE_RECORD + 15
  793.                MOV     CL,4
  794.                SHR     DI,CL
  795.                ADD     BP,DI
  796.                RET
  797.  
  798. ;--------------------------------------------------------------------------;
  799. ; Keyboard subroutines.                                                    ;
  800. ; INPUT: BP = BAR_LINE; BX = LISTING_LINE; CX = LAST_BAR; DX = PAGE_LENGTH ;
  801. ;--------------------------------------------------------------------------;
  802. PLUS:          MOV     AL,LITTLE_ARROW         ;Use little right arrow for mark.
  803.                JMP     SHORT PLUSMINUS
  804.  
  805. MINUS:         MOV     AL,SPACE                ;Remove mark with space char.
  806.  
  807. PLUSMINUS:     PUSH    DS                      ;Preserve some registers.
  808.                PUSH    BX
  809.                CALL    FIND_BAR                ;Find bar record.
  810.                JC      PLUSMINUS_END           ;If on blank line, skip.
  811.                MOV     MARK[SI],AL             ;Else, store the mark.
  812. PLUSMINUS_END: POP     BX                      ;Restore registers.
  813.                POP     DS
  814.                MOV     AH,2
  815.                INT     16H                     ;Shift key pressed?
  816.                TEST    AL,SHIFT_KEYS           ;If no, move down line.
  817.                JZ      DOWN                    ;Else, move up a line.
  818.  
  819. UP:            DEC     BP                      ;Move bar up a line.
  820.                JL      PAGEKEY_END             ;If < 0, ignore.
  821.                CMP     BP,BX                   ;If bar below top, OK.
  822.                JAE     PAGE_UPDATE
  823.                DEC     BX                      ;Else, move listing up a line.
  824.                JMP     SHORT PAGE_UPDATE
  825.  
  826. DOWN:          INC     BP                      ;Move bar down a line.
  827.                CMP     BP,CX                   ;If > last line, then ignore.
  828.                JA      PAGEKEY_END
  829.                ADD     DX,BX                   ;Listing top + page length =
  830.                CMP     BP,DX                   ; listing bottom; If bar below
  831.                JB      PAGE_UPDATE             ; listing bottom, OK.
  832.                INC     BX                      ;Else move listing down a line.
  833.                JMP     SHORT PAGE_UPDATE
  834.  
  835. PGUP:          SUB     BP,DX                   ;Move bar up a page.
  836.                SUB     BX,DX                   ;Move listing up a page.
  837.                JC      HOME                    ;If listing < top, then home.
  838.                JMP     SHORT PAGE_UPDATE       ;Else, OK.
  839.  
  840. PGDN:          ADD     BX,DX                   ;Move listing down a page.
  841.                CMP     BX,CX                   ;If <= last line, do bar.
  842.                JBE     DO_BAR
  843.                SUB     BX,DX                   ;Else, back to where we were
  844.                MOV     BP,CX                   ; and move bar to last line
  845.                JMP     SHORT PAGE_UPDATE       ; and update.
  846. DO_BAR:        ADD     BP,DX                   ;Move bar down a page.
  847.                CMP     BP,CX                   ;If bar <= last line, OK.
  848.                JBE     PAGE_UPDATE
  849.                MOV     BP,CX                   ;Else, move bar to last line.
  850.                JMP     SHORT PAGE_UPDATE
  851.  
  852. HOME:          XOR     BP,BP                   ;Move bar to top.
  853.                XOR     BX,BX                   ;Move listing to top.
  854.                JMP     SHORT PAGE_UPDATE
  855.  
  856. END_KEY:       MOV     BP,CX                   ;Move bar to last line.
  857.                INC     CX                      ;Last line + 1 - page length =
  858.                SUB     CX,DX                   ; top of last page.
  859.                CMP     BX,CX                   ;If less than a full page,
  860.                JG      PAGE_UPDATE             ; then already at last page.
  861.                MOV     BX,CX                   ;Else, move listing to last page.
  862.                JMP     SHORT PAGE_UPDATE
  863.  
  864. PAGE_UPDATE:   MOV     BAR_LINE,BP             ;Store the new bar
  865.                MOV     LISTING_LINE,BX         ; and listing line start.
  866. PAGEKEY_END:   RET
  867.  
  868. ;----------------------------------------------;
  869. F1:            MOV     AH,FILES_MODE           ;Retrieve current file mode.
  870.                INC     AH                      ;Go to next mode.
  871.                INC     AH
  872.                CMP     AH,ALIKE                ;Is it above last mode, Alike?
  873.                JBE     F1_STORE                ;If no, OK.
  874.                XOR     AH,AH                   ;Else, wrap to All file mode.
  875.                JMP     SHORT F1_STORE          ;Store and update.
  876.  
  877. S_F1:          MOV     AH,FILES_MODE           ;Retrieve current file mode.
  878.                DEC     AH                      ;Reverse direction.
  879.                DEC     AH
  880.                CMP     AH,ALL                  ;Is it below All file mode?
  881.                JGE     F1_STORE                ;If no, OK.
  882.                MOV     AH,ALIKE                ;Else, wrap to last mode, Alike?
  883.  
  884. F1_STORE:      MOV     FILES_MODE,AH           ;Store new mode.
  885.                CALL    DISPLAY_MENU            ;Update the menu.
  886.                CALL    MATCH                   ;Update the matches.
  887.                RET
  888.  
  889. ;----------------------------------------------;
  890. F2:            MOV     AL,LITTLE_ARROW         ;Mark all records with little
  891.                JMP     SHORT DO_MARKS          ; right arrow.
  892.  
  893. ;----------------------------------------------;
  894. F3:            MOV     AL,SPACE                ;Mark all records with space char
  895. DO_MARKS:      PUSH    DS
  896.                MOV     DS,SOURCE_SEG
  897.                XOR     SI,SI                   ;DS:SI -> source records.
  898.                JMP     SHORT DO_MARK
  899. NEXT_ALL:      ADD     SI,SIZE FILE_RECORD     ;Next record.
  900. DO_MARK:       CMP     LIST_NAME[SI],-1        ;Is this last record?
  901.                JZ      MARKS_END               ;If yes, done.
  902.                MOV     MARK[SI],AL             ;Else, store mark.
  903.                JMP     SHORT NEXT_ALL
  904. MARKS_END:     POP     DS
  905.                RET
  906.  
  907. ;----------------------------------------------;
  908. F4:            MOV     RESPONSE,OFFSET COPY_MSG
  909.                JMP     SHORT CK_COPY
  910.  
  911. F5:            MOV     RESPONSE,OFFSET MOVE_MSG
  912.                CMP     FILES_MODE,ALIKE        ;Can't move files in alike mode.
  913.                JNZ     CK_COPY
  914.                CALL    BEEP
  915.                RET
  916.  
  917. CK_COPY:       PUSH    DS                      ;Preserve data segment.
  918.                MOV     DS,SOURCE_SEG           ;DS:SI -> source records.
  919.                XOR     SI,SI
  920.                XOR     CX,CX                   ;Initialize counter to zero.
  921.                JMP     SHORT COUNT_MARKS       ;Count the marks.
  922. FOUND_MARK:    INC     CX                      ;Increment count.
  923. NEXT_COUNT:    ADD     SI,SIZE FILE_RECORD     ;Next record.
  924. COUNT_MARKS:   CMP     LIST_NAME[SI],-1        ;Last record?
  925.                JZ      GOT_COUNT               ;If yes, got count of marks.
  926.                CMP     DISP_ORDER[SI],-1       ;Else, is record displayed?
  927.                JZ      NEXT_COUNT              ;If no, skip.
  928.                CMP     MARK[SI],LITTLE_ARROW   ;Else, is it marked?
  929.                JNZ     NEXT_COUNT              ;If no, skip.
  930.                JMP     FOUND_MARK              ;Else, count it.
  931. GOT_COUNT:     POP     DS                      ;Restore data segment.
  932.  
  933.                MOV     MARKED_COUNT,CX         ;Save count of marks.
  934.                JCXZ    COPY_BAR                ;If none marked, copy bar.
  935.                CALL    GET_COUNT               ;Else, convert count to ASCII.
  936.                MOV     BX,OFFSET MARKED_MSG    ;Will display marked message.
  937.                CALL    GET_RESPONSE            ;Ask user if should continue.
  938.                JNZ     COPY_MARKED             ;If confirmed, continue.
  939.                JMP     F4_END                  ;Else, exit.
  940.  
  941. COPY_MARKED:   PUSH    LISTING_LINE            ;Preserve current page
  942.                PUSH    BAR_LINE                ; and bar line.
  943.                CALL    HOME                    ;Start searching for marked
  944.                XOR     SI,SI                   ; files from home position.
  945.                JMP     SHORT CK_ABORT          ;Go check keypress for abort.
  946.  
  947. NEXT_REC3:     ADD     SI,SIZE FILE_RECORD     ;Next record.
  948. NEXT_MARKED:   MOV     BP,BAR_LINE             ;Paging commands need line
  949.                MOV     BX,LISTING_LINE         ; page data.
  950.                MOV     CX,LAST_BAR
  951.                MOV     DX,PAGE_LENGTH
  952.                CALL    DOWN                    ;Move bar down a line.
  953.  
  954. CK_ABORT:      CALL    CK_KEY                  ;Any keypress?
  955.                JNZ     MARKED_END              ;If yes, quite copying.
  956.                CALL    DISP_LISTINGS           ;Else, display current bar.
  957.                PUSH    DS
  958.                MOV     DS,SOURCE_SEG
  959.                MOV     AX,DISP_ORDER[SI]       ;Retrieve display order and
  960.                MOV     BL,MARK[SI]             ; mark of current record.
  961.                POP     DS
  962.                CMP     AX,-1                   ;Is it displayed?
  963.                JNZ     CK_BAR                  ;If yes, see if bar record.
  964.                ADD     SI,SIZE FILE_RECORD     ;Else, next record.
  965.                JMP     CK_ABORT
  966.  
  967. CK_BAR:        AND     AX,NOT 8000H            ;Else, strip highlight bit.
  968.                CMP     AX,BAR_LINE             ;Is it current line?
  969.                JA      NEXT_MARKED             ;If above, skip for now.
  970.                CMP     BL,LITTLE_ARROW         ;Is it marked?
  971.                JNZ     NEXT_REC3               ;If no, next record.
  972.  
  973.                MOV     BP,SI                   ;Else, copy; First convert name
  974.                CALL    GET_SOURCE              ; back to dot delimited ASCIIZ.
  975.                CALL    COPY                    ;Copy the file.
  976.                JC      MARKED_END              ;If failed, exit.
  977.                MOV     SI,BP                   ;Else, retrieve record pointer.
  978.                DEC     MARKED_COUNT            ;Decrement marked count.
  979.                JNZ     NEXT_REC3               ;Continue until zero.
  980.                CALL    DISP_LISTINGS           ;Display last asterisk.
  981.  
  982. MARKED_END:    POP     BAR_LINE                ;Restore bar and page.
  983.                POP     LISTING_LINE
  984.                JMP     SHORT F4_REREAD         ;Done.
  985.  
  986. ;----------------------------------------------;
  987. COPY_BAR:      PUSH    DS
  988.                CALL    FIND_BAR                ;Find bar record.
  989.                POP     DS
  990.                JNC     VALID_BAR               ;Is bar on blank line?
  991.                CALL    BEEP                    ;If yes, beep and exit.
  992.                JMP     SHORT F4_END
  993. VALID_BAR:     MOV     BP,SI                   ;Else, convert name to dot
  994.                CALL    GET_SOURCE              ; delimited ASCIIZ.
  995.                XOR     BX,BX                   ;No "marked files" message.
  996.                CALL    GET_RESPONSE            ;Ask user for confirmation.
  997.                JZ      F4_END                  ;If aborted, exit.
  998.                CALL    COPY                    ;Else, copy the highlighted file.
  999.  
  1000. F4_REREAD:     CMP     RESPONSE,OFFSET MOVE_MSG  ;Did we move files?
  1001.                JNZ     READ_TARGET             ;If no, just read target.
  1002.                CALL    SOURCE_DIR              ;Else, get new source dir also.
  1003. READ_TARGET:   CALL    TARGET_DIR
  1004.                JNC     F4_UPDATE
  1005.                CALL    MENU_OFFSET             ;Calculate menu offset.
  1006.                ADD     DI,80 * 2               ;Place error message on second
  1007.                MOV     BH,MENU_ATTR            ; menu line with menu attribute.
  1008.                MOV     SI,DX                   ;Error message.
  1009.                CALL    WRITE_STRING            ;Write the message.
  1010.                MOV     SI,OFFSET PRESS_MSG
  1011.                CALL    WRITE_STRING
  1012.                CALL    HIDE_CURSOR             ;Rehide the cursor.
  1013.                CALL    BEEP                    ;Draw attention with beep.
  1014.                CALL    GET_KEY                 ;Pause for keystroke.
  1015.                CALL    CLS
  1016.                XOR     DX,DX
  1017.                CALL    SET_CURSOR
  1018.                JMP     ERROR                   ;Abort to DOS.
  1019.  
  1020. F4_UPDATE:     CMP     RESPONSE,OFFSET MOVE_MSG  ;Did we do a move?
  1021.                JZ      KEEP_BAR                  ;If yes, preserve bar/page.
  1022.                CMP     FILES_MODE,UNIQUE         ;Are different files displayed?
  1023.                JNZ     KEEP_BAR                  ;If no, then preserve bar/page.
  1024.                CALL    MATCH                     ;Else, home bar and page.
  1025.                JMP     SHORT F4_END
  1026. KEEP_BAR:      CALL    DO_MATCH
  1027.  
  1028. F4_END:        CALL    HIDE_CURSOR             ;Rehide the cursor.
  1029.                CALL    DISPLAY_MENU            ;Redisplay the menu.
  1030.                CALL    CLEAR_KEY               ;Clear the keyboard.
  1031.                RET                             ;Done.
  1032.  
  1033. ;--------------------------------------------------;
  1034. ; OUTPUT:  CY = 1 if failed; CY = 0 if successful. ;
  1035. ;--------------------------------------------------;
  1036. COPY:          MOV     SI,OFFSET SOURCE_NAME   ;Add filename to both source
  1037.                MOV     DI,SOURCE_END           ; and target path spec.
  1038.                CALL    ADD_NAME
  1039.                MOV     SI,OFFSET SOURCE_NAME
  1040.                MOV     DI,TARGET_END
  1041.                CALL    ADD_NAME
  1042.  
  1043.                MOV     DX,OFFSET SOURCE_FILE   ;Get attribute, size and date
  1044.                CALL    FIND_FIRST              ; of source file via Find First.
  1045.                MOV     SI,OFFSET DTA
  1046.                MOV     DI,OFFSET SOURCE_STATS  ;Store the info.
  1047.                MOV     CX,SIZE MATCHING
  1048.                REP     MOVSB
  1049.  
  1050.                MOV     AX,3D00H                ;Open source file for reading.
  1051.                INT     21H
  1052.                JNC     SAVE_HANDLE
  1053.                JMP     COPY_END                ;If failed, exit.
  1054. SAVE_HANDLE:   MOV     DI,AX                   ;Else, save source handle.
  1055.  
  1056.                MOV     DX,OFFSET TARGET_FILE   ;Point to target name.
  1057.                CALL    FIND_FIRST              ;Does it exist?
  1058.                JNC     CK_IF_MOVE              ;If yes, see if move request.
  1059.                CALL    DISK_FREE               ;Else, get disk free space.
  1060.                JMP     SHORT CK_FREE           ;Go see if enough room.
  1061.  
  1062. CK_IF_MOVE:    CMP     RESPONSE,OFFSET MOVE_MSG ;Is it a move request?
  1063.                JNZ     CK_IF_SAME               ;If no, see if same as source.
  1064.                STC
  1065.                JMP     CLOSE_READ              ;Else, exit with error flag.
  1066.  
  1067. CK_IF_SAME:    MOV     CL,DTA.ATTRIBUTE        ;Get attribute of target
  1068.                XOR     CH,CH
  1069.                MOV     SI,CX                   ; and save.
  1070.                XOR     CX,1                    ;Flip read-only attribute.
  1071.                MOV     AX,4301H                ;Change file mode.
  1072.                INT     21H
  1073.                MOV     DX,OFFSET SOURCE_FILE   ;Now get source attribute.
  1074.                MOV     AX,4300H
  1075.                INT     21H
  1076.                JNC     CK_CHANGED
  1077.                JMP     COPY_END                   ;Exit if error.
  1078. CK_CHANGED:    CMP     CL,SOURCE_STATS.ATTRIBUTE  ;Else, see if it has changed.
  1079.                PUSHF                              ;Save compare results.
  1080.                MOV     DX,OFFSET TARGET_FILE      ;Restore target attribute.
  1081.                MOV     CX,SI
  1082.                MOV     AX,4301H                 ;Change file mode.
  1083.                INT     21H
  1084.                POPF                             ;Retrieve compare results.
  1085.                STC                              ;Assume files are the same.
  1086.                JNZ     CLOSE_READ               ;If attr changed, they are; exit
  1087.                CALL    DISK_FREE                ;Else, get disk free space.
  1088.                ADD     AX,DTA.SIZE_LOW
  1089.                ADC     DX,DTA.SIZE_HIGH           ;Target size + disk free.
  1090. CK_FREE:       SUB     AX,SOURCE_STATS.SIZE_LOW   ;Total - source size.
  1091.                SBB     DX,SOURCE_STATS.SIZE_HIGH
  1092.                JB      CLOSE_READ                 ;If negative, not enough room.
  1093.  
  1094. CREATE:        MOV     DX,OFFSET TARGET_FILE   ;Create and truncate target file
  1095.                XOR     CX,CX                   ; to zero.
  1096.                MOV     AH,3CH
  1097.                INT     21H
  1098.                JC      CLOSE_READ
  1099.                MOV     SI,AX                   ;Save handle.
  1100.                MOV     DS,BUFFER_SEG           ;Read/write buffer.
  1101.                XOR     DX,DX                   ;Offset zero.
  1102.  
  1103. COPY_READ:     MOV     BX,DI                   ;Retrieve read handle.
  1104.                MOV     CX,CS:BUFFER_SIZE       ;Buffer size.
  1105.                MOV     AH,3FH
  1106.                INT     21H                     ;Read source file.
  1107.                JC      COPY_DONE               ;If carry, failed; exit.
  1108.                OR      AX,AX                   ;If zero bytes read, done.
  1109.                JZ      CHANGE_DATE             ;Change target date to source.
  1110.  
  1111.                MOV     CX,AX                   ;Else, bytes read into counter.
  1112.                MOV     BX,SI                   ;Retrieve write handle.
  1113.                MOV     AH,40H
  1114.                INT     21H                     ;Write the buffer to disk.
  1115.                JC      COPY_DONE               ;If failed, exit.
  1116.                CMP     CX,AX                   ;Write same number as read?
  1117.                STC                             ;Assume no.
  1118.                JNZ     COPY_DONE               ;If no, failed; exit.
  1119.                CMP     CX,CS:BUFFER_SIZE       ;Was it a full read?
  1120.                JZ      COPY_READ               ;If yes, there must be more.
  1121.  
  1122. CHANGE_DATE:   MOV     BX,SI                         ;Write handle.
  1123.                MOV     CX,CS:SOURCE_STATS.FILE_TIME  ;Else, make time/date same
  1124.                MOV     DX,CS:SOURCE_STATS.FILE_DATE  ; as source.
  1125.                MOV     AX,5701H
  1126.                INT     21H
  1127.                MOV     DS,CS:SOURCE_SEG        ;Mark success with asterisk.
  1128.                MOV     DS:MARK[BP],"*"
  1129.  
  1130. COPY_DONE:     PUSH    CS                      ;Restore data segment.
  1131.                POP     DS
  1132.  
  1133. CLOSE_WRITE:   PUSHF                           ;Save error if any.
  1134.                MOV     BX,SI                   ;Close write file.
  1135.                MOV     AH,3EH
  1136.                INT     21H
  1137.                POP     AX                      ;Retrieve flags.
  1138.                JC      CLOSE_READ              ;Close successful?
  1139.                XCHG    AH,AL                   ;If no, exit with error, else
  1140.                SAHF                            ; retrieve write state.
  1141.  
  1142. CLOSE_READ:    PUSHF                           ;Save flags.
  1143.                MOV     BX,DI                   ;Close read file.
  1144.                MOV     AH,3EH
  1145.                INT     21H
  1146.                POPF                            ;Write file status.
  1147.  
  1148. COPY_END:      PUSHF                           ;Save status.
  1149.                JNC     CK_DELETE               ;If no carry, successful.
  1150.                CALL    HIDE_CURSOR
  1151.                CALL    MENU_OFFSET             ;Else, calculate menu offset.
  1152.                ADD     DI,80 * 2               ;Place error message on second
  1153.                MOV     BH,MENU_ATTR            ; menu line with menu attribute.
  1154.                MOV     SI,RESPONSE
  1155.                CALL    WRITE_STRING            ;Write the message.
  1156.                MOV     SI,OFFSET PRESS_MSG
  1157.                CALL    WRITE_STRING
  1158.                CALL    BEEP                    ;Draw attention with beep.
  1159.                CALL    GET_KEY                 ;Pause for keystroke.
  1160.                JMP     SHORT COPY_RETURN
  1161.  
  1162. CK_DELETE:     CMP     RESPONSE,OFFSET MOVE_MSG  ;Move request?
  1163.                JNZ     COPY_RETURN               ;If no, done here.
  1164.                POPF
  1165.                MOV     DX,OFFSET SOURCE_FILE     ;Else, delete the source file.
  1166.                MOV     AH,41H
  1167.                INT     21H
  1168.                PUSHF
  1169.  
  1170. COPY_RETURN:   POPF                            ;Retrieve status.
  1171.                RET
  1172.  
  1173. ;----------------------------------------------;
  1174. ; INPUT: SI -> Filename;  DI -> End of path.   ;
  1175. ;----------------------------------------------;
  1176. ADD_NAME:      MOV     AL,"\"                  ;Backslash delimiter.
  1177.                CMP     [DI - 1],AL             ;Is there a delimiter?
  1178.                JZ      ADD_IT                  ;If yes, continue.
  1179.                STOSB                           ;Else, add delimiter.
  1180. ADD_IT:        LODSB                           ;Add the filename.
  1181.                CMP     AL,"a"
  1182.                JB      GOT_NAME
  1183.                CMP     AL,"z"
  1184.                JA      GOT_NAME
  1185.                AND     AL,5FH                  ;Capitalize.
  1186. GOT_NAME:      STOSB
  1187.                OR      AL,AL                   ;ASCIIZ.
  1188.                JNZ     ADD_IT
  1189.                RET
  1190.  
  1191. ;----------------------------------------------;
  1192. F6:            PUSH    DS                      ;Preserve segment registers.
  1193.                PUSH    ES                      ;Place cursor back on screen at
  1194.                MOV     DX,300H                 ; third row in case there is
  1195.                CALL    SET_CURSOR              ; a DOS print error message.
  1196.                MOV     BX,SOURCE_SEG           ;BX -> source segment.
  1197.                XOR     SI,SI                   ;Start of source.
  1198.                XOR     DI,DI                   ;Start of target.
  1199.                XOR     BP,BP                   ;Start of order.
  1200.                JMP     SHORT PRINT_HEADER      ;Print directory header on page.
  1201.  
  1202. NEXT_PRINT:    MOV     DS,BX                   ;Source on left side of page.
  1203.                CMP     LIST_NAME[SI],-1        ;End of listing?
  1204.                JNZ     PRINT1                  ;If no, continue.
  1205.                MOV     DS,CS:TARGET_SEG        ;Target listing segment
  1206.                CMP     LIST_NAME[DI],-1        ;End of Target listing also?
  1207.                JZ      F6_END                  ;If yes, done.
  1208.  
  1209. PRINT1:        MOV     DS,BX                   ;Source segment.
  1210.                MOV     CX,40                   ;40 characters per half line.
  1211.                CALL    DO_LINE                 ;Print a spec.
  1212.                XCHG    SI,DI                   ;Target pointer.
  1213.                MOV     DS,CS:TARGET_SEG        ;Target segment.
  1214.                MOV     CX,40
  1215.                CALL    DO_LINE                 ;Print left half of line.
  1216.                XCHG    SI,DI                   ;Restore pointers.
  1217.                CALL    NEW_LINE                ;CR LF to new line.
  1218.                INC     BP                      ;Increment order counter.
  1219.                MOV     AX,BP
  1220.                XOR     DX,DX
  1221.                MOV     CX,54
  1222.                DIV     CX
  1223.                OR      DX,DX                   ;If MOD 54 = 0 then formfeed.
  1224.                JNZ     NEXT_PRINT
  1225.                CALL    FORMFEED
  1226. PRINT_HEADER:  PUSH    CS                      ;Back to code segment.
  1227.                POP     DS
  1228.                PUSH    SI                      ;Save some pointers.
  1229.                PUSH    BP
  1230.                MOV     BP,OFFSET PRINT_CHAR    ;Print directory heading at
  1231.                CALL    WRITE_PATH              ; top of each page.
  1232.                POP     BP                      ;Restore the pointers.
  1233.                POP     SI
  1234.                CALL    NEW_LINE                ;Double space before filenames.
  1235.                CALL    NEW_LINE
  1236.                JMP     NEXT_PRINT              ;Next line.
  1237.  
  1238. F6_END:        CALL    FORMFEED                ;Spit out the last printed page.
  1239.                CALL    HIDE_CURSOR
  1240.                POP     ES                      ;Restore segments.
  1241.                POP     DS
  1242.                RET
  1243.  
  1244. ;----------------------------------------------------;
  1245. ; INPUT: DS:SI -> filename.  Entry point at DO_LINE  ;
  1246. ;----------------------------------------------------;
  1247. NEXT_REC2:     ADD     SI,SIZE FILE_RECORD     ;Next filename.
  1248. DO_LINE:       CMP     LIST_NAME[SI],-1        ;Last record?
  1249.                JZ      BLANK_LINE              ;If yes, blank line.
  1250.                MOV     DX,DISP_ORDER[SI]       ;Retrieve display order.
  1251.                CMP     DX,-1                   ;Is it displayed?
  1252.                JZ      NEXT_REC2               ;If no, next record.
  1253.                MOV     AX,OFFSET NOT_RECENT    ;Assume not a recent file.
  1254.                TEST    DX,8000H                ;Is it highlighted?
  1255.                JZ      COMPARE_PRINT           ;If no, see if current order.
  1256.                MOV     AX,OFFSET RECENT        ;Else, use recent codes.
  1257.                AND     DX,NOT 8000H            ;Strip highlight bit.
  1258. COMPARE_PRINT: CMP     DX,BP                   ;Entry less than order?
  1259.                JB      NEXT_REC2               ;If yes, next record.
  1260.                JA      BLANK_LINE              ;If above, blank line.
  1261.                PUSH    BX
  1262.                PUSH    CX
  1263.                MOV     BX,AX                   ;Get offset.
  1264.                MOV     AL,CS:[BX]              ;Get char or code count.
  1265.                CMP     AL,6                    ;Is it above 6?
  1266.                JA      PRINT_MARK              ;If yes, assumed right.
  1267.                MOV     CL,AL                   ;Else, it's a printer code count.
  1268.                XOR     CH,CH                   ;Zero in high half.
  1269. NEXT_CODE:     INC     BX                      ;Point to a code.
  1270.                MOV     AL,CS:[BX]              ;Retrieve it.
  1271.                CALL    PRINT_CHAR              ;Print it.
  1272.                LOOP    NEXT_CODE
  1273.                MOV     AL,SPACE                ;Indent with a space.
  1274. PRINT_MARK:    CALL    PRINT_CHAR
  1275.                POP     CX
  1276.                POP     BX
  1277.                DEC     CX
  1278. PRINT_LINE:    LODSB                           ;Else, print the line.
  1279.                CALL    PRINT_CHAR
  1280.                LOOP    PRINT_LINE
  1281.                ADD     SI,7                    ;Pointer date/time/order fields.
  1282.                JMP     SHORT DO_LINE_END
  1283. BLANK_LINE:    MOV     AL,SPACE                ;Blank line with spaces.
  1284.                CALL    PRINT_CHAR
  1285.                LOOP    BLANK_LINE
  1286. DO_LINE_END:   RET
  1287.  
  1288. ;----------------------------------------------;
  1289. NEW_LINE:      MOV     AL,CR                   ;Carriage return linefeed.
  1290.                CALL    PRINT_CHAR
  1291.                MOV     AL,LF
  1292.                CALL    PRINT_CHAR
  1293.                RET
  1294.  
  1295. FORMFEED:      MOV     AL,FF                   ;Formfeed.
  1296.  
  1297. PRINT_CHAR:    MOV     DL,AL                   ;Print via DOS.
  1298.                MOV     AH,5
  1299.                INT     21H
  1300.                RET
  1301.  
  1302. ;-----------------------------------------------------------------------;
  1303. ; OUTPUT: DS:SI -> Highlighted bar record; CY = 1 if bar on blank line. ;
  1304. ;-----------------------------------------------------------------------;
  1305. FIND_BAR:      MOV     DI,BAR_LINE             ;Retrieve bar line.
  1306.                XOR     SI,SI                   ;DS:SI -> source records.
  1307.                MOV     DS,SOURCE_SEG
  1308.                JMP     SHORT GET_BAR
  1309. NEXT_BAR:      ADD     SI,SIZE FILE_RECORD     ;Next record.
  1310. GET_BAR:       CMP     LIST_NAME[SI],-1        ;End of listing?
  1311.                JZ      NO_NAME                 ;If yes, no name.
  1312.                MOV     BX,DISP_ORDER[SI]       ;Retrieve display order.
  1313.                CMP     BX,-1                   ;Is it displayed?
  1314.                JZ      NEXT_BAR                ;If no, next record.
  1315.                AND     BX,NOT 8000H            ;Else, strip highlight bit.
  1316.                CMP     BX,DI                   ;Is display order same as bar?
  1317.                JB      NEXT_BAR                ;If > then next record.
  1318.                JA      NO_NAME                 ;If above, then no name.
  1319.                CLC                             ;If same, then valid name.
  1320.                RET
  1321.  
  1322. NO_NAME:       STC
  1323.                RET
  1324.  
  1325. ;-----------------------------------------------------------------;
  1326. ; INPUT: CX = binary count; OUTPUT: SOURCE_NAME = ASCII of count. ;
  1327. ;-----------------------------------------------------------------;
  1328. GET_COUNT:     PUSH    BX
  1329.                PUSH    DI
  1330.                MOV     AX,CX                   ;Retrieve number.
  1331.                MOV     BX,10                   ;Divisor of ten.
  1332.                XOR     CX,CX                   ;Zero in counter.
  1333. NEXT_DIV:      XOR     DX,DX                   ;Zero in high half.
  1334.                DIV     BX                      ;Divide by ten.
  1335.                ADD     DL,"0"                  ;Convert to ASCII.
  1336.                PUSH    DX                      ;Save results.
  1337.                INC     CX                      ;Also increment count.
  1338.                OR      AX,AX                   ;Are we done?
  1339.                JNZ     NEXT_DIV                ;Continue until zero.
  1340.  
  1341.                MOV     DI,OFFSET SOURCE_NAME
  1342. NEXT_NUMBER:   POP     AX                      ;Retrieve numbers.
  1343.                STOSB                           ;And store.
  1344.                LOOP    NEXT_NUMBER
  1345.                XOR     AL,AL                   ;ASCIIZ string.
  1346.                STOSB
  1347.                POP     DI
  1348.                POP     BX
  1349.                RET
  1350.  
  1351. ;--------------------------------------------------------------;
  1352. ; INPUT: BP -> Source filename; OUTPUT: SOURCE_NAME = filename ;
  1353. ;--------------------------------------------------------------;
  1354. GET_SOURCE:    PUSH    DS
  1355.                MOV     DS,SOURCE_SEG           ;DS:SI -> Source name.
  1356.                MOV     SI,BP
  1357.                MOV     DI,OFFSET SOURCE_NAME   ;Name storage.
  1358.                MOV     CX,8                    ;8 characters of name.
  1359. NEXT_NAME:     LODSB
  1360.                CMP     AL,SPACE                ;End of name?
  1361.                JZ      EXTENSION               ;If yes, do extension.
  1362.                STOSB
  1363.                LOOP    NEXT_NAME
  1364. EXTENSION:     MOV     SI,BP                   ;Retrieve name start.
  1365.                ADD     SI,9                    ;Move to extension field.
  1366.                CMP     BYTE PTR [SI],SPACE     ;Is there any extension?
  1367.                JZ      NAME_DONE               ;If no, done.
  1368.                MOV     AL,"."                  ;Else, add delimiting dot.
  1369.                STOSB
  1370.                MOV     CX,3                    ;3 characters for extension.
  1371. NEXT_EXT:      LODSB
  1372.                CMP     AL,SPACE
  1373.                JZ      NAME_DONE
  1374.                STOSB
  1375.                LOOP    NEXT_EXT
  1376. NAME_DONE:     XOR     AL,AL                   ;ASCIIZ.
  1377.                STOSB
  1378.                POP     DS
  1379.                RET
  1380.  
  1381. ;-----------------------------------------------------------------------------;
  1382. ; INPUT: BX -> MARKED_MSG if marked; OUTPUT: ZF=1 if cancel; ZF=0 if confirm. ;
  1383. ;-----------------------------------------------------------------------------;
  1384. GET_RESPONSE:  PUSH    BX                      ;Save message pointer.
  1385.                CALL    MENU_OFFSET             ;Calculate menu screen offset.
  1386.                MOV     BH,MENU_ATTR            ;Menu attribute.
  1387.                MOV     CX,80 * 2               ;Blank out the two lines of menu.
  1388. NEXT_MENU:     MOV     AL,SPACE
  1389.                CALL    WRITE_SCREEN
  1390.                LOOP    NEXT_MENU
  1391.                MOV     DH,ROWS                 ;Retrieve the rows.
  1392.                DEC     DH                      ;Next to last line.
  1393.                XOR     DL,DL
  1394.                CALL    SET_CURSOR              ;Set the cursor.
  1395.                MOV     SI,RESPONSE             ;Write TTY, copy or move message.
  1396.                CALL    TTY_STRING
  1397.                MOV     SI,OFFSET SOURCE_NAME   ;Write filename or mark count.
  1398.                CALL    TTY_STRING
  1399.                POP     BX                      ;Retrieve message pointer.
  1400.                CMP     BX,OFFSET MARKED_MSG    ;Is it "marked files" message?
  1401.                JNZ     DO_TO                   ;If no, skip.
  1402.                MOV     SI,BX                   ;Else, display it.
  1403.                CALL    TTY_STRING
  1404. DO_TO:         MOV     SI,OFFSET TO_MSG        ;Display rest of
  1405.                CALL    TTY_STRING              ; "to Target Directory?  Y/N"
  1406.                MOV     SI,OFFSET DIRECTORY_MSG ; message.
  1407.                CALL    TTY_STRING
  1408.                MOV     SI,OFFSET QUERY_MSG
  1409.                CALL    TTY_STRING
  1410. NEXT_RESPONSE: CALL    GET_KEY                 ;Get a key.
  1411.                CMP     AL,ESC_SCAN             ;If ESC, abort.
  1412.                JZ      RESPONSE_END
  1413.                CMP     AL,N_SCAN               ;If "N", abort.
  1414.                JZ      RESPONSE_END
  1415.                CMP     AL,Y_SCAN               ;If not "Y", ignore.
  1416.                JNZ     NEXT_RESPONSE           ;Else, cursor to
  1417.                MOV     DX,300H                 ; third row in case there is
  1418.                CALL    SET_CURSOR              ; a DOS critical error message.
  1419.                OR      AL,1                    ;Return ZF = 0 to confirm.
  1420. RESPONSE_END:  RET
  1421.   
  1422. ;----------------------------------------------;
  1423. VIDEO_SETUP:   MOV     AX,500H                 ;Make sure active page is zero.
  1424.                INT     10H
  1425.                MOV     AX,40H                  ;Point to the ROM BIOS data area
  1426.                MOV     ES,AX
  1427.  
  1428.                MOV     AL,ES:CRT_MODE          ;Retrieve current video mode.
  1429.                CMP     AL,7                    ;Is it mono mode?
  1430.                JZ      GET_ROWS                ;If yes, continue.
  1431.                ADD     STATUS_REG,20H          ;Else, adjust status register
  1432.                ADD     VIDEO_SEG,800H          ; and video segment.
  1433.                CMP     AL,2                    ;Is it BW80?
  1434.                JZ      GET_ROWS                ;If yes, continue.
  1435.                MOV     HEADING_ATTR,INVERSE_BLUE
  1436.                MOV     ACTIVE_ATTR,INTENSE
  1437.                MOV     BODY_ATTR,BLUE          ;Else, use color attributes.
  1438.                MOV     HIGHLIGHT_ATTR,INTENSE_BLUE
  1439.                MOV     MENU_ATTR,INVERSE_BLUE
  1440.                MOV     BAR_ATTR,CYAN
  1441.                CMP     AL,3                    ;Is it mode CO80?
  1442.                JZ      GET_ROWS                ;If yes, continue.
  1443.                MOV     AX,300H                 ;Else, change video mode to CO80.
  1444.                INT     10H
  1445.  
  1446. GET_ROWS:      XOR     BH,BH
  1447.                MOV     DL,24
  1448.                MOV     AX,1130H
  1449.                INT     10H
  1450.                MOV     ROWS,DL                 ;Store rows.
  1451.                XOR     DH,DH
  1452.                SUB     DX,4
  1453.                MOV     PAGE_LENGTH,DX          ;Page length = display rows - 4.
  1454.  
  1455. ;----------------------------------------------;
  1456. DISPLAY_SETUP: PUSH    CS
  1457.                POP     ES
  1458.                CALL    CLS                     ;Clear screen.
  1459.                CALL    HIDE_CURSOR             ;Hide the cursor off screen.
  1460.  
  1461.                MOV     BL,MENU_ATTR            ;Turn on border.
  1462.                MOV     CL,4
  1463.                SHR     BL,CL
  1464.                MOV     AH,0BH
  1465.                INT     10H
  1466.  
  1467.                MOV     SI,OFFSET COPYRIGHT     ;Point to copyright message.
  1468.                XOR     DI,DI                   ;Point to top left of display.
  1469.                MOV     BH,HEADING_ATTR         ;Use header attribute.
  1470.                CALL    WRITE_STRING            ;And display it.
  1471.                MOV     AL,BOX
  1472.                CALL    WRITE_SCREEN
  1473.                MOV     AL,SPACE
  1474.                CALL    WRITE_SCREEN
  1475.                INC     SI                      ;Bump pointer past LF
  1476.                CALL    WRITE_STRING            ; and display rest of header.
  1477.                CALL    DISPLAY_DIRS            ;Display directory heading.
  1478.  
  1479.                MOV     BP,OFFSET WRITE_SCREEN  ;Display directories.
  1480.                CALL    WRITE_PATH
  1481.  
  1482.                MOV     BH,BODY_ATTR            ;Body attribute.
  1483.                MOV     CX,PAGE_LENGTH          ;Page length.
  1484.                MOV     DI,(3 * 160) + (2 * 40) ;Middle of third row.
  1485. NEXT_LINE:     MOV     AL,VERT_LINE            ;Display delimiting
  1486.                CALL    WRITE_SCREEN            ; vertical lines.
  1487.                ADD     DI,(2 * 79)
  1488.                LOOP    NEXT_LINE
  1489.  
  1490. ;----------------------------------------------;
  1491. DISPLAY_MENU:  MOV     SI,OFFSET MENU          ;Display menu on bottom two lines
  1492.                CALL    MENU_OFFSET
  1493.                MOV     CL,MENU_ATTR            ;Menu attribute.
  1494.                MOV     CH,ACTIVE_ATTR          ;Active mode attribute.
  1495.  
  1496.                MOV     BH,CL
  1497.                CALL    WRITE_STRING            ;"F1"
  1498.  
  1499.                CMP     FILES_MODE,ALL
  1500.                JNZ     DISPLAY3
  1501.                MOV     BH,CH
  1502. DISPLAY3:      CALL    WRITE_STRING            ;"All files"
  1503.  
  1504.                MOV     BH,CL
  1505.                CMP     FILES_MODE,UNIQUE
  1506.                JNZ     DISPLAY4
  1507.                MOV     BH,CH
  1508. DISPLAY4:      CALL    WRITE_STRING            ;"Different files"
  1509.  
  1510.                MOV     BH,CL
  1511.                CMP     FILES_MODE,ALIKE
  1512.                JNZ     DISPLAY5
  1513.                MOV     BH,CH
  1514. DISPLAY5:      CALL    WRITE_STRING            ;"Alike files"
  1515.  
  1516.                MOV     BH,CL
  1517.                CALL    WRITE_STRING            ;Print rest of menu
  1518.                RET
  1519.  
  1520. ;----------------------------------------------;
  1521. DISPLAY_DIRS:  MOV     BH,ACTIVE_ATTR          ;Directory attribute.
  1522.                MOV     DI,80 * 2
  1523.                MOV     SI,OFFSET SOURCE_MSG    ;Display "Source Directory"
  1524.                CALL    WRITE_STRING
  1525.                CALL    WRITE_STRING
  1526.                MOV     CX,SOURCE_COUNT
  1527.                CALL    WRITE_COUNT             ;Write the source file count.
  1528.                MOV     SI,OFFSET TARGET_MSG    ;Display "Target Directory".
  1529.                CALL    WRITE_STRING
  1530.                MOV     SI,OFFSET DIRECTORY_MSG
  1531.                CALL    WRITE_STRING
  1532.                MOV     CX,TARGET_COUNT         ;And finally target files count.
  1533.  
  1534. WRITE_COUNT:   CALL    GET_COUNT
  1535.                MOV     CX,GAP
  1536. NEXT_GAP:      MOV     AL,SPACE                ;Space over some.
  1537.                CALL    WRITE_SCREEN
  1538.                LOOP    NEXT_GAP
  1539.                MOV     SI,OFFSET SOURCE_NAME   ;Storage for count in ASCIIZ.
  1540.                MOV     CX,40 - DIRECTORY_LEN
  1541. NEXT_NUM:      LODSB                           ;Get a number.
  1542.                OR      AL,AL                   ;End of string?
  1543.                JZ      WRITE_FILES             ;If yes, add "files" message.
  1544.                CALL    WRITE_SCREEN
  1545.                LOOP    NEXT_NUM
  1546. WRITE_FILES:   MOV     SI,OFFSET FILES_MSG
  1547.                CALL    WRITE_STRING
  1548. NEXT_SPACE:    MOV     AL,SPACE                ;Pad balance with spaces.
  1549.                CALL    WRITE_SCREEN
  1550.                LOOP    NEXT_SPACE
  1551.                RET
  1552.  
  1553. ;----------------------------------------;
  1554. ; OUTPUT: DI -> Screen offset for menu.  ;
  1555. ;----------------------------------------;
  1556. MENU_OFFSET:   MOV     AL,2 * 80               ;(Rows * chars) - chars
  1557.                MUL     ROWS                    ; = menu offset.
  1558.                SUB     AX,2 * 80
  1559.                MOV     DI,AX
  1560.                RET
  1561.  
  1562. ;------------------------------------------------------------------------------;
  1563. ; INPUT: SI-> Filespec; DI-> Video buffer; BP=OFFSET WRITE_SCREEN OR PRINT_CHAR;
  1564. ;------------------------------------------------------------------------------;
  1565. WRITE_PATH:    MOV     SI,OFFSET SOURCE_SPEC   ;Write first string.
  1566.                CALL    DISP_FILESPEC
  1567.                MOV     SI,OFFSET TARGET_SPEC   ;Write second string.
  1568.  
  1569. DISP_FILESPEC: MOV     AL,SPACE                ;Indent one space.
  1570.                CALL    BP
  1571.                MOV     CX,39
  1572. NEXT_FILESPEC: LODSB
  1573.                OR      AL,AL                   ;Null terminates string.
  1574.                JZ      PAD_SPACES              ;Pad balance with spaces.
  1575.                CALL    BP
  1576.                LOOP    NEXT_FILESPEC
  1577.                JMP     SHORT FILESPEC_END
  1578. PAD_SPACES:    MOV     AL,SPACE
  1579.                CALL    BP
  1580.                LOOP    PAD_SPACES
  1581. FILESPEC_END:  RET
  1582.  
  1583. ;----------------------------------------------------;
  1584. ; INPUT:  AL = character to write;  BH = attribute.  ;
  1585. ;----------------------------------------------------;
  1586. WRITE_SCREEN:  PUSH    ES
  1587.                MOV     ES,CS:VIDEO_SEG         ;Point to screen segment.
  1588.                MOV     DX,CS:STATUS_REG        ;Retrieve status register.
  1589.                MOV     BL,AL                   ;Store character in BL.
  1590.  
  1591. HORZ_RET:      IN      AL,DX                   ;Get status.
  1592.                RCR     AL,1                    ;Is it low?
  1593.                JC      HORZ_RET                ;If not, wait until it is.
  1594.                CLI                             ;No more interrupts.
  1595.  
  1596. HWAIT:         IN      AL,DX                   ;Get status.
  1597.                RCR     AL,1                    ;Is it high?
  1598.                JNC     HWAIT                   ;If no, wait until it is.
  1599.  
  1600.                MOV     AX,BX                   ;Retrieve character; now it's OK
  1601.                STOSW                           ; to write to screen buffer.
  1602.                STI                             ;Interrupts back on.
  1603.                POP     ES
  1604.                RET                             ;Return
  1605.  
  1606. ;------------------------------------------------------------------;
  1607. ; INPUT:  SI -> to string to display;  DI -> where to display it.  ;
  1608. ;   Entry point is WRITE_STRING.                                   ;
  1609. ;------------------------------------------------------------------;
  1610. WRITE_IT:      CALL    WRITE_SCREEN            ;Write a character.
  1611. WRITE_STRING:  LODSB                           ;Retrieve a character.
  1612.                CMP     AL,CR                   ;Keep writing until a carriage
  1613.                JA      WRITE_IT                ; return or zero encountered.
  1614.                RET
  1615.  
  1616. ;----------------------------------------------;
  1617. STORE_NAME:    MOV     SI,OFFSET DTA.FILE_NAME ;Point to filename.
  1618.                PUSH    DI
  1619.                MOV     AX,SPACE SHL 8 + SPACE  ;Initiate storage with spaces.
  1620.                MOV     CX,(SIZE FILE_RECORD - 6) / 2   ;Fill out with spaces.
  1621.                REP     STOSW
  1622.                POP     DI                      ;Point to start of storage again.
  1623.                MOV     CX,SIZE LIST_NAME       ;Store 12 bytes of filename.
  1624. NEXT_STORE:    LODSB                           ;Get a byte.
  1625.                OR      AL,AL                   ;End of filename?
  1626.                JZ      END_STORE               ;If yes, finish with blanks.
  1627.                CMP     AL,"."                  ;Is it the period?
  1628.                JNZ     STORE_BYTE              ;If no, store.
  1629.                SUB     CX,3                    ;Else, store 3 spaces.
  1630.                MOV     AL,SPACE
  1631.                REP     STOSB
  1632.                ADD     CX,3
  1633.                JMP     SHORT NEXT_STORE        ;Get next byte.
  1634.  
  1635. STORE_BYTE:    STOSB                           ;Store byte.
  1636.                LOOP    NEXT_STORE              ;Get next byte.
  1637. END_STORE:     MOV     AL,SPACE                ;Pad balance with spaces.
  1638.                REP     STOSB
  1639.  
  1640.                PUSH    DI                      ;Save pointer.
  1641.                ADD     DI,8                    ;Move to end of bytes field.
  1642.                MOV     DX,DTA.SIZE_LOW         ;Retrieve high and low words
  1643.                MOV     AX,DTA.SIZE_HIGH        ; of size in bytes.
  1644.                MOV     BX,10                   ;Convert to decimal.
  1645.                STD                             ;Reverse direction.
  1646.  
  1647. NEXT_SIZE:     MOV     CX,DX                   ;Low word in CX.
  1648.                XOR     DX,DX                   ;Zero in high half.
  1649.                DIV     BX                      ;Convert to decimal.
  1650.                XCHG    AX,CX                   ;Retrieve low word.
  1651.                DIV     BX
  1652.                XCHG    AX,DX                   ;Retrieve remainder.
  1653.                ADD     AL,"0"                  ;Convert to ASCII.
  1654.                STOSB                           ;Store it.
  1655.                MOV     AX,CX                   ;Are we done?
  1656.                OR      CX,DX
  1657.                JNZ     NEXT_SIZE               ;If no, divide again.
  1658.  
  1659.                CLD                             ;Back to forward direction.
  1660.                POP     DI                      ;Retrieve pointer.
  1661.                ADD     DI,11                   ;Move to date field.
  1662. DATE:          MOV     DX,DTA.FILE_DATE        ;Retrieve date.
  1663.                MOV     AX,DX
  1664.                MOV     CL,5                    ;Shift to lowest bits.
  1665.                SHR     AX,CL
  1666.                AND     AX,1111B                ;Mask off all but month.
  1667.                MOV     CL,0FFH                 ;Flag as no leading zeros.
  1668.                MOV     CH,"-"                  ;Delimiting character.
  1669.                CALL    STORE_WORD              ;Store it.
  1670.  
  1671.                MOV     AX,DX                   ;Retrieve date.
  1672.                AND     AX,11111B               ;Mask off all but day.
  1673.                XOR     CL,CL                   ;Flag include leading zeros.
  1674.                MOV     CH,"-"
  1675.                CALL    STORE_WORD              ;Store it.
  1676.  
  1677.                MOV     AX,DX                   ;Retrieve date for last time.
  1678.                MOV     CL,9
  1679.                SHR     AX,CL                   ;Mask off all but year.
  1680.                ADD     AX,80                   ;Adjust to ASCII.
  1681.                CMP     AX,100                  ;Past year 2000?
  1682.                JB      DISPLAY_DATE            ;If no, display. Else, adjust for
  1683.                SUB     AX,100                  ; next century. (Planning ahead!)
  1684. DISPLAY_DATE:  XOR     CL,CL                   ;Display leading zeros.
  1685.                MOV     CH,SPACE
  1686.                CALL    STORE_WORD              ;Store it.
  1687.  
  1688. TIME:          INC     DI                      ;Move to time field.
  1689.                MOV     DX,DTA.FILE_TIME        ;Retrieve time.
  1690.                MOV     AX,DX
  1691.                MOV     CL,11                   ;Shift to hours bits.
  1692.                SHR     AX,CL
  1693.                PUSH    AX
  1694.                CMP     AX,12                   ;Past noon?
  1695.                JBE     MERIDIAN
  1696.                SUB     AX,12                   ;If yes, adjust.
  1697. MERIDIAN:      CMP     AX,0                    ;Midnight?
  1698.                JNZ     NOT_MIDNIGHT
  1699.                MOV     AX,12                   ;If yes, adjust.
  1700. NOT_MIDNIGHT:  MOV     CL,0FFH                 ;Suppress leading zeros.
  1701.                MOV     CH,":"
  1702.                CALL    STORE_WORD              ;Store it.
  1703.  
  1704.                MOV     AX,DX                   ;Retrieve time.
  1705.                MOV     CL,5                    ;Shift to minutes bits.
  1706.                SHR     AX,CL
  1707.                AND     AX,111111B              ;Mask off all but minutes.
  1708.                XOR     CL,CL
  1709.                POP     DX                      ;Retrieve hours.
  1710.                MOV     CH,"p"                  ;Assume PM.
  1711.                CMP     DX,12                   ;Is it PM?
  1712.                JAE     PM
  1713.                MOV     CH,"a"                  ;If no, AM.
  1714.  
  1715. PM:            CALL    STORE_WORD              ;Store it.
  1716.                INC     DI                      ;Pointer past mark.
  1717.                MOV     AX,DTA.FILE_DATE
  1718.                STOSW                           ;Store date in DOS format.
  1719.                MOV     AX,DTA.FILE_TIME
  1720.                STOSW                           ;Store time in DOS format.
  1721.                INC     DI                      ;Bump pointer past DISP_ORDER.
  1722.                INC     DI
  1723.                RET                             ;Done here.
  1724.  
  1725. ;-----------------------------------------------------------------------;
  1726. ; Converts a two byte hex number to decimal followed by delimiter.      ;
  1727. ; INPUT: AX = hex number; BL = 10; CH = delimiter character to store.   ;
  1728. ;   CL = 0 if zeros are to be stored; CL = -1 if leading zeros ignored. ;
  1729. ;   ES:DI points to storage.                                            ;
  1730. ;-----------------------------------------------------------------------;
  1731. STORE_WORD:    DIV     BL                      ;Divide by ten.
  1732.                ADD     AX,"00"                 ;Convert to ASCII.
  1733.                CMP     CL,0                    ;Are we to display leading zero?
  1734.                JZ      STORE_IT                ;If yes, store as is.
  1735.                CMP     AL,"0"                  ;Is it a leading zero?
  1736.                JNZ     STORE_IT                ;If no, store it.
  1737.                MOV     AL,SPACE                ;Else, store a space.
  1738. STORE_IT:      STOSW
  1739.                MOV     AL,CH                   ;Store delimiter character also.
  1740.                STOSB
  1741.                RET
  1742.  
  1743. ;----------------------------------------------;
  1744. CLS:           XOR     CX,CX                   ;Top left corner.
  1745.                MOV     DH,ROWS
  1746.                MOV     DL,80 - 1
  1747.                MOV     BH,BODY_ATTR            ;Normal attribute.
  1748.                MOV     AX,600H                 ;Scroll active page.
  1749.                INT     10H
  1750.                RET
  1751.  
  1752. ;----------------------------------------------;
  1753. GET_DIR:       MOV     BYTE PTR [SI],"\"       ;DOS doesn't preface directory
  1754.                INC     SI                      ; with slash so we must.
  1755.                XOR     DL,DL
  1756.                MOV     AH,47H                  ;Get current directory.
  1757.                INT     21H
  1758.                RET
  1759.  
  1760. CHANGE_DIR:    MOV     AH,3BH                  ;Change current directory.
  1761.                INT     21H
  1762.                RET
  1763.  
  1764. ;----------------------------------------------;
  1765. FIND_FIRST:    XOR     CX,CX                   ;Normal files.
  1766.                MOV     AH,4EH                  ;Find first.
  1767.                INT     21H
  1768.                RET
  1769.  
  1770. ;----------------------------------------------;
  1771. PRINT_STRING:  MOV     AH,9                    ;Print string via DOS.
  1772.                INT     21H
  1773.                RET
  1774.  
  1775. ;----------------------------------------------;
  1776. DISK_FREE:     MOV     DL,BYTE PTR TARGET_SPEC ;Target drive.
  1777.                SUB     DL,"A" - 1
  1778.                MOV     AH,36H                  ;Disk free space.
  1779.                INT     21H
  1780.                XOR     DX,DX
  1781.                MUL     BX                      ;Sectors per cluster * clusters
  1782.                MUL     CX                      ;Result times bytes per cluster
  1783.                RET                             ; = available bytes.
  1784.  
  1785. ;----------------------------------------------;
  1786. BEEP:          MOV     BX,NOTE                 ;Tone frequency divisor.
  1787.                MOV     DX,12H
  1788.                XOR     AX,AX
  1789.                DIV     BX
  1790.                MOV     BX,AX                   ;8253 countdown.
  1791.  
  1792.                CALL    DELAY                   ;Wait till clock rolls over.
  1793.  
  1794.                MOV     AL,0B6H                 ;Channel 2 speaker functions.
  1795.                OUT     43H,AL                  ;8253 Mode Control.
  1796.                JMP     $+2                     ;IO delay.
  1797.                MOV     AX,BX                   ;Retrieve countdown.
  1798.                OUT     42H,AL                  ;Channel 2 LSB.
  1799.                JMP     $+2
  1800.                MOV     AL,AH                   ;Channel 2 MSB.
  1801.                OUT     42H,AL
  1802.                IN      AL,61H                  ;Port B.
  1803.                OR      AL,3                    ;Turn on speaker.
  1804.                JMP     $+2
  1805.                OUT     61H,AL
  1806.  
  1807.                CALL    DELAY                   ;Delay one second.
  1808.                IN      AL,61H                  ;Get Port B again.
  1809.                AND     AL,NOT 3                ;Turn speaker off.
  1810.                JMP     $+2
  1811.                OUT     61H,AL
  1812.                RET                             ;Done.
  1813.  
  1814. ;-----------------------------;
  1815. DELAY:         PUSH    DS                      ;Preserve data segment.
  1816.                MOV     AX,40H                  ;Point to BIOS data segment.
  1817.                MOV     DS,AX
  1818.                MOV     AX,DS:[6CH]             ;Retrieve timer low.
  1819. NEXT_BEEP:     MOV     DX,DS:[6CH]             ;Retrieve timer low.
  1820.                CMP     DX,AX                   ;Have we timed out?
  1821.                JZ      NEXT_BEEP               ;If not, wait until second up.
  1822.                POP     DS                      ;Restore data segment.
  1823.                RET
  1824.  
  1825. ;----------------------------------------------;
  1826. HIDE_CURSOR:   MOV     DH,ROWS                 ;Retrieve CRT rows.
  1827.                INC     DH                      ;Move one line below off screen.
  1828.                XOR     DL,DL                   ;Column zero.
  1829.  
  1830. SET_CURSOR:    XOR     BH,BH                   ;Page zero.
  1831.                MOV     AH,2                    ;Set cursor position.
  1832.                INT     10H
  1833.                RET
  1834.  
  1835. ;----------------------------------------------;
  1836. GET_KEY:       MOV     AH,0                    ;Wait for next keyboard input.
  1837.                INT     16H
  1838.                XCHG    AH,AL
  1839.                RET
  1840.  
  1841. CK_KEY:        MOV     AH,1                    ;Is there a keystroke available.
  1842.                INT     16H
  1843.                RET
  1844.  
  1845. CLEAR_IT:      CALL    GET_KEY                 ;Read keystrokes until buffer
  1846. CLEAR_KEY:     CALL    CK_KEY                  ; empty.
  1847.                JNZ     CLEAR_IT
  1848.                RET
  1849.  
  1850. ;----------------------------------------------;
  1851. WRITE_TTY:     MOV     AH,0EH
  1852.                INT     10H
  1853.                RET
  1854.  
  1855. TTY:           CALL    WRITE_TTY
  1856. TTY_STRING:    LODSB                           ;ASCIIZ marks end of string.
  1857.                OR      AL,AL
  1858.                JNZ     TTY
  1859.                RET
  1860.  
  1861. ;----------------------------------------------;
  1862. EVEN
  1863. DTA            =  $
  1864. SOURCE_STATS   =  DTA          + SIZE MATCHING
  1865. CURRENT_DIR    =  SOURCE_STATS + SIZE MATCHING
  1866. SOURCE_SPEC    =  CURRENT_DIR  + SPEC_LENGTH
  1867. SOURCE_FILE    =  SOURCE_SPEC  + SPEC_LENGTH
  1868. TARGET_SPEC    =  SOURCE_FILE  + SPEC_LENGTH
  1869. TARGET_FILE    =  TARGET_SPEC  + SPEC_LENGTH
  1870. USER_INPUT     =  TARGET_FILE  + SPEC_LENGTH
  1871. SOURCE_NAME    =  USER_INPUT   + 14
  1872. STACK_POINTER  =  SOURCE_NAME  + 68 + 256
  1873. SOURCE_OFFSET  =  STACK_POINTER
  1874.  
  1875. _TEXT          ENDS
  1876.                END     START
  1877.