2 TITLE XCPYINIT
- XCOPY INITIALIZATION PROGRAM
- Ver
. 4.00
4 ;****************** START OF SPECIFICATIONS *****************************
5 ; MODULE NAME: XCPYINIT
7 ; DESCRIPTIVE NAME: Called by XCOPY(MAIN) to perform initialization
10 ; FUNCTION: Performs Parsing, Resource validation and Tagging, Error
11 ; hooking and then returns to XCOPY(MAIN). This code will
12 ; then be overwritten, providing additional memory for the
17 ; INPUT: (DOS COMMAND LINE PARAMETERS)
19 ; SOURCE OPERAND: TARGET OPERAND:
21 ; [d:] [path] filename[.ext] [d:] [path] [filename[.ext]]
23 ; [d:] path [filename[.ext]]
25 ; d: [path] [filename[.ext]]
29 ; /A /D /E /M /P /S /V /W
31 ; EXIT-NORMAL: ERRORLEVEL_0 - This is the normal completion code.
32 ; ERRORLEVEL_2 - This is due to termination via Control-Break.
33 ; ERRORLEVEL_4 - This is used to indicate an error condition.
35 ; INTERNAL REFERENCES:
42 ; EXTERNAL REFERENCES:
49 ; NOTES: This module should be processed with the SALUT pre-processor
50 ; with the re-alignment not requested, as:
54 ; To assemble these modules, the sequential
55 ; ordering of segments may be used.
57 ; For LINK instructions:
60 ; REVISION HISTORY: A000 Version 4.00: add PARSER, System Message Handler,
61 ; Remove the BELL char.,turn off APPEND during TREE
62 ; search,Extended Attribute processing, Uppercasing
63 ; and "Out Of Space" during write to standard out.
64 ; NOTE: SEE XCOPY.SAL FOR TOTAL HISTORY.
66 ; Label: "The DOS XCOPY Utility"
67 ; "Version 4.00 (C) Copyright 1988 Microsoft"
68 ; "Licensed Material - Program Property of Microsoft"
70 ;****************** END OF SPECIFICATIONS *****************************
77 CSEG
SEGMENT PUBLIC ;PLACE HOLDER FOR INIT CODE
80 ;******************************************************************************
82 DGROUP GROUP DSEG
, DSEG_INIT
83 DSEG
SEGMENT PARA
PUBLIC
84 ;--- EXTERNAL VARIABLES ---
86 EXTRN PSP_SEG
:WORD ;PSP segment ** USE OF ES SHOULD BE EXAMINED FURTHER
87 EXTRN SAV_DEFAULT_DRV
:BYTE ;1 = A, 2 = B ...
88 EXTRN SAV_DEFAULT_DIR
:BYTE
90 EXTRN SAV_S_CURDIR
:BYTE
92 EXTRN SAV_T_CURDIR
:BYTE
93 EXTRN TOP_OF_MEMORY
:WORD
94 EXTRN S_DRV_NUMBER
:BYTE ;source drive number, 1 = A, 2 = B ...
95 EXTRN T_DRV_NUMBER
:BYTE ;target drive number
96 EXTRN SO_DRIVE
:BYTE ;AN000;S DRIVE LETTER SPECIFIED IN PARSE
99 EXTRN S_DRV_PATH
:BYTE ;formal source drv, path
101 EXTRN T_DRV_PATH
:BYTE ;formal target drv, path
103 EXTRN TAR_DRIVE
:BYTE ;AN000;T DRIVE LETTER SPECIFIED IN PARSE
104 EXTRN PARMS
:DWORD ;AN000;PARSER PARAMETER CONTROL BLOCK
105 EXTRN CURRENT_PARM
:WORD ;AN004;POINTER TO NEXT CMD LINE OPERAND
106 EXTRN T_DRV
:BYTE ;target drv letter
107 EXTRN T_DRV_1
:BYTE ;target drv letter
109 EXTRN S_FILE
:BYTE ;source filename
110 EXTRN T_FILENAME
:BYTE
111 EXTRN T_TEMPLATE
:BYTE
112 EXTRN DISP_S_PATH
:BYTE ;input mirror image source path
113 EXTRN DISP_T_PATH
:BYTE ;input mirror image target path
114 EXTRN BUFFER_PTR
:WORD
115 EXTRN BUFFER_BASE
:WORD
116 EXTRN BUFFER_LEFT
:WORD
117 EXTRN MAX_BUFFER_SIZE
:WORD
119 EXTRN S_ARC_DRV
:BYTE ;source drv, path for archieve bit handling
120 EXTRN S_ARC_PATH
:BYTE
121 EXTRN T_MKDIR_LVL
:BYTE ;# of target starting directories created.
122 EXTRN MSG_NUM
:WORD ;AN000;MESSAGE NUMBER
123 EXTRN MSG_CLASS
:BYTE ;AN000;MESSAGE CLASS
124 EXTRN INPUT_FLAG
:BYTE ;AN000;TYPE INT21 USED FOR KBD INPUT
125 EXTRN SUBST_COUNT
:WORD ;AN000;MESSAGE SUBSTITUTION COUNT
126 EXTRN SUBLIST1
:DWORD ;AN000;MSG SUBLIST USED BY INIT & MAIN
130 EXTRN COPY_STATUS
:BYTE
131 EXTRN OPTION_FLAG
:BYTE
133 EXTRN INPUT_DATE
:WORD
134 EXTRN INPUT_TIME
:WORD
139 DSEG_INIT
SEGMENT PARA
PUBLIC ;AN000;
140 ;--- Local variables for INIT which will be free into memory after init.
141 ;----include file(s)------
142 INCLUDE XINITMSG
.EQU
;AN000;xcopy initialization, prompt msg
143 ;----variables------------
144 S_INPUT_PARM
DB 80 DUP (0) ;source image of input parm
145 T_INPUT_PARM
DB 80 DUP (0) ;target image of input parm
146 T_TRANS_PATH
DB 128 DUP (0) ;AN016;TARGET BUFFER FOR NAME TRANSLATE
147 S_TRANS_PATH
DB 128 DUP (0) ;AN016;SOURCE BUFFER FOR NAME TRANSLATE
151 ; first_parm_flag equ 01h ;first parm entered in input parm
152 ; second_parm_flag equ 02h ;second parm entered.
153 ; end_of_parm_flag equ 04h ;end of parm reached
154 ; copy_onto_itself_flag equ 08h ;copy onto itself flag
155 ; cyclic_flag equ 10h ;cyclic copy flag
156 ; inv_time_flag equ 20h ;invalid time
157 ; inv_date_flag equ 40h ;invalid date
158 ; init_error_flag equ 80h ;critical initialization error. Should abort.
161 ; inv_s_path_flag equ 01h ;invalid source path (path not found)
162 ; inv_t_path_flag equ 02h ;invalid target path
163 ; s_file_flag equ 04h ;source filename entered
164 ; t_file_flag equ 08h ;target filename entered
165 ; INV_SW_flag equ 10h ;AN004;DUPLICATE OR INVALID SW ENTERED
167 TEMP_T_FILENAME
DB 15 DUP (0) ;temporary target filename holder
168 FILENAME_FOR_PROMPT
DB 15 DUP (0) ;upper case lettered TEMP_T_FILENAME for prompts
169 ;** The following definitions are used for "Does ... specify a file name
170 ;** or directory name (F:file, D:directory)?.
171 ALPHA_FILE
DW ?
;AN000;THIS IS THE TRANSLATION OF 'F'
172 ALPHA_DIR
DW ?
;AN000;THIS IS THE TRANSLATION OF 'D'
173 USER_INPUT
DW ?
;AC000;KEYBOARD SAVE - MAY BE DBCS -
175 Maxdays db 31,28,31,30,31,30,31,31,30,31,30,31 ;Max days per month
179 Parmdate dw ?
;date parameter used in file date
181 COUNTRY_INFO
DB 34 DUP (0)
182 ;-------------------------------
184 ;-------------------------------
186 SUB_LIST
STRUC ;AN000;MSG RETRIEVER SUBSTITUTION LST
189 DATA_OFF
DW 0 ;AN000; offset of data to be inserted
190 DATA_SEG
DW 0 ;AN000; offset of data to be inserted
191 MSG_ID
DB 0 ;AN000; n of %n
192 FLAGS
DB 0 ;AN000; Flags
193 MAX_WIDTH
DB 0 ;AN000; Maximum field width
194 MIN_WIDTH
DB 0 ;AN000; Minimum field width
195 PAD_CHAR
DB 0 ;AN000; character for pad field
197 SUB_LIST ENDS
;AN000;
200 ;*******************************************************************************
202 CSEG
SEGMENT PUBLIC ;ATTACHED TO MAIN PROGRAM
203 ASSUME
CS:CSEG
, DS:DGROUP
, ES:DGROUP
205 ;--- PUBLIC PROCEDURES --- ;USED BY PARSER
206 PUBLIC GET_PARMS
;AN000;
207 ;---------------------------
209 ;--- EXTERNAL PROCEDURES ---
210 EXTRN SET_BUFFER_PTR
:NEAR
211 EXTRN STRING_LENGTH
:NEAR
212 EXTRN CONCAT_ASCIIZ
:NEAR
213 EXTRN LAST_DIR_OUT
:NEAR
214 EXTRN CHK_DBCS
:NEAR ;AN010;NEEDED TO PARSE THE PATH STRING
215 EXTRN COMPRESS_FILENAME
:NEAR
216 EXTRN CHK_DRV_LETTER
:NEAR
217 EXTRN SET_DEFAULT_DRV
:NEAR
218 EXTRN PRINT_STDOUT
:NEAR
219 EXTRN PRINT_STDERR
:NEAR
221 EXTRN MAIN_EXIT_A
:NEAR
222 EXTRN CTRL_BREAK_EXIT
:NEAR
223 EXTRN PARSER
:NEAR ;AN000;PROCESS THE KBD INPUT STRING
224 EXTRN SYSGETMSG
:NEAR ;AN000;TO GET THE 'F'ILE or 'D'IRECTORY
227 EXTRN SAV_INT24_OFF
:WORD ;int 24, critical error handler addr.
228 EXTRN SAV_INT24_SEG
:WORD
230 ;--- PARSER REFERENCES ---
232 EXTRN RESULT1
:BYTE ;AN000;
233 EXTRN RESULT_PTR1
:DWORD ;AN000;
234 EXTRN TYPE1
:BYTE ;AN000;
235 EXTRN RESULT2
:BYTE ;AN000;
236 EXTRN RESULT_PTR2
:DWORD ;AN000;
237 EXTRN TYPE2
:BYTE ;AN000;
238 EXTRN RESULTSW1
:BYTE ;AN000;
239 EXTRN RESULTSWSYN
:WORD ;AN000;
240 EXTRN SW_A
:BYTE ;AN000;
241 EXTRN SW_E
:BYTE ;AN000;
242 EXTRN SW_M
:BYTE ;AN000;
243 EXTRN SW_P
:BYTE ;AN000;
244 EXTRN SW_S
:BYTE ;AN000;
245 EXTRN SW_V
:BYTE ;AN000;
246 EXTRN SW_W
:BYTE ;AN000;
247 EXTRN SW_D
:BYTE ;AN000;
248 EXTRN DATE_YEAR
:WORD ;AN000;
249 EXTRN DATE_MONTH
:BYTE ;AN000;
250 EXTRN DATE_DAY
:BYTE ;AN000;
255 CMP AX, 0 ;check drv validity
258 MOV DX, MSG_INVALID_DRV
;AC000;GET THE MESSAGE ID
259 OR PARM_FLAG
, INIT_ERROR_FLAG
;critical error. Abort
263 CALL HOOK_CTRL_BREAK
;hooks control break
264 CALL SAV_HOOK_INT24
;hooks critical err handler
265 CALL GET_CUR_DRV
;save current default drv
266 MOV DL, SAV_DEFAULT_DRV
267 LEA SI, SAV_DEFAULT_DIR
268 CALL GET_CUR_DIR
;save current default dir
269 CALL PARSE_INPUT_PARM
270 TEST PARM_FLAG
, INIT_ERROR_FLAG
273 CALL TOP_OF_MEM
;set top_of_memory
274 CALL INIT_BUFFER
;init buffer information
278 CALL SET_DEFAULT_DRV
;set source as a default drv
283 TEST PARM_FLAG
, INIT_ERROR_FLAG
;any error?
284 ; $IF NZ ;yes. critical error
286 CMP DX,MSG_INV_SW
;AN004;MSG REQUIRES SUB LIST
287 ; $IF NE,AND ;AC023;NO SUBLIST REQUIRED
289 CMP DX,MSG_INVALID_PARM
;AN004;MSG REQUIRES SUB LIST
290 ; $IF NE,AND ;AC023;NO SUBLIST REQUIRED
292 CMP DX,MSG_INV_NUM_PARM
;AN004;MSG REQUIRES SUB LIST
293 ; $IF NE ;AC023;NO SUBLIST REQUIRED
295 MOV SUBST_COUNT
,NO_SUBST
;AN000;NO SUBSTITUTION TEXT
296 CMP DX,SYSPRM_MISSING_OP
;AN024;OPERANDS MISSING(2) ERR?
299 MOV DX,MSG_INV_NUM_PARM
;AN024;NO SUBLIST REQUIRED
302 MOV MSG_NUM
,DX ;AN000;NEED MESSAGE ID FOR PRINT
303 ; $ELSE ;AN004;SUBST LIST REQUIRED
306 MOV MSG_NUM
,DX ;AN004;NEED MESSAGE ID FOR PRINT
307 MOV SUBST_COUNT
,PARM_SUBST_ONE
;AN004;PARM SUBST COUNT=1
309 MOV DX,CURRENT_PARM
;AN004;OFFSET TO BAD SWITCH
310 LEA SI,SUBLIST1
;AN004; address to sublist
311 MOV [SI].DATA_OFF
,DX ;AN004; save data offset
312 MOV [SI].DATA_SEG
,DS ;AN004; save data segment
313 MOV [SI].MSG_ID
,0 ;AN023; message ID
314 MOV [SI].FLAGS
,010H ;AN004; ASCIIZ str,l align
315 MOV [SI].MAX_WIDTH
,0 ;AN004; MAXIMUM FIELD WITH
316 MOV [SI].MIN_WIDTH
,0 ;AN004; MINIMUM FIELD WITH
319 MOV INPUT_FLAG
,NO_INPUT
;AN000;NO INPUT = 0
320 MOV MSG_CLASS
,UTILITY_MSG_CLASS
;AN000;MESSAGE CLASS = -1
321 CALL PRINT_STDERR
;AN000;print error. AX point to msg ID
322 MOV ERRORLEVEL
, 4 ;error ending
323 STC ;set carry and exit to the main_exit
334 PARSE_INPUT_PARM PROC
NEAR
336 CALL PARSER
;AN000;the PARSER interface routine
337 ; $IF C ;AC000;if no non_delimiter chr?
339 TEST PARM_FLAG
,INIT_ERROR_FLAG
;AN000;PARM ERR HAS OCCURRED
340 ; $IF Z ;AN000;NO, MUST BE PARSER ERROR
342 OR PARM_FLAG
,INIT_ERROR_FLAG
;AN000;SET THE FLAG
343 CMP AX,SYSPRM_EX_MANY
;AN000;TOO MANY OPERANDS (1) ERR?
346 MOV BYTE PTR [SI],NUL
;AN024;DELIMIT BAD PARM
347 MOV DX,MSG_INV_NUM_PARM
;AN000;MSG NUM = 21
351 CMP AX,SYSPRM_DUP_SW
;AN004;DUPLICATE SW REQUESTED
354 MOV BYTE PTR [SI],NUL
;AN004;DELIMIT BAD PARM
355 MOV DX,MSG_INV_SW
;AN004;MSG NUM = 35
359 CMP AX,SYSPRM_MISSING_OP
;AN006;MISSING PARM=2
362 MOV DX,AX ;AN024 ;MSG NUM=21-NO SUBLIST
366 MOV BYTE PTR [SI],NUL
;AN024;DELIMIT BAD PARM
367 MOV DX,MSG_INVALID_PARM
;AN000;MSG NUM = 3
374 ; $ELSE ;AN006;INIT_ERROR_FLAG ALSO SET
377 TEST PARM_FLAG
,INV_DATE_FLAG
;AN006;WAS DATE INVALID?
378 ; $IF NZ ;AN006;THE DATE IS INVALID
380 MOV DX,MSG_INVALID_DATE
;AN006;MSG NUM = 9
388 CALL GET_DRIVES
;get source, target drive
389 TEST PARM_FLAG
, INIT_ERROR_FLAG
;critical syntax error?
392 CALL CHK_SLASH_W
;with /w, show "Press any key to begin ... " msg.
393 call save_for_display
;save source, target parm for display purposes
394 CALL CHK_SET_PARMS
;check and set each parms.
395 TEST PARM_FLAG
, INIT_ERROR_FLAG
;critical syntax error?
398 call modify_for_display
;set the source, target parm for display
407 CALL STRING_LENGTH
;cx - # of chr
410 REP MOVSB ;s_path => s_arc_path
412 PARSE_INPUT_PARM ENDP
415 CHK_SLASH_W PROC
NEAR
416 ;if /W option is specified, then
417 ;show "Press any key to begin copying file(z)" message and wait for a key stroke.
420 TEST OPTION_FLAG
, SLASH_W
;/W option taken?
424 MOV AX, MSG_TO_BEGIN
;AC000;GET THE MESSAGE ID
425 MOV MSG_NUM
,AX ;AN000;SET THE MESSAGE NUMBER
426 MOV SUBST_COUNT
,NO_SUBST
;AN000;NO SUBSTITUTION TEXT
427 MOV INPUT_FLAG
,DOS_KEYB_INP
;AN000;RESPONSE EXPECTED = 1
428 MOV MSG_CLASS
,UTILITY_MSG_CLASS
;AN000;MESSAGE CLASS = -1
429 CALL PRINT_STDOUT
;AN000;MSG AX points to message ID
431 MOV AX,MSG_CR_LF_STR
;AN000; JUST CR,LF
432 MOV MSG_NUM
,AX ;AN000; set message number
433 MOV INPUT_FLAG
,NO_INPUT
;AN000; NO INPUT
434 CALL PRINT_STDOUT
;AN000; Display message
443 PROMPT_TO_USER PROC
NEAR
444 ;guide the user to enter the input parameters
445 ;get user input to S_INPUT_PARM, T_INPUT_PARM for source, target parms.
450 MOV dx, msg_inv_num_parm
;AC000;GET THE MESSAGE ID
451 or parm_flag
, init_error_flag
456 ;Get the first parameter(s), second parameter(s) and option(s).
457 ;Not checking correct character entered.
459 ;1). Find the first non_delim from the Parser control block. This is the
460 ; start of the first parm. Validate the length and put into S_INPUT_PARM.
461 ; Note that this routine currently does not check the S_INPUT_PARM to see
462 ; if it is valid or not.
463 ;2). Find the next non_delim from the Parser control block. This is the
464 ; start of the second parm. Validate the length and put into T_INPUT_PARM.
465 ; Note that this routine currently does not check the T_INPUT_PARM to see
466 ; if it is valid or not.
467 ;3). Find the switch(es) from the parser control block and set the
468 ; corresponding bit in the option flag word(OPTION_FLAG) by calling
472 ; BX - PARSER OPERAND POINTER
475 CMP BX,OFFSET DGROUP
:RESULT1
;AN000;WAS FIRST FILESPEC SPECIFIED?
476 ; $IF E ;AN000;IF FIRST FILESPEC SPECIFIED,
478 LDS SI,RESULT_PTR1
;AN000;GET WHERE THE STRING IS
479 ASSUME
DS:NOTHING
;AN000;
480 CMP DS:BYTE PTR [SI]+BYTE,COLON
;AN000;DOES FILESPEC START WITH
482 ; $IF E ;AN000;STARTS WITH DRIVE
484 LODSW ;AN000;GET JUST THE DRIVE LETTER AND
485 MOV ES:SO_DRIVE
,AL ;AN000;ALSO ADJUSTS WHERE THE STRING IS
486 LEA DI,ES:S_INPUT_PARM
;AN000;MOVE PARM TO SOURCE FILESPEC
487 STOSW ;AN000;MOVE DRIVE TO FILESPEC
488 ; $ELSE ;AN000;DOES NOT START WITH DRIVE
491 LEA DI,ES:S_INPUT_PARM
;AN000;MOVE PARM TO SOURCE FILESPEC
492 ; $ENDIF ;AN000;FILESPEC HAVE DRIVE?
494 CMP DGROUP
:TYPE1
,5 ;AN000;FILESPEC ?
495 ; $IF E ;AN000;MORE THAN JUST DRIVE
497 ;MOVE PARM TO WHERE FIND FIRST/NEXT
498 ; WILL KNOW WHERE TO START
499 PUSH BX ;AN000;SAVE THE DATABASE POINTER
500 XOR BX,BX ;AN000;ZERO FOR THE PARAMETER LENGTH
501 ; $DO COMPLEX ;AN000;
504 INC BX ;AN000;CALCULATE LENGTH
505 STOSB ;AN000;MOVE CHAR TO FILESPEC
508 LODSB ;AN000;GET NEXT CHAR FROM COMMAND LINE
509 CMP AL,NUL
;AN000;IS THAT THE END OF THE STRING
510 ; $ENDDO E ;AN000;GOT IT ALL, QUIT
512 CALL CHK_MAX_LENGTH
;AN000;LENGTH OF STRING <=64
513 POP BX ;AN000;RESTORE THE DATA BASE POINTER
514 ; $IF NC ;no, less than or equal
516 OR PARM_FLAG
, FIRST_PARM_FLAG
520 MOV DX, MSG_LONG_PATH
;AN000;ADDRESS OF MESSAGE TXT
521 OR PARM_FLAG
, INIT_ERROR_FLAG
;AN000;
522 ; $ENDIF ;AN000;CRITICAL ERROR INDICATED
524 ; $ENDIF ;AN000;MOVE ALL DONE
526 ; $ELSE ;AN000;IF SECOND FILESPEC SPECIFIED,
529 CMP BX,OFFSET DGROUP
:RESULT2
;AN000;WAS 2nd FILESPEC SPECIFIED?
530 ; $IF E ;AN000;IF SECOND FILESPEC SPECIFIED
532 LDS SI,RESULT_PTR2
;AN000;GET WHERE THE STRING IS
533 ASSUME
DS:NOTHING
;AN000;
534 CMP DS:BYTE PTR [SI]+BYTE,COLON
;AN000;DOES FILESPEC START
536 ; $IF E ;AN000;STARTS WITH DRIVE
538 LODSW ;AN000;GET JUST THE DRIVE LETTER AND
539 MOV ES:TAR_DRIVE
,AL ;AN000;ALSO ADJUSTS WHERE THE STRING IS
540 LEA DI,ES:T_INPUT_PARM
;AN000;MOVE PARM TO TARGET FILESPEC
541 STOSW ;AN000;MOVE DRIVE TO FILESPEC
542 ; $ELSE ;AN000;DOES NOT START WITH DRIVE
545 LEA DI,ES:T_INPUT_PARM
;AN000;MOVE PARM TO TARGET FILESPEC
546 ; $ENDIF ;AN000;FILESPEC HAVE DRIVE?
548 CMP DGROUP
:TYPE2
,5 ;AN000;FILESPEC ?
549 ; $IF E ;AN000;MORE THAN JUST DRIVE
551 ;AN000;MOVE PARM TO WHERE FIND FIRST/NEXT
552 ;AN000; WILL KNOW WHERE TO START
553 PUSH BX ;AN000;SAVE THE DATABASE POINTER
554 XOR BX,BX ;AN000;ZERO FOR THE PARAMETER LENGTH
555 ; $DO COMPLEX ;AN000;
558 INC BX ;AN000;CALCULATE LENGTH
559 STOSB ;AN000;MOVE CHAR TO FILESPEC
562 LODSB ;AN000;GET NEXT CHAR FROM COMMAND LINE
563 CMP AL,NUL
;AN000;IS THAT THE END OF THE STRING
564 ; $ENDDO E ;AN000;GOT IT ALL, QUIT
566 CALL CHK_MAX_LENGTH
;AN000;LENGTH OF STRING <=64
567 POP BX ;AN000;RESTORE THE DATA BASE POINTER
570 OR PARM_FLAG
, SECOND_PARM_FLAG
574 MOV DX, MSG_LONG_PATH
;AN000;ADDRESS OF MESSAGE TXT
575 OR PARM_FLAG
, INIT_ERROR_FLAG
;AN000;
576 ; $ENDIF ;AN000;CRITICAL ERROR INDICATED
578 ; $ENDIF ;AN000;SECOND FILESPEC
580 ; $ELSE ;AN000;FILESPEC NOT SPECIFIED
583 CALL GET_OPTIONS
;AN000;PROCESS THE SWITCHES
584 ; $ENDIF ;AN000;MOVE ALL DONE
586 ; $ENDIF ;AN000;FILESPEC?
589 ASSUME
DS:DGROUP
;AN000;
593 SAVE_FOR_DISPLAY PROC
NEAR
594 ;save first parm, second parm into DISP_S_PATH, DISP_T_PATH.
595 ;at this time, this is not gauranteed to be a path. They may
596 ;contains filename in it.
597 ;input: S_INPUT_PARM, T_INPUT_PARM, PARM_FLAG
604 TEST PARM_FLAG
, FIRST_PARM_FLAG
;first parm entered?
609 CALL STRING_LENGTH
;now CX has length
611 LEA DI, DISP_S_PATH
;source path for display
612 CALL MOV_STRING
;AC000;s_input_parm => disp_s_path
616 TEST PARM_FLAG
, SECOND_PARM_FLAG
;second parm entered?
624 CALL MOV_STRING
;AC000;s_input_parm => disp_s_path
629 SAVE_FOR_DISPLAY ENDP
631 MOV_STRING PROC
NEAR ;AN000;
632 ; move string from DS:SI to ES:DI
633 ; CX should indicate string length
647 MOV_STRING ENDP
;AN000;
649 MODIFY_FOR_DISPLAY PROC
NEAR
650 ;finally trims DISP_S_PATH, DISP_T_PATH into good shape.
651 ;input: DS, ES = data seg. S_FILE_FLAG, T_FILE_FLAG
655 TEST PARM1_FLAG
, S_FILE_FLAG
;source filename entered?
657 CALL MASSAGE_DISP_PATH
;yes, entered.
659 MFD_NO_FILE1: ;no source filename
660 CALL CHK_DRV_LETTER
;using [si]
662 CMP BYTE PTR [SI], 0 ;D:,0 case
664 CMP BYTE PTR [SI], '\'
665 JNE MFD_CHK_TAIL1 ;D:dir... case
666 CMP BYTE PTR [SI+1], 0 ;D:\,0 case
668 MFD_CHK_TAIL1: ;else check tail
669 CALL CHK_TAIL_CHR ;chk tail and put \ at the end. using di
673 TEST PARM1_FLAG, T_FILE_FLAG
675 CALL MASSAGE_DISP_PATH
682 CMP BYTE PTR [SI], '\'
684 CMP BYTE PTR [SI+1], 0
690 MODIFY_FOR_DISPLAY ENDP
692 CHK_TAIL_CHR PROC
NEAR
693 ;check the last chr of ASCIIZ string pointed by DI.
694 ;if it is \,0 then OK, else put \ there.
696 ;DI points to string.
697 ;OUTPUT: Revised string.
698 ;AX, BX, CX - destroyed
701 CALL STRING_LENGTH
;now cx got the length including 0
706 CMP BYTE PTR [DI][BX], '\' ;last chr before 0
707 JE CTC_EXIT ;\,0 case
708 MOV BYTE PTR [DI][BX+1], '\' ;change 0 to '\'
709 MOV BYTE PTR [DI][BX+2], 0 ;make it asciiz again.
714 MASSAGE_DISP_PATH PROC
NEAR
715 ;INPUT: DS, ES = data seg
716 ; DI = points to source. Used for LAST_DIR_OUT
717 ; SI = points to source. Used for CHK_DRV_LETTER routine
718 ;OUTPUT: Revised source string
721 ; $IF C ;failure? no '\' found
723 CALL CHK_DRV_LETTER
;drive letter?
724 ; $IF NC ;yes. "D:filename",0 case
726 MOV BYTE PTR DS:[SI], 0 ;make it "D:",0 since SI now points to the next chr
727 ; $ELSE ;no. "filename",0 case
730 MOV BYTE PTR [DI], 0 ;set DISP_S_PATH to 0
733 ; $ELSE ;found '\' and last '\' became 0
736 MOV DI, AX ;we want to restore '\' and put 0 just after that.
737 DEC DI ;for ex, "D:\filename"=>"D:"=>"D:\"
738 MOV BYTE PTR [DI], '\' ; "D:dir1\dir2"=>"D:dir1"=>"D:dir1\"
739 MOV BYTE PTR [DI+1], 0
743 MASSAGE_DISP_PATH ENDP
745 CHK_MAX_LENGTH PROC NEAR
746 ;Check the length of the source or target input string although this does not
747 ;gaurantee the validity of the length of path. This will just check/reduce
748 ;the possibilities of long path.
749 ;If the path string is longer than 64 (this includes 0 at the end of the string)
750 ;then, carry will be set.
751 ;INPUT: ds - data seg
753 ; SI - points to the starting chr of the string.
754 ; BX - length of the string
756 ; carry will set if the length if longer than we expected.
761 ;AC001;DELETED CODE FOR PTM0011
762 CMP BYTE PTR [SI], '\' ;SI points to '\'?
763 JNE CML_LENGTH
;no, now compare the length
764 DEC BX ;AC000;decrease length by 1 for '\'
766 CMP BX, 63 ;AC000;length of string > 63?
767 JG CML_CARRY
;AC027;WORK WITH ONLY + CMP RESULT
781 GET_OPTIONS PROC
NEAR
782 ;get options from the PARSER and
785 ; BX - PARSER OPERAND POINTER
787 CMP BX,OFFSET DGROUP
:RESULTSW1
;AN000;WAS SW 1 THROUGH 7 SPECIFIED?
788 MOV DI,RESULTSWSYN
;AN000;GET THE SYNONYM POINTER [ES]
790 ; $IF E,LONG ;AN000;IF SWITCH SPECIFIED
794 CMP BYTE PTR ES:[DI+BYTE],ALPHA_S
;AC000;"S"
796 OR OPTION_FLAG
, SLASH_S
;set the walk the tree bit on.
797 MOV SW_S
,SPACE
;AN004;DISALLOW DUPLICATE SWITCHES
800 CMP BYTE PTR ES:[DI+BYTE],ALPHA_A
;AN000;"A"
802 MOV SW_A
,SPACE
;AN004;DISALLOW DUPLICATE SWITCHES
803 TEST OPTION_FLAG
, SLASH_M
;hard archieve already on?
804 JZ GO_A1
;if not, continue
805 AND OPTION_FLAG
, RESET_SLASH_M
;else turn it off
807 OR OPTION_FLAG
, SLASH_A
;set soft archieve
810 CMP BYTE PTR ES:[DI+BYTE],ALPHA_M
;AN000;"M"
812 MOV SW_M
,SPACE
;AN004;DISALLOW DUPLICATE SWITCHES
813 TEST OPTION_FLAG
, SLASH_A
;soft archieve already on?
814 JZ GO_M1
;if not, skip this part
815 AND OPTION_FLAG
, RESET_SLASH_A
;else turn off the soft archieve bit
817 OR OPTION_FLAG
, SLASH_M
;turn on the hard archieve bit.
820 CMP BYTE PTR ES:[DI+BYTE],ALPHA_P
;AN000;"P"
822 MOV SW_P
,SPACE
;AN004;DISALLOW DUPLICATE SWITCHES
823 OR OPTION_FLAG
, SLASH_P
824 OR MY_FLAG
, SINGLE_COPY_FLAG
;if user want prompt, then should be single copy (not a multi copy).
825 JMP SHORT GO_EXIT
;AC000;
827 CMP BYTE PTR ES:[DI+BYTE],ALPHA_E
;AN000;"E"
829 MOV SW_E
,SPACE
;AN004;DISALLOW DUPLICATE SWITCHES
830 OR OPTION_FLAG
, SLASH_E
;turn on "creating empty dir" bit.
831 JMP SHORT GO_EXIT
;AC000;
833 CMP BYTE PTR ES:[DI+BYTE],ALPHA_V
;AN000;"V"
835 MOV SW_V
,SPACE
;AN004;DISALLOW DUPLICATE SWITCHES
836 MOV AH, 54h
;get verify setting
839 JNE GO_EXIT
;AC000;if not 0, then already on.
840 MOV AX, 2E01h
;else set it on
842 OR SYS_FLAG
, TURN_VERIFY_OFF_FLAG
;don't forget it off when exit to dos.
843 JMP SHORT GO_EXIT
;AC000;
845 OR OPTION_FLAG
, SLASH_W
846 MOV SW_W
,SPACE
;AN004;DISALLOW DUPLICATE SWITCHES
847 JMP SHORT GO_EXIT
;AC000;
848 ; $ELSE ;AN000;SINCE SWITCH 1 - 7 NOT SPECIFIED
851 ; IT MUST BE THE DATE SWITCH
852 CALL GET_INPUT_DATE
;AN000;get date from parser control block
853 OR OPTION_FLAG
, SLASH_D
854 MOV SW_D
,SPACE
;AN004;DISALLOW DUPLICATE SWITCHES
861 GET_INPUT_DATE PROC
NEAR
862 ;get the input date from the parser and save it to INPUT_DATE form which
863 ;it can be used for comparison with FILE_DATE_DTA.
872 CALL VALIDATE_INPUT_DATE
;AN006;GO CHECK THE DATE
873 ; $IF C ;AN006;SET IF THE DATE WAS INVALID
875 OR PARM_FLAG
,INV_DATE_FLAG
;AN006;SET THE FLAG FOR DATE ERROR
876 OR PARM_FLAG
,INIT_ERROR_FLAG
;AN006;SET THE FLAG FOR ERROR
877 ; $ELSE ;AN006;DATE WAS OK
880 MOV AX,DATE_YEAR
;AN000;GET YEAR FROM PARSER CTRL BLOCK
881 SUB AX,1980 ;AN000;SUBTRACT THE BASE YEAR
882 mov cl,4 ;AN000;SHIFT REG COUNT = 4
883 shl ax,cl ;AN000;Shift it over 4
884 xor dh,dh ;AN000;CLEAR THE AREA
885 mov dl,DATE_MONTH
;AN000;GET MONTH FROM PARSER CTRL BLOCK
886 add ax,dx ;AN000;Add in the Month
887 inc cl ;AN000;BUMP SHIFT COUNT
888 shl ax,cl ;AN000;Shift it over 5
889 xor dh,dh ;AN000;CLEAR THE AREA
890 mov dl,DATE_DAY
;AN000;GET DAY FROM PARSER CTRL BLOCK
891 add ax,dx ;AN000;Add in the Day
892 mov INPUT_DATE
,ax ;AN000;Store the date in DOS FCB format
893 CLC ;AN000;CLEAR THE CARRY
899 VALIDATE_INPUT_DATE PROC
NEAR
900 ;CHECK FOR VALID DATE.
902 ;OUTPUT: INVALID DATE = CARRY SET
907 MOV AH,GET_DATE
;AN006;DOS INT 2AH
908 INT 21H
;AN006;MAKE THE CALL
910 PUSH DX ;AN006;MONTH,DAY
911 MOV AH,SET_DATE
;AN006;DOS INT 2BH
912 MOV CX,DATE_YEAR
;AN006;GET YEAR FROM PARSER CTL BLOCK
913 MOV DH,DATE_MONTH
;AN006;GET MONTH FROM PARSER CTL BLOCK
914 MOV DL,DATE_DAY
;AN006;GET DAY FROM PARSER CTL BLOCK
915 INT 21H
;AN006;MAKE THE CALL
916 POP DX ;AN006;GET THE SYSTEM MONTH,DAY
917 POP CX ;AN006;GET THE SYSTEM YEAR
918 OR AL,AL ;AN006;WAS MY INPUT DATE VALID?
919 STC ;AN006;SET THE CARRY
920 JNZ ERR_DATE
;AN006;GET OUT WITH C SET
921 CLC ;AN006;CLEAR THE CARRY, NO ERROR
922 MOV AH,SET_DATE
;AN006;RESTORE THE SYSTEM DATE
923 INT 21H
;AN006;MAKE THE CALL
927 VALIDATE_INPUT_DATE ENDP
929 CHK_SET_PARMS PROC
NEAR
930 ;This does a semantic checking on the given S_INPUT_PARM, T_INPUT_PARM and
931 ;sets each of the starting drv path into S_PATH, T_PATH.
933 ;1). Try to change dir to a given S_INPUT_PARM.
934 ; if a success, then it must be the path. Chdir to it and get current
935 ; source directory using S_DRV_NUMBER by issuing GET_Current_directory call,
936 ; which starts from the root of the source drive. In this way, you don't
937 ; have to worry about what type of path for the source has been entered.
938 ; You just try to chdir according to S_INPUT_PARM and
939 ; then call get_cur_dir to get the S_PATH which will always start
940 ; from the root of the source drive.
941 ; if not, then there must be the filename at the end, or there might be
942 ; garbage in the path. So, take the last path name (which is, hopely,
943 ; a filename) and try chdir again. If a success, then current source dir
944 ; is determined. Otherwise, error. Issue "Invalid direcory name". If a
945 ; success, then check the saved filename to make sure that there are no
946 ; invalid chr's in it. (When you try to take the last_dir_out, and
947 ; it has failed (carry set), then it was a filename candidate itself
948 ; (sometimes together with an drive id d:). In this case, you have to
949 ; check the filename candidate if it has a drive id in front of it.
950 ; if it is, then take the drive id d: off from it and reshape the
951 ; filename candidate. And check the invalid characters if any. Of cause
952 ; in this case, current direcory of source drv becomes S_PATH.
953 ;2). Try to change dir to a given T_INPUT_PARM, if any. (If no T_INPUT_PARM
954 ; entered, then set current directory to the starting path of target using
956 ; If a success, then no problem. It is a strating target path.
957 ; If not, then take the last dir out and try again. If a failure, then
958 ; error "Invalid directory".
959 ; If a success, then check the saved filename to see if any illigal
960 ; characters in it. If they are, then error. Else issue fun.29h
961 ; to see if there are any global characters in it. If there
962 ; are, then assume a filename. If there are not, then ask user
963 ; "Is XXXXX a filename in the target? (n)" If no, then it is a
964 ; subdirectory name. Make a new subdirectory in the target and
965 ; concatenate a new directory name to the T_INPUT_PARM and chdir to
966 ; the new path (, which is the original path in fact) again.
968 ; ES - PSP seg ; this will be changed to DS within this routine
973 TEST PARM_FLAG
, FIRST_PARM_FLAG
;first parm entered?
976 TEST PARM_FLAG
, SECOND_PARM_FLAG
;second parm entered?
979 MOV DX, MSG_INV_NUM_PARM
;AC000;GET THE MESSAGE ID
980 OR PARM_FLAG
, INIT_ERROR_FLAG
;critical error. exit program
987 CALL GET_CUR_DIR
;get and save current source directory
988 OR SYS_FLAG
, DEFAULT_S_DIR_FLAG
;indicates source dir saved
989 TEST PARM_FLAG
, FIRST_PARM_FLAG
;first parm only entered?
990 ; $IF Z ;no first parm
992 LEA SI, S_PATH
;then make current source dir as S_PATH
994 ; $ELSE ;else first parm entered. check it
997 LEA DX, S_INPUT_PARM
;try to chdir to S_INPUT_PARM
1002 MOV DL, S_DRV_NUMBER
1003 LEA SI, S_PATH
;get current dir and save it
1004 CALL GET_CUR_DIR
;as a starting dir to S_PATH
1008 LEA BX, S_INPUT_PARM
1009 LEA DX, S_FILE
;source filename
1010 CALL TAKE_PATH_TAIL
;take out the tail part of S_INPUT_PARM
1011 LEA DX, S_INPUT_PARM
1012 MOV AH, Chdir
;= 3Bh
1013 INT 21h
;try chdir again
1014 ; $IF NC,AND ;success?
1016 CMP S_FILE
, 0 ;check s_file if something is there
1017 ; $IF NE ;yes, filename entered.
1019 MOV DL, S_DRV_NUMBER
1021 CALL GET_CUR_DIR
;save current dir
1022 OR PARM1_FLAG
, S_FILE_FLAG
;source filename entered
1023 call chk_s_reserved_name
;is it a reserved name?
1027 MOV DX, MSG_INVALID_PATH
;AC000;GET THE MESSAGE ID
1028 OR PARM_FLAG
, INIT_ERROR_FLAG
;critical error
1037 TEST PARM_FLAG
, INIT_ERROR_FLAG
1038 ; $IF Z,LONG ;no error so far,
1042 TEST SYS_FLAG
, ONE_DISK_COPY_FLAG
;if one disk copy
1043 ; $IF NZ ;then saved source default directory
1045 LEA DX, SAV_S_DRV
;is the same as target current dir
1047 INT 21h
;so restore target default dir.
1050 MOV DL, T_DRV_NUMBER
1051 LEA SI, SAV_T_CURDIR
1052 CALL GET_CUR_DIR
;save current target directory
1053 OR SYS_FLAG
, DEFAULT_T_DIR_FLAG
;indicates target dir saved
1054 TEST PARM_FLAG
, SECOND_PARM_FLAG
;second parm has been entered?
1055 ; $IF Z ;second parm not entered
1058 CALL GET_CUR_DIR
;make the current target dir as T_PATH
1059 ; $ELSE ;then deals with the second parm
1063 LEA DX, T_INPUT_PARM
;try to chdir according to T_INPUT
1068 CALL PARSE_SECOND_PARM
1072 TEST PARM_FLAG
, INIT_ERROR_FLAG
;no error so far?
1075 MOV DL, T_DRV_NUMBER
1077 CALL GET_CUR_DIR
;save target starting dir
1078 CMP TEMP_T_FILENAME
, 0 ;any non_global target file name entered?
1081 MOV CX, 13 ;maximum 13 char.
1082 LEA SI, TEMP_T_FILENAME
1083 LEA DI, T_FILENAME
;then move it to T_FILENAME while convert it to capital letter.
1084 CALL MOV_STRING
;AC000; SI => DI
1087 ; $ENDIF ;end - no error so far
1089 ; $ENDIF ;end - second parm not entered
1094 TEST PARM_FLAG
, INIT_ERROR_FLAG
1097 CALL CHK_CYCLIC_COPY
;check source, target parms
1098 TEST PARM_FLAG
, INIT_ERROR_FLAG
;cyclic copy?
1101 TEST SYS_FLAG
, ONE_DISK_COPY_FLAG
;if one disk drv letter copy
1102 ; $IF NZ ;then set the starting dir
1104 LEA DX, S_DRV_PATH
;to that of source.
1105 MOV AH, Chdir
; = 3Bh
1106 INT 21H
;should succeed since alreay tested.
1115 PARSE_SECOND_PARM PROC
NEAR
1116 ;called after the initial chdir to T_INPUT_PARM failed. Remember the second parm should
1117 ;exist when you call this routine.
1118 ;INPUT: DS, ES - data seg
1119 ;OUTPUT:if error, init_error_flag will be set.
1121 LEA SI, T_INPUT_PARM
1122 CALL CHK_HEAD_PARM
;check the head part of parm. SI will points
1123 ;to the next chr after the header.
1124 TEST PARM_FLAG
, INIT_ERROR_FLAG
1125 JNZ PSP_EXIT
;YES, ERROR.
1126 CALL NEXT_PATH_DELIM
;Let SI points to the next path delim "\" or 0
1127 LEA DX, T_INPUT_PARM
1128 CALL PARSING_T_PATH
;chdir for every directory starting from the
1129 ;first. If it fails, then create a directory
1133 PARSE_SECOND_PARM ENDP
1135 NEXT_PATH_DELIM PROC
NEAR
1136 ;starting from SI, check every chr until it is '\' or 0 or ':'.
1137 ;if the starting chr is '\' or 0 or ':', then SI won't change.
1138 ;the caller should be sure that it is an ASCIIZ string.
1139 ;INPUT: DS, ES - data seg
1140 ; SI - starting point
1142 ; SI - next path delimeter
1147 POP DI ;NOW DI POINTS TO THE STARTING CHR
1151 CLC ;AN010;INITIALIZE TO NOT DBCS
1152 MOV AL,BYTE PTR [DI] ;AN010;GET THE 1st CHAR TO TEST
1153 CALL CHK_DBCS
;AN010;SEE IF WE ARE IN DBCS
1154 ; $LEAVE NC ;AN010;THIS IS NOT DBCS
1156 INC DI ;AN010;GO TO THE NEXT CHAR TO CHECK
1162 SCASB ;0 - ES:[DI], DI=DI+1
1164 DEC DI ;check it again if it is '\'
1169 MOV AL, ':' ;is it a filename terminator not filter before?
1174 DEC DI ;adjust DI to the chr found
1176 POP SI ;now SI points to the chr
1179 NEXT_PATH_DELIM ENDP
1182 CHK_HEAD_PARM PROC NEAR
1183 ;check the starting header part of parameter pointed by SI to eliminate
1184 ;error such as A:\\..., A:\.., \\, \.. etc.
1185 ;This routine will change the current target directory to the root
1186 ;when "d:\" or "\" has been found.
1187 ;The parameter string should be ASCIIZ and should exist.
1188 ;INPUT: DS, ES - DATA SEG
1189 ; SI - POINTS TO THE PARAMETER
1190 ;OUTPUT:SI POINTS TO THE NEXT VALID PATH
1191 ; DX WILL POINTS TO THE ERROR MESSAGE
1193 CALL CHK_DRV_LETTER ;si points to the next chr after drv letter, if found.
1194 CMP BYTE PTR [SI], 0 ;"A:0" case
1197 MOV BYTE PTR [SI], '.'
1199 MOV BYTE PTR [SI], 0 ;make it "A:.0"
1203 CMP BYTE PTR [SI], '\'
1204 ; $IF E ;A:\--- or \--- cases
1207 CLC ;AN010;INITIALIZE TO NOT DBCS
1208 MOV AL,DS:BYTE PTR [SI] ;AN010;GET THE 1st CHAR TO TEST
1209 CALL CHK_DBCS
;AN010;SEE IF WE ARE IN DBCS
1210 ; $IF NC ;AN010;THIS IS NOT DBCS
1212 CMP BYTE PTR [SI], '\'
1213 ; $IF E ;A:\\--- or \\--- cases ; ERROR
1215 MOV DX, MSG_INVALID_PATH ;AC000;GET THE MESSAGE ID
1216 OR PARM_FLAG, INIT_ERROR_FLAG
1220 CMP BYTE PTR [SI], '.'
1221 ; $IF E ;A:\.--- or \.--- cases
1224 MOV AL,DS:BYTE PTR [SI] ;AN010;GET 1st CHAR
1226 CALL CHK_DBCS ;AN010;SEE IF WE ARE IN
1228 ; $IF NC ;AN010;THIS IS NOT DBCS
1230 CMP BYTE PTR [SI], '.'
1233 CMP BYTE PTR [SI], '\'
1234 ; $IF NE ;if not A:\.\--- or \.\--- cases
1237 MOV DX, MSG_INVALID_PATH
;AC000;MSG ID
1238 OR PARM_FLAG
, INIT_ERROR_FLAG
1241 ; $ENDIF ;AN010;END OF DBCS TEST
1250 INT 21h
;"Chdir to root" is no problem.
1251 ; $ENDIF ;AN010;DBCS TEST END
1261 PARSING_T_PATH PROC
NEAR
1262 ;chdir to every path element from the first. If fails, create the directory and
1263 ;try to chdir again. T_MKDIR_LVL will increase when new starting directory is created
1264 ;INPUT: DX - OFFSET OF T_INPUT_PARM
1265 ; SI - points to '\' or 0, or ':'
1266 ;OUTPUT: directories are created if necessary.
1267 ; DX points to the last path entry
1268 ; if fails to create a directory, then INIT_ERROR_FLAG set and
1269 ; DX points to MSG_NOT_CREATE_DIR msg.
1272 MOV DL, T_DRV_NUMBER
1274 CALL SET_DEFAULT_DRV
;set target drive as a default
1277 CMP BYTE PTR [SI], 0 ;end of string? the last path element?
1279 CMP BYTE PTR [SI], ':' ;filename terminator not checked before?
1280 JNE PTP_CHDIR
;else it is '\'.
1281 MOV BYTE PTR [SI], 0 ;change ':' to 0 for termination.
1286 MOV BYTE PTR [SI], 0 ;replace '\' with 0
1290 MOV BYTE PTR [SI], '\' ;restore '\'
1291 INC SI ;SI points to next to old '\'
1292 MOV DX, SI ;DX points to next path entry
1293 CALL NEXT_PATH_DELIM
1294 JMP PTP_NEXT
;handles next path element
1298 JC PTP_ERROR
;cannot make directory
1299 INC T_MKDIR_LVL
;# of MKDIR for the starting directory.
1300 JMP PTP_CHDIR
;try again to chdir
1302 MOV DX, MSG_NOT_CREATE_DIR
;AC000;GET THE MESSAGE ID
1303 OR PARM_FLAG
, INIT_ERROR_FLAG
;critical error
1309 LAST_T_PATH PROC
NEAR
1310 ;called when the second parm reached last. *** this routine is the same as the old routine ***
1311 ;and the initial try to chdir to the given T_INPUT_PARM has been failed.
1312 ;INPUT: ES, DS - data seg
1313 ; DX - points to the last path entry
1314 ;OUTPUT:target starting directory.
1316 MOV AH, Chdir
;try to chdir to the last path entry
1318 ; $IF C,LONG ;if fail.
1323 LEA BX, T_INPUT_PARM
1324 LEA DX, TEMP_T_FILENAME
;take the last path element into TEMP_T_FILENAME
1326 CMP TEMP_T_FILENAME
, 0 ;any filename candidate entered?
1327 ; $IF NE,LONG ;yes. let's check it has any global chr.
1333 LEA SI, TEMP_T_FILENAME
1334 MOV ES, PSP_SEG
;ES - psp seg
1335 MOV DI, PSPFCB2_DRV
;use this area for this test purposes
1336 MOV AL, 0 ;control bit
1339 CMP AL, 0 ;no global filename entered?
1340 ; $IF E ;yes, no globals
1342 CALL PROMPT_CREATE_DIR
;then ask the user, it is a filename or subdir name?
1343 MOV DX,USER_INPUT
;AN000;SET UP FOR COMPAIR
1344 CMP DX, alpha_dir
;directory?
1345 ; $IF E ;yes, a subdir name.
1347 LEA DX, TEMP_T_FILENAME
1349 INT 21h
;create a new subdir
1352 INC T_MKDIR_LVL
;one more directory has been made.
1354 INT 21h
;Chdir to a new dir. This time it should be a success.
1355 MOV TEMP_T_FILENAME
, 0 ;mark temp_t_filename that it is empty
1356 ; $ELSE ;ERROR IN CREATING DIRECTORY
1359 MOV DX, MSG_NOT_CREATE_DIR
;AC000;GET THE MESSAGE ID
1360 OR PARM_FLAG
, INIT_ERROR_FLAG
1363 ; $ELSE ;USER ANSWERED IT A FILENAME
1366 OR PARM1_FLAG
, T_FILE_FLAG
;set target file entered.
1367 ; $ENDIF ;use TEMP_T_FILENAME as a filename
1369 ; $ELSE ;GLOBALS IN THE FILENAME
1372 MOV TEMP_T_FILENAME
, 0 ;mark it to 0 since we don;t need this.
1373 CALL MAKE_TEMPLATE
;make a template of the target filename
1374 OR PARM1_FLAG
, T_FILE_FLAG
;set target file entered flag
1375 ; $ENDIF ;GLOBAL TEST
1377 ; $ENDIF ;NO, FILENAME NOT ENTERED. TEMP_T_FILENAME = 0
1379 ; $ENDIF ;CHDIR FAIL
1385 CHK_S_RESERVED_NAME PROC
NEAR
1386 ;check the source filename entered, and if it does not have any global chr,
1387 ;then check it whether it is reserved filename or not.
1388 ;input: es,ds - data seg
1390 mov ax, 3d00h
;let's try to open it
1391 lea dx, s_drv_1
;'A:S_FILE'
1393 jc csrn_exit
;open failure? jmp to exit
1394 mov bx, ax ;else ax has file handle
1395 mov ax, 4400h
;get device info.
1396 int 21h
;ioctl fun call
1397 test dx, 80h
;ISDEV ?
1398 jz csrn_close
;no, block device. close handle and exit
1400 MOV AX, msg_res_s_name
;AC000;reserved file name as a source"
1401 MOV MSG_NUM
,AX ;AN000;NEED MESSAGE ID FOR PRINT
1402 MOV SUBST_COUNT
,NO_SUBST
;AN000;NO SUBSTITUTION TEXT
1403 MOV INPUT_FLAG
,NO_INPUT
;AN000;NO INPUT = 0
1404 MOV MSG_CLASS
,UTILITY_MSG_CLASS
;AN000;MESSAGE CLASS = -1
1405 CALL PRINT_STDERR
;AN000;print error. AX points to msg ID
1407 mov errorlevel
, 4 ;abnormal termination
1408 or parm_flag
, init_error_flag
;set init_error_flag
1411 mov ah, 3eh
;close filehandle in bx
1415 CHK_S_RESERVED_NAME ENDP
1417 PROMPT_CREATE_DIR PROC
NEAR
1421 lea si, temp_t_filename
1422 lea di, filename_for_prompt
1423 call mov_STRING
;AC000;
1425 ;CALL GET MESSAGE TO DETERMINE WHAT THIS COUNTRY INPUT FOR 'F' OR 'D' IS.
1428 ASSUME
DS:NOTHING
;AN000;TELL THE ASSEMBLER
1429 MOV AX,MSG_F_D
;AN000;MESSAGE NUMBER = 29 = 'F D '
1430 MOV DH,UTILITY_MSG_CLASS
;AN000;MESSAGE DEFINED FOR XCPYINIT
1431 CALL SYSGETMSG
;AN000;GET THE MESSAGE
1432 LODSW ;AN000;'F'PART OF MSG (DS:SI => AX)
1433 CMP AH,SPACE
;AN000;NOT 'SPACE' THEN IT IS DBCS !
1434 ; $IF E ;AN000;IGNORE THE NEXT WORD
1436 MOV AH,NUL
;AN000;THE END OF THE STRING
1437 ; $ENDIF ;AN000;NOW GET TRANSLATION OF 'D'
1439 MOV ES:ALPHA_FILE
,AX ;AN000;TRANSLATED CHAR FOR 'F' TO BUFF
1440 LODSW ;AN000;'D'PART OF MSG (DS:SI => AX)
1441 CMP AH,SPACE
;AN000;NOT 'SPACE' THEN IT IS DBCS !
1442 ; $IF E ;AN000;IGNORE THE NEXT WORD
1444 MOV AH,NUL
;AN000;REMOVE SPACE CHARACTER
1445 ; $ENDIF ;AN000;NOW GET TRANSLATION OF 'D'
1447 MOV ES:ALPHA_DIR
,AX ;AN000;TRANSLATED CHAR FOR 'D' TO BUFF
1448 POP DS ;AN000;RESTORE AFTER CALL TO MSG HANDLR
1449 ASSUME
DS:DGROUP
;AN000;TELL THE ASSEMBLER
1450 ;remember this may be DBCS
1452 ; Set message substitution list
1453 LEA SI,SUBLIST1
;AN000; get addressability to sublist
1454 LEA DX,FILENAME_FOR_PROMPT
;AN000; offset to file name
1455 MOV [SI].DATA_OFF
,DX ;AN000; save data offset
1456 MOV [SI].DATA_SEG
,DS ;AN000; save data segment
1457 MOV [SI].MSG_ID
,1 ;AN000; message ID
1458 MOV [SI].FLAGS
,010H ;AN000; ASCIIZ string, left align
1459 MOV [SI].MAX_WIDTH
,0 ;AN000; MAXIMUM FIELD WITH
1460 MOV [SI].MIN_WIDTH
,0 ;AN000; MINIMUM FIELD WITH
1462 MOV AX,MSG_CREATE_DIR
;AN000;ID OF MESSAGE TO BE DISPLAYED
1463 MOV MSG_NUM
,AX ;AN000;SET THE MESSAGE NUMBER
1464 MOV SUBST_COUNT
,PARM_SUBST_ONE
;AN000;PARM SUBSTITUTION COUNT=1
1465 MOV MSG_CLASS
,UTILITY_MSG_CLASS
;AN000;MESSAGE CLASS = -1
1466 MOV INPUT_FLAG
,KEYBOARD_INPUT
;AN000;KEYBOARD INPUT EXPECTED FUNCTION
1467 CALL PRINT_STDOUT
;show prompt and get user input
1469 MOV USER_INPUT
,AX ;AN000;RESPONSE BUFF FOR CAPITALIZATION
1471 MOV AX,MSG_CR_LF_STR
;AN000; JUST CR,LF
1472 MOV MSG_NUM
,AX ;AN000; set message number
1473 MOV SUBST_COUNT
,NO_SUBST
;AN000;NO PARAMETER SUBSTITUTION
1474 MOV INPUT_FLAG
,NO_INPUT
;AN000; NO INPUT
1475 CALL PRINT_STDOUT
;AN000; Display message
1477 MOV AX,UPPER_CASE_STRING
;AN000;AX = 6521H GET EXT CTRY INFO
1478 LEA DX,USER_INPUT
;AN000;RESPONSE BUFF FOR CAPITALIZATION
1479 MOV CX,2 ;AN000;TWO CHARACTERS, ONE WORD
1480 INT 21H
;AN000;ISSUE INT TO CAP STRING (DBCS?)
1481 MOV AX,USER_INPUT
;AN000;SO I CAN DO THE COMPARE
1482 CMP AX,ALPHA_FILE
;AN000;KEYBOARD INPUT AX = 'F' ?
1484 CMP AX,ALPHA_DIR
;AN000;KEYBOARD INPUT AX = 'D' ?
1491 PROMPT_CREATE_DIR ENDP
1493 TAKE_PATH_TAIL PROC
NEAR
1494 ;check the tail of the source input parm.
1497 ; then check the drive letter
1498 ; if entered, then save the rest of the string after drv: into
1499 ; a tempory filename holder, and put "." after the drive letter
1500 ; (For ex, if the input had been 'A:name1',0 then no change after
1501 ; LAST_DIR_OUT. This has to be changed to 'A:.',0 and name1.)
1502 ; else save the last dir into a filename, and
1503 ; check the result path
1504 ; if it is a drive only, then put "\" ( For ex, if the input
1505 ; had been 'A:\name1',0 then after LAST_DIR_OUT, it will be changed
1506 ; to 'A:',0 and 'name1',0. In this case, we have to change the
1509 ;INPUT: DS - data seg
1511 ; BX - offset value of S_INPUT_PARM or T_INPUT_PARM
1512 ; DX - offset value of TEMP_S_FILENAME or TEMP_T_FILENAME
1515 MOV DI, BX ;offset of S(T)_INPUT_PARM
1517 ; $IF C ;Not found a "\"
1519 MOV SI, DI ;set si = di
1520 CALL CHK_DRV_LETTER
;if drv letter:, then SI will
1521 ;point to next chr. Otherwise no change
1522 cmp byte ptr [si], 0 ;only drv letter has entered. No filename
1523 ; $IF NE ;filename entered
1526 MOV CX, 13 ;max # of filename in ASCIIZ
1528 REP MOVSB ;save it to temporay name holder
1532 mov byte ptr [si], A_dot
;to be used for Chdir fun call
1533 mov byte ptr [si+1], 0 ;make it ASCIIZ
1534 ; $ELSE ;at least found a "\"
1537 mov cx, 13 ;let's save tail into filename holder first
1538 mov si, ax ;AX is an offset value of the tail
1539 mov di, DX ;TEMP_FILENAME
1541 mov si, BX ;return to the Revised input
1542 CALL CHK_DRV_LETTER
;it starts with drv letter?
1543 cmp byte ptr [si], 0 ;si points to the end of string?
1546 MOV byte ptr [SI], '\' ;then add '\' in the Revised S_INPUT_PARM
1547 MOV byte ptr [SI+1], 0
1556 CHK_CYCLIC_COPY PROC
NEAR
1557 ;With the one_disk_copy case, if the starting source path is a member of
1558 ;parent directory of the startind target path, then infinite copy cycle
1559 ;can occur. This routine prevents that situation.
1564 POP ES ;set ES to DS (ES = DS)
1565 CALL TRANS_NAMES
;AN016;CHK ASSIGN, JOIN & SUBST CONDITN
1566 TEST SYS_FLAG
, ONE_DISK_COPY_FLAG
;source, target drv let same
1567 ; $IF NZ ;if they are, then check below facts
1569 MOV DI, OFFSET DGROUP
:T_TRANS_PATH
;AC025;
1572 MOV DX, CX ;save the length of S_PATH
1573 MOV DI, OFFSET DGROUP
:S_TRANS_PATH
;AC025;
1575 CMP DX,CX ;compare the length
1576 ; $IF AE ;if target length >= source length
1578 MOV SI, OFFSET DGROUP
:S_TRANS_PATH
;AC025;
1579 MOV DI, OFFSET DGROUP
:T_TRANS_PATH
;AC025;
1580 DEC CX ;get the actual length of chr's
1583 ; $SEARCH ;current CX = source length
1586 ; $EXITIF E ;exit if cx = 0
1588 CMP DX, 0 ;target length = 0 too?
1589 ; $IF E ;yes, source = target
1591 TEST OPTION_FLAG
, SLASH_S
; tree copy?
1594 TEST OPTION_FLAG
, SLASH_E
1598 MOV DX, MSG_CYCLIC_COPY
;AC000;GET THE MESSAGE ID
1599 OR PARM_FLAG
, INIT_ERROR_FLAG
;critical error
1600 ; $ELSE ;same length, but not a tree copy.
1603 OR COPY_STATUS
, MAYBE_ITSELF_FLAG
;possibly, copy onto itself.
1604 ; $ENDIF ;cannot fully determine this time until file creation time
1606 ; $ELSE ;target > source
1609 TEST OPTION_FLAG
, SLASH_S
;tree copy?
1612 TEST OPTION_FLAG
, SLASH_E
1616 CMP BYTE PTR [DI], '\' ;source = d:\abc, target = d:\abc\def case
1619 CMP BYTE PTR [DI-1], '\' ;source = d:\, target=d:\abc case
1623 MOV DX, MSG_CYCLIC_COPY
;AC000;GET THE MESSAGE ID
1624 OR PARM_FLAG
, INIT_ERROR_FLAG
; critical error
1634 LODSB ;[SI] => AL, SI = SI + 1
1635 SCASB ;AL vs. [DI], DI = DI + 1
1636 ; $LEAVE NE ;leave if not same
1639 DEC DX ;decrease target length, too
1651 CHK_CYCLIC_COPY ENDP
1653 TRANS_NAMES PROC
NEAR
1654 ;TRANSLATE THE INPUT TARGET AND SOURCE PATH TO DETERMINE
1655 ;IF ASSIGN, JOIN OR SUBSD WAS USET TO MODIFY HIDE THE TRUE
1656 ;PATH. THIS INFO. WILL BE USED TO DETERMINE CYCLIC COPY.
1657 ;INPUT: T_DRV_PATH, S_DRV_PATH
1659 PUSH SI ;AN016;SI WILL BE DESTROYED
1660 PUSH DI ;AN016;DI WILL BE DESTROYED
1662 MOV SI,OFFSET DGROUP
:T_DRV_PATH
;AN016;DO NAME TRANSLATE OF TAR
1663 MOV DI,OFFSET DGROUP
:T_TRANS_PATH
;AN025;SAVE FOR COMPARE
1664 MOV AH,60h
;AN016;NAMETRANSLATE
1665 INT 21h
;AN016;EXECUTE
1667 MOV SI,OFFSET DGROUP
:S_DRV_PATH
;AN016;DO NAME TRANSLATE OF SRC
1668 MOV DI,OFFSET DGROUP
:S_TRANS_PATH
;AN025;SAVE FOR COMPARE
1669 MOV AH,60h
;AN016;NAMETRANSLATE
1670 INT 21h
;AN016;EXECUTE
1672 ;NOW COMPARE THE TRANSLATED NAMES
1674 MOV SI,OFFSET DGROUP
:T_TRANS_PATH
;AN025;GET THE TAR FOR COMPARE
1675 MOV DI,OFFSET DGROUP
:S_TRANS_PATH
;AN025;GET THE SRC FOR COMPARE
1676 CALL STR_COMP
;AN016;DO THE COMPARE
1677 ; $IF Z ;AN016;STRING DID COMPARE
1679 OR SYS_FLAG
, ONE_DISK_COPY_FLAG
;AN016;source, target drv let same
1683 POP DI ;AN016;restore DI
1684 POP SI ;AN016;restore SI
1689 ;COMPARE ASCIIZ DS:SI WITH ES:DI
1690 ;DI,SI ARE DESTROYED
1693 CMPSB ;AN016;ONE BYTE AT A TIME
1694 ; $IF NZ ;AN016;DID NOT COMPARE
1696 RET ;AN016;NZ = DIFFERENCE
1699 CMP BYTE PTR [SI-1],NUL
;AN016;CHK FOR END OF THE STRING
1700 ; $IF Z ;ANO16;IT IS E O S
1702 RET ;AN016;IT COMPARED
1705 JMP SHORT STRCOMP
;AN016;GO AGAIN
1708 MAKE_TEMPLATE PROC
NEAR
1709 ;copy the formatted filename into the T_TEMPLATE which will be
1710 ;used to name a new filename.
1711 ;INPUT: PSP FCB 6ch for filename which have global chr.
1713 PUSH DS ;ES = DS = DATA SEG
1715 MOV DS, PSP_SEG
;DS = PSP_SEG
1721 REP MOVSB ;filename => t_template
1727 GET_DRIVES PROC
NEAR
1728 ;get source and target phisical drive letter from parser area.
1729 ;set ONE_DISK_COPY_FLAG, if the user XCOPY using the same drive letter.
1731 MOV AL, SO_DRIVE
;AN000;source drive letter
1732 CMP AL,SPACE
;AN000;IS DRIVE LETTER BLANK?
1733 ; $IF E ;AN000;YES, GET THE DEFAULT
1735 MOV AL, SAV_DEFAULT_DRV
;(1=A, 2=B,...)
1736 ; $ELSE ;AN000;NO, CHANGE FROM CHAR TO #
1739 SUB AL,BASE_OF_ALPHA_DRV
;AN000;NEED THE DRV # HERE
1742 MOV S_DRV_NUMBER
, AL ;SAVE DRV #
1743 ADD AL, BASE_OF_ALPHA_DRV
1744 MOV S_DRV
, AL ;save source drive letter
1749 MOV AL, TAR_DRIVE
;AN000;target drive letter
1750 CMP AL,SPACE
;AN000;IS DRIVE LETTER BLANK?
1751 ; $IF E ;AN000;YES, GET THE DEFAULT
1753 MOV AL, SAV_DEFAULT_DRV
;AN000;(1=A, 2=B,...)
1754 ; $ELSE ;AN000;NO, CHANGE FROM CHAR TO #
1757 SUB AL,BASE_OF_ALPHA_DRV
;AN000;NEED THE DRV # HERE
1760 MOV T_DRV_NUMBER
, AL ;save target drv #
1762 CMP S_DRV_NUMBER
, AL ;s_drv_number = t_drv_number?
1765 OR SYS_FLAG
, ONE_DISK_COPY_FLAG
;same logical drv copy
1769 ADD AL, BASE_OF_ALPHA_DRV
;make target drv # to drive letter
1770 MOV T_DRV
, AL ;target drive letter
1778 GET_CUR_DRV PROC
NEAR
1779 ;get the current default drive number (0 = A, 1 = B ..),
1780 ;change it to BIOS drive number and save it.
1781 MOV AH, Current_Disk
; = 19h
1783 INC AL ;(1 = A, 2 = B ..)
1784 MOV SAV_DEFAULT_DRV
, AL ;save it
1788 GET_CUR_DIR PROC
NEAR
1789 ;get current directory and save it
1790 ;input: DL - drive # (0 = default, 1 = A etc)
1791 ; DS:SI - pointer to 64 byte user memory
1793 MOV AH, Get_Current_Directory
1798 TOP_OF_MEM PROC
NEAR
1804 MOV AX, ES:2 ;PSP top of memory location
1805 SUB AX, 140H
;subtract dos transient area (5k)
1806 MOV TOP_OF_MEMORY
, AX ;save it for buffer top
1811 INIT_BUFFER PROC
NEAR
1812 ;initialize buffer information
1813 ;set buffer_base, max_buffer_size
1814 ; call set_block ;SET BLOCK FOR BUFFR (for new 3.2 linker)
1816 PUSH CS ;cs segment is the highest segment in this program
1821 MOV BUFFER_BASE
, AX ;set buffer_base
1823 CMP AX, 140h
;BUFFER_LEFT < 5K which is the minimum size this program supports?
1826 MOV AX, MSG_INSUF_MEMORY
;AC000;GET THE MESSAGE ID
1827 MOV MSG_NUM
,AX ;AN000;NEED MESSAGE ID FOR PRINT
1828 MOV SUBST_COUNT
,NO_SUBST
;AN000;NO SUBSTITUTION TEXT
1829 MOV INPUT_FLAG
,NO_INPUT
;AN000;NO INPUT = 0
1830 MOV MSG_CLASS
,UTILITY_MSG_CLASS
;AN000;MESSAGE CLASS = -1
1831 CALL PRINT_STDERR
;AN000;print error. AX points to msg ID
1833 MOV ERRORLEVEL
, 4 ;abnormal termination
1834 JMP MAIN_EXIT_A
;terminate this program
1836 MOV MAX_BUFFER_SIZE
, AX ;set max buffer size in para
1837 CMP AX, 0FFFh ;max_buffer_size > 64 K in para ?
1841 MUL CX ;AX = AX * 16 (DX part will be 0)
1842 SUB AX, 544 ;AN000;subtract header size
1843 MOV MAX_CX
, AX ;this will be max_cx
1847 MOV MAX_CX
, 0FFD0h ;else max_cx = fff0 - 32 bytes
1848 ;which is the max # this program can support.
1849 ; $ENDIF ;(min # this program support for buffer is 5 k
1851 ; which has been decided by BIG_FILE )
1855 HOOK_CTRL_BREAK PROC
NEAR
1861 MOV DX, OFFSET CTRL_BREAK_EXIT
1865 HOOK_CTRL_BREAK ENDP
1867 SAV_HOOK_INT24 PROC
NEAR
1868 ;sav the int_24 addr, and hooks it to my_int24
1871 MOV AL, 24h
;get critical error handler addr
1873 MOV SAV_INT24_OFF
, BX ;offset ip
1874 MOV SAV_INT24_SEG
, ES ;seg cs
1881 MOV DX, OFFSET MY_INT24
;now DS:DX contains the addr.
1882 INT 21h
;hook it to my_int24 routine