summaryrefslogtreecommitdiff
path: root/v4.0/src/SELECT/MOD_COPY.ASM
diff options
context:
space:
mode:
Diffstat (limited to 'v4.0/src/SELECT/MOD_COPY.ASM')
-rw-r--r--v4.0/src/SELECT/MOD_COPY.ASM2484
1 files changed, 2484 insertions, 0 deletions
diff --git a/v4.0/src/SELECT/MOD_COPY.ASM b/v4.0/src/SELECT/MOD_COPY.ASM
new file mode 100644
index 0000000..a4e65d8
--- /dev/null
+++ b/v4.0/src/SELECT/MOD_COPY.ASM
@@ -0,0 +1,2484 @@
1 PAGE, 132 ;AN000;
2TITLE XCOPY WITH FULL MEMORY USE ;AN000;
3
4; ##### R E A D M E #####
5;
6; This file contains a copy of the XCOPY code. The code has been
7; Revised (additions and many parts commented out) to conform to the
8; needs of SELECT.
9;
10; #########################
11
12;****************** START OF SPECIFICATIONS *****************************
13; MODULE NAME: XCOPY
14;
15; DESCRIPTIVE NAME: selectively copy groups of files, which can include
16; lower level subdirectories.
17;
18; FUNCTION: The modules of XCOPY will be placed in the following order -
19; SSEG, DSEG(MAIN DATA, MAIN MSG), CSEG (MAIN + INIT),
20; DSEG_INIT(INIT DATA, INIT MSG)
21;
22; HEADER - informations needed about the file, subdirectory ...
23; Continue_Info -> 0 - a whole single file in this header
24; segment, or dir.
25; 1 - Continuation of a small file.
26; 2 - Continuation of a Big file
27; 3 - Eof of continuation
28; Next_Ptr -> points to the next header segment
29; Before_Ptr -> points to the old header segment
30;
31; By optionally using the Archive bit in the directory of each
32; file, XCOPY can be used as an alternative method of creating
33; backup files which can be accessed directly by DOS and its
34; applications without the need to "restore" the backup files.
35;
36; XCOPY is especially useful when several files are being copied
37; and there is a generous amount of RAM available, because XCOPY
38; will fill the memory with all the source files it can read in
39; before starting to create output files. If the memory is not
40; enough to hold all the source, this cycle will be repeated until
41; the process is completed. For single drive systems, this maximum
42; usage of the memory greatly reduces the amount of diskette
43; swapping that would be required by the usual COPY command.
44;
45; ENTRY POINT: MAIN
46;
47; INPUT: (DOS COMMAND LINE PARAMETERS)
48;
49; SOURCE OPERAND: TARGET OPERAND:
50;
51; [d:] [path] filename[.ext] [d:] [path] [filename[.ext]]
52; or
53; [d:] path [filename[.ext]]
54; or
55; d: [path] [filename[.ext]]
56;
57;
58; SWITCHES:
59;
60; /A /D /E /M /P /S /V /W
61;
62;The /A switch will copy only those files whose archive bit of the attribute is
63;set to one. The attribute of the source file is not changed. This option is
64;useful when making multiple backups when doing the non-final backup.
65;The archive bit is one when a file has be created or Revised since the last
66;time the bit was turned off. XCOPY /M or BACKUP /M will turn this bit off.
67;The ATTRIB command can also be used to change the setting of the archive bit.
68;
69;The /D switch will copy only those files whose date is the same or later than
70;the date specified. Depending on the country code you selected using the
71;COUNTRY command, the date is specified in the format corresponding to the
72;indicated country.
73;
74;The /E switch will create subdirectories on the target even if they end up
75;being empty after all copying is over. If /E is not specified, empty
76;subdirectories are not created.
77;
78;The /M switch will copy only those files whose archive bit is set in its
79;attribute. Unlike the /A switch, /M will cause the archive bit in the source
80;file to be turned off. This allows XCOPY to be used in making a final backup.
81;The archive bit is one when a file has be created or Revised since the last
82;time the bit was turned off. XCOPY /M or BACKUP /M will turn this bit off.
83;The ATTRIB command can also be used to change the setting of the archive bit.
84;
85;The /P switch will prompt the operator before copying each file. In this
86;situation, each file is copied onto the target before reading in the next
87;file. The multi-file copy into a large memory buffer is not done. The prompt
88;displays the complete filespec it proposes to copy and asks for (Y/N)
89;response, which is then read in from the standard input device.
90;
91;The /S switch will not only copy the files in the current source directory but
92;also those in all the subdirectories below the current one, with XCOPY
93;following the Tree of the subdirectories to access these files. /S does not
94;create an empty subdirectory on the target (unless /E is also specified).
95;If the /S switch is not specified, XCOPY works only within the specified (or
96;current) subdirectory of the source.
97;
98;The /V switch will cause DOS to verify that the sectors written on the target
99;are recorded properly. This option has been provided so you can verify that
100;critical data has been correctly recorded. This option will cause XCOPY to
101;run more slowly, due to the additional overhead of verification.
102;
103;The /W switch will instruct XCOPY to pause before actually starting the
104;movement of data, thus permit the copying of diskettes that do not actually
105;have XCOPY available on them. The diskette containing XCOPY can be mounted
106;first, the XCOPY command given with the /W option, then when the prompt
107;requesting permission to continue is given, that diskette can then be removed
108;and the source diskette mounted in its place, then the operator can press any
109;key to continue after the pause. This feature is especially useful in a
110;non-hardfile system.
111;
112; EXIT-NORMAL: ERRORLEVEL_0 - This is the normal completion code.
113; ERRORLEVEL_2 - This is due to termination via Control-Break.
114; ERRORLEVEL_4 - This is used to indicate an error condition.
115;
116; There are many types of problems that are detected and result in this
117; return code, such as:
118;
119; write failure due to hard disk error
120; disk full
121; conflict between name of new subdirectory and existing filename
122; access denied
123; too many open files
124; sharing violation
125; lock violation
126; general failure
127; file not found
128; path not found
129; directory full
130; invalid parms
131; reserved file name as source
132; insufficient memory
133; incorrect DOS version
134;
135;
136; INTERNAL REFERENCES:
137;
138; ROUTINES:
139;
140;
141; DATA AREAS:
142;
143;
144; EXTERNAL REFERENCES:
145;
146; ROUTINES:
147;
148;
149; DATA AREAS:
150;
151;
152; NOTES: This module should be processed with the SALUT pre-processor
153; with the re-alignment not requested, as:
154;
155; SALUT XCOPY,NUL,;
156;
157; To assemble these modules, the sequential
158; ordering of segments may be used.
159;
160; For LINK instructions:
161; link profile ..\lib
162;
163; REVISION HISTORY: A000 Version 4.00: add PARSER, System Message Handler,
164; Remove the BELL char.,turn off APPEND during TREE
165; search,Extended Attribute processing, Uppercasing
166; and "Out Of Space" during write to standard out.
167; A001 PTM0011 XCOPY not handling path >63 characters.
168; CHK_MAX_LENGTH proc(XCPYINIT) is Revised to err if
169; >63 chrs.
170; A002 PTM0012 XCOPY unnecessarily accessing current drive.
171; ORG_S_T_DEF is Revised to ignore CHDIR if drive
172; is not TARGET or SOURCE.
173; A003 PTM0088 XCOPY (\) missing in 'FILE SHARING ERROR'.
174; This problem is fixed with incorporation of the
175; new message services.
176; A005 DCR0201 10/9/87 Incorperate new format for EXTENDED
177; ATTRIBUTES.
178;
179;
180; Label: "DOS XCOPY Utility"
181; "Version 4.00 (C) Copyright 1988 Microsoft"
182; "Licensed Material - Program Property of Microsoft"
183;
184;****************** END OF SPECIFICATIONS *****************************
185
186CLEAR_SCREEN2 MACRO;AN000;
187 MOV CX,0 ;;AN000;
188 MOV DX,184Fh ;;AN000; scroll screen from (0,0) tO (24,79)
189 MOV AX,0600h ;;AN000; AH = 6, Scroll Function
190 ;; AL = 0, Clear scroll area
191 MOV BH,7 ;;AN000; video I/O interrupt
192 INT 10H ;;AN000;
193 MOV DX,0 ;;AN000; RKJ-set cursor posn to top right hand corner
194 MOV BH,0 ;;AN000; RKJ
195 MOV AH,2 ;;AN000; RKJ
196 INT 10H ;;AN000; RKJ
197 ENDM ;;AN000;
198;--------------------------------
199; Include Files
200;--------------------------------
201INCLUDE STRUC.INC ;AN000; SAR
202INCLUDE XMAINMSG.EQU ;AN000;message file
203INCLUDE DOS.EQU ;AN000;
204INCLUDE XCOPY.EQU ;AN000;
205INCLUDE PAN-LIST.INC ;AN111;JW
206INCLUDE PANEL.MAC ;AN111;JW
207INCLUDE CASEXTRN.INC ;AN111;JW
208
209
210EXTRN FK_ENT:BYTE ;AN111;JW
211EXTRN FK_ENT_LEN:ABS ;AN111;JW
212EXTRN E_RETURN:ABS ;AN111;JW
213EXTRN S_DOS_SHEL_DISK:WORD ;AN111;JW
214EXTRN S_DOS_SEL_360:WORD ;AN111;JW
215EXTRN E_FILE_ATTR:ABS ;AN111;JW
216
217EXTRN FIND_FILE_ROUTINE:FAR ;AN111;JW
218EXTRN EXIT_SELECT:near ;AN111;JW
219
220;-------------------------------
221; Structures
222;-------------------------------
223;HEADER - informations needed about the file, subdirectory ...
224;Continue_Info -> 0 - a whole single file in this header segment, or dir.
225; 1 - Continuation of a small file.
226; 2 - Continuation of a Big file
227; 3 - EOF of continuation
228;Next_Ptr -> points to the next header segment
229;Before_Ptr -> points to the old header segment
230
231HEADER STRUC ;AN000;
232 CONTINUE_INFO DB 0 ;AN000;set for filesize bigger then 0FFD0h
233 NEXT_PTR DW ? ;AN000;next buffer ptr in para
234 BEFORE_PTR DW ? ;AN000;before ptr in para
235 DIR_DEPTH DB ? ;AN000;same as S_DEPTH
236 CX_BYTES DW 0 ;AN000;actual # of bytes in this buffer seg.
237 ATTR_FOUND DB ? ;AN000;attribute found
238 FILE_TIME_FOUND DW ?;AN000;
239 FILE_DATE_FOUND DW ?;AN000;
240 LOW_SIZE_FOUND DW ?;AN000;
241 HIGH_SIZE_FOUND DW ?;AN000;
242 TARGET_DRV_LET DB " :" ;AN000;used for writing
243 FILENAME_FOUND DB 13 DUP (0) ;AN000; FILENAME
244 ATTRIB_LIST DB ? ;AC005;EXTENDED ATTRIBUTE BUFFER
245;-------------------------------------------------------------------
246; extended attribute list used by extended open & get extended
247;-------------------------------------------------------------------
248; ATTRIB_LIST LABEL BYTE extended attribute buffer
249;
250;EA STRUC ; EXTENDED ATTRIBUTE
251;EA_TYPE DB ? ; TYPE
252;EAISUNDEF EQU 0 ; UNDEFINED TYPE (ATTRIB SKIPS)
253; ; (OR TYPE NOT APPLICABLE)
254; ; LENGTH: 0 TO 64K-1 BYTES
255;EAISLOGICAL EQU 1 ; LOGICAL (0 OR 1) (ATTRIB DISPLAYS) ; LENGTH: 1 BYTE
256;EAISBINARY EQU 2 ; BINARY INTEGER (ATTRIB DISPLAYS)
257; ; LENGTH: 1, 2, 4 BYTES
258;EAISASCII EQU 3 ; ASCII TYPE (ATTRIB DISPLAYS)
259; ; LENGTH: 0 TO 128 BYTES
260;EAISDATE EQU 4 ; DOS FILE DATE FORMAT (ATTRIB DISPLAYS)
261; ; LENGTH: 2 BYTES
262;EAISTIME EQU 5 ; DOS FILE TIME FORMAT (ATTRIB DISPLAYS)
263; ; LENGTH: 2 BYTES
264; ; OTHER VALUES RESERVED
265;EA_FLAGS DW ? ; FLAGS
266;EASYSTEM EQU 8000H ; EA IS SYSTEM DEFINED
267; ; (BUILTIN, NOT APPLICATION DEFINED)
268;EAREADONLY EQU 4000H ; EA IS READ ONLY (CANT BE CHANGED)
269;EAHIDDEN EQU 2000H ; EA IS HIDDEN FROM ATTRIB
270;EACREATEONLY EQU 1000H ; EA IS SETABLE ONLY AT CREATE TIME
271; ; OTHER BITS RESERVED
272;EA_RC DB ? ; FAILURE REASON CODE (SET BY DOS)
273;EARCNOTFOUND EQU 1 ; NAME NOT FOUND
274;EARCNOSPACE EQU 2 ; NO SPACE TO HOLD NAME OR VALUE
275;EARCNOTNOW EQU 3 ; NAME CAN'T BE SET ON THIS FUNCTION
276;EARCNOTEVER EQU 4 ; NAME CAN'T BE SET
277;EARCUNDEF EQU 5 ; NAME KNOWN TO THIS FS BUT NOT SUPPORTED
278;EARCDEFBAD EQU 6 ; EA DEFINTION BAD (TYPE, LENGTH, ETC)
279;EARCACCESS EQU 7 ; EA ACCESS DENIED
280;EARCUNKNOWN EQU -1 ; UNDETERMINED CAUSE
281;EA_NAMELEN DB ? ; LENGTH OF NAME
282;EA_VALLEN DW ? ; LENGTH OF VALUE
283;EA_NAME DB ? ; FIRST BYTE OF NAME
284;
285;EA_VALUE DB ? ; FIRST BYTE OF VALUE
286;
287HEADER ENDS ;AN000;
288
289;;;;SUB_LIST STRUC ; SAR
290;;;; DB 11 ; SAR ;AN000;
291;;;; DB 0 ; SAR ;AN000;
292;;;;DATA_OFF DW 0 ; SAR ;AN000; offset of data to be inserted
293;;;;DATA_SEG DW 0 ; SAR ;AN000; offset of data to be inserted
294;;;;MSG_ID DB 0 ; SAR ;AN000; n of %n
295;;;;FLAGS DB 0 ; SAR ;AN000; Flags
296;;;;MAX_WIDTH DB 0 ; SAR ;AN000; Maximum field width
297;;;;MIN_WIDTH DB 0 ; SAR ;AN000; Minimum field width
298;;;;PAD_CHAR DB 0 ; SAR ;AN000; character for pad field
299;;;; ; SAR
300;;;;SUB_LIST ENDS ; SAR
301;******************************************************************************
302DATA SEGMENT BYTE PUBLIC 'DATA' ;AN000; DATA Segment
303
304INCLUDE DOSFILES.INC ;AN000; SAR
305
306;; ERRORLEVEL DB 0 ; SAR ;errorlevel
307;; INPUT_DATE DW 0 ; SAR
308;; INPUT_TIME DW 0 ; SAR
309PSP_SEG DW ? ;AN000;
310SAV_DEFAULT_DRV DB ? ;AN000;1 = A, 2 = B etc. saved default
311SAV_DEF_DIR_ROOT DB '\';AN000;
312SAV_DEFAULT_DIR DB 64 DUP (0);AN000;
313SAV_S_DRV DB 'A:\' ;AN000;
314SAV_S_CURDIR DB 64 DUP (0);AN000;
315SAV_T_DRV DB 'B:\' ;AN000;
316SAV_T_CURDIR DB 64 DUP (0);AN000;
317
318 PUBLIC SOURCE_PANEL, DEST_PANEL, CHECK_FILE ;AN111;JW
319SOURCE_PANEL DW ? ;AN111;JW
320DEST_PANEL DW ? ;AN111;JW
321CHECK_FILE DW ? ;AN111;JW
322
323SOURCE_IN DB ? ;AN111;JW
324YES EQU 0 ;AN111;JW
325NO EQU 1 ;AN111;JW
326
327OLD_DTA_SEG DW ? ;AN111;JW
328OLD_DTA_OFF DW ? ;AN111;JW
329
330;
331
332;; DISP_S_PATH DB 67 DUP (0) ; SAR ;mirror image of source path. used for display message when copying
333;; DISP_S_FILE DB 13 DUP (0) ; SAR
334;; DISP_T_PATH DB 67 DUP (0) ; SAR ;mirror image of target path
335;; DISP_T_FILE DB 13 DUP (0) ; SAR
336;
337;;B_SLASH DB '\',0 ; SAR
338
339
340FILE_COUNT LABEL WORD ;AN000;
341FILE_CNT_LOW DW 0 ;AN000;copied file count
342FILE_CNT_HIGH DW 0 ;AN000;
343;
344
345;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
346;; APPENDFLAG DW 0 ; SAR ;append /X status save area
347FOUND_FILE_FLAG DB 0 ;AN000;used for showing the message "File not found"
348;
349S_DRV_NUMBER DB 0 ;AN000;source, target drv #
350T_DRV_NUMBER DB 0 ;AN000;
351;
352S_DRV_PATH LABEL BYTE ;AN000;source drv, path used for single_drv_copy
353S_DRV DB 'A:\' ;AN000;
354S_PATH DB 80 DUP (0) ;AN000;Initialized by calling GET CUR DIR
355S_DEPTH DB 0 ;AN000;
356S_DRV_1 DB 'A:' ;AN000;
357S_FILE DB '????????.???',0 ;AN000;default filename to find file
358;; S_DIR DB '????????.???',0 ; SAR ;to find any subdirectory name
359
360;; S_PARENT DB '..',0 ; SAR ;source parent used for non single_drv_copy
361S_HANDLE DW 0 ;AN000;file handle opened
362
363;; S_ARC_DRV_PATH LABEL BYTE ; SAR ;informations used to change source file's
364;; S_ARC_DRV DB 'A:\' ; SAR ;archieve bits.
365;; S_ARC_PATH DB 64 DUP (0) ; SAR
366;; S_ARC_DEPTH DB 0 ; SAR
367
368T_DRV_PATH LABEL BYTE ;AN000;target drv, path used all the time
369T_DRV DB 'B:\' ;AN000;
370T_PATH DB 64 DUP (0) ;AN000;initialized by calling GET CUR DIR in INIT
371T_DEPTH DB 0 ;AN000;
372
373;; T_FILE LABEL BYTE ; SAR ;target filename for file creation
374;; T_DRV_1 DB 'B:' ; SAR ;target drv letter
375;; T_FILENAME DB 13 DUP (0) ; SAR ;target filename
376;; T_TEMPLATE DB 11 DUP (0) ; SAR ;if global chr entered, this will be used instead of filename.
377
378;; T_PARENT LABEL BYTE ; SAR
379;; T_DRV_2 DB 'B:' ; SAR
380;; T_PARENT_1 DB '..',0 ; SAR
381T_HANDLE DW 0 ;AN000;target handle created
382;; T_MKDIR_LVL DB 0 ; SAR ;# of target starting directories created.
383;
384;------------------------------------------
385; PRINT_STDOUT input parameter save area
386;------------------------------------------
387;; SUBST_COUNT DW 0 ; SAR ;AN000; message substitution count
388;; MSG_CLASS DB 0 ; SAR ;AN000; message class
389;; INPUT_FLAG DB 0 ; SAR ;AN000; Type of INT 21 used for KBD input
390;; MSG_NUM DW 0 ; SAR ;AN000; message number
391
392;----------------------------------------------
393; Parameter list used by extended open DOS call
394;----------------------------------------------
395PARAM_LIST LABEL WORD;AN000;
396E_A_LST DD 0 ;AN005; E A LIST POINTER
397 DW 1 ;AN005; number of additional parameters
398 DB 6 ;AN005; ID for IO mode = WORD VALUE
399 DW 1 ;AN005; IO mode = PURE SEQUENTIAL
400
401
402;; INPUT_BUFF db 20 dup(0) ; SAR ;AN000; keyboard input buffer used
403 ;for user response (Y/N)
404
405;--------------------------------------------------------------
406; Following three sublists are used by the Message Retriever
407;--------------------------------------------------------------
408;;SUBLIST1 LABEL DWORD ; SAR ;AN000;SUBSTITUTE LIST 1
409;; DB 11 ; SAR ;AN000;sublist size
410;; DB 0 ; SAR ;AN000;reserved
411;; DD 0 ; SAR ;AN000;substition data Offset
412;; DB 1 ; SAR ;AN000;n of %n
413;; DB 0 ; SAR ;AN000;data type
414;; DB 0 ; SAR ;AN000;maximum field width
415;; DB 0 ; SAR ;AN000;minimum field width
416;; DB 0 ; SAR ;AN000;characters for Pad field
417;; ; SAR
418;; ; SAR
419;;SUBLIST2 LABEL DWORD ; SAR ;AN000;SUBSTITUTE LIST 2
420;; DB 11 ; SAR ;AN000;sublist size
421;; DB 0 ; SAR ;AN000;reserved
422;; DD 0 ; SAR ;AN000;substition data Offset
423;; DB 2 ; SAR ;AN000;n of %n
424;; DB 0 ; SAR ;AN000;data type
425;; DB 0 ; SAR ;AN000;maximum field width
426;; DB 0 ; SAR ;AN000;minimum field width
427;; DB 0 ; SAR ;AN000;characters for Pad field
428;; ; SAR
429;; ; SAR
430;;SUBLIST3 LABEL DWORD ; SAR ;AN000;SUBSTITUTE LIST 3
431;; DB 11 ; SAR ;AN000;sublist size
432;; DB 0 ; SAR ;AN000;reserved
433;; DD 0 ; SAR ;AN000;substition data Offset
434;; DB 3 ; SAR ;AN000;n of %n
435;; DB 0 ; SAR ;AN000;data type
436;; DB 0 ; SAR ;AN000;maximum field width
437;; DB 0 ; SAR ;AN000;minimum field width
438;; DB 0 ; SAR ;AN000;characters for Pad field
439;;
440
441
442FILE_SEARCH_ATTR DW NORM_ATTR;AN000;
443;; DIR_SEARCH_ATTR DW INCL_H_S_DIR_ATTR ; SAR
444;
445OPEN_MODE DB Read_Only_Deny_Write ;AN000;READ_ONLY_DENY_WRITE ;access, sharing mode
446;
447;Equates are defined in XCOPY.EQU
448
449MY_FLAG DB 0 ;AN000;informations for a tree walk
450; find_first_flag equ 01h ;set MY_FLAG by "OR"
451; findfile_flag equ 02h
452; no_more_file equ 04h
453; single_copy_flag equ 08h ;single copy instead of multi copy
454; visit_parent_flag equ 10h ;visit parent node
455; found_flag equ 20h ;found flag - for find subdir
456; missing_link_flag equ 40h ;insuffiecient info. for not creating empty dir
457; is_source_flag equ 80h ;if set, dealing with source
458; reset_find_first equ 0FEh ;reset by AND
459; reset_findfile equ 0FDh
460; reset_no_more equ 0FBh
461; reset_visit_parent equ 0EFh
462; reset_found equ 0DFh
463; reset_missing_link equ 0BFh
464; reset_is_source equ 07Fh
465
466FILE_FLAG DB 0 ;AN000;
467; cont_flag equ 01h
468; eof_flag equ 02h
469; big_file_flag equ 04h
470; file_bigger_flag equ 08h
471; created_flag equ 10h
472; reset_cont equ 0FEh
473; reset_eof equ 0FDh
474; reset_big_file equ 0FBh
475; reset_file_bigger equ 0F7h
476; reset_created equ 0EFh
477; reset_readfile equ 0F0h ;reset FILE_FLAG for read a file
478;
479COPY_STATUS DB 0;AN000;
480; open_error_flag equ 01h
481; read_error_flag equ 02h
482; create_error_flag equ 04h
483; write_error_flag equ 08h
484; mkdir_error_flag equ 10h
485; chdir_error_flag equ 20h
486; maybe_itself_flag equ 40h
487; disk_full_flag equ 80h
488; reset_open_error equ 0FEh
489; reset_read_error equ 0FDh
490; reset_create_error equ 0FBh
491; reset_write_error equ 0F7h
492; reset_close_error equ 0EFh
493; reset_chdir_error equ 0DFh
494;
495ACTION_FLAG DB 0;AN000;
496; reading_flag equ 01h ;display "Reading source files..."
497; reset_reading equ 0FEh ;do not display.
498;
499SYS_FLAG DB 0 ;AN000;system information
500; one_disk_copy_flag equ 01h ;xcopy with only one logical drive.
501; default_drv_set_flag equ 02h ;default drive has been changed by this program
502; default_s_dir_flag equ 04h ;source current directory saved.
503; default_t_dir_flag equ 08h ;target current directory saved.
504; removalble_drv_flag equ 10h
505; sharing_source_flag equ 20h ;source shared
506; sharing_target_flag equ 40h
507; turn_verify_off_flag equ 80h ;turn the verify off when exit to dos
508; reset_default_s_dir equ 0FBh ;reset default_s_dir_flag
509;
510OPTION_FLAG DB 0;AN000;
511; slash_a equ 01h ;soft archieve ?
512; slash_d equ 02h ;date?
513; slash_e equ 04h ;create empty dir?
514; slash_m equ 08h ;hard archieve ? (turn off source archieve bit)
515; slash_p equ 10h ;prompt?
516; slash_s equ 20h ;walk the tree?
517; slash_v equ 40h ;verify on?
518; slash_w equ 80h ;show "Press any key to begin copying" msg)
519; reset_slash_a equ 0FEh ;turn off soft archieve
520; reset_slash_m equ 0F7h ;turn off hard archieve
521
522MAX_CX DW 0 ;AN000;less than 0FFD0h
523ACT_BYTES DW 0 ;AN000;actual bytes read.
524HIGH_FILE_SIZE DW 0;AN000;
525LOW_FILE_SIZE DW 0;AN000;
526;
527TOP_OF_MEMORY DW 0 ;AN000;para
528BUFFER_BASE DW 0 ;AN000;para
529MAX_BUFFER_SIZE DW 0 ;AN000;para. BUFFER_LEFT at INIT time.
530BUFFER_LEFT DW 0 ;AN000;para
531BUFFER_PTR DW 0 ;AN000;para. If buffer_left=0 then invalid value
532DATA_PTR DW 0 ;AN000;buffer_ptr + 2 (32 bytes)
533OLD_BUFFER_PTR DW 0 ;AN000;last buffer_ptr
534SIZ_OF_BUFF DW ? ;AN005;para. EXTENDED ATTRIB BUFF SIZE
535BYTS_OF_HDR DW ? ;AN005;bytes TOTAL HEADER SIZE
536PARA_OF_HDR DW ? ;AN005;para. TOTAL HEADER SIZE
537OPEN_FILE_COUNT DW ? ;AN005;TRACKING OF OPEN FLS FOR BUFFER
538; ;SIZE CALCULATION.
539;
540;structured data storage allocation
541FILE_DTA Find_DTA <> ;AN000;DTA for find file
542DTAS Find_DTA 32 dup (<>) ;AN000;DTA STACK for find dir
543;** Througout the program BP will be used for referencing fieldsname in DTAS.
544;For example, DS:[BP].dta_filename.
545DATA ENDS ;AN000;
546
547;******************************************************************************
548
549SELECT SEGMENT PARA PUBLIC 'SELECT';AN000;
550 ASSUME CS:SELECT, DS:DATA ;AN000;
551
552;--- START OF A PROGRAM ---
553
554PUBLIC MOD_XCOPY ;AN000;
555MOD_XCOPY PROC NEAR ;AN000; SAR
556
557
558 PUSH ES ;AN000; SAR
559 PUSH BP ;AN000; SAR
560 ; SAR
561 PUSH DS ;AN000; SAR
562 POP ES ;AN000; SAR
563 MOV SP_SAVE, SP ;AN000; SAR
564 ; SAR
565 MOV SOURCE_IN,YES ;AN111;JW
566 .IF < AL eq 1 > ;AN000;
567 MOV AL,2 ;AN000;
568 .ELSEIF < AL eq 2 > ;AN000;
569 MOV AL,1 ;AN000;
570 .ENDIF ;AN000;
571 MOV DEST,AL ;AN000; SAR
572 MOV TABLE_OFFSET, BX ;AN000; SAR
573 MOV NUMBER_OF_FILES, CX ;AN000; SAR
574 MOV PATH_OFFSET, SI ;AN000; SAR
575 CALL SAVE_DTA ;AN000;
576
577 MOV AH, 62H ;AN000; SAR
578 INT 21H ;AN000; SAR
579 MOV PSP_SEG, BX ;AN000; SAR
580
581 CALL ALLOCATE ;AN000; SAR
582 .IF < C > ;AN000; SAR
583 JMP JUST_EXIT ;AN000; SAR
584 .ENDIF ;AN000; SAR
585
586XCOPY_INIT: ;AN000;
587 CALL INIT ;AN000;initialization
588 JC MAIN_EXIT ;AN000;error. (Already message has been displayed)
589
590 MOV BP, OFFSET DTAS ;AN000;initialize BP
591 OR ACTION_FLAG, READING_FLAG ;AN000;set reading flag for copy message
592
593 CALL TREE_COPY ;AN000;
594
595 CALL ORG_S_DEF ;AN000;restore the original source default dir
596
597 CALL WRITE_FROM_BUFFER ;AN000;write from buffer if we missed it.
598
599 CALL SWITCH_DTAS ;AN111;JW
600
601 CLC ;AN000; SAR
602 JMP RESTORE_DIRS ;AN000; SAR
603
604MAIN_EXIT: ;AN000;
605;;;;; MOV BX, DATA ; SAR
606;;;;; MOV DS, BX ; SAR re initialize ds, es
607;;;;; MOV ES, BX ; SAR exit here if the status of source, target or default drv has been changed.
608;;;;; CALL CHK_FILE_NOT_FOUND ; SAR if no files has been found, show the message.
609
610MAIN_EXIT_A: ;AN000;
611 STC ;AN000; SAR
612
613RESTORE_DIRS:;AN000;
614 MOV BX, DATA ;AN000; SAR
615 MOV DS, BX ;AN000;re initialize ds, es
616 MOV ES, BX ;AN000;exit here if the status of source, target or default drv has been changed.
617;;;;; CALL CHK_MKDIR_LVL ; SAR starting target directory has been created?
618 PUSHF ;AN000; SAR
619 CALL ORG_S_T_DEF ;AN000;restore original target, source, default drv, and verify status
620 POPF ;AN000; SAR
621 JMP DO_DEALLOCATE ;AN000; SAR
622JUST_EXIT: ;AN000;unconditional immediate exit
623 MOV AX, DATA ;AN000; SAR
624 MOV DS, AX ;AN000; SAR
625 STC ;AN000; SAR
626
627DO_DEALLOCATE: ;AN000; SAR
628; Restore the original status of APPEND if active.
629 CALL DEALLOCATE ;AN000; SAR
630 .IF < NC > ;AN000; SAR
631 .IF < NOT_FOUND_FLAG EQ 1 > ;AN000; SAR
632 STC ;AN000; SAR
633 .ELSE ;AN000; SAR
634 CLC ;AN000; SAR
635 .ENDIF ;AN000; SAR
636 .ENDIF ;AN000; SAR
637 MOV SP, SP_SAVE ;AN000; SAR
638 POP BP ;AN000; SAR
639 POP ES ;AN000; SAR
640 RET ;AN000; SAR
641
642; MOV AH, 4Ch ;return to dos
643; MOV AL, ERRORLEVEL ;set return code whatever
644; INT 21H
645
646MOD_XCOPY ENDP;AN000;
647;
648
649
650;----------------- SUBROUTINES ---------------------------------------------
651
652ALLOCATE PROC NEAR ;AN000; SAR
653 ; SAR
654 MOV BX, 0FFFFH ;AN000; SAR Attempt to allocate as much as possible
655 MOV AH, 48H ;AN000; SAR
656 INT 21H ;AN000; SAR
657 MOV AH, 48H ;AN000; SAR BX contains the amount of memory available
658 INT 21H ;AN000; SAR
659 MOV ALLOCATE_START, AX ;AN000; SAR
660 ; SAR
661 RET ;AN000; SAR
662 ; SAR
663ALLOCATE ENDP ;AN000; SAR
664 ; SAR
665DEALLOCATE PROC NEAR ;AN000; SAR
666 ; SAR
667 PUSHF ;AN000; SAR
668 PUSH ES ;AN000; SAR
669 MOV AX, ALLOCATE_START ;AN000; SAR
670 MOV ES, AX ;AN000; SAR
671 MOV AH, 49H ;AN000; SAR
672 INT 21H ;AN000; SAR
673 POP ES ;AN000; SAR
674 POPF ;AN000; SAR
675 ; SAR
676 RET ;AN000; SAR
677 ; SAR
678DEALLOCATE ENDP ;AN000; SAR
679
680
681
682
683TREE_COPY PROC NEAR ;AN000;
684
685;Walk the source tree to read files and subdirectories
686
687 .IF < DEST EQ 1 > ;AN000; SAR Copying to drive b?
688 MOV SI, OFFSET B_TARGET ;AN000; SAR Yes! Copy the drive information
689 MOV CX, LENGTH_B_TARGET ;AN000; SAR
690 .ELSEIF < DEST EQ 3 > ;AN111;JW ; SAR Copying to drive A?
691 MOV SI, OFFSET A_TARGET ;AN111;JW ; SAR Yes! Copy the drive information
692 MOV CX, LENGTH_A_TARGET ;AN111;JW ; SAR
693 .ELSE ;AN000; SAR
694 MOV SI, PATH_OFFSET ;AN000; SAR No! Copy to this directory.
695 MOV CX, WORD PTR [SI] ;AN000; SAR
696 ADD SI, 2 ;AN000; SAR Adjust for the length word
697 .ENDIF ;AN000; SAR
698 MOV DI,OFFSET T_DRV_PATH ;AN000; SAR
699 CLD ;AN000; SAR
700 REP MOVSB ;AN000; SAR
701
702
703
704 OR MY_FLAG, FINDFILE_FLAG ;AN000;deals with files
705 OR MY_FLAG, FIND_FIRST_FLAG ;AN000;find first
706
707 MOV NOT_FOUND_FLAG, 0 ;AN000; SAR
708 ; SAR
709NEXT_PASS: ;AN000; SAR
710 ; SAR
711 MOV SI, TABLE_OFFSET ;AN000; SAR
712 MOV DOS_FILE_PTR,SI ;AN000; SAR
713 MOV FILE_NUM,1 ;AN000; SAR
714
715 CALL SET_MY_DTA ;AN000;set DTA to FILE_DTA
716; $DO
717$$DO1: ;AN000;
718 AND MY_FLAG, RESET_NO_MORE ;AN000; SAR
719 CALL LOAD_DOS_FILENAME ;AN000; SAR
720 TEST MY_FLAG, NO_MORE_FILE ;AN000; SAR
721; $LEAVE NZ ; SAR
722 JNZ $$EN1 ;AN000;
723
724 .IF < SOURCE_IN EQ NO > AND ;AN000;
725 .IF < DEST EQ 3 > ;AN000;
726 CALL GET_SOURCE ;AN000;
727 .ENDIF ;AN000;
728
729 CALL FIND_FILE ;AN000;find first (next) ; SAR
730 .IF < BIT MY_FLAG NAND NO_MORE_FILE > ;AN000; SAR
731 CALL READ_INTO_BUFFER ;AN000; SAR
732 .ELSE ;AN000; SAR
733 MOV NOT_FOUND_FLAG, 1 ;AN000; SAR
734 .ENDIF ;AN000; SAR
735; $ENDDO ; SAR
736 JMP SHORT $$DO1 ;AN000;
737$$EN1: ;AN000;
738 CLC ;AN000; SAR
739
740;  SAR 
741;;;;;; TEST OPTION_FLAG, SLASH_S ;walk the tree?
742; $IF NZ,LONG
743;
744; AND MY_FLAG, RESET_FINDFILE ;now, deals with directory
745; OR MY_FLAG, FIND_FIRST_FLAG ;find first
746; $DO
747; CALL SET_MY_DTA ;set DTA to DTAS according to BP
748; CALL FIND_DIR ;find first (next)
749; TEST MY_FLAG, NO_MORE_FILE ;no more subdirectory?
750; $LEAVE NZ ;then leave this loop to return to caller
751; LEA DI, S_DRV_PATH
752; LEA SI, [BP].DTA_FILENAME
753; CMP S_PATH, 0 ;root directory?
754; $IF E
755; MOV AL, 0FFh ;then '\' is already provided. Just concat.
756; $ELSE
757; MOV AL, PATH_DELIM ;put delimiter
758; $ENDIF
759; CALL CONCAT_ASCIIZ ;make new path
760; test option_flag, slash_p ;prompt mode?
761; $IF NZ
762; call p_concat_display_path
763; $ENDIF
764; INC S_DEPTH ;increase depth
765; CALL MAKE_HEADER ;make header in the buffer
766; OR MY_FLAG, IS_SOURCE_FLAG ;dealing with source
767; AND MY_FLAG, RESET_VISIT_PARENT ;going to visit child node
768; CALL CHANGE_S_DIR ;change source dir
769; ADD BP, type FIND_DTA ;increase DTAS stack pointer
770; CALL TREE_COPY ;tree copy the sub directory
771; $ENDDO
772;
773; CMP S_DEPTH, 0 ;starting directory? then exit
774; $IF NE ;else
775; DEC S_DEPTH ;dec depth
776; TEST OPTION_FLAG, SLASH_E ;copy subdirectories even if empty?
777; $IF Z
778; CALL DEL_EMPTY ;then check the old_buffer_ptr and
779; ;if it is a directory, then restore
780; ;buffer_ptr to old.
781; $ENDIF
782; LEA DI, S_DRV_PATH
783; CALL LAST_DIR_OUT ;change environments
784; test option_flag, slash_p ;prompt mode?
785; $IF NZ
786; call p_cut_display_path
787; $ENDIF
788; LEA DX, S_DRV_PATH ;before returning to the caller
789; OR MY_FLAG, IS_SOURCE_FLAG
790; OR MY_FLAG, VISIT_PARENT_FLAG
791; CALL CHANGE_S_DIR
792; SUB BP, type FIND_DTA
793; $ENDIF
794;;;;;;; $ENDIF ;walk the tree
795 RET ;AN000;
796TREE_COPY ENDP;AN000;
797
798
799GET_SOURCE PROC NEAR;AN000;
800
801 CALL SWITCH_DTAS;AN000;
802
803 .REPEAT ;AN000;
804
805 INIT_PQUEUE PAN_INST_PROMPT ;AN000; initialize queue
806 PREPARE_PANEL SOURCE_PANEL ;AN000; remove select from A: & insert DOS
807 PREPARE_PANEL PAN_HBAR ;AN000;
808 PREPARE_CHILDREN ;AN000; prepare child panels
809 DISPLAY_PANEL ;AN000;
810 ;
811 GET_FUNCTION FK_ENT ;AN000;
812
813 .IF < SOURCE_PANEL eq SUB_REM_DOS_A > ;AN000;
814 LEA DI, S_DOS_SEL_360 ;AN000;
815 .ELSE ;AN000;
816 LEA DI, S_DOS_SHEL_DISK ;AN000;
817 .ENDIF ;AN000;
818 MOV CX, E_FILE_ATTR ;AN000;
819 CALL FIND_FILE_ROUTINE ;AN000;
820 .LEAVE < nc > ;AN000;
821 ;
822 HANDLE_ERROR ERR_DOS_DISK, E_RETURN ;AN000;
823 ;
824 .UNTIL ;AN000;
825
826 ;;;copying files from diskette 1 screen ;
827 INIT_PQUEUE PAN_INSTALL_DOS ;AN000; initialize queue
828 PREPARE_PANEL SUB_COPYING ;AN000; prepare copying from diskette 1 message
829 DISPLAY_PANEL ;AN000;
830
831 MOV SOURCE_IN,YES ;AN000;
832
833 CALL SWITCH_DTAS ;AN000;
834
835 RET ;AN000;
836GET_SOURCE ENDP ;AN000;
837
838GET_DEST PROC NEAR ;AN000;
839
840
841 INIT_PQUEUE PAN_INST_PROMPT ;AN000; initialize queue
842 PREPARE_PANEL DEST_PANEL ;AN000; remove select from A: & insert DOS
843 PREPARE_PANEL PAN_HBAR ;AN000;
844 PREPARE_CHILDREN ;AN000; prepare child panels
845 DISPLAY_PANEL ;AN000;
846 ;
847 GET_FUNCTION FK_ENT ;AN000;
848 ;
849
850 ;;;copying files from diskette 1 screen ;
851 INIT_PQUEUE PAN_INSTALL_DOS ;AN000; initialize queue
852 PREPARE_PANEL SUB_COPYING ;AN000; prepare copying from diskette 1 message
853 DISPLAY_PANEL ;AN000;
854
855 MOV SOURCE_IN,NO ;AN000;
856; SUB DOS_FILE_PTR,12
857; DEC FILE_NUM
858
859 RET ;AN000;
860GET_DEST ENDP ;AN000;
861;
862;******************************************************************************
863; Subroutine: LOAD_DOS_FILENAME - Load the next filename into S_FILE.
864; INPUT:
865; SI - Points to the start of the filename
866;
867; OUTPUT:
868; The S_FILE field in the data segment is updated.
869;Registers Affected:
870; SI - At the end, SI points to the end of the filename. It therefore
871; also points to the beginning of the next filename.
872;
873;******************************************************************************
874LOAD_DOS_FILENAME PROC NEAR;AN000;
875
876 PUSH DI ;AN000;
877 PUSH ES ;AN000;
878
879 OR MY_FLAG, FIND_FIRST_FLAG ;AN000; Find first in the directory
880
881 MOV SI,DOS_FILE_PTR ;AN000;
882
883LDF_SEE_IF_DONE: ;AN000;
884 ;
885 ; See if we are finished this pass of the files
886 ;
887 OR MY_FLAG, NO_MORE_FILE ;AN000; For now, assume there are not files found
888 MOV DX, NUMBER_OF_FILES ;AN000; Get the number of files in the table
889 .IF < FILE_NUM BE DX > ;AN000; Search while there are still more files
890 AND MY_FLAG, RESET_NO_MORE ;AN000; Indicate that there are more files
891 LEA DI,S_FILE ;AN000; Where to put the name
892 MOV CX,12 ;AN000; Number of bytes
893 CLD ;AN000;
894 REP MOVSB ;AN000;
895 INC FILE_NUM ;AN000;
896 .ENDIF ;AN000;
897
898 MOV DOS_FILE_PTR,SI ;AN000; Save the pointer to the files
899 POP ES ;AN000;
900 POP DI ;AN000;
901 RET ;AN000;
902
903LOAD_DOS_FILENAME ENDP ;AN000;
904;
905READ_INTO_BUFFER PROC NEAR ;AN000;
906;Read *** a *** file into buffer
907
908;  SAR 
909; TEST MY_FLAG, SINGLE_COPY_FLAG ;single copy?
910; $IF Z,AND ;no, multi copy
911; TEST ACTION_FLAG, READING_FLAG ;show message?
912; $IF NZ ;yes.
913; MOV AX,MSG_READING_SOURCE ;AN000; message number
914; MOV MSG_NUM,AX ;AN000; set message number
915; MOV SUBST_COUNT,0 ;AN000; no message substitution
916; MOV MSG_CLASS,-1 ;AN000; message class
917; MOV INPUT_FLAG,0 ;AN000; no input
918; MOV AX,MSG_READING_SOURCE
919; CALL PRINT_STDOUT ;show message "Reading source files"
920;
921; AND ACTION_FLAG, RESET_READING ;reset it
922;;;;;;; $ENDIF
923
924 AND FILE_FLAG, RESET_READFILE ;AN000;reset file_flag to read a file
925 MOV AX,FILE_DTA.DTA_FILE_SIZE_HIGH;AN000;
926 MOV HIGH_FILE_SIZE, AX ;AN000;
927 MOV AX,FILE_DTA.DTA_FILE_SIZE_LOW;AN000;
928 MOV LOW_FILE_SIZE, AX ;AN000;
929
930 MOV AX, PARA_OF_HDR ;AN005;GET THE HEADER SIZE (para.)
931 CMP MAX_BUFFER_SIZE,AX ;AN005;IS EA BUFFER TOO LARGE?
932 JB RIB_ERROR ;AN005;CLOSE THE FILE AND GET THE NEXT
933
934 CALL CMP_FILESIZE_TO_BUFFER_LEFT ;AN000;compare sizes
935 TEST FILE_FLAG, FILE_BIGGER_FLAG ;AN000;filesize > buffer_left - header?
936 JZ RIB_SMALL ;AN000;if not, then small file
937 MOV BX, S_HANDLE ;AN005;
938 CALL CLOSE_A_FILE ;AN005;ONLY OPENED TO GET BUFFER SIZE
939 CALL WRITE_FROM_BUFFER;AN000;
940
941 .IF < SOURCE_IN EQ NO > AND ;AN111;JW
942 .IF < DEST EQ 3 > ;AN111;JW
943 CALL GET_SOURCE ;AN111;JW put source diskette in A:
944 .ENDIF ;AN111;JW
945
946; JC RIB_ERROR ;any problem with writing?
947 CALL CMP_FILESIZE_TO_BUFFER_LEFT ;AN000;compare again
948 TEST FILE_FLAG, FILE_BIGGER_FLAG ;AN000;still bigger?
949 JNZ RIB_BIG ;AN000;yes. Big file
950RIB_SMALL: ;AN000;
951 CALL SMALL_FILE;AN000;
952 JC RIB_ERROR ;AN000;
953 JMP RIB_EXIT ;AN000;
954RIB_BIG: ;AN000;
955 MOV BX, S_HANDLE ;AN005;
956 CALL CLOSE_A_FILE ;AN005;ONLY OPENED TO GET BUFFER SIZE
957 CALL BIG_FILE ;AN000;
958 JNC RIB_EXIT ;AN000;
959RIB_ERROR: ;AN000;
960 TEST COPY_STATUS, OPEN_ERROR_FLAG ;AN000;open error?
961 JNZ RIB_EXIT ;AN000;just exit. find next file
962 MOV BX, S_HANDLE ;AN000;else write error
963 CALL CLOSE_A_FILE ;AN000;close the troubled file
964 ;and find next file
965RIB_EXIT: ;AN000;
966 TEST MY_FLAG, SINGLE_COPY_FLAG ;AN000;single copy?
967; $IF NZ
968 JZ $$IF4 ;AN000;
969 CALL WRITE_FROM_BUFFER ;AN000;then write a file
970; $ENDIF
971$$IF4: ;AN000;
972 RET ;AN000;
973READ_INTO_BUFFER ENDP ;AN000;
974;
975
976SMALL_FILE PROC NEAR ;AN000;
977;handles a file smaller than max_buffer_size or buffer_left, i.e. fit in memory.
978;This routine will call MAKE_HEADER, SET_BUFFER_PTR< READ_A_FILE, OPEN_A_FIEL
979;CALC_FILE_SIZE, CMP_FILE_FFD0h, CLOSE_A_FILE.
980
981 TEST FILE_FLAG, BIG_FILE_FLAG ;AN000;called from BIG_FILE?
982 JNZ SMF_CONT ;AN000;then need not open a file again
983 CALL OPEN_A_FILE ;AN000;open a file using FILE_DTA
984 JC SMF_ERROR ;AN000;open error?
985SMF_CONT: ;AN000;
986 CALL CMP_FILE_FFD0h ;AN000;filesize > 0FFD0h ?
987 TEST FILE_FLAG, FILE_BIGGER_FLAG;AN000;
988 JZ SMF_EOF ;AN000;filesize <= 0FFD0h
989 OR FILE_FLAG, CONT_FLAG ;AN000;filesize > 0FFD0h. set cont_flag
990 MOV CX, 0FFD0h ;AN000;# of bytes to read
991 CALL READ_A_FILE;AN000;
992 JC SMF_ERROR ;AN000;unsuccessful read?
993 CALL MAKE_HEADER ;AN000;else make header and ready for next
994 CALL CALC_FILE_SIZE ;AN000;filesize = filesize - bytes read
995 JMP SMF_CONT ;AN000;loop. compare again with the rest
996
997SMF_EOF: ;AN000;
998 MOV CX, LOW_FILE_SIZE ;AN000;rest of the bytes to read
999 OR FILE_FLAG, EOF_FLAG ;AN000;set EOF
1000 CALL READ_A_FILE ;AN000;
1001 JC SMF_ERROR ;AN000;
1002 CALL MAKE_HEADER ;AN000;
1003 MOV BX, S_HANDLE ;AN000;
1004 CALL CLOSE_A_FILE ;AN000;
1005 JMP SMF_EXIT ;AN000;
1006SMF_ERROR: ;AN000;
1007 ;
1008SMF_EXIT: ;AN000;
1009 RET ;AN000;
1010SMALL_FILE ENDP ;AN000;
1011;
1012
1013BIG_FILE PROC NEAR ;AN000;
1014;handles a file which is bigger than max_buffer_size
1015;Needs 2 file handles open concurrently for read and write
1016
1017 OR FILE_FLAG, BIG_FILE_FLAG;AN000;
1018 OR FILE_FLAG, CONT_FLAG;AN000;
1019 CALL OPEN_A_FILE ;AN000;
1020 JC BIF_ERROR ;AN000;error in open?
1021 CMP MAX_BUFFER_SIZE, 0FFFh ;AN000;max buffer size > 0FFFh in para ?
1022 JA BIF_BIG ;AN000;yes. large buffer system
1023 ;else small buffer
1024 MOV CX, MAX_CX ;AN000;CX = max_buffer_size * 16 - 32
1025BIF_SM: ;AN000;
1026 CALL READ_A_FILE;AN000;
1027 JC BIF_ERROR ;AN000;read error?
1028 CALL MAKE_HEADER;AN000;
1029 CALL WRITE_FROM_BUFFER;AN000;
1030 JC BIF_ERROR ;AN000;write error?
1031 TEST FILE_FLAG, EOF_FLAG ;AN000;end of file set by READ_A_FILE?
1032 JZ BIF_SM ;AN000;if not, read again
1033 MOV BX, S_HANDLE;AN000;
1034 CALL CLOSE_A_FILE;AN000;
1035 JMP BIF_EXIT ;AN000;finished.
1036BIF_BIG: ;AN000;
1037 MOV CX, 0FFD0h ;AN000;max # of data bytes this program supports
1038BIF_BIG1: ;AN000;
1039 CALL READ_A_FILE;AN000;
1040 JC BIF_ERROR ;AN000;
1041 CALL MAKE_HEADER;AN000;
1042 CALL CALC_FILE_SIZE ;AN000;modify file size
1043BIF_BIG2: ;AN000;
1044 CALL CMP_FILESIZE_TO_BUFFER_LEFT ;AN000;filesize > buffer_left?
1045 TEST FILE_FLAG, FILE_BIGGER_FLAG ;AN000;yes.
1046 JZ BIF_END ;AN000;if it is not, call small_file
1047 CMP BUFFER_LEFT, 0FFFh ;AN000;BUFFER_LEFT >= 0FFF0h in bytes?
1048 JAE BIF_BIG ;AN000;then loop again.
1049 CMP BUFFER_LEFT, 140H ;AN000;else BUFFER_LEFT >= 5 K in bytes? ;minimum buffer size this program supports.
1050 JL BIF_BIG3 ;AN000;then flush buffer and try again. **IF system buffer left < 5 K then infinit loop can happen.
1051 MOV AX,BUFFER_LEFT;AN000;
1052 SUB AX,PARA_OF_HDR ;AC005;FOR HEADER SIZE para.
1053 MOV CX,BYTS_OF_HDR ;AN005;FOR HEADER SIZE bytes.
1054 JMP BIF_BIG1 ;AN000;read again
1055BIF_BIG3: ;AN000;
1056 CALL WRITE_FROM_BUFFER;AN000;
1057 JC BIF_ERROR ;AN000;
1058 JMP BIF_BIG2 ;AN000;flush buffer and compare again.
1059BIF_END: ;AN000;
1060 CALL SMALL_FILE ;AN000;when filesize <= buffer_left then SMALL_FILE will finish it.
1061 JC BIF_ERROR ;AN000;something wrong?
1062 CALL WRITE_FROM_BUFFER ;AN000;else finish copying this file
1063 JNC BIF_EXIT ;AN000;
1064BIF_ERROR: ;AN000;
1065 ;what happened?
1066BIF_EXIT: ;AN000;
1067 RET ;AN000;
1068BIG_FILE ENDP ;AN000;
1069;
1070MAKE_HEADER PROC NEAR ;AN000;
1071;When called by READ_A_FILE after the data had been read into the buffer, this
1072;routine will put the header which is just below the data area where the
1073;current BUFFER_PTR points. The header is 32 (2 para) byte long. And this
1074;routine will also call SET_BUFFER_PTR to set the BUFFER_PTR, BUFFER_LEFT
1075;for the next process.
1076;If called by TREE_COPY for a SUBDIRECTORY handle, this routine should
1077;check the BUFFER_LEFT (when called by READ_A_FILE, the caller is assumed
1078;to check the size of buffer_left before calling.) In this case, this
1079;routine will set the next BUFFER_PTR, BUFFER_LEFT, OLD_BUFFER_PTR
1080;instead of SET_BUFFER_PTR routine.
1081;Informations are obtained from the DTA area (for file - FILE_DTA.xxx
1082;dir - DS:[BP].xxx ) and stored into the header by referencing ES:field;s name.
1083;DS - Program Data area
1084;ES - will be used for a header segment in the buffer.
1085;
1086 PUSH ES ;AN000;save ES
1087 PUSH AX ;AN000;
1088
1089MH_AGAIN: ;AN000;
1090 MOV AX,BUFFER_PTR ;AN000;buffer_ptr is a segment
1091 MOV ES, AX ;AN000;now, ES is a header seg.
1092;
1093 MOV AX, PARA_OF_HDR ;AN005;GET THE HEADER SIZE (para.)
1094 CMP BUFFER_LEFT,AX ;AC005;buffer_left=less than NEEDED?
1095 JAE MH_START ;AN000;
1096 CALL WRITE_FROM_BUFFER ;AN000;if so, flush buffer
1097 JC MH_ERROR_BRIDGE ;AN000;write error?
1098 JMP SHORT MH_AGAIN ;AN000;reinitialize ES to new buffer ptr
1099MH_START: ;AN000;
1100 TEST MY_FLAG, FINDFILE_FLAG ;AN000;identify caller.
1101 JNZ MH_FILE ;AN000;if a file, jmp to MH_FILE
1102 ;else deals with directory.
1103 MOV ES:CONTINUE_INFO, 0 ;AN000;not a continuation.
1104 MOV AX,OLD_BUFFER_PTR ;AN000;
1105 MOV ES:BEFORE_PTR, AX ;AN000;set before_ptr in header
1106 MOV AX,BUFFER_PTR ;AN000;
1107 MOV OLD_BUFFER_PTR, AX ;AN000;set variable OLD_BUFFER_PTR
1108 ADD AX,PARA_OF_HDR ;AC005;AX = BUFFER_PTR+HEADER(para)
1109 MOV BUFFER_PTR, AX ;AN000;set new BUFFER_PTR
1110 MOV ES:NEXT_PTR, AX ;AN000;set NEXT_PTR in the header
1111 MOV AX, PARA_OF_HDR ;AN005;GET THE HEADER SIZE (para.)
1112 SUB BUFFER_LEFT,AX ;AC005;adjust BUFFER_LEFT
1113 CMP BUFFER_LEFT,AX ;AC005;less than HEADER SIZE (para) ?
1114; $IF B
1115 JNB $$IF6 ;AN000;
1116 MOV BUFFER_LEFT, 0 ;AN000;indicate buffer_full
1117; $ENDIF
1118$$IF6: ;AN000;
1119 MOV AL, S_DEPTH ;AN000;
1120 MOV ES:DIR_DEPTH, AL ;AN000;now save other info's
1121 MOV AL, DS:[BP].DTA_ATTRIBUTE;AN000;
1122 MOV ES:ATTR_FOUND, AL ;AN000;in this case, DIR
1123 MOV AL, BYTE PTR T_DRV;AN000;
1124 MOV ES:TARGET_DRV_LET, AL ;AN000;mov target drive letter
1125 MOV ES:TARGET_DRV_LET+1, DRV_delim ;AN000; ':'
1126 MOV CX, 13 ;AN000;
1127 LEA SI, [BP].DTA_FILENAME ;AN000;DS:SI
1128 MOV DI, OFFSET ES:FILENAME_FOUND ;AN000;ES:DI
1129 REP MOVSB ;AN000;mov sting until cx = 0
1130 JMP MH_EXIT ;AN000;
1131MH_ERROR_BRIDGE: JMP MH_ERROR;AN000;
1132MH_FILE: ;AN000;handles a file header hereafter.
1133 TEST FILE_FLAG, CONT_FLAG ;AN000;continuation?
1134 JZ MH_WHOLE_FILE ;AN000;no, just a whole file
1135 TEST FILE_FLAG, EOF_FLAG ;AN000;Eof flag set?
1136 JNZ MH_CONT_END ;AN000;yes, must be end of continuation
1137 TEST FILE_FLAG, BIG_FILE_FLAG ;AN000;Is this a big file?
1138 JNZ MH_BIG ;AN000;yes
1139 MOV ES:CONTINUE_INFO, 1 ;AN000;else small file continuation.
1140 JMP MH_A_FILE ;AN000;
1141MH_WHOLE_FILE: ;AN000;
1142 MOV ES:CONTINUE_INFO, 0 ;AN000;
1143 JMP MH_A_FILE ;AN000;
1144MH_CONT_END: ;AN000;
1145 MOV ES:CONTINUE_INFO, 3 ;AN000;
1146 JMP MH_A_FILE ;AN000;
1147MH_BIG: ;AN000;
1148 MOV ES:CONTINUE_INFO, 2 ;AN000;
1149MH_A_FILE: ;AN000;
1150 MOV AX,FILE_DTA.DTA_FILE_TIME;AN000;
1151 MOV ES:FILE_TIME_FOUND, AX;AN000;
1152 MOV AX, FILE_DTA.DTA_FILE_DATE;AN000;
1153 MOV ES:FILE_DATE_FOUND, AX;AN000;
1154 MOV AX, FILE_DTA.DTA_FILE_SIZE_LOW;AN000;
1155 MOV ES:LOW_SIZE_FOUND, AX;AN000;
1156 MOV AX, FILE_DTA.DTA_FILE_SIZE_HIGH;AN000;
1157 MOV ES:HIGH_SIZE_FOUND, AX;AN000;
1158 MOV AL, BYTE PTR T_DRV ;AN000;
1159 MOV ES:TARGET_DRV_LET, AL;AN000;
1160 MOV ES:TARGET_DRV_LET+1, DRV_DELIM;AN000;
1161 MOV CX, 13 ;AN000;
1162 MOV SI, OFFSET FILE_DTA.DTA_FILENAME;AN000;
1163 MOV DI, OFFSET ES:FILENAME_FOUND;AN000;
1164 REP MOVSB ;AN000;
1165
1166; Get Extended Attribute list of the opened file and save in attribute buff.
1167
1168; old method
1169; MOV AX,INT_ORDINAL ;AN000; SET THE ORDINAL TO 0
1170; MOV ES:QUERY_LIST,AX ;AN000; PUT IT IN THE BUFFER
1171; MOV AX,SIZ_OF_BUFF ;AN000; SET THE SIZE TO 510 BYTES
1172; MOV ES:BUFR_SIZ,AX ;AN000; PUT IT IN THE BUFFER
1173;
1174; MOV BX,S_HANDLE ;AN000; BX = handle
1175; MOV AX, QUY_ATTRIB ;AN000; extended attribute code 5703H
1176; MOV DI, OFFSET QUERY_LIST ;AN000; ES:DI-->QUERY list
1177; INT 21H ;AN000; get extended attribute list
1178;
1179 MOV BX,S_HANDLE ;AN005; BX = handle
1180 MOV SI,ALL_ATTR ;AN005; SELECT ALL ATTRIBUTES SIZE
1181 MOV CL, PARAGRAPH ;AN005; PARAGRAPH = 4 FOR DIV BY 16
1182 MOV AX,SIZ_OF_BUFF ;AN005; GET THE SIZE EXPRESSED IN para.
1183 SHL AX, CL ;AN005; GET # OF BYTES FROM para.
1184 MOV CX, AX ;AN005; NEEDS TO BE IN CX
1185 MOV DI, OFFSET ES:ATTRIB_LIST ;AN005; ES:DI = E A LIST IN BUFFER
1186 MOV AX, GET_ATTRIB ;AN005; extended attribute code 5702H
1187 INT 21H ;AN005; get extended attribute list
1188
1189; JC MH_ERROR ;AN000; jump if error
1190
1191 MOV AX, OLD_BUFFER_PTR;AN000;
1192 MOV ES:BEFORE_PTR, AX;AN000;
1193 MOV AX, ACT_BYTES;AN000;
1194 MOV ES:CX_BYTES, AX;AN000;
1195 CALL SET_BUFFER_PTR ;AN000;set buffer_ptr for next. AX is already set.
1196 MOV AX, BUFFER_PTR ;AN000;
1197 MOV ES:NEXT_PTR, AX ;AN000;next buffer_ptr is next_ptr
1198 MOV AL, S_DEPTH ;AN000;
1199 MOV ES:DIR_DEPTH, AL ;AN000;same as source depth
1200 MOV AL, FILE_DTA.DTA_ATTRIBUTE;AN000;
1201 MOV ES:ATTR_FOUND, AL ;AN000;attribute found
1202 JMP MH_EXIT ;AN000;
1203MH_ERROR: ;AN000;
1204 OR COPY_STATUS, OPEN_ERROR_FLAG ;AN000;
1205 CALL EXTENDED_ERROR_HANDLER ;AN000;
1206MH_EXIT: ;AN000;
1207 POP AX ;AN000;
1208 POP ES ;AN000;
1209 RET ;AN000;
1210MAKE_HEADER ENDP ;AN000;
1211;
1212
1213OPEN_A_FILE PROC NEAR ;AN000;
1214
1215;-------------------------------------------------------------------------
1216; Use extended open DOS call to open source file,
1217; if successfully open, then save filehand to S_HANDLE.
1218;-------------------------------------------------------------------------
1219; Set drive letter and file name pointer in parameter list
1220 LEA SI,FILE_DTA.DTA_FILENAME ;AN005; DS:SI-->NAME TO OPEN
1221 MOV DX,OPN_FLAG ;AN000; flag = 0101H
1222 MOV CX,OPN_ATTR ;AN000; attribute = 0
1223 MOV BX,OPN_MODE ;AN000; open mode = 0002H
1224 MOV DI, NUL_LIST ;AN005; ES:DI = -1
1225 MOV AX, Ext_Open ;AN000; = 6Ch
1226 INT 21H ;AN000; OPEN SOURCE FILE
1227
1228 JC OF_ERROR;AN000;
1229 MOV S_HANDLE, AX ;AN000;save filehandle
1230 INC OPEN_FILE_COUNT ;AN005;UPDATE THE OPEN FILE COUNTER
1231
1232
1233 JMP OF_EXIT ;AN000; exit
1234
1235OF_ERROR: ;AN000;
1236 OR COPY_STATUS, OPEN_ERROR_FLAG;AN000;
1237 CALL EXTENDED_ERROR_HANDLER;AN000;
1238OF_EXIT: ;AN000;
1239 RET ;AN000;
1240OPEN_A_FILE ENDP;AN000;
1241;
1242
1243
1244CMP_FILE_FFD0h PROC NEAR;AN000;
1245;check whether the filesize in HIGH_FILE_SIZE, LOW_FILE_SIZE is bigger than
1246;0FFD0h. If it is, then set FILE_BIGGER_FLAG, else reset it.
1247 CMP HIGH_FILE_SIZE, 0;AN000;
1248; $IF E,AND
1249 JNE $$IF8 ;AN000;
1250 CMP LOW_FILE_SIZE, 0FFD0h;AN000;
1251; $IF BE
1252 JNBE $$IF8 ;AN000;
1253 AND FILE_FLAG, RESET_FILE_BIGGER ;AN000;filesize <= 0FFD0h
1254; $ELSE
1255 JMP SHORT $$EN8 ;AN000;
1256$$IF8: ;AN000;
1257 OR FILE_FLAG, FILE_BIGGER_FLAG ;AN000;
1258; $ENDIF
1259$$EN8: ;AN000;
1260 RET ;AN000;
1261CMP_FILE_FFD0h ENDP ;AN000;
1262;
1263
1264CALC_FILE_SIZE PROC NEAR ;AN000;
1265;subtract the bytes read (ACT_BYTES) from the filesize in HIGH_FILE_SIZE,
1266;LOW_FILE_SIZE.
1267 MOV AX, ACT_BYTES ;AN000;
1268 SUB LOW_FILE_SIZE, AX ;AN000;
1269 SBB HIGH_FILE_SIZE, 0 ;AN000;
1270 RET ;AN000;
1271CALC_FILE_SIZE ENDP ;AN000;
1272;
1273
1274READ_A_FILE PROC NEAR ;AN000;
1275;read a file.
1276;if after reading, AX < CX or AX = 0 the set EOF_FLAG.
1277;INPUT:CX - # of bytes to read
1278; BUFFER_PTR
1279; S_HANDLE
1280;OUTPUT: ACT_BYTES
1281
1282; .IF < SOURCE_IN EQ NO > AND
1283; .IF < DEST EQ 3 >
1284; CALL GET_SOURCE
1285; .ENDIF
1286
1287 PUSH DS ;AN000;save program data seg
1288 MOV AH, Read;AN000;
1289 MOV BX, S_HANDLE;AN000;
1290 MOV DX, BUFFER_PTR ;AN000;current buffer header seg
1291 ADD DX, PARA_OF_HDR ;AC005;skip the header part
1292 MOV DS, DX ;AN000;now DS = buffer_ptr + 2, data area
1293 XOR DX, DX ;AN000;offset DX = 0
1294 INT 21H ;AN000;
1295 POP DS ;AN000;restore program data area
1296 JC RF_ERROR ;AN000;read error?
1297 CMP AX, CX ;AN000;
1298 JE RF_OK ;AN000;
1299 OR FILE_FLAG, EOF_FLAG ;AN000;EOF reached. AX = 0 or AX < CX
1300RF_OK: ;AN000;
1301 CLC ;AN000;clear carry caused from CMP
1302 MOV ACT_BYTES, AX ;AN000;save actual bytes read
1303 JMP RF_EXIT ;AN000;
1304RF_ERROR: ;AN000;
1305 OR COPY_STATUS, READ_ERROR_FLAG;AN000;
1306 CALL EXTENDED_ERROR_HANDLER;AN000;
1307RF_EXIT: ;AN000;
1308 RET ;AN000;
1309READ_A_FILE ENDP ;AN000;
1310;
1311
1312FIND_IT PROC NEAR ;AN000;
1313;set first or next depending on FIND_FIRST_FLAG.
1314;once called, reset FIND_FIRST_FLAG.
1315 TEST MY_FLAG, FIND_FIRST_FLAG;AN000;
1316; $IF NZ ;yes
1317 JZ $$IF11 ;AN000;
1318 MOV AH, Find_First;AN000;
1319; $ELSE
1320 JMP SHORT $$EN11 ;AN000;
1321$$IF11: ;AN000;
1322 MOV AH, Find_Next;AN000;
1323; $ENDIF
1324$$EN11: ;AN000;
1325 AND MY_FLAG, RESET_FIND_FIRST ;AN000;reset FIND_FIRST_FLAG
1326 INT 21H ;AN000;
1327 RET ;AN000;
1328FIND_IT ENDP ;AN000;
1329;
1330FIND_FILE PROC NEAR ;AN000;
1331;find a file
1332;set NO_MORE_FILE if carry.
1333; $SEARCH
1334
1335; PUSH DS
1336; MOV DX,DATA
1337; MOV DS,DX
1338; .IF < SOURCE_IN EQ NO > AND
1339; .IF < DEST EQ 3 >
1340; CALL GET_SOURCE
1341; .ENDIF
1342; POP DS
1343
1344$$DO14: ;AN000;
1345 TEST MY_FLAG, FIND_FIRST_FLAG ;AN000;find first ?
1346; $IF NZ
1347 JZ $$IF15 ;AN000;
1348 MOV DX, OFFSET S_FILE ;AN000;
1349 MOV CX, File_Search_Attr ;AN000;normal = 0
1350; $ELSE
1351 JMP SHORT $$EN15 ;AN000;
1352$$IF15: ;AN000;
1353 MOV DX, OFFSET FILE_DTA ;AN000;
1354; $ENDIF
1355$$EN15: ;AN000;
1356 CALL FIND_IT ;AN000;
1357; $EXITIF C
1358 JNC $$IF14 ;AN000;
1359 OR MY_FLAG, NO_MORE_FILE ;AN000;no more file in this directory
1360; $ORELSE
1361 JMP SHORT $$SR14 ;AN000;
1362$$IF14: ;AN000;
1363 MOV FOUND_FILE_FLAG, 1 ;AN000;set the flag for "File not found" msg.
1364 OR MY_FLAG, FOUND_FLAG ;AN000; SAR
1365;;;;;;; CALL FILTER_FILES ;found. filter it with options
1366 TEST MY_FLAG, FOUND_FLAG ;AN000;
1367; $ENDLOOP NZ ;if found, leave this loop else start again
1368 JZ $$DO14 ;AN000;
1369 AND MY_FLAG, RESET_NO_MORE;AN000;
1370; $ENDSRCH
1371$$SR14: ;AN000;
1372 RET ;AN000;
1373FIND_FILE ENDP ;AN000;
1374;
1375SET_MY_DTA PROC NEAR ;AN000;
1376;set DS:DX for find_first(next). If MY_FLAG is set to FINDFILE_FLAG then
1377;set it to the offset FILE_DTA, otherwise to BP.
1378;DS should be set to the area whre FILE_DTA, DTAS are.
1379 PUSH DX ;AN000;save current DX
1380 TEST MY_FLAG, FINDFILE_FLAG ;AN000;handling file?
1381; $IF NZ
1382 JZ $$IF22 ;AN000;
1383 MOV DX, OFFSET FILE_DTA;AN000;
1384; $ELSE
1385 JMP SHORT $$EN22 ;AN000;
1386$$IF22: ;AN000;
1387 MOV DX, BP ;AN000;
1388; $ENDIF
1389$$EN22: ;AN000;
1390 MOV AH, Set_DTA ;AN000;
1391 INT 21H ;AN000;
1392 POP DX ;AN000;
1393 RET ;AN000;
1394SET_MY_DTA ENDP ;AN000;
1395;
1396;
1397SAVE_DTA PROC NEAR ;AN000;
1398; Save old DTA address
1399 PUSH ES ;AN000;
1400 PUSH BX ;AN000;
1401 MOV AH, Get_DTA ;AN000;
1402 INT 21H ;AN000;
1403 MOV OLD_DTA_SEG,ES ;AN000;
1404 MOV OLD_DTA_OFF,BX ;AN000;
1405 POP BX ;AN000;
1406 POP ES ;AN000;
1407 RET ;AN000;
1408SAVE_DTA ENDP ;AN000;
1409;
1410;
1411SWITCH_DTAS PROC NEAR ;AN000;
1412; SWITCH DTA ADDRESSES
1413 PUSH DS ;AN000;
1414 PUSH DX ;AN000;
1415 PUSH OLD_DTA_SEG ;AN000;
1416 PUSH OLD_DTA_OFF ;AN000;
1417 CALL SAVE_DTA ;AN000;
1418 POP DX ;AN000;
1419 POP DS ;AN000;
1420 MOV AH, Set_DTA ;AN000;
1421 INT 21H ;AN000;
1422 POP DX ;AN000;
1423 POP DS ;AN000;
1424SWITCH_DTAS ENDP ;AN000;
1425;
1426;
1427CHANGE_T_DIR PROC NEAR ;AN000;
1428;change target dir according to t_drv_path.
1429;Since this routine is called by WRITE_FROM_BUFFER and DS now points
1430;to buffer area while ES points to the program data area, we set DS
1431;to data seg again here for the function call Chdir.
1432 PUSH DS ;AN000;save current buffer seg
1433 PUSH ES ;AN000;currentpy es is a data seg
1434 POP DS ;AN000;restore DS value as program data seg
1435
1436 CMP T_DRV[2], 0 ;AN000;LAST_DIR_OUT took '\' out?
1437; $IF E
1438 JNE $$IF25 ;AN000;
1439 MOV T_DRV[2], '\' ;AN000;then put it back for root dir
1440 MOV T_DRV[3], 0 ;AN000;
1441; $ENDIF
1442$$IF25: ;AN000;
1443
1444 MOV DX, OFFSET T_DRV_PATH ;AN000;
1445 MOV AH, CHDIR ;AN000;
1446 INT 21H ;AN000;
1447
1448 POP DS ;AN000;restore caller's DS value
1449 RET ;AN000;
1450CHANGE_T_DIR ENDP;AN000;
1451;
1452
1453CMP_FILESIZE_TO_BUFFER_LEFT PROC NEAR;AN000;
1454;Compare buffer_left (paragraph) with filesize (high_file_size, low_file_size.)
1455;if filesize is bigger than buffer_left, then set FILE_BIGGER_FLAG
1456;indicating filesize > buffer_left.
1457 PUSH DX ;AN000;
1458 PUSH AX ;AN000;
1459
1460 CMP OPEN_FILE_COUNT,NUL ;AN005;ARE THERE ANY OPEN FILES
1461; $IF Z ;AN005;NO, THEN GO AHEAD AND OPEN
1462 JNZ $$IF28A ;AN000;
1463 CALL OPEN_A_FILE ;AN005;OPEN A FILE USING FILE_DTA
1464
1465; Get extended Attribute list size.
1466
1467 MOV BX,S_HANDLE ;AN005; BX = handle
1468 MOV AX, GET_ATTRIB ;AN005; extended attribute code 5702H
1469 MOV SI,ALL_ATTR ;AN005; SELECT ALL ATTRIBUTES SIZE
1470 XOR CX,CX ;AN005; JUST QUERY SIZE NEEDED
1471 MOV DI, OFFSET NUL_LIST ;AN005; DI = LIST FOR NO DATA RETURNED
1472 INT 21H ;AN005; get extended attribute SIZE
1473 ADD CX,PARA_BOUND ;AN005; TO FIGURE THE NEXT PARAGRAPH
1474 MOV AX,CX ;AN005;
1475 MOV CL,PARAGRAPH ;AN005; GET PARAGRAPHS (DIV BY 16)
1476 SHR AX,CL ;AN005;
1477 MOV SIZ_OF_BUFF,AX ;AN005;SAVE BUFF SIZE FOR THE HEADER
1478 ADD AX,FIXD_HD_SIZ ;AN005;GET THE TOTAL HEADER SIZE
1479 MOV PARA_OF_HDR,AX ;AN005;SAVE FOR LATER
1480 SHL AX, CL ;AN005;CONVERT BACK TO TOTAL BYTES
1481 MOV BYTS_OF_HDR,AX ;AN005;SAVE FOR LATER
1482 MOV BX,S_HANDLE ;AN005;
1483 CALL CLOSE_A_FILE ;AN005;CLOSE THE FILE OPENED
1484; $ENDIF
1485$$IF28A: ;AN000;
1486
1487 AND FILE_FLAG, RESET_FILE_BIGGER;AN000;
1488 MOV AX,PARA_OF_HDR ;AN005;GET THE HEADER SIZE (para.)
1489 CMP BUFFER_LEFT,AX ;AC005;buffer_left >= HEADER SIZE
1490; $IF AE
1491 JNAE $$IF27 ;AN000;
1492 MOV AX, BUFFER_LEFT ;AN000;buffer_left in para
1493 SUB AX,PARA_OF_HDR ;AC005;consider header size in advance
1494 MOV CX, 16 ;AN000;
1495 MUL CX ;AN000;* 16. result in DX;AX
1496 CMP HIGH_FILE_SIZE, DX;AN000;
1497; $IF A ;if high_filesize > dx
1498 JNA $$IF28 ;AN000;
1499 OR FILE_FLAG, FILE_BIGGER_FLAG;AN000;
1500; $ELSE
1501 JMP SHORT $$EN28;AN000;
1502$$IF28: ;AN000;
1503; $IF E
1504 JNE $$IF30 ;AN000;
1505 CMP LOW_FILE_SIZE, AX;AN000;
1506; $IF A
1507 JNA $$IF31 ;AN000;
1508 OR FILE_FLAG, FILE_BIGGER_FLAG;AN000;
1509; $ENDIF
1510$$IF31: ;AN000;
1511; $ENDIF
1512$$IF30: ;AN000;
1513; $ENDIF
1514$$EN28: ;AN000;
1515; $ELSE
1516 JMP SHORT $$EN27 ;AN000;
1517$$IF27: ;AN000;
1518 OR FILE_FLAG, FILE_BIGGER_FLAG ;AN000;buffer_left < 2
1519; $ENDIF
1520$$EN27: ;AN000;
1521 POP AX ;AN000;
1522 POP DX ;AN000;
1523 RET ;AN000;
1524CMP_FILESIZE_TO_BUFFER_LEFT ENDP ;AN000;
1525;
1526
1527SET_BUFFER_PTR PROC NEAR ;AN000;
1528;set BUFFER_PTR, BUFFER_LEFT, OLD_BUFFER_PTR in paragraph boundary
1529;to be used when reading a file into buffer.
1530;this routine uses current BUFFER_PTR to figure out the next BUFFER_PTR.
1531;So, at initialization time set BUFFER_PTR to CS, and set AX to the offset
1532;of INIT, then thr resultant BUFFER_PTR indicates the BUFFER_BASE and
1533;OLD_BUFFER_PTR indicates CS.(This means if old_buffer_ptr = cs, then
1534;it is the start of buffer)
1535;To get the next BUFFER_PTR during multi-copy, just set the AX to the
1536;number of bytes read. This routine will add 32 bytes for header size and
1537;will set the next BUFFER_PTR.
1538;input: AX - offset of buffer
1539; Top_of_memory in segment
1540; current BUFFER_PTR
1541; current OLD_BUFFER_PTR
1542; current BUFFER_LEFT
1543;output: BUFFER_PTR for next reading
1544; OLD_BUFFER_PTR
1545; BUFFER_LEFT (Top_of_memory - Buffer_Ptr. If it is 0, then indicates
1546; the BUFFER is FULL. In this case, the BUFFER_PTR is
1547; invalid, but OLD_BUFFER_PTR keep the former buffer_ptr
1548; value which says that it is the last header in the buffer)
1549;** Currently this program support maxium top of memory in seg 0FFFF - resident
1550; area. This routine will check the overflow case to gaurd the next buffer_ptr
1551; not to exceed FFFF.
1552
1553 PUSH CX ;AN000;
1554 MOV CX, BUFFER_PTR ;AN000;
1555 MOV OLD_BUFFER_PTR, CX ;AN000;set old_buffer_ptr
1556 MOV CL, 4 ;AN000;
1557 SHR AX, CL ;AN000;get paragraphs
1558 INC AX ;AN000;get next paragraph
1559 ADD AX,PARA_OF_HDR ;AC005;consider header size
1560 ADD BUFFER_PTR, AX ;AN000;add this to the current buffer_ptr
1561
1562; $IF NC,AND ;not exceed 16 bit.
1563 JC $$IF37 ;AN000;
1564 MOV AX, Top_of_memory;AN000;
1565 SUB AX, BUFFER_PTR ;AN000;AX = Top_of_memory - Buffer_ptr
1566; $IF A ;if buffer_left > 0
1567 JNA $$IF37 ;AN000;
1568 MOV BUFFER_LEFT, AX;AN000;
1569; $ELSE
1570 JMP SHORT $$EN37 ;AN000;
1571$$IF37: ;AN000;
1572 MOV BUFFER_LEFT, 0 ;AN000;indication of buffer full
1573; $ENDIF
1574$$EN37: ;AN000;
1575 POP CX ;AN000;
1576 RET ;AN000;
1577SET_BUFFER_PTR ENDP ;AN000;
1578;
1579
1580WRITE_FROM_BUFFER PROC NEAR ;AN000;
1581;Write from the first header starting at buffer_base until finishes
1582;the last header which, actually, happens to be the old_buffer_ptr
1583;at the time of the call. After the writing, reset the buffer_ptr
1584;to buffer_base again for the next read_into_buffer.
1585;If continue_info is 1 or 2 (Continue of small, bigfile) then after
1586;the creation of a target file, it will set the CREATED_FLAG.
1587;This flag will be reset when it found the continue_info to be 3
1588;(End of contine).
1589;For convenience of use of function call, ES will be used for
1590;the program data seg while DS will be used for the BUFFER seg.
1591;
1592 PUSH DS ;AN000;
1593 PUSH ES ;AN000;save ds, es
1594
1595 PUSH DS ;AN000;
1596 POP ES ;AN000;set ES to program data seg
1597
1598 OR ACTION_FLAG, READING_FLAG ;AN000;show reading message next time
1599; AND ES:MY_FLAG, RESET_IS_SOURCE ;now, deals with target
1600 ;set this for change_dir
1601 MOV AX, ES:BUFFER_BASE ;AN000;
1602 MOV DS, AX ;AN000;
1603 PUSH CS ;AN000;
1604 POP AX ;AN000;
1605 CMP ES:OLD_BUFFER_PTR, AX ;AN000;if old_buffer_ptr = CS then
1606 ;buffer is empty. Just exit
1607 JE WFB_EXIT_BRIDGE ;AN000;
1608
1609 PUSH DS ;AN000;
1610 MOV DX,DATA ;AN000;
1611 MOV DS,DX ;AN000;
1612 .IF < DEST eq 3 > ;AN000;
1613 CALL GET_DEST ;AN000;
1614 .ENDIF ;AN000;
1615 POP DS ;AN000;
1616
1617WFB_CD: ;AN000;
1618 CALL CHANGE_T_DIR ;AN000;
1619 JC WFB_ERROR_BRIDGE ;AN000;error?
1620WFB_CHATT: ;AN000;
1621 CMP DS:ATTR_FOUND, Is_subdirectory ;AN000;a subdirectory? = 10H
1622 JNE WFB_FILE ;AN000;no. a file
1623
1624WFB_CMP_DEPTH: ;AN000;
1625;  SAR 
1626;;;;;;;
1627; MOV AH, ES:T_DEPTH ;yes. a subdir.
1628; CMP DS:DIR_DEPTH, AH ;DIR_DEPTH > T_DEPTH ?
1629; JBE WFB_DEC_DEPTH ;if not, go to parent node
1630; LEA DI, ES:T_DRV_PATH ;else goto child node
1631; LEA SI, DS:FILENAME_FOUND
1632; CMP ES:T_PATH, 0 ;root directory?
1633; $IF E
1634; MOV AL, 0FFh ;then don't need to put delim since it is already there
1635; $ELSE
1636; MOV AL, Path_delim ;path_delim '\'
1637; $ENDIF
1638; CALL CONCAT_ASCIIZ
1639; call concat_display_path ;modify the path for display
1640; INC ES:T_DEPTH
1641; CALL MAKE_DIR ;try to make a new sub directory
1642; JC WFB_EXIT_A_BRIDGE ;there exists a file with same name.
1643; MOV AX, DS ;current buffer seg = old_buffer_ptr?
1644; CMP ES:OLD_BUFFER_PTR, AX
1645; JNE WFB_NEXT ;not finished yet. jmp to next
1646; OR ES:MY_FLAG, MISSING_LINK_FLAG ;Finished. Missing link condition occurred regarding empty sub dir
1647; JMP WFB_EXIT_A ;check archieve options.
1648WFB_NEXT: ;AN000;
1649; MOV DS, DS:NEXT_PTR ;let's handles next header.
1650; JMP WFB_CD ;change directory first.
1651WFB_EXIT_BRIDGE: JMP WFB_EXIT;AN000;
1652WFB_ERROR_BRIDGE: JMP WFB_ERROR;AN000;
1653WFB_EXIT_A_BRIDGE: JMP WFB_EXIT_A;AN000;
1654WFB_DEC_DEPTH: ;AN000;
1655; LEA DI, ES:T_DRV_PATH
1656; CALL RM_EMPTY_DIR ;check flags and remove empty dir
1657; CALL LAST_DIR_OUT ;take off the last dir from path
1658; call cut_display_path ;modify path for display purpose
1659;;;;;; DEC ES:T_DEPTH ;and decrease depth
1660 JMP WFB_CD ;AN000;CHANGE DIR AND compare the depth again.
1661
1662
1663WFB_FILE: ;AN000;Handling a file
1664 AND ES:MY_FLAG, RESET_MISSING_LINK ;AN000;if found a file, then current dir is not empty.
1665 TEST ES:FILE_FLAG, CREATED_FLAG ;AN000; A file handle is created ?
1666 JNZ WFB_WRITE ;AN000;yes, skip create again.
1667 CALL CREATE_A_FILE ;AN000;create a file in the cur dir
1668 JC WFB_ERROR ;AN000;file creation error?
1669WFB_WRITE: ;AN000;
1670 CALL WRITE_A_FILE;AN000;
1671 JC WFB_EXIT_A ;AN000;target file has been already deleted.
1672 CMP DS:CONTINUE_INFO, 0;AN000;
1673; $IF E,OR ;if continue_info = 0 or 3
1674 JE $$LL40 ;AN000;
1675 CMP DS:CONTINUE_INFO, 3;AN000;
1676; $IF E
1677 JNE $$IF40 ;AN000;
1678$$LL40: ;AN000;
1679 MOV BX, ES:T_HANDLE;AN000;
1680 CALL SET_FILE_DATE_TIME ;AN000;then set file's date, time
1681 PUSH DS ;AN005;SAVE THE BUFFER PTR
1682 PUSH ES ;AN005;WE NEED THE DATA PTR
1683 POP DS ;AN005;DS = THE DATA PTR
1684 CALL CLOSE_A_FILE ;AN000;and close the handle
1685 POP DS ;AN005;DS = THE BUFFER PTR AGAIN
1686;;;;;;; CALL RESTORE_FILENAME_FOUND ; SAR if filename_found has been changed, restore it for reset_s_archieve.
1687 AND ES:FILE_FLAG, RESET_CREATED ;AN000;and reset created_flag
1688 CALL INC_FILE_COUNT ;AN000;increase file count
1689; $ENDIF
1690$$IF40: ;AN000;
1691 MOV AX, DS ;AN000;
1692 CMP ES:OLD_BUFFER_PTR, AX ;AN000;current header is the last one?
1693 JE WFB_EXIT_A ;AN000;then exit
1694 MOV DS, DS:NEXT_PTR ;AN000;else set ds to the next ptr
1695 JMP WFB_CHATT ;AN000;handle the next header
1696WFB_ERROR: ;AN000;
1697 jmp main_exit ;AN000;meaningful when MKDIR failed because
1698 ;of there already exist same named file,
1699 ;or disk_full case.
1700WFB_EXIT_A: ;AN000;
1701 test ES:option_flag, slash_m ;AN000;hard archieve ? - turn off source archieve bit.
1702 jz wfb_exit_B ;AN000;no, chk error flag and exit
1703;;;; call reset_s_archieve ; SAR reset source file(s) archieve bit using header info(s).
1704WFB_EXIT_B: ;AN000;
1705 test ES:copy_status, mkdir_error_flag ;AN000;mkdir error happened?
1706 JNZ WFB_ERROR ;AN000;yes, exit
1707 test ES:copy_status, disk_full_flag ;AN000;disk full happened?
1708 JNZ WFB_ERROR ;AN000;yes, exit
1709WFB_EXIT: ;AN000;
1710 MOV ES:OLD_BUFFER_PTR, CS ;AN000;set old_buffer_ptr to CS
1711 MOV AX, ES:BUFFER_BASE ;AN000;
1712 MOV ES:BUFFER_PTR, AX ;AN000;set buffer_ptr to base
1713 MOV AX, ES:MAX_BUFFER_SIZE;AN000;
1714 MOV ES:BUFFER_LEFT, AX ;AN000;set buffer_left
1715 POP ES ;AN000;
1716 POP DS ;AN000;
1717;;;; TEST SYS_FLAG, ONE_DISK_COPY_FLAG ; SAR one drive letter copy?
1718; ; $IF NZ ; SAR yes
1719; ; CALL CHANGE_S_DIR ; SAR then change current dir to s dir
1720;;;; $ENDIF
1721 RET ;AN000;
1722WRITE_FROM_BUFFER ENDP ;AN000;
1723;
1724INC_FILE_COUNT PROC NEAR;AN000;
1725;increase the file count by one.
1726;increase file_cnt_low, file_cnt_high.
1727;input: DS - buffer
1728; ES - data seg
1729 INC ES:FILE_CNT_LOW ;AN000;
1730 JNZ IFC_EXIT ;AN000;
1731 INC ES:FILE_CNT_HIGH ;AN000;if carry over, then inc file_cnt_high
1732IFC_EXIT: ;AN000;
1733 RET ;AN000;
1734INC_FILE_COUNT ENDP ;AN000;
1735;
1736CREATE_A_FILE PROC NEAR;AN000;
1737;create a file in the header and return the file handle in T_HANDLE.
1738;Set CREATED_FLAG. This will be reset by WRITE_FROM_BUFFER when it
1739;close the handle.
1740;this routine will check the T_FILENAME and T_TEMPLATE if any target
1741;filename has been entered. If T_FILENAME is there, then DX will
1742;points to this (This is the case when the user has specified non_global
1743;chr filename and any source filename be changed to this name.)
1744;If T_TEMPLATE is present, then modify the filename found in the
1745;header part.
1746;Also, this routine show copy messages just before a file creation using
1747;FILENAME_FOUND.
1748;ES - data seg
1749;DS - buffer seg
1750
1751 PUSH DS ;AN000;
1752 PUSH ES ;AN000;
1753
1754;  SAR  ;save the original filename from the header
1755;;;;; MOV CX, 13 ;max 13 chr
1756; LEA SI, DS:FILENAME_FOUND ;original source file name
1757; LEA DI, ES:DISP_S_FILE ;filename to be displayed
1758; REP MOVSB ;filename_found => disp_s_file
1759;;;;; test es:option_flag, slash_p ; SAR
1760;;;;; $IF Z ; SAR
1761;;;;; CALL SHOW_COPY_MESSAGE ; SAR he source path, file
1762;;;;; $ENDIF ; SAR
1763;
1764; CMP ES:T_FILENAME, 0
1765; $IF NE ;non_global target filename entered.
1766; TEST ES:COPY_STATUS, MAYBE_ITSELF_FLAG
1767; $IF NZ
1768; LEA SI, DS:FILENAME_FOUND
1769; LEA DI, ES:T_FILENAME
1770; CALL COMP_FILENAME ;compare it. if same then show
1771; ;file cannot be copied onto itself and
1772; ;abort
1773; $ENDIF
1774;
1775; CALL SWITCH_DS_ES ;now ds - data, es - buffer
1776; MOV CX, 13
1777; LEA SI, DS:T_FILENAME
1778; LEA DI, ES:FILENAME_FOUND
1779; REP MOVSB ; t_filename => filename_found
1780; CALL SWITCH_DS_ES ;now ds - buffer, es - data seg
1781;
1782; $ELSE
1783; CMP ES:T_TEMPLATE, 0 ;global chr target filename entered?
1784; $IF NE ;yes, entered. modify the filename found
1785;;;;; CALL MODIFY_FILENAME ; SAR
1786; TEST ES:COPY_STATUS, MAYBE_ITSELF_FLAG
1787; $IF NZ
1788; LEA SI, DS:FILENAME_FOUND ;compare the Revised filename
1789; LEA DI, ES:DISP_S_FILE ;with original name
1790; CALL COMP_FILENAME ;if same, then issue error message and exit
1791; $ENDIF
1792; $ELSE
1793; TEST ES:COPY_STATUS, MAYBE_ITSELF_FLAG ;*.* CASE
1794; $IF NZ
1795; PUSH ES
1796; POP DS ;ds - data seg
1797;
1798; ; Set message parameters
1799;;;;; MOV AX,MSG_COPY_ITSELF ; SAR
1800; MOV MSG_NUM,AX ; SAR ;AN000; set message number
1801; MOV SUBST_COUNT,0 ; SAR AN000; no message subst.
1802; MOV MSG_CLASS,-1 ; SAR AN000; message class
1803; MOV INPUT_FLAG,0 ; SAR AN000; no user input
1804; CALL PRINT_STDERR ; SAR AN000; display error
1805; JMP MAIN_EXIT
1806; $ENDIF
1807; $ENDIF
1808;;;;;; $ENDIF
1809
1810;-------------------------------------------------------------------------
1811; Use extended open DOS call to create the target file, use attribute list
1812; obtained from the previous Get Extended attribute DOS call
1813;-------------------------------------------------------------------------
1814
1815; SET ATTRIBUTE LIST POINTER IN PARAMETER LIST
1816 MOV DX, OFFSET DS:ATTRIB_LIST ;AN005;E A BUFFER IN HEADER
1817 MOV WORD PTR ES:E_A_LST,DX ;AN005; set offset
1818 MOV WORD PTR ES:E_A_LST+WORD,DS ;AN005; set segment
1819
1820 MOV AX, Ext_Open ;AN000; = 6Ch
1821 MOV DX,CREATE_FLAG ;AN000; flag = 0111H
1822 MOV BX,CREATE_MODE ;AN000;CREATE MODE = 0011H
1823 MOV CX,CREATE_ATTR ;AN000; attribute = 0
1824 MOV SI,OFFSET TARGET_DRV_LET ;AN005; DS:SI-->NAME TO CREATE
1825 LEA DI,ES:PARAM_LIST ;AN005;PARAMETER LIST (ES:DI)
1826 INT 21H ;AN000; create file
1827
1828 JC CAF_ERROR ;AN000;
1829 MOV ES:T_HANDLE, AX ;AN000;save handle
1830
1831;;;;; CALL CHK_T_RES_DEVICE ; SAR check target handle is a reserved dev
1832
1833 OR ES:FILE_FLAG, CREATED_FLAG ;AN000;set created_flag
1834 JMP CAF_EXIT ;AN000;
1835CAF_ERROR: ;AN000;
1836 PUSH DS ;AN000;
1837 PUSH ES ;AN000;
1838 POP DS ;AN000;
1839 OR COPY_STATUS, CREATE_ERROR_FLAG;AN000;
1840 CALL EXTENDED_ERROR_HANDLER ;AN000;
1841 POP DS ;AN000;
1842CAF_EXIT: ;AN000;
1843 POP ES ;AN000;
1844 POP DS ;AN000;
1845 RET ;AN000;
1846CREATE_A_FILE ENDP ;AN000;
1847;
1848;COMP_FILENAME PROC NEAR
1849;;this routine is called when MAYBE_COPY_ITSELF flag in on.
1850;;SI, DI asciiz string will be compared and if they are identical
1851;;the show "Cannot copy onto itself" msg and jmp to main_exit.
1852;;INPUT: DS - buffer
1853;; ES - data seg
1854;
1855; CLD
1856; MOV AL, 0
1857; PUSH DI ;save DI
1858; CALL STRING_LENGTH ;CX get the length of string
1859; MOV BX, CX ;now, BX got the length of the target filename entered.
1860; PUSH BX ;save BX
1861; PUSH ES ;save ES
1862;
1863; PUSH DS
1864; POP ES ;now ES set to DS
1865; PUSH SI
1866; POP DI ;now DI points to the source filename found.
1867;
1868; MOV AL, 0
1869; CALL STRING_LENGTH ;CX got the length of the string
1870;
1871; POP ES ;restore ES
1872; POP BX ;restore BX
1873; POP DI ;restore DI
1874; ;;
1875; CMP BX, CX ;COMPARE LENGTH
1876; JNE CF_EXIT ;IF THEY ARE DIFFERENT, EXIT
1877;
1878; REPE CMPSB ;compare SI, DI until not equal,
1879; CMP CX, 0 ;finish at cx = 0?
1880; JE CF_SAME
1881; JMP SHORT CF_EXIT
1882;CF_SAME:
1883; PUSH ES
1884; POP DS ;ds = data seg
1885;
1886;; Set message parameters
1887;;;;;; MOV AX,MSG_COPY_ITSELF ; SAR ;AN000; message number
1888;; MOV MSG_NUM,AX ; SAR AN000; set message number
1889;; MOV SUBST_COUNT,0 ; SAR AN000; no message substitution
1890;; MOV MSG_CLASS,-1 ; SAR AN000; message class
1891;;; MOV INPUT_FLAG,0 ; SAR AN000; no input
1892;; CALL PRINT_STDERR ; SAR AN000; display error message
1893; JMP MAIN_EXIT
1894;CF_EXIT:
1895; RET
1896;COMP_FILENAME ENDP
1897;;
1898WRITE_A_FILE PROC NEAR ;AN000;
1899;write a file from the data area in the buffer.
1900;Remember the caller is WRITE_FROM_BUFFER which use ES for
1901;the program data area and DS for the header in the buffer.
1902 MOV AH, Write ;AN000; = 40h
1903 MOV BX, ES:T_HANDLE ;AN000;handle saved in the program data area
1904 MOV DX, ES:BYTS_OF_HDR ;AC005;skip header
1905 MOV CX, DS:CX_BYTES ;AN000;get the # from the header
1906 INT 21h ;AN000;
1907 JC WAF_ERROR ;AN000;write error
1908 CMP AX, DS:CX_BYTES;AN000;
1909 JNE WAF_DISKFULL;AN000;
1910 JMP WAF_EXIT ;AN000;
1911WAF_ERROR: ;AN000;
1912 CALL CLOSE_DELETE_FILE ;AN000;close delete troubled file
1913 OR COPY_STATUS, WRITE_ERROR_FLAG;AN000;
1914 CALL SWITCH_DS_ES ;AN000;DS = DATA SEG, ES = BUFFER
1915 CALL EXTENDED_ERROR_HANDLER;AN000;
1916 CALL SWITCH_DS_ES ;AN000;ES = DATA SEG, DS = BUFFER
1917WAF_DISKFULL: ;AN000;
1918; MOV ERRORLEVEL, 4 ; SAR ;set errorlevel
1919
1920; Set message parameters
1921; Target disk full, critical error
1922
1923 PUSH DS ;AN000;DS = BUFFER
1924 PUSH ES ;AN000;ES = DATA SEG
1925 POP DS ;AN000;ES => DS = DATA SEG
1926;;;;; MOV AX,MSG_DISK_FULL ; SAR ;AN000; message number
1927; MOV MSG_NUM,AX ; SAR AN000; set message number
1928; MOV SUBST_COUNT,0 ; SAR AN000; no message substitution
1929; MOV MSG_CLASS,UTILITY_MSG_CLASS ; SAR AN000; message class
1930; MOV INPUT_FLAG,0 ; SAR AN000; no input
1931; CALL PRINT_STDERR ; SAR AN000; display error message
1932 OR COPY_STATUS, DISK_FULL_FLAG ;AN000;set disk_full_flag
1933 POP DS ;AN000;RESTORE DS = BUFFER
1934 CALL CLOSE_DELETE_FILE;AN000;
1935 STC ;AN000;set carry and return to caller
1936WAF_EXIT:;AN000;
1937 RET ;AN000;
1938WRITE_A_FILE ENDP;AN000;
1939;
1940SET_FILE_DATE_TIME PROC NEAR;AN000;
1941;input: BX - target file handle
1942;
1943 MOV AH, File_date_time ;AN000; = 57h
1944 MOV AL, Set_file_time ;AN000; = 1
1945 MOV CX, DS:FILE_TIME_FOUND;AN000;
1946 MOV DX, DS:FILE_DATE_FOUND;AN000;
1947 INT 21h ;AN000;
1948 RET ;AN000;
1949SET_FILE_DATE_TIME ENDP;AN000;
1950;
1951CLOSE_A_FILE PROC NEAR ;AN000;
1952;INPUT: BX - file handle to be closed
1953 CMP OPEN_FILE_COUNT,NUL ;AN005;ARE THERE ANY OPEN FILES?
1954; $IF A ;AN005;
1955 JNA $$IF42A ;AN000;
1956 DEC OPEN_FILE_COUNT ;AN005;IF SO, REDUCE THE COUNT BY 1.
1957; $ENDIF ;AN005;
1958$$IF42A: ;AN000;
1959 MOV AH, Close ;AN000; = 3Eh
1960 INT 21H ;AN000;
1961 RET ;AN000;
1962CLOSE_A_FILE ENDP ;AN000;
1963;
1964DELETE_A_FILE PROC NEAR;AN000;
1965;input: DS:DX - points to ASCIIZ string
1966
1967 MOV AH, 41h ;AN000; = 41h
1968 INT 21H ;AN000;
1969 RET ;AN000;
1970DELETE_A_FILE ENDP;AN000;
1971;
1972;
1973;CHK_DISK_FULL PROC NEAR
1974;check target disk space, and if no more clusters then set carry, disk_full_flag.
1975;this routine is called by MAKE_DIR routine.
1976;INPUT: DS - buffer
1977; ES - data seg
1978; PUSH AX
1979; PUSH BX
1980; PUSH CX
1981; PUSH DX
1982; MOV AH, 36h ;GET DISK FREE SPACE
1983; MOV DL, ES:T_DRV_NUMBER ;OF TARGET
1984; INT 21h
1985; CMP BX, 0 ;NO MORE CLUSTER?
1986; JE CDF_FULL
1987; CLC
1988; JMP SHORT CDF_EXIT
1989;CDF_FULL:
1990; OR ES:COPY_STATUS, DISK_FULL_FLAG ;SET DISK FULL FLAG
1991; STC ;SET CARRY
1992;CDF_EXIT:
1993; POP DX
1994; POP CX
1995; POP BX
1996; POP AX
1997; RET
1998;
1999;CHK_DISK_FULL ENDP
2000;;
2001;;subttl string_length
2002;page
2003;******************************************************************************
2004;PURPOSE: Get the length of a string pointed by ES:DI until it encounters
2005; the same character given by the user in AL.
2006; The length will be an output in CX. The number includes the
2007; charater found.
2008; For example, if you want to determine the length of an ASCIIZ string,
2009; set ES:DI to that string and set AL to 0. The output CX is the
2010; total length of the ASCIIZ string including 0.
2011; So, if the first character pointed by DI is the same as that of AL,
2012; then the length will be 1.
2013; !!! It is the user's responsibility to make it sure that the string
2014; contains the character given in AL. If not, unpredictable
2015; results will occur.!!!
2016;
2017; DATA INPUT
2018; REGISTERS: AL - ASCII CHARACTER
2019; ES:DI - POINTER TO THE STRING.
2020; DATA OUTPUT
2021; REGISTERS: AX,DX,SI etc - PRESERVED.
2022; BX - DISTROYED
2023; CX - STRING LENGTH UNTIL FOUND THE GIVEN CHARACTER.
2024; DI - POINTS TO THE NEXT CHARACTER AFTER THE STRING.
2025; DIRECTION FLAG - CLEARED
2026; ZERO FLAG - RESET
2027;******************************************************************************
2028;
2029;STRING_LENGTH PROC NEAR
2030;PUBLIC STRING_LENGTH
2031; CLD ;CLEAR DIRECTION
2032; MOV BX,DI ;SAVE ORIGINAL DI VALUE
2033; MOV CX,80H ;TRY MAX 128 BYTES
2034; REPNE SCASB ;SCAN THE STRING UNTIL FOUND
2035; PUSH DI ;SAVE CURRENT DI VALUE WHICH POINTS TO NEXT CHR AFTER STRING
2036; SUB DI,BX ;GET THE LENGTH
2037; MOV CX,DI ;MOV THE LENGTH TO CX
2038; POP DI
2039; RET
2040;STRING_LENGTH ENDP
2041;
2042;subttl concat_asciiz
2043;page
2044;******************************************************************************
2045;PURPOSE: Concatenate two ASCIIZ string into one ASCIIZ string.
2046; The ASCIIZ string pointed by DS:SI will be concatenated to
2047; the one pointed by ES:DI. The result string will be pointed by
2048; ES:DI.
2049; AL is used to put the delimeter character in between the strings.
2050; If you *DON'T* like to put the delimeter ***make AL to 0FFh***.
2051; For example, assume sting1 "ABCDE",0 pointed by DI and string2
2052; "FGHI",0 pointed by SI.
2053; If you want a delimeter "\" between two string, set AL to "\"
2054; before calling. The result will "ABCDE\FGHI",0 pointed by DI.
2055; If you set AL to "0FFh", then it becomes "ABCDEFGHI",0.
2056; This feature is useful for handling PATH if you set AL to "\"
2057; and, for any general string processes if you set AL to "0FFh".
2058; This routine will call subroutine STRING_LENGTH.
2059;DATA INPUT
2060; REGISTERS: AL - DELIMETER OR 0FFh
2061; ES:DI - POINTER TO THE DESTINATION STRING.
2062; DS:SI - POINTER TO THE SOURCE TO BE CONCATENATED.
2063;DATA OUTPUT
2064; REGISTERS: AL, DX - preserved
2065; DI - preserved. POINTER TO THE RESULT STRING
2066; SI - DISTROYED
2067; CX - RESULT ASCIIZ STRING LENGTH INCLUDE 0
2068; DIRECTION FLAG - CLEARED
2069;******************************************************************************
2070;CONCAT_ASCIIZ PROC NEAR
2071;
2072;PUBLIC CONCAT_ASCIIZ
2073; PUSH DI ;SAVE POINTER VALUE WHICH WILL BE RETRUNED TO CALLER.
2074; PUSH AX ;SAVE VALUE IN AL.
2075; MOV AL, 0 ;DEALING WITH ASCIIZ STRING
2076; CALL STRING_LENGTH ;LET DI POINTS TO THE NEXT CHR AFTER THIS STRING
2077; ;DIRECTION WILL BE CLEARED.
2078; DEC DI ;MAKE DI POINT TO THE LAST CHARACTER 0
2079; POP AX ;RESTORE AL.
2080; CMP AL, 0FFh
2081;; $IF NE ;IF THE USER WANTS TO PUT DIMIMETER,
2082; JE $$IF42
2083; STOSB ; REPLACE 0 WITH IT.
2084;; $ELSE
2085; JMP SHORT $$EN42
2086;$$IF42:
2087; DEC CX ;ELSE DECREASE LENGTH BY 1
2088;; $ENDIF
2089;$$EN42:
2090;; $DO
2091;$$DO45:
2092; LODSB ;MOV [SI] TO AL
2093; STOSB ;STORE AL TO [DI]
2094; INC CX ;INCREASE LENGTH
2095; CMP AL, 0 ;WAS IT A LAST CHARACTER?
2096;; $ENDDO E ;THEN EXIT THIS LOOP
2097; JNE $$DO45
2098; POP DI
2099; RET
2100;CONCAT_ASCIIZ ENDP
2101;;
2102;
2103;subttl last_dir_out
2104;page
2105;******************************************************************************
2106;PURPOSE: Take off the last directory name from the path pointed by DI.
2107; This routine assumes the pattern of a path to be an ASCIIZ string
2108; in the form of "[d:][\]dir1\dir2". Notice that this path does not
2109; have entailing "\". This routine will simply travel the string
2110; until it found last "\" which will, then, be replaced with 0.
2111; If no "\" found, then carry will be set.
2112; *** This should be not be used for the path in the form of
2113; *** "d:\", 0 for the root directory, since in this case the returned
2114; *** string will be "d:",0 and AX value returned be meaningless (Just
2115; *** points to 0.)
2116;DATA INPUT
2117; REGISTERS: DI - points to an ASCIIZ path string.
2118; ES - assumed default segment for DI
2119;DATA OUTPUT
2120; REGISTERS: DI - points to the resultant path string.
2121; AX - offset value of the last subdirectory name taken out, in case
2122; of the user's need.
2123; Other register will be unchanged.
2124; CARRY FLAG WILL SET IF NOT FOUND.
2125;******************************************************************************
2126;
2127;LAST_DIR_OUT PROC NEAR
2128;PUBLIC LAST_DIR_OUT
2129;
2130; PUSH DI
2131; PUSH SI ;save current DI, SI
2132; CLD ;clear direction
2133; MOV SI, 0FFFFh ;used as a not_found flag if unchanged.
2134;; $DO
2135;$$DO47:
2136; MOV AL, 0
2137; SCASB
2138;; $LEAVE Z ;if [DI] = 0, then end of string. Ends this loop.
2139; JZ $$EN47
2140; DEC DI ;if [DI] <> 0, then go back and scan char again
2141; MOV AL, "\" ;to see it was a back slash.
2142; SCASB
2143;; $IF Z ;if it was, then save the addr to SI.
2144; JNZ $$IF49
2145; PUSH DI
2146; POP SI
2147;
2148; DEC SI
2149;; $ENDIF ;else do loop again.
2150;$$IF49:
2151;; $ENDDO
2152; JMP SHORT $$DO47
2153;$$EN47:
2154; CLC ;clear carry flag.
2155; CMP SI, 0FFFFh ;Had SI been changed?
2156;; $IF E
2157; JNE $$IF52
2158; STC ;No, set the carry. Not found.
2159;; $ELSE
2160; JMP SHORT $$EN52
2161;$$IF52:
2162; MOV BYTE PTR ES:[SI], 0 ;Yes, replace "\" with 0. Seg override to get default DI seg.
2163; MOV AX, SI
2164; INC AX ;let AX have the last dir offset value.
2165; CLC ;clear carry
2166;; $ENDIF
2167;$$EN52:
2168; POP SI ;restore original value
2169; POP DI ;original string offset
2170; RET
2171;LAST_DIR_OUT ENDP
2172;;
2173;
2174SET_DEFAULT_DRV PROC NEAR;AN000;
2175;change source drv as a default drv for conveniece of find, read operation
2176;of source. (handling target should be more specific as for as drive letter
2177;goes.)
2178;input: DL - drive # (0 = A, 1 = B ...)
2179
2180 MOV AH, Select_Disk ;AN000; = 0Eh
2181 INT 21H ;AN000;
2182 OR SYS_FLAG, DEFAULT_DRV_SET_FLAG ;AN000;indicates default drv has been changed
2183 ;Used for exit the program to restore default drv
2184 RET ;AN000;
2185SET_DEFAULT_DRV ENDP ;AN000;
2186;
2187ORG_S_DEF PROC NEAR ;AN000;
2188;restore the original source directory.
2189 PUSH ES ;AN000;
2190 PUSH DS ;AN000;
2191
2192 PUSH DS ;AN000;
2193 POP ES ;AN000;DS=ES=data seg
2194
2195 TEST SYS_FLAG, DEFAULT_S_DIR_FLAG ;AN000;source default direcotry saved?
2196; $IF NZ
2197 JZ $$IF55 ;AN000;
2198 MOV DX, OFFSET SAV_S_DRV ;AN000;saved source drive letter & directory
2199 MOV AH, 3Bh ;AN000;
2200 INT 21h ;AN000;restore source
2201 AND SYS_FLAG, RESET_DEFAULT_S_DIR ;AN000;reset the flag
2202; $ENDIF
2203$$IF55: ;AN000;
2204
2205 POP DS ;AN000;
2206 POP ES ;AN000;
2207
2208 RET ;AN000;
2209ORG_S_DEF ENDP ;AN000;
2210;
2211ORG_S_T_DEF PROC NEAR ;AN000;
2212;retore original target, source and default drv and directory
2213;check default_s(t)_dir_flag, default_drv_set_flag to restore source,
2214;or target directory and default drive.
2215
2216 TEST SYS_FLAG, TURN_VERIFY_OFF_FLAG ;AN000;turn off verify?
2217; $IF NZ ;yes
2218 JZ $$IF57 ;AN000;
2219 MOV AX, 2E00h ;AN000;turn it off
2220 INT 21H ;AN000;
2221; $ENDIF
2222$$IF57: ;AN000;
2223
2224 TEST SYS_FLAG, DEFAULT_DRV_SET_FLAG ;AN000;default drive has been changed?
2225; $IF NZ ;yes
2226 JZ $$IF59 ;AN000;
2227 MOV DL, SAV_DEFAULT_DRV ;AN000;
2228 DEC DL ;AN000;
2229 CALL SET_DEFAULT_DRV ;AN000;restore default drv.
2230
2231; Following is a fix for PTR 0000012 . The fix is to skip changing default
2232; drive directory if source drive is not the default drive.
2233
2234 MOV AL, S_DRV_NUMBER ;AN002; get source drive number
2235 CMP AL, SAV_DEFAULT_DRV ;AN002; src drive is the default drv ?
2236 JNE SKIP_CH_DIR ;AN002; no, dont change directory
2237
2238 MOV DX, OFFSET SAV_DEF_DIR_ROOT;AN000;
2239 MOV AH, Chdir ;AN000;
2240 INT 21H ;AN000;restore current dir of default dir
2241SKIP_CH_DIR: ;AN000;
2242; $ENDIF
2243$$IF59: ;AN000;
2244
2245 TEST SYS_FLAG, DEFAULT_S_DIR_FLAG ;AN000;source default direcotry saved?
2246; $IF NZ
2247 JZ $$IF61 ;AN000;
2248 MOV DX, OFFSET SAV_S_DRV ;AN000;saved source drive letter & directory
2249 MOV AH, 3Bh ;AN000;
2250 INT 21h ;AN000;restore source. This is for the case of ERROR exit.
2251; $ENDIF
2252$$IF61: ;AN000;
2253
2254 TEST SYS_FLAG, DEFAULT_T_DIR_FLAG ;AN000;target default directory saved?
2255; $IF NZ ;then assume both source, target default saved
2256 JZ $$IF63 ;AN000;
2257 MOV DX, OFFSET SAV_T_DRV ;AN000;saved target drive letter & directory
2258 MOV AH, 3Bh ;AN000;
2259 INT 21h ;AN000;restore target
2260; $ENDIF
2261$$IF63: ;AN000;
2262
2263 RET ;AN000;
2264ORG_S_T_DEF ENDP ;AN000;
2265;
2266EXTENDED_ERROR_HANDLER PROC NEAR;AN000;
2267;This routine calls fun 59(Get extended error) and
2268;check the actions returned. If it is Immediate exit, then jmp to JUST_EXIT
2269;If it is abort, then jmp to MAIN_EXIT.
2270;Or else, it check the COPY_STATUS flag. If is not open, read, create or
2271;write, then it is considered as a critical error and jmp to MAIN_EXIT.
2272;If access denied
2273; too many open files
2274; sharing violation
2275; lock violation
2276; general failure
2277;then show the message and jmp to the MAIN_EXIT.
2278; *** Currently, this routine directly jump to the main_exit instead of
2279; *** returing to the caller. The reason is we regard the above error conditions
2280; *** as being not suitable to continue copying and, hence, to simplify
2281; *** the error process.
2282;INPUT:
2283; DS - DATA SEG
2284;OUTPUT:
2285; ALL THE REG PRESERVED
2286
2287GOTO_MAIN_EXIT: ;AN000;
2288 JMP MAIN_EXIT ;AN000;restore conditions
2289 ;and exit
2290QUICK_EXIT: ;AN000;
2291 JMP JUST_EXIT ;AN000;immediate exit
2292
2293 RET ;AN000;
2294
2295EXTENDED_ERROR_HANDLER ENDP;AN000;
2296;
2297CLOSE_DELETE_FILE PROC NEAR;AN000;
2298;when writing error occurs, then this routine is called to
2299;clean up the troubled target file.
2300;INPUT: DS - buffer seg
2301; ES - data seg
2302
2303 MOV BX, ES:T_HANDLE ;AN000;close target file
2304 PUSH DS ;AN005;SAVE THE BUFFER PTR
2305 PUSH ES ;AN005;WE NEED THE DATA PTR
2306 POP DS ;AN005;DS = THE DATA PTR
2307 CALL CLOSE_A_FILE;AN000;
2308 POP DS ;AN005;DS = THE BUFFER PTR AGAIN
2309 LEA DX, DS:target_drv_let ;AN000;target drv, filename
2310 CALL DELETE_A_FILE ;AN000;delete it
2311 RET ;AN000;
2312CLOSE_DELETE_FILE ENDP;AN000;
2313;
2314;
2315
2316SWITCH_DS_ES PROC NEAR;AN000;
2317; switch DS, ES
2318 PUSH DS ;AN000;
2319 PUSH ES ;AN000;
2320 POP DS ;AN000;
2321 POP ES ;AN000;
2322 RET ;AN000;
2323SWITCH_DS_ES ENDP ;AN000;
2324;
2325;
2326INIT PROC NEAR ;AN000;
2327
2328 CALL GET_CUR_DRV ;AN000;save current default drv
2329 MOV DL, SAV_DEFAULT_DRV;AN000;
2330 LEA SI, SAV_DEFAULT_DIR;AN000;
2331
2332 CALL GET_CUR_DIR ;AN000;save current default dir
2333 CALL GET_DRIVES ;AN000; SAR
2334 CALL TOP_OF_MEM ;AN000;set top_of_memory
2335 CALL INIT_BUFFER ;AN000;init buffer information
2336
2337 MOV DL, T_DRV_NUMBER ;AN000; SAR
2338 .IF < DL AE 3 > ;AN000; SAR
2339 LEA SI, SAV_T_CURDIR ;AN000; SAR
2340 CALL GET_CUR_DIR ;AN000; SAR
2341 OR SYS_FLAG, DEFAULT_T_DIR_FLAG ;AN000; SAR
2342 .ELSE ;AN000; SAR
2343 AND SYS_FLAG, NOT DEFAULT_T_DIR_FLAG ;AN000; SAR
2344 .ENDIF ;AN000; SAR
2345
2346
2347 MOV DL, S_DRV_NUMBER;AN000;
2348 DEC DL ;AN000;
2349 CALL SET_DEFAULT_DRV ;AN000;set source as a default drv
2350 CLC ;AN000;
2351 RET ;AN000;
2352INIT ENDP ;AN000;
2353;
2354GET_DRIVES PROC NEAR ;AN000;
2355;get source and target phisical drive letter from parser area.
2356;set ONE_DISK_COPY_FLAG, if the user XCOPY using the same drive letter.
2357
2358;;;;; MOV AL, SO_DRIVE ;AN000;source drive letter
2359; CMP AL,SPACE ;AN000;IS DRIVE LETTER BLANK?
2360; $IF E ;AN000;YES, GET THE DEFAULT
2361; MOV AL, SAV_DEFAULT_DRV ;(1=A, 2=B,...)
2362; $ELSE ;AN000;NO, CHANGE FROM CHAR TO #
2363; SUB AL,BASE_OF_ALPHA_DRV ;AN000;NEED THE DRV # HERE
2364; $ENDIF
2365
2366 MOV AL, 1 ;AN000; SAR A is the source drive
2367 MOV S_DRV_NUMBER, AL ;AN000;SAVE DRV #
2368 ADD AL, BASE_OF_ALPHA_DRV;AN000;
2369
2370 MOV S_DRV, AL ;AN000;save source drive letter
2371 MOV S_DRV_1, AL;AN000;
2372;; MOV S_ARC_DRV, AL ; SAR
2373 MOV SAV_S_DRV, AL;AN000;
2374
2375 .IF < DEST eq 3 > ;AN111;JW
2376 MOV AL,0 ;AN111;JW
2377 .ELSE ;AN111;JW
2378 MOV AL, DEST ;AN000; SAR target drive letter
2379 .ENDIF ;AN111;JW
2380 INC AL ;AN000; SAR
2381;;;;; CMP AL,SPACE ;AN000;IS DRIVE LETTER BLANK?
2382; ; $IF E ;AN000;YES, GET THE DEFAULT
2383; ; MOV AL, SAV_DEFAULT_DRV ;(1=A, 2=B,...)
2384; ; $ELSE ;AN000;NO, CHANGE FROM CHAR TO #
2385; ; SUB AL,BASE_OF_ALPHA_DRV ;AN000;NEED THE DRV # HERE
2386;;;;; $ENDIF
2387 MOV T_DRV_NUMBER, AL ;AN000;save target drv #
2388
2389;;;;; CMP S_DRV_NUMBER, AL ;s_drv_number = t_drv_number?
2390; ; $IF E
2391; ; OR SYS_FLAG, ONE_DISK_COPY_FLAG ;same logical drv copy
2392;;;;; $ENDIF
2393
2394 ADD AL, BASE_OF_ALPHA_DRV ;AN000;make target drv # to drive letter
2395 MOV T_DRV, AL ;AN000;target drive letter
2396;; MOV T_DRV_1, AL ; SAR
2397;; MOV T_DRV_2, AL ; SAR
2398 MOV SAV_T_DRV, AL;AN000;
2399 RET ;AN000;
2400GET_DRIVES ENDP ;AN000;
2401;
2402GET_CUR_DRV PROC NEAR;AN000;
2403;get the current default drive number (0 = A, 1 = B ..),
2404;change it to BIOS drive number and save it.
2405 MOV AH, Current_Disk ;AN000; = 19h
2406 INT 21h ;AN000;
2407 INC AL ;AN000;(1 = A, 2 = B ..)
2408 MOV SAV_DEFAULT_DRV, AL ;AN000;save it
2409 RET ;AN000;
2410GET_CUR_DRV ENDP ;AN000;
2411;
2412GET_CUR_DIR PROC NEAR ;AN000;
2413;get current directory and save it
2414;input: DL - drive # (0 = default, 1 = A etc)
2415; DS:SI - pointer to 64 byte user memory
2416
2417 MOV AH, Get_Current_Directory;AN000;
2418 INT 21H ;AN000;
2419 RET ;AN000;
2420GET_CUR_DIR ENDP ;AN000;
2421;
2422TOP_OF_MEM PROC NEAR ;AN000;
2423;set Top_of_memory
2424 PUSH ES ;AN000;
2425 MOV BX, PSP_SEG ;AN000;
2426 MOV ES, BX ;AN000;
2427 MOV AX, ES:2 ;AN000;PSP top of memory location
2428 SUB AX, 100H ;AN000;subtract dos transient area (4k)
2429 MOV TOP_OF_MEMORY, AX ;AN000;save it for buffer top
2430 POP ES ;AN000;
2431 RET ;AN000;
2432TOP_OF_MEM ENDP ;AN000;
2433
2434INIT_BUFFER PROC NEAR ;AN000;
2435;initialize buffer information
2436;set buffer_base, max_buffer_size
2437; call set_block ;SET BLOCK FOR BUFFR (for new 3.2 linker)
2438 MOV AX, 0 ;AN000; SAR
2439;;;; PUSH CS ; SAR cs segment is the highest segment in this program
2440;;;; POP DX ; SAR
2441 MOV DX, ALLOCATE_START ;AN000; SAR
2442 MOV BUFFER_PTR, DX ;AN000;
2443 CALL SET_BUFFER_PTR ;AN000;
2444 MOV AX, BUFFER_PTR ;AN000;
2445 MOV BUFFER_BASE, AX ;AN000;set buffer_base
2446 MOV AX, BUFFER_LEFT ;AN000;
2447 CMP AX, 140h ;AN000;BUFFER_LEFT < 5K which is the minimum size this program supports?
2448 JAE IB_CONT ;AN000;
2449;;;;;; PUSH AX ; SAR ;AN000;
2450; MOV AX, MSG_INSUF_MEMORY ; SAR ;AC000;GET THE MESSAGE ID
2451; MOV MSG_NUM,AX ; SAR ;AN000;NEED MESSAGE ID FOR PRINT
2452; MOV SUBST_COUNT,NUL ; SAR ;AN000;NO SUBSTITUTION TEXT
2453; MOV INPUT_FLAG,NUL ; SAR ;AN000;NO INPUT = 0
2454; MOV MSG_CLASS,UTILITY_MSG_CLASS ; SAR ;AN000;MESSAGE CLASS = -1
2455; CALL PRINT_STDERR ; SAR ;print error. AX points to message ID
2456; POP AX ; SAR ;AN000;
2457; MOV ERRORLEVEL, 4 ; SAR ;abnormal termination
2458 JMP MAIN_EXIT_A ;AN000;terminate this program
2459IB_CONT: ;AN000;
2460 MOV MAX_BUFFER_SIZE, AX ;AN000;set max buffer size in para
2461 CMP AX, 0FFFh ;AN000;max_buffer_size > 64 K in para ?
2462; $IF B
2463 JNB $$IF65 ;AN000;
2464 MOV CX, 16;AN000;
2465 MUL CX ;AN000;AX = AX * 16 (DX part will be 0)
2466 SUB AX, 544 ;AN000;AN000;subtrack header size
2467 MOV MAX_CX, AX ;AN000;this will be max_cx
2468; $ELSE
2469 JMP SHORT $$EN65 ;AN000;
2470$$IF65: ;AN000;
2471 MOV MAX_CX, 0FFD0h ;AN000;else max_cx = fff0 - 32 bytes
2472 ;which is the max # this program can support.
2473; $ENDIF ;(min # this program support for buffer is 5 k
2474$$EN65: ;AN000;
2475 ; which has been decided by BIG_FILE )
2476 RET ;AN000;
2477INIT_BUFFER ENDP ;AN000;
2478
2479
2480
2481SELECT ENDS ;AN000;
2482
2483 END ;AN000;
2484