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