/*{{{ defines*/ /************************************************* LHarc version 1.13b (c)Yoshi, 1988-89. main module : 1989/ 5/14 adaption to ATARI ST with TURBO-C 1.1 and some corrections by J. Moeller 1990/01/31 Assembly and more corrections with Turbo-C 1.0, 2.0, by Thomas Quester HTAB = 4 *************************************************/ #define ThisSystem 'A' /* Atari */ #include #include #include #include #include #include #include #include #ifdef Japanese #include "usage_j.h" #else #ifdef German #include "usage_d.h" #else #include "usage_e.h" #endif #endif #define from extern #ifndef __TOS__ #include #include #include #include #include #else #include #include #define MAXPATH 119 #define MAXDIR 102 #define MAXNUMFILES 128 #define far #define huge #define setmode(stream,mode) /* sorry: no such function known */ #include "goodputc.h" #endif #define UNKNOWNERR 0 #define INVCMDERR 1 #define MANYPATERR 2 #define NOARCNMERR 3 #define NOFNERR 4 #define NOARCERR 5 #define RENAMEERR 6 #define MKTMPERR 7 #define DUPFNERR 8 #define TOOMANYERR 9 #define TOOLONGERR 10 #define NOFILEERR 11 #define MKFILEERR 12 #define RDERR 13 #define WTERR 14 #define MEMOVRERR 15 #define INVSWERR 16 #define CTRLBRK 17 #define NOMATCHERR 18 #define COPYERR 19 #define NOTLZH 20 #define OVERWT 21 #define MKDIR 22 #define MKDIRERR 23 #define CRCERR 24 #define RDONLY 25 #ifndef __TOS__ #define PAGER "less" #define BUFFERSIZ 4096L #else #define PAGER "less.ttp" #define BUFFERSIZ 16384L #endif #define MAXBLK 64 #define MAX_PAT 512 #define FAULT 0 #define SUCCS ~FAULT #ifndef __TOS__ #define getch() (bdos(0x08, 0, 0) & 0xff) #endif #define min(a,b) ((a>b) ? b : a) typedef unsigned char uchar; typedef unsigned int uint; typedef unsigned long ulong; FILE *file1, *file2, *file3; from FILE *infile; from FILE *outfile; from int FileFits; /* 1, wenn File passt */ int cmd; /* command */ int cmdupdate; /* Not zero, when updating archive */ int errorlevel = 0; /* return value */ jmp_buf exit_jmp; /* Jump to exit of program */ extern long textsize; /* file size before compression */ extern long codesize; /* file size after compression */ from long blocksize; /* Bytes bis "*" (norm. 4096) */ long arcpos0; /* position pointer for archive */ uchar *basedir; /* base directory (home-directory) */ uchar *wdir = ""; /* work directory */ uchar workdir[MAXPATH]; /* work directory */ uchar *infname; /* input file name (for error message) */ uchar *outfname; /* output file name (for error message)*/ int attr; /* file attributes for search files */ int Nfile; /* number of files which was found */ /* >> fbmax is used to compute the total amout used by filenames << */ ulong fblft, fbsize; ulong fbmax,fbfiles; /* for buffers handling file names */ #ifndef __TOS__ uint seg; /* beginning segment of file name buffers */ #endif uchar far *fbuf, huge *fbnxt; /* pointer to file name buffers */ uchar arcname[MAXPATH]; /* archive name */ uchar pathname[MAXPATH]; /* work for file name (extracting) */ uchar dospathname[MAXPATH]; /* work for filename (8+3 chars) */ uchar filename[MAXPATH]; /* work for file name (for file in archive) */ uchar comment[MAXPATH]; /* Komments in archives */ uchar SystemId; /* Archiv createt on system */ uchar freezing=0; /* Enables extended headers */ uchar UseExthdr=0; /* 1, if gethdr has to use exthdrs */ int patno; /* No. of path names in command line */ int UnixFile; /* !=0 if filename is not 8+3 */ uchar patfile[MAX_PAT][12]; /* file name in command line */ uchar *patpath[MAX_PAT]; /* directory name in command line */ int patcnt[MAX_PAT]; /* counts which this name matched */ uchar patnul[] = "*.*"; /* default path name */ uchar backup1[MAXPATH], backup2[MAXPATH]; /* temporary file names */ char *TheInputBuf; /* Input-Buffer */ char *TheOutputBuf; from int unpackable; /* temporary file names */ uchar flg_r = 0, flg_p = 0, flg_x = 0, flg_m = 0; uchar flg_a = 0, flg_c = 0, flg_v = 0, flg_w = 0; uchar flg_d = 0, flg_u = 0, flg_s = 0, flg_k = 0; uchar flg_e = 0; uchar flg_unpacked; /* Set to 1, if 100% used in pack_afx */ uchar elen=3; from uchar flg_n = 0; uchar flg_t = 0; uchar flg_5 = 0; uchar flg_arc = 0,flg_backup=0; uchar method=5, FlgMethod=5; #ifdef __TOS__ uchar flg_h = 0; #endif /* switches */ uchar copying = 0; /* turn on when copying temporary file */ uchar crcflg = 0; /* force copyfile() to calculate CRC*/ uchar tstflg = 0; /* turn on in 't' command */ uchar swchar; /* switch character */ uchar *pager = PAGER; /* utility used in 'p /v' mode */ from uint crc; /* calculated CRC code */ uchar *keyword = ""; /* key word for auto-execution */ struct filebuf { /* work for file name buffer */ void far *next; uchar fpos; /* position of file name */ uchar cpos; /* position of effective path name */ uchar dir[MAXDIR]; /* full path name */ } fb0, fb1; extern char *errmes[]; /* array of pointers to error messages */ /* extern uchar use[]; */ /* usage */ extern uchar buf2[], buf3[]; /* I/O buffers */ #ifdef Japanese /* routines for handling Japanese strings (import from util.c) */ extern uchar *j_strupr(uchar *p); extern int j_strcmp(char *p, char *q); extern uchar *j_strchr(char *p, uint c); extern uchar *j_strrchr(char *p, uint c); extern void slash2yen(uchar *p); /* convert '/' to '\' */ extern void yen2shlas(uchar *p); #define strupr j_strupr #define strcmp j_strcmp #define strchr j_strchr #define strrchr j_strrchr #else extern void slash2yen(uchar *p); /* convert '/' to '\' */ extern void yen2slash(uchar *p); /* #define slash2yen(p) */ /* extern void slash2yen(uchar *p); /* convert '/' to '\' */ #endif extern int getfattr(uchar *fn); /* get file attributes */ extern void setfattr(uchar *fn, int attr);/* set file attributes */ #ifndef __TOS__ extern uchar getswchar(void); /* get switch character */ extern int test_afx(char *s); /* šberprft, ob Datei gepackt ist */ #else extern char *stpcpy (char *dest, char *source); extern int mkdir (char *path); #define getswchar() ('/') #endif #ifdef __TOS__ struct outbuf { char *ptr; /* aktuelles Zeichen */ char *last; /* letztes Zeichen */ char *base; /* erstes Zeichen */ FILE *file; /* dateiname */ } OutBufMem; struct outbuf *OutBuf; #endif __TOS__ extern void mkcrc (void); /* import from 'LZS.*' */ extern void copyfile (FILE *Source, FILE *Dest, long size); extern void Encode (void); /* import from 'LZHUF.*' */ extern ulong encode5(ulong orgsize); extern void init_encode5(void); extern void EncodeOld(void); extern void Decode (void); extern void decode_lh5(ulong orgsize,ulong pacsize); extern void DecodeOld(void); extern char M_NOMATCHERR[]; extern char M_COPYERR[]; extern char M_NOTLZH[]; extern char M_OVERWT[]; extern char M_MKDIR[]; extern char M_MKDIRERR[]; extern char M_CRCERR[]; extern char M_RDONLY[]; struct ftime arcstamp /* = {0L} */; /* time stamp for archive */ struct LzHead { /* file header */ uchar HeadSiz, HeadChk, HeadID[5]; ulong PacSiz, OrgSiz; /* 16- and 32-bit Intel format !!!*/ struct ftime Ftime; uint Attr; uchar Fname[MAXPATH]; /* packed filename + crc */ } Hdr1, Hdr2; #ifndef __TOS__ struct exeHead { /* EXE header for SFX */ uint exeID, byte, page, reloc; uint hdrsize, minalloc, maxalloc, initSS; uint initSP, chksum, initIP, initCS; uint reloctab, overlay, dummy1, dummy2; } ExeHdr = { 'MZ', 0, 0, 0, 2, 0, 0xffff, 0xfff0, 0x100, 0, 0x100, 0xfff0, 0x1e, 0, 0, 0 }; #endif #define FTimeToUIntTime(t) ((((t.ft_hour << 6) | t.ft_min) << 5) | t.ft_tsec) #define FTimeToUIntDate(t) ((((t.ft_year << 4) | t.ft_month) << 5) | t.ft_day) #define FTimeToULong(t) (((ulong)FTimeToUIntDate(t) << 16) | \ (ulong)FTimeToUIntTime(t)) uchar mksum(struct LzHead *h); #ifdef __TOS__ extern int argvmain (int, uchar **, uchar **); static DTA _mydta; #endif __TOS__ /*}}} */ /*{{{ setcrc:*/ #ifndef __TOS__ #define setcrc(h, crc) (*(uint *)(&(h)->Fname[1]+(h)->Fname[0])=(crc)) #define getcrc(h) (*(uint *)(&(h)->Fname[1]+(h)->Fname[0])) #else static void setcrc (struct LzHead *h, uint crc) { uchar *CrcPtr = &h->Fname[1] + h->Fname[0]; *CrcPtr++ = (uchar)(crc & 0xff); *CrcPtr++ = (uchar)(crc >> 8); *CrcPtr++ = (uchar)(ThisSystem); /* SystemId */ if (freezing==0) { /* *CrcPtr++ = (uchar) 0; *CrcPtr++ = (uchar) 0; */ } } /*}}} */ /*{{{ getcrc:*/ static uint getcrc (struct LzHead *h) { uchar *CrcPtr = &h->Fname[1] + h->Fname[0]; return ((uint)*CrcPtr) | ((uint)*(CrcPtr + 1) << 8); } #endif /*}}} */ /*{{{ usage: display helps*/ /******************************* display helps *******************************/ void usage(void) { int i; char *s,c; s=use; i=1; while ( (c=*s++) != 0) { if (c=='\n') if (i++ == 24) { fflush (stdin); /* wait for keystroke when used */ printf ("\n%s",M_PRESSKEY); /* with GEM-Desktop */ getch (); putchar ('\n'); i=1; } putchar(c); } putchar ('\n'); longjmp (exit_jmp, 1); } /*}}} */ /*{{{ message: Display a message*/ /******************************* display a message *******************************/ void message(uchar *p, uchar *q) { if (flg_d == 0) { printf("%s", p); if (q) { printf(" : '%s'", q); } printf("\n"); } } /*}}} */ /*{{{ error: process for an error*/ /******************************* process for an error *******************************/ void error(int errcode, uchar *p) { if (copying) { /* error during copying temporary? */ fprintf(stderr, "\n%s\n", M_COPYERR); fclose(file1); unlink(arcname); /* erase incomplete archive */ file1 = NULL; } fprintf(stderr, "\n%s", errmes[errcode]); if (p) { fprintf(stderr, " : '%s'", p); } fprintf(stderr, "\n"); if (file3) { fclose(file3); if (!cmdupdate) /* during extracting */ unlink(pathname); /* delete the file */ file3=NULL; } if (file1) { fclose(file1); if (cmdupdate) /* during updating */ rename(backup1, arcname); /* recover old archive */ } if (file2) { fclose(file2); if (!copying) { /* if not copying */ unlink(backup2); /* delete temporary */ file2=NULL; } } if (copying) errorlevel = 3; else errorlevel = 2; longjmp (exit_jmp, 1); } /*}}} */ /*{{{ userbreak: handle user break*/ /******************************* handle user break *******************************/ #ifndef __TOS__ void userbreak(void) { error(CTRLBRK, NULL); } #endif /*}}} */ /*{{{ e_fopen: fopen with detecting error*/ /******************************* fopen with detecting error *******************************/ FILE *e_fopen(uchar *fname, uchar *mode, int errID) { FILE *f; if ((f = fopen(fname, mode)) == NULL) { if (errno == EACCES) error(RDONLY, fname); error(errID, fname); } return f; } /*}}} */ /*{{{ e_rename: rename with detecting erorr*/ /******************************* rename with detecting error *******************************/ void e_rename(uchar *old, uchar *new) { if (rename(old, new)) error(RENAMEERR, old); } /*}}} */ /*{{{ getyn: ask 'Y' or 'N'*/ /******************************* ask 'Y' or 'N' *******************************/ uint getyn(void) { uint yn; do { yn = toupper(getch()); #ifdef German } while (yn != 'J' && yn != 'N'); #else } while (yn != 'Y' && yn != 'N'); #endif fprintf(stderr, "%c\n", yn); #ifdef German if (yn == 'J') yn = 'Y'; #endif return yn; } /*}}} */ /*{{{ getynr: ask 'Y', 'N' or 'R'*/ /******************************* ask 'Y' or 'N' *******************************/ uint getynr(void) { uint yn; do { yn = toupper(getch()); #ifdef German } while (yn != 'J' && yn != 'N' && yn != 'R'); #else } while (yn != 'Y' && yn != 'N' && yn != 'R'); #endif fprintf(stderr, "%c\n", yn); #ifdef German if (yn == 'J') yn = 'Y'; #endif return yn; } /*}}} */ /*{{{ extfn: File name -> internal format*/ /******************************* file name -> internal format *******************************/ void extfn(uchar *p, uchar *pb) { int i; uchar * q; if ((q = strrchr(p, '\\')) != NULL || (q = strchr(p, ':')) != NULL) p = q + 1; q = p; for (i = 8; i > 0; i--, pb++) { switch (*p) { case '*': *pb = '?'; break; case '.': case '\0': *pb = ' '; break; default: *pb = *p++; } } while (+(*p != '\0' && *p++ != '.')); for (i = 3; i > 0; i--, pb++) { switch (*p) { case '*': *pb = '?'; break; case '\0': *pb = ' '; break; default: *pb = *p++; } } *q = *pb = '\0'; } /*}}} */ /*{{{ packfn: internal format -> file name*/ /******************************* internal format -> file name *******************************/ void packfn(uchar *p, uchar *q) { int i; for (i = 8; i > 0; i--) { if (*q != ' ') *p++ = *q; q++; } *p++ = '.'; for (i = 3; i > 0; i--) { if (*q != ' ') *p++ = *q; q++; } if (p[-1] == '.') p--; *p = '\0'; } /*}}} */ /*{{{ backpath get back to parent directory*/ /******************************* get back to parent directory *******************************/ uchar *backpath(uchar *p) { uchar *q; if ((q = strrchr(p, '\\')) == NULL && (q = strchr(p, ':')) == NULL) { *p = '\0'; q = p; } else { *++q = '\0'; } return q; } /*}}} */ /*{{{ tstpat : whether path name was used or not*/ /*********************************** whether path name was used or not ***********************************/ void tstpat(void) { int i, cnt; uchar path[MAXPATH]; cnt = 0; for (i = 0; i < patno; i++) cnt += patcnt[i]; if (cnt == 0) /* no file matched */ error(NOFILEERR, NULL); for (i = 0; i < patno; i++) { if (patcnt[i] == 0) { /* if any path name was not used */ packfn(stpcpy(path, patpath[i]), patfile[i]); fprintf(stderr, "%s : '%s'\n", M_NOMATCHERR, path); errorlevel = 1; /* display warning */ } } } /*}}} */ /*{{{ sethdr: make a file header*/ /******************************* make a file header *******************************/ void sethdr(uchar *fn, uint attr, struct LzHead *h) { uint l; memset(h, 0, sizeof(struct LzHead)); l = (uint)strlen(fn); /* length of file name */ h -> Fname[0] = l; memcpy(h -> Fname + 1, fn, l); l += 20 + elen +2; /* size of header */ h -> HeadSiz = l; fseek(file3, 0L, SEEK_END); h -> OrgSiz = textsize = ftell(file3); /* original size of a file */ h -> PacSiz = codesize = 0; method=FlgMethod; /* if (h->OrgSiz < 5000 && FlgMethod==5) method=1; */ rewind(file3); getftime(fileno(file3), &(h -> Ftime)); /* get time stamp */ h -> Attr = attr; /* file attributes */ if (method==0) memcpy(h->HeadID,"-lz5-",5); if (method==1) memcpy(h->HeadID,"-lh1-",5); if (method==5) memcpy(h->HeadID,"-lh5-",5); if (cmd== 'C') memcpy(h->HeadID,"-afx-",5); } /*}}} */ /*{{{ wthdr680x0: write a file header on atari (or any system)*/ #ifdef __TOS__ /******************************* write a file header on Atari ST (680x0) *******************************/ int wthdr680x0 (register struct LzHead *h, FILE *file) { uchar buffer [256]; uchar chksum,*ptr2; int comlen; register uchar *ptr,*co,*ptr1; union { uint x; uchar bytes [2]; } swap16; union { ulong x; uchar bytes [4]; } swap32; register int i; int len; char c; if (comment[0] == 0) comlen = 0; else { comlen = 4 + strlen(comment); h->PacSiz += comlen; } if (flg_s) yen2slash(&(h->Fname)); h -> HeadChk = mksum(h); /* header sum */ ptr = buffer; *ptr++ = h->HeadSiz; *ptr++ = h->HeadChk; for (i = 0; i < 5; i++) *ptr++ = h->HeadID [i]; swap32.x = h->PacSiz; for (i = 3; i >= 0; i--) /* convert motorola --> intel */ *ptr++ = swap32.bytes [i]; swap32.x = h->OrgSiz; for (i = 3; i >= 0; i--) /* convert motorola --> intel */ *ptr++ = swap32.bytes [i]; swap32.x = FTimeToULong (h->Ftime); for (i = 3; i >= 0; i--) /* convert motorola --> intel */ *ptr++ = swap32.bytes [i]; swap16.x = h->Attr; for (i = 1; i >= 0; i--) /* convert motorola --> intel */ *ptr++ = swap16.bytes [i]; len = *ptr++ = h->Fname [0]; for (i = 1; i <= len + elen+2; i++) *ptr++ = h->Fname[i]; if (freezing && flg_k==0) { ptr2=ptr-1; if (comlen) { ptr-=2; *ptr++=comlen; *ptr++=0; *ptr++=0x3f; co=comment; while (*co) *ptr++=*co++; *ptr++=0xff; *ptr++=0x0; *ptr++=0x0; } ptr1=&buffer[2]; chksum=0; while (ptr1 != ptr2) chksum = chksum + *ptr1++; buffer[1]=chksum; len = (int) fwrite (buffer, ptr-buffer , 1, file); } else len = (int) fwrite (buffer, h->HeadSiz +2 , 1, file); /* slash2yen(&(h->Fname)); */ h -> HeadChk = mksum(h); /* header sum */ return len; } #endif /*}}} */ /*{{{ wthdr: write a file header*/ /******************************* write a file header *******************************/ void wthdr(struct LzHead *h) { arcpos0 = ftell(file2); /* memorize this position */ #ifndef __TOS__ if (fwrite(h, h -> HeadSiz + 2, 1, file2) == 0) error(WTERR, backup2); #else if (wthdr680x0 (h, file2) == 0) error(WTERR, backup2); #endif } /*}}} */ /*{{{ mksum: calculate check-sum*/ /******************************* calculate check-sum of header *******************************/ uchar umksum(struct LzHead *h) { uchar *p, *q; uchar i; p = (uchar *)h ; q = p + h -> HeadSiz; p+=2; q+=2; for (i = 0; p < q; p++) i += *p; return i; } #ifndef __TOS__ uchar mksum(struct LzHead *h) { uchar *p, *q; uchar i; p = (uchar *)h + 2; q = p + h -> HeadSiz; for (i = 0; p < q; p++) i += *p; return i; } #else uchar mksum(struct LzHead *h) { union { uint x; uchar bytes [2]; } swap16; union { ulong x; uchar bytes [4]; } swap32; char *s; register uchar sum; register int i; int len; sum = 0; for (i = 0; i < 5; i++) sum += h->HeadID [i]; swap32.x = h->PacSiz; for (i = 3; i >= 0; i--) sum += swap32.bytes [i]; swap32.x = h->OrgSiz; for (i = 3; i >= 0; i--) sum += swap32.bytes [i]; swap32.x = FTimeToULong (h->Ftime); for (i = 3; i >= 0; i--) sum += swap32.bytes [i]; swap16.x = h->Attr; for (i = 1; i >= 0; i--) sum += swap16.bytes [i]; sum += h->Fname [0]; len = (int) h->Fname [0]; s=h->Fname; s++; for (i = 1; i <= h->HeadSiz - 20; i++) sum += *s++; return sum; } #endif /*}}} */ /*{{{ remkhdr: remake file header and write*/ /******************************* remake file header & write *******************************/ void remkhdr(struct LzHead *h) { int flg; long arcpos1; flg = 0; h -> PacSiz = codesize; /* packed size of a file */ setcrc (h, crc); flg_unpacked=0; if (h -> OrgSiz <= codesize && flg_5==0) { /* if packed size >= original size */ flg = 1; /* select method "simple copy" */ flg_unpacked=1; memcpy(h->HeadID,"-lh0-",5); h -> PacSiz = h -> OrgSiz; } h -> HeadChk = mksum(h); /* header sum */ if (flg_u && flg_5 == 0) { /* without compression */ crcflg=1; crc=0; copyfile(file3, file2, h -> OrgSiz); /* do simple copy */ flg = 0; setcrc(h,crc); } arcpos1 = ftell(file2); /* memorize this position */ fseek(file2, arcpos0, SEEK_SET); /* seek to header */ #ifndef __TOS__ fwrite(h, h -> HeadSiz + 2, 1, file2); /* rewrite header */ #else wthdr680x0 (h, file2); #endif if (flg && flg_5 == 0) { rewind(file3); copyfile(file3, file2, h -> OrgSiz); /* do simple copy */ } else { fseek(file2, arcpos1, SEEK_SET); /* return to the end */ } } /*}}} */ /*{{{ rdhdr680x0: read a file header on Atari*/ #ifdef __TOS__ /******************************* read a file header on Atari ST (680x0) *******************************/ int rdhdr680x0 (register struct LzHead *h, FILE *file) { uchar buffer [sizeof (struct LzHead)]; register uchar *ptr; union { uint x; uchar bytes [2]; } swap16; union { ulong x; uchar bytes [4]; } swap32; register int i; int len; if ((h -> HeadSiz = getc (file)) <= 0 || ferror (file) || h->HeadSiz > sizeof buffer - 1 || fread (buffer, (int) h->HeadSiz + 1, 1, file) == 0) { return FAULT; } ptr = buffer; h->HeadChk = *ptr++; for (i = 0; i < 5; i++) h->HeadID [i] = *ptr++; for (i = 3; i >= 0; i--) /* convert intel --> motorola */ swap32.bytes [i] = *ptr++; h->PacSiz = swap32.x; for (i = 3; i >= 0; i--) /* convert intel --> motorola */ swap32.bytes [i] = *ptr++; h->OrgSiz = swap32.x; for (i = 3; i >= 0; i--) /* convert intel --> motorola */ swap32.bytes [i] = *ptr++; h->Ftime.ft_tsec = (uint)(swap32.x & 0x1f); h->Ftime.ft_min = (uint)((swap32.x >> 5) & 0x3f); h->Ftime.ft_hour = (uint)((swap32.x >> 11) & 0x1f); h->Ftime.ft_day = (uint)((swap32.x >> 16) & 0x1f); h->Ftime.ft_month = (uint)((swap32.x >> 21) & 0x0f); h->Ftime.ft_year = (uint)((swap32.x >> 25) & 0x7f); for (i = 1; i >= 0; i--) /* convert intel --> motorola */ swap16.bytes [i] = *ptr++; h->Attr = swap16.x; for (i=0;i<=MAXPATH;i++) h->Fname[i]=0; len = h->Fname [0] = *ptr++; for (i = 1; i <= h->HeadSiz - 20; i++) h->Fname [i] = *ptr++; return SUCCS; } #endif /*}}} */ /*{{{ gethdr : get a file header*/ /******************************* get a file header *******************************/ uchar *gethdr(FILE *arc, struct LzHead *h) { uchar *q,*p,*p1, i; uint extsize; char exthdr[256]; char fname[256]; #ifndef __TOS__ if ((h -> HeadSiz = getc(arc)) <= 0 || h -> HeadSiz > sizeof(struct LzHead) - 3 || fread(&(h -> HeadChk), h -> HeadSiz + 1, 1, arc) == 0) { /* read file header */ return NULL; } #else if (!rdhdr680x0 (h, arc)) return NULL; #endif if (mksum(h) != h -> HeadChk) if (umksum(h) != h -> HeadChk) /* if sum is wrong */ return NULL; i = *(h -> Fname); strncpy(filename, h -> Fname + 1, i); *(filename + i) = '\0'; if ( (flg_k == 0) && UseExthdr) { extsize=h->Fname[h->Fname[0]+4]; SystemId = h->Fname[h->Fname[0]+3]; comment[0] = 0; /* Prevent showing an illegal comment */ if (extsize != 0) { fread(exthdr,1,extsize-2,arc); /* h->PacSiz-=extsize; extsize=fgetc(arc); extsize+=(uint)fgetc(arc)<<8; */ while (extsize != 0) { if (exthdr[0] == 2) { /* pathname-header */ p=fname; p1=&exthdr[1]; while ( (*p++=*p1++) != 0xff); p--; *p++='\\'; strcpy(p,filename); strcpy(filename,fname); } if (exthdr[0] == 0x3f) { /* Komment - Header */ p=comment;p1=&exthdr[1]; while ((*p++=*p1++) != 0xff); p--; *p=0; } h->PacSiz-=extsize; extsize=fgetc(arc); extsize+=(uint)fgetc(arc)<<8; if (extsize) { if (extsize > 250) { fseek(arc,extsize-2,SEEK_CUR); /* Header to long, skip */ exthdr[0]=255; } else { fread(exthdr,1,extsize-2,arc); } } } } } if ((q = strrchr(filename, '\\')) == NULL && (q = strrchr(filename, '/')) == NULL && (q = strchr(filename, ':')) == NULL) q = filename; else q++; return q; /* return the portion of file name */ } /*}}} */ /*{{{ matchpat: test match of file name*/ /******************************* test match of file name *******************************/ int matchpat(uchar *p) { uchar buf[12], name[MAXPATH]; int i, j, retcode; retcode = FAULT; strcpy(name, p); extfn(name, buf); for (i = 0; i < patno; i++) { if (flg_p || *patpath[i]) { /* should compare full path ? */ if (strcmp(name, patpath[i])) continue; } for (j = 0; j < 11; j++) { /* compare file name */ if (patfile[i][j] != buf[j] && patfile[i][j] != '?') break; } if (j == 11) { /* if matched */ patcnt[i]++; retcode = SUCCS; } } return retcode; } /*}}} */ /*{{{ ratio: ratio * 1000*/ /******************************* ratio * 1000 *******************************/ uint ratio(ulong a, ulong b) { int i; if (!b) return 0; /* if diviser == 0 */ for (i = 0; i < 3 && a < 0x19999999L; i++) { a *= 10; /* while not overflow */ } /* upto 1000 times */ for (; i < 3; i++) { /* the case of overflow */ b /= 10; } a += b / 2; /* for round up */ return (uint)(a / b); /* return (a * 1000 / b) */ } /*}}} */ /*{{{ cmpname: compare names*/ /******************************* compare names *******************************/ int cmpname(uchar *f0, uchar *f1, uchar *p0, uchar *p1) { int c; c = strcmp(f0, f1); /* compare only file names */ if (c == 0) { c = (int)(strlen(p0) - strlen(p1)); /* compare lengths of path names */ if (c == 0) { c = strcmp(p0, p1); /* compare path names */ } } return c; } /*}}} */ /*{{{ regfile: regist file names*/ /******************************* regist file names *******************************/ int regfile(uchar *p, uchar *q, uchar *f, int attrib) /* p: full path name including base directory q: directory name to be registed f: file name */ { uchar path[MAXPATH]; struct filebuf far *f0; struct filebuf far *f1; uchar *s; int c,size; if (flg_arc) if ((attrib & 0x20) == 0) return 0; if (strstr(f, "LHARC.)1(") || strstr(f, "LHARC.)2(")) return 0; /* temporary file ? */ stpcpy(stpcpy(path, q), f); stpcpy(s = stpcpy(fb1.dir, p), f); fb1.fpos = s - (uchar *)&fb1; fb1.cpos = flg_x ? (q - p) + (fb1.dir - (uchar *)&fb1) : fb1.fpos; if (fbuf == NULL) { /* for first entry */ fbfiles=0; /* >> Number of files matched << */ #ifndef __TOS__ if (allocmem(fbsize = 0x100, &seg) != -1) error(MEMOVRERR, NULL); fbuf = (uchar far *)fbnxt = MK_FP(seg, 0); fbleft = 0x100; #else /* >> get all the memory. fbmax holds the number of bytes available << */ fbsize=sizeof(struct filebuf) * MAXNUMFILES; fbmax= (long) Malloc(-1); fbuf = fbnxt = Malloc(fbmax); if (fbuf == NULL) error(MEMOVRERR, NULL); fblft = fbmax; #endif *(long far *)fbuf = 0; fbnxt += 4; } f0 = (struct filebuf far *)fbuf; do { /* search position in which should be inserted*/ f1 = f0; if ((f0 = f0 -> next) == NULL) break; fb0 = *f0; c = cmpname((uchar *)&fb0 + fb0.fpos, (uchar *)&fb1 + fb1.fpos, (uchar *)&fb0 + fb0.cpos, (uchar *)&fb1 + fb1.cpos); } while (c < 0); if (f0 && c == 0 && strcmp(fb0.dir, fb1.dir)) { error(DUPFNERR, (uchar *)&fb1 + fb1.cpos); } /* same registing names of different files */ if (f0 == NULL || c) { /* do regist */ size = (int)(strlen(fb1.dir) + (fb1.dir - (uchar *)&fb1)) + 1; #ifndef __TOS__ if (fblft < sizeof(struct filebuf)) { /* if buffer is short */ if (setblock(seg, fbsize += 0x100) != -1) error(TOOMANYERR, NULL); fblft += 0x100; } #else size += size & 1; /* size must be even to avoid address error! */ if (fblft < sizeof (struct filebuf)) error(TOOMANYERR, NULL); #endif fb1.next = f0; f0 = (struct filebuf far *)fbnxt; f1 -> next = f0; *f0 = fb1; fblft -= size; fbnxt += size; fbfiles++; /* >> Count files << */ } return 1; } /*}}} */ /*{{{ travel: recursive collection of files*/ /******************************* recursive collection of files *******************************/ int travel(uchar *p, uchar *q, uchar *f) { struct ffblk ffb; static uchar buf[12]; uchar *r, *s; int done, cnt, j; cnt = 0; if (flg_r == 1 || strrchr(q, '\\') == q + strlen(q) - 1) { stpcpy(s = q + strlen(q), "*.*"); } done = findfirst(p, &ffb, attr); /* search the first file */ s = backpath(q); while (! done) { if (ffb.ff_attrib & 0x10) { /* if this is a sub-directory */ if (ffb.ff_name[0] != '.') { r = stpcpy(stpcpy(s, ffb.ff_name), "\\"); if (r - p > MAXPATH) error(TOOLONGERR, p); cnt += travel(p, q, f); /* search recursively */ *s = '\0'; } } else /* if this is a file */ if (flg_r == 2) { /* in /r2 mode */ cnt += regfile(p, q, ffb.ff_name,ffb.ff_attrib); /* regist name */ } else { /* in /r+ mode */ stpcpy(s, ffb.ff_name); extfn(s, buf); for (j = 0; j < 11; j++) { /* test file names */ if (f[j] != buf[j] && f[j] != '?') break; } if (j == 11) { cnt += regfile(p, q, ffb.ff_name,ffb.ff_attrib); /* if match, regist */ } } done = findnext(&ffb); } return cnt; /* number of registed files */ } /*}}} */ /*{{{ findfile: non-recursive collection of files*/ /********************************** non-recursive collection of files **********************************/ int findfile(uchar *p, uchar *q) { struct ffblk ffb; int done, cnt; cnt = 0; done = findfirst(p, &ffb, attr); backpath(p); while (! done) { cnt += regfile(p, q, ffb.ff_name,ffb.ff_attrib); done = findnext(&ffb); } return cnt; } /*}}} */ /*{{{ mklilst: make file list to append*/ /******************************* make file lists to append *******************************/ void mklist(void) { uchar path[MAXPATH], *p, *q, *r; int i, cnt; Nfile = 0; if (flg_a) { /* set attributes for search */ attr = 0x07; } else { attr = 0; } if (flg_r) { attr |= 0x10; } for (i = 0; i < patno; i++) { p = patpath[i]; q = path; if (*p && p[1] == ':') { /* if path name includes drive */ q = stpcpy(path, p); /* ignore base directory */ r = path + 2; /* don't regist drive name */ } else { q = stpcpy(r = stpcpy(path, basedir), p); } if (flg_r == 1) { /* /r+ mode */ cnt = travel(path, r, patfile[i]); } else if (flg_r > 1) { /* /r2 mode */ packfn(q, patfile[i]); cnt = travel(path, r, NULL); } else { /* /r- mode */ packfn(q, patfile[i]); cnt = findfile(path, r); } Nfile += patcnt[i] = cnt; } #ifdef __TOS__ /* >> After registering all files, free the unused memory << */ Mshrink(0,fbuf,fbmax-fblft+5); if (flg_d == 0) printf("Files matched: %ld\n",fbfiles); #endif } /*}}} */ /*{{{ mkhdr: make file header*/ /******************************* make file header *******************************/ uchar *mkhdr(struct filebuf far *f, struct LzHead *h) { int attr; fb0 = *f; attr = getfattr(fb0.dir); file3 = e_fopen(fb0.dir, "rb", RDERR); sethdr((uchar *)&fb0 + fb0.cpos, attr, h); return (uchar *)&fb0 + fb0.fpos; /* position of file name */ } extern uint blkcnt; uint curcnt; uint nxtcnt; /*}}} */ /*{{{ blkdisp: calculate and display*/ /******************************* calculate and display for indicator *******************************/ void blkdisp(long l, char *s) { uint i; if (flg_n == 0) { blocksize=4096; printf("\n %s : ", s); blkcnt = (uint)((l + 4095) / 4096); if (blkcnt > MAXBLK) { blkcnt = MAXBLK; blocksize= l / MAXBLK; } i = blkcnt; while (i-- > 0) { putchar('.'); } printf("\r %s : ", s); curcnt = nxtcnt = 0; } else { curcnt = 0; nxtcnt = -1; } } /*}}} */ /*{{{ curback: let cursor back after displaying indicator*/ /******************************* let cursor back after displaying indicator *******************************/ void curback(void) { if (flg_n == 0) { printf("\r "); } } /*}}} */ /*{{{ MKinputbuf: make buffers for reading*/ /* Try to read the complete file. If the position is odd, begin reading at */ /* an even position and dicard one byte */ void MKinputbuf(long filesize) { long bufsize; long Pos; bufsize=(long)Malloc(-1)-50000; if (bufsize < 0) bufsize=8192; bufsize=min(filesize,bufsize)+1024; TheInputBuf=(char *) Malloc(bufsize+2); if (TheInputBuf < 0) error(MEMOVRERR,NULL); if (TheInputBuf>0) { if ((bufsize & 1) == 1) bufsize--; /* Make bufsize even */ if ((ftell(infile) & 1) == 1) { /* Odd position */ fseek(infile,ftell(infile)-1,0); /* go to even pos. */ setvbuf(infile,TheInputBuf, _IOFBF, bufsize); /* set buffer */ getc(infile); /* fill buffer, dicard char */ } else { fseek(infile,ftell(infile),0); /* even position is ok */ setvbuf(infile,TheInputBuf, _IOFBF, bufsize); } FileFits=1; /* signal file fits into mem */ } else FileFits=0; } /*}}} */ /*{{{ mkoutboutb Make buffers for writing*/ void MKoutputbuf( void ) { long bufsize; char *start,ende; bufsize=(long)Malloc(-1)-20000; TheOutputBuf=Malloc(bufsize); fseek(outfile,ftell(outfile),0); if (TheOutputBuf>0) { setvbuf(outfile,TheOutputBuf,_IOFBF,bufsize); } else { setvbuf(outfile,buf3,_IOFBF,BUFFERSIZ); } } /*}}} */ /*{{{ freeze: freeze a file*/ /******************************* freeze a file *******************************/ void freeze(uchar *p) { char *hp; char iname[128]; if (FTimeToULong (arcstamp) < FTimeToULong (Hdr2.Ftime)) arcstamp = Hdr2.Ftime; strcpy(iname,p); freezing=1; if (flg_d == 0) printf("%s ", p); if (flg_e) { /* Enter comment THQ */ printf("\n"); printf(M_COMMENT); gets(comment); } if (method!=5) blkdisp(Hdr2.OrgSiz, "Freezing "); else blkdisp(Hdr2.OrgSiz/2, "Freezing "); wthdr(&Hdr2); if (method == 5) init_encode5(); setvbuf(file3, buf3, _IOFBF, BUFFERSIZ); infile = file3; outfile = file2; MKinputbuf(Hdr2.OrgSiz); infname = p; textsize = Hdr2.OrgSiz; crc = 0; codesize=0; if (flg_u) codesize = Hdr2.OrgSiz + 1; else { if (method==0) EncodeOld(); if (method==1) Encode(); if (method==5) codesize=encode5(Hdr2.OrgSiz); } fflush(outfile); fseek(infile,ftell(infile),0); setvbuf(file3,buf3,_IOFBF,BUFFERSIZ); fseek(file2,0,SEEK_END); Mfree(TheInputBuf); if (flg_backup) Fattrib(iname,1,Fattrib(iname,0,0) & 0xff-0x20); remkhdr(&Hdr2); curback(); if (flg_d == 0) printf("Frozen(%3d%%) \n", ratio(Hdr2.PacSiz, Hdr2.OrgSiz) / 10); comment[0] = 0; freezing=0; } /*}}} */ /*{{{ copyold: copy file from old archiv*/ /******************************* Copy a file from old archive *******************************/ void copyold(void) { if (FTimeToULong (arcstamp) < FTimeToULong (Hdr1.Ftime)) arcstamp = Hdr1.Ftime; wthdr(&Hdr1); /* copy from old archive */ copyfile(file1, file2, Hdr1.PacSiz); } /*}}} */ /*{{{ execappend: execute one of a, u, m commands*/ /******************************* execute one of a, u, m commands *******************************/ int execappend(void) { struct filebuf far *f0; uchar *p, *q; int c, d; int cnt = 0; q = file1 ? gethdr(file1, &Hdr1) : NULL; /* read header from old arc */ if ((f0 = ((struct filebuf far *)fbuf) -> next) != NULL) { p = mkhdr(f0, &Hdr2); /* make header from the file list */ } while (1) { if (f0 == NULL) { d = 1; if (q == NULL) break; } else if (q == NULL) { d = -1; } else { d = cmpname(p, q, (uchar *)&fb0 + fb0.cpos, filename); } c = d; if (c == 0) { if (flg_c || FTimeToULong (Hdr1.Ftime) < FTimeToULong (Hdr2.Ftime)) { c = -1; } else { c = 1; } } if (c < 0) { /* freeze a new file */ if (d == 0) { fseek(file1, Hdr1.PacSiz, SEEK_CUR); q = gethdr(file1, &Hdr1); /* skip a file in old */ } /* archive */ freeze(fb0.dir); fclose(file3); cnt++; if ((f0 = fb0.next) != NULL) { /* make header of the next */ p = mkhdr(f0, &Hdr2); /* file in file list */ } } else { /* copy a file from old archive */ if (d == 0) { fclose(file3); if ((f0 = fb0.next) != NULL) { /* make header of the next */ p = mkhdr(f0, &Hdr2); /* file in file list */ } } copyold(); q = gethdr(file1, &Hdr1); /* get the next header */ } /* in old archive */ } return cnt; } /*}}} */ /*{{{ delfile: delete files after execution of updating in 'm' command*/ /******************************* delete files after execution of updating in 'm' command *******************************/ void delfile(void) { struct filebuf far *f0; struct filebuf fb0; f0 = (struct filebuf far *)fbuf; while ((f0 = f0 -> next) != NULL) { fb0 = *f0; unlink(fb0.dir); }; } /*}}} */ /*{{{ openarc1: open an old archiv*/ /******************************* open an old archive *******************************/ void openarc1(void) { uchar *p, *q; file1 = e_fopen(infname = arcname, "rb", NOARCERR); /* >> Because some SFX-Versions for the ST have a header bigger 2048 Bytes 4096 bytes are read here << */ q = buf2 - 5 + fread(buf2, 1, 4096, file1); for (p = buf2; p < q; p++) { if (p[0] == '-' && p[4] == '-') if (p[1] == 'l' || p[1] == 'a') break; } if (p >= q) { error(NOFILEERR, arcname); } fseek(file1, (long)(p - buf2 - 2), SEEK_SET); } /*}}} */ /*{{{ openrwarc1: open an archiv in rd/wt for testing read-only*/ /******************************* open an archive in rd/wt for testing read-only *******************************/ void openrwarc1(void) { file1 = e_fopen(arcname, "r+b", NOARCERR); } /*}}} */ /*{{{ openbackup1 close an old archiv & rename to temporary*/ /******************************* close an old archive & rename to temporary *******************************/ static void openbackup1(void) { fclose(file1); stpcpy(backpath(strcpy(backup1, arcname)), "lharc.)1("); e_rename(arcname, backup1); file1 = fopen(infname = backup1, "rb"); } /*}}} */ /*{{{ openbackup2 open a temporary file for a new archiv*/ /******************************* open a temporary file for a new archive *******************************/ static void openbackup2(void) { if (flg_w) { stpcpy(stpcpy(backup2, workdir), "lharc.)2("); } else { strcat(backpath(strcpy(backup2, arcname)), "lharc.)2("); } file2 = e_fopen(outfname = backup2, "w+b", MKTMPERR); setvbuf(file2, buf2, _IOFBF, BUFFERSIZ); } /*}}} */ /*{{{ stclosearc: set time & close an archive*/ /******************************* set time & close an archive *******************************/ void stclosearc(FILE *f) { if (flg_t) { fflush(f); setftime(fileno(f), &arcstamp); } fclose(f); } /*}}} */ /*{{{ endofupdate end-of-job process in making new archive*/ /******************************* end-of-job process in making new archive *******************************/ void endofupdate(int cnt) { if (file1) stclosearc(file1); tstpat(); if (cnt) { /* if any files are manipulated */ if (file1) if (unlink(backup1)) /* delete an old archive */ printf("debug : Failed in deleting '%s'.", backup1); if ((arcpos0 = ftell(file2)) != 0) { if (putc(0, file2) == EOF) error(WTERR, backup2); if (flg_w) { /* if work directory is assigned */ rewind(file2); infname = backup2; copying = 1; /* copy temporary to new archive */ file1 = e_fopen(outfname = arcname, "wb", MKFILEERR); if (flg_d == 0) printf("Copying Temp to Archive ..."); copyfile(file2, file1, arcpos0 + 1); if (flg_d == 0) printf("\n"); copying = 0; stclosearc(file1); fclose(file2); unlink(backup2); } else { stclosearc(file2); /* else rename temporary to archive */ rename(backup2, arcname); } } else { fclose(file2); unlink(backup2); } } else { /* if no change was made in archive */ fclose(file2); unlink(backup2); rename(backup1, arcname); /* restore the old archive */ } } /*}}} */ /*{{{ append: a,u,m command*/ /******************************* a, u, m command *******************************/ void append(void) { int cnt; file1 = fopen(arcname, "r+b"); if (file1) { openbackup1(); /* if archive presents, rename to temp */ } else { if (errno == EACCES) error(RDONLY, arcname); /* read-only error */ } mklist(); /* make a file list */ if (Nfile == 0) { error(NOFILEERR, NULL); } if (file1) { message("Updating archive", arcname); } else { message("Creating archive", arcname); } openbackup2(); /* open temporary for new archive */ cnt = execappend(); /* execute updating archive */ endofupdate(cnt); /* end-of-job process */ if (cmd == 'M') delfile(); /* if 'm' command, delete files */ #ifndef __TOS__ freemem(seg); #else free (fbuf); #endif } /*}}} */ /*{{{ open_afxb: open backup-file for afx*/ void open_afxbackup(char *s) { char *p,*d,c; p=backup2; d=p; *backup2='\0'; while ( (c=*s++) != 0) { if ((c=='\\') || (c==':')) d=p+1; *p++=c; } strcpy(d,"__temp__.lzs"); file2=e_fopen(outfname=backup2,"w+b",MKTMPERR); setvbuf(file2,buf2,_IOFBF,BUFFERSIZ); } /*}}} */ /*{{{ pack_aafx: subprocess in packing afx*/ void pack_aafx(void) { struct filebuf far *f0; uchar *p, *q; int c, d; int cnt = 0; if ((f0 = ((struct filebuf far *)fbuf) -> next) != NULL) { p = mkhdr(f0, &Hdr2); /* make header from the file list */ } while (f0 != NULL) { switch(test_afx(fb0.dir)) { case 0: open_afxbackup(fb0.dir); freeze(fb0.dir); fclose(file3); fclose(file2); if (flg_unpacked==0) { unlink(fb0.dir); if (rename(backup2,fb0.dir) != 0) error(RENAMEERR, fb0.dir); } else unlink(backup2); break; case 1: printf("%s\n already in AFX-format\n",fb0.dir); break; case 2: printf("%s\n already in LHarc-format\n",fb0.dir); break; case 3: printf("%s\n Program-file\n",fb0.dir); break; } if (file2 != NULL) fclose(file2); if (file3 != NULL) fclose(file3); cnt++; if ((f0 = fb0.next) != NULL) { /* make header of the next */ p = mkhdr(f0, &Hdr2); /* file in file list */ } } return cnt; } /*}}} */ /*{{{ pack_afx: pack-afx*/ void pack_afx(void) { int cnt; char *p; mklist(); /* make a file list */ if (Nfile == 0) { error(NOFILEERR, NULL); } FlgMethod=0; pack_aafx(); #ifndef __TOS__ freemem(seg); #else free (fbuf); #endif } /*}}} */ /*{{{ freshen: f command*/ /******************************* f command *******************************/ void freshen(void) { uchar path[MAXPATH]; int c; int cnt = 0; openrwarc1(); /* open an archive */ message("Freshening archive", arcname); openbackup1(); /* rename the archive to temp. */ openbackup2(); /* open temp. for a new archive */ while (gethdr(file1, &Hdr1)) { c = 0; if (matchpat(filename)) { stpcpy(stpcpy(path, basedir), filename); if ((file3 = fopen(path, "rb")) != NULL) { sethdr(filename, getfattr(path), &Hdr2); if (flg_c || FTimeToULong (Hdr1.Ftime) < FTimeToULong (Hdr2.Ftime)) { c = 1; /* found the file to be updated */ } } } if (c) { freeze(path); /* do updating */ cnt++; fseek(file1, Hdr1.PacSiz, SEEK_CUR); } else { copyold(); } if (file3) fclose(file3); } endofupdate(cnt); /* end-of-job process */ } /*}}} */ /*{{{ tstdir: test the file which should be melted*/ /******************************* test the file which should be melted *******************************/ int tstdir(uchar *name) { uchar path[MAXPATH], *p, yn; struct ffblk ffb; Again: p = name; if (*p && p[1] == ':') /* skip a drive name */ p += 2; if (*p == '\\') /* skip a root mark('\') */ p++; yn = flg_m ? 'Y' : 'N'; while ((p = strchr(p, '\\')) != NULL) { /* skip to next '\' */ memcpy(path, name, p - name); path[p - name] = '\0'; if (findfirst(path, &ffb, 0x1f)) { /* Is there this directory? */ if (yn == 'N') { printf("'%s' : %s", name, M_MKDIR); yn = getyn(); } if (yn == 'N') { return FAULT; } else { if (strcmp(path,".") != 0) if (mkdir(path)) { /* make directory */ error(MKDIRERR, path); } } } else { if ((ffb.ff_attrib & 0x10) == 0) { error(MKDIRERR, path); /* if the name isn't directory */ } } p++; } if (! findfirst(name, &ffb, 0x1f)) { /* if a file has the same name */ if (ffb.ff_attrib & 0x01 && ffb.ff_attrib != Hdr1.Attr) { /* if the file is read-only, */ /* attributes must match */ fprintf(stderr, "'%s' %s\n", M_RDONLY); return FAULT; } yn = 'Y'; #ifdef __TOS__ if (flg_c == 0 && UnixFile == 0) { #else if (flg_c == 0) { #endif if (((ulong)ffb.ff_fdate << 16) + (ulong)ffb.ff_ftime < FTimeToULong (Hdr1.Ftime)) { /* compare time stamps */ yn = 'Y'; } else { printf("Skipped : '%s' : New or same file exists.\n", name); yn = 'N'; } } if (yn == 'Y' && flg_m == 0) { fprintf(stderr, "'%s' : %s", name, M_OVERWT); yn = getynr(); /* may overwrite? */ if (yn == 'R') { printf(M_ENTERNEW); scanf("%s",name); goto Again; } } if (yn == 'N') { return FAULT; } setfattr(name, 0x20); /* reset attributes */ } return SUCCS; } /*}}} */ /*{{{ tstID: read header-ID (method)*/ /******************************* read header-ID (method) *******************************/ int tstID(uchar *h) { int m; static uchar IDpat[6][6] = {"-lz4-", "-lz5-", "-lh0-", "-lh1-","-lh5-","-afx-"}; /* 0 1 2 3 4 5 */ m = (int)((sizeof IDpat) / (sizeof IDpat [0])); while (m >= 0 && memcmp(h, IDpat[m], 5)) { m--; } if (m==5) m=1; return m; } /*}}} */ /*{{{ Dos1File: Dateiname nach 8+3 Zeichen wandeln*/ #ifdef __TOS__ char LegalChar(char c) { if (c <= 32) return 0; if (c == '*' || c == '?') return 0; return 1; } char *Dos1File(char *s, char *d) /* Ein Dateiname ohne Ordner wird berprft */ { char c,*t; int p; int l; int i; int j; int k; int m; /* Suche von hinten den letzten Punkt. i ist die Position des letzten Zeichens vor der Extension */ l = strlen(s); for (i=l; i>=0;i--) if (s[i] == '.') break; m = i-1; if (i<=0) m = l; /* Kopiere maximal 8 Zeichen des Dateinamens. šberspringe Punkte und illegale Zeichen */ j = 0; k = 0; t=s; for (j = 0; j<=7; j++) { c = *t++; if (i>0) if (k++>i) break; if (c=='\0') break; if (j > m) break; if (c != '.' && c > 32 && c != ':') { if (LegalChar(c)) *d++ = c;} else j--; } if (i>0) { *d++ = '.'; i++; for (j=0; j<=2; j++) { c=s[i++]; if (c==0) break; if (c > 32 && c != ':') if (LegalChar(c)) *d++ = c; } } *d='\0'; return d; } /*}}} */ /*{{{ DosFile: File mit Ordnername nach 8+3 wandeln*/ /* Auftrennen des Files in einzelne Ordner (falls n”tig) und anpassung jedes Ordners an 8+3 Zeichen */ void DosFile(char *s) { char file[128], *f=file; char dest[128], *d=dest; char c,*s1=s; *d=0; while (( c= *s++) != 0) { if (c=='/') c = '\\'; if (c==':' || c == '\\') { *d=0; f=Dos1File(dest,f); *f++=c; *f='\0'; d=dest; } else *d++=c; } *d=0; f=Dos1File(dest,f); strcpy(s1,file); } #endif /*}}} */ /*{{{ extract: a,x,p,t command*/ /******************************* e, x, p, t command *******************************/ int extract(void) { uchar *p, *q; int m; int cnt = 0; openarc1(); /* open an archive */ setvbuf(file1, buf2, _IOFBF, 1024); message("Extract from", arcname); if (flg_v == 1) fprintf(file3, "Extract from '%s'\n", arcname); UseExthdr=1; while ((p = gethdr(file1, &Hdr1)) != NULL) { if (matchpat(filename)) { arcpos0 = ftell(file1) + Hdr1.PacSiz; infile=file1; MKinputbuf(Hdr1.PacSiz); if (cmd == 'E') { /* if extract command, */ if (flg_x) { /* get the destination path name */ p = stpcpy(pathname, basedir); if (filename[0] == '\\') { p = pathname; if (*p && p[1] == ':') { p += 2; } } stpcpy(p, filename); } else { stpcpy(stpcpy(pathname, basedir), p); } } slash2yen(pathname); strcpy(dospathname,pathname); if (pathname[0] == 0) #ifdef __TOS__ DosFile(dospathname); UnixFile = strcmp(dospathname,pathname); if (dospathname[strlen(dospathname)-1]=='\\') goto weiter; #endif m=tstID(Hdr1.HeadID); if (cmd != 'E' || tstdir(dospathname)) { if ((m = tstID(Hdr1.HeadID)) < 0) { printf("Skipped : '%s' : Unknown method\n", pathname); } else { cnt++; p = "Melting "; q = "Melted "; switch (cmd) { case 'X': case 'E': if (flg_d == 0) printf("%s ", pathname); file3 = fopen(outfname = dospathname, "wb"); break; case 'T': if (flg_d == 0) printf("%s ", filename); #ifndef __TOS__ file3 = fopen ("nul", "wb"); #else file3 = NULL; /* no NUL-Device supported! */ #endif p = "Testing "; q = "Tested "; break; case 'P': if (flg_v != 2) fprintf(file3, "<<< %s >>>\n", filename); if (flg_v) printf("%s ", filename); fflush(file3); setmode(fileno(file3), O_BINARY); break; } #ifndef __TOS__ if ((ioctl(fileno(file3), 0) & 0x82) == 0x82) { flg_n = 1; /* Console output ? */ } else { setvbuf(file3, buf3, _IOFBF, BUFFERSIZ); } #else if (file3 != NULL) { if (file3 == stdout) { flg_n = 1; /* Console output ? */ } else { outfile=file3; /* MKoutputbuf(); */ /* setvbuf(file3, buf3, _IOFBF, BUFFERSIZ); */ } } else OutBuf=NULL; #endif if (m != 4) blkdisp(Hdr1.OrgSiz, p); else blkdisp(Hdr1.OrgSiz/2,p); outfile = file3; infile = file1; textsize = Hdr1.OrgSiz; codesize = Hdr1.PacSiz; crc = 0; if (m == 3) { Decode(); /* extract LHarc's file */ } else if (m == 1) { DecodeOld(); /* extract LArc's file */ } else if (m == 4) { decode_lh5(Hdr1.OrgSiz,Hdr1.PacSiz); } else { crcflg = 1; copyfile(infile, outfile, Hdr1.OrgSiz); crcflg = 0; /* only stored file */ } fflush(file1); fseek(file1,ftell(file1),0); setvbuf(file1, buf2, _IOFBF, 1024); Mfree(TheInputBuf); if (file3 != NULL) { Mfree(TheOutputBuf); } if (file3 != NULL && fflush(file3)) { error(WTERR, outfname); } if (pathname[0] != 0) if (cmd == 'E') { setftime(fileno(file3), &Hdr1.Ftime); fclose(file3); setfattr(pathname, Hdr1.Attr); file3 = NULL; } else if (cmd == 'T') { #ifndef __TOS__ fclose(file3); #endif } else { setmode(fileno(file3), O_TEXT); if (flg_v != 2) fprintf(file3, "\n"); } curback(); if (getcrc (&Hdr1) != crc) { errorlevel = 1; /* test CRC */ printf("CRC err\n"); if (flg_m == 0) getchar(); } else if (cmd != 'P' || flg_v != 0) { if (flg_d == 0) printf("%s\n", q); } } } weiter: fseek(file1, arcpos0, SEEK_SET); /* move pointer to next file */ } else { fseek(file1, Hdr1.PacSiz, SEEK_CUR); } } fclose(file1); file1 = NULL; return cnt; } /*}}} */ /*{{{ delete: d command*/ /******************************* d command *******************************/ void delete(void) { int cnt = 0; openrwarc1(); /* open archive */ if (patno == 0) { error(NOFNERR, NULL); } message("Updating archive", arcname); openbackup1(); /* rename to temporary name */ openbackup2(); /* open another temporary file */ while (gethdr(file1, &Hdr1)) { if (matchpat(filename)) { message("Deleting", filename); cnt++; fseek(file1, Hdr1.PacSiz, SEEK_CUR); /* skip file */ } else { copyold(); } } endofupdate(cnt); /* end-of-job process */ } /*}}} */ /*{{{ self: s command*/ /******************************* s command *******************************/ void self(void) { #ifndef __TOS__ uchar *p, /* *q,*/ buf[12], yn; int flg, i; long l, m, n; void sfx(void), sfx2(void); openarc1(); /* open archive */ message("Making Sfx from archive", arcname); stpcpy(stpcpy(backup2, workdir), "lharc.)2("); file2 = e_fopen(outfname = backup2, "w+b", MKTMPERR); /* open temporary */ while (gethdr(file1, &Hdr1)) { flg = 0; if (matchpat(filename)) { if (flg_d == 0) printf("Extracting '%s' ", filename); if (tstID(Hdr1.HeadID) < 2) { printf("(not supported) skipped."); } else { if (flg_x == 0 && (p = strrchr(filename, '\\')) != NULL) { p++; /* delete directory part */ Hdr1.Fname[0] = strlen(p); i = p - filename; Hdr1.HeadSiz -= i; memcpy(Hdr1.Fname + 1, Hdr1.Fname + 1 + i, Hdr1.Fname[0] + 2); Hdr1.HeadChk = mksum(&Hdr1); /* recalculate sum */ } wthdr(&Hdr1); copyfile(file1, file2, Hdr1.PacSiz); flg = 1; } printf("\n"); } if (flg == 0) { fseek(file1, Hdr1.PacSiz, SEEK_CUR); } } fclose(file1); if (putc(0, file2) == EOF) /* end-mark of archive */ error(WTERR, backup2); if ((l = ftell(file2)) <= 1) { goto self9; } if (flg_x == 0) { m = (uchar*)sfx2 - (uchar*)sfx; /* size of sfx routine */ } else { m = (uchar*)usage - (uchar*)sfx2; } n = l + m; /* total size of sfx file */ rewind(file2); infname = backup2; extfn(arcname, buf); /* make the name of sfx */ p = stpcpy(pathname, basedir); strcpy(&buf[8], "COM"); if (flg_x || n > 0xfe80ul) { strcpy(&buf[8], "EXE"); } packfn(p, buf); if ((getfattr(pathname) & 0x8000) == 0) { /* if the same name exists */ fprintf(stderr, "'%s' : %s", pathname, M_OVERWT); yn = getyn(); /* may overwrite */ if (yn == 'N') { goto self9; } } file3 = e_fopen(outfname = pathname, "wb", MKFILEERR); if (buf[8] == 'E') { /* if .EXE */ if (flg_x) { n = m; } n += 0x20; ExeHdr.page = (n + 511) / 512; ExeHdr.byte = n % 512; ExeHdr.minalloc = (flg_x ? 0x66c0 : 0x2560) / 0x10; if (fwrite(&ExeHdr, 0x20, 1, file3) == 0) error(WTERR, pathname); } movedata(_CS, (flg_x ? (unsigned)sfx2 : (unsigned)sfx), _DS, (unsigned)buf2, m); if (flg_x) { memcpy(buf2 + 0x34, p, strlen(p)); /* large ver. */ } else { *((uint *)buf2 + 1) = (l + m + 0x10f) / 0x10; /* small ver. */ } if (fwrite(buf2, m, 1, file3) == 0) /* write sfx routine */ error(WTERR, pathname); if (flg_x) { if (fwrite(keyword, strlen(keyword) + 1, 1, file3) == 0) error(WTERR, pathname); } copyfile(file2, file3, l); /* write an archive */ printf("\nCreated : '%s'\n", pathname); fclose(file3); self9: fclose(file2); unlink(backup2); #else fprintf (stderr, "Self-Extracting-Files: NOT YET IMPLEMENTED!!!\7\n"); errorlevel = 1; longjmp (exit_jmp, 1); /* NOT YET IMPLEMENTED !!! */ #endif } /*}}} */ /*{{{ sysid*/ char *sysid( void ) { char *s; if (flg_k == 0) { switch(SystemId) { case 'M' : s="MSDOS "; break; case '2' : s="OS/2 "; break; case '9' : s="OS9 "; break; case 'K' : s="OS/68K"; break; case '3' : s="OS/386"; break; case 'H' : s="HUMAN "; break; case 'U' : s="UNIX "; break; case 'C' : s="CP/M "; break; case 'm' : s="Mac "; break; case 'R' : s="Runser"; break; case 'A' : s="Atari "; break; default : s=" "; break; } } else s=" "; return s; } /*}}} */ /*{{{ list: l,v command*/ /******************************* l, v command *******************************/ void list(void) { uint rt; uchar buf[79], *p,*b; static uchar attr[7] = "ohs--a"; int i, j, k, Fno; ulong Osize, Psize; Osize = Psize = 0L; Fno = 0; openarc1(); /* open archive */ UseExthdr=1; #ifdef German printf("Inhalt von : '%s'\n\n", arcname); printf(" Name Original Gepackt Rate" " Datum Zeit Attr Typ CRC\n"); #else printf("Listing of archive : '%s'\n\n", arcname); printf(" Name Original Packed Ratio" " Date Time Attr Type CRC\n"); #endif printf("-------------- -------- -------- ------" " -------- -------- ---- ----- ----\n"); while ((p = gethdr(file1, &Hdr1)) != NULL) { if (matchpat(filename)) { rt = ratio(Hdr1.PacSiz, Hdr1.OrgSiz); sprintf(buf, " %10lu%10lu %3d.%1d%% " "%2d-%02d-%02d %2d:%02d:%02d ---w %04X\n", Hdr1.OrgSiz, Hdr1.PacSiz, rt / 10, rt % 10, (Hdr1.Ftime.ft_year + 80) % 100, Hdr1.Ftime.ft_month, Hdr1.Ftime.ft_day, Hdr1.Ftime.ft_hour, Hdr1.Ftime.ft_min, Hdr1.Ftime.ft_tsec * 2, getcrc (&Hdr1)); memcpy(&buf[65], Hdr1.HeadID, 5); for (i = 0, j = 1; i < 6; i++, j <<= 1) { /* attributes */ if (Hdr1.Attr & j) { k = attr[i]; if (i <= 2) { buf[63 - i] = k; } else { buf[60] = k; } } } if (flg_x) { printf("%s\n", filename); /* display in 2 lines */ p=sysid(); b = buf; while (*p != 0) *b++=*p++; if (comment[0] != 0) printf("%s\n",comment); } else { if (p != filename) { /* display in one line */ *buf = '+'; } memcpy(&buf[2], p, strlen(p)); } printf("%s", buf); Fno ++; Osize += Hdr1.OrgSiz; Psize += Hdr1.PacSiz; } if (fseek(file1, Hdr1.PacSiz, 1)) break; } if (Fno) { printf("-------------- -------- -------- ------" " -------- --------\n"); rt = ratio(Psize, Osize); getftime(fileno(file1), &arcstamp); printf(" %3d files %10lu%10lu %3d.%1d%% " "%2d-%02d-%02d %2d:%02d:%02d\n", Fno, Osize, Psize, rt / 10, rt % 10, (arcstamp.ft_year + 80) % 100, arcstamp.ft_month, arcstamp.ft_day, arcstamp.ft_hour, arcstamp.ft_min, arcstamp.ft_tsec * 2); } else { printf(" no file\n"); } fclose(file1); } /*}}} */ /*{{{ getsw: get switches*/ /******************************* get switches *******************************/ void getsw(uchar *p) { #ifndef __TOS__ static uchar flg[] = "rpxmacntvwyb"; static uchar *flgpos[] = {&flg_r, &flg_p, &flg_x, &flg_m, &flg_a, &flg_c, &flg_n, &flg_t, &flg_v, &flg_w}; #else static uchar flg[] = "rpxmacntvwhybludoske5"; static uchar *flgpos[] = {&flg_r, &flg_p, &flg_x, &flg_m, &flg_a, &flg_c, &flg_n, &flg_t, &flg_v, &flg_w, &flg_h}; #endif int i; uchar s; uchar *q; while ((s = *p++) != 0) { q = strchr(flg, s); /* search switch */ if (q) { i = (int)(q - flg); if (*p == '+') { *flgpos[i] = 1; p++; } else if (*p == '-') { *flgpos[i] = 0; p++; } else if (*p == '2') { *flgpos[i] = 2; p++; } else if (s == 'v' && *p) { if (flg_v == 0) /* process of '/vSTRING' */ flg_v = 1; pager = p; p = ""; } else if (s == 'y') flg_arc = 1; else if (s == 'k') { flg_k=1; elen=0; } else if (s == 'b') { flg_arc=1; flg_backup=1; } else if (s == '5') flg_5=1; else if (s == 'l') FlgMethod=0; else if (s == 'o') FlgMethod=1; else if (s == 's') flg_s=1; else if (s == 'u') flg_u = 1; else if (s == 'e') flg_e = 1; else if (s == 'w' && *p) { flg_w = 1; /* process of '/wSTRING' */ wdir = p; p = ""; } else if (s == 'd') flg_n = flg_d = 1; else { if (*flgpos[i]) { /* flip-flop */ *flgpos[i] = 0; } else { *flgpos[i] = 1; } } if (s == 'r' && flg_r > 0) { flg_x = 1; } #ifndef __TOS__ } else if (s == 'k') { keyword = p; p = ""; #endif } else { if (s == '?') usage(); error(INVSWERR, NULL); } } } /*}}} */ /*{{{ executecmd: execute command*/ /******************************* execute command *******************************/ void executecmd(void) { int cnt; switch (cmd) { case 'A': flg_c++; case 'U': case 'M': append(); break; case 'C': pack_afx(); break; case 'F': freshen(); break; case 'P': if (flg_v == 0) { file3 = stdout; goto common; } stpcpy(stpcpy(pathname, workdir), "LHARC.TMP"); /* view files */ file3 = e_fopen(outfname = pathname, "w", MKTMPERR); cnt = extract(); fclose(file3); if (cnt) /* if any files extracted */ #ifndef __TOS__ stpcpy(stpcpy(stpcpy(buf2, pager), " "), pathname); execute(buf2); /* execute by INT 0x2e */ #else { int retcode; exec (pager, pathname, "", &retcode); } #endif #if 0 spawnlp(P_WAIT, pager, pager, pathname, NULL); #endif unlink(pathname); break; case 'T': tstflg = 1; goto common; case 'X': case 'E': cmd = 'E'; common: flg_v = 0; extract(); break; case 'V': flg_x++; case 'L': list(); break; case 'D': delete(); break; case 'S': self(); break; } if (!flg_d) putchar('\n'); } /*}}} */ /*{{{ recoverbrk: handle userbreak*/ /******************************* handle userbreak *******************************/ #ifndef __TOS__ int cbrk; void recovercbrk(void) { setcbrk(cbrk); } #endif /*}}} */ /*{{{ OneNewFile:*/ void OneNewFile(char *p) { char *s; s = strchr(p,'\n'); if (s != NULL) *s='\0'; if (patno == 0 && basedir == NULL && (strrchr(p, '\\') == p + strlen(p) - 1 || p[strlen(p) - 1] == ':')) { basedir = p; /* get base (or home) directory */ } else if (patno >= MAX_PAT) { message("File table overflow. ignore", p); } else { patpath[patno] = p; extfn(p, patfile[patno]); patno++; /* regist path names */ } } /*}}} */ /*{{{ newfile*/ void newfile(char *p) { char file[128]; /* Dateiname bei &datei */ FILE *f; if (*p == '&') { if (strcmp("-",&p[1]) == 0) f=stdin; else f=fopen(&p[1],"r"); if (f != NULL) { while ( fgets(file,127,f) != NULL) OneNewFile(strdup(file)); /* regist copy of filecontents */ fclose(f); } } else OneNewFile(p); } /*}}} */ /*{{{ argv_main: main routine*/ /******************************* main routine *******************************/ #ifndef __GEM__ #ifdef __TOS__ int argvmain(int argc, uchar **argv,uchar **envp) #else int main(int argc, uchar *argv[]) #endif { uchar *p, *q, *env, *env9; uchar ptitel=0; int yn; extern char title[]; struct ffblk ffb; FILE *fp; char buffer[256]; if (!setjmp (exit_jmp)) { #ifndef __TOS__ ctrlbrk(userbreak); /* set vector for '^C' */ cbrk = getcbrk(); setcbrk(1); atexit(recovercbrk); #endif remove("LHARC.)1("); remove("LHARC.)2("); mkcrc(); /* make CRC table */ swchar = getswchar(); /* get the setting of switch char */ argc--; argv++; if (argc-- == 0) { flg_h = 1; usage(); /* if no parameter given */ } p = (argv++)[0]; cmd = toupper(*p); if (strlen(p) - 1 || strchr("EXTDLVAUMFPSC", cmd) == 0) { cmd = 'X'; /* if no command, assume 'X' command */ argc++; argv--; flg_x = 1; /* @@25.5.91 Ohne Kommando x -rm */ flg_m = 1; } cmdupdate = (int)strchr("AUMFD", cmd); /* command updating archive? */ if ((env = getenv("TMP")) != NULL) { /* get 'TMP' from environment */ wdir = env; flg_w = 1; } if ((env = getenv("LHARC")) != NULL) { /* get 'LHARC' from environment */ for (p = env; *p != '\0'; p++) { if (*p == ' ' || *p == '\x08') *p = '\0'; } env9 = p; p = env; while (p < env9) { while (*p == '\0') p++; if (*p == swchar || *p == '-') p++; getsw(p); while (*p) p++; } } patno = -1; if (cmd == 'C') patno=0; basedir = NULL; while (argc--) { p = (argv++)[0]; if (*p == swchar || *p == '-') { getsw(++p); } else { if (ptitel == 0 && flg_d == 0) { puts(title); /* output title */ if ((fp = fopen("lharc.ttp","rb")) != NULL || (fp = fopen("lzh.ttp","rb")) != NULL || (fp = fopen("lharcd.ttp","rb")) != NULL) { fread(buffer,1,256,fp); if (strncmp(buffer+30,"LArc's PFX",10) == 0) printf(morefiles); fclose(fp); } putchar('\n'); ptitel=1; } strupr(p); slash2yen(p); /* convert '/' to '\' */ /* in japanese version */ if (patno < 0) { /* get archive name */ strcpy(arcname, p); if ((p = strrchr(arcname, '\\')) == NULL) { p = arcname; /* pointer of the part of file name */ } if ((q = strchr(p, '.')) == NULL) { strcat(arcname, ".LZH"); /* if no extension */ } else if (strcmp(".LZH", q) && flg_m == 0 && cmdupdate) { fprintf(stderr, M_NOTLZH, arcname); yn = getyn(); /* if the extension is not '.LZH' */ if (yn == 'N') { errorlevel = 1; longjmp (exit_jmp, 1); } } patno++; } else { newfile(p); /* Register file or files */ } } } if (patno < 0) { error(NOARCNMERR, NULL); } if (patno == 0 && cmd != 'D') { /* if no name given */ extfn(patpath[0] = patnul, patfile[0]); /* '*.*' is assumed */ patno++; } p = stpcpy(workdir, wdir) - 1; if (*workdir != '\0' && strrchr(workdir, '\\') != p && *p != ':') { strcat(workdir, "\\"); /* concatenate '\' after the work dir. */ } if (cmdupdate) { if (strchr(arcname, '*') || strchr(arcname, '?')) { error(NOARCERR, arcname); } /* when updating archive, wild cards can't used */ executecmd(); } else { if (cmd == 'C') executecmd(); else { if (findfirst(arcname, &ffb, 0x07)) { error(NOARCERR, arcname); } do { strcpy(backpath(arcname), ffb.ff_name); executecmd(); } while (!findnext(&ffb)); if (cmd != 'L' && cmd != 'V') tstpat(); /* whether all given names were used? */ } } } #ifdef __TOS__ if (flg_h) { fflush (stdin); /* wait for keystroke when used */ printf (M_PRESSKEY); /* with GEM-Desktop */ getch (); putchar ('\n'); } #endif return errorlevel; } /*}}} */ /*{{{ main: argv calculations*/ int main (int argc, char *argv[], char *envp[]) { char **myargv; extern BASPAG *_BasPag; char *env; char *startpar; char *oldline; int count = 0; int i; Fsetdta (&_mydta); /* Anfang der alten Kommandozeile */ oldline = &_BasPag->p_cmdlin[1]; /* Flag fuer Verwendung von ARGV */ if (_BasPag->p_cmdlin[0] != 127) return argvmain (argc, argv, envp); /* Zeiger auf Env-Var merken */ env = getenv("ARGV"); if (!env) return argvmain (argc, argv, envp); /* alle weiteren envp's loeschen */ i = 0; while (strncmp (envp[i], "ARGV", 4)) i++; envp[i] = NULL; /* alles, was dahinter kommt, abschneiden */ if (env[0] && env[-1]) { *env++ = 0; /* kill it */ while (*env++); } /* Parameterstart */ startpar = env; while (*env) { count++; while (*env++); } /* Speicher fuer neuen Argument-Vektor */ myargv = Malloc ((count+1)*sizeof (char *)); env = startpar; count = 0; while (*env) { myargv[count++] = env; while (*env++); } myargv[count] = NULL; /* moeglichst viele Parameter in alte Kommandozeile */ { int i; *oldline = 0; i = 1; while ((i < count) && (strlen (oldline) + strlen (myargv[i]) < 120)) { if (i > 1) strcat (oldline, " "); strcat (oldline, myargv[i]); i++; } if (i < count) strcat (oldline, " ..."); } /* und ...argvmain() starten */ count = argvmain (count, myargv, envp); Mfree (myargv); return count; } #endif /*}}} */