summaryrefslogtreecommitdiff
path: root/v4.0/src/CMD/COMMAND/COPY.ASM
blob: 37bb8867f6f1910cdb7628a056347a03e461072f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
 page 80,132
;	SCCSID = @(#)copy.asm	1.1 85/05/14
;	SCCSID = @(#)copy.asm	1.1 85/05/14
TITLE	COMMAND COPY routines.

; MODIFICATION HISTORY
;
;   11/01/83 EE  Added a few lines at the end of SCANSRC2 to get multiple
;		 file concatenations (eg copy a.*+b.*+c.*) to work properly.
;   11/02/83 EE  Commented out the code in CPARSE which added drive designators
;		 to tokens which begin with path characters so that PARSELINE
;		 will work correctly.
;   11/04/83 EE  Commented out the code in CPARSE that considered paren's to be
;		 individual tokens.  That distinction is no longer needed for
;		 FOR loop processing.
;   11/17/83 EE  CPARSE upper case conversion is now flag dependent.  Flag is
;		 1 when Cparse is called from COPY.
;   11/17/83 EE  Took out the comment chars around code described in 11/04/83
;		 mod.  It now is conditional on flag like previous mod.
;   11/21/83 NP  Added printf
;   12/09/83 EE  CPARSE changed to use CPYFLAG to determine when a colon should
;		 be added to a token.
;   05/30/84 MZ  Initialize all copy variables.  Fix confusion with destclosed
;		 NOTE: DestHand is the destination handle.  There are two
;		 special values:  -1 meaning destination was never opened and
;		 0 which means that the destination has been openned and
;		 closed.
;   06/01/84 MZ  Above reasoning totally specious.  Returned things to normal
;   06/06/86 EG  Change to fix problem of source switches /a and /b getting
;		 lost on large and multiple file (wildcard) copies.
;   06/09/86 EG  Change to use xnametrans call to verify that source and
;		 destination are not equal.


.xlist
.xcref
	INCLUDE comsw.asm
	INCLUDE DOSSYM.INC
	INCLUDE comseg.asm
	INCLUDE comequ.asm
.list
.cref


DATARES 	SEGMENT PUBLIC BYTE	;AC000;
	EXTRN	VERVAL:WORD
	EXTRN	RSRC_XA_SEG:WORD	;AN030;
DATARES ENDS

TRANDATA	SEGMENT PUBLIC BYTE	;AC000;
	EXTRN	BADCD_ptr:word
	EXTRN	COPIED_ptr:word
	EXTRN	Extend_buf_ptr:word	;AN000;
	EXTRN	Extend_buf_sub:byte	;AN000;
	EXTRN	file_name_ptr:word
	EXTRN	INBDEV_ptr:word 	;AC000;
	EXTRN	msg_disp_class:byte	;AN000;
	EXTRN	overwr_ptr:word
TRANDATA	ENDS

TRANSPACE	SEGMENT PUBLIC BYTE	;AC000;
	EXTRN	ALLSWITCH:WORD
	EXTRN	ARGC:BYTE
	EXTRN	ASCII:BYTE
	EXTRN	BINARY:BYTE
	EXTRN	BYTCNT:WORD
	EXTRN	CFLAG:BYTE
	EXTRN	comma:byte
	EXTRN	CONCAT:BYTE
	EXTRN	concat_xa:byte		;AN000;
	EXTRN	copy_num:word		;AC000;
	EXTRN	CPDATE:WORD
	EXTRN	CPTIME:WORD
	EXTRN	cpyflag:byte		;AC000;
	EXTRN	CURDRV:BYTE
	EXTRN	DESTBUF:BYTE
	EXTRN	DestClosed:BYTE
	EXTRN	DESTFCB:BYTE
	EXTRN	DESTFCB2:BYTE
	EXTRN	DESTHAND:WORD
	EXTRN	DESTINFO:BYTE
	EXTRN	DESTISDIR:BYTE
	EXTRN	DESTSIZ:BYTE
	EXTRN	DESTSWITCH:WORD
	EXTRN	DESTTAIL:WORD
	EXTRN	DESTVARS:BYTE
	EXTRN	DIRBUF:BYTE
	EXTRN	expand_star:byte
	EXTRN	FILECNT:WORD
	EXTRN	FIRSTDEST:BYTE
	EXTRN	FRSTSRCH:BYTE
	EXTRN	INEXACT:BYTE
	EXTRN	MELCOPY:BYTE
	EXTRN	MELSTART:WORD
	EXTRN	msg_flag:byte		;AN022;
	EXTRN	NOWRITE:BYTE
	EXTRN	NXTADD:WORD
	EXTRN	objcnt:byte
	EXTRN	one_char_val:byte	;AN000;
	EXTRN	parse_last:word 	;AN018;
	EXTRN	PLUS:BYTE
	EXTRN	plus_comma:byte
	EXTRN	RDEOF:BYTE
	EXTRN	RESSEG:WORD
	EXTRN	SCANBUF:BYTE
	EXTRN	SDIRBUF:BYTE
	EXTRN	src_xa_size:word	;AN000;
	EXTRN	src_xa_seg:word 	;AN000;
	EXTRN	SRCBUF:BYTE
	EXTRN	SRCHAND:WORD
	EXTRN	SRCINFO:BYTE
	EXTRN	SRCISDEV:BYTE
	EXTRN	SRCPT:WORD
	EXTRN	SRCSIZ:BYTE
	EXTRN	SRCTAIL:WORD
	EXTRN	SRCVARS:BYTE
	EXTRN	srcxname:byte
	EXTRN	STARTEL:WORD
	EXTRN	string_ptr_2:word
	EXTRN	TERMREAD:BYTE
	EXTRN	TPA:WORD
	EXTRN	USERDIR1:BYTE
	EXTRN	WRITTEN:WORD
	EXTRN	xa_cp_out:byte		;AN030;
	EXTRN	xa_list_attr:word	;AC030;
TRANSPACE	ENDS


; ******************************************
; COPY CODE
;

TRANCODE	SEGMENT PUBLIC BYTE

	EXTRN	CERROR:NEAR
	EXTRN	COPERR:NEAR
	EXTRN	TCOMMAND:NEAR

	PUBLIC	COPY

ASSUME	CS:TRANGROUP,DS:TRANGROUP,ES:TRANGROUP,SS:NOTHING
	break	Copy
assume	ds:trangroup,es:trangroup

COPY:
; First order of buisness is to find out about the destination
;
; initialize all internal variables
;
	xor	ax,ax
	mov	copy_num,ax
	mov	SrcPt,AX
	mov	SrcTail,AX
	mov	CFlag,AL
	mov	NxtAdd,AX
	mov	DestSwitch,AX
	mov	StartEl,AX
	mov	DestTail,AX
	mov	DestClosed,AL
	mov	DestSiz,AL
	mov	SrcSiz,AL
	mov	DestInfo,AL
	mov	SrcInfo,AL
	mov	InExact,AL
	mov	DestVars,AL
	mov	SrcVars,AL
	mov	UserDir1,AL
	mov	NoWrite,AL
	mov	RdEOF,AL
	mov	SrcHand,AX
	mov	CpDate,AX
	mov	CpTime,AX
	mov	xa_list_attr,ax 		;AN030; initialize code page to none
	mov	SrcIsDev,AL
	mov	TermRead,AL
	mov	comma,al			;g
	mov	plus_comma,al			;g
	mov	msg_flag,al			;AN022;
	mov	[ALLSWITCH],AX			; no switches
	mov	[ARGC],al			; no arguments
	mov	[PLUS],al			; no concatenation
	mov	[BINARY],al			; Binary not specifically specified
	mov	[ASCII],al			; ASCII not specifically specified
	mov	[FILECNT],ax			; No files yet
	mov	[WRITTEN],ax			; Nothing written yet
	mov	[CONCAT],al			; No concatenation
	mov	[MELCOPY],al			; Not a Mel Hallerman copy
	mov	[concat_xa],al			;AN000; initialize flag for concatenation XA
	mov	MelStart,ax			; Not a Mel Hallerman copy
	mov	word ptr [SCANBUF],ax		; Init buffer
	mov	word ptr [DESTBUF],ax		; Init buffer
	mov	word ptr [SRCBUF],ax		; Init buffer
	mov	word ptr [SDIRBUF],ax		; Init buffer
	mov	word ptr [DIRBUF],ax		; Init buffer
	mov	word ptr [DESTFCB],ax		; Init buffer
	mov	objcnt,al			; Init command line object count
	dec	ax
	mov	DestHand,AX			; destination has never been opened
	mov	[FRSTSRCH],al			; First search call
	mov	[FIRSTDEST],al			; First time
	mov	[DESTISDIR],al			; Don't know about dest
	mov	src_xa_seg,ax			;AN000; initialize attribute segment to -1
	mov	si,81H
	mov	bl,plus_chr			; include '+' as a delimiter
	inc	byte ptr [expand_star]		; want to include * expansion in cparse
	mov	cpyflag,1			; Turn "CPARSE called from COPY flag" on

DESTSCAN:
	xor	bp,bp				; no switches
	mov	di,offset trangroup:SCANBUF
	mov	parse_last,si			;AN018; save start of parsed string
	invoke	CPARSE
	PUSHF					; save flags
	inc	objcnt
	test	bh,80H				; A '+' argument?
	jz	NOPLUS				; no
	mov	[PLUS],1			; yes
NOPLUS:
	test	bh,1				; Switch?
	jz	TESTP2				; no

	test	bp,SwitchV			;AN038; Verify requested?
	jz	not_slashv			;AN038; No - set the switch
	test	[allswitch],SwitchV		;AN038; Verify already entered?
	jz	not_slashv			;AN038; No - set the switch
;AD018; or	[allswitch],FBadSwitch		;AN038; Set up bad switch
	or	BP,FBadSwitch			;AN018; Set up bad switch

not_slashv:					;AN038;
	or	[DESTSWITCH],BP 		; Yes, assume destination
	or	[ALLSWITCH],BP			; keep tabs on all switches

	test	BP,NOT SwitchCopy		;AN018; Bad switch?
	jz	NOT_BAD_SWITCH			;AN018; Switches are okay
	popf					;AN018; fix up stack
	mov	ax,BadSwt_ptr			;AN018; get "Invalid switch" message number
	invoke	Setup_parse_error_msg		;AN018; setup to print the message
	jmp	CERROR				;AC018; exit

NOT_BAD_SWITCH: 				;AN018; switch okay
	POPF					; get flags back
	jc	CHECKDONE			; Hit CR?
	jmp short DESTSCAN

TESTP2:
	POPF					; get flags back
	jc	CHECKDONE			; Hit CR?
	test	bh,80H				; Plus?
	jnz	GOTPLUS 			; Yes, not a separate arg
	inc	[ARGC]				; found a real arg
GOTPLUS:
	push	SI
	mov	ax,[STARTEL]
	mov	SI,offset trangroup:SCANBUF	; Adjust to copy
	sub	ax,SI
	mov	DI,offset trangroup:DESTBUF
	add	ax,DI
	mov	[DESTTAIL],AX
	mov	[DESTSIZ],cl			; Save its size
	inc	cx				; Include the nul
	rep	movsb				; Save potential destination
	mov	[DESTINFO],bh			; Save info about it
	mov	[DESTSWITCH],0			; reset switches
	pop	SI
	jmp	DESTSCAN			;AC018; keep going

CHECKDONE:
	cmp	plus,1				; If a statement like "copy file+" is
	jnz	cdcont				;  entered, complain about it.
	cmp	argc,1
	jnz	cdcont
	cmp	objcnt,2
	jnz	cdcont
	mov	dx,offset trangroup:overwr_ptr
	jmp	coperr
cdcont:
	mov	al,[PLUS]
	mov	[CONCAT],al			; PLUS -> Concatination
	shl	al,1
	shl	al,1
	mov	[INEXACT],al			; CONCAT -> inexact copy
	mov	al,[ARGC]
	or	al,al				; Good number of args?
	jnz	TRY_TOO_MANY			;AC000; there are args, see if too many
	MOV	DX,OFFSET TranGroup:Extend_Buf_ptr  ;AC000; get extended message pointer
	mov	Extend_Buf_ptr,LessArgs_ptr	;AN000; get "Required parameters missing" message number
	jmp	short cerror_parsej		;AN000; exit

TRY_TOO_MANY:
	cmp	al,2
	jbe	ACOUNTOK
	MOV	DX,OFFSET TranGroup:Extend_Buf_ptr  ;AC000; get extended message pointer
	mov	Extend_Buf_ptr,MoreArgs_ptr	;AN000; get "Too many parameters" message number

CERROR_PARSEJ:
	mov	msg_disp_class,parse_msg_class	;AN000; set up parse error msg class
CERROR4J:
	jmp	CERROR				; no, too many

ACOUNTOK:
	mov	bp,offset trangroup:DESTVARS
	cmp	al,1
	jnz	GOT2ARGS
	mov	al,[CURDRV]			; Dest is default drive:*.*
	add	al,capital_A
	mov	ah,':'
	mov	[bp.SIZ],2
	mov	di,offset trangroup:DESTBUF
	stosw
	mov	[DESTSWITCH],0			; no switches on dest
	mov	[bp.INFO],2			; Flag dest is ambig
	mov	[bp.ISDIR],0			; Know destination specs file
	invoke	SETSTARS
GOT2ARGS:
	cmp	[bp.SIZ],2
	jnz	NOTSHORTDEST
	mov	al,':'
	cmp	[DESTBUF+1],al
	jnz	NOTSHORTDEST			; Two char file name
	or	[bp.INFO],2			; Know dest is d:
	mov	di,offset trangroup:DESTBUF + 2
	mov	[bp.ISDIR],0			; Know destination specs file
	invoke	SETSTARS
NOTSHORTDEST:
	mov	di,[bp.TTAIL]
	cmp	byte ptr [DI],0
	jnz	CHKSWTCHES
	mov	dx,offset trangroup:BADCD_ptr
	mov	al,':'
	cmp	byte ptr [DI-2],al
	jnz	CERROR4J			; Trailing '/' error
	mov	[bp.ISDIR],2			; Know destination is d:/
	or	[bp.INFO],6
	invoke	SETSTARS
CHKSWTCHES:
;AD018; mov	ax,[ALLSWITCH]
;AD018; test	ax,NOT SwitchCopy
;AD018; jz	NOT_BAD_SWITCH			;AN000; Switches are okay
;AD018; MOV	DX,OFFSET TranGroup:Extend_Buf_ptr  ;AC000; get extended message pointer
;AD018; mov	Extend_Buf_ptr,BadSwt_ptr	;AN000; get "Invalid switch" message number
;AD018; jmp	short CERROR_PARSEJ		;AC000; Switch specified which is not known

; Now know most of the information needed about the destination

;AD018; NOT_BAD_SWITCH:
if not ibmcopyright
	mov	ax, [allswitch]			; Which switches were requested?  Hmmm?
endif
	TEST	AX,SwitchV			; Verify requested?
	JZ	NOVERIF 			; No
	MOV	AH,GET_VERIFY_ON_WRITE
	INT	int_command			; Get current setting
	PUSH	DS
	MOV	DS,[RESSEG]
ASSUME	DS:RESGROUP
	XOR	AH,AH
	MOV	[VERVAL],AX			; Save current setting
	POP	DS
ASSUME	DS:TRANGROUP
	MOV	AX,(SET_VERIFY_ON_WRITE SHL 8) OR 1 ; Set verify
	INT	int_command
NOVERIF:
	xor	bp,bp				; no switches
	mov	si,81H
	mov	bl,plus_chr			; include '+' as a delimiter
SCANFSRC:
	mov	di,offset trangroup:SCANBUF
	invoke	CPARSE				; Parse first source name
	test	bh,1				; Switch?
	jnz	SCANFSRC			; Yes, try again
	or	[DESTSWITCH],bp 		; Include copy wide switches on dest
	test	bp,SwitchB
	jnz	NOSETCASC			; Binary explicit
	cmp	[CONCAT],0
	JZ	NOSETCASC			; Not Concat
	mov	[ASCII],SwitchA 		; Concat -> ASCII copy if no B switch
	mov	[concat_xa],do_xa		;AN000; set up to do XA only on first file
NOSETCASC:
	call	source_set
	call	FRSTSRC
	jmp	FIRSTENT

PUBLIC	EndCopy
ENDCOPY:
	CALL	CLOSEDEST
ENDCOPY2:
	call	deallocate_src_xa		;AN030; deallocate xa segment
	invoke	free_tpa			;AN000; Make sure work area
	invoke	alloc_tpa			;AN000;   is reset properly
	MOV	DX,OFFSET TRANGROUP:COPIED_ptr
	MOV	SI,[FILECNT]
	mov	copy_num,si
	invoke	std_printf
	JMP	TCOMMAND			; Stack could be messed up

SRCNONEXIST:
	cmp	[CONCAT],0
	jnz	NEXTSRC 			; If in concat mode, ignore error
	mov	msg_disp_class,ext_msg_class	     ;AN000; set up extended error msg class
	mov	dx,offset TranGroup:Extend_Buf_ptr   ;AC000; get extended message pointer
	mov	Extend_Buf_ptr,error_file_not_found  ;AN000; get message number in control block
	mov	string_ptr_2,offset trangroup:srcbuf ;AC046; get address of failed string
	mov	Extend_buf_sub,one_subst	     ;AC046; put number of subst in control block
	jmp	COPERR

SOURCEPROC:
	call	source_set
	cmp	[CONCAT],0
	jnz	LEAVECFLAG			; Leave CFLAG if concatination
FRSTSRC:
	xor	ax,ax
	mov	[CFLAG],al			; Flag destination not created
	mov	[NXTADD],ax			; Zero out buffer
	mov	DestClosed,AL
LEAVECFLAG:
	mov	[SRCPT],SI			; remember where we are
	mov	di,offset trangroup:USERDIR1
	mov	bp,offset trangroup:SRCVARS
	invoke	BUILDPATH			; Figure out everything about the source
	mov	si,[SRCTAIL]			; Create the search FCB
	return

NEXTSRC:
	cmp	[PLUS],0
	jnz	MORECP
ENDCOPYJ2:
	jmp	ENDCOPY 			; Done
MORECP:
	xor	bp,bp				; no switches
	mov	si,[SRCPT]
	mov	bl,plus_chr			; include '+' as a delimiter
SCANSRC:
	mov	di,offset trangroup:SCANBUF
	invoke	CPARSE				; Parse first source name
	JC	EndCopyJ2			; if error, then end (trailing + case)
	test	bh,80H
	jz	ENDCOPYJ2			; If no '+' we're done
	test	bh,1				; Switch?
	jnz	SCANSRC 			; Yes, try again
	call	SOURCEPROC
	cmp	comma,1 			;g  was +,, found last time?
	jnz	nostamp 			;g  no - try for a file
	mov	plus_comma,1			;g  yes - set flag
	jmp	srcnonexist			;g  we know we won't find it
nostamp:					;g
	mov	plus_comma,0			;g  reset +,, flag
FIRSTENT:
	mov	di,FCB
	mov	ax,PARSE_FILE_DESCRIPTOR SHL 8
	INT	int_command
	CMP	BYTE PTR [SI],0 		; parse everything?
	JNZ	SrchDone			; no, error, simulate no more search
	mov	ax,word ptr [SRCBUF]		; Get drive
	cmp	ah,':'
	jz	DRVSPEC1
	mov	al,'@'
DRVSPEC1:
	or	al,20h
	sub	al,60h
	mov	ds:[FCB],al
	mov	ah,DIR_SEARCH_FIRST
	call	SEARCH
SrchDone:
	pushf					; Save result of search
	invoke	RESTUDIR1			; Restore users dir
	popf
	jz	NEXTAMBIG0
	jmp	SRCNONEXIST			; Failed
NEXTAMBIG0:
	xor	al,al
	xchg	al,[FRSTSRCH]
	or	al,al
	jz	NEXTAMBIG
SETNMEL:
	mov	cx,12
	mov	di,OFFSET TRANGROUP:SDIRBUF
	mov	si,OFFSET TRANGROUP:DIRBUF
	rep	movsb				; Save very first source name
NEXTAMBIG:
	xor	al,al
	mov	[NOWRITE],al			; Turn off NOWRITE
	mov	di,[SRCTAIL]
	mov	si,offset trangroup:DIRBUF + 1
	invoke	FCB_TO_ASCZ			; SRCBUF has complete name
MELDO:
	cmp	[CONCAT],0
	jnz	SHOWCPNAM			; Show name if concat
	test	[SRCINFO],2			; Show name if multi
	jz	DOREAD
SHOWCPNAM:
	mov	dx,offset trangroup:file_name_ptr
	invoke	std_printf
	invoke	CRLF2
DOREAD:
	call	DOCOPY
	cmp	[CONCAT],0
	jnz	NODCLOSE			; If concat, do not close
	call	CLOSEDEST			; else close current destination
	jc	NODCLOSE			; Concat flag got set, close didn't really happen
	mov	[CFLAG],0			; Flag destination not created
NODCLOSE:
	cmp	[CONCAT],0			; Check CONCAT again
	jz	NOFLUSH
	invoke	FLSHFIL 			; Flush output between source files on
						; CONCAT so LOSTERR stuff works
						; correctly
	TEST	[MELCOPY],0FFH
	jz	NOFLUSH
	jmp	SHORT DOMELCOPY

NOFLUSH:
	call	SEARCHNEXT			; Try next match
	jnz	NEXTSRCJ			; Finished with this source spec
	mov	[DESTCLOSED],0			; Not created or concat ->...
	jmp	NEXTAMBIG			; Do next ambig

DOMELCOPY:
	cmp	[MELCOPY],0FFH
	jz	CONTMEL
	mov	SI,[SRCPT]
	mov	[MELSTART],si
	mov	[MELCOPY],0FFH
CONTMEL:
	xor	BP,BP
	mov	si,[SRCPT]
	mov	bl,plus_chr
SCANSRC2:
	mov	di,OFFSET TRANGROUP:SCANBUF
	invoke	CPARSE
	test	bh,80H
	jz	NEXTMEL 			; Go back to start
	test	bh,1				; Switch ?
	jnz	SCANSRC2			; Yes
	call	SOURCEPROC
	invoke	RESTUDIR1
	mov	di,OFFSET TRANGROUP:DESTFCB2
	mov	ax,PARSE_FILE_DESCRIPTOR SHL 8
	INT	int_command
	mov	bx,OFFSET TRANGROUP:SDIRBUF + 1
	mov	si,OFFSET TRANGROUP:DESTFCB2 + 1
	mov	di,[SRCTAIL]
	invoke	BUILDNAME
	cmp	[CONCAT],0			; Are we concatenating?
	jz	meldoj				; No, continue.
;
; Yes, turn off nowrite because this part of the code is only reached after
; the first file has been dealt with.
;
	mov	[NOWRITE],0
meldoj:
	jmp	MELDO

NEXTSRCJ:
	jmp   NEXTSRC

NEXTMEL:
	call	CLOSEDEST
	xor	ax,ax
	mov	[CFLAG],al
	mov	[NXTADD],ax
	mov	[DESTCLOSED],al
	mov	si,[MELSTART]
	mov	[SRCPT],si
	call	SEARCHNEXT
	jz	SETNMELJ
	jmp	ENDCOPY2
SETNMELJ:
	jmp	SETNMEL

SEARCHNEXT:
	MOV	AH,DIR_SEARCH_NEXT
	TEST	[SRCINFO],2
	JNZ	SEARCH				; Do search-next if ambig
	OR	AH,AH				; Reset zero flag
	return
SEARCH:
	PUSH	AX
	MOV	AH,SET_DMA
	MOV	DX,OFFSET TRANGROUP:DIRBUF
	INT	int_command			; Put result of search in DIRBUF
	POP	AX				; Restore search first/next command
	MOV	DX,FCB
	INT	int_command			; Do the search
	OR	AL,AL
	return

DOCOPY:
	mov	si,offset trangroup:SRCBUF	;g do name translate of source
	mov	di,offset trangroup:SRCXNAME	;g save for name comparison
	mov	ah,xnametrans			;g
	int	int_command			;g

	mov	[RDEOF],0			; No EOF yet

	MOV	AX,EXTOPEN SHL 8		;AC000; open the file
	mov	bx,read_open_mode		;AN000; get open mode for COPY
	xor	cx,cx				;AN000; no special files
	mov	dx,read_open_flag		;AN000; set up open flags
	mov	di,-1				;AN030; no parameter list
	INT	int_command

	jnc	OpenOK
;
; Bogosity:  IBM wants us to issue Access denied in this case.	THey asked
; for it...
;
	jmp	error_on_source 		;AC022; clean up and exit

OpenOK:
	mov	bx,ax				; Save handle
	mov	[SRCHAND],bx			; Save handle
	mov	ax,(FILE_TIMES SHL 8)
	INT	int_command
	jc	src_cp_error			;AN022; If error, exit
	mov	[CPDATE],dx			; Save DATE
	mov	[CPTIME],cx			; Save TIME

	mov	cx,xa_list_attr 		;AN000; get old code page in cx
	push	cx				;AN000; save old attribute
	mov	xa_list_attr,0			;AN000; initialize code page

	mov	ax,(file_times SHL 8)+get_XA	;AC030; get extended attribute size
	mov	si,-1				;AN030; no querylist
	xor	cx,cx				;AN030; indicate we want size
	int	int_command			;AC000;
	jc	src_cp_error			;AN022; If error, exit
	mov	src_xa_size,cx			;AN000; save size
	cmp	cx,0				;AN000; are there any?
	pop	cx				;AN000; get old attribute
	jz	no_cp_get			;AN030; no - don't get attributes

	push	cx				;AN030; save old code page
	invoke	get_file_code_page_tag		;AN000; get file's code page
	pop	cx				;AN030	retrieve old code page
	jnc	no_cp_get			;AN000; no error - continue
src_cp_error:					;AN022;
	jmp	error_on_source 		;AC022; and exit

no_cp_get:
	cmp	[concat],0			;AN000; are we doing concatenation
	jz	get_src_xa			;AN000; no get source extended attrib
	cmp	[concat_xa],do_xa		;AN000; is this the first file?
	jz	get_src_xa			;AN000; yes - get extended attributes
	cmp	cx,xa_list_attr 		;AN000; no - see if code pages match
	jz	no_copy_xa_jmp			;AN000; code pages match - continue
	mov	xa_list_attr,inv_cp_tag 	;AN000; set invalid code page tag
no_copy_xa_jmp: 				;AC022;
	jmp	no_copy_xa			;AN000; don't get extended attributes

get_src_xa:
	call	deallocate_src_xa		;AN030; deallocate any existing XA segment
	cmp	src_xa_size,0			;AN000; are there any extended attributes?
	jz	no_copy_xa_jmp			;AC022; nothing there - don't allocate memory
	push	bx				;AN000; save handle
	invoke	free_tpa			;AN000; need to make free memory, first
	mov	bx,src_xa_size			;AN000; get bytes (size of XA) into bx
	mov	cl,4				;AN000; divide bytes by 16 to convert
	shr	bx,cl				;AN000;    to paragraphs
	inc	bx				;AN000; round up
	mov	ax,(alloc SHL 8)		;AN000; allocate memory for XA
	int	int_command			;AN000;
	pushf					;AN000; save flags
	mov	[src_xa_seg], AX		;AN000; save new segment
	push	ds				;AN030; get resident segment
	mov	ds,[resseg]			;AN030;   and save copy of xa
	assume	ds:resgroup			;AN030;   segment in resident
	mov	[rsrc_xa_seg],ax		;AN030;   in case user breaks
	pop	ds				;AN030;   out or has critical
	assume	ds:trangroup			;AN030;   error
	invoke	alloc_tpa			;AN000; reallocate the work area
	popf					;AN000; restore flags
	pop	bx				;AN000; restore handle
	jnc	Alloc_for_xa_okay		;AN000; no carry - everything okay
	call	closesrc			;AN000; close the source file
	mov	msg_disp_class,ext_msg_class	       ;AN000; set up extended error msg class
	mov	dx,offset TranGroup:Extend_Buf_ptr     ;AC000; get extended message pointer
	mov	Extend_Buf_ptr,error_not_enough_memory ;AN000; get message number in control block
	jmp	cerror				;AN000; exit

Alloc_for_xa_okay:

	mov	ax,(file_times SHL 8)+get_XA	;AN000; get extended attributes
	push	es				;AN000; save es
	mov	es,[src_xa_seg] 		;AN000; get segment for XA list
	xor	di,di				;AN000; offset of return list
	mov	si,-1				;AN030; get all attributes
	mov	cx,[src_xa_size]		;AN000; get size of list
	int	int_command			;AN000; get all the attributes
	pop	es				;AN000; restore es
	jnc	no_copy_xa			;AC022; no error - continue

error_on_source:				;AN022; we have a BAD error
	invoke	set_ext_error_msg		;AN022; set up the error message
	mov	string_ptr_2,offset trangroup:srcbuf ;AN022; get address of failed string
	mov	Extend_buf_sub,one_subst	;AN022; put number of subst in control block
	invoke	std_Eprintf			;AN022; print it
	cmp	[srchand],0			;AN022; did we open the file?
	jz	no_close_src			;AN022; no - don't close
	call	closesrc			;AN022; clean up
no_close_src:					;AN022;
	cmp	[cflag],0			;AN022; was destination created?
	jz	endcopyj3			;AN022; no - just cleanup and exit
	jmp	endcopy 			;AN022; clean up concatenation and exit
endcopyj3:					;AN022;
	jmp	endcopy2			;AN022;
no_copy_xa:
	mov	bx,[srchand]			;AN022; get handle back
	mov	ax,(IOCTL SHL 8)
	INT	int_command			; Get device stuff
	and	dl,devid_ISDEV
	mov	[SRCISDEV],dl			; Set source info
	jz	COPYLP				; Source not a device
	cmp	[BINARY],0
	jz	COPYLP				; ASCII device OK
	mov	dx,offset trangroup:INBDEV_ptr	; Cannot do binary input
	jmp	COPERR

COPYLP:
	mov	bx,[SRCHAND]
	mov	cx,[BYTCNT]
	mov	dx,[NXTADD]
	sub	cx,dx				; Compute available space
	jnz	GOTROOM
	invoke	FLSHFIL
	CMP	[TERMREAD],0
	JNZ	CLOSESRC			; Give up
	mov	cx,[BYTCNT]
GOTROOM:
	push	ds
	mov	ds,[TPA]
ASSUME	DS:NOTHING
	mov	ah,READ
	INT	int_command
	pop	ds
ASSUME	DS:TRANGROUP
	jc	error_on_source 		;AC022; Give up if error
	mov	cx,ax				; Get count
	jcxz	CLOSESRC			; No more to read
	cmp	[SRCISDEV],0
	jnz	NOTESTA 			; Is a device, ASCII mode
	cmp	[ASCII],0
	jz	BINREAD
NOTESTA:
	MOV	DX,CX
	MOV	DI,[NXTADD]
	MOV	AL,1AH
	PUSH	ES
	MOV	ES,[TPA]
	REPNE	SCASB				; Scan for EOF
	POP	ES
	JNZ	USEALL
	INC	[RDEOF]
	INC	CX
USEALL:
	SUB	DX,CX
	MOV	CX,DX
BINREAD:
	ADD	CX,[NXTADD]
	MOV	[NXTADD],CX
	CMP	CX,[BYTCNT]			; Is buffer full?
	JB	TESTDEV 			; If not, we may have found EOF
	invoke	FLSHFIL
	CMP	[TERMREAD],0
	JNZ	CLOSESRC			; Give up
	JMP	SHORT COPYLP

TESTDEV:
	cmp	[SRCISDEV],0
	JZ	CLOSESRC			; If file then EOF
	CMP	[RDEOF],0
	JZ	COPYLP				; On device, go till ^Z
CLOSESRC:
	mov	bx,[SRCHAND]
	mov	ah,CLOSE
	INT	int_command
	return

;
; We are called to close the destination.  We need to note whether or not
; there is any internal data left to be flushed out.
;
CLOSEDEST:
	cmp	[DESTCLOSED],0
	retnz					; Don't double close
	MOV	AL,BYTE PTR [DESTSWITCH]
	invoke	SETASC				; Check for B or A switch on destination
	JZ	BINCLOS
	MOV	BX,[NXTADD]
	CMP	BX,[BYTCNT]			; Is memory full?
	JNZ	PUTZ
	invoke	TRYFLUSH			; Make room for one lousy byte
	jz	NOCONC
CONCHNG:					; Concat flag changed on us
	stc
	return
NOCONC:
	XOR	BX,BX
PUTZ:
	PUSH	DS
	MOV	DS,[TPA]
	MOV	WORD PTR [BX],1AH		; Add End-of-file mark (Ctrl-Z)
	POP	DS
	INC	[NXTADD]
	MOV	[NOWRITE],0			; Make sure our ^Z gets written
	MOV	AX,[WRITTEN]
	ADD	AX,[NXTADD]
	JC	BINCLOS 			; > 1
	CMP	AX,1
	JZ	FORGETITJ			; WRITTEN = 0 NXTADD = 1 (the ^Z)
BINCLOS:
	invoke	TRYFLUSH
	jnz	CONCHNG
	cmp	[WRITTEN],0
ForgetItJ:
	jnz	no_forget			;AC000; Wrote something
	jmp	FORGETIT			;AC000; Never wrote nothing
no_forget:
	MOV	BX,[DESTHAND]
	MOV	CX,[CPTIME]
	MOV	DX,[CPDATE]
	CMP	[INEXACT],0			; Copy not exact?
	JZ	DODCLOSE			; If no, copy date & time
	MOV	AH,GET_TIME
	INT	int_command
	SHL	CL,1
	SHL	CL,1				; Left justify min in CL
	SHL	CX,1
	SHL	CX,1
	SHL	CX,1				; hours to high 5 bits, min to 5-10
	SHR	DH,1				; Divide seconds by 2 (now 5 bits)
	OR	CL,DH				; And stick into low 5 bits of CX
	PUSH	CX				; Save packed time
	MOV	AH,GET_DATE
	INT	int_command
	SUB	CX,1980
	XCHG	CH,CL
	SHL	CX,1				; Year to high 7 bits
	SHL	DH,1				; Month to high 3 bits
	SHL	DH,1
	SHL	DH,1
	SHL	DH,1
	SHL	DH,1				; Most sig bit of month in carry
	ADC	CH,0				; Put that bit next to year
	OR	DL,DH				; Or low three of month into day
	MOV	DH,CH				; Get year and high bit of month
	POP	CX				; Get time back
DODCLOSE:
	CMP	BX,0
	JLE	CloseDone
	MOV	AX,(FILE_TIMES SHL 8) OR 1
	INT	int_command			; Set date and time
	jc	xa_cleanup_err			;AN022; handle error

	mov	ax,(file_times SHL 8)+set_XA	;AN000; set code page
	mov	di,offset trangroup:xa_cp_out	;AC030; offset of attr list
	int	int_command			;AN000;
	jc	xa_cleanup_err			;AN030; exit if error

;
; See if the destination has *anything* in it.	If not, just close and delete
; it.
;
no_xa_cleanup_err:
	mov	ax,(lseek shl 8) + 2		; seek to EOF
	xor	dx,dx
	mov	cx,dx
	int	21h
;
; DX:AX is file size
;
	or	dx,ax
	pushf
	mov	ax,(IOCTL SHL 8) + 0		; get the destination attributes
	int	21h
	push	dx				; save them away
	MOV	AH,CLOSE
	INT	int_command
	pop	dx
	jnc	close_cont			;AN022; handle error on close
	popf					;AN022; get the flags back
xa_cleanup_err: 				;AN022;
	call	cleanuperr			;AN022; attempt to delete the target
	call	DestDelete			;AN022; attempt to delete the target
	jmp	short fileclosed		;AN022; close the file
close_cont:					;AN022; no error - continue
	popf
	jnz	CloseDone
	test	dx,80h				; is the destination a device?
	jnz	CloseDone			; yes, copy succeeded
	call	DestDelete
	jmp	short FileClosed
CloseDone:
	INC	[FILECNT]
FileClosed:
	INC	[DESTCLOSED]
RET50:
	CLC
	return


FORGETIT:
	MOV	BX,[DESTHAND]
	CALL	DODCLOSE			; Close the dest
	call	DestDelete
	MOV	[FILECNT],0			; No files transferred
	JMP	RET50

DestDelete:
	MOV	DX,OFFSET TRANGROUP:DESTBUF
	MOV	AH,UNLINK
	INT	int_command			; And delete it
	return

source_set	proc near

	push	SI
	mov	ax,[STARTEL]
	mov	SI,offset trangroup:SCANBUF	; Adjust to copy
	sub	ax,SI
	mov	DI,offset trangroup:SRCBUF
	add	ax,DI
	mov	[SRCTAIL],AX
	mov	[SRCSIZ],cl			; Save its size
	inc	cx				; Include the nul
	rep	movsb				; Save this source
	mov	[SRCINFO],bh			; Save info about it
	pop	SI
	mov	ax,bp				; Switches so far
	invoke	SETASC				; Set A,B switches accordingly
	invoke	SWITCH				; Get any more switches on this arg
	invoke	SETASC				; Set
	return

source_set	endp


;****************************************************************
;*
;* ROUTINE:	Cleanuperr
;*
;* FUNCTION:	Issues extended error message for destination
;*		if not alreay issued
;*
;* INPUT:	return from INT 21
;*
;* OUTPUT:	none
;*
;****************************************************************

cleanuperr	proc	near			;AN022;

	cmp	msg_flag,0			;AN022; have we already issued a message?
	jnz	cleanuperr_cont 		;AN022; yes - don't issue duplicate error
	invoke	set_ext_error_msg		;AN022; set up error message
	mov	string_ptr_2,offset trangroup:destbuf ;AN022; get address of failed string
	mov	Extend_buf_sub,one_subst	;AN022; put number of subst in control block
	invoke	std_eprintf			;AN022; issue the error message
cleanuperr_cont:				;AN022;

	ret					;AN022; return to caller
cleanuperr	endp				;AN022;

;****************************************************************
;*
;* ROUTINE:	Deallocate_Src_XA
;*
;* FUNCTION:	Deallocates source extended attribute segment
;*		and resets both resident and transient variables.
;*
;*
;* INPUT:	none
;*
;* OUTPUT:	none
;*
;****************************************************************

Deallocate_Src_XA  proc    near 		;AN030;

	cmp	[src_xa_seg],no_xa_seg		;AN030; has any XA segment been allocated
	jz	no_src_xa			;AN030; no - continue
	push	es				;AN030;
	mov	es,src_xa_seg			;AN030; yes - free it
	mov	ax,(Dealloc SHL 8)		;AN030; Deallocate memory call
	int	int_command			;AN030;
	pop	es				;AN030;
	mov	[src_xa_seg],no_xa_seg		;AN030; reset to no segment
	push	ds				;AN030; reinitialize resident
	mov	ds,[resseg]			;AN030;   copy of xa segment
	assume	ds:resgroup			;AN030;
	mov	[rsrc_xa_seg],no_xa_seg 	;AN030; reset to no segment
	pop	ds				;AN030;
	assume	ds:trangroup			;AN030;
no_src_xa:					;AN030;

	ret					;AN030; return to caller
Deallocate_Src_XA  endp 			;AN030;


TRANCODE	ENDS
	END