static char *sccsid = "@(#)usq.c 1.8u (UCF) 83/09/02"; /* * THIS IS THE SOURCE CODE FOR USQ.C. * * THE ROUTINE "SQ.EXE", ON "DISKETTE B", SQUEEZES A MODULE TO * CONSERVE DISKETTE SPACE. * THE ROUTINE USQ.EXE, ALSO ON "DISKETTE B", UNSQUEEZES MODULES * SQUEEZED BY SQ.EXE. * * usq.c - CP/M compatible file unsqueezer utility * * compile as follows: * cc [-DVAX] -O usq.c -o usq * (define VAX only if running on VAX) */ /* modified by J. Chappell 02-02-84 to check if ferror occurred on write 02-07-84 to accept wildcards in filenames */ #include #define VAX 1 /* #include */ /* #include */ #include #define TRUE 1 #define FALSE 0 #define ERROR (-1) #define PATHLEN 312 /* Number of characters allowed in pathname */ #define OK 0 #define RECOGNIZE 0xFF76 /* unlikely pattern */ #define DLE 0x90 /* repeat byte flag */ #define SPEOF 256 /* special endfile token */ #define NUMVALS 257 /* 256 data values plus SPEOF*/ #define LARGE 30000 /* #define WILDCARD FALSE */ #ifdef VAX /* then we don't want 32 bit integers */ typedef short INT; typedef unsigned short UNSIGNED; #else /* 16 bit machines */ typedef int INT; typedef unsigned UNSIGNED; #endif struct _sqleaf { /* Decoding tree */ INT _children[2]; /* left, right */ }; struct _sqleaf Dnode[NUMVALS - 1]; INT Bpos; /* last bit position read */ INT Curin; /* last byte value read */ INT Repct; /* Number of times to return value */ INT Value; /* current byte value or EOF */ INT MakeLCPathname=TRUE; /* translate pathname to lc if all caps */ INT Nlmode=FALSE; /* zap cr's if true */ INT Inbackground = FALSE; INT getcr(), getuhuff(), portgetw(); /* extern int fflush(),ferror(),fclose(); */ main(argc, argv) unsigned char *argv[]; { register unsigned char *cp; register INT npats=0; unsigned char **patts; INT n, errorstat; /* if (signal(SIGINT, SIG_IGN)==SIG_IGN) Inbackground++; else signal(SIGINT, SIG_DFL); signal(SIGHUP, SIG_IGN); */ errorstat=0; if(argc<2) goto usage; while (--argc) { cp = *++argv; if(*cp == '-') { while( *++cp) { switch(*cp) { case 'n': Nlmode=TRUE; break; case 'u': MakeLCPathname=FALSE; break; default: goto usage; } } } else if( !npats && argc>0) { if(argv[0][0]) { npats=argc; patts=argv; } } } if(npats < 1) { usage: fprintf(stderr,"Usage: usq [-nu] file ...\n"); fprintf(stderr,"\t-n Nlmode: remove carriage returns\n"); fprintf(stderr,"\t-u preserve Uppercase pathnames\n"); #ifdef WILDCARD fprintf(stderr,"\twildcards are acceptable in filenames.\n"); #endif exit(1); } #ifdef WILDCARD for(n=0; n= NUMVALS) { fprintf(stderr, "usq: %s has invalid decode tree\n", fname); fclose(in); return(ERROR); } /* Initialize for possible empty tree (SPEOF only) */ Dnode[0]._children[0] = -(SPEOF + 1); Dnode[0]._children[1] = -(SPEOF + 1); for(i = 0; i < numnodes; ++i) { /* Get decoding tree from file */ Dnode[i]._children[0] = portgetw(in); Dnode[i]._children[1] = portgetw(in); } /* Get translated output bytes and write file */ if(MakeLCPathname && !IsAnyLower(origname)) uncaps(origname); for(p=origname; *p; ++p) /* change / to _ */ if( *p == '/') *p = '_'; if (!Inbackground) fprintf(stderr, "usq: %s -> %s\n",fname,origname); if((out=fopen(origname, "wb"))==NULL) { fprintf(stderr, "usq: can't create %s\n", origname); } while ((c = getcr()) != EOF) { crc += (UNSIGNED) c; if ( c == '\r' && Nlmode) continue; if(fputc(c,out)!=c){ fclose(in); abort("usq: error in writing file: %s\n",origname); } } fclose(in); if(fflush(out)<0 || ferror(out)<0) abort("usq: Error writing file: %s\n",origname); if(fclose(out)<0) abort("usq: Error closing file: %s\n",origname); if( crc != filecrc ) { fprintf(stderr, "usq: bad checksum in %s\n", fname); fflush(stdout); return(ERROR); } return(OK); } /*** from utr.c - */ /* initialize decoding functions */ init_cr() { Repct = 0; } init_huff() { Bpos = 99; /* force initial read */ } /* Get bytes with decoding - this decodes repetition, * calls getuhuff to decode file stream into byte * level code with only repetition encoding. * * The code is simple passing through of bytes except * that DLE is encoded as DLE-zero and other values * repeated more than twice are encoded as value-DLE-count. */ INT getcr() { register INT c; if(Repct > 0) { /* Expanding a repeated char */ --Repct; return(Value); } else { /* Nothing unusual */ if((c = getuhuff()) != DLE) { /* It's not the special delimiter */ Value = c; if(Value == EOF) Repct = LARGE; return(Value); } else { /* Special token */ if((Repct = getuhuff()) == 0) /* DLE, zero represents DLE */ return(DLE); else { /* Begin expanding repetition */ Repct -= 2; /* 2nd time */ return(Value); } } } } /* Decode file stream into a byte level code with only * repetition encoding remaining. */ INT getuhuff() { register INT i; /* Follow bit stream in tree to a leaf*/ i = 0; /* Start at root of tree */ do { if(++Bpos > 7) { if((Curin = getc(in)) == ERROR) return(ERROR); Bpos = 0; /* move a level deeper in tree */ i = Dnode[i]._children[1 & Curin]; } else i = Dnode[i]._children[1 & (Curin >>= 1)]; } while(i >= 0); /* Decode fake node index to original data value */ i = -(i + 1); /* Decode special endfile token to normal EOF */ i = (i == SPEOF) ? EOF : i; return(i); } /* * Machine independent getw which always gets bytes in the same order * as the CP/M version of SQ wrote them */ INT portgetw(f) FILE *f; { register INT c; c = getc(f) & 0377; return(c | (getc(f) << 8)); } /* make string s lower case */ uncaps(s) unsigned char *s; { for( ; *s; ++s) if(isupper(*s)) *s = tolower(*s); } /* * IsAnyLower returns TRUE if string s has lower case letters. */ IsAnyLower(s) unsigned char *s; { for( ; *s; ++s) if (islower(*s)) return(TRUE); return(FALSE); } #ifdef WILDCARD /* dir: for DOS ALL Entry: 1. Filename possibly containing wildcards ? and * 2. Drive specifier flag Returns: Pointer to data area containing NULL terminated list of filenames, or NULL if none found. Notes: User must free up data allocated by this function with free() if memory is to be restored to heap after use. Drive specifier: if non-zero will drive specifiers will be put on file names Path names: not supported */ unsigned char *dir(filespec,drflag) unsigned char *filespec; short drflag; { #define BLOCK 100 /* room for fcb,dta,etc.. */ #define FIRST 0x1100 /* search first */ #define NEXT 0x1200 /* search next */ #define CURRENT 0x19 /* get current drive */ #define PARSE 0x2900 /* parse file name */ #define SETDTA 0x1a00 /* set disk transfer address */ unsigned char *fcb,*rets,*cp,*tmp,*dta,*realloc(); unsigned short mode,pos,i; struct regval { int ax,bx,cx,dx,si,di,ds,es;} r; tmp=realloc(0,BLOCK); fcb=realloc(0,BLOCK); dta=realloc(0,BLOCK); rets=realloc(0,BLOCK); segread(&r.si); /* parse file name */ r.es=r.ds; r.si=filespec; r.di=fcb; r.ax=PARSE; sysint21(&r,&r); segread(&r.si); /* set dta */ r.dx=dta; r.ax=SETDTA; sysint21(&r,&r); for(pos=0,mode=FIRST;;mode=NEXT){ segread(&r.si); r.ax=mode; r.dx=fcb; sysint21(&r,&r); /* search */ if(r.ax&0xff==0xff)break; /* not found */ cp=tmp; if(drflag){ /* put on drive specifier */ if(*dta==0)*dta=(bdos(CURRENT)&0xff)+1; *cp++=*dta+'A'-1; *cp++=':'; } for(i=1;i<9;i++)if(*(dta+i)!=' ')*cp++=*(dta+i); *cp++='.'; for(;i<12;i++)if(*(dta+i)!=' ')*cp++=*(dta+i); *cp='\0'; rets=realloc(rets,pos+strlen(tmp)+1); /* store file name */ strcpy(rets+pos,tmp); pos+=(strlen(tmp)+1); } if(pos)rets=realloc(rets,pos+strlen(tmp)+1); else free(rets); free(fcb); free(tmp); free(dta); return pos ? rets: 0; } #endif