home *** CD-ROM | disk | FTP | other *** search
/ Share Gallery 1 / share_gal_1.zip / share_gal_1 / UT / UT009.ZIP / SOURCE.ARC / CP.ASM < prev    next >
Assembly Source File  |  1988-07-09  |  38KB  |  922 lines

  1.         TITLE CP - MSDOS FILE COPY UTILITY
  2.         PAGE 55,132
  3. ;***************************************************************************
  4. ;       THIS PROGRAM COPIES ONE OR MORE FILES, OR THE CONTENTS OF A WHOLE
  5. ;       DIRECTORY, TO ANOTHER DISK, FILE OR DIRECTORY.
  6. ;
  7. ;       USAGE (afn = ambiguous file name, ufn = unambiguous file name,
  8. ;              dir = directory):
  9. ;
  10. ;               CP ufn1 ufn2    - copies ufn1 to unf2
  11. ;
  12. ;               CP afn1 afn2 ... dir  - copies one or more files into dir.
  13. ;
  14. ;               CP -R dir1 dir2  - if dir2 doesn't exist, creates it and
  15. ;                                 copies dir1 to dir2.
  16. ;
  17. ;                               - if dir2 exists, creates dir2\dir1 and
  18. ;                                 copies dir1 to it.
  19. ;
  20. ;       SWITCHES (OPTIONAL):
  21. ;
  22. ;        CP -I  prompt before overwriting file
  23. ;
  24. ;        CP -R  allow recursive copying of directories.
  25. ;
  26. ;               CP -V  turns on "verbose" mode (shows name of each file as it
  27. ;                      is copied).
  28. ;***************************************************************************
  29. ;   TO BUILD CP.EXE:
  30. ;    MASM CP,CP,NUL,NUL
  31. ;    LINK CP,CP,NUL,ASM
  32. ;    EXEPACK CP.EXE CP.NEW
  33. ;    DEL CP.EXE
  34. ;    REN CP.NEW=CP.EXE
  35. ;***************************************************************************
  36. ;       BY: JON DART
  37. ;           3012 HAWTHORN ST.,
  38. ;           SAN DIEGO, CA 92104
  39. ;***************************************************************************
  40. ;    Version 1.7, 09-Feb-88 assembles under MASM 5.0
  41. ;    Version 1.6, 28-Nov-86 fixes bug involving relative directory moves
  42. ;                (e.g. mv -r ..\foo .)
  43. ;    Version 1.5, 24-Oct-86 switch parser now accepts -rvi as well as 
  44. ;                   -r -v -i
  45. ;    Version 1.4, 06-Jul-86 changes to memory alloc., allows hyphen for
  46. ;                switches, now assembles under masm 4.0
  47. ;    Version 1.3, 30-Jun-86 minor cleanup, adds i and r switches, removes
  48. ;                c switch
  49. ;       Version 1.2, 26-Apr-86 doesn't exit after user types n to overwrite
  50. ;                    msg
  51. ;       Version 1.1, 31-Mar-86 bug fixes
  52. ;       Version 1.0, 30-Mar-86 modified from MV v. 1.7
  53. ;***************************************************************************
  54.  
  55.     DOSSEG
  56.     .MODEL    SMALL
  57.  
  58. PATHSIZE EQU    65                      ;MAX. SIZE OF DOS PATHNAME, +1
  59. BUFSIZE EQU     32*1024                 ;SIZE OF COPY BUFFER
  60. MAXLEVEL EQU    12                      ;MAX NESTING LEVEL FOR DIRECTORIES
  61. MAXARGS EQU     40                      ;MAXIMUM # OF COMMAND LINE ARGUMENTS
  62. TRUE    EQU     0FFH
  63. FALSE   EQU     0
  64. CONFIRM EQU     FALSE                   ;"CONFIRM BEFORE OVERWRITE" OPTION (DEFAULT VALUE)
  65. RECURSE EQU    FALSE            ;"RECURSIVE" DEFAULT
  66. VERBOSE EQU     FALSE                   ;"VERBOSE" OPTION (DEFAULT VALUE)
  67. M       EQU     BYTE PTR 0[BX]
  68. BIT$DIR EQU     00010000B               ;BIT IN ATTRIBUTE FOR DIRECTORY
  69. BIT$RO  EQU     00000001B               ;BIT IN ATTRIBUTE FOR WRITE-PROTECT
  70.  
  71.         .XLIST
  72.         INCLUDE ASCII.DEF
  73.         INCLUDE MSDOS2.DEF
  74.     INCLUDE MACROS.DEF
  75.  
  76. ADDR    MACRO   REG,OFFST            ;COMPUTE ADDRESS OFFSET FROM BASE REGISTER (BX)
  77.     MOV    REG,BX
  78.     ADD    REG,OFFST
  79.         ENDM
  80.  
  81. ERROR   MACRO   ERRNUM                  ;SHOW ERROR MESSAGE
  82.         MOV     DX,OFFSET DGROUP:MSG&ERRNUM
  83.     CALL    PRTERR
  84.     ENDM
  85.  
  86. COPYPATH MACRO  SOURCE,DEST             ;COPY PATHNAME FROM SOURCE TO DEST
  87.         ADDR    SI,SOURCE
  88.         ADDR    DI,DEST
  89.         MOV     CX,PATHSIZE
  90.         CALL    CPYCNT
  91.         ENDM
  92.  
  93.         .LIST
  94.  
  95. MVINFO  STRUC
  96. NEWDIR  DW      1 DUP (?)               ;FLAG, =1 IF NEW DIRECTORY CREATED
  97. SRCTYPE DB     2 DUP (?)                ;TYPE OF SOURCE (0 IF UFN)
  98. DESTTYPE DB    2 DUP (?)                ;TYPE OF DEST (0 IF UFN)
  99. ARG1    DB      PATHSIZE DUP (?)        ;FIRST ARGUMENT (SOURCE)
  100. ARG2    DB      PATHSIZE DUP (?)        ;SECOND ARGUMENT (DEST)
  101. ARG2A   DB      PATHSIZE DUP (?)        ;SOURCE PREFIX + DEST
  102. SSPATH  DB      PATHSIZE DUP (?)        ;SOURCE SEARCH PATH
  103. SPREFIX DB      PATHSIZE DUP (?)        ;SOURCE LEAD-IN PATH
  104. DSPATH  DB      PATHSIZE DUP (?)        ;DEST SEARCH PATH
  105.                                         ;(USED ONLY AS SCRATCH AREA)
  106. DPREFIX DB      PATHSIZE DUP (?)        ;DEST LEAD-IN PATH
  107. SRCNAME DB      PATHSIZE DUP (?)        ;UNAMBIGUOUS SOURCE NAME
  108. DESTNAME DB     PATHSIZE DUP (?)        ;UNAMBIG. DEST NAME
  109. DTA     DB      128 DUP (?)             ;DTA FOR SEARCH FN.
  110. MVINFO  ENDS
  111. MVSTRUCSIZE EQU 9*PATHSIZE+135          ;SIZE OF STRUCTURE
  112.  
  113.     .DATA
  114. ;       INITIALIZED DATA STORAGE:
  115. ;
  116. MSG1    DB 'CP Version 1.7 by Jon Dart (09-Feb-88)',CR,LF,CR,LF
  117.         DB 'USAGE (afn = ambiguous file name, ufn = unambiguous file name,'
  118.         DB CR,LF
  119.         DB '       dir = directory):',CR,LF,CR,LF
  120.         DB 'CP ufn1 ufn2          copies ufn1 to ufn2.',CR,LF,CR,LF
  121.         DB 'CP afn1 afn2 ... dir  copies one or more files into dir.',CR,LF
  122.         DB CR,LF
  123.         DB "CP -R dir1 dir2       if dir2 doesn't exist, creates it and copies"
  124.         DB CR,LF
  125.         DB '                      all files from dir1 to dir2.',CR,LF,CR,LF
  126.         DB "                      if dir2 exists, creates dir2\dir1 and copies"
  127.         DB CR,LF
  128.         DB '                      all files from dir1 into it.',CR,LF,CR,LF
  129.         DB 'SWITCHES (OPTIONAL):',CR,LF,CR,LF
  130.     DB '-I   prompt before overwriting files.',CR,LF,CR,LF
  131.     DB '-R   allow recursive copying of directories.',CR,LF,CR,LF
  132.         DB '-V   echo file names as they are copied.',CR,LF
  133.         DB 0
  134. MSG2    DB      ': file not found.',CR,LF,0
  135. MSG3    DB      'Source and dest are incompatible.',CR,LF,0
  136. MSG4    DB      ' exists. Overwrite [Y or N]? ',0
  137. MSG5    DB      ': open failed.',CR,LF,0
  138. MSG6    DB      ': file is R/O. Are you SURE [Y or N]? ',0
  139. MSG7    DB    ': directory.',CR,LF,0
  140. MSG8    DB      ': write error.',CR,LF,0
  141. MSG9    DB      ': read error.',CR,LF,0
  142. MSG10   DB      ': write error (probably disk full).',CR,LF,0
  143. MSG11   DB      ': rename failed.',CR,LF,0
  144. MSG12   DB      ": can't create.",CR,LF,0
  145. MSG13   DB      ": can't remove.",CR,LF,0
  146. MSG14   DB      "Directories nested too deep.",CR,LF,0
  147. ; MSG15   DB      "Insufficient memory for buffers.",CR,LF,0
  148. MSG16   DB      ": Illegal switch.",CR,LF,0
  149. MSG17   DB      "Error: source and dest are identical.",CR,LF,0
  150. MSG18   DB      "Too many arguments.",CR,LF,0
  151. SWLIST    DB    'IRV',0        ;LIST OF VALID SWITCHES
  152.  
  153.     .STACK
  154.         DB      512 DUP (?)
  155.  
  156. ;       UNITIALIZED VARIABLES AND BUFFER AREAS
  157.  
  158.     .DATA?
  159. RBASE   DW     1 DUP (?)               ;POINTER TO MVSTRUC IN RSTACK
  160. LEVEL   DW      1 DUP (?)               ;RECURSION LEVEL
  161. SRCDRIVE  DW    1 DUP (?)               ;SOURCE DRIVE (0 = DEFAULT)
  162. DESTDRIVE  DW   1 DUP (?)               ;DEST DRIVE (0 = DEFAULT)
  163. INHANDLE DW    1 DUP (?)               ;INPUT FILE HANDLE
  164. OUTHANDLE DW    1 DUP (?)               ;OUTPUT FILE HANDLE
  165. IFLAG   DW    1 DUP (?)               ;CONFIRM FLAG
  166. RFLAG    DW    1 DUP (?)        ;RECURSIVE FLAG
  167. VFLAG   DW    1 DUP (?)               ;VERBOSE FLAG
  168. CMDTAIL DB    128 DUP (?)             ;STORAGE FOR COMMAND TAIL
  169. DEST_DTA DB     128 DUP (?)             ;HOLDS INFO ON DEST, RETURNED FROM DOS
  170.                                         ;FN 4E.
  171. NUMARGS DW      1 DUP (?)               ;NUMBER OF ARGUMENTS ON COMMAND LINE
  172. ARGPTRS DW      MAXARGS DUP (?)         ;POINTERS TO START OF ARGUMENTS
  173. BUFFER  DB      BUFSIZE DUP (?)         ;FILE XFER BUFFER
  174. RSTACK  MVINFO  MAXLEVEL DUP (<>)    ;RECURSION STACK
  175.  
  176.         PAGE +
  177.  
  178.     .CODE
  179.  
  180. EXTRN   CPYCNT:NEAR,UC:NEAR,UCSTR:NEAR,CRLF:NEAR
  181. EXTRN   ERRORMSG:NEAR,COUT:NEAR,CIN:NEAR,CLRCO:NEAR
  182. EXTRN   SKIPSP:NEAR,TYPTX:NEAR,ERRORMSG:NEAR,CLRCO:NEAR
  183. EXTRN   CMDSRC:NEAR,FIXPATH:NEAR,TYPE_DIR:ABS,TYPE_AFN:ABS
  184. EXTRN   TYPE_UFN:ABS,TYPE_DSP:ABS,TYPE_DRV:ABS,TYPE_UNK:ABS
  185. EXTRN   GETYORN:NEAR,UNLINK2:NEAR
  186.  
  187. ;**********************
  188. ; PROGRAM ENTRY POINT *
  189. ;**********************
  190. ENTRY:
  191.         TEST_DOS2                       ;TEST FOR DOS 2.0, EXIT IF DOS 1
  192.     MOV    AX,DGROUP
  193.     MOV    ES,AX
  194.         MOV     BX,(80H)              ;POINT TO BYTE COUNT FOR COMMAND LINE
  195.         CMP     [BX],BYTE PTR 0
  196.         JE      USEMSG                  ;IF NO COMMAND TAIL
  197.         PUSH    BX
  198.         MOV     DL,[BX]            ;LOAD BYTE COUNT IN DX
  199.         MOV     DH,0
  200.         ADD     BX,DX
  201.         INC     BX
  202.         MOV     [BX],BYTE PTR 0         ;PUT 0 BYTE AT END OF COMMAND LINE
  203.         POP     BX
  204.         INC     BX
  205.         CALL    SKIPSP                  ;SKIP LEADING SPACES
  206.         JNC     L_2                     ;IF SOMETHING ON LINE
  207. USEMSG: ERROR   1
  208.     MOV    AL,1            ;SET ERROR CODE
  209.         JMP     EXIT2
  210. L_2:
  211.         MOV     SI,BX
  212.         MOV     DI,OFFSET ES:CMDTAIL
  213.         MOV     CX,128
  214.         CALL    CPYCNT                  ;SAVE COMMAND TAIL
  215.         MOV     AX,ES
  216.         MOV     DS,AX                   ;SET DATA SEG TO VARIABLE AREA
  217.         MOV     BYTE PTR DS:IFLAG,CONFIRM  ;SET CONFIRM FLAG DEFAULT
  218.         MOV     BYTE PTR DS:VFLAG,VERBOSE  ;SET VERBOSE FLAG DEFAULT
  219.     MOV    BYTE PTR DS:RFLAG,RECURSE  ;SET RECURSIVE FLAG DEFAULT
  220.     MOV    WORD PTR DS:LEVEL,0    ;ZERO RECURSION LEVEL
  221.         MOV     BYTE PTR DS:SRCDRIVE,0  ;SET SOURCE DRIVE DEFAULT
  222.         MOV     BYTE PTR DS:DESTDRIVE,0 ;SET DEST DRIVE DEFAULT
  223. ;***************************
  224. ; COLLECT SWITCHES, IF ANY *
  225. ;***************************
  226.         MOV     BX,OFFSET CMDTAIL       ;POINT TO COMMAND TAIL
  227.         CALL    UCSTR                   ;MAKE UPPER-CASE
  228. NEXTSW:
  229.         CALL    SKIPSP
  230.         JB      USEMSG                  ;IF NOTHING ON LINE BESIDES SWITCHES
  231.         CMP     BYTE PTR [BX],'/'       ;SWITCH SPECIFIED?
  232.         JE      GOTSW            ;YES.
  233.     CMP    BYTE PTR [BX],'-'    ;CHECK FOR HYPHEN, TOO
  234.     JNE    NOSWITCH
  235. GOTSW:
  236.         INC     BX                      ;SKIP OVER SWITCH CHARACTER
  237.         CALL    SKIPSP                  ;SKIP LEADING BLANKS
  238.         JB      USEMSG                  ;IF NOTHING
  239. SWLOOP:
  240.     PUSH    BX
  241.     MOV    BX,OFFSET SWLIST
  242.     CALL    CMDSRC            ;SEARCH LIST OF VALID SWITCHES
  243.     POP    BX
  244.     MOV    AH,0
  245.     ADD    AX,AX            ;NOT FOUND IN LIST?
  246.     JZ    BADSWITCH        ;NO.
  247.     MOV    SI,OFFSET IFLAG - 2
  248.     ADD    SI,AX            ;POINT TO FLAG
  249.     NOT    BYTE PTR [SI]        ;1'S COMPLEMENT
  250.     INC    BX
  251.     MOV    AL,BYTE PTR [BX]    ;GET NEXT CHAR. FROM LINE
  252.     CMP    AL,SPACE
  253.     JE    NEXTSW            ;IF SPACE, LOOK FOR - OR FILENAME
  254.     CMP    AL,TAB
  255.     JE    NEXTSW            ;IF TAB, LOOK FOR - OR FILENAME
  256.     JMP    SWLOOP            ;ELSE ASSUME THIS IS A SWITCH CHAR.
  257. BADSWITCH:
  258.     MOV    AL,BYTE PTR [BX]
  259.         CALL    COUT                    ;DISPLAY BAD CHAR.
  260.         ERROR   16                      ;ILLEGAL SWITCH
  261.     MOV    AL,16            ;SET ERROR CODE
  262.         JMP     EXIT2
  263. ;************************************************************
  264. ; SCAN THE COMMAND LINE AND STORE POINTERS TO ALL ARGUMENTS *
  265. ;************************************************************
  266. NOSWITCH:
  267.         MOV     CX,0                    ;CX COUNTS # OF ARGUMENTS
  268.         MOV     SI,OFFSET DS:ARGPTRS    ;POINT TO ARG POINTER TABLE
  269. SAVEARG:
  270.         INC     CX                      ;BUMP ARGUMENT COUNT
  271.         CMP     CX,MAXARGS
  272.         JG      TOOMANY                 ;IF TOO MANY
  273.         MOV     DS:[SI],BX              ;SAVE POINTER TO ARG
  274.         ADD     SI,2                    ;ADVANCE TO NEXT TABLE ENTRY
  275. CNTARGS:
  276.         MOV     AL,DS:[BX]              ;GET CHAR. FROM COMMAND LINE
  277.         CMP     AL,0
  278.         JE      ENDLINE                 ;IF END OF LINE
  279.         COMPLIST <SPACE,TAB>,NEXTARG    ;SEE IF SPACE OR TAB
  280.         INC     BX
  281.         JMP     CNTARGS                 ;LOOP TILL DELIMITER FOUND
  282. NEXTARG:
  283.         CALL    SKIPSP                  ;SKIP SPACES AND TABS
  284.         JNB     SAVEARG                 ;IF NOT EOL, BACK TO TOP OF LOOP
  285. ENDLINE:
  286.         CMP     CX,0                    ;CHECK ARGUMENT COUNT
  287.         JE      NOARGS                  ;IF NO ARGS
  288.         CMP     CX,1
  289.         JG      ARGSOK                  ;IF >=2 ARGS
  290.         MOV     DS:[SI],BX              ;EXACTLY ONE ARGUMENT, SO
  291.         INC     CX                      ;MAKE A DUMMY (NULL) 2ND ARGUMENT
  292.         JMP     SHORT ARGSOK
  293. NOARGS:
  294.         JMP     USEMSG                  ;ELSE USE MESSAGE
  295. TOOMANY:
  296.         ERROR   18                      ;TOO MANY ARGUMENTS (PRETTY UNLIKELY)
  297.     MOV    AL,18            ;SET ERROR CODE
  298.         JMP     EXIT2
  299. ;************************************
  300. ;* COLLECT THE DESTINATION PATHNAME *
  301. ;************************************
  302. ARGSOK: MOV     WORD PTR NUMARGS,CX      ;SAVE NUMBER OF ARGUMENTS
  303.         DEC     CX                      ;NUMBER OF ARGS - 1
  304.         ADD     CX,CX                   ;TIMES TWO
  305.         MOV     SI,OFFSET ARGPTRS
  306.         ADD     SI,CX                   ;POINT TO ADDR. OF LAST ARGUMENT (DEST)
  307.         MOV     BX,DS:[SI]              ;PUT ADDR. INTO BX
  308.         MOV     DI,OFFSET RSTACK.ARG2      ;POINT TO STORAGE FOR DEST
  309.         MOV     AL,[BX+1]
  310.         CMP     AL,':'                  ;CHECK FOR DEST DRIVE SPEC
  311.         JNE     GETLAST                 ;IF NONE
  312.         MOV     AL,[BX]                 ;DRIVE SPECIFIED, GET DRIVE LETTER
  313.         SUB     AL,'A'-1                ;MAKE BINARY
  314.         MOV     BYTE PTR DESTDRIVE,AL   ;SAVE DRIVE
  315. GETLAST: MOV    AL,[BX]                 ;GET A CHAR. FROM CMD LINE
  316.         COMPLIST <0,SPACE,TAB>,ENDARG2  ;IF DELIMITER
  317.         STOSB                           ;NOT DELIMITER, STORE IT
  318.         INC     BX                      ;BUMP POINTER
  319.         JMP     GETLAST                 ;LOOP
  320. ENDARG2:
  321.         MOV     AL,0
  322.         STOSB                           ;END DEST W. 0
  323. ;************************************************************
  324. ;* LOOP, TAKING ONE SOURCE AT A TIME AND COPYING IT TO DEST *
  325. ;************************************************************
  326.         MOV     CX,WORD PTR DS:NUMARGS  ;GET NUMBER OF ARGS AGAIN
  327.         DEC     CX                      ;-1
  328.         MOV     SI,OFFSET ARGPTRS        ;POINT TO POINTER TABLE
  329. COPY1ARG:
  330.         MOV     BX,DS:[SI]              ;GET POINTER TO ARG
  331.         PUSH    SI
  332.         PUSH    CX
  333.         CALL    COPYARG                 ;COPY IT
  334.         POP     CX
  335.         POP     SI
  336.         ADD     SI,2                    ;ADVANCE TO NEXT ARG POINTER
  337.         LOOP    COPY1ARG                ;LOOP TILL NO MORE ARGS TO COPY
  338.     MOV    AL,0            ;ERROR CODE 0 MEANS OK
  339.         JMP     EXIT2
  340.  
  341. ;**********************************
  342. ;* COPY 1 SOURCE ARGUMENT TO DEST *
  343. ;**********************************
  344. COPYARG PROC   NEAR
  345.         MOV     BYTE PTR DS:SRCDRIVE,0  ;SET SOURCE DRIVE DEFAULT
  346.         MOV     DI,OFFSET RSTACK.ARG1      ;COLLECT SOURCE
  347.         MOV     AL,[BX+1]
  348.         CMP     AL,':'                  ;CHECK FOR SOURCE DRIVE SPEC
  349.         JNE     GETARG
  350.         MOV     AL,[BX]                 ;GET DRIVE LETTER
  351.         SUB     AL,'A'-1                ;MAKE BINARY
  352.         MOV     BYTE PTR DS:SRCDRIVE,AL ;SAVE SOURCE DRIVE
  353. GETARG: MOV     AL,[BX]                 ;COPY FROM [BX] TO [DI] UNTIL DELIMITER
  354.         COMPLIST <0,SPACE,TAB>,ENDARG
  355.         STOSB
  356.         INC     BX
  357.         JMP     GETARG
  358. ENDARG: MOV     AL,0
  359.         STOSB                           ;END ARG1 W. ZERO
  360.         MOV     WORD PTR RBASE,OFFSET RSTACK   ;SAVE OFFSET TO RSTACK
  361.         CALL    COPYIT                  ;DO THE STUFF
  362.         RET
  363. COPYARG ENDP
  364.  
  365.         PAGE +
  366. ;********************************************************************
  367. ; THIS IS THE COPY SUBROUTINE. IT ASSUMES THAT ARG1 AND ARG2 ARE
  368. ; SET UP PROPERLY IN THE RECURSION STACK AREA, AND THAT "RBASE" POINTS
  369. ; TO THE START OF THE DATA STRUCTURE FOR THIS RECURSION LEVEL.
  370. ;
  371. COPYIT  PROC    NEAR
  372.         MOV     BX,WORD PTR RBASE        ;GET BASE ADDR. (POINTER TO MVINFO)
  373.         CALL    SETUP                   ;PARSE ARGUMENTS, CHECK FOR ERRORS
  374.         JNC     NOARGERR                ;IF OK
  375.         JMP     EXIT2                   ;QUIT IF ERROR
  376. ;******************************************
  377. ; SEE IF ANYTHING MATCHES THE SOURCE SPEC *
  378. ;******************************************
  379. NOARGERR:
  380.         ADDR    DX,SSPATH               ;POINT TO SEARCH PATH
  381.         MOV     CX,31H                  ;SET SEARCH ATTRIBUTES
  382.         MOV     AH,FIND_FIRST
  383.         INT     DOS                     ;SEARCH FOR 1ST MATCH
  384.         JNC     SRCOK                   ;OK IF SOMETHING FOUND
  385.         ADDR    DX,ARG1
  386.         CALL    ERRORMSG                ;ELSE SHOW ARGUMENT
  387.         ERROR   2                       ;SAY IT DOESN'T EXIST
  388.     MOV    AL,2            ;SET ERROR CODE
  389.         JMP     EXIT2            ;EXIT 2 DOS
  390. ;**************************************
  391. ; CREATE DEST DIRECTORY, IF NECESSARY *
  392. ;**************************************
  393. SRCOK:  CMP     WORD PTR [BX].NEWDIR,1  ;CHECK NEW DIRECTORY FLAG
  394.         JNE     GOTONE                  ;IF NOT SET
  395.         ADDR    DX,ARG2A                ;POINT TO DEST NAME
  396.         MOV     AH,MKDIR
  397.         INT     DOS                     ;CREATE NEW DIRECTORY
  398.         JNB     GOTONE                  ;IF OK
  399.         ADDR    DX,ARG2A                ;IF CAN'T CREATE,
  400.         CALL    ERRORMSG                ;SHOW DIRECTORY NAME
  401.         ERROR   12                      ;AND ERROR MSG.
  402.     MOV    AL,12            ;SET ERROR CODE
  403.         JMP     EXIT2                   ;EXIT 2 DOS
  404. ;**************
  405. ; TOP OF LOOP *
  406. ;**************
  407. GOTONE:
  408.         CALL    BUILD_NAMES             ;MAKE UNAMBIG. SOURCE AND DEST NAMES
  409.         JNC     NOSKIP
  410.         JMP     NEXTFILE                ;IF SOURCE IS "." OR ".." OR = DEST
  411. NOSKIP:
  412.         CMP     BYTE PTR VFLAG,TRUE      ;CHECK VERBOSE FLAG
  413.         JNE     QUIET                   ;IF QUIET MODE
  414.         ADDR    DX,SRCNAME              ;NOT QUIET, SHOW VERBIAGE
  415.         CALL    ERRORMSG
  416.         CALL    TYPTX
  417.         DB      ' -->',SPACE+200Q
  418.         ADDR    DX,DESTNAME
  419.         CALL    ERRORMSG
  420.         CALL    CRLF
  421. QUIET:
  422.         TEST    [BX].DTA+21,BIT$DIR     ;IS SOURCE A DIRECTORY?
  423.         JZ      COPYFILE                ;NO
  424.     CMP    BYTE PTR DS:RFLAG,TRUE    ;IS R FLAG SET?
  425.     JNE    NEXTFILE        ;NO, JUST SKIP OVER DIRECTORY
  426. ;***********************************************
  427. ; IF SOURCE IS A DIRECTORY, RECURSIVELY COPY IT*
  428. ;***********************************************
  429.         CMP     WORD PTR LEVEL,MAXLEVEL-1 ;ARE WE AT MAX LEVEL?
  430.         JL      NOTMAX                  ;NO
  431.         ERROR   14                      ;YES, TOO DEEP
  432.     MOV    AL,14            ;SET ERROR CODE
  433.         JMP     EXIT2
  434. NOTMAX:
  435.         COPYPATH SRCNAME,(ARG1+MVSTRUCSIZE)  ;COPY SOURCE DIRECTORY TO ARG1 AT NEXT LEVEL
  436.         COPYPATH DESTNAME,(ARG2+MVSTRUCSIZE) ;COPY DEST NAME TO ARG2 AT NEXT LEVEL
  437.         PUSH    BX                      ;SAVE POINTER TO BASE
  438.         INC     WORD PTR LEVEL           ;INCREMENT RECURSION LEVEL
  439.         ADD     WORD PTR RBASE,MVSTRUCSIZE ;ADVANCE BASE POINTER
  440.         CALL    COPYIT                  ;COPY THE DIRECTORY
  441.         POP     BX                      ;RESTORE BASE POINTER
  442.         DEC     WORD PTR LEVEL          ;DECREMENT RECURSION LEVEL
  443.         SUB     WORD PTR RBASE,MVSTRUCSIZE ;RESTORE BASE TO PREVIOUS LEVEL
  444.         ADDR    DX,DTA
  445.         MOV     AH,SET_DTA
  446.         INT     DOS                     ;RESET DTA
  447.         JMP     SHORT NEXTFILE          ;DO NEXT FILE
  448. ;*******************************
  449. ; IF SOURCE IS A FILE, COPY IT *
  450. ;*******************************
  451. COPYFILE:
  452.         CALL    COPY_FILE        ;COPY A FILE
  453.     JNB    NEXTFILE        ;IF OK
  454.     JMP    EXIT2            ;IF ERROR
  455. ;*****************
  456. ; BOTTOM OF LOOP *
  457. ;*****************
  458. NEXTFILE:
  459.         MOV     AH,FIND_NEXT
  460.         INT     DOS                     ;FIND NEXT MATCH, IF ANY
  461.         JC      NOMORE                  ;IF NONE
  462.         JMP     GOTONE                  ;GOT ONE, BACK TO TOP OF LOOP
  463. ;**********************
  464. ; NO MORE FILES, DONE *
  465. ; *********************
  466. NOMORE:
  467. JUSTCLOSE:
  468.         CALL    CLOSE2                 ;CLOSE OUTPUT FILE
  469.         CALL    CLOSE1                 ;CLOSE INPUT FILE
  470.         RET                             ;ALL DONE
  471. COPYIT  ENDP
  472.  
  473.         PAGE +
  474. ;*************************************************************************
  475. ; THIS PROCEDURE PARSES ARG1 AND ARG2 AND CHECKS FOR INCOMPATIBLE TYPES
  476. ; (E.G. "MV FOOBAR *.*").  IF SUCCESSFUL, IT SETS SSPATH = SOURCE SEARCH
  477. ; PATH, SPREFIX = SOURCE PREFIX, DSPATH = DEST SEARCH PATH (NOT USED),
  478. ; DPREFIX = DEST PREFIX, SRCTYPE = SOURCE TYPE DESTTYPE = DESTINATION TYPE.
  479. ; IT ALSO SETS "NEWDIR"=1 IF THE DESTINATION DIRECTORY MUST BE CREATED.
  480. ; ALL OF THESE VARIABLES ARE IN A STRUCTURE OF TYPE 'MVINFO' IN THE RECURSION
  481. ; STACK AREA (STARTING AT THE ADDRESS IN 'RBASE').
  482. ;
  483. ; ON RETURN, THE CARRY FLAG IS SET IF AN ERROR OCCURRED, AND AL HOLDS AN
  484. ; ERROR CODE (<>0)
  485. ;
  486. SETUP   PROC    NEAR
  487.         MOV     BX,WORD PTR DS:RBASE    ;GET ADDR. OF DATA STRUCTURE
  488.         MOV     WORD PTR [BX].NEWDIR,0  ;CLEAR "NEW DIRECTORY" FLAG
  489.         ADDR    DX,DTA
  490.         MOV     AH,SET_DTA
  491.         INT     DOS                     ;SET DTA
  492.         ADDR    SI,ARG1
  493.         ADDR    DI,ARG2
  494.         COMP_STRINGS                    ;COMPARE ARG1 AND ARG2
  495.         JNE     NOTIDENT                ;IF NOT IDENTICAL
  496.         ERROR   17                      ;ARG1 = ARG2, BAD NEWS
  497.     MOV    AL,17            ;SET ERROR CODE
  498.         STC
  499.         RET
  500. NOTIDENT:
  501.         ADDR    CX,SSPATH
  502.         ADDR    DX,SPREFIX
  503.         PUSH    BX
  504.         ADD     BX,ARG1
  505.         CALL    FIXPATH                 ;PARSE SOURCE PATHNAME
  506.         POP     BX
  507.         CMP     AX,TYPE_UNK
  508.         JNE     GOODPATH                ;IF APPARENTLY OK
  509.         ADDR    DX,ARG1
  510.         CALL    ERRORMSG
  511.         ERROR   2                       ;NONEXISTENT PATHNAME, COMPLAIN
  512.     MOV    AL,2            ;SET ERROR CODE
  513.         STC
  514.         RET
  515. GOODPATH:
  516.         MOV     WORD PTR [BX].SRCTYPE,AX     ;SAVE TYPE OF SOURCE
  517.     CMP    AX,TYPE_DIR        ;IS IT DIRECTORY?
  518.     JNE    RSET            ;NO.
  519.     CMP    BYTE PTR DS:RFLAG,TRUE  ;YES IT IS, IS RFLAG SET?
  520.     JE    RSET            ;YES.
  521.     ADDR    DX,ARG1            ;R FLAG NOT SET,
  522.     CALL    ERRORMSG        ;SHOW NAME
  523.     ERROR    7            ;COMPLAIN ABOUT DIRECTORY
  524.     MOV    AL,7            ;SET ERROR CODE
  525.     STC                ;SIGNAL ERROR
  526.     RET
  527. RSET:
  528.         ADDR    SI,ARG2
  529. PDEST:  PUSH    SI
  530. SRCBS:  MOV     AX,[SI]                 ;FIND END OF DEST
  531.         COMPLIST <0,SPACE,TAB>,GOTEND
  532.         INC     SI
  533.         JMP     SRCBS
  534. GOTEND:
  535.         DEC     SI
  536.         CMP     [SI],BYTE PTR '\'       ;DOES DEST SPEC END W. BACKSLASH?
  537.         JNE     NOBS                    ;NO, IT DOESN'T
  538.         MOV     [SI],BYTE PTR 0         ;IF SO, REMOVE IT
  539. NOBS:   COPYPATH ARG2,ARG2A           ;MAKE ARG2A = ARG2
  540.         POP     SI                      ;POINT TO START OF ARG2 AGAIN
  541.         ADDR    CX,DSPATH
  542.         ADDR    DX,DPREFIX
  543.         PUSH    BX
  544.         MOV     BX,SI
  545.         CALL    FIXPATH                 ;PARSE DEST PATHNAME
  546.         POP     BX
  547.         MOV     WORD PTR [BX].DESTTYPE,AX       ;SAVE DEST TYPE
  548.         CMP     AL,TYPE_AFN
  549.         JE      BADDEST                 ;DEST CAN'T BE AFN
  550.         CMP     AL,TYPE_UFN
  551.         JNE     NOTUFN                  ;IF DEST TYPE IS UFN,
  552.         CMP     WORD PTR DS:NUMARGS,2   ;BETTER HAVE ONLY 1 SOURCE
  553.         JG      BADDEST
  554.         CMP     WORD PTR DS:SRCTYPE,TYPE_AFN  ;AND SOURCE TYPE BETTER NOT BE AFN
  555.         JNE     NOTUFN
  556. BADDEST:
  557.         ERROR   3
  558.     MOV    AL,3            ;SET ERROR CODE
  559.         STC
  560.         RET
  561. NOTUFN:
  562.         COMPLIST <TYPE_DSP,TYPE_DRV,TYPE_DIR>,DESTDSP ;IF DEST IS DIR OR DRIVE
  563.         CMP     AL,TYPE_UNK
  564.         JNE     SHORT DESTOK            ;IF DEST EXISTS
  565. DESTNX:
  566.         MOV     AX,WORD PTR [BX].SRCTYPE  ;DEST DOESN'T EXIST, SO IF
  567.         CMP     AL,TYPE_DIR             ;SOURCE TYPE IS DIRECTORY,
  568.         JNE     DESTOK
  569.         CALL    SETUP_DEST_DIR          ;MAKE DEST A DIRECTORY, TOO
  570.         JMP     SHORT DESTOK
  571. DESTDSP: MOV    AX,WORD PTR [BX].SRCTYPE  ;DEST IS DIRECTORY, DIR SPEC OR DRIVE
  572.         CMP     AL,TYPE_DIR             ;IS SOURCE A DIRECTORY? -
  573.         JNE     DESTOK                  ;- NO
  574.         CALL    SETUP_SRC_DIR           ;- YES, SOURCE IS DIRECTORY, SET IT UP
  575.         JB      ERRRET                  ;IF ERROR
  576.         MOV     AX,WORD PTR [BX].DESTTYPE
  577.         CMP     AX,TYPE_DIR             ;IS DEST A DIRECTORY? -
  578.         JNE     DESTOK                  ;- NO
  579.         CALL    SETUP_DEST_DIR          ;- YES, SET IT UP, TOO
  580. ;*******************************
  581. ; CHECK FOR INCOMPATIBLE TYPES *
  582. ;*******************************
  583. DESTOK:
  584.         MOV     CX,WORD PTR [BX].DESTTYPE    ;GET DEST TYPE
  585.         MOV     AX,WORD PTR [BX].SRCTYPE     ;GET SOURCE TYPE
  586.         CMP     AX,TYPE_DIR             ;IS SOURCE A DIRECTORY? -
  587.         JNE     TYPEOK                  ;- NO, IT ISN'T
  588.         CMP     CX,TYPE_DIR             ;- YES, SOURCE IS DIRECTORY,
  589.         JE      TYPEOK                  ;DEST BETTER BE DIRECTORY
  590.         CMP     CX,TYPE_DRV             ;OR DRIVE SPEC
  591.         JE      TYPEOK
  592. ERRRET:
  593.         ERROR   3                       ;ELSE INCOMPATIBLE TYPE ERROR
  594.     MOV    AL,3            ;SET ERROR CODE
  595.     STC                             ;ERROR RETURN
  596.         RET
  597. TYPEOK: CLC                             ;NORMAL RETURN
  598.         RET
  599. SETUP   ENDP
  600.  
  601. ;**********************************************
  602. ; COPY IS FROM DIR TO DIR, DIR SPEC OR DRIVE
  603. ; BUILD FULL DEST PATHNAME (IN ARG2A) AND CHECK
  604. ; ITS TYPE.  (SETS CARRY ON ERROR)
  605. ;
  606. SETUP_SRC_DIR PROC NEAR
  607.         COPYPATH ARG2,DSPATH          ;COPY DEST DIRECTORY OR DRIVE SPEC TO
  608.                                         ;DEST PATH (USE AS SCRATCH AREA)
  609.         DEC     DI                      ;BACK UP OVER NULL
  610.         MOV     AX,WORD PTR [BX].DESTTYPE
  611.         CMP     AX,TYPE_DIR             ;SEE IF DEST IS DIRECTORY
  612.         JNE     NOTDIR                  ;NOPE
  613.         MOV     BYTE PTR [DI],'\'       ;YES, ADD BACKSLASH TO DEST NAME
  614.         INC     DI
  615.         DEC     CX
  616. NOTDIR: ADDR    SI,ARG1                 ;POINT TO SOURCE DIRECTORY NAME
  617.         CMP     BYTE PTR [SI+1],':'     ;DRIVE SPECIFIED? -
  618.         JNE     NODRV                   ;- NO IT WASN'T
  619.         ADD     SI,2                    ;- YES, IT WAS, SKIP IT
  620. NODRV:
  621. RMDOT:
  622.     CMP    BYTE PTR [SI],'.'    ;DOES SOURCE START W. PERIOD?
  623.     JNE    NODOTS            ;NO, WE'RE OK
  624.     INC    SI
  625.     JMP    RMDOT            ;YES, REMOVE PERIOD
  626. NODOTS: CMP    BYTE PTR [SI],'\'    ;IS NEXT CHAR. \?
  627.     JNE    NOBKSL            ;NO
  628.     INC    SI            ;YES, SKIP PAST IT
  629. NOBKSL:
  630.         CALL    CPYCNT                  ;COPY SOURCE DIRECTORY NAME (MINUS
  631.                                         ;DRIVE SPEC) TO DEST PATH
  632.         COPYPATH DSPATH,ARG2A         ;COPY AUGMENTED DEST PATH TO ARG2A
  633.         ADDR    CX,DSPATH
  634.         ADDR    DX,DPREFIX
  635.         PUSH    BX
  636.         ADD     BX,ARG2A
  637.         CALL    FIXPATH                 ;PARSE FULL DEST PATHNAME
  638.         POP     BX
  639.         MOV     WORD PTR [BX].DESTTYPE,AX    ;SAVE DEST TYPE
  640.         CMP     AL,TYPE_UNK
  641.         JNE     DESTXST                 ;IF DEST EXISTS
  642.         MOV     AX,WORD PTR [BX].SRCTYPE  ;DEST DOESN'T EXIST, GET SOURCE TYPE
  643.         CMP     AX,TYPE_DIR             ;IF SOURCE IS A DIRECTORY,
  644.         JNE     DESTXST
  645.         MOV     [BX].DESTTYPE,TYPE_DIR  ;MAKE DEST A DIRECTORY, TOO
  646. DESTXST:
  647.         CLC
  648.         RET
  649. SETUP_SRC_DIR ENDP
  650.  
  651. ;***************************************************************
  652. ; THIS PROCEDURE IS CALLED IF THE DESTINATION IS A NEW DIRECTORY
  653. ;
  654. SETUP_DEST_DIR PROC NEAR
  655.         ADDR    SI,DSPATH
  656.         ADDR    DI,DPREFIX
  657.         PUSH    DI
  658.         MOV     CX,PATHSIZE
  659.         CALL    CPYCNT                  ;COPY SEARCH PATH TO PREFIX
  660.         POP     DI
  661.         MOV     CX,PATHSIZE
  662.         MOV     AL,0
  663.         REPNE   SCASB                   ;FIND END OF DEST PREFIX
  664.         DEC     DI
  665.         MOV     [DI],BYTE PTR '\'       ;ADD BACKSLASH
  666.         MOV     [DI+1],BYTE PTR 0
  667.         MOV     [BX].NEWDIR,WORD PTR 1  ;SET "NEW DIRECTORY FLAG"
  668.         MOV     WORD PTR [BX].DESTTYPE,TYPE_DIR ;SET DEST TYPE = DIRECTORY
  669.         RET
  670. SETUP_DEST_DIR ENDP
  671.  
  672.         PAGE +
  673. ;****************************************************************************
  674. ; THIS ROUTINE TAKES THE INFO ON A FILE IN THE DTA AND USES IT TO GENERATE
  675. ; FULL, UNAMBIGUOUS SOURCE AND DESTINATION FILE NAMES BY ADDING THE NECESSARY
  676. ; DIRECTORY PREFIXES TO IT.  IT SETS THE CARRY FLAG IF THE "FILE"
  677. ; IS "." OR "..", OR IF THE SOURCE IS IDENTICAL TO THE DESTINATION.
  678. ;
  679. BUILD_NAMES  PROC  NEAR
  680.         COPYPATH SPREFIX,SRCNAME    ;GET SOURCE PREFIX, 
  681.                     ;COPY TO SOURCE NAME
  682.         DEC     DI                      ;BACK UP OVER NULL
  683.         ADDR    SI,(DTA+30)             ;POINT TO FILE NAME WE FOUND
  684.         CMP     [SI],BYTE PTR '.'       ;DOES IT START WITH .? -
  685.         JNE     NOTDOT                  ;- NO
  686.         STC                             ;- YES, SET CARRY TO SKIP IT
  687.         RET
  688. NOTDOT:
  689.         CALL    CPYCNT                  ;ADD IT TO SOURCE PREFIX
  690.         CMP     WORD PTR [BX].DESTTYPE,TYPE_UFN  ;IS DEST A UFN?
  691.         JE      DESTUFN                 ;YES, JUST USE IT
  692.         CMP     WORD PTR [BX].DESTTYPE,TYPE_UNK
  693.         JE      DESTUFN                 ;DITTO IF DEST DOESN'T EXIST
  694.                                         ;IF NOT, MAKE DEST NAME = SOURCE NAME
  695.         COPYPATH DPREFIX,DESTNAME       ;COPY DEST PREFIX TO DEST NAME
  696.         DEC     DI                      ;BACK UP OVER NULL
  697.         ADDR    SI,DTA+30               ;POINT TO FILE NAME WE FOUND
  698.         CALL    CPYCNT                  ;ADD IT TO DEST PREFIX
  699.         JMP     SHORT DONE              ;GO TO NEXT STEP
  700. DESTUFN:                                ;DEST IS A FILE, NOT A DIRECTORY
  701.         COPYPATH ARG2,DESTNAME          ;SO DESTNAME JUST = ARG2
  702. DONE:
  703.         CALL    CHECK_NAMES             ;CHECK SOURCE AND DEST FOR IDENTITY
  704.         RET
  705. BUILD_NAMES ENDP
  706.  
  707.         PAGE +
  708. ;*********************************************************************
  709. ; THIS PROCEDURE CHECKS THE SOURCE AND DEST FILES, AND SETS THE CARRY
  710. ; FLAG IF THEY ARE IDENTICAL
  711. ;
  712. CHECK_NAMES PROC NEAR
  713.         MOV     BX,WORD PTR DS:RBASE    ;GET ADDR. OF DATA STRUCTURE
  714.         MOV     AH,SET_DTA
  715.         MOV     DX,OFFSET DEST_DTA
  716.         INT     DOS                     ;SET DTA
  717.         ADDR    DX,ARG2                 ;POINT TO DESTINATION
  718.         MOV     CX,0FFH
  719.         MOV     AH,FIND_FIRST
  720.         INT     DOS                     ;SEARCH FOR IT
  721.         PUSHF
  722.         ADDR    DX,DTA
  723.         MOV     AH,SET_DTA
  724.         INT     DOS                     ;RESET DTA
  725.         POPF
  726.         JNB     GOTDEST                 ;IF FOUND IT
  727.         CLC                             ;OK IF IT DOESN'T EXIST
  728.         RET
  729. GOTDEST: ADDR   SI,DTA+21               ;POINT TO INFO ON SOURCE
  730.         MOV     DI,OFFSET DEST_DTA+21      ;POINT TO INFO ON DEST
  731.         MOV     CX,9                    ;SIZE OF FILE ATTRIBUTES
  732.         REPE    CMPSB                   ;COMPARE SOURCE AND DEST
  733.         JNE     NOTEQU                  ;IF NOT =
  734.         COMP_STRINGS                    ;COMPARE STRINGS
  735.         JNE     NOTEQU                  ;IF SOURCE AND DEST NAMES NOT EQUAL
  736.         STC                             ;FILES ARE EQUAL (NAMES AND ATTRIB.)
  737.         RET
  738. NOTEQU: CLC
  739.         RET
  740. CHECK_NAMES ENDP
  741.         PAGE +
  742. ;**************************************************************************
  743. ; THIS ROUTINE COPIES A SINGLE FILE (SRCNAME) TO ITS DESTINATION (DESTNAME)
  744. ;
  745. ; IT SETS THE CARRY FLAG ON ERROR, AND RETURNS AN ERROR CODE IN AL.
  746. ;
  747. COPY_FILE PROC  NEAR
  748.         ADDR    DX,SRCNAME              ;DX = SOURCE FILE NAME
  749.         MOV     AL,READ_ACCESS
  750.         MOV     AH,DOS2_OPEN
  751.         INT     DOS                     ;TRY TO OPEN SOURCE FILE
  752.         JC      FAIL                    ;IF CAN'T
  753.         MOV     WORD PTR DS:INHANDLE,AX    ;SAVE FILE HANDLE
  754.         CALL    GETOK                   ;GET CONFIRMATION IF DEST EXISTS
  755.         JNC     OKGIVEN                 ;IF OK TO DELETE
  756.         MOV     BX,WORD PTR DS:INHANDLE ;IF NOT OK,
  757.         MOV     AH,DOS2_CLOSE
  758.         INT     DOS                     ;CLOSE INPUT FILE
  759.     CLC
  760.         RET                             ;QUIT W/O COPYING
  761. FAIL:   ADDR    DX,SRCNAME              ;POINT TO SOURCE FILE NAME
  762.         CALL    ERRORMSG                ;SHOW IT
  763.         ERROR   5                       ;COMPLAIN THAT CAN'T OPEN
  764.     MOV    AL,5            ;SET ERROR CODE
  765.     STC
  766.         RET                ;ERROR RETURN
  767. OKGIVEN: ADDR   DX,DESTNAME
  768.         MOV     CL,BYTE PTR [BX].DTA+21  ;MAKE DEST ATTRIBUTES=SOURCE ATTRIB.
  769.         MOV     CH,0
  770.         MOV     AH,DOS2_CREATE
  771.         INT     DOS                     ;CREATE DEST FILE (OR TRUNCATE OLD ONE)
  772.         JNC     CREATED                 ;IF OK
  773.         ADDR    DX,DESTNAME
  774.         CALL    ERRORMSG                ;CREATE FAILED, SHOW FILE NAME
  775.         ERROR   5                       ;COMPLAIN THAT CAN'T OPEN
  776.     CALL    CLOSE1            ;CLOSE INPUT FILE
  777.     MOV    AL,5            ;SET ERROR CODE
  778.     STC                ;SIGNAL ERROR
  779.     RET
  780. CREATED:
  781.         MOV     WORD PTR DS:OUTHANDLE,AX   ;SAVE OUTPUT HANDLE
  782. COPYLOOP:
  783.         PUSH    BX
  784.         MOV     BX,WORD PTR DS:INHANDLE ;BX = FILE HANDLE
  785.         MOV     DX,OFFSET BUFFER        ;DX = BUFFER OFFSET
  786.         MOV     CX,BUFSIZE              ;CX = BUFFER SIZE
  787.         MOV     AH,READ                 ;USING DOS 2 CALL,
  788.         INT     DOS                     ;READ FROM SOURCE
  789.         POP     BX
  790.         JC      RDERR                   ;IF ERROR
  791.         MOV     CX,AX                   ;SAVE AMT. READ
  792.         CMP     AX,0
  793.         JE      ENDCOPY                 ;IF 0
  794.         PUSH    BX
  795.         MOV     BX,WORD PTR DS:OUTHANDLE ;BX = FILE HANDLE
  796.         MOV     DX,OFFSET BUFFER        ;DX = BUFFER OFFSET
  797.         MOV     AH,WRITE
  798.         INT     DOS                     ;WRITE BUFFER TO DEST
  799.         POP     BX
  800.         JC      WRERR                   ;IF ERROR
  801.         CMP     AX,CX                   ;WERE ALL BYTES WRITTEN?
  802.         JE      COPYLOOP                ;YES, KEEP GOING
  803.     ADDR    DX,DESTNAME        ;ERROR, POINT TO DEST NAME
  804.     CALL    ERRORMSG        ;SHOW IT
  805.         ERROR   10                      ;PROBABLY DISK FULL
  806.     MOV    AL,10
  807.         JMP     SHORT SCRATCH        ;ABORT
  808. WRERR:  ADDR    DX,DESTNAME        ;POINT TO DEST NAME
  809.     CALL    ERRORMSG        ;SHOW IT
  810.     ERROR   8                       ;WRITE ERROR
  811.     MOV    AL,8
  812.         JMP     SHORT SCRATCH        ;ABORT
  813. RDERR:  ADDR    DX,SRCNAME        ;POINT TO SOURCE NAME
  814.     CALL    ERRORMSG        ;SHOW IT
  815.     ERROR   9                       ;READ ERROR
  816.     MOV    AL,9
  817.         JMP     SHORT SCRATCH        ;ABORT
  818. ENDCOPY: PUSH   BX                      ;NO ERRORS
  819.         MOV     BX,WORD PTR DS:INHANDLE
  820.         MOV     AH,FILE_TIMES
  821.         MOV     AL,0                    ;GET FILE DATE AND TIME FOR SOURCE
  822.         INT     DOS
  823.         MOV     BX,WORD PTR DS:OUTHANDLE   ;GET OUTPUT FILE HANDLE
  824.         MOV     AH,FILE_TIMES
  825.         MOV     AL,1
  826.         INT     DOS                     ;SET OUTPUT DATE AND TIME SAME AS INPUT
  827.         MOV     BX,WORD PTR DS:INHANDLE
  828.         MOV     AH,DOS2_CLOSE
  829.         INT     DOS                     ;CLOSE INPUT FILE
  830.         MOV     BX,WORD PTR DS:OUTHANDLE
  831.         MOV     AH,DOS2_CLOSE
  832.         INT     DOS                     ;CLOSE OUTPUT FILE
  833.         POP     BX
  834.         RET
  835. SCRATCH:
  836.     PUSH    AX            ;SAVE ERROR CODE
  837.     ADDR    DX,DESTNAME        ;POINT TO DEST FILE
  838.     CALL    UNLINK2            ;REMOVE IT
  839.     CALL    CLOSE1            ;CLOSE INPUT FILE
  840.     POP    AX
  841.     STC                ;SIGNAL ERROR
  842.     RET
  843. COPY_FILE ENDP
  844.  
  845.         PAGE +
  846. ;*******************************************************************
  847. ;       THIS ROUTINE CHECKS TO SEE IF THE DEST FILE EXISTS.
  848. ;       IF IT DOES, AND IF THE CONFIRM FLAG IS SET, IT ASKS
  849. ;       FOR CONFIRMATION BEFORE DELETING THE FILE.  IF THE
  850. ;       CONFIRM FLAG IS NOT SET, IT JUST DELETES IT.
  851. ;       ON EXIT, 'C'=1 IF THE USER REPLIED 'N' TO THE CONFIRM MSG.
  852. ;
  853. GETOK   PROC    NEAR
  854.         ADDR    DX,DESTNAME
  855.         MOV     AL,0
  856.         MOV     AH,CHMOD
  857.         INT     DOS                     ;GET ATTRIBUTES FOR DEST
  858.         JNC     EXISTS                  ;IF FILE EXISTS
  859.         CLC
  860.         RET
  861. EXISTS:
  862.         CMP     BYTE PTR DS:IFLAG,TRUE  ;IS FLAG SET TO CONFIRM?
  863.         JNE     COK                     ;NO.
  864.         ADDR    DX,DESTNAME
  865.         CALL    ERRORMSG                ;SHOW DEST FILE
  866.         ERROR   4                       ;ASK FOR CONFIRMATION
  867.     CALL    GETYORN            ;GET Y OR N RESPONSE
  868.         CMP     AL,'Y'                  ;IS IT YES?
  869.         JNE     ABEXIT                  ;NO, SIGNAL CALLING ROUTINE
  870. COK:
  871. TRYAGAIN:
  872.         ADDR    DX,DESTNAME
  873.         MOV     AH,UNLINK
  874.         INT     DOS                     ;DELETE THE FILE
  875.         JNC     OKEXIT                  ;IF NO PROBLEM
  876.         CMP     AX,5                    ;WAS FILE R/O? (THIS OUGHT TO BE
  877.                                         ; THE ONLY POSSIBLE ERROR)
  878.         JNE     ABEXIT                  ;EXIT IF SOME OTHER ERROR
  879.     ADDR    DX,DESTNAME
  880.     CALL    ERRORMSG        ;SHOW DEST FILE NAME
  881.         ERROR   6                       ;R/O FILE, QUERY USER AGAIN
  882.     CALL    GETYORN            ;GET Y OR N RESPONSE
  883.         CMP     AL,'Y'                  ;TEST FOR 'Y' RESPONSE
  884.         JNE     ABEXIT                  ;ABORT IF USER SAYS 'N'
  885.         MOV     CX,0                    ;'Y' TYPED CLEAR ALL ATTRIBUTES
  886.         ADDR    DX,DESTNAME             ;POINT TO FILE NAME
  887.         MOV     AH,CHMOD
  888.         MOV     AL,1                    ;CHANGE ATTRIBUTES
  889.         INT     DOS                     ;TRY MAKING IT R/W
  890.         JMP     TRYAGAIN                ;TRY TO ERASE IT AGAIN
  891. ABEXIT: STC
  892.         RET
  893. OKEXIT: CLC
  894.         RET
  895. GETOK   ENDP
  896.  
  897. ; PRTERR = PRINT ERROR MESSAGE (DX POINTS TO OFFSET FROM DGROUP)
  898.  
  899. PRTERR:
  900.         PUSH    DS
  901.         MOV     AX,DGROUP
  902.         MOV     DS,AX
  903.         CALL    ERRORMSG
  904.         POP     DS
  905.     RET
  906.  
  907. CLOSE2:  MOV    BX,WORD PTR OUTHANDLE
  908.         MOV     AH,DOS2_CLOSE
  909.         INT     DOS                     ;CLOSE OUTPUT FILE
  910.     RET
  911. CLOSE1:
  912.         MOV     BX,WORD PTR INHANDLE
  913.         MOV     AH,DOS2_CLOSE
  914.         INT     DOS                     ;CLOSE INPUT FILE
  915.     RET
  916. EXIT2:
  917.         MOV     AH,EXIT
  918.         INT     DOS                     ;EXIT TO DOS
  919.  
  920.         END     ENTRY
  921.  
  922.