?codesize
?resize TRUE
?parsecommandline TRUE
?align
?use80386

?include "STRING.H--"
?include "KEYCODES.H--"
?include "dos.H--"
?include "file.h--"
?include "DWRITE.h--"
?include "WRITE.h--"
?include "IO.h--"
?include "SYSTEM.H--"
?define NULL 0
?define MINLEN 	3	/* Minimum possible match lenght for this */
?define BLOCKLEN 0X8000
word ib=0;
word ob=0;
word ibl,obl,ibf;
?include "ERROR.C--"
?include "asc.c--"
?include "dostounx.c--"
?include "HSC.C--"
?include "PRINTF.I--"

//commands
?define ADD		  'A'
?define EXTRAC  'E'
?define PEXTRAC 'X'
?define LIST	  'L'
?define DELETE  'D'
?define TEST	  'T'
?define FRESHEN 'F'
?define UPDATE  'U'
?define YES		  'Y'
?define RECURSE 'R'
?define MOVE		'M'
?define ARC_OLD	1			/* Mode flags for arc_open()	*/
?define ARC_NEW 2
?define ARC_RDO 4
?define MYVER   	2			/* Version info in archives 	*/
?define LOWVER  	2			/* Lowest supported version 	*/
?define MSDOSMDH	1		/* Identifiers for machine 	*/
?define UNIXMDH		2		/*   specific header data 	*/
?define STRING	300/16
?define CRCCALC		1	/* flag to setinput/setoutput */
?define PROGDISP	2	/* flog to setinput/setoutput */
?define CRCMASK		0xffffffff
?define CRCP		0xEDB88320
?define F_OK	0
?define ATRIBFINDFILE 0X17
?define OFSATR 0X15
?define NAMEDTA 0X1E
?define MAXNUMDIR 255
?define OFSDATE 0X18
?define OFSTIME 0X16
?define OFSSIZE 0X1A
?define SIZEBUFDTA MAXNUMDIR*0X2C/16+1
enum {M_CPY=0,M_ASC,M_HSC,M_UNK,M_DIR=14,M_SPECIAL};  /* Method types	*/

//инициализированые переменные
byte metqueue[M_UNK+1]={M_UNK};
byte BANNERS="HA %s%c Copyright (c) 1995 Harri Hirvola\n";
byte MYNAME="Optimization of speed Sheker Mishel 1996 Udomlia.\n";
byte VERS="0.9991";
byte NONE="none ??";
byte defpat="*.*";
byte ty_sp="  ";
byte dirty=0;
byte quiet=0,useattr=0;//,special=0;
byte fulllist=0,usepath=1,yes=0,touch=0,recurse=0,savedir=0,move=0;
byte skipemptypath=0,sloppymatch=1;
byte INFO="\n usage : HA <cmd> archive [files]"
	    "\n\n commands :"
	    "\n   a[sdqemr012] - Add files      d[q]         - Delete files"
	    "\n   e[aqty]      - Extract files  f[sdqemr012] - Freshen files NOT SUPPORTED"
	    "\n   l            - List files     u[sdqemr012] - Update files NOT SUPPORTED"
	    "\n   t[q]         - Test files     x[aqty]      - eXtract files with pathnames"
	    "\n"
	    "\n switches :"
	    "\n   0,1,2  - try method (0-CPY,1-ASC,2-HSC)"
	    "\n   t      - Touch files          r      - Recurse subdirs"
	    "\n   f      - Full listing         y      - assume Yes on all questions"
	    "\n   m      - Move files           a      - set system specific file Attributes"
	    "\n   e      - Exclude pathnames    s      - Special long compress"
	    "\n   q      - Quiet operation      d      - make Directory entries\n";
byte DBLLINE="\n═══════════════════════════════════════════════════════════════════════════";
byte method="CPY\000ASC\000HSC\000DIR";
byte crctabok=0;
byte SDQEMR012="SDQEMR012";
byte arc_seek="arc_seek";
byte arc_delete="arc_delete";
byte FF="\255";
byte arc_clean="arc_clean";
byte P5B=" %\008\008\008\008\008";
byte arc_addfile="arc_addfile";
byte delold="delold";
byte arc_adddir="arc_adddir";
word arccnt=0;
word maxcnt=1024,ATRIBF=0X27;

//не инециализированые переменные
byte NSP;
byte addtries,attr;
byte drive[MAXDRIVE],dir[MAXDIR],file[MAXFILE],ext[MAXEXT],arcname[MAXPATH+4];
byte type;
byte ver;
byte path[256];
byte name[13];
byte mdilen;
byte mylen;
byte r_crc,w_crc,r_progdisp,w_progdisp;
byte NEWARX;
byte fullname[256];
byte BUFF[256];
byte NUMDIR;
byte fulname[MAXDRIVE+MAXDIR];

word command,addthis;
word ARGM,patcnt;
word arcfile;	//ДЕСКРИПТОР АРХИВНОГО ФАЙЛА
word inname,outname,infile,outfile;
word write_on;
word fpath;
word SEGDTA,OFSDTA;
word OFSPATSH[MAXNUMDIR];
dword arcsize;	//РАЗМЕР АРХИВНОГО ФАЙЛА
dword totalsize;
dword icnt,ocnt;
dword crctab[256];
dword clen;
dword olen;
dword time;
dword hcrc;
dword nextheader,thisheader;
dword crc;
dword trypos,bestpos;
dword crcf;

