N1MAKEFILE ÒÙREADME ó‡SQCOM H 6)USQ C WjUSQ H c—ÈUTR C f/Çÿ# # %W% %G% %U% # CFLAGS=-v -O usq: usq.o utr.o $(CC) $(CFLAGS) $(LDFLAGS) -o usq usq.o utr.o usq.o utr.o: usq.h sqcom.h  This archive contains a version of the CP/M USQ program which runs on a 68000 under System V. I make no promises about whether it works on any other systems. If you find bugs, post them, don't send them to me. I don't use it any more. Geoff Kuenning ...!ihnp4!trwrb!desint!geoff /* @(#)sqcom.h 1.3 9/4/84 19:57:00 */ /* Definitions and external declarations */ #define RECOGNIZE 0xFF76 /* unlikely pattern */ /* *** Stuff for first translation module *** */ #define DLE 0x90 unsigned short crc; /* error check code */ #ifdef cpm char outdrv[3]; /* current output drive (string) */ #endif /* *** Stuff for second translation module *** */ #define SPEOF 256 /* special endfile token */ #define NUMVALS 257 /* 256 data values plus SPEOF*/ #define CPMEOF 0x1a #define ERROR (-1) #define SECSIZ 128 #ifndef EOF #define EOF (-1) #endif static char Sccs_Id[] = "@(#)usq.c 1.3 9/4/84 19:57:05"; /* USQ.C CHANGE HISTORY: * 1.3 Converted to support USG Unix on 68000. Define unix to * get unix version, cpm to get CP/M-68K version. Geoff Kuenning 9/3/84 * 1.2 Converted to Unix SCCS. Geoff Kuenning 9/3/84 * 1.1 Added WILDEXP. JEC 1/2/84 * 1.0 Converted to CP/M-68K C, Jim Cathey 11-5-83 * Taken from BDS C version 2.0 * 2.0 Added checkurk(), changed credits -CAF 8-14-83 * 1.9 Added wildexp -CAF 6-12-82 * 1.8 Output CPMEOF's while last output sector is partially filled. * Needed if file was squeezed on a non-CP/M system. -CAF 3-10-82 * 1.7 Added -n to change NL to CRLF when unsqueezing files. Added CPMEOF * at end of file in case of checksum error detected. * 1.6 Lengthened permissible length of unsqueezed filename so long **nix * pathnames won't choke unsqueeze(). -CAF 12-5-81 * 1.5 Break up long lines of introductory text * -count no longer appends formfeed to preview of each file. * -fcount (-f10, -F10) does append formfeed. * 1.4 Add -count option to allow quick inspection of files. * 1.3 Close inbuff to avoid exceeding maximum number of * open files. Includes rearranging error exits. * * Program to unsqueeze files formed by sq.com * * Usage (CPM version): * USQ item ... * where ... represents more (optional) items and * "item" is either: * drive: to change the output drive * file input file * drive:file input file * - 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. * * -f Same as -count except formfeed * appended to preview of each file. * Example: -f10. * * -n Change NL to CRLF * * 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. * * Usage (USG Unix version): * USQ item ... * where ... represents more (optional) items and * "item" is either: * file input file * - 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. * Count defaults to a very high value. * No CRC check is performed when previewing. * Use -e to cancel this. * * -f Same as - except formfeed * appended to preview of each file. * Example: -f10. * * -u Cancel - or -f. * -n Change CRLF to NL. Note that this is the EXACT * opposite of the meaning of this flag in CP/M. * * 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. * * Examples (CP/M): * A>USQ GRUMP.QQQ writes on a: * A>USQ D:CRAP.XQZ writes on A: * A>USQ B: D:CRAP.CQM writes on B: * B>USQ X.AQ C: Y.BQ writes X.?? on B: and Y.?? on C: * * Examples (Unix): * usq grump.qqq writes grump.q?q in current directory * usq - crap.xqz writes cleaned-up crap to standard output */ #ifndef unix /* Make sure *something* is defined */ #define cpm #endif #ifdef unix #include #include #else #include #include #endif #include "sqcom.h" #include "usq.h" #define VERSION "1.3 9/4/84" /* Version for titling output */ unsigned dispcnt; /* How much of each file to preview */ char ffflag; /* Formfeed separates preview from different files */ char nlmode; /* <>0 if adding/deleting cr's for host system */ #ifdef cpm #define SENTINEL 055555 /* For catching out-of-memory conditions */ #ifndef PATHLEN #define PATHLEN 16 /* Maximum length of an input filename */ #endif #define LONGPATH 257 /* Maximum length of an output filename */ char origname[LONGPATH]; /* Original file name without drive */ unsigned Sentinel; /* be sure this doesn't get munged ! */ #endif #ifdef unix #ifndef PATHLEN #define PATHLEN 512 /* Maximum length of a pathname */ #endif #define LONGPATH PATHLEN #endif short brgetw (); main(argc, argv) int argc; char *argv[]; { int i,c; char inparg[PATHLEN]; /* parameter from input */ #ifdef cpm wildexp(&argc, &argv); Sentinel = SENTINEL; /* unlikely value */ #endif nlmode = dispcnt = 0; /* Not in preview or nlmode */ #ifdef cpm /* Initialize output drive to default drive */ outdrv[0] = '\0'; /* But prepare for a specific drive */ outdrv[1] = ':'; outdrv[2] = '\0'; /* string terminator */ #endif /* Process the parameters in order */ for(i = 1; i < argc; ++i) obey(argv[i]); if(argc < 2) { fprintf(stderr, "File unsqueezer version %s\n", VERSION); fprintf(stderr,"Conceived by Richard Greenlaw Modified by Chuck Forsberg et al.\n"); #ifdef cpm fprintf(stderr, "Accepts redirection and wildcards.\n"); fprintf(stderr, "Usage: usq [-count][-Fcount][-N] [file ...]\n"); fprintf(stderr, "Parameters are from command line or one-at-a-time from standard\n"); fprintf(stderr, "input and are output drives and input file names. Empty to quit.\n"); #endif #ifdef unix fprintf(stderr, "Usage: usq [-][-f][-u][-n] [file ...]\n"); fprintf(stderr, "Parameters are from command line or one-at-a-time from standard\n"); fprintf(stderr, "input and are input file names. Empty to quit.\n"); #endif do { fprintf(stderr, "\n*"); for(i = 0; i < sizeof (inparg); ++i) { if((c = getchar()) == EOF) c = '\n'; /* force empty (exit) command */ if((inparg[i] = c) == '\n') { inparg[i] = '\0'; break; } } if(inparg[0] != '\0') obey(inparg); } while(inparg[0] != '\0'); } #ifdef cpm if (Sentinel != SENTINEL) fprintf(stderr,"Out of memory: translation suspect!\007\n"); #endif return 0; } obey(p) char *p; { char *q; if(*p == '-') { if('n' ==tolower(p[1])) { ++nlmode; return; } #ifdef unix if('e' == tolower (p[1])) { dispcnt = 0; /* cancel previewing */ return; } #endif if(ffflag = (tolower(*(p+1)) == 'f')) ++p; /* Set number of lines of each file to view */ dispcnt = 65535; /* default */ if(*(p+1)) if((dispcnt = atoi(p + 1)) == 0) fprintf(stderr, "\nBAD COUNT %s", p + 1); return; } #ifdef cpm if(*(p + 1) == ':') { /* Got a drive */ if(isalpha(*p)) { if(*(p+2) == '\0') { /* Change output drive */ dispcnt = 0; /* cancel previewing */ printf("\nOutput drive =%s",p); outdrv[0] = *p; return; } } else { fprintf(stderr, "\nERROR - Ignoring %s.", p); return; } } /* Check for ambiguous (wild-card) name */ for(q = p; *q != '\0'; ++q) if(*q == '*' || *q == '?') { fprintf(stderr, "\nCan't accept ambiguous name %s.", p); return; } #endif unsqueeze(p); } unsqueeze(infile) char *infile; { FILE *inbuff, *outbuff; /* file buffers */ #ifdef cpm FILE *fopenb(), *fdopen(); #endif #ifdef unix FILE *fopen (), *fdopen (); #define creatb creat #define fopenb fopen #endif int i, c, ofd; char cc; char *p; unsigned short filecrc; /* checksum */ int numnodes; /* size of decoding tree */ char outfile[LONGPATH]; /* output file name */ unsigned linect; /* count of number of lines previewed */ if((inbuff = fopenb(infile,"r")) == 0) { fprintf(stderr, "Can't open %s\n", infile); return; } /* Initialization */ linect = 0; crc = 0; init_cr(); init_huff(); /* Process header */ if(brgetw (inbuff) != RECOGNIZE) { fprintf(stderr, "'%s' is not a squeezed file!\n", infile); goto closein; } filecrc = brgetw(inbuff); /* Get original file name */ #ifdef cpm p = origname; /* send it to array */ #endif #ifdef unix p = outfile; #endif do { *p = getc(inbuff); } while(*p++ != '\0'); #ifdef cpm /* Combine with output drive */ outfile[0] = '\0'; /* empty */ strcat(outfile, outdrv); /* drive */ strcat(outfile, origname); /* name */ #endif printf("\n%s -> %s: ", infile, outfile); numnodes = brgetw(inbuff); if(numnodes < 0 || numnodes >= NUMVALS) { fprintf(stderr, "'%s' has invalid decode tree size.\n", infile); 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] = brgetw(inbuff); dnode[i].children[1] = brgetw(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 */ if((ofd = creatb(outfile, 0755)) == ERROR) { fprintf(stderr, "Can't create '%s'.\n", outfile); goto closeall; } outbuff = fdopen(ofd,"w"); /* Get translated output bytes and write file */ while((c = getcr(inbuff)) != EOF) { crc += c; if(nlmode && c=='\n') fputc('\r',outbuff); if((fputc(c, outbuff)) == ERROR) { fprintf(stderr, "Write error in '%s'.\n", outfile); goto closeall; } } if(filecrc != crc) { #ifdef cpm fputc(CPMEOF, outbuff); #endif fprintf(stderr, "ERROR - checksum error in '%s'.\n", outfile); } closeall: /* * If the last sector is partially filled (this would happen * iff the file was squeezed on MARC, Unix(TM), MS-DOS or * similar system which avoids the CP/M EOF crock), * pad it out with ^Z characters so editors, * etc. won't choke on it. -CAF 3-10-82 */ /* while(outbuff._nleft % SECSIZ) /* for BDS C 1.4x only */ /* putc(CPMEOF, &outbuff); */ fflush(outbuff); fclose(outbuff); } closein: fclose(inbuff); } short brgetw(stream) FILE *stream; { /* Get word from stream. Since BDS C is byte reversed and CP/M-68K isn't, we need to swap every byte. We don't use 'getw' because it returns 32 bits on a 32-bit machine. */ short wordin, wordout; wordin = (getc (stream) << 8) | (getc (stream) & 0xFF); swab(&wordin, &wordout, 2); return wordout; } /* @(#)usq.h 1.3 9/4/84 19:57:23 */ #define LARGE 30000 /* Decoding tree */ struct { int children[2]; /* left, right */ } dnode[NUMVALS - 1]; int bpos; /* last bit position read */ int curin; /* last byte value read */ /* Variables associated with repetition decoding */ int repct; /*Number of times to retirn value*/ int value; /*current byte value or EOF */ static char Sccs_Id[] = "@(#)utr.c 1.3 9/4/84 19:57:28"; #include #include "sqcom.h" #include "usq.h" /* 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(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; } } } } /* Decode file stream into a byte level code with only * repetition encoding remaining. */ int getuhuff(ib) FILE *ib; { int i; int bitval; /* 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; }