home *** CD-ROM | disk | FTP | other *** search
/ Frostbyte's 1980s DOS Shareware Collection / floppyshareware.zip / floppyshareware / APOG / ASM2.ZIP / DM.ASM < prev    next >
Encoding:
Assembly Source File  |  1989-09-13  |  94.9 KB  |  1,931 lines

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