

/* lino.c (main) */
/* AZTEC_C 5.x: cc -md -sa lino / ln lino xpklib checksum -lc */
/* SAS_C 6.x: sc OPTTIME OPTIMIZE link lino checksum.asm */



#include <exec/types.h>
#include <exec/memory.h>
#include <libraries/dos.h>
#include <stdio.h>

#ifndef AZTEC_C
#include <stdlib.h>
#include <string.h>
#include <proto/exec.h>
#include <proto/dos.h>
#else
#include <functions.h>
#endif

#include <inc/lin.h>  /* 'inc' is your subdirectory of include */



#define UB UBYTE
#define US USHORT
#define UL ULONG

/* keys */
#define K_LSHFT   61
#define K_RSHFT   63
#define K_DELAY    8

/* file type */
#define EXPAND	   0
#define COMPRESS   1
#define DATAFILE   1
#define EXECUTABLE 2


/* error codes */

#define UPPER_ERR	   6

#define ERR_LOCK	   5
#define ERR_OPEN	   4
#define ERR_WRITE	   3
#define ERR_READ	   2
#define X_INFO		   1
/* XPK-ERROR-CODES from 0 to -32 */
#define ERR_EXECUTABLE	 -33
#define ERR_DATAFILE	 -34
#define ERR_TOO_SMALL	 -35
#define ERR_PATTERN	 -36
#define ERR_PATTERN_2	 -37
#define ERR_NO_PRINTER	 -38
#define ERR_WRONG_PACKER -39
#define ERR_PROT	 -40
#define ERR_DELETE	 -41

#define LOWER_ERR	 -42

#define MAX_ERRS (UPPER_ERR-LOWER_ERR)
#define BLEVEL	      -17  /* ERR > BLEVEL will cause a break */

#define NO_PATTERN     0
#define PATTERN        1
#define NO_MATCH       0
#define MATCH	       1
#define NO_CUT	   (UB)0
#define CUT	   (UB)1
#define PACKED	       1

#define MIN_SIZE     250L    /* minimal size of file */
#define MAX_SIZE  0x7fffffff /* maximal size of file */
#define EPU_MIN      130L    /* f. EPU	*/
#define MARGIN	     256L


/* f. F_HEADER->flags (XPK-Format) */
/* flag1 */
#define LONGHDR   0x01000000
#define PASSWORD  0x02000000


#define MAX_DIRS       10
#define MAX_FILES      40
#define MAX_FLEN       32   /* max.len of filename */
#define MIN_CHUNK	1   /* 1 KB */
#define MAX_CHUNK 2097152   /* MAX_CHUNK*KB = 2^31 */
#define CHUNK_DEF      32L
#define CHUNK_SUBDEF	0   /* will get default chunksize of sublib */
#define MODE_SUBDEF    -1   /* - || - default mode - || - */
#define SMARG		5   /* OutBuffer += (OutBuffer >> smarg) */

#define FORMAT 0x4c494e4f   /* 'LINO' */


#define XRead(to,len) if(Read((BPTR)lock,(char *)(to),\
   (long)(len))!=(long)(len)){ Close((BPTR)lock); return(ERR_READ); }

#define Low(x) (((x)>0x40 && (x)<0x5b) ? (x) | 0x20 : x)
#define Cap(x) (((x)>0x60 && (x)<0x7b) ? (x) & 0xdf : x)

#define act_ticks clo.ds_Minute*3000+clo.ds_Tick
struct DateStamp clo;
int timer=0,i_time=0,stime;


#define XPK_COMPAT 4L

typedef struct C_Header {
   long clen;
   long dlen;
} CH_HEAD;
CH_HEAD cheadv,*chead;
#define CHUNK_HEAD (long)sizeof(CH_HEAD)
#define SHORT_HEAD  4L

typedef struct F_Header {
   long head;  // XPKF/LINO
   long clen;
   long pack;  // LIN1,ZENO,...
   long dlen;
   char first16[16];  // first 16 bytes of original file
   long flags;	 // differs from XPK file format
   long chksum;  //	    -  ||  -
   long cchunk;
   long dchunk;
} FHEAD;
FHEAD fheadv,*fhead;
#define XHEAD (long)sizeof(FHEAD)
#define HEAD (XHEAD-CHUNK_HEAD)



struct xfile{
   char fname[MAX_FLEN];
   long prot;
   long len;
};
struct dfile{
   char dname[MAX_FLEN];
};


FILE *Out = stdout;


XPARAMS xpav,*xpar;

struct Library *XpkSubBase;
char xpklib[40];

long dlen,clen,csum,dsum,chunk,cmin,cover,pack,passw,format,smarg,
     longhdr,packed,minsize,maxchunk;
US count,fcon;
char readfile[256],writefile[256],owfile[256],sfile[40],wpath[256],
     suff[32],pstr[32],crst[5],
     pat,pflag,pcom,prio,info,mode,blevel,fc16[16],
     fh16[16]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 },
     patt[MAX_FLEN],ca[MAX_FLEN],na[MAX_FLEN],fa[MAX_FLEN],ta[MAX_FLEN];
UB hid,type,out,ex,exe,pri,all,wf,ident,pre,epu,time,kilo,oflow,
   *adr=0L, *xkey=(UB*)0xbfec01,*xmouse=(UB*)0xbfe001;
UB errstr[MAX_ERRS-1][30] = {
   "Can't delete tempfile",
   "File is protected",
   "Wrong packer",
   "Can't open printer",
   "File/Path missing",    // Pattern_err_2
   "Wrong pattern",        // Pattern_err_1
   "File is too small",
   "No Exe file",
   "No Data file",
   "Sorry, wrong password",  // WRONGPW (XPK -32)
   "",
   "",
   "",
   "Can't find info",  // NOINFO
   "",
   "",
   "",
   "",
   "File is not packed",  // NOTPACKED
   "File already packed", // PACKED
   "",
   "",
   "User-break",  // ABORTED
   "",
   "Can't pack file",  // EXPANSION
   "",
   "Can't find packing-library",  // MISSINGLIB
   "packed file is corrupt",  // CORRUPTPKD
   "Password required",  // NEEDPASSWD
   "",
   "",
   "",
   "",
   "",
   "No memory",  // NOMEM
   "",
   "Wrong checksum",  // CHECKSUM
   "",
   "IO-Error", // IOERRIN
   "",
   "",
   "",  // OK     (XPK 0)
   "",  // f.e. INFO
   "Read-Error",
   "Write-Error",
   "Open-Error",
   "Lock-Error",
};