USAGE()
{
	$PUSH AX
	BANNER();
	DWRITESTR(#MYNAME);
	DWRITESTR(#INFO);
	$POP AX
	EXIT();
}

?define SIZE_IO BLOCKLEN/16

SET_BUF_IO()
{
	ib=GETMEM(BLOCKLEN/8);
	$OR AX,AX
	IF(ZEROFLAG)error(1,ERR_MEM,"input/output bufer",AX);
	ob=AX+SIZE_IO;
}

FREE_BUF_IO()
{
	FREEBL(,#ib);
	FREEBL(,#hrt);
}

BANNER()
{
	PRINTF(#BANNERS,#VERS,'a');
}

switchparse(word ss,valid)
{
	$PUSH SI
	SI=ss;
	if(DSBYTE[SI]!=0){
		do
		{
			$PUSH SI
			STRCHR(valid,DSBYTE[SI]);
			$POP SI
			AX|=AX;
			IF(ZEROFLAG)error(1,ERR_INVSW,DSBYTE[SI],AX);
			AL=DSBYTE[SI];
			AH=AL-'0';
			IF(AL=='Q')quiet=1;
			else IF(AL=='Y')yes=1;
			else IF(AL=='F')fulllist=1;
			else IF(AL=='A')useattr=1;
			ELSE IF(AL=='T')touch=1;
			ELSE IF(AL=='R'){
				recurse=1;
				ATRIBF|=0X10;
			}
			ELSE IF(AL=='S')maxcnt=-2;
			ELSE IF(AL=='D')savedir=1;
			ELSE IF(AL=='E')usepath=0;
			ELSE IF(AL=='M')move=1;
			ELSE IF(AH<M_UNK){
				BX=0;
				do{
					AL=metqueue[BX];
					$CMP AL,AH
					$JZ BRSW
					IF(AL==M_UNK){
						metqueue[BX]=AH;
						metqueue[BX+1]=M_UNK;
						$JMP SHORT BRSW
					}
					BX++;
				} while ( BX<M_UNK );
BRSW:
			}
			ELSE error(1,ERR_INVSW,DSBYTE[SI],AX);
			ss++;
			SI=ss;
		} while ( DSBYTE[SI]!=0 );
	}
	IF (quiet==0) BANNER();
	$POP SI
}

DO_ADD()
word i,found;
{
	i=0;
	found=0;
	SEGDTA=GETMEM(SIZEBUFDTA);
	do{
		fpath=PATTERNS(i);
		STRRCHR(,'\\');
		$OR AX,AX;
		IF(ZEROFLAG){
			OFSPATSH=#BUFF;
			AX=#fulname;
			BX=fpath;
		}
		ELSE{
			AX++;
			BX=AX;
			AX-=fpath;
			AX=AX+#BUFF;
			OFSPATSH=AX;
			AX=#fulname;
		}
		strcpy(AX,BX);
		strcpy(#BUFF,fpath);
		NUMDIR=0;
		found|=FILEFIND();
		i++;
  }while(i<patcnt);
  IF(quiet==0){
		IF(found!=0)DWRITELN();
		ELSE DWRITESTR("\nNothing to do\n");
  }
	FREEBL(,#SEGDTA);
	ARC_CLOSE();
}

int freshentest()
{
}

updatetest()
{
}

DO_EXTRACT()
word ofname,newdir,of;
{
	ARC_RESET();
  IF(ARC_SEEK()==0)error(1,ERR_NOFILES,AX,AX);
	do {
		IF(usepath!=0){
	    MAKEPATH(#path);
			strcpy(#fullname,#path);
			strcat(#fullname,#name);
		  ofname=MD_TOMDPATH(#fullname);
		}
		ELSE ofname=MD_TOMDPATH(#name);
	  if(type==M_DIR){
			strcat(ofname,"\\NUL");
			newdir=ACCESS(ofname,F_OK);
			STRRCHR(ofname,'\\');
			BX=AX;
			DSBYTE[BX]=0;
    	IF(newdir==0){
				IF(useattr!=0){
					YESNO("\nRemake directory %s ? (y/n/a) ",ofname);
					IF(AX==0)$JMP BS
				}
			}
	    IF(quiet==0){
				PRINTF("\nMaking    DIR        %s",ofname);
				BACKSTEP(STRLEN(ofname)+8);
	    }
	    IF(newdir){
				DX=ofname;
				AH=0X39;
				$INT 0X21
				IF(CARRYFLAG)error(0,ERR_MKDIR,ofname,AX);
    	}
	    IF(useattr!=0)CHMOD(,,attr,ofname);
  	  IF(quiet==0)DWRITESTR("DONE");
		}
		else{
			//FIND FILE
			CX=ATRIBFINDFILE;
			DX=ofname;
			AH=0X4E;
			$INT 0X21
    	IF(NOTCARRYFLAG){
				IF(YESNO("\nOverwrite file %s ? (y/n/a) ",ofname)==0)$JMP BS
				CHMOD(,,0,ofname);
			}
			IF (create(ofname,FA_NORMAL)==0){
				error(0,ERR_OPEN,ofname);
				$JMP BS
			}
			of=AX;
   		setinput(arcfile,0,#arcname);
	    IF(quiet!=0)setoutput(of,CRCCALC,ofname);
	    ELSE{
				setoutput(of,CRCCALC|PROGDISP,ofname);
				AX=type<<2;
				BX=AX+#method;
				PRINTF("\nUnpacking %s        %s",,ofname);
				BACKSTEP(STRLEN(ofname)+7);
		  }
		  IF(olen!=0) {
				totalsize=olen;
				AL=type;
				IF(AL==0){
					CPY();
				}
				ELSE IF(AL==1){
					ASC_UNPACK();
				}
				ELSE IF(AL==2){
					HSC_UNPACK();
				}
	  	}
		  ELSE IF(quiet==0)DWRITESTR("100 %");
			getcrc();
			IF(EAX!=hcrc)error(0,ERR_CRC,NULL,AX);
		  IF(touch==0){
				unixtodos(dword time,#ptab,#ttab);
				AX=ptab-1980;
				$SHL AX,9
				BX=DSWORD[#ptab+2];
				AL|=BL;
				BL=0;
				$SHR BX,3
				AX|=BX;

				DX=AX;
				CX=ttab;
				$SHL CL,2
				$SHL CX,3
				AL=DSBYTE[#ttab+2];
				$SHR AL,1
				CL|=AL;
				AX=0X5701;
				BX=of;
				$INT 0X21
			}
  		BX=of;
			AH=0X3E;
			$INT 0X21
	  	IF(useattr!=0)CHMOD(,,attr,ofname);
		}
BS:
  }while(ARC_SEEK()!=NULL);
EN:
  IF(quiet==0)DWRITELN();
	ARC_CLOSE();
}

MAKEPATH()
{
	$PUSH DI
	$PUSH SI
	SI=AX;
	DI=#dir;
	ES=DS;
	do{
		$LODSB
		IF(AL==-1){
			DSBYTE[DI]=0;
			$PUSH DI
			$PUSH SI
			strcat(#dir,"\\NUL");
			IF(ACCESS(#dir,F_OK)!=0){
				STRRCHR(#dir,'\\');
				BX=AX;
				DSBYTE[BX]=0;
				DX=#dir;
				AH=0X39;
				$INT 0X21
				IF(CARRYFLAG)error(0,ERR_MKDIR,#dir,AX);
			}
			$POP SI
			$POP DI
			AL='\\';
		}
		$STOSB
	}while(AL!=0);
	$POP SI
	$POP DI
M1:
}

word YESNO()
{
	IF(yes==0){
		IF(quiet==0){
	    PRINTF(AX,BX);
WK:
			AH=0;
			$INT 0X16
			IF(AH==21){
				AX=1;
				$JMP SHORT EN
			}
			IF(AH==30){
				AX=1;
				yes=AX;
				$JMP SHORT EN
			}
			IF(AH==49){
				AX=0;
				$JMP SHORT EN
			}
			$JMP SHORT WK
		}
	}
	AX=1;
EN:
}

DO_TEST()
word ofname;
{
	ARC_RESET();	//установить указатель на первый файл
	IF(ARC_SEEK()==NULL)error(1,ERR_NOFILES,AX,AX);
	do {
		strcpy(#path,#name);
		ofname=MD_TOMDPATH(#path);
		IF(type==M_DIR){
			IF(quiet==0)PRINTF("\nTesting DIR DONE   %s",ofname);
		}
		else IF(type==M_SPECIAL){
			IF(quiet==0)PRINTF("\nTesting SPC DONE   %s",ofname);
		}
		else{
			setinput(arcfile,0,#arcname);
			IF(quiet) setoutput(-1,CRCCALC,#NONE);
			ELSE{
				setoutput(-1,CRCCALC|PROGDISP,#NONE);
				AX=type<<2;
				BX=AX+#method;
				PRINTF("\nTesting %s        %s",,ofname);
				BACKSTEP(STRLEN(ofname)+7);
			}
			IF(olen!=0){
				totalsize=olen;
				AL=type;
				IF(AL==0){
					CPY();
				}
				ELSE IF(AL==1){
					ASC_UNPACK();
				}
				ELSE IF(AL==2){
					HSC_UNPACK();
				}
			}
			ELSE IF(quiet==0)DWRITESTR("100 %%");
			getcrc();
			IF(EAX!=hcrc)error(0,ERR_CRC,NULL,AX);
		}
	} while(ARC_SEEK()!=NULL);
	IF(quiet==0)DWRITELN();
}

DO_LIST()
dword tcs,tos;
word files;
byte NUMLINESCR;
{
	ES=0;
	NUMLINESCR=ESBYTE[0X484]-2;
	ARC_RESET();
	IF (ARC_SEEK()==0) error(1,ERR_NOFILES,AX,AX);
	SHAPKA();
	tcs=0;
	tos=0;
	files=0;
	do{
		if(type!=0xff){
			PRINTF("\n  %s",#name);
			NSP=16;
			PRINT_SP();
			EAX=olen;
			DWRITEDWORDSP();
			NSP=30;
			PRINT_SP();
			EAX=clen;
			DWRITEDWORDSP();
			NSP=43;
			PRINT_SP();
			IF(olen!=0)EAX=100*clen/olen;
			ELSE AX=100;
			LEFTWORD();
			DWRITE('.');
			IF(olen!=0)EAX=1000*clen/olen%10;
			ELSE AX=0;
			__dwriteword();
			DWRITESTR(" %");
			DWRITESTR(#ty_sp);
			unixtodos(dword time,#ptab,#ttab);
			AX=DSWORD[#ptab];
			__dwriteword();
			DWRITE('-');
			AX=DSWORD[#ptab+2];
			$PUSH AX
			AL=AH;
			WRITENULNUM();
			DWRITE('-');
			$POP AX
			WRITENULNUM();
			DWRITESTR(#ty_sp);
			AX=DSWORD[#ttab];
			$PUSH AX
			AL=AH;
			WRITENULNUM();
			DWRITE(':');
			$POP AX
			WRITENULNUM();
			DWRITESTR(#ty_sp);
			AX=type;
			IF(AX==14)AX=3;
			AX<<=2;
			AX+=#method;
			DWRITESTR();
			tcs+=clen;
			tos+=olen;
			files++;
			IF(files%NUMLINESCR==0)PAUSE();
		}
	}while(ARC_SEEK()!=0);
BW:
	DWRITESTR(#DBLLINE);
	PRINTF("\n  %d",files);
	NSP=16;
	PRINT_SP();
	EAX=tos;
	DWRITEDWORDSP();
	NSP=30;
	PRINT_SP();
	EAX=tcs;
	DWRITEDWORDSP();
	NSP=43;
	PRINT_SP();
	IF(tos!=0)EAX=100*tcs/tos;
	ELSE AX=100;
	LEFTWORD();
	DWRITE('.');
	IF(tos!=0)EAX=1000*tcs/tos%10;
	ELSE AX=0;
	__dwriteword();
	DWRITESTR(" %");
	DWRITELN();
	ARC_CLOSE();
}

WRITENULNUM()
{
	AH=0;
	IF(AX<10){
		$PUSH AX
		DWRITE('0');
		$POP AX
	}
	__dwriteword();
}

LEFTWORD()
{
	IF(AX<100){
		$PUSH AX
		DWRITE(' ');
		$POP AX
	}
	IF(AX<10){
		$PUSH AX
		DWRITE(' ');
		$POP AX
	}
	__dwriteword();
}

PAUSE()
{
	DWRITESTR("\nContinue? ");
	AH=0;
	$INT 0X16
	IF(AH!=21)EXIT(0);
	SHAPKA();
}

SHAPKA()
{
	DWRITESTR("\n  filename        original    compressed   rate     date        time   m");
	DWRITESTR(#DBLLINE);
}

PRINT_SP()
{
	GETXY();
	CL=NSP-AL;
	IF(NOTCARRYFLAG){
		CH=0;
		loop(CX){
			$PUSH CX
			DWRITE(' ');
			$POP CX
		}
	}
}

DO_DELETE()
{
	ARC_RESET();
	IF(ARC_SEEK()==0)error(1,ERR_NOFILES,AX,AX);
	do {
		IF(quiet==0){
			strcpy(#path,#name);
			MD_TOMDPATH(#path);
			BX=AX;
			PRINTF("\nDeleting %s");
		}
		ARC_DELETE();
	}while (ARC_SEEK()!=0);
	IF (quiet==0)DWRITELN();
	ARC_CLOSE();
}

word PARSE_CMDS()
{
	SI=AX;
	$LODSB
	IF(AL==ADD){
		switchparse(SI,#SDQEMR012);
		IF (usepath==0) savedir=0;
		ARCOPEN(ARC_OLD|ARC_NEW);
		FIX_METHODS();
		AX=#DO_ADD;
	}
	else IF(AL==FRESHEN){
		switchparse(SI,#SDQEMR012);
		IF (usepath==0) savedir=0;
		ARCOPEN(ARC_OLD);
		addthis=#freshentest;
		FIX_METHODS();
		sloppymatch=0;
		AX=#DO_ADD;
	}
	else IF(AL==UPDATE){
		switchparse(SI,#SDQEMR012);
		IF (usepath==0) savedir=0;
		ARCOPEN(ARC_OLD|ARC_NEW);
		addthis=#updatetest;
		FIX_METHODS();
		sloppymatch=0;
		AX=#DO_ADD;
	}
	ELSE IF(AL==EXTRAC){
		usepath=0;
		switchparse(SI,"AQTY");
		ARCOPEN(ARC_OLD|ARC_RDO);
		AX=#DO_EXTRACT;
	}
	ELSE IF(AL==PEXTRAC){
		switchparse(SI,"AQTY");
		ARCOPEN(ARC_OLD|ARC_RDO);
		AX=#DO_EXTRACT;
	}
	ELSE IF(AL==TEST){
	 	switchparse(SI,"QE");
		ARCOPEN(ARC_OLD|ARC_RDO);
		AX=#DO_TEST;
	}
	ELSE IF(AL==LIST){
		switchparse(SI,"F");
		ARCOPEN(ARC_OLD|ARC_RDO);
		AX=#DO_LIST;
	}
	ELSE IF(AL==DELETE){
		switchparse(SI,"QE");
		ARCOPEN(ARC_OLD);
		AX=#DO_DELETE;
	}
	ELSE USAGE(1);
}

main()
word i;
{
	IF(@GETCPU()<3){
		DWRITESTR("\nThis program requisite CPY 386 or later.\n");
		EXIT(-1);
	}
	ARGM=@PARAMCOUNT();
	IF(AX<2)USAGE();
//ПРЕОБР ПАРАМЕТРЫ В НИЖНИЙ РЕГИСТР
	i=PARAMSTR(0);
	STR_UP();
	SET_BUF_IO();
	command=PARSE_CMDS(i);
	IF(ARGM==2)patcnt=1;
	ELSE patcnt=ARGM-2;
	$CALL command
	FREE_BUF_IO();
	EXIT(lasterror);
}

word PATTERNS()
{
	BX=ARGM;
	AX+=2;
	IF(BX>AX)PARAMSTR(AX);
	ELSE AX=#defpat;
}
byte SIGNAT="HA\000";

ARCOPEN()
byte MODE,ID[2],dost;
{
	MODE=AL;
	dirty=0;
	ARCNAME(PARAMSTR(1));	//РАЗАБРАТЬ ИМЯ АРХИВНОГО ФАЙЛА
	AL=MODE&ARC_OLD;
	if(AL!=0){
		AL=MODE&ARC_RDO;
		IF(AL)dost=F_READ;
		ELSE dost=F_READWRITE;
		if(FOPEN(dost,,,#arcname)){		//ОТКРЫТЬ
			arcfile=AX;
			@FILELENGTH32(arcfile);
			arcsize=EAX;
			@LSEEKHOME();
			IF(FREAD(,arcfile,2,#ID)!=2)$JMP SHORT ER1
			IF(ID!='H')$JMP SHORT ER1
			IF(ID[1]!='A'){
ER1:
				error(1,ERR_NOHA,#arcname,AX);
			}
			IF(FREAD(,arcfile,2,#arccnt)!=2)$JMP SHORT ER1
			arcsize=ARC_SCAN();
			IF (quiet==0) PRINTF("\nArchive : %s (%d files)\n",#arcname,arccnt);
			NEWARX=FALSE;
			$JMP SHORT EN
		}
	}
	AL=MODE&ARC_NEW;
	IF(AL){
		IF (create(#arcname,FA_NORMAL)>0) {
			arcfile=AX;
			IF (quiet==0) PRINTF("\nNew archive : %s\n",#arcname);
			BX=arcfile;
			DX=#SIGNAT;
			CX=4;
			AH=0X40;
			$INT 0X21
			IF (CARRYFLAG) error(1,ERR_WRITE,#arcname,AX);
			arccnt=0;
			arcsize=4;
			NEWARX=TRUE;
			$JMP SHORT EN
	  }
	}
	error(1,ERR_ARCOPEN,#arcname,AX);
//  cu_add(CU_FUNC,arc_close);
EN:
}

ARCNAME()
{
	FNSPLIT(,#drive,#dir,#file,#ext);
	IF(ext==0)strcpy(#ext,".HA");
	FNMERGE(#arcname,#drive,#dir,#file,#ext);
	STR_UP(#arcname);
}

ARC_SCAN()
dword pos;
{
	$PUSH SI
	pos=4;
	SI=0;
	do
	{
		IF(dword pos>=arcsize){
	    error(0,ERR_CORRUPTED,AX,AX);
	    arccnt=SI;
			$JMP SHORT EN
		}
		DX=SSWORD[#pos];
		CX=SSWORD[#pos+2];
		LSEEK(,arcfile);
		IF (CARRYFLAG) error(1,ERR_SEEK,"arc_seek",AX);
		GETHEADER();
		pos+=clen+mylen;
		IF(ver==0xff) {
	    dirty=1;
	    SI--;
		}
		SI++;
	} while ( SI<arccnt );
	IF(pos!=arcsize) dirty=1;
EN:
	EAX=pos;
	$POP SI
}

GETHEADER()
{
	$PUSH SI
	$PUSH DI
	READFAR(,arcfile,512,ib);
	IF(CARRYFLAG)error(1,ERR_READ,#arcname,AX);
	ES=ib;
	AL=ESBYTE[0];
	IF (AL!=0xff) {
		AH=AL;
		type=AL&0xf;
		ver=AH>>4;
		IF (ver>MYVER) error(1,ERR_TOONEW,AX,AX);
		IF (ver<LOWVER) error(1,ERR_TOOOLD,AX,AX);
		IF (type!=M_SPECIAL)IF(type!=M_DIR)IF(type>=M_UNK)error(1,ERR_UNKMET,type,AX);
  }
	ELSE ver=AL;
	clen=ESDWORD[1];
	olen=ESDWORD[5];
	hcrc=ESDWORD[9];
	time=ESDWORD[13];
	SI=17;
	DI=#path;
	DS=ES;
	ES=SS;
	MOVESTR();
	DI=#name;
	MOVESTR();
	$LODSB
	BL=AL;
	ES=DS;
	DS=SS;
	mdilen=BL;
	mylen=mdilen+20;
	STRLEN(#path);
	mylen+=AX;
	STRLEN(#name);
	mylen+=AX;
	IF (ESBYTE[SI]==MSDOSMDH)attr=ESBYTE[SI+1];
	ELSE {
		IF(type==M_DIR)attr=FA_DIRECTORY;
		ELSE attr=FA_ARCHIVE;
  }
	$POP DI
	$POP SI
}

FIX_METHODS()
{
	$PUSH SI
	IF (metqueue[0]==M_UNK) {
		metqueue[0]=M_ASC;
		metqueue[1]=M_CPY;
		metqueue[2]=M_UNK;
	}
	ELSE {
		SI=0;
		do{
			IF (metqueue[SI]==M_CPY)$JMP SHORT EN;
			SI++;
		} while (metqueue[SI]!=M_UNK);
EN:
		IF (metqueue[SI]==M_UNK) {
			metqueue[SI]=M_CPY;
			metqueue[SI+1]=M_UNK;
		}
	}
	$POP SI
}

ARC_RESET()
{
	nextheader=4;
}

word ARC_SEEK()
//СЧИТЫВАЕТ ЗАГОЛОВОК ИЗ АРХИВА, ПРОВЕРЯЕТ ЕГО НА НЕОБХОДИМОСТЬ ВЫВОДА И
//ЕСЛИ НЕ НАДО ТО ВОЗВР 0
{
WH1:
	EAX=nextheader;
	IF (EAX>=arcsize){
		AX=0;
		$JMP SHORT EN
	}
	DX=DSWORD[#nextheader];
	CX=DSWORD[#nextheader+2];
	LSEEK(,arcfile);
	IF (CARRYFLAG)error(1,ERR_SEEK,#arc_seek,AX);
	GETHEADER();
	thisheader=nextheader;
	nextheader+=mylen;
	DX=DSWORD[#nextheader];
	CX=DSWORD[#nextheader+2];
	LSEEK(,arcfile);
	IF (CARRYFLAG)error(1,ERR_SEEK,#arc_seek,AX);
	nextheader+=clen;
	IF (ver==0xff) dirty=1;
	ELSE{
		MATCH();
		$OR AX,AX
		$JNZ EN
	}
	$JMP SHORT WH1
EN:
}

word MATCH()
//ПРОВЕРЯЕТ НЕОБХ ВЫВОДА ЕСЛИ ДА ТО 1 ИНАЧЕ 0
word i,fullhapath;
{
	i=0;
	do{
		fullhapath=md_tohapath(PATTERNS(i));
		STR_UP(#path);
		STR_UP(#name);
		IF(matchpattern(getpath(fullhapath),getname(fullhapath),#path,#name)){
			AX=1;
			$JMP SHORT EN
		}
		i++;
	}while(i<patcnt);
	AX=0;
EN:
}

word md_tohapath(word mdpath)
word i,j;
{
	$PUSH SI
	i=0;
	do{
		BX=mdpath+i;
		AL=DSBYTE[BX];
		IF(AL!='.')$JMP SHORT BW
		IF(AL!='\\')$JMP SHORT BW
		i++;
	}while(DSBYTE[BX+1]);
BW:
	IF(i==0)$JMP SHORT BW1
	do{
		BX=mdpath+i-1;
		IF(DSBYTE[BX]!='.')$JMP SHORT BW1
		i--;
	}while (i);
BW1:
	IF(i==0)skipemptypath=1;
	ELSE skipemptypath=0;
	j=0;
	do{
		BX=mdpath+i;
		SI=#fullname+j;
		AL=DSBYTE[BX];
		IF(AL=='\\')DSBYTE[SI]=0xff;
		ELSE DSBYTE[SI]=AL;
		j++;
		i++;
	}while(DSBYTE[BX+1]!=0);
	DSBYTE[SI+1]=0;
	STR_UP(#fullname);
	AX=#fullname;
	$POP SI
}

word matchpattern(word matchpath,matchpat,pat,nam)
{
	IF(matchpath)IF(skipemptypath==0)IF(sloppymatch){
		strcmp(matchpath,pat);
		IF(AL!=0){
			AX=0;
			$JMP SHORT EN
		}
	}
	IF(md_namecmp(matchpat,nam))AX=1;
	ELSE AX=0;
EN:
}

getpath(word fullpath)
word i;
{
	i=STRLEN(fullpath);
	loop(i){
		BX=fullpath+i;
		IF(DSBYTE[BX]==0xff){
			STRNCPY(#dir,fullpath,i);
			BX=#dir+i+1;
			DSBYTE[BX]=0;
			AX=#dir;
			$JMP SHORT EN
		}
	}
	AX=0;
EN:
}

byte name2[13];

getname(word fullpath)
word i;
{
	$PUSH SI
	i=STRLEN(fullpath);
	loop(i){
		BX=fullpath+i;
		IF(DSBYTE[BX]==0xff) {
			strcpy(#name2,fullpath+i+1);
			AX=#name2;
			$JMP SHORT EN
		}
	}
	AX=fullpath;
EN:
}

word md_namecmp(word pat,cmp)
{
	$PUSH SI
	do{
		BX=pat;
		SI=cmp;
		AL=DSBYTE[BX];
		IF(AL=='?'){
			AL=DSBYTE[SI];
			IF(AL!='.')IF(AL)SI++;
		}
		ELSE IF(AL=='*'){
WH1:
			AL=DSBYTE[SI];
			IF(AL==0)$JMP SHORT BW
			IF(AL=='.')$JMP SHORT BW
			SI++;
			$JMP SHORT WH1
BW:
			cmp=SI-1;
		}
		ELSE IF(AL=='.'){
			AL=DSBYTE[SI];
			IF(AL=='.'){
				STRRCHR(SI,'.');
				SI=AX;
			}
			ELSE IF (AL){
				AX=0;
				$JMP SHORT EN
			}
			ELSE {
				do{
					BX++;
				}while (DSBYTE[BX]=='?');
				AL=DSBYTE[BX];
				IF(AL==0)$JMP SHORT CN
				IF(AL=='*'){
					do{
						BX++;
					}while(DSBYTE[BX]);
				}
CN:
				BX--;
				pat=BX;
				SI--;
			}
			cmp=SI;
		}
		ELSE IF(AL!=DSBYTE[SI]){
			AX=0;
			$JMP SHORT EN
		}
		cmp++;
		pat++;
		BX=pat;
	}while(DSBYTE[BX]);
	SI=cmp;
	IF(DSBYTE[SI]==0)AX=1;
	ELSE AX=0;
EN:
	$POP SI
}

ARC_DELETE()
{
	DX=DSWORD[#thisheader];
	CX=DSWORD[#thisheader+2];
	LSEEK(,arcfile);
	IF (CARRYFLAG)error(1,ERR_SEEK,#arc_delete,AX);
	BX=arcfile;
	CX=1;
	DX=#FF;
	AH=0X40;
	$INT 0X21
	IF(CARRYFLAG) error(1,ERR_WRITE,#arcname,AX);
	LSEEK(,arcfile,0,2);
	IF(CARRYFLAG) error(1,ERR_SEEK,#arc_delete,AX);
	arccnt--;
	EAX=arccnt;
	putvalue(dword EAX,2);
	dirty=1;
}

putvalue(dword val;word len)
byte buf[4];
{
	$PUSH SI
	SI=0;
	do{
		buf[SI]=val;
		$SHR val,8
		 SI++;
	}while(SI<len);
	BX=arcfile;
	CX=len;
	DX=#buf;
	AH=0X40;
	$INT 0X21
	IF(CARRYFLAG) error(1,ERR_WRITE,arcname,AX);
	$POP SI
}

word MD_TOMDPATH()
//ФУНКЦИЯ УПРОЩЕНА
{
	$PUSH AX
	BX=AX;
	do{
		IF(DSBYTE[BX]==0XFF)DSBYTE[BX]='\\';
		BX++;
	}while(DSBYTE[BX]);
	$POP AX
}

ARC_CLOSE()
{
	IF(arcfile>0){
		IF(arccnt==0){
			REMOVER(,,,#arcname);
			IF(CARRYFLAG)error(1,ERR_REMOVE,#arcname,AX);
		}
		ELSE IF(dirty!=0)ARC_CLEAN();
		BX=arcfile;
		AH=0X3E;
		$INT 0X21
	}
}

ARC_CLEAN()
dword ipos,opos,cpylen;
word len;
word cnt,sizebuf;
{
	ipos=4;
	opos=4;
	cnt=arccnt;
	do{
		DX=ipos;
		CX=SSWORD[#ipos+2];
		LSEEK(,arcfile);
		IF (CARRYFLAG) error(1,ERR_SEEK,#arc_clean,AX);
WH1:
		GETHEADER();
		IF(ver!=0xff)$JMP SHORT BW
		ipos+=clen+mylen;
		DX=ipos;
		CX=SSWORD[#ipos+2];
		LSEEK(,arcfile);
		IF (CARRYFLAG) error(1,ERR_SEEK,#arc_clean,AX);
		$JMP SHORT WH1
BW:
		IF(ipos==opos){
			opos+=clen+mylen;
			ipos=opos;
		}
		else{
			cpylen=clen+mylen;
			do{
				DX=ipos;
				CX=SSWORD[#ipos+2];
				LSEEK(,arcfile);
				IF (CARRYFLAG) error(1,ERR_SEEK,#arc_clean,AX);
				IF(cpylen<BLOCKLEN)sizebuf=cpylen;
				ELSE sizebuf=BLOCKLEN;
				len=READFAR(,arcfile,sizebuf,ib);
				IF (CARRYFLAG) error(1,ERR_READ,#arcname,AX);
				cpylen-=len;
				ipos+=len;
				DX=opos;
				CX=SSWORD[#opos+2];
				LSEEK(,arcfile);
				IF (CARRYFLAG) error(1,ERR_SEEK,#arc_clean,AX);
				WRITEFAR(,arcfile,len,ib);
				IF (AX!=len) error(1,ERR_WRITE,#arcname,AX);
				opos+=len;
			}while (cpylen!=0);
		}
		cnt--;
	}while(cnt!=0);
	md_truncfile(arcfile,dword opos);
}

md_truncfile(word fh; dword len)
{
  chsize(fh,dword len);
}

setinput(word fh,mode,nm)
{
	inname=nm;
  ibl=0;
  icnt=0;
  infile=fh;
	r_crc=mode&CRCCALC;
	IF(NOTZEROFLAG){
		IF(crctabok==0)MAKECRCTAB();
		crc=CRCMASK;
	}
  r_progdisp=mode&PROGDISP;
}

setoutput(int fh;word mode,nm)
{
	outname=nm;
  IF(fh!=-1)write_on=1;
  ELSE write_on=0;
  obl=0;
  ocnt=0;
  outfile=fh;
	w_crc=mode&CRCCALC;
	IF(NOTZEROFLAG){
		IF(crctabok==0)MAKECRCTAB();
		crc=CRCMASK;
	}
  w_progdisp=mode&PROGDISP;
}

MAKECRCTAB()
{
	$PUSH DI
	CX=0;
	DI=#crctab;
	ES=DS;
	$CLD
	do{
		$DB	0X66,0Xf,0Xb7,0Xc1	//	movzx	eax,cx
		DL=8;
		do{
 			$DB	0X66,0Xa9,1,0,0,0	//test	eax,1
			IF(NOTZEROFLAG)EAX=EAX/2^0XEDB88320;
			ELSE EAX=EAX/2;
			DL--;
		}while(NOTZEROFLAG);
		$STOSD
		CX++;
	}while(CX<0X100);
	crctabok=1;
	$POP DI
}

BACKSTEP()
{
	IF(AX!=0){
		$PUSH SI
		SI=AX;
		do
		{
			DWRITE(8);
			SI--;
		} while (SI!=0);
		$POP SI
	}
}

getcrc()
{
	EAX=crc^CRCMASK;
}

BREAD()
{
	$PUSH SI
	$PUSH DI
	BX=infile;
	CX=BLOCKLEN;
	DX=0;
	DS=ib;
	AH=0X3F;
	$INT 0X21
	BX=SS;
	DS=BX;
	ibl=AX;
	IF (CARRYFLAG)error(1,ERR_READ,inname,AX);
	ibf=0;
	$OR AX,AX
	IF(NOTZEROFLAG){
		icnt+=AX;//ОБЩЕЕ ЧИСЛО СЧИТАННЫХ БАЙТ
		IF(r_progdisp!=0){
			EBX=totalsize;
			IF(EBX==0)BX++;
			EAX=icnt*100/EBX;
			LEFTWORD();
			DWRITESTR(#P5B);
		}
		IF(r_crc!=0){
			ES=ib;
			SI=0;
			EDX=crc;
			CX=ibl;
			do
			{
				BL=DL;
				$XOR BL,ESBYTE[SI]
				BH=0;
				$SHL BX,2
				$SHR EDX,8
				$XOR EDX,DSDWORD[BX+#crctab]
				SI++;
			} while (SI<CX);
			crc=EDX;
		}
	}
	$POP DI
	$POP SI
}

CPY()
dword cnt;
word OLDSEG;
{
	cnt=totalsize;
	OLDSEG=ob;
	ob=ib;
	do{
		IF(cnt>BLOCKLEN)AX=BLOCKLEN;
		ELSE AX=cnt;
		obl=AX;
		cnt-=AX;
		BREAD();
		BWRITE();
	}while(cnt!=0);
	ob=OLDSEG;
}

BWRITE()
{
	$PUSH SI
	$PUSH DI
	AX=obl;
	$OR AX,AX
	if(NOTZEROFLAG){
		IF(write_on!=0){
			BX=outfile;
			CX=AX;
			DX=0;
			DS=ob;
			AH=0X40;
			$INT 0X21
			BX=SS;
			DS=BX;
			IF(CARRYFLAG)error(1,ERR_WRITE,outname,AX);
		}
		ocnt+=AX;
		IF(w_progdisp!=0){
			EBX=totalsize;
			IF(EBX==0)BX++;
			EAX=ocnt*100/EBX;
			LEFTWORD();
			DWRITESTR(#P5B);
		}
 		IF(w_crc!=0) {
			SI=0;
			ES=ob;
			EDX=crc;
			CX=obl;
			do
			{
				BL=DL;
				$XOR BL,ESBYTE[SI]
				BH=0;
				$SHL BX,2
				$SHR EDX,8
				$XOR EDX,DSDWORD[BX+#crctab]
				SI++;
			} while ( SI<CX);
			crc=EDX;
		}
		obl=0;
	}
	$POP DI
	$POP SI
}

/************************************************************************
	HA sliding window dictionary
***********************************************************************/

/*
cr - таблица со смещениями хешкода начало цепочки
ll - таб с пред смещ хешкода тело цепочки
ccnt_swd - таб с числом данных хешкодов
bbf - текущ положение в словаре
swd_char - символ в тек полож
swd_mlf - мин длина цепочки
bbl - размер словаря
swd_bpos - смещение цепочки с наибольш совпадением
binb - индикатор того что началось зацикливание словаря
inptr - указатель на точку ввода нового символа
*/

SWD_FINDBEST()
word start_len;
byte ref;
{
	$PUSH SI
	$PUSH DI
	ES=b;
	BX=bbf;
	CX=ESWORD[BX+1];
	DX=0;
	DL><CH;
	$SHL DX,HSHIFT
	CX^=DX;
	$SHL CX,HSHIFT
	CL^=ESBYTE[BX]; //хеш-код для первых 3 симвл
	DI=CX;
	DI+=DI;
	GS=ccnt_swd;
	DX=GSWORD[DI];	//число слов с этим хеш-кодом
	GSWORD[DI]++;
	IF(DX>maxcnt)DX=maxcnt;
	FS=cr;
	SI=FSWORD[DI];	//предыдущее начало
	CX=BX;
	BX+=BX;
	GS=ll;
	GSWORD[BX]=SI;	//вставить в цепочку
	FSWORD[DI]=CX;	//новое начало цепочки
	BX=CX;
	AL=ESBYTE[BX];
	AH=0;
	swd_char=AX;	//перв символ из словаря
	CX=swd_mlf;	//МИНИМ ДЛИНА ЦЕПОЧКИ ВНАЧАЛЕ = 2
	start_len=CX;
	FS=best;
	IF(CX>=bbl){	//если длина цепочки больше размера словаря
		IF(bbl==0)swd_char=-1;	//длина словаря 0 символ FFFF
		BX+=BX;
		FSWORD[BX]=30000;
	}
	else{
		$OR DX,DX
		if(NOTZEROFLAG){
			BX+=CX;	//swd_mlf;
			BX--;
			ref=ESBYTE[BX];	//следующий(предпоследний) символ из словаря
CONT:
				BX=SI+swd_mlf;
				BX--;
				AL=ESBYTE[BX];	//получить символ из предыдущей группы символов
				IF(AL==ref){
					BX=SI;
					DI=bbf;
					CX=bbl;
					AX=CX;
					$REPE
					$DB 0X26
					$CMPSB
					IF(ZEROFLAG){	//если длина цепочки равна длине словаря прекр поиск
						swd_bpos=BX;
						swd_mlf=AX;
						$JMP SHORT BW
					}
					CX++;
					AX-=CX;
					SI=BX;
					$CMP AX,swd_mlf
					$JBE CW				//длина найденной цепочки меньше миним
					swd_bpos=BX;	//смещ более длинной цепочки
					swd_mlf=AX;	//новая мин длина цепочки
					$CMP FSWORD[BX+SI],AX	//прекратить поиск если число совподений
					$JB BW                //больше числа совподений для данной цепочки
																//полученных ранее ???
					DI-=2;
					ref=ESBYTE[DI];	//последний символ в совпавшей цепочке
				}
				BX=SI;
CW:
				DX--;	//уменьшить число непровереных совподений
				$JZ BW
				SI=GSWORD[BX+SI];	//взять следующую группу
				$JMP SHORT CONT
BW:
			BX=bbf;
			BX+=BX;
			AX=swd_mlf;
			FSWORD[BX]=AX;	//сохранить длину цепочки в таблице с макс длинами
			IF(AX>start_len){	//Если найдена более длинная цепочка
				IF(swd_bpos<bbf){	//и расположена она ниже исходной точки
					AX=bbf-swd_bpos;
					AX--;
				}
				ELSE{	//найдена точка расположена выше текущей
					AX=POSCODES+LENCODES+MINLEN-2-swd_bpos+bbf;
				}
				swd_bpos=AX;	//сохранить расстояние до неё
			}
		}
	}
	IF(binb==POSCODES){	//если был достигнут конец словаря
		SI=inptr;
		BX=ESWORD[SI+1];
		DX=0;
		DL><BH;
		$SHL DX,HSHIFT
		BX^=DX;
		$SHL BX,HSHIFT
		BL^=ESBYTE[SI];
		GS=ccnt_swd;
		BX+=BX;
		GSWORD[BX]--;	//уменьшить число ссылок на хэш код который будет убран
	}
	ELSE binb++;
	bbf++;
	IF(bbf==POSCODES+LENCODES+MINLEN-1)bbf=0;	//достигнут конец словаря
	IF(ibl==0){
		BREAD();
		ES=b;
		IF(ibl==0){
			bbl--;
			$JMP SHORT EN
		}
	}
	ibl--;
	GS=ib;
	BX=ibf;
	DL=GSBYTE[BX];	//получить символ из потока
	ibf++;
	BX=inptr;
	ESBYTE[BX]=DL;	//заисать новый символ в словарь
	IF(BX<LENCODES+MINLEN-2){	//если  inptr переместился в начало для поиска посл
		BX+=POSCODES+LENCODES+MINLEN-1;	//нужно записать символ и в конец словаря
		ESBYTE[BX]=DL;
		inptr++;
	}
	ELSE{
EN:
		inptr++;
		IF(inptr==POSCODES+LENCODES+MINLEN-1)inptr=0;
	}
	$POP DI
	$POP SI
}

SWD_ACCEPT()
{
	$PUSH SI
	$PUSH DI
	DI=swd_mlf-2;
	FS=cr;
	GS=ccnt_swd;
  do{   		/* Relies on non changed swd_mlf !!! */
		ES=b;
		IF(binb==POSCODES){
			SI=inptr;
			BX=ESWORD[SI+1];
			DX=0;
			DL><BH;
			$SHL DX,HSHIFT
			BX^=DX;
			$SHL BX,HSHIFT
			BL^=ESBYTE[SI];
			BX+=BX;
			GSWORD[BX]--;//уменьшить число ссылок на этот хэш код
		}
		ELSE binb++;
		SI=bbf;
		BX=ESWORD[SI+1];	//получить хэш код для текущ символа
		DX=0;
		DL><BH;
		$SHL DX,HSHIFT
		BX^=DX;
		$SHL BX,HSHIFT
		BL^=ESBYTE[SI];
		BX+=BX;
		AX=FSWORD[BX];	//перенести начало цепочки в тело цепочки
		ES=ll;
		CX=SI;
		SI+=SI;
		ESWORD[SI]=AX;
		ES=best;
		ESWORD[SI]=30000;	//записать длину макс больше предельной
		FSWORD[BX]=CX;	//записать новое начало
		GSWORD[BX]++;   //увеличить указатель длины цепочки
		bbf++;
		IF(CX==POSCODES+LENCODES+MINLEN-2)bbf=0;
		IF(ibl==0){
			BREAD();
			IF(ibl==0){
			  bbl--;
				$JMP SHORT CW
			}
		}
		ibl--;
		ES=ib;
		BX=ibf;
		CL=ESBYTE[BX];
		ibf++;
		ES=b;
		BX=inptr;
    ESBYTE[BX]=CL;
		IF(BX<LENCODES+MINLEN-2){
			BX+=POSCODES+LENCODES+MINLEN-1;
			ESBYTE[BX]=CL;
	    inptr++;
		}
		ELSE{
CW:
			inptr++;
	    IF(inptr==POSCODES+LENCODES+MINLEN-1)inptr=0;
		}
		DI--;
  }while(NOTZEROFLAG);
  swd_mlf=MINLEN-1;
	$POP DI
	$POP SI
}

/******************** поиск файлов ****************************/

SETDTA()
{
	AX=NUMDIR*0X2C;
	DX=AX;
	OFSDTA=AX;
	DS=SEGDTA;
	AH=0X1A;
	$INT 0X21
	DS=SS;
}

MOVESTR()
{
	do
	{
		$LODSB
		$STOSB
	} while ( AL!=0 );
}

word FILEFIND()
word found;
{
	found=0;
	SETDTA();
	CX=ATRIBF;
	DX=#BUFF;
	AH=0X4E;
	$INT 0X21
	if(NOTCARRYFLAG){
		do{
			AX=OFSDTA+OFSATR;
			SI=AX;
			ES=SEGDTA;
			$DB 0X26,0XF6,4,0X10	//$TEST ESBYTE[SI],0X10
			IF(NOTZEROFLAG){
				SI+=NAMEDTA-OFSATR;
				IF(ESBYTE[SI]!='.'){
					IF(savedir!=0){
						$PUSH SI
						ES=SS;
						DI=#name;
						DS=SEGDTA;
						MOVESTR();
						DS=SS;
						STR_UP(#name);
						DIRNAME();
						found|=ADDDIR();
						$POP SI
					}
					AX=NUMDIR*2+#OFSPATSH;
					BX=AX;
					DI=DSWORD[BX];
					ES=SS;
					DS=SEGDTA;
					MOVESTR();
					DS=SS;
					NUMDIR++;
					DSWORD[BX+2]=DI;
					DSBYTE[DI-1]='\\';
					SI=#fulname;
					MOVESTR();
					found|=FILEFIND();
				}
			}
			ELSE{
				SI+=NAMEDTA-OFSATR;
				DI=#name;
				DS=SEGDTA;
				ES=SS;
				MOVESTR();
				DS=SS;
				STR_UP(#name);
				STRRCHR(#arcname,'\\');
				BX><AX;
				$OR BX,BX
				IF(ZEROFLAG)BX=#arcname;
				strcmp(#name,BX);
				$OR AL,AL
				IF(NOTZEROFLAG){
					DIRNAME();
					found|=ADDFILE();
				}
			}
			FINDNEXTFILE();
			$OR AX,AX
		}while(ZEROFLAG);
	}
	NUMDIR--;
	IF(NUMDIR==-1){
		DX=0X80;
		AH=0X1A;
		$INT 0X21
	}
	ELSE SETDTA();
	AX=found;
}

DIRNAME()
{
	AX=NUMDIR*2+#OFSPATSH;
	BX=AX;
	CX=DSWORD[BX];
	SI=#BUFF;
	DI=#path;
	IF(CX!=SI){
		do{
			$MOVSB
		}while(SI<CX);
	}
	AL=0;
	$STOSB
}

word ADDFILE()
word bestm;
dword bestsize;
{
	$PUSH SI
	$PUSH DI
	ES=SEGDTA;
	BX=OFSDTA+OFSSIZE;
	EAX=ESDWORD[BX];
	bestsize=EAX;
	totalsize=EAX;
	olen=EAX;
	bestm=M_CPY;
	strcpy(#fullname,#path);
	strcat(#fullname,#name);
	ARC_NEWFILE();
	FOPEN(F_READ,,,#fullname);
	$OR AX,AX
	IF (ZEROFLAG){
		error(0,ERR_OPEN,#fullname,AX);
		AX=0;
		$JMP EN
	}
	DI=AX;
	IF(quiet==0){
		DWRITELN();
		setinput(DI,CRCCALC|PROGDISP,#fullname);
	}
	ELSE setinput(DI,CRCCALC,#fullname);
	setoutput(arcfile,0,#arcname);
	if(totalsize!=0){
		SI=0;
DW:
		ARC_TRYNEXT();
		IF(quiet==0) {
			BL=metqueue[SI];
			BH=0;
			BX<<=2;
			BX+=#method;
			PRINTF("\rPacking %s          %s",BX,#fullname);
			BACKSTEP(STRLEN(#fullname)+8);
		}
		AL=metqueue[SI];
		IF(AL==M_CPY)CPY();
		ELSE IF(AL==M_ASC)ASC_PACK();
		ELSE IF(AL==M_HSC)HSC_PACK();
		EAX=ocnt;
		IF(EAX<bestsize)$JMP SHORT M1
		IF(metqueue[SI]==M_CPY){
M1:
			bestm=metqueue[SI];
			ARC_ACCEPT(AX);
			bestsize=ocnt;
		}
		SI++;
		IF (metqueue[SI]==M_UNK)$JMP SHORT BW
		IF(metqueue[SI]==M_CPY){
			IF(bestsize!=totalsize)$JMP SHORT BW
		}
		setoutput(arcfile,0,arcname);
		LSEEK(,DI,0,0);
		IF(quiet!=0)setinput(DI,CRCCALC,#fullname);
		ELSE setinput(DI,CRCCALC|PROGDISP,#fullname);
		$JMP DW
BW:
	}
	ELSE {
		IF(quiet==0){
			PRINTF("\rPacking CPY          %s",#fullname);
			BACKSTEP(STRLEN(#fullname)+8);
		}
		ARC_ACCEPT(M_CPY);
	}
	IF(quiet==0){
		BACKSTEP(5);
		AX=bestm;
		AX<<=2;
		AX+=#method;
		DWRITESTR();
		DWRITE(' ');
		IF(bestsize!=0)EAX=100*bestsize/totalsize;
		ELSE AX=100;
		LEFTWORD();
		DWRITE('.');
		IF(bestsize!=0)EAX=1000*bestsize/totalsize%10;
		ELSE AX=0;
		__dwriteword();
		DWRITESTR(" %");
	}
	ARC_ADDFILE();
	IF(move!=0){
		REMOVER(,,,#fullname);
		IF(CARRYFLAG)error(0,ERR_REMOVE,#fullname,AX);
	}
	BX=DI;
	AH=0X3E;
	$INT 0X21
EN:
	AX=1;
	$POP DI
	$POP SI
}

ARC_NEWFILE()
{
	ver=MYVER;
	ES=SEGDTA;
	BX=OFSDTA+OFSTIME;
	CX=ESWORD[BX];
	SI=#ttab;
	AX=CX;
	$SHR AX,5
	AL&=0X3F;
	DSBYTE[SI]=AL;
	SI++;
	AL=CH;
	$SHR AL,3
	DSBYTE[SI]=AL;
	CL&=0X1F;
	CL+=CL;
	SI++;
	DSBYTE[SI]=CL;
	CX=ESWORD[BX+2];
	SI=#ptab;
	AL=CH;
	$SHR AL,1;
	AH=0;
	AX+=1980;
	DSWORD[SI]=AX;
	SI+=3;
	AX=CX;
	$SHR AX,5
	AL&=0XF;
	DSBYTE[SI]=AL;
	SI--;
	CL&=0X1F;
	DSBYTE[SI]=CL;
	dostounix(#ptab,#ttab);
	time=EAX;
  mdilen=2;
	BX=OFSDTA+OFSATR;
	attr=ESBYTE[BX];
/*	STRRCHR(#path,':');	//ВАРИАНТ С ОТСЕЧЕНИЕМ БУКВЫ ДИСКОВОДА
	$OR AX,AX
	IF(NOTZEROFLAG){
		AX++;
		SI=AX;
		IF(DSBYTE[SI]=='\\')SI++;
		DI=#path;
		ES=SS;
		MOVESTR();
	}           */
	STRRCHR(fpath,'\\');	//ВАРИАНТ С ОТСЕЧЕНИЕМ ПОДВОДЯЩЕГО ПУТИ
	$OR AX,AX
	IF(NOTZEROFLAG){
		AX-=fpath;
		AX++;
		SI=#path;
		DI=SI;
		SI+=AX;
		ES=SS;
		MOVESTR();
	}
	MD_PATHTOMD(#path);
  mylen=STRLEN(#path);
	mylen+=STRLEN(#name)+22;
	EAX=arcsize+mylen;
	trypos=EAX;
	bestpos=EAX;
  addtries=0;
  dirty|=2;
}

ARC_TRYNEXT()
{
  DX=trypos;
  CX=DSWORD[#trypos+2];
	LSEEK(,arcfile);
	IF(CARRYFLAG)error(1,ERR_SEEK,"arc_trynext",AX);
  IF(addtries!=0)dirty=1;
	addtries++;
}

word MD_PATHTOMD()
{
  BX><AX;
  do{
    IF(DSBYTE[BX]=='\\')DSBYTE[BX]=0XFF;
    BX++;
  }while(DSBYTE[BX]!=0);
}

ARC_ACCEPT()
{
	type=AL;
	bestpos=trypos;
	EAX=ocnt;
	clen=EAX;
	trypos+=EAX;
	getcrc();
	crcf=EAX;
}

int ARC_ADDFILE()
dword basepos,len;
word cplen;
{
	EAX=arcsize+mylen;
	basepos=EAX;
	if(EAX!=bestpos){
		DX=AX;	//basepos;
		CX=SSWORD[#basepos+2];
		LSEEK(,arcfile);
		IF(CARRYFLAG)error(1,ERR_SEEK,#arc_addfile,AX);
		len=clen;
		$JMP TW
		do{
			DX=bestpos;
			CX=SSWORD[#bestpos+2];
			LSEEK(,arcfile);
			IF(CARRYFLAG)error(1,ERR_SEEK,#arc_addfile,AX);
			IF(len<BLOCKLEN)cplen=len;
			ELSE cplen=BLOCKLEN;
			READFAR(,arcfile,cplen,ib);
			IF(AX!=cplen)error(1,ERR_READ,arcname,AX);
			len-=cplen;
			bestpos+=cplen;
			DX=basepos;
			CX=SSWORD[#basepos+2];
			LSEEK(,arcfile);
			IF(CARRYFLAG)error(1,ERR_SEEK,#arc_addfile,AX);
			WRITEFAR(,arcfile,cplen,ib);
			IF(AX!=cplen)error(1,ERR_WRITE,arcname,AX);
			basepos+=cplen;
TW:
		}while(len!=0);
	}
	DX=arcsize;
	CX=DSWORD[#arcsize+2];
	LSEEK(,arcfile);
	IF(CARRYFLAG)error(1,ERR_SEEK,#arc_addfile,AX);
	PUTHEADER();
	dirty&=1;
	IF(NEWARX==FALSE)DELOLD();
	arccnt++;
	arcsize+=mylen+clen;
	LSEEK(,arcfile,0,2);
	IF(CARRYFLAG)error(1,ERR_SEEK,#arc_addfile,AX);
	BX=arcfile;
	DX=#arccnt;
	CX=2;
	AH=0X40;
	$INT 0X21
	AX=1;
}

PUTHEADER()
{
	$PUSH SI
	$PUSH DI
	ES=ob;
	DI=0;
	AL=ver;
	$SHL AL,4
	AL|=type;
	$STOSB
	EAX=clen;
	$STOSD
	EAX=olen;
	$STOSD
	EAX=crcf;
	$STOSD
	EAX=time;
	$STOSD
	SI=#path;
	MOVESTR();
	SI=#name;
	MOVESTR();
	AL=mdilen;
	$STOSB
	AL=MSDOSMDH;
	$STOSB
	AL=attr;
	$STOSB
	WRITEFAR(,arcfile,DI,ob);
	IF(CARRYFLAG)error(1,ERR_WRITE,arcname,AX);
	$POP DI
	$POP SI
}

DELOLD()
dword pos,oldpos;
word i,nmylen;
{
	pos=4;
	i=arccnt;
	ES=ib;
	do{
		DX=pos;
		CX=SSWORD[#pos+2];
		LSEEK(,arcfile);
		IF(CARRYFLAG)error(1,ERR_SEEK,#delold,AX);
		READFAR(,arcfile,512,ib);
		oldpos=pos;
		DS=ES;
		STRLEN(0X11);
		AX+=0X12;
		$PUSH AX
		STRLEN();
		$POP BX
		CX=BX;
		BX+=AX;
		BX++;
		AL=DSBYTE[BX];
		AH=0;
		BX+=AX;
		BX++;
		DS=SS;
		EBX=BX;
		pos+=ESDWORD[1]+EBX;
		IF(ESBYTE[0]==0xff){
			dirty=1;
			i++;
		}
		ELSE{
			nmylen=CX;
			$PUSH CX
			DS=ES;
			STR_UP(0X11);
			$POP AX
			STR_UP();
			DS=SS;
			FARSTRCMP(#path,0X11);
			IF(AL==0){
				FARSTRCMP(#name,nmylen);
				IF(AL==0){
					DX=oldpos;
					CX=SSWORD[#oldpos+2];
					LSEEK(,arcfile);
					IF(CARRYFLAG)error(1,ERR_SEEK,#delold,AX);
					ESBYTE[0]=0XFF;
					WRITEFAR(,arcfile,1,ib);
					IF(CARRYFLAG)error(1,ERR_WRITE,arcname,AX);
					dirty=1;
					arccnt--;
					$JMP SHORT BW
				}
			}
		}
		EAX=arcsize;
		$CMP pos,EAX
		$JAE BW
		i--;
	}while(i!=0);
BW:
}

FARSTRCMP()
{
	$PUSH SI
	SI><AX;
	BX--;
TOP:
	BX++;
	$LODSB
	$CMP AL,0
	$JE HERE
	$CMP ESBYTE[BX],AL
	$JE TOP
HERE:
	AL-=ESBYTE[BX];
	$POP SI
}

int ADDDIR()
{
	strcpy(#fullname,#path);
	strcat(#fullname,#name);
	IF(quiet==0){
		PRINTF("\nSaving  DIR          %s",#fullname);
		BACKSTEP(STRLEN(#fullname)+8);
	}
	ARC_NEWFILE();
	IF(ARC_ADDDIR()!=0){
		IF(quiet==0)DWRITESTR(" DONE");
		AX=1;
	}
	ELSE AX=0;
}

int ARC_ADDDIR()
{
	type=M_DIR;
	olen=0;
	clen=0;
	crc=0;
	DX=arcsize;
	CX=DSWORD[#arcsize+2];
	LSEEK(,arcfile);
	IF(CARRYFLAG)error(1,ERR_SEEK,#arc_adddir,AX);
	PUTHEADER();
	dirty&=1;
	IF(NEWARX==FALSE)DELOLD();
	arccnt++;
	arcsize+=mylen;
	LSEEK(,arcfile,0,2);
	IF(CARRYFLAG)error(1,ERR_SEEK,#arc_adddir,AX);
	BX=arcfile;
	DX=#arccnt;
	CX=2;
	AH=0X40;
	$INT 0X21
	AX=1;
}
