/* Program to unsqueeze files formed by sq.com * * Useage: * * usq [-count] [-fcount] [file1] [file2] ... [filen] * * where file1 through filen represent one or more files to be compressed, * and the following options may be specified: * * -count Previewing feature: redirects output * files to standard output with parity stripped * and unprintables except CR, LF, TAB and FF * converted to periods. Limits each file * to first count lines. * Defaults to console, but see below how * to capture all in one file for further * processing, such as by PIP. * Count defaults to a very high value. * No CRC check is performed when previewing. * Use drive: to cancel this. * * -fcount Same as -count except formfeed * appended to preview of each file. * Example: -f10. * * If no such items are given on the command line you will be * prompted for commands (one at a time). An empty command * terminates the program. * * The unsqueezed file name is recorded in the squeezed file. * */ /* CHANGE HISTORY: * 1.3 Close inbuff to avoid exceeding maximum number of * open files. Includes rearranging error exits. * 1.4 Add -count option to allow quick inspection of files. * 1.5 Break up long lines of introductory text * 1.5 -count no longer appends formfeed to preview of each file. * -fcount (-f10, -F10) does append formfeed. * 1.6 Modified to work correctly under MP/M II (DIO.C change) and * signon message shortened. * 2.0 Modified to work with CI-C86 compiler (CP/M-86 and MS-DOS) * 2.1 Modified for use in MLINK * 2.2 Modified for use with optimizing CI-C86 compiler (MS-DOS) * 3.0 Generalized for use under UNIX * * 3.2 Ported to Amiga & Lattice * Rick Schaeffer [70120,174] 12/03/85 * 3.3 Small changes to eliminate warning messages from Lattice C ver 3.02 * Joanne Dow jdow on bix - BYTE INFORMATION EXCHANGE * 3.3A (CP/M-68K version) converted for CP/M-68K. Sat Nov 8, 1986 18:15:14.01 * Robert Heller heller on BIX, RHELLER on GEnie, * Heller@UMass-CS.CSNET on ARPANet, Heller@UMass.BITNET on BITNET, * Robert Heller at Dave's Fido - 101/27 on FidoNet. */ #include #define ERROR -1 #define CPM68K /* CPM68K - *RPH* */ /* Definitions and external declarations */ #define RECOGNIZE 0xFF76 /* unlikely pattern */ /* *** Stuff for first translation module *** */ #define DLE 0x90 static unsigned int crc; /* error check code */ /* *** Stuff for second translation module *** */ #define SPEOF 256 /* special endfile token */ #define NUMVALS 257 /* 256 data values plus SPEOF*/ #define LARGE 30000 /* Decoding tree */ static struct { int children[2]; /* left, right */ } dnode[NUMVALS - 1]; static int bpos; /* last bit position read */ static int curin; /* last byte value read */ /* Variables associated with repetition decoding */ static int repct; /*Number of times to retirn value*/ static int value; /*current byte value or EOF */ #ifdef CPM68K #define VERSION "3.3A (CP/M-68K) Nov 8, 1986" #define void int #else #define VERSION "3.3 12/13/85" #endif /* This must follow all include files */ unsigned int dispcnt; /* How much of each file to preview */ char ffflag; /* should formfeed separate preview from different files */ /* eject^Leject */ int unsqueeze(infile) char *infile; { unsigned int getx16(); FILE *inbuff, *outbuff; /* file buffers */ #ifdef CPM68K FILE *fopenb(); #endif int i, c; char cc; register int rstat; char *p; unsigned int filecrc; /* checksum */ int numnodes; /* size of decoding tree */ char outfile[128]; /* output file name */ unsigned int linect; /* count of number of lines previewed */ char obuf[128]; /* output buffer */ int oblen; /* length of output buffer */ static char errmsg[] = "ERROR - write failure in %s\n"; rstat = 1; #ifdef CPM68K if(!(inbuff=fopenb(infile, "r"))) { #else if(!(inbuff=fopen(infile, "rb"))) { #endif printf("Can't open %s\n", infile); rstat = 0; return; } /* Initialization */ linect = 0; crc = 0; init_cr(); init_huff(); /* Process header */ if(getx16(inbuff) != RECOGNIZE) { printf("%s is not a squeezed file\n", infile); rstat = 0; goto closein; } filecrc = getw16(inbuff); /* Get original file name */ p = outfile; /* send it to array */ do { *p = getc(inbuff); } while(*p++ != '\0'); printf("%s -> %s: ", infile, outfile); numnodes = getw16(inbuff); if(numnodes < 0 || numnodes >= NUMVALS) { printf("%s has invalid decode tree size\n", infile); rstat = 0; goto closein; } /* Initialize for possible empty tree (SPEOF only) */ dnode[0].children[0] = -(SPEOF + 1); dnode[0].children[1] = -(SPEOF + 1); /* Get decoding tree from file */ for(i = 0; i < numnodes; ++i) { dnode[i].children[0] = getw16(inbuff); dnode[i].children[1] = getw16(inbuff); } if(dispcnt) { /* Use standard output for previewing */ putchar('\n'); while(((c = getcr(inbuff)) != EOF) && (linect < dispcnt)) { cc = 0x7f & c; /* strip parity */ if((cc < ' ') || (cc > '~')) /* Unprintable */ switch(cc) { case '\r': /* return */ /* newline will generate CR-LF */ goto next; case '\n': /* newline */ ++linect; case '\f': /* formfeed */ case '\t': /* tab */ break; default: cc = '.'; } putchar(cc); next: ; } if(ffflag) putchar('\f'); /* formfeed */ } else { /* Create output file */ #ifdef CPM68K if(!(outbuff=fopenb(outfile, "w"))) { #else if(!(outbuff=fopen(outfile, "wb"))) { #endif printf("Can't create %s\n", outfile); rstat = 0; goto closeall; } printf("unsqueezing,"); /* Get translated output bytes and write file */ oblen = 0; while((c = getcr(inbuff)) != EOF) { crc += c; obuf[oblen++] = c; if (oblen >= sizeof(obuf)) { if(!fwrite(obuf, sizeof(obuf), 1, outbuff)) { printf(errmsg, outfile); rstat = 0; goto closeall; } oblen = 0; } } if (oblen && !fwrite(obuf, oblen, 1, outbuff)) { printf(errmsg, outfile); rstat = 0; goto closeall; } if((filecrc && 0xFFFF) != (crc && 0xFFFF)) { printf("ERROR - checksum error in %s\n", outfile); rstat = 0; } else printf(" done.\n"); closeall: fclose(outbuff); } closein: fclose(inbuff); return(rstat); } static getw16(iob) /* get 16-bit word from file */ FILE *iob; { int temp; temp = getc(iob); /* get low order byte */ temp |= getc(iob) << 8; if (temp & 0x8000) temp |= (~0) << 15; /* propogate sign for big ints */ return temp; } static unsigned int getx16(iob) /* get 16-bit (unsigned) word from file */ FILE *iob; { int temp; temp = getc(iob); /* get low order byte */return temp | (getc(iob) << 8); } /* initialize decoding functions */ static init_cr() { repct = 0; } static 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. */ static int getcr(ib) FILE *ib; { int c; if(repct > 0) { /* Expanding a repeated char */ --repct; return value; } else { /* Nothing unusual */ if((c = getuhuff(ib)) != DLE) { /* It's not the special delimiter */ value = c; if(value == EOF) repct = LARGE; return value; } else { /* Special token */ if((repct = getuhuff(ib)) == 0) /* DLE, zero represents DLE */ return DLE; else { /* Begin expanding repetition */ repct -= 2; /* 2nd time */ return value; } } } } /* eject^Leject */ /* Decode file stream into a byte level code with only * repetition encoding remaining. */ static int getuhuff(ib) FILE *ib; { int i; /* Follow bit stream in tree to a leaf*/ i = 0; /* Start at root of tree */ do { if(++bpos > 7) { if((curin = getc(ib)) == 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; }