;---------------------------------------------------------------------; ; ; ; SPAZ 1.50 ; ; October 7, 1990 ; ; ; ; By Dan Thomson, Andrew Farmer and Jeffrey Nonken. ; ; ; ; ; ; SOURCE CODE ; ; ; ; ; ; Copyright (c) 1989-1990 Dan Thomson and Andrew Farmer. ; ; All Rights Reserved. ; ; ; ;---------------------------------------------------------------------; name SPAZ page 60,132 title Smart Pak, Arc and Zoo Shell false equ 00h tab equ 09h ;ASCII tab lf equ 0ah ;ASCII line feed cr equ 0dh ;ASCII carriage return blank equ 20h ;ASCII blank arc_len equ 21h ;Only save info for sort DOS equ 21h ;DOS int call CntrolC equ 23h ;Control C checking... cmdtail equ 80h ;Offset to command tail true equ 255 bsize equ 4096 ;Size of copy buffer ; If you have lots of memory, (Not running a multi-tasker) then the ; following variables can be changed to allow running SPAZ a little ; faster, but using alot more memory.... ; 1. Entries is the number of members in a standard ARC file that ; can be stored for sorting. If an ARC has more than 150, the ; file is not sorted. This can be increased until buffers reach ; (64K - code size). Each entry needs 29 bytes of buffer space. Entries equ 150 ; 2. This entry controls how many file names will be stored in ; memory. This is used during wild card processing to run ; SPAZ on each individual name. It has been set at 30 to ; allow most systems to run without writing to disk. If you ; run a busy mail system or process alot of archives, this ; can be increased (at the cost of memory) for faster processing. NamesFound equ 30 ;DOS interupt equates... CharacterOutput equ 02h OutputString equ 09h SetDTA equ 1ah SetVector equ 25h GetVector equ 35h CreateFile equ 3ch OpenFile equ 3dh CloseFile equ 3eh ReadFile equ 3fh WriteFile equ 40h DeleteFile equ 41h MoveFilePointer equ 42h GetOrSetAttribute equ 43h ModifyMemory equ 4ah ExecuteProgram equ 4bh ExitWithCode equ 4ch GetReturnCode equ 4dh SearchForFirst equ 4eh SearchForNext equ 4fh RenameFile equ 56h cseg segment para public 'code' assume cs:cseg,ds:cseg,es:cseg,ss:cseg org 100h ;Skip to end of the PSP entry: jmp start ;comm file entry always 0100H TitleScreen db cr,lf,'SPAZ 1.50; Written by Dan Thomson, Andrew Farmer and Jeffrey Nonken.',cr,lf db 'Copyright (c) 1989-1990 Dan Thomson & Andrew Farmer. All Rights Reserved.',cr,lf TitleLength equ $-TitleScreen Usage db cr,lf,'Syntax/Usage: SPAZ [switches] Path\Archive [switches] [files....]' db cr,lf,'Square brackets indicate optionals. Switches are set with - or /.' db cr,lf,cr,lf,'Switches:',cr,lf,cr,lf db ' -A Will use ONLY "ARCE" on standard (ARC Style) archives.',cr,lf db ' -D Will delete the archive if the extract was successful.',cr,lf db ' -F Will process all Compressed Mail bundles found in Dir.',cr,lf db ' -Maddr Will calculate Compressed Mail bundle name to show the',cr,lf db ' sending Net Address. "addr" is YOUR Net/Node address.',cr,lf db ' -N Will NOT attempt to sort the archive prior to extract.',cr,lf db ' -O|-R Overwrite. Will NOT prompt if existing file is found.',cr,lf db ' -V Verbose Mode. Will display the runtime configuration.',cr,lf,cr,lf db 'If -F is used then "Archive" MUST be a Path ONLY, not a Filename.',cr,lf db 'Use of -F forces -D and -O to be set TRUE and -N to be set False.',cr,lf UsageLength equ $-Usage even errmsg dw err2,err2,err2,err4,err5,err13 dw err13,err8,err8,err10,err11,err5 dw err13,err15,err15,err2,err2,err2 dw err20,err20,err21,err22,err23,err24,err25 err2 db cr,lf,'File not found: ',0 err4 db cr,lf,'Too many open files.',cr,lf,0 err5 db cr,lf,'Access denied.',cr,lf,0 err8 db cr,lf,'Insufficient memory.',cr,lf,0 err10 db cr,lf,'Invalid environment.',cr,lf,0 err11 db cr,lf,'Invalid format.',cr,lf,0 err13 db cr,lf,'Invalid data.',cr,lf,0 err15 db cr,lf,'Invalid drive was specified.',cr,lf,0 err20 db cr,lf,'Invalid file format, not changed.',cr,lf,0 err21 db cr,lf,'Too many archive entries.',cr,lf,0 err22 db cr,lf,'Unarchiver not found on path.',cr,lf,0 err23 db cr,lf,'Invalid Command Line Option used.',cr,lf,0 err24 db cr,lf,'Archive name not specified!',cr,lf,0 err25 db cr,lf,'Invalid directory specified.',cr,lf,'$' NoMail db cr,lf,'No Compressed Mail Bundles Found in Directory!',cr,lf,cr,lf,'$' SortErr db 'Sort failed, attempting extract anyway...',cr,lf,0 zerr db 'Problem reading archive for type check.',cr,lf,0 crlf equ $-3 TempErr db 'Unable to process temporary file, aborting.',cr,lf,'$' del_msg db cr,lf,'Extract successful - Unlinking ',0 will db cr,lf,'Will ',0 wont db cr,lf,'Will NOT ',0 info1 db 'use ARCE on standard (ARC style) archives.',0 info2 db 'delete the archives if extract was successful.',0 info3 db 'attempt to sort the archives.',cr,lf,0 info4 db ' - From: ',0 info5 db 'expand network addresses.',0 info6 db 'process Compressed Mail bundles ONLY.',0 info7 db 'operate in overwrite mode.',0 msg1 db ' Adjusting: ',0 msg2 db '- Location = ',0 msg3 db ' Length = ',0 msg4 db 'Searching: ',0 UnArc1 db 'PKXARC.EXE',0 UnArc2 db 'PKXARC.COM',0 UnArc3 db 'PKUNPAK.EXE',0 UnArc4 db 'LOOZ.EXE',0 UnArc5 db 'PAK.EXE',0 UnArc6 db 'ARCE.COM',0 UnArc7 db 'ZOO.EXE',0 UnArc8 db 'DWC.EXE',0 UnArc9 db 'PKUNZIP.EXE',0 UnArc10 db 'LHARC.EXE',0 on_disk db 0 ;True if names on disk .jjn num_names db 0 ;# of filenames in buffer .jjn num_hdr db 0 ;Number of headers input first db true ;Flag for search first/next flag db false ;Show sort done on pass Zooflag db false ;Flag to signify zoo file Crushed db false ;Flag to signify crushed files A_Flag db false ;Set no default archiver D_Flag db false ;Set no delete when finished F_Flag db false ;Set no mail only stuff M_Flag db false ;Show net/node on extract? N_Flag db true ;Set default sort performed O_Flag db false ;Set default to non-overwrite Q_Flag db true ;Set default to quiet IsZip db false ;Flag to show ZIP file IsDWC db false ;Flag to show DWC file IsLZH db false ;Flag to show LZH file Parsed db false ;Flag to show names were parsed Got_name db false ;Cmd line fname is OK... Characters db false ;Print string char counter Last_Chance db false ;Flag for Arce useage elevel db 0 ;Last reported error level count db 0 ;Number of passes complete order db 0 ;Flag to show archive in order temp db 'SpazTmp1.$$$',0 ;Temp filename to use thomlen equ $-temp ; .jjn filename_file db 'SpazTmp2.$$$',0 ;Filename for list of files end_arc db 1Ah,0 ;Mark to show end of arc even arg_len dw 0 ;Length of command line arg buf_pos dw 0 ;Position in header buffer endpath dw 0 ;Holds end of path address pathlen dw 0 ;Holds length of path .jjn files_handle dw 0 ;Handle for filespec file .jjn name_count dw 0 ;Number of filenames found .jjn names_used dw 0 ;Number of names used after.jjn ; all the names were found .jjn fname_ptr dw 0 ;Point into filename buffer.jjn Opt_Address dw false ;Pointer to cmd line fname Opt_Length dw false ;Address of cmd line fname high_pos dw 0 ;High byte of file pointer low_pos dw 0 ;Low byte of file pointer in_handle dw 0 ;Handle for read file out_handle dw 0 ;Handle for write file par_blk dw 0 ;Copy of parent's environment dw offset cmd_cnt ;Pointer to command line sg1 dw 0 dw offset fcb1 sg2 dw 0 dw offset fcb2 sg3 dw 0 stk_seg dw 0 ;Saved stack segment stk_ptr dw 0 ;Saved stack pointer dir dw 0 ;Pointer for PATH search enddir dw 0 ;End address of PATH variable cmd1_cnt dw 0 ;Length of wildcard filename env_len dw 0 ;Length of PATH in Environment BundlePosition dw offset BundleNames ;Current position for mail env db 'PATH',0 ;Environment variable to find DefaultBundle db '*.MO?',0 ;First mail type to look for BundleNames db 'TUWETHFRSASU' ; and the rest of 'em.... Spaz proc near ;Entry point from MS-DOS start: mov AX,CS mov sg1,AX mov sg2,AX mov sg3,AX mov AH,SetDTA ;AH = Set Disk Tranfer Area mov DX,offset dta_buf ;Address of scratch space int DOS ;Give it to DOS xor AX,AX mov word ptr Names_Count,AX cli ;Disable interupts lea sp,bottom-1 ;Move stack to save position sti ;OK for interups now... mov DX,offset bottom ;Point DX to end of Spaz mov BX,DX ;Info needed in BX add BX,0fh ;Add 1 paragraph to it mov CL,4 ;CL = counter for shift shr BX,CL ;= BX/16 (# of paras needed) mov AH,ModifyMemory ;AH = Modify memory block int DOS ;Extra memory released... ; First, identify self and examine parameters... mov DX,offset TitleScreen ;DX points to message mov BX,2 ;Output to standard error mov CX,TitleLength ;Length of header string mov AH,WriteFile ;Output to handle int DOS ;Call DOS to do it mov SI,offset env ;Search for 'PATH' mov es,es:[2ch] ;Get environment segment call getenv ;Read in PATH string mov BX,cmdtail ;ES:BX = command parameters call argc ;Get number of arguments cmp AX,2 ;At least 1 argument? jae args_ok ;If yes, keep going Syntax: mov DX,offset Usage ;DX points to usage string mov BX,2 ;Output to standard error mov CX,UsageLength ;Length of usage string mov AH,WriteFile ;Output to handle int DOS ;Call DOS to do it mov AL,0 ;Errorlevel 0 exit mov AH,ExitWithCode ;AH = Terminate to DOS int DOS ;Transfer to DOS (for good) args_ok: call options ;Scan off any options ; Here, ES:BX = argument address and AX = argument length cld ;Direction register increments mov SI,BX ;Point SI to argument lea DI,cmd1 ;DI = destination mov CX,AX ;Put character count in CX mov cmd1_cnt,AX ;And save it for later! rep movsb ;Move argument to buffer ; End the filename (or PATH if -F used) with a zip. mov byte ptr [DI],0 ; Here, we check for a -F option. If it is true, we tack on the ; default filename (*.MO?) and start a mail run. cmp F_Flag,true ;Is this a mail run? jne NotAMailRun ;Nope, continue cmp byte ptr [DI-1],'\' ;Did they have backslash? je AddName ;If yes, do the name mov byte ptr [DI],'\' ;Else add a slash inc word ptr cmd1_cnt ;And bump counter inc DI ;Adjust pointer AddName: mov byte ptr [DI-1],0 ;Make it ASCIIZ mov DX,offset cmd1 ;Point to filename/path mov AX,4300h ;Get attribute int DOS ;Call DOS to do it mov byte ptr [DI-1],'\' ;Restore back slash and CX,00010000b ;Is this a directory? jnz DirectoryFound ;Go if yes. mov DX,offset err25 ;Invalid directory message mov AH,OutputString ;DOS print string function int DOS ;Call DOS to do it jmp syntax ;Display syntax screen DirectoryFound: mov SI,offset DefaultBundle ;Point to bundle name mov CX,3 ;Count for name length rep movsw ;Stuff name in buffer add cmd1_cnt,6 ;Fix the counter jmp short Isolate ;No need to check it now ; Here, we will check to make sure there is a valid extension. ; If none was given, a default extention of '.*' will be added. NotAMailRun: std ;Set up to move backwards mov SI,offset cmd1 ;Get address of filename mov DI,SI ;So we can check for end mov AX,cmd1_cnt ;Get length in AX add SI,AX ;Point to end of filename push SI ;Save end address scan: lodsb ;Get a character cmp AL,'.' ;Is it a period? je ExtentionIsOk ;If yes, extention OK cmp AL,'\' ;Is it filename separater? je UseDefault ;Stop if yes cmp DI,SI ;Scanned whole name? jne scan ;No, go get more UseDefault: pop DI ;DI = end address of filename mov byte ptr [DI],'*' ;Add full wildcard search mov byte ptr [DI+1],'.' ;Add a dot to filename mov byte ptr [DI+2],'*' ;Add wildcard extension mov byte ptr [DI+3],0 ;End it with a zip add word ptr cmd1_cnt,3 ;Adjust length count push DI ;Maintain stack balance ; Next, we isolate the path from the filename so that successive ; filenames can be tacked onto it in case wildcards are used... public ExtentionIsOk ExtentionIsOk: add SP,2 ;Remove garbage from stack Isolate: call show_opt ;Display option info std ;Set up to move backwards mov SI,offset cmd1 ;Get address of filename ;so we can check for a path.jjn mov CX,cmd1_cnt ;Get length in CX .jjn add SI,CX ;SI = end of filename .jjn dec SI ; .jjn public path1 path1: lodsb ;Get a character cmp AL,'\' ;Filename separator? je save_path ;Stop if yes cmp AL,':' ;Drive separator? je save_path ;Stop if yes loop path1 ;Decrement and loop .jjn inc SI mov endpath,SI ;Save address mov pathlen,CX ;Save path length (0) .jjn jmp short _end_p ;Skip double save .jjn public save_path save_path: inc SI ;Adjust past \ character inc SI ;Need 2 for auto dec... mov endpath,SI ;Save address of end of path mov pathlen,CX ;Save path length .jjn _end_p: ; .jjn cld ;Set direction forward ; ; Now we call the wildcard expander. This creates a list of filenames that ; match the filespec so we can retrieve them later. If there are more than ; 'NamesFound' matches, it will save them on disk. ; mov on_disk,0 ;List of files is not on disk mov Name_count,0 ;No names found yet mov num_names,0 DoAllMail: call FindNames ; Find all matching files .jjn cmp F_Flag,true ;Are we doing a mail run? jne NotDoingMail ;Go if not mov SI,BundlePosition ;Get address for bundle name cmp SI,offset SPAZ ;No more names to do? je NotDoingMail ;If not, we're done... lodsw ;Get next bundle name mov DI,EndPath ;End of path to filename add DI,2 ;Adjust to right spot stosw ;And stuff in new name mov BundlePosition,SI ;Save new name offset jmp short DoAllMail ;And get more filenames NotDoingMail: cmp on_disk,0 ;Is stuff on disk? jz NothingOnDisk ;Nope skip pointer adjust mov AH,MoveFilePointer ;Move pointer DOS function xor CX,CX ;Offset from beginning of file mov DX,CX ;32 bit mov AL,CL ;Mark for 'beginning' mov BX,files_handle ;Get the file handle int DOS ;Call DOS to do it NothingOnDisk: mov AX,name_count ; number of names found or AX,AX ; return with zero flag set jnz Main ; skip error stuff .jjn ; If we got here, there were no names found. ; (Moved from the old wild_card procedure. .jjn) cmp F_Flag,true ;Was this a mail run? jne NormalNotFound ;If not, do normal exit mov DX,offset NoMail ;Mail run error message mov AH,OutputString ;DOS print string function int DOS ;Call DOS to do it jmp short DoneTotally ;Denis Miller time NormalNotFound: mov AX,2 ;Change error to file not found call err_msg ;Display error in english push AX ;Save error code mov SI,offset cmd1 ;Point to filename call upper ;Convert to upper case call ShowIt ;Show it (not found) mov SI,offset crlf ;CR,LF call ShowIt ;On screen pop AX ;Restore error code DoneTotally: mov AH,ExitWithCode ;Terminate with code int DOS ;Exit program ; This is the main loop of the program. It is run once for every ; matching filename found from the command line. Needed variables ; are reset each time through. Main: mov zooflag,false ;Reset variables mov byte ptr cmd_cnt,9 mov crushed,false mov word ptr buf_pos,0 mov flag,false mov count,false mov order,false mov num_hdr,false mov IsZip,false mov IsDWC,false mov IsLZH,false mov Last_Chance,false mov DI,offset ExtractOptions ;Point to last set of options mov CX,9 ;Max options set at 5 bytes mov AL,blank ;Blank them out (spaces) rep stosb mov SI,offset crlf ;Cr,Lf between runs call ShowIt call wild_card ;Grab a filename to work on ; If we return from wild_card, at least 1 matching filename was found. ; Otherwise the program reports its status and quits. If a wild card ; was used, it has now been extended to a fully qualified filename. Now ; it has to be checked for archive type etc. etc. mov SI,offset msg4 ;SI = 'Searching:' call ShowIt ;Put it on screen mov SI,offset cmd1 ;SI = filename call upper ;Convert it to upper case call ShowIt ;Put it on screen cmp M_Flag,true ;Displaying net/node? jne NoAddress ;Skip next part if not call DisplayNode ;Figure out the info mov SI,offset info4 ;From message call ShowIt ;Display it mov SI,offset BuildNet ;Our ASCII info call ShowIt ;Display it NoAddress: mov SI,offset crlf ;SI = cr/lf call ShowIt ;On screen mov SI,offset cmd1 ;SI = full filename mov DI,offset pakfile ;DI = new command line do_count: lodsb ;Get a character from line cmp AL,0 ;End of filename? je done ;yes, we are finished cmp AL,cr je done1 inc byte ptr cmd_cnt ;Else, bump character counter stosb ;Save char in command line jmp short do_count ;and loop back... done: mov AL,cr ;Cmd line must end with cr done1: stosb ;Stuff final character mov byte ptr [DI],0 ;make it ASCIIZ *** ; This little section adds any unique file names that are to be ; extracted from the archive. If this option is used in conjunction ; with /d, the archive will be deleted after extraction. BE CAREFUL cmp Parsed,true ;Were filenames specified? jne No_Parsed ;Skip this if not dec DI ;Back up destination pointer mov SI,offset Extract_Names ;SI = extract name buffer mov CX,word ptr Names_Count ;Get length of names add byte ptr cmd_cnt,CL rep movsb ;Set up the line mov byte ptr [DI],cr ;End it all with a cr mov byte ptr [DI+1],0 ;Make it ASCIIZ ; Here is where we check the archive type. If it is a zoo file, it is ; extracted as is. If it is an ARC/PAK/PK file, it is first checked to ; ensure that it is in proper order by date time... No_Parsed: call ArchiveCheck ;Check the archive type jnc Zoo_Check_OK ;If all is well, continue jmp main ;Else, try to do the next one Zoo_Check_OK: mov DX,offset UnArc4 ;Point to LOOZ.EXE cmp zooflag,true ;Is this a zoo file? jne no_zoo call find ;Does LOOZ exist? jc no_looz ;Nope, check for zoo ; If execution falls here, LOOZ was found on the path. We have to change ; the extract option to 'x' as looz does not understand 'e' cmp O_Flag,true ;Do we want forced overwrite? jne DontForceLooz ;Go if not jmp short no_looz ;If we do, call zoo instead DontForceLooz: mov byte ptr ExtractOptions + 1,'x' ;Change extract option jmp X_OK ;Go execute looz ; If we get here, a zoo archive was detected, and LOOZ was not found. ; Check for ZOO.EXE and quit if not found... no_looz: mov DX,offset UnArc7 ;DX = zoo.exe cmp O_Flag,true ;Do we want forced overwrite? jne DoNotForceZoo ;Exit if not, else mov byte ptr ExtractOptions +2,'S' ;This will force overwrite mov byte ptr ExtractOptions +3,'O' ;This is needed too DoNotForceZoo: mov byte ptr ExtractOptions +1,'x' ;Change extract option jmp zoo ;Go hunt for it no_zoo: cmp IsDWC,true ;Is this a DWC file? jne TryZIP ;Nope, check for ZIP mov DX,offset UnArc8 ;Point to 'DWC.EXE' cmp O_Flag,true ;Overwrite mode? jne DoNotForceDwc ;If not, exit mov byte ptr ExtractOptions + 1,'x' ;This will allow DWC mov byte ptr ExtractOptions + 2,'w' ;to overwrite existing files jmp Zoo ;Try to run it DoNotForceDwc: mov byte ptr ExtractOptions + 1,'e' ;Normal extract mode jmp Zoo ;Try to run it TryZIP: cmp IsZIP,true ;Is this a ZIP file? jne TryLZH ;If not, check for LHArc mov DX,offset UnArc9 ;Point to 'PKUNZIP.EXE' cmp O_Flag,true ;Overwrite mode? jne DoNotForceZIP ;Exit if not mov byte ptr ExtractOptions + 1,'-' ;This will allow Zip mov byte ptr ExtractOptions + 2,'o' ;to overwrite existing files jmp Zoo ;Try to run it DoNotForceZIP: jmp Zoo ;Try to run it TryLZH: cmp IsLZH,true ;Is this an LHZ file? jne TryNormal ;Must be an ARC mov DX,offset UnArc10 ;Point to 'LHARC.EXE' mov byte ptr ExtractOptions,'e' ;Must have extract option cmp O_Flag,true ;Overwrite mode? jne DoNotForceLZH ;Exit if not mov byte ptr ExtractOptions + 2,'/' ;This will allow LHArc mov byte ptr ExtractOptions + 3,'m' ;to overwrite existing files mov byte ptr ExtractOptions + 4,'c' ;Not very exotic.... jmp Zoo ;Try to run it DoNotForceLZH: jmp Zoo ;Try to run it TryNormal: call Sort_It jnc part2 ;Sort was good, go unarc mov SI,offset sorterr ;Point to error message call ShowIt ;Put it on screen Part2: mov byte ptr ExtractOptions + 1,'e' ;Normal extract option cmp Crushed,true ;Crushed files? jne part3 ;Nope, check for ARCE Part2a: mov DX,offset UnArc5 ;Point to PAK.EXE cmp O_Flag,true ;Overwrite mode? jne DoNotForcePak ;Exit if not mov byte ptr ExtractOptions + 2,' ' ;A space for the new PAK mov byte ptr ExtractOptions + 3,'/' ;A hyphen for the new PAK mov byte ptr ExtractOptions + 4,'w' ;This tells pak to force mov byte ptr ExtractOptions + 5,'a' ; overwrites always DoNotForcePak: cmp byte ptr D_flag,true ;Was delete flag set? jne NoDelete ;Nope, continue... mov byte ptr ExtractOptions + 1,'x' ;Delete archive when done NoDelete: jmp zoo ;Do PAK and PAK only. part3: cmp byte ptr A_Flag,true ;Default to ARCE? jne Xarc ;Go if not NoneFound: cmp Crushed,true ;Crushed files? jne OkForArce ;Nope, keep going jmp Give_Up ;If yes, just quit OkForArce: cmp O_Flag,true ;Force overwrite mode? jne DontForceArce ;Go if not mov SI,offset pakfile ;Point to command line goagain: lodsb or AL,AL jnz goagain mov DI,SI ;Get address in DI mov byte ptr [DI-2],Blank ;Put in a space mov byte ptr [DI-1],'/' ;and an Option delimiter mov byte ptr [DI],'R' ;and Force overwrites... mov byte ptr [DI+1],cr mov byte ptr [DI+2],0 add byte ptr cmd_cnt,3 ;Fix the count up DontForceArce: mov DX,offset UnArc6 ;Else point to it mov byte ptr ExtractOptions + 1,' ' ;This removes any options mov byte ptr ExtractOptions + 2,' ' ; that may have been put mov byte ptr ExtractOptions + 3,' ' ; in by other un-archers jmp short zoo ;Go try to run it Xarc: mov DX,offset UnArc1 ;Point to PKXARC.EXE mov byte ptr ExtractOptions + 1,' ' ;Remove 'e' option cmp O_Flag,true ;Overwrite mode? jne DoNotForceXarc ;Exit if not mov byte ptr ExtractOptions + 1,'-' ;This forces PKWare to use mov byte ptr ExtractOptions + 2,'r' ; it's overwrite mode DoNotForceXarc: call find ;See if it exists jnc X_OK ;Got it! mov DX,offset UnArc2 ;Point to PKXARC.COM call find ;See if it exists jnc X_OK ;Got it! mov DX,offset UnArc3 ;Point to PKUNPAK.EXE call find ;See if it exists jnc X_OK ;Got it, keep going mov DX,offset UnArc5 ;Point to PAK.EXE mov byte ptr ExtractOptions + 1,'e' ;Set up extract for pak cmp O_Flag,true ;Overwrite mode? jne DontForcePak ;Exit if not mov byte ptr ExtractOptions + 2,' ' ;A space for the new PAK mov byte ptr ExtractOptions + 3,'/' ;A hyphen for the new PAK mov byte ptr ExtractOptions + 4,'w' ;This tells pak to force mov byte ptr ExtractOptions + 5,'a' ;overwrite always DontForcePak: cmp byte ptr D_flag,true ;Was delete flag set? jne part3a ;Nope, continue... mov byte ptr ExtractOptions + 1,'x' ;Delete archive when done part3a: call find ;See if it exists jnc X_OK ;Got it, continue jmp NoneFound ;Try Arce.... Zoo: call find ;See if it exists jnc X_OK ;Got it! ; If this code is executed, then no Un-Arc program was found on the ; path. It reports the error and aborts... Give_Up: mov AX,22 ;Unarcher not found call err_msg ;Report error in english mov AH,ExitWithCode ;Exit with code int DOS ;Back to DOS (for good) X_OK: mov BX,offset par_blk ;BX points to spawn info mov AL,0 ;AL = load and execute push DS push ES cli ;Disable interupts mov stk_seg,SS ;Save the Stack mov stk_ptr,SP ;Both parts... sti ;Enable inerupts mov AH,ExecuteProgram ;AH = MSDOS exec function int DOS ;Transfer to DOS cli ;disable interupts mov SS,stk_seg ;Restore stack segment mov SP,stk_ptr ;Restore stack pointer sti ;Enable interupts pop ES pop DS mov AH,GetReturnCode ;Get return code from Un-Arcer int DOS ;Transfer to DOS mov elevel,AL ;Save errorlevel for later cmp byte ptr crushed,true ;Did we use PAK? jne normal ;Nope, check for delete flag cmp byte ptr D_Flag,true ;Did we mark for delete? jne main_loop ;Exit if no mov SI,offset del_msg ;SI = 'Unlinking...' call ShowIt mov SI,offset cmd1 ;SI = filename call ShowIt mov SI,offset crlf call ShowIt jmp short main_loop ;Go do next file normal: or AL,AL ;Make sure all is well jnz main_loop ;Before allowing a delete cmp byte ptr D_Flag,true ;Should we delete arc file? jne main_loop ;Skip if not mov SI,offset del_msg ;SI = 'Unlinking...' call ShowIt mov SI,offset cmd1 ;SI = filename call ShowIt mov SI,offset crlf call ShowIt mov AH,DeleteFile ;AH = delete file mov DX,offset cmd1 ;DX = archive name int DOS ;Call DOS to do it jnc main_loop ;Go if no errors call err_msg ;Show errors but continue... main_loop: jmp main ;Go get next file ; Print ASCIIZ string pointed to by SI ShowIt: mov AH,CharacterOutput ;Function = console out mov byte ptr Characters,0 ;Set count to zip show_loop: lodsb ;Get a character or AL,AL ;Is it a 0? jz ShowIt_exit ;If yes, exit inc byte ptr Characters ;Bump char counter mov DL,AL ;ASCII char in DL int DOS ;Call DOS to print it jmp short show_loop ;Go get more ShowIt_exit: ret ;Return to caller Spaz endp argc proc near ;count command line arguments push BX ;save original BX and CX push CX ; for later mov AX,1 ;force count >= 1 argc1: mov CX,-1 ;set flag = outside argument argc2: inc BX ;point to next character cmp byte ptr [BX],cr je argc3 ;exit if carriage return cmp byte ptr [BX],blank je argc1 ;out of argument if blank cmp byte ptr [BX],tab je argc1 ;outside argument if ASCII tab ;otherwise not blank or tab, jcxz argc2 ;jump if already in argument inc AX ;else found argument, count it not CX ;set flag = inside argument jmp argc2 ;and look at next character argc3: pop CX ;restore original BX and CX pop BX ret ;return AX = argument count argc endp argv proc near ;get address & length of ;command tail argument xor AH,AH ;initialize argument countef argv1: mov CX,-1 ;set flag = outside argument argv2: inc BX ;point to next character cmp byte ptr [BX],cr je argv7 ;exit if carriage return cmp byte ptr [BX],blank je argv1 ;outside argument if ASCII blank cmp byte ptr [BX],tab je argv1 ;outside argument if ASCII tab ;if not blank or tab... jcxz argv2 ;jump if already inside argument inc AH ;else count arguments found cmp AH,AL ;is this the one we're looking for? je argv4 ;yes, go find its length not CX ;no, set flag = inside argument jmp argv2 ;and look at next character argv4: ;found desired argument, now ;determine its length... mov AX,BX ;save param, starting address argv5: inc BX ;point to next character cmp byte ptr [BX],cr je argv6 ;found end if carriage return cmp byte ptr [BX],blank je argv6 ;found end if ASCII blank cmp byte ptr [BX],tab jne argv5 ;found end if ASCII tab argv6: xchg BX,AX ;set ES:BX = argument address sub AX,BX ;and AX = argument length jmp short argvx ;return to caller argv7: xor AX,AX ;set AX = 0, argument not found argvx: ret ;return to caller argv endp getenv proc near ; return address and length ; of environment variable push CX ; save registers push SI mov CX,8000h ; assume max env. = 32 KB xor DI,DI ; initial env. offset xor AX,AX ; default length result get1: cmp byte ptr ES:[DI],0 ; check for end of environment je get4 ; end reached, return AX = 0 pop SI ; initialize address of target push SI ; variable to be found repe cmpsb ;Compare target and env. strings cmp byte ptr [SI-1],0 jne get2 ;Jump if incomplete match cmp byte ptr ES:[DI-1],'=' je get3 ;Jump if match was complete get2: repne scasb ;No match, scan for end string jmp get1 ;Try again to match get3: push DI ;Save address after = sign repne scasb ;Look for end of this string pop AX ;Get back starting address xchg DI,AX ;Find string length sub AX,DI dec AX ;Don't include null byte get4: pop SI ;Common exit point pop CX mov CS:env_len,AX ;Save PATH length or AX,AX ;Null PATH? jz get5 ;Exit if yes push ES ;Get path segment into pop DS ; DX for string move push CS ;Now ES points to data pop ES ; in our code segment mov CX,AX ;Get length of path in CX mov SI,DI ;Path is now source mov DI,offset saved ;Destination is our area rep movsb ;Move path into this segment get5: push CS ;Now we have to restore pop DS ; the original DS push CS pop ES ret ;Return to caller getenv endp ; This routine searches the current directory, and (if needed), the ; entire PATH, looking for an unarchiver to use. It is called with ; DX pointing to an ASCIIZ filename to look for and returns with ; carry clear if it is found. Carry Set if not found. find proc near push DX ;Save pointer to filename mov AH,SearchForFirst ;Search for first pop DX ;Get filename address push DX ;Save it again xor CX,CX ;Normal attribute int DOS ;Give it to DOS jc find1 ;Not found, search path pop DX ;Point DX to filename ret ;exit Find... find1: mov AX,env_len ;Get PATH length or AX,AX ;Did we find a path? jnz find2 ;Keep going if yes no_exist: pop DX ;Point DX to filename stc ;Carry set to show error ret ;Exit Find find2: mov DI,offset saved ;Point to the path string mov dir,DI ;dir = start of path string add DI,AX ;AX = end of path string mov enddir,DI ;save it mov byte ptr [DI],0 ;Null terminator for path find3: mov DI,offset new ;Area for path\filename mov SI,dir ;Get current address in path cmp [enddir],SI ;End of path variable? jbe no_exist ;Not found, exit find4: lodsb ;Get a character cmp AL,';' ;Seperator? je find5 ;Yes, go tack on filename cmp AL,0 ;Are we finished? je find5 ;Yes, go stosb ;Stuff character jmp short find4 ;and go for another find5: mov dir,SI ;Save current path address cmp byte ptr [DI-1],'\' ;Path separator? je find6 ;Yup, keep goin mov byte ptr [DI],'\' ;Else, put one in inc DI ;Bump the pointer find6: pop SI ;Get filename address push SI ;Save it back again find7: lodsb ;Get character from filename cmp AL,0 ;Got whole filename? je find8 ;Go if yes stosb ;Else put character in buffer jmp find7 ;Go get the rest find8: stosb ;Save the null (ASCIIZ) mov AH,SearchForFirst ;Search for first mov DX,offset new ;Point to path\filename xor CX,CX ;Normal attribute int DOS ;Give it to DOS jc find3 ;Not found try next path pop DX ;Clear junk off stack mov DX,offset new ;DX = full path\filename clc ;Show no errors ret ;Exit (so we can exec it) find endp ; This routine determines what type of archive is being worked on. ; It will set a flag to tell SPAZ which un-archiver to try and use. ArchiveCheck proc near mov AH,OpenFile ;AH = open file request mov AL,0 ;read access only mov DX,offset cmd1 ;Point to archive name int DOS ;Call DOS to open it jc probs xchg AX,BX ;Handle in BX mov AH,ReadFile ;AH = read file mov CX,4 ;Read first 4 bytes mov DX,offset Usage ;Read byte into usage area int DOS ;Call DOS to do it jc probs mov AH,MoveFilePointer ;Get ready to adjust mov AL,2 ;From end of file mov CX,0ffffh ;2 spaces mov DX,0fffeh int DOS ;Call DOS to do it jc probs mov AH,ReadFile ;Read last 2 bytes mov CX,2 mov DX,offset Usage + 4 ;Buffer for save int DOS ;Call DOS to do it jc probs mov AH,CloseFile ;AH = close file int DOS ;Call DOS to do it jc probs mov AX,word ptr Usage + 4 ;Get DWC bytes cmp AX,4357h ;Is it a DWC file? jne IsItZoo ;Go, if not mov IsDWC,true ;Else set flag jmp short EndCheck ;And exit IsItZoo: mov AX,word ptr Usage ;Get value cmp AX,4f5ah ;Is it a zoo file? jne IsItZip ;Go if not, else mov zooflag,true ;Mark for zoo jmp short EndCheck IsItZip: cmp AX,4b50h ;Is it a ZIP file? jne IsItArc ;Go, if not mov IsZip,true ;Set flag jmp short EndCheck ;We're outa here IsItArc: cmp AL,1Ah ;Is it a normal Arc/Pak? jne IsItLZH ;Skip this file if not jmp short EndCheck ;We're outa here IsItLZH: mov AX,word ptr Usage + 2 ;Get LH's ID bytes cmp AX,6C2Dh ;Is this an LH Arc? jne NotAnArchive ;Report error if not mov IsLZH,true ;Mark for LHArc EndCheck: clc ;Show no errors ret probs: push AX ;Save error code call err_msg ;Report error in english mov SI,offset zerr ;SI = Zoo check error message call ShowIt ;Display it pop AX ;Restore error code NotAnArchive: stc ;Show error ret ;Return to caller ArchiveCheck endp ; This routine is responsible for sorting ARCType bundles into proper ; FidoNet Mail format. i.e. Sorted by date/time. It is accomplished ; by sorting all the headers and re-writting the entire archive... Sort_It proc near cld ;Move forward again... xor AL,AL mov num_hdr,AL ;Init header counter mov flag,false mov DX,offset cmd1 ;DX = Archive filename mov AH,OpenFile ;AX = Open file xor AL,AL ;Normal Attribute int DOS ;Give it to DOS jnc open_ok ;Continue if it worked jmp short inv_hdr ;Go report errors ; This routine will read in the archive file headers so that they ; can be sorted. open_ok: mov in_handle,AX ;Save file handle mov buf_pos,0 ;Init buffer position call read_hdr ;Read in first header jnc got_1st ;If clear, we're OK ; Truncated file. Somethings weird in Denmark! mov AX,19 ;Truncated file inv_hdr: call err_msg ;Put it on screen stc ret ;Exit Sort_It with error ; If we get this far, the first header has been read in. Stuff it in ; the buffer and go for the rest... got_1st: mov SI,cmdtail ;Point to arc data cmp byte ptr [SI+1],0 ;End of Archive? jne Chk_Crushed ;Exit for sort jmp got_em Chk_Crushed: cmp byte ptr [SI+1],10 ;Crushed file? jb Not_Crushed ;Nope, continue mov Crushed,true ;Else, show crushed Not_Crushed: cmp byte ptr [SI],1ah ;Do we have a PAK file? je pak_ok ;If yes, keep going mov AX,20 ;Invalid header call err_msg ;Report error in english add sp,2 ;Remove return address mov AH,CloseFile ;Close the file mov BX,in_handle int DOS ;Call DOS to close file mov byte ptr elevel,1 ;Report error for no delete jmp main ;Bad file, try the next one pak_ok: mov DI,offset hdr_buf ;Get buffer address add DI,[buf_pos] ;Adjust to current pos mov AX,low_pos ;Get file pointer low word mov [DI],AX ;Stuff it in buffer mov AX,high_pos ;Get file pointer high word mov [DI+2],AX ;Stuff it in buffer add DI,4 ;Adjust the pointer mov CX,29 ;Length of archive header rep movsb ;Put info in buffer add buf_pos,arc_len ;Bump the buffer pointer inc num_hdr cmp num_hdr,Entries ;Have we got too many? jb room ;Nope, continue... mov AX,21 ;Too many archive entries jmp nope ;Report and exit room: call read_next ;Get next header jnc got_1st ;Go stuff it in buffer jmp short got_em ;Got all headers, exit read_next: mov DI,cmdtail ;DI = start of header mov DX,word ptr [DI+15] ;DX = low byte of arc size mov CX,word ptr [DI+17] ;CX = high byte of arc size mov BX,in_handle ;BX = opened file handle mov AH,MoveFilePointer ;AH = move file pointer mov AL,1 ;AL = from current position int DOS ;Give it to DOS read_hdr: mov BX,in_handle ;Get opened file handle xor CX,CX ;Set offset for search xor DX,DX ; to zero bytes mov AH,MoveFilePointer ;AH = move file pointrr mov AL,1 ;AL = from currcnt position int DOS ;Call DOS to do it mov high_pos,DX ;Save the high word mov low_pos,AX ;Save the low word mov BX,in_handle ;Get opened file handle mov CX,29 ;Read in 29 bytes mov DX,cmdtail ;Buffer for read... mov AH,ReadFile ;Read from file int DOS ;Give it to DOS ret got_em: mov Order,true ;Archive already in order cmp byte ptr N_Flag,false ;Skip sort? jne sort ;If yes, exit mov BX,in_handle ;Get the file handle mov AH,CloseFile ;So we can close it int DOS ;Call DOS to do it jmp Back_to_main ;Exit sort sort: mov flag,false ;Show no changes made mov count,1 ;To prevent sort past end mov AH,num_hdr ;Get number of entrys cmp AH,1 ;Is there only 1 entry? jbe sort_exit ;No sort if 0 or 1 entry mov SI,offset hdr_buf ;SI = start of header buffer mov DI,offset hdr_buf+arc_len ;DI = 2nd entry in buffer sort1: mov BX,23 ;BX = offset to header date mov AX,[SI+BX] ;Get date from 1st entry mov DX,[DI+BX] ;Got date from 2nd entry cmp AX,DX ;Which is higher? ja change ;Swap if 1st > 2nd jne sort2 ;If not = get next entry mov BX,25 ; else get offset to time mov AX,[SI+BX] ;Get time from 1st entry mov DX,[DI+BX] ;Get time from 2nd entry cmp AX,DX ;Which is higher? ja change ;Swap if 1st > 2nd ; If Date and Time are identical, no changes are made sort2: add SI,arc_len ;Point to next entry add DI,arc_len ;Point to next entry inc count ;Bump # of entries completed mov AH,count ;Get the number cmp AH,num_hdr ;Done all entries? je pass ;End of this pass if yes jmp short sort1 ;Else do next entry ; This section will swap the entry pointed to by SI with the entry ; pointed to by DI... change: push SI ;Save pointer to 1st entry push DI ;Save pointer to 2nd entry mov CX,arc_len ;# of bytes in an entry chg1: mov AL,[DI] ;Get byte from destination movsb ;Move Source to Destination mov [SI-1],AL ;Move Destination to Source loop chg1 ;Loop back for more pop DI ;Restore 2nd entry address pop SI ;Restore 1st entry address mov flag,true ;A swap has been made (pass) mov Order,false ;Show swap made (constant) jmp sort2 ;Do next entry ; Here we check if a change was made. If no changes were made ; then the archive was already in order... pass: mov AH,flag ;Get the sort flag cmp AH,true ;Was a change made? je sort ;Go again if change was made sort_exit: mov AL,Order ;Was archive in order? cmp AL,true ;If yes, do not write jne write mov BX,in_handle ;Get the file handle mov AH,CloseFile ;So we can close it int DOS ;Call DOS to do it jmp Back_to_main ;The file out again. write: mov DI,offset tempspec ;point to temp filespec .jjn mov SI,offset cmd1 ;get location of command .jjn mov CX,pathlen ;get path length .jjn rep movsb ;make a copy .jjn mov SI,offset temp ;Point to temp filename .jjn mov CX,thomlen ;get length of filename .jjn rep movsb ;copy it after the path .jjn mov DX,offset tempspec ;Point to temp filespec .jjn xor CX,CX ;Use normal attribute mov AH,CreateFile ;AH = create or truncate int DOS ;Call DOS to do it jnc create_ok ;Go if all is well nope: call err_msg ;Report error in english stc ;Carry = Sort failed ret ;Back to main section ; Here, the temp file has been created and the handle for that file is ; in AX. create_ok: mov out_handle,AX ;Save handle for write file ; Now, we have to read in the sorted entry info, and gather more stuff ; from the archive headers mov SI,offset hdr_buf ;Point to the sorted info mov AL,num_hdr ;Get number of entries nxt_hdr: mov flag,false ;Use flag for eof check push AX ;Save # of entries for later push SI ;Save buffer pointer mov DX,[SI] ;Get low word of file position mov CX,[SI+2] ;Get high word of position mov low_pos,DX mov high_pos,CX clc add DX,29 ;Adjust for arc header adc CX,0 ;Include carry if any mov BX,in_handle ;Get read file handle mov AL,0 ;Offset is from beginning mov AH,MoveFilePointer ;AH = move file pointer int DOS ;Call DOS to do it ; The file pointer has been set to the read location. First we ; write the header. Then we read and write the archive data. hdr_in: call info ;Print the copy info pop DX ;Get buffer pointer push DX ;And save it again add DX,4 ;Skip past file location mov CX,29 ;Number of bytes to write mov BX,out_handle ;Get the write file handle mov AH,WriteFile ;AH = write to file int DOS ;Call DOS to write the header jnc hdr_out ;Header written ... go add sp,4 ;Get rid of stack junk jmp short nope ;Exit, we had problems hdr_out: pop SI ;Point to the header push SI ;Save it back mov DX,[SI+21] ;Get high word of entry size mov AX,[SI+19] ;Get low word of entry size ; DX:AX contains the number of bytes that have to be read/written. xor CX,CX ;High word of buffer size mov BX,bsize ;Low word of buffer size ; CX:BX contains the number of bytes we can do at one time. cont: clc ;Get ready for subtract sub AX,BX ;Subtract low word sbb DX,CX ;Subtract high word push AX push DX push BX push CX jae more1 ;There's still more to go clc add BX,AX ;Add back last result mov flag,true ;Show end of data reached ; Here BX contains the remaining number of bytes to read write. ; So we have to put it in CX more1: xchg BX,CX ;Get count in CX mov DX,offset cpy_buf ;Point to our buffer mov BX,in_handle ;Handle for read mov AH,ReadFile ;AH = read file ; Note: CX should contain [bsize] OR the remaining bytes to go... int DOS ;Call DOS to read file jnc data_ok ;Got the data add sp,12 ;Remove stack junk jmp nope ;Exit, we had probs... data_ok: mov BX,out_handle ;Handle for write mov AH,WriteFile ;AH = write to file int DOS ;Call DOS to write out buffer jnc write_ok ;Go if all is well, else add sp,12 ;Remove junk from stack jmp nope ;Exit... write_ok: cmp flag,true ;Was this end of arc data? je do_next ;Get next header if yes pop CX ;Low word buffer size pop BX ;Low word file size pop DX ;High word file size pop AX ;Low word buffer size jmp cont ;Continue with this entry do_next: add SP,8 ;Clear junk off stack pop SI ;Get back buffer position add SI,33 ;Adjust to next entry pop AX ;Get back number of entrys dec AL ;Subtract 1 from it jz no_more ;We're done with data jmp nxt_hdr ;Else go get the next one no_more: ; Before we quit, we have to write out a 1A 00 to show the end of ; the archive. mov AH,WriteFile ;AH = write to file mov BX,out_handle ;Handle for write file mov CX,2 ;Number of bytes to write mov DX,offset end_arc ;Point to the data int DOS ;Call DOS to do it jnc delete ;We're finished ! jmp nope ;Exit sort routine ; Now that the meat of the work is done, we have to delete the old ; arc file and rename the new one. delete: mov BX,in_handle mov AH,CloseFile int DOS mov BX,out_handle mov AH,CloseFile int DOS mov DX,offset cmd1 ;Point to original name mov AH,DeleteFile ;AH = delete file int DOS ;Call DOS to do it jnc del_ok jmp nope del_ok: mov AH,RenameFile ;AH = rename file mov DI,offset cmd1 ;Original filename mov DX,offset tempspec ;Temporary filename .jjn int DOS ;Call DOS to do it jnc Back_to_main ;Go if no problems jmp nope ;Exit program... Back_to_main: clc ;Sort done. No errors ret ;Return to main section ; Convert double word to ascii decimal. Uses divide instruction ; Parameters passed in registers as follows: ; DX:AX = binary word to be converted DecimalOut: push DI push AX mov DI,offset decbuf ; address of output buffer mov CX,7 ; buffer length-1 mov AL,' ' ; pad character rep stosb ; clear buffer & point to end mov byte ptr [DI], 0 ; init end of string dec DI pop AX ;Get low word back xchg BP,DX ;Save high word mov BX,10 ;Use base 10 for decimal mov CL,30h ;For conversion to ASCII HighWordLoop: or BP,BP ;Are we done with high words? jz LowWordLoop ;Yes xchg AX,BP ;No, get high word xor DX,DX ;Clear DX div BX xchg BP,AX ;Save new high word div BX ;Divide low word + remainder or DL,CL ;Convert hex value to ASCII mov [DI],DL ;Save decimal character dec DI ;Back up in the buffer jmp HighWordLoop ;Repeat until done LowWordLoop: xor DX,DX ;Clear DX div BX or DL,CL ;Convert hex value to ASCII mov [DI],DL ;Save decimal character dec DI ;Back up in the buffer or AX,AX ;Are we done? jnz LowWordLoop ;No pop DI ret Sort_It endp ;Convert an ASCIIZ string to upper case. ; Call with SI pointing to string to be converted upper proc near push SI ; save string address up1: lodsb ; next character or AL,AL ; found end (null byte) ? jz up2 ; yes, jump cmp AL,'a' ; test if in range 'a'-'z' jb up1 ; skip it if not >= a cmp AL,'z' ja up1 ; skip it if not <= z sub byte ptr [SI-1],'a'-'A' ; change char to upper case jmp up1 ; get another char up2: pop SI ; restore original string ret ; address and return upper endp ; This routine is called by the sort. It prints a line of information ; for every entry in the archive detailing its size, filename, and ; new locatio in the archive.... info proc near mov SI,offset msg1 ;SI = 'Adjusting' call ShowIt ;Put it on screen mov BP,SP ;Get stack pointer mov SI,[BP+2] ;SI = address of arc entry add SI,6 ;Now SI points to filename push SI ;Save address for later call ShowIt ;Put it on screen mov CX,14 ;Tab length for info screen sub CL,Characters ;Subtract # of chars printed mov DL,blank ;AL = space mov AH,CharacterOutput ;Function = console out info_loop: int DOS ;Call DOS to print space loop info_loop ;Loop till tab is complete mov SI,offset msg2 ;SI = 'Location =' call ShowIt ;Put it on screen mov DX,high_pos ;High word file position mov AX,low_pos ;Low word file position call DecimalOut ;Convert to ASCII and print mov SI,offset decbuf ;Yes, String address to SI call ShowIt ; Output it mov SI,offset msg3 ;SI = 'Length =' call ShowIt ;Put it on screen pop SI ;Restore Arc filename address mov AX,[SI+13] ;Low word file size mov DX,[SI+15] ;High word file size clc ;Get ready for addition add AX,29 ;Add in length of header adc DX,0 ;Add in any carry call DecimalOut ;Convert to ASCII and print mov SI,offset decbuf ;Yes, String address to SI call ShowIt ; Output it mov SI,offset crlf ;SI = cr/lf call ShowIt ;Put it on screen ret ;Return to caller info endp ; This routine prints one of DOS's error messages and returns to ; which ever section of the code called it... err_msg proc near push AX ;Save errorlevel dec AX ;Adjust for beginning of table add AX,AX ; * 2 for DW variables mov SI,AX ;Get offset in SI mov SI,errmsg[SI] ;Now SI = address of string call ShowIt ;Put it on screen pop AX ;Restore errorlevel ret err_msg endp ;************************************************************************ ; FindNames: find all file names matching the file specification in cmd1. ; REGISTERS ON EXIT: ; AX = number of files found (may be 0). ; ZF = reset if files found, set if no files found. ; This procedure written by Jeffrey J Nonken. (Modified by Dan) ;************************************************************************ public FindNames FindNames proc near mov DI,offset save_buf ;Get dest addresm of filename mov AL,num_names ;Get # of names already there mov CL,13 ;Length of 1 entry mul CL ;Names * 13 add DI,AX ;Now DI points into buffer mov AH,SearchForFirst ;AH = Search for first xor CX,CX ;Attribute = 'normal' mov DX,offset cmd1 ;Point to ASCIIZ filename int DOS ;Give it to DOS jnc get1fname ; Found a file, process it jmp no_files ;Finished with search ; Loop to here if buffer was written to disk. clean_buf: mov num_names,0 ; no more names in the buffer mov DI,offset save_buf ;Get dest address of filename ; Loop to here after each file name, look for the next one. next: mov AH,SearchForNext ;AH = Search for next int DOS ;Give it to DOS jnc get1fname ; Found a file, process it jmp short NoMoreFiles ; If not, quit now. get1fname: ;Now we move the filename.ext up to our own ASCIIZ string ;so that open can use the correct path to the file. mov SI,offset dta_buf+30 ;SI = filename found mov CX,6 ; Name is <= 13 bytes ; (including trailing null) rep movsw ; Move 12 bytes (6 words) movsb ; Move the last byte inc name_count ; Count up (total count) inc num_names ; Count up (buffer count) cmp num_names,NamesFound ; See if we have names yet jb next ; Just repeat if not ; If we got here, there were at least 'NamesFound' names. ; Start writing them to disk. cmp on_disk,0 ; See if there's a file open jnz already_open ; If so, skip the open step mov DX,offset filename_file ; Get the file's name mov AH,CreateFile ; Open the file xor CX,CX ;No attributes int DOS ; Do it mov files_handle,AX ; Save the file handle(error) jnc already_open ; If no errors, write to file call err_msg ;Report error in english mov DX,offset TempErr ;Unable to create file mov AH,OutputString ;DOS print string function int DOS ;Display error jmp short NoMoreFiles ;Continue on ; If the temporary file can't be created, we exit here. This will allow ; SPAZ to process at least 'NamesFound' archives before quitting. If this ; is a disk full condition, it will be reported by the un-archiver. already_open: mov DX,offset save_buf ; point to buffer mov BX,files_handle ; get the file handle mov CX,13 * NamesFound ; number of file names to write mov AH,WriteFile ; write to the file int DOS mov on_disk,1 ; say it's on disk jmp clean_buf ; loop around and clear buffer ; No more files found. Clean up and exit. NoMoreFiles: ; Last file was found cmp on_disk,0 ; see if there is a files file jz no_files ; if not, just return cmp num_names,0 ; see if any left in buffer jz no_files mov AL,num_names ; Yes, get the number of names mov BL,13 ; length of a name mul BL ; how many bytes to write mov DX,offset save_buf ; point to buffer mov BX,files_handle ; get the file handle mov CX,AX ; number of bytes to write mov AH,WriteFile ; write to the file int DOS ; Hmmmmm. If disk is full, un-archiver will report error. If it's just ; a bad read/write, DOS's abort, retry, ignore will display. Don't ; think we have to check? ; All files (if any) have been found and buffered or written to disk. Save ; the address of the buffer in case we have files in the buffer. Restore the ; DTA. no_files: mov fname_ptr,offset save_buf ;Address of scratch space mov names_used,0 ; No names used yet ret FindNames endp ;**************************************************************************** ; wild_card: Each time called this returns the next name in the list, if any. ; It 'returns' it by copying it into the end of the command line buffer ; after the path so it can be used immediatly. If it has no more names, ; it exits the program. ; This procedure written by Jeffrey J. Nonken (and mangled by Dan) ;**************************************************************************** public wild_card wild_card proc near mov AX,names_used ; Get number of names returned cmp AX,name_count ; Compare to total # of names jb more_names ; If less, we still have some ; We have no names left to return. See if they were on disk. If so, close up. cmp on_disk,0 ; see if on disk jz w_skip_close ; if not, skip over the close mov AH,CloseFile ; close file command mov BX,files_handle ; get the file handle int DOS mov AH,DeleteFile ; Delete file command mov DX,offset filename_file ; Name of file to delete int DOS ; Delete our scratch file w_skip_close: mov AL,elevel ;Get last reported errorlevel mov AH,ExitWithCode ;Terminate with return code int DOS ;Exit program ; We still have names left. Let's see if they're on disk. more_names: cmp on_disk,0 ; Are they stored on disk? jz not_on_disk ; If not, get from the buffer. ; If we got here, the files are stored on disk. Read one name, 13 bytes, right ; into the file spec. The name was originally null terminated, so extra junk ; on the end won't matter. mov AH,ReadFile ; Read file command mov BX,files_handle ; get the file handle mov DX,endpath ;Get end address of path mov CX,13 ; Read 1 filename int DOS jnc w_got1 ; If no carry, we got it ; If we can't process the temp file, SPAZ has no filenames to work with. ; The only safe thing to do, is exit with the errorlevel. This will leave ; any archives intact so they can be handled later. call err_msg ;Report error in english mov DX,offset TempErr ;Error processing temp file mov AH,OutputString ;DOS print string function int DOS ;Display error mov AH,ExitWithCode ;Terminate SPAZ int DOS ;Tell DOS to do it ; If we got here, there are four or fewer filenames, and they are in the ; scratch buffer. fname_ptr points to the current filename. Just copy all ; 13 bytes in; as before, the name was already null terminated. not_on_disk: push SI ; Save the index registers push DI mov SI,fname_ptr ; get the current source ptr mov DI,endpath ; Get end address of path mov CX,6 ; copy 12 bytes (6 words) rep movsw movsb ; copy the 13th byte mov fname_ptr,SI ; save the new pointer pop DI ; restore the index registers pop SI ; One way or another, we copied a filename. w_got1: inc names_used ; Note that we used a name clc ; Clear the carry flag ret wild_card endp ; The following routine scans each command line option and sets various ; flags according to options used. options proc near cld ;Ensure forward movements xor AX,AX ;Start with argument 1 Opt0: inc AX ;Bump argument number push AX ;Save argument number mov BX,cmdtail ;Point BX to command line call argv ;Get info on argument or AX,AX ;Did we find an argument? jnz StillMore jmp end_Opts ;Nope, we must be done... StillMore: push AX ;Save argument length mov SI,BX ;Address in SI call upper ;Convert to upper case lodsb ;Get first character cmp AL,'/' ;Is this an option? je Opt1 ;Go get it if yes cmp AL,'-' ;Option? jne arc_name ;Get archive name Opt1: pop AX ;Get argument length back push AX ;Maintain stack balance cmp AX,2 ;Check for valid size jne bad_opt ;Report bad option lodsb ;Get option ID cmp AL,'D' ;Delete flag? jne Opt2 ;Next check if not mov byte ptr D_Flag,true ;Set flag to delete arc's jmp short nxt_opt ;Do next option Opt2: cmp AL,'N' ;Sort flag? jne Opt3 ;Next check if not mov byte ptr N_Flag,false ;Set flag for no sort jmp short nxt_opt ;Do next option Opt3: cmp AL,'A' ;Default arc program flag? jne Opt4 ;Next check if not mov byte ptr A_Flag,true ;Set flag to show default set jmp short nxt_opt ;Do next option Opt4: cmp AL,'V' ;Verbose mode desired? jne Opt5 ;Next check if not mov byte ptr Q_Flag,false ;**Kludge** inverted quiet jmp short nxt_opt ;Do next option Opt5: cmp AL,'F' ;Is this a mail run? jne Opt6 ;Report bad option if not mov byte ptr F_Flag,true ;Set up for mail run jmp short nxt_opt ;Do next option Opt6: cmp AL,'O' ;Overwrite mode? jne Opt7 ;Make 1 more check mov byte ptr O_Flag,true ;Set overwrite mode jmp short nxt_opt Opt7: cmp AL,'R' ;For Opus compatibility jne bad_opt ;Report bad option if not mov byte ptr O_Flag,true ;Set overwrite mode jmp short nxt_opt bad_opt: call CheckMFlag ;Are we expanding addresses? jnc Nxt_Opt ;It's Ok, keep going mov AX,23 ;Unknow option used... call err_msg ;Report it jmp syntax ;Show syntax screen and exit arc_name: pop AX ;Get length back push AX ;Maintain stack balance cmp byte ptr Got_name,true ;Do we have an archive name? jne arc_name1 ;Nope, go get it call parse_line ;Yup, pass it the filenames... jmp short nxt_opt ;Continue with options arc_name1: mov Opt_Address,BX ;Save address of file name mov Opt_Length,AX ;Save length of file name mov byte ptr Got_name,true ;Set flag to show we got it! nxt_opt: pop AX ;Remove argument length pop AX ;Get arg number to work on jmp Opt0 ;Continue... end_Opts: add SP,2 ;Clean off stack junk cmp byte ptr Got_name,true ;Did we get a filename? jne bad_line ;Report error if not cmp F_Flag,true ;Is this a mail run? jne RestoreArg ;Go if not mov byte ptr D_Flag,true ;Set auto delete mov byte ptr N_Flag,true ;Force an archive sort mov byte ptr O_Flag,true ;Force overwrite mode RestoreArg: mov AX,Opt_Length ;Get length of argument mov BX,Opt_Address ;Get address of argument ret ;And we are outa' here.. ;If the program falls through to here, all arguments were examined and ;an archive name was NOT found. Report an error, show the syntax screen ;and quit. What else can we do? bad_line: mov AX,24 call err_msg jmp syntax options endp CheckMFlag proc near lodsb ;Get next character cmp AL,'M' ;Is this the M flag? jne NotTheMFlag ;Exit if no call DecimalIn ;Get net number mov word ptr OurNet,DX ;Save it call DecimalIn ;Get node number mov word ptr OurNode,DX ;Save it mov M_Flag,true ;Set our flag clc ;Show we processed it ret ;And exit NotTheMFlag: stc ;Oops, a boo-boo... ret ;Back to caller CheckMFlag endp ; This routine displays the current settings of the command line ; parameters. i.e. will sort, will not delete etc... show_opt proc near push AX push BX cmp byte ptr Q_Flag,true ;Quiet mode? jne NotQuietMode jmp show_x ;Exit if yes NotQuietMode: cld ;Ensure forward movements mov SI,offset will ;Point to will message cmp byte ptr A_Flag,true ;Use Arce? je show1 mov SI,offset wont show1: call ShowIt mov SI,offset info1 call ShowIt mov SI,offset will cmp byte ptr D_Flag,true ;Delete archives? je show2 mov SI,offset wont show2: call ShowIt mov SI,offset info2 call ShowIt mov SI,offset will cmp M_Flag,true ;Expand net address? je show3 mov SI,offset wont show3: call ShowIt mov SI,offset info5 call ShowIt mov SI,offset will cmp F_Flag,true ;A mail run? je show4 mov SI,offset wont show4: call ShowIt mov SI,offset info6 call ShowIt mov SI,offset will cmp byte ptr O_Flag,true ;Force overwrite mode? je show5 mov SI,offset wont show5: call ShowIt mov SI,offset info7 call ShowIt mov SI,offset will cmp byte ptr N_Flag,true ;Sort archive? je show6 mov SI,offset wont show6: call ShowIt mov SI,offset info3 call ShowIt show_x: pop BX pop AX ret show_opt endp ; This procedure converts an ASCII number to it's binary form. The ; routine will exit when the first non-ascii-number is reached. The ; binary value is returned in DX. DecimalIn proc near xor DX,DX ;Initialize variable DecimalLoop: lodsb ;Get first character sub AL,30h ;Subtract ASCII base jl DecimalExit ;If too low, we're finished cmp AL,9 jg DecimalExit ;If too high, we're finished cbw ;Convert to word value push AX ;Save digit mov AX,DX mov CX,10 ;Working with base 10 mul CX ; 10 * digit mov DX,AX ;Result in DX pop AX ;Get number back add DX,AX ;Add number in jmp short DecimalLoop ;Get next digit DecimalExit: ret ;Back to main section DecimalIn endp ; This routine parses filenames from the command line that must be passed ; to the unarchive program. parse_line proc near cld ;Go in the right direction! mov Parsed,true ;Show names were parsed mov CX,word ptr Names_Count ;Get current character count push AX ;Save argument length add AX,CX ;AX = new length total mov SI,BX ;Argument address to source mov DI,offset Extract_Names ;DI = buffer address add DI,CX ;Adjust to current position mov byte ptr [DI],blank ;Add in a space inc DI ;Adjust pointer inc AX ;Add 1 to total length mov word ptr Names_Count,AX ;Save new total length pop CX ;Get argument length in CX rep movsb ;Move extract name into buffer mov byte ptr [DI],0 ;End it with a null ret parse_line endp DisplayNode proc near cmp M_Flag,true ;Should we do this? jne ExitDisplayNode ;Exit if not mov SI,endpath ;Point to bundle name call GetFromAddress ;Decode the Address mov DI,offset BuildNet ;Where to store it mov AX,word ptr FromNet ;Get the Senders net mov DX,word ptr OurNet ;Get our own net add AX,DX ;Figure out the difference xor DX,DX ;Get ready for conversion call DecimalOut ;Convert to ASCII call InsertAddress ;Add Net number to string mov AL,'/' ;Address delimiter stosb ;Stuff it in mov AX,word ptr FromNode ;Get the Senders node mov DX,word ptr OurNode ;Get our node address add AX,DX ;Figure out the difference xor DX,DX ;Get ready for conversion call DecimalOut ;Convert to ASCII call InsertAddress ;Add node number to string mov byte ptr [DI],0 ;Make it ASCIIZ ExitDisplayNode: ret ;Back to main DisplayNode endp InsertAddress proc near mov SI,offset DecBuf ;Point to ASCII buffer Insert1: lodsb ;Get a byte cmp AL,blank ;Is it ASCII space? je Insert1 ;Loop if yes Insert2: stosb ;Not 0, we keep it... lodsb ;And get another or AL,AL ;Check for end jnz Insert2 ;Loop till finished ret ;Back to caller InsertAddress endp GetFromAddress proc near call GetNet ;Get the net bundle is from mov word ptr FromNet,DX ;And save it call GetNet ;Get the node number mov word ptr FromNode,DX ;And save it ret ;That's it! GetNet: xor DX,DX ;Start with 0 mov CX,4 ;Counter for Hex number Net1: lodsb ;Grab a byte sub AL,30h ;Mask off the ASCII jl Net3 ;Too low, exit cmp AL,9 ;0 to 9? jle Net2 ;If yes, no adjustment and AL,5fh ;Mask off the casing sub AL,7 ;Adjust for A-F jl Net3 ;Quit if too low cmp AL,15 ;Higher than F? jg Net3 ;Quit if too high Net2: push CX ;Save character counter cbw ;Sign extend our number mov CL,4 ;4 bits per hex character sal DX,CL ;Shift over previous value add DX,AX ;And add in the new pop CX ;Restore character counter loop Net1 ;Do 4 characters Net3: ret ;And then exit GetFromAddress endp BuildNet equ $ ;Buffer for Net/Node FromNet equ BuildNet + 12 ;Sending Net FromNode equ FromNet + 2 ;Sending Node OurNet equ FromNode + 2 ;Our Net OurNode equ OurNet + 2 ;Our Node cpy_buf equ OurNode + 2 ;Storage for copy buffer hdr_buf equ cpy_buf + bsize ;Buffer to hold headers cmd1 equ hdr_buf + entries * arc_len ;Buffer for wildcard filenames new equ cmd1 + 80 ;Buffer for Arc path search saved equ new + 80 ;Buffer for Arc exec decbuf equ saved + 192 ;Buffer for decimal conversions dta_buf equ decbuf + 8 ;Disk Transfer Area Def_Arc equ dta_buf + 43 ;Default Archive Name Fcb1 equ Def_Arc + 13 ;File Control Block 1 Fcb2 equ Fcb1 + 37 ;File control Block 2 Cmd_Cnt equ Fcb2 + 37 ;Command Line Char Counter ExtractOptions equ Cmd_Cnt + 1 ;Options to pass to Un-Archer Pakfile equ ExtractOptions + 9 ;Filenames to pass to Un-Archer Extract_Names equ Pakfile + 160 ;Buffer for names to extract Names_Count equ Extract_Names + 128 ;Count for names to extract tempspec equ Names_Count + 2 ;Scratch for temp filespec .jjn save_buf equ tempspec + 80 ; Filename buffer .jjn stk equ save_buf + (13 * NamesFound) ;Stack Area .jjn bottom equ stk + 200 ;End of code and data cseg ends end entry