long GetDir(char *path);
UB parent(char *path,UB cut);
char getwc(char *name);
char pmatch(char text[]);
long work(char *sfile,char *readfile);
long file_check(char *filename);
long xload(char *readfile,char *writefile,long len);
long eload(char *readfile,char *writefile);
long xsave(char *readfile,char *writefile,long len,
   long chunk,char mode,long pack,UB out);
long xcopy(char *readfile,char *writefile,long len,long chunk);
long esave(char *readfile,char *writefile,long *clen,long len,
	  long chunk,char mode);
long change_name(char *readfile, char *writefile);
void write_err(long xerr);
long breaktest(void);


void START (void);
void STOP (void);
void I_START (void);
void I_STOP (void);
void PRINT_TIME(long len);

long checksum(long *adr,long len);  // see checksum.asm


#ifdef AZTEC_C
void _wb_parse(){}
void _abort(){}
#endif


void main(int argc,char *argv[])
{
   char c,d,par,path[256];
   UB len;
   US i,j;
   long xerr;

   if(argc == 1 || (argc == 2 &&  *(argv[1]) == '?')){
      fprintf(Out,"%s <readfile> [options]!!\n",argv[0]);
      fprintf(Out,"  -w Write-file/path\n");
      fprintf(Out,"  -s Suffix\n");
      fprintf(Out,"  -m Method (4 letters)\n");
      fprintf(Out,"  -e Efficiency/mode (0-100)\n");
      fprintf(Out,"  -c Chunksize (KB def: 32)\n");
      fprintf(Out,"  -p Password\n");
      fprintf(Out,"  -z Minimal filesize (def: 250 bytes)\n");
      fprintf(Out,"  -y Taskpriority (def: -5)\n");
      fprintf(Out,"  -l Errorlevel (-42 to +5, def:-17)\n");
      fprintf(Out,"  -b overflow buffer (3-5 def:5)\n");

      fprintf(Out,"  -u  Expansion                  ");
      fprintf(Out,"  -h  Hidden password entry\n");
      fprintf(Out,"  -x  Executable files only      ");
      fprintf(Out,"  -d  Data files only\n");
      fprintf(Out,"  -n  No output                  ");
      fprintf(Out,"  -o  Output to printer\n");
      fprintf(Out,"  -a  All subdirectories         ");
      fprintf(Out,"  -k  Speed in kb/sec\n");
      fprintf(Out,"  -i  Info about packer          ");
      fprintf(Out,"  -t  Output of time\n");
      fprintf(Out,"  -f  Packed file is allowed to be larger than original\n");

      fprintf(Out,"\nPattern matching: ?, #, #?(*), !(not)\n");
      fprintf(Out,"Press left mousebutton and -Shft- to abort program!!!\n");

      fprintf(Out,"\nExamples\n");
      fprintf(Out,"%s file -s .xp -m ZENO -c 64 -e 100\n",argv[0]);
      fprintf(Out,"%s df0:back/!f#? -u -w dh0:tools/\n",argv[0]);
      fprintf(Out,"%s -m LIN1.100 -p Aladdin file\n",argv[0]);

      exit(0L);
   }


   strcpy(crst,"LINO");   par = 0;
   xpar = &xpav;  fhead = &fheadv;  chead = &cheadv;
   suff[0] = 0;  pstr[0] = 0;  path[0] = 0;
   clen = 0L;  dlen = 0L;  cmin = 0L;
   pre = 0;  info = 0;	 epu = 0;
   XpkSubBase = 0L;  chunk = CHUNK_SUBDEF;
   passw = 0L;	 minsize = MIN_SIZE;
   prio = -5;	pcom = 0;
   pri = 0;  mode = MODE_SUBDEF;
   hid = 0;  wf = 0;
   type = COMPRESS;  ex = 0;  out = 1;
   all = 0;  count = 0;
   pat = NO_PATTERN;  pflag = MATCH;
   time = 0;  kilo = 0;  oflow = 0;  blevel=BLEVEL;


   i = 1;
   while(i<argc){
      d = Low(*argv[i]);  c = *(argv[i]+1);
      if(d == '-'){
	 i++;	d = Low(*argv[i]);
	 if(c == 'w'){ strcpy(owfile,argv[i]);  wf=1; }
	 else if(c == 's') strcpy(suff,argv[i]);
	 else if(c == 'm'){
	    crst[0]=Cap(*(argv[i]));  pack = crst[0]<<24;
	    crst[1]=Cap(*(argv[i]+1));  pack += crst[1]<<16;
	    crst[2]=Cap(*(argv[i]+2));  pack += crst[2]<<8;
	    crst[3]=Cap(*(argv[i]+3));  pack += crst[3];
	    crst[4]='\0';
	    if(*(argv[i]+4) == '.'){
	       mode = 0;  j = 5;
	       while((c = *(argv[i]+j)) >= '0'){
		  mode = mode*10+c-48;	j++;
	       }
	       if(mode<0 || mode>100) mode=-1;
	    }
	 }
	 else if(c == 'e' && d >= '0' && d <= '9'){
	    mode = (char)atoi(argv[i]);
	    if(mode<0 || mode>100) mode=MODE_SUBDEF;
	 }
	 else if(c == 'c' && d >= '0' && d <= '9'){
	    chunk = (long)atoi(argv[i]);
	    if(chunk < MIN_CHUNK) chunk = MIN_CHUNK;
	    if(chunk > MAX_CHUNK) chunk = MAX_CHUNK;
	 }
	 else if(c == 'p'){
	    if(strlen(argv[i])>=32) strncpy(pstr,argv[i],31);
	    else strcpy(pstr,argv[i]);
	    passw = (long)PASSWORD;
	 }
	 else if(c == 'z' && d >= '0' && d <= '9'){
	    minsize = (long)atoi(argv[i]);
	    if(minsize<MIN_SIZE || minsize>MAX_SIZE) minsize=MIN_SIZE;
	 }
	 else if(c == 'y'){
	    prio = atoi(argv[i]);
	    if(prio<-50 || prio>50) prio=-5;
	 }
	 else if(c == 'l'){
	    blevel = atoi(argv[i]);
	    if(blevel<-42 || blevel>5) blevel=BLEVEL;
	 }
	 else if(c == 'b'){
	    smarg = atoi(argv[i]);
	    if(smarg<3 || smarg>5) smarg=SMARG;
	 }
	 else{
	    i--;
	    if(c == 'u') type = EXPAND;
	    else if(c == 'd') ex = DATAFILE;
	    else if(c == 'x') ex = EXECUTABLE;
	    else if(c == 'h') hid = 1;
	    else if(c == 'n') out = 0;
	    else if(c == 'o') pri = 1;
	    else if(c == 'a') all = 1;
	    else if(c == 'k') kilo = 1;
	    else if(c == 'i') info = 1;
	    else if(c == 't') time = 1;
	    else if(c == 'f') oflow = 1;
	    else i++;
	 }
      }
      else{
	 if(!par){ strcpy(path,argv[i]);  par = i; }
      }
      i++;
   }


   if(pri){
     if(!(Out = fopen("PRT:","w+"))){
	write_err(ERR_NO_PRINTER);
	exit(0L);
     }
   }


   if(info){
      work((char*)"",(char*)"");
      if(pri) fclose(Out);
      exit(0L);
   }

   if(!wf && suff[0]==0) ident=1;

   if(chunk) chunk = (chunk<<10)-4L;


   if(path[0] == 0){ write_err(ERR_PATTERN_2);  exit(0L); }

   len = parent(path,NO_CUT);
   strncpy(patt,argv[par]+strlen(argv[par])-len,len);

   pat = getwc(patt);

   if(pat == MATCH) parent(path,CUT);

   if(path[0] == 0){ write_err(ERR_PATTERN_2); exit(0L); }

   if(pat > PATTERN){
      write_err(ERR_PATTERN);
      exit(0L);
   }

   if(hid){                   // hidden entry
      printf("\033[30m\033[40m");
      scanf("%s",pstr);
      printf("\033[31m\n");
      passw = (long)PASSWORD;
   }

   xpar->Password = (APTR)pstr;


   if(time) START();


   prio = SetTaskPri(FindTask(0L),prio);

   xerr = GetDir(path);

   prio = SetTaskPri(FindTask(0L),prio);

   if(xerr != XPKERR_OK) write_err(xerr);

   if(out && count>1){
      if(type==COMPRESS){
	 cmin = ((dsum-csum)*1000)/dsum;
	 fprintf(Out,"%d files compressed:  %ld -> %ld bytes (%ld.%ld%%)\n",count,dsum,csum,cmin/10,cmin-(cmin/10)*10);
      }
      else fprintf(Out,"%d files expanded:  %ld -> %ld bytes\n",count,csum,dsum);
   }

   if(pri) fclose(Out);

   if(time){
      STOP();
      PRINT_TIME(dsum);
   }

}



long GetDir(char *path)
{
   struct xfile *Fcopy,*FList;
   struct dfile *Dcopy,*DList;
   struct FileInfoBlock *fib = 0L;
   BPTR lock = 0L;
   long xerr;
   US dnum=0,fnum=0,maxfiles=MAX_FILES,maxdirs=MAX_DIRS;
   UB len;


   if(!(FList = (struct xfile*)calloc((long)
    sizeof(struct xfile),MAX_FILES)))
      return(XPKERR_NOMEM);
   if(!(DList = (struct dfile*)calloc((long)
    sizeof(struct dfile),MAX_DIRS))){
      xerr = XPKERR_NOMEM;  goto exidus; }
   if(!(fib = AllocMem((long)sizeof(struct FileInfoBlock),0L))){
      xerr = XPKERR_NOMEM;  goto exidus; }
   if(!(lock = Lock(path,ACCESS_READ))){
      xerr = ERR_LOCK;	goto exidus; }
   if(!(Examine((BPTR)lock,(struct FileInfoBlock*)fib))){
      xerr = XPKERR_IOERRIN;  goto exidus; }

   do{
      if(fib->fib_DirEntryType > 0){  //directory
	 if(all){
	    if(!dnum){
	       len = path[strlen(path)-1];
	       if(len != '/' && len != ':'){
		  strcat(path,"/");
		  if(wf) strcat(wpath,"/");
	       }
	    }
	    else strcpy(DList[dnum].dname,fib->fib_FileName);
	 }//all
	 if(++dnum % maxdirs == maxdirs-1){
	    if(!(Dcopy = (struct dfile*)calloc((long)
	       sizeof(struct dfile),dnum+MAX_DIRS+1))){
		xerr = XPKERR_NOMEM;
		goto exidus;
	    }
	    movmem(DList,Dcopy,(long)(dnum+1)*sizeof(struct dfile));
	    free(DList);  DList = Dcopy;
	    maxdirs += MAX_DIRS;
	 }
      }
      else{   // file
	 if(pat == PATTERN) pflag = pmatch(fib->fib_FileName);
	 if(pflag){
	    if(fib->fib_Size>=minsize || type==EXPAND || wf){
	       strcpy(FList[fnum].fname,fib->fib_FileName);
	       FList[fnum].len = fib->fib_Size;
	       FList[fnum].prot = fib->fib_Protection;
	       fnum++;
	       if(!dnum){
		  parent(path,CUT);
		  if(all && wf) parent(wpath,CUT);
		  goto next;
	       }
	    }
	 }
	 if(fnum % maxfiles == maxfiles-1){
	    if(!(Fcopy = (struct xfile*)calloc((long)
	      sizeof(struct xfile),fnum+MAX_FILES+1))){
		xerr = XPKERR_NOMEM;
		goto exidus;
	    }
	    movmem(FList,Fcopy,(long)(fnum+1)*sizeof(struct xfile));
	    free(FList);  FList = Fcopy;
	    maxfiles += MAX_FILES;
	 }
      }//else
      if((xerr = breaktest()) != XPKERR_OK) goto exidus;

   }while(ExNext((BPTR)lock,(struct FileInfoBlock *)fib));

next:
   UnLock((BPTR)lock);  lock = 0L;
   FreeMem(fib,(long)sizeof(struct FileInfoBlock));  fib = 0L;
   while(fnum>0){
      fnum--;
      strcpy(sfile,FList[fnum].fname);
      strcpy(readfile,path);
      strcat(readfile,FList[fnum].fname);
      clen = dlen = FList[fnum].len;
      if(!(FList[fnum].prot & 1) || !ident){
	 xerr = work(sfile,readfile);
	 if(ident) SetProtection(readfile,FList[fnum].prot);
      }
      else xerr = ERR_PROT;
      if(xerr != XPKERR_OK){
	 if(all == 0 && xerr != XPKERR_OK && xerr>blevel) goto exidus2;
	 if(dnum == 0 || (xerr != XPKERR_PACKED && \
	  xerr != XPKERR_NOTPACKED)){
	     fprintf(Out,"%s  -  ",readfile);
	     write_err(xerr);
	  }
      }
      if((xerr=breaktest()) != XPKERR_OK) goto exidus2;
   }
   free(FList); FList = 0L;
   if(all){
      while(dnum>1){
	 dnum--;
	 strcat(path,DList[dnum].dname);
	 if(wf) strcat(wpath,DList[dnum].dname);
	 xerr = GetDir(path);
	 if(xerr != XPKERR_OK){
	    if(xerr>blevel) goto exidus2;
	    else write_err(xerr);
	 }
	 parent(path,CUT);
	 if(wf) parent(wpath,CUT);
      }
   }

   xerr = XPKERR_OK;

exidus:
   if(fib)   FreeMem(fib,(long)sizeof(struct FileInfoBlock));
   if(lock)  UnLock((BPTR)lock);
exidus2:
   if(FList) free(FList);
   if(DList) free(DList);

   return(xerr);
}



UB parent(char *path,UB cut)
{
   UB len = 0;

   char *ptr = path;
   path += strlen(path) - 1;
   do{
      path--; len++;
   }while(!((*path == '/')||(*path == ':')||(path<ptr)));
   if(cut == CUT) *(path + 1) = '\0';

   return(len);
}


char getwc(char *name)
{
   short pp,pl,cn,last;
   char c1,c2,flag=0,pattern[MAX_FLEN];


   pp = 0;  pl = 1;

   if(name[0] == '!'){ pcom = 1; pp++; }
   else pcom = 0;
   while(name[pp] != '\0'){
      if(name[pp] == '*'){
	 pattern[pl] = '#';  pl++;
	 pattern[pl] = '?';  flag = 1;
      }
      else if(name[pp]=='#' && name[pp+1]>='0' && name[pp+1]<='9'){
	 flag = 1;  cn = name[pp+1]-48;  last = pp+2;
	 if(name[pp+2]>='0' && name[pp+2]<='9'){
	    cn = cn*10+name[pp+2]-48;  last++;
	 }
	 if(cn+pp<=last){
	    if(cn) name[pp] = name[last];
	    c1 = pp+1;	c2 = cn+pp;
	    while(c1<c2){ name[c1] = name[c1-1];  c1++; }
	    c1 = last+1;  c2 = pp+cn;  cn = c1-c2;
	    while(name[c1]){ name[c1-cn] = name[c1]; c1++; }
	    name[c1-cn] = '\0';
	 }
	 else{
	    c1 = cn-last+pp-1;
	    if(c1+pp >= MAX_FLEN) c1 = MAX_FLEN-pp-1;
	    cn = MAX_FLEN-1; name[cn--] = '\0';  c2 = last+c1;
	    while(cn>c2){ name[cn] = name[cn-c1];  cn--; }
	    name[cn] = name[last];  c1 = cn--;
	    while(cn>=pp){ name[cn] = name[c1];  cn--; }
	 }
	 pattern[pl] = Low(name[pp]);
      }
      else{
	 pattern[pl] = Low(name[pp]);
	 if(!flag)
	    if(pattern[pl] == '#' || pattern[pl] == '?') flag=1;
      }
      pp++;  pl++;
   }
   if(!flag) return(NO_PATTERN);

   cn = pp = 1;  last = -1;  na[0] = 0;  pl--;
   while(pp <= pl){
      c1 = pattern[pp];
      c2 = pattern[pp+1];
      if(c1 == '#' && c2 == '\0') return(ERR_PATTERN);
      if(c1 == '#' && c2 == '?'){
	 last = cn;  ta[cn] = 1;  pp++;
      }
      else{
	 if(c1 == '#'){
	    na[cn] = cn;  fa[cn] = cn+1;  ca[cn] = c2;
	    na[0] = 1;	pp++;
	 }
	 else if(c1 == '?'){
	    na[cn] = cn+1;  ca[cn] = c1;  fa[cn] = cn+1;
	 }
	 else{
	    na[cn] = cn+1;  ca[cn] = c1;  fa[cn] = last;
	 }
	 ta[cn] = (cn > fa[cn]) ? 0 : 1;
	 cn++;
      }
      pp++;
   }
   na[cn] = -2;  fa[cn] = last;
   return(PATTERN);
}


char pmatch(char text[])
{
   short pp,pl,next;
   char true=0;

   pp = 0;  next = 1;
   pl = strlen(text);
   while (pp < pl && next>0){
      if(Low(text[pp]) == ca[next]) { pp++;  next = na[next]; }
      else { pp += ta[next];  next = fa[next]; }
   }
   if(next>0) next = na[next+na[0]];
   if(next == -2) true = 1;
   if(next > 0)
      if(fa[next] != -1 && pp<pl) true = 1;
   if(pcom) true = 1-true;

   return(true);
}



long work(char *sfile,char *readfile)
{
   char wdir,i,j;
   long xerr;
   XINFO *xinfo;
   XMINFO *xminfo;

   if(!info){
      if(dlen < XHEAD){
	 if(type == EXPAND) clen=1;
      }
      else{
	 xerr = file_check(readfile);
	 if(xerr == XPKERR_PACKED || xerr == XPKERR_NOTPACKED){
	    clen=1L;
	 }
	 else{
	    if(xerr != XPKERR_OK) return(xerr);
	 }
      }

      if(wf){
	 strcpy(writefile,owfile);
	 if(all) strcat(writefile,wpath);
	 wdir = writefile[strlen(writefile)-1];
	 if(wdir == ':' || wdir == '/') strcat(writefile,sfile);
      }
      else strcpy(writefile,readfile);

      if(suff[0]){
	 if(type == COMPRESS) strcat(writefile,suff);
	 else{
	    i=strlen(writefile)-1;  j=strlen(suff)-1;
	    while(writefile[i]==suff[j] && i>1 && j>=0){ i--; j--; }
	    writefile[i+1] = '\0';
	 }
      }
      else if(ident) strcat(writefile,".lin_tempfile");

      if(clen == 1L)
	 return(xload(readfile,writefile,dlen)); //copy unpacked file
      if(type == COMPRESS && dlen < minsize)
	 return(xsave(readfile,writefile,dlen,20000L,mode,pack,out));
   }

   strcpy(xpklib,"xpk");
   strcat(xpklib,crst);  strcat(xpklib,".library");
   if(!(XpkSubBase=(struct Library*)OpenLibrary(xpklib,0L))){
      strcpy(xpklib,"compressors/xpk");
      strcat(xpklib,crst);  strcat(xpklib,".library");
      if(!(XpkSubBase=(struct Library*)OpenLibrary(xpklib,0L)))
	 return(XPKERR_MISSINGLIB);
   }
   xinfo = (XINFO*)XpksPackerInfo();
   if(xinfo == 0L){ xerr=XPKERR_NOINFO; goto werr; }

   if(info){
      fprintf(Out,"\nXpkInfoVersion: %d\n",xinfo->XpkInfoVersion);
      fprintf(Out,"LibVersion:     %d\n",xinfo->LibVersion);
      fprintf(Out,"MasterVersion:  %d\n",xinfo->MasterVersion);
      fprintf(Out,"ModesVersion:   %d\n",xinfo->ModesVersion);
      fprintf(Out,"Name:           %s\n",xinfo->Name);
      fprintf(Out,"LongName:       %s\n",xinfo->LongName);
      fprintf(Out,"Description:    %s\n",xinfo->Description);
      fprintf(Out,"ID:             %s\n",crst);  // (xinfo->ID);
      fprintf(Out,"Flags:          ");
      if(xinfo->Flags & 0x1) fprintf(Out,"PK_CHUNK  ");
      if(xinfo->Flags & 0x2) fprintf(Out,"PK_STREAM  ");
      if(xinfo->Flags & 0x4) fprintf(Out,"PK_ARCHIVE  ");
      if(xinfo->Flags & 0x8) fprintf(Out,"UP_CHUNK  ");
      if(xinfo->Flags & 0x10) fprintf(Out,"UP_STREAM  ");
      if(xinfo->Flags & 0x20) fprintf(Out,"UP_ARCHIVE  ");
      fprintf(Out,"\n                ");
      if(xinfo->Flags & 0x80) fprintf(Out,"HOOKIO  ");
      if(xinfo->Flags & 0x400) fprintf(Out,"CHECKING  ");
      if(xinfo->Flags & 0x800) fprintf(Out,"PREREADHDR  ");
      if(xinfo->Flags & 0x2000) fprintf(Out,"ENCRYPTION  ");
      if(xinfo->Flags & 0x4000) fprintf(Out,"NEEDPASSWD  ");
      if(xinfo->Flags & 0x8000) fprintf(Out,"MODES  ");
      if(xinfo->Flags & 0x10000) fprintf(Out,"LOSSY");
      fprintf(Out,"\nMaxPkInChunk:   %ld\n",xinfo->MaxPkInChunk);
      fprintf(Out,"MinPkInChunk:   %ld\n",xinfo->MinPkInChunk);
      fprintf(Out,"DefPkInChunk:   %ld\n",xinfo->DefPkInChunk);
      fprintf(Out,"PackMsg:        %s\n",xinfo->PackMsg);
      fprintf(Out,"UnpackMsg:      %s\n",xinfo->UnpackMsg);
      fprintf(Out,"PackedMsg:      %s\n",xinfo->PackedMsg);
      fprintf(Out,"UnpackedMsg:    %s\n",xinfo->UnpackedMsg);
      fprintf(Out,"DefMode:        %d\n\n\n",xinfo->DefMode);
      //fprintf(Out,"Pad:            %d\n\n\n",xinfo->Pad);

      xminfo = xinfo->ModeDesc;
      do{
	 if(xerr = breaktest()) goto werr;
	 fprintf(Out,"Upto:          %ld\n",xminfo->Upto);
	 fprintf(Out,"Flags:         ");
	 if(xminfo->Flags & 1) fprintf(Out,"A3000SPEED  ");
	 if(xminfo->Flags & 2) fprintf(Out,"PK_NOCPU  ");
	 if(xminfo->Flags & 4) fprintf(Out,"UP_NOCPU");
	 fprintf(Out,"\nPackMemory:    %ld\n",xminfo->PackMemory);
	 fprintf(Out,"UnpackMemory:  %ld\n",xminfo->UnpackMemory);
	 fprintf(Out,"PackSpeed:     %ld\n",xminfo->PackSpeed);
	 fprintf(Out,"UnpackSpeed:   %ld\n",xminfo->UnpackSpeed);
	 fprintf(Out,"Ratio:         %d\n",xminfo->Ratio);
	 fprintf(Out,"ChunkSize:     %d\n",xminfo->ChunkSize);
	 fprintf(Out,"Description:   %s\n\n",xminfo->Description);

	 xminfo = xminfo->Next;
      }while(xminfo);

      xerr = X_INFO;  goto werr;
   }

   if(!(xinfo->Flags & XPKIF_PK_CHUNK))
      { xerr=ERR_WRONG_PACKER; goto werr; }
   if(!passw && (xinfo->Flags & XPKIF_NEEDPASSWD))
      { xerr=XPKERR_NEEDPASSWD; goto werr; }
   cmin = xinfo->MinPkInChunk;

   if(type == COMPRESS){  // save
      if(xinfo->Flags & XPKIF_PREREADHDR) pre=1;
      if(mode==MODE_SUBDEF) mode = (char)xinfo->DefMode;
      if(chunk==CHUNK_SUBDEF) chunk = xinfo->DefPkInChunk;
      if(chunk==0L) chunk = CHUNK_DEF;
      if(chunk>xinfo->MaxPkInChunk) chunk = xinfo->MaxPkInChunk;

      xerr = xsave(readfile,writefile,dlen,chunk,mode,pack,out);
      if(xerr != XPKERR_OK) goto werr;
   }
   else{  // load
      xerr = xload(readfile,writefile,clen);
   }


werr:
   if(XpkSubBase) CloseLibrary(XpkSubBase);
   return(xerr);
}





long file_check(char *name)
{
   struct FileLock *lock;
   long *lptr;	    //	EPU
   char *ptr;	    //	EPU



   epu = 0;  longhdr = 0;
   if(!(lock = (struct FileLock *)Open(name,MODE_OLDFILE))){
      return(ERR_OPEN);
   }
   XRead(fhead,XHEAD);
   Close((BPTR)lock);

   format = fhead->head;

   /* check if packed */

   if(format == 0x58504b46 || format == FORMAT){ // ('XPKF' || 'LINO')
      if(type == COMPRESS) return(XPKERR_PACKED);
      if(!passw && (fhead->flags & PASSWORD)) return(XPKERR_NEEDPASSWD);
      lptr = (long*)fhead+4;
      if(*lptr == 0x03f3 && ex == DATAFILE) return(ERR_EXECUTABLE);
      if(*lptr != 0x03f3 && ex == EXECUTABLE) return(ERR_DATAFILE);
      pack = fhead->pack;
      clen = fhead->clen;
      dlen = fhead->dlen;
      mode = (char)fhead->flags;
      longhdr = (long)(fhead->flags & LONGHDR);
      if(longhdr){
	 maxchunk = fhead->dchunk;
	 if(fhead->cchunk>maxchunk) maxchunk=fhead->cchunk;
      }
      else{
	 maxchunk = (fhead->cchunk) & 0xffff;
	 if((fhead->cchunk>>16)>maxchunk) maxchunk=fhead->cchunk>>16;
      }
      crst[0] = (pack & 0xff000000) >> 24;
      crst[1] = (pack & 0xff0000) >> 16;
      crst[2] = (pack & 0xff00) >> 8;
      crst[3] = pack;  crst[4] = '\0';
      packed = PACKED;
   }

   else if(format == 0x01806368){              // EPU
      if(type == COMPRESS) return(XPKERR_PACKED);
      ptr = (char*)fhead+19;
      strncpy(crst,ptr,4);
      maxchunk = (long)((fhead->clen)&0xff)*1000;
      dlen = fhead->pack;   clen = fhead->dlen+8L;
      lptr = (long*)fhead+4;
      pack = ((*lptr++)<<24) | ((*lptr)>>8);
      longhdr = 0L;
      packed = PACKED;
      epu = 1;
   }					       // -EPU
   else{   // not packed
      dlen = clen;
      if(type == EXPAND) return(XPKERR_NOTPACKED);
      if(format == 0x03f3 && ex == DATAFILE) return(ERR_EXECUTABLE);
      if(format != 0x03f3 && ex == EXECUTABLE) return(ERR_DATAFILE);
   }
   return(XPKERR_OK);
}




long xload(char *readfile,char *writefile,long len)
{
   long xerr;


   if(out) fprintf(Out,"%s  -  cr: %s\n",readfile,crst);

   if(clen == 1L) xerr = xcopy(readfile,writefile,dlen,20000L);
   else xerr = eload(readfile,writefile);

   if(!xerr && ident) xerr = change_name(readfile,writefile);
   else if(xerr){
      if(DeleteFile(writefile) != -1) xerr = ERR_DELETE;
   }

   if(xerr) return(xerr);

   count++;  dsum += dlen;  csum += len;

   if(out){
      fprintf(Out,"%ld -> %ld bytes",len,dlen);
      if(!time){ fprintf(Out,"  - "); PRINT_TIME(dlen); }
      else fprintf(Out,"\n");
   }
   return(XPKERR_OK);
}


long eload(char *readfile,char *writefile)
{
   char ln,newdir[256];
   struct FileLock *rlock,*wlock,*dlock;
   long xerr,ch_size;
   register long xlen,iblen,oblen,ilen,olen,chksum;

   xerr = 0L;  chksum = 0L;  ln = 2;

   if(!(rlock = (struct FileLock *)Open(readfile,MODE_OLDFILE)))
      return(ERR_OPEN);

   rw_open:
   if(!(wlock = (struct FileLock *)Open(writefile,MODE_NEWFILE))){
      if(all && wf && ln>1){
	 strcpy(newdir,writefile);  ln = strlen(newdir)-1;
	 rw_sub:
	 while(newdir[ln] != '/' && ln>1) ln--;
	 newdir[ln]=0;
	 if(ln>1){  // new subdirectory
	   if((dlock=(struct FileLock*)CreateDir(newdir))){
	      UnLock((BPTR)dlock);
	      if(out) fprintf(Out,"(dir) %s  [created]\n",newdir);
	      goto rw_open;
	   }
	   else goto rw_sub;
	 }
      }
      xerr = ERR_OPEN; goto felo;
   }

   if(Read((BPTR)rlock,(char*)fhead,HEAD)!=HEAD){
       xerr = ERR_READ; goto felo;
   }

   if(epu){       // EPU
      fhead->dlen = dlen;  // glob
      cmin = EPU_MIN;
      if(Seek((BPTR)rlock,-16L,OFFSET_CURRENT)==-1L){
	 xerr = XPKERR_IOERRIN;  goto felo;
      }
   }		  // -EPU

   iblen = maxchunk+16L;  // ilen maybe larger
   iblen = iblen+(iblen>>smarg)+MARGIN+MARGIN;
   xpar->OutBufLen = iblen;
   oblen = iblen+MARGIN;

   xpar->InBuf = 0L;  xpar->OutBuf = 0L;
   xpar->Sub[0] = 0L;

   if(!(xpar->InBuf = (APTR)AllocMem((long)iblen,
     (long)(MEMF_PUBLIC+MEMF_CLEAR)))){ xerr = XPKERR_NOMEM; goto felo; }
   if(!(xpar->OutBuf = (APTR)AllocMem((long)oblen,
    (long)(MEMF_PUBLIC+MEMF_CLEAR)))){ xerr = XPKERR_NOMEM; goto felo; }

   if(longhdr) ch_size = CHUNK_HEAD;
   else if(epu) ch_size = 2;          // EPU
   else ch_size = SHORT_HEAD;
   xlen = 0L;  xpar->Number = 0L;

   if(!time){ START(); I_STOP(); }
   while(xlen<fhead->dlen){
      if(Read((BPTR)rlock,(char*)chead,ch_size)!=ch_size){
	  xerr = ERR_READ; goto felo;
      }
      if(longhdr){
	 ilen = (UL)chead->clen;
	 olen = (UL)chead->dlen;
      }
      else{
	 ilen = (UL)(chead->clen)>>16;
	 olen = (UL)(chead->clen)&0xffff;
      }
      if(ilen != olen) packed=1; else packed=0;
      if(epu){                // EPU
	 if(ilen==0L) break;
	 else{
	    if(fhead->dlen-xlen<maxchunk) olen = fhead->dlen-xlen;
	    else olen = maxchunk;
	    if(olen<=cmin) ilen = olen;
	 }
      } 		      // -EPU

      xpar->InLen = ilen;
      xpar->OutLen = olen;
      if(epu) ilen = ((ilen+1L)&0xfffffffe);  // EPU
      else ilen = ((ilen+3L)&0xfffffffc);
      if(format == 0x58504b46) ilen += XPK_COMPAT;   // ('XPKF')
      if(Read((BPTR)rlock,(char*)xpar->InBuf,ilen)!=ilen){
	  xerr = ERR_READ; goto felo;
      }
      // if(pre){  // if lib prereads chunkheader
      //    if(Seek((BPTR)rlock,-4L,OFFSET_CURRENT)==-1L){
      //       xerr = XPKERR_IOERRIN;  goto felo;
      // }

      xpar->Number = xpar->Number+1;

      if(packed && xpar->OutLen>cmin){
	 if(!time) I_START();
	 xerr = XpksUnpackChunk(xpar);
	 if(!time) I_STOP();
	 if(format == FORMAT)
	    chksum += checksum((long*)xpar->OutBuf,xpar->OutLen);
      }
      else{
	 CopyMem((char*)xpar->InBuf,(char*)xpar->OutBuf,xpar->InLen);
	 xpar->OutLen = xpar->InLen;
      }


      if(xerr != XPKERR_OK) goto felo;
      if(xpar->OutLen > xpar->OutBufLen || xpar->OutLen != olen)
	 { xerr=XPKERR_CORRUPTPKD; goto felo; }

      if(!xlen) strncpy(fc16,(char*)xpar->OutBuf,16);

      xlen += xpar->OutLen;

      if(Write((BPTR)wlock,(char*)xpar->OutBuf,
       xpar->OutLen)!=xpar->OutLen){
	 xerr = ERR_WRITE;  goto felo;
      }
      if(epu){ XpksUnpackFree(xpar);  xpar->Sub[0]=0L; }  // EPU
   }

   if(!epu){  // EPU
    if(!passw && strncmp(fhead->first16,fc16,16))
      xerr = XPKERR_CORRUPTPKD;
   }	      // EPU

   if(format == FORMAT){
      if(chksum != fhead->chksum)
	 xerr=XPKERR_CHECKSUM; goto felo;
   }


   felo:
   if(!time) STOP();
   if(!epu) XpksUnpackFree(xpar);      // epu
   if(xpar->InBuf){ FreeMem(xpar->InBuf,iblen); xpar->InBuf=0L; }
   if(xpar->OutBuf){ FreeMem(xpar->OutBuf,oblen); xpar->OutBuf=0L; }
   if(rlock) Close((BPTR)rlock);
   if(wlock) Close((BPTR)wlock);

   return(xerr);
}




long xsave(char *readfile,char *writefile,long len,long chunk,char mode,
	 long pack,UB out)
{
   long clen,pro,xerr;


   if(out){
     if(ident) fprintf(Out,"%s  -  cr: %s  mode %d\n",readfile,crst,mode);
     else fprintf(Out,"%s  -  cr: %s  mode %d\n",writefile,crst,mode);
   }
   clen = len;

   if(dlen >= minsize)
      xerr = esave(readfile,writefile,&clen,len,chunk,mode);
   if(dlen < minsize || xerr != XPKERR_OK)
      xerr = xcopy(readfile,writefile,len,chunk);

   if(dlen>=minsize){
      if(!xerr && ident) xerr = change_name(readfile,writefile);
      else if(xerr){
	 if(DeleteFile(writefile) != -1) xerr = ERR_DELETE;
      }
   }

   if(xerr != XPKERR_OK) return(xerr);

   count++;  dsum += len;  csum += clen;
   if(out){
      fprintf(Out,"%ld -> %ld bytes",len,clen);
      pro = ((len-clen)*1000)/len;
      fprintf(Out,"  %ld.%ld%%  - ",pro/10,pro-(pro/10)*10);
      if(!time) PRINT_TIME(len);
      else fprintf(Out,"\n");
   }

   return(xerr);
}



long xcopy(char *readfile,char *writefile,long len,long chunk)
{
   char ln,newdir[256];
   struct FileLock *rlock,*wlock,*dlock;
   long *buf,blen,slen,xerr;


   buf = 0L;  xerr = 0L;  ln = 2;
   if(!(rlock = (struct FileLock *)Open(readfile,MODE_OLDFILE)))
      return(ERR_OPEN);

   xw_open:
   if(!(wlock = (struct FileLock *)Open(writefile,MODE_NEWFILE))){
      if(all && wf && ln>1){
	 strcpy(newdir,writefile);  ln = strlen(newdir)-1;
	 xw_sub:
	 while(newdir[ln] != '/' && ln>1) ln--;
	 newdir[ln]=0;
	 if(ln>1){  // new subdirectory
	   if((dlock=(struct FileLock*)CreateDir(newdir))){
	      UnLock((BPTR)dlock);
	      if(out) fprintf(Out,"(dir) %s  [created]\n",newdir);
	      goto xw_open;
	   }
	   else goto xw_sub;
	 }
      }
      xerr = ERR_OPEN;	goto fxw;
   }

   blen = chunk;
   if(!(buf = (long*)AllocMem((long)blen,
      (long)(MEMF_PUBLIC+MEMF_CLEAR)))){ xerr=XPKERR_NOMEM; goto fxw; }
   slen = 0L;
   while(slen<len){
      if(len-slen<chunk) chunk=len-slen;
      if(Read((BPTR)rlock,(char*)buf,(long)chunk)!=(long)chunk){
	 { xerr=ERR_READ;  goto fx1; }
      }
      if(Write((BPTR)wlock,(char*)buf,(long)chunk)!=(long)chunk){
	 { xerr=ERR_WRITE;  goto fx1; }
      }
      slen += chunk;
   }
   goto fxw;

   fx1:
   Close((BPTR)wlock);  wlock=0L;
   if(DeleteFile(writefile) != -1) xerr = ERR_DELETE;

   fxw:
   if(buf) FreeMem(buf,blen);
   Close((BPTR)rlock);
   if(wlock) Close((BPTR)wlock);
   return(xerr);
}




long esave(char *readfile,char *writefile,long *clen,long len,long chunk,
	 char mode)
{
   char ln,newdir[256];
   struct FileLock *rlock,*wlock,*dlock;
   long *lptr,*sptr,iblen,oblen,ch_size,w_over,xerr=0L;
   register long xclen,xdlen,chksum,echunk,olen;
   UB *dst;

   xpar->InBuf = 0L;  xpar->Sub[0] = 0L;  dst = 0L;  ln=2;
   chksum = 0L;  echunk = chunk;
   if(!(rlock = (struct FileLock *)Open(readfile,MODE_OLDFILE)))
      return(ERR_OPEN);

   sw_open:
   if(!(wlock = (struct FileLock *)Open(writefile,MODE_NEWFILE))){
      if(all && wf && ln>1){
	 strcpy(newdir,writefile);  ln = strlen(newdir)-1;
	 sw_sub:
	 while(newdir[ln] != '/' && ln>1) ln--;
	 newdir[ln]=0;
	 if(ln>1){  // new subdirectory
	   if((dlock=(struct FileLock*)CreateDir(newdir))){
	      UnLock((BPTR)dlock);
	      if(out) fprintf(Out,"(dir) %s  [created]\n",newdir);
	      goto sw_open;
	   }
	   else goto sw_sub;
	 }
      }
      xerr = ERR_OPEN;	goto fepo;
   }

   if(echunk>len) echunk = ((len+3L)&0xfffffffc);
   iblen = echunk;
   w_over = (iblen>>smarg)+MARGIN;
   xpar->OutBufLen = echunk+w_over+MARGIN;
   oblen = xpar->OutBufLen+MARGIN;

   if(echunk>0xffff){
      longhdr = LONGHDR;
      ch_size = CHUNK_HEAD;
   }
   else{
      longhdr = 0L;
      ch_size = SHORT_HEAD;
   }

   if(!(xpar->InBuf = (APTR)AllocMem((long)iblen,
    (long)(MEMF_PUBLIC+MEMF_CLEAR)))){ xerr=XPKERR_NOMEM; goto fepo; }
   if(!(dst = (UB*)AllocMem((long)oblen,
    (long)(MEMF_PUBLIC+MEMF_CLEAR)))){ xerr=XPKERR_NOMEM; goto fepo; }
   xpar->OutBuf = (APTR)((long)dst+ch_size);

   xpar->Mode = (long)mode;

   // Header
   sptr = (long*)fhead->first16;
   if(passw) lptr = (long*)fh16;
   else lptr = (long*)fhead;
   *sptr++ = *lptr++;  *sptr++ = *lptr++;
   *sptr++ = *lptr++;  *sptr = *lptr;

   fhead->head = (long)FORMAT;
   fhead->pack = pack;
   fhead->dlen = len;
   fhead->flags = mode|passw|longhdr;


   if(Write((BPTR)wlock,(char*)fhead,HEAD)!=HEAD){
      xerr = ERR_WRITE;  goto fepo;
   }

   xclen = 0L;	xdlen = 0L;
   xpar->Number = 0L;
   lptr = (long*)dst;

   if(!time){ START(); I_STOP(); }

   while((long)xdlen<len){
      if(len-xdlen<echunk){
	 echunk=len-xdlen;
	 xpar->OutBufLen = echunk+w_over+MARGIN;
      }

      if(Read((BPTR)rlock,(char*)xpar->InBuf,echunk)!=echunk){
	 xerr=ERR_READ;
	 goto fepo;
      }

      xpar->InLen = (long)echunk;
      xpar->Number = xpar->Number+1;


      if(echunk>cmin){
	 if(!time) I_START();
	 xerr = XpksPackChunk(xpar);
	 if(!time) I_STOP();
	 if(xerr == XPKERR_EXPANSION || (xpar->OutLen > xpar->InLen && !oflow)){
	    CopyMem((char*)xpar->InBuf,(char*)xpar->OutBuf,echunk);
	    xpar->OutLen = echunk;
	    xerr = XPKERR_OK;
	 }
	 else chksum += checksum((long*)xpar->InBuf,xpar->InLen);
      }
      else{
	 CopyMem((char*)xpar->InBuf,(char*)xpar->OutBuf,echunk);
	 xpar->OutLen = echunk;
      }


      if(xerr != XPKERR_OK) goto fepo;

      olen = xpar->OutLen+ch_size;
      olen = ((olen+3L)&0xfffffffc);  //+XPK_COMPAT;
      if(longhdr){
	 *lptr = xpar->OutLen;
	 *(lptr+1) = echunk;
      }
      else *lptr = ((xpar->OutLen)<<16)|(echunk&0xffff);

      if(Write((BPTR)wlock,(char*)dst,olen)!=olen){
	 xerr = ERR_WRITE;
	 goto fepo;
      }

      xdlen += echunk;
      xclen += olen;
      if(!oflow){
	 if(xclen>xdlen+w_over && !passw)
	    { xerr=XPKERR_EXPANSION; goto fepo; }
      }
   }
   xclen += HEAD;
   if(!oflow){
      if(xclen >= len && !passw)
	 { xerr = XPKERR_EXPANSION; goto fepo; }
   }
   if(Seek((BPTR)wlock,4L,OFFSET_BEGINNING)==-1L){
      xerr = XPKERR_IOERRIN;  goto fepo;
   }
   w_over = xclen;  // bec. of reg.
   if(Write((BPTR)wlock,(char*)&w_over,4L)!=4L){ // packed length
      xerr = ERR_WRITE;  goto fepo;
   }
   *clen = xclen;

   if(Seek((BPTR)wlock,36L,OFFSET_BEGINNING)==-1L){
      xerr = XPKERR_IOERRIN;  goto fepo;
   }
   w_over = chksum;  // bec. of reg.
   if(Write((BPTR)wlock,(char*)&w_over,4L)!=4L){ // checksum
      xerr = ERR_WRITE;  goto fepo;
   }


   fepo:
   if(!time) STOP();
   XpksPackFree(xpar);
   if(xpar->InBuf){ FreeMem(xpar->InBuf,iblen); xpar->InBuf=0L; }
   if(dst) FreeMem(dst,oblen);
   if(rlock) Close((BPTR)rlock);
   if(wlock) Close((BPTR)wlock);

   return(xerr);
}


long change_name(char *readfile, char *writefile)
{
   if(DeleteFile(readfile) != -1) return(ERR_LOCK);
   if(Rename(writefile,readfile) != -1) return(ERR_LOCK);

   return(XPKERR_OK);
}


void write_err(long xerr)
{
   if(out && xerr != XPKERR_OK)
      fprintf(Out,"%s !!!\n",errstr[xerr-LOWER_ERR-1]);
}


long breaktest(void)
{
   if (*xkey == K_LSHFT || *xkey == K_RSHFT){ // Keys -SHFT-
      *xkey = 0;
      Delay (K_DELAY);
      if(!(*xmouse & (1<<6)))  // left mouse-button
	 return(XPKERR_ABORTED);
   }
   return(XPKERR_OK);
}







void START (void)
{
   DateStamp(&clo); timer=act_ticks;
}
void STOP (void)
{
   DateStamp(&clo);  timer=act_ticks-timer;
}
void PRINT_TIME(long len)
{
   i_time = timer/50; stime = (timer-i_time*50)*2;
   if(timer==0) timer=1;  // to prevent from division by zero
   if(kilo){
     if(stime<10) fprintf(Out," %d.0%d sec (%ld kb/s)\n",i_time,stime,(len*50/timer+512)>>10);
     else fprintf(Out," %d.%d sec (%ld kb/s)\n",i_time,stime,(len*50/timer+512)>>10);
   }
   else{
     if(stime<10) fprintf(Out," %d.0%d sec (%ld bps)\n",i_time,stime,len*50/timer);
     else fprintf(Out," %d.%d sec (%ld bps)\n",i_time,stime,len*50/timer);
   }
}
void I_START (void)      /* continues after I_STOP */
{
   DateStamp(&clo);
   i_time = act_ticks-i_time;
   timer = timer+i_time;
}

void I_STOP (void)
{
   DateStamp(&clo);
   i_time = act_ticks;
}




/************************************************

Some ideas, what future versions could support:

+ Reading files, that are packed with powerpacker
+ Writing other fileformats
+ Recrunchmode
+ Workbench version

*************************************************/

