/* USQ.C CHANGE HISTORY: * 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: * USQ item ... * where ... represents more (optional) items and * "item" is either: * drive: to change the output drive * file input file * drive:file input file * -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. * * -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. * * USQ uses the dio package, so input and output can be redirected * by special items on the command line such as: * file sends console output to file * +file sends console output to console and file * Also console output of another program using dio can be piped * to the input of USQ or vice-versa. Example: * A>fls parameters |usq * where fls might be a program that expands patterns like *.asm * to a list of specific file names for usq to unsqueeze. * * The unsqueezed file name is recorded in the squeezed file. * * Examples: * 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: */ #include #include #include "sqcom.h" #include "usq.h" #define VERSION "2.0 8-14-83" #define STDERR 4 /*Error output stream (always console) */ /* This must follow all include files. USQ.CRL must be linked first! */ 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 */ unsigned Sentinel; /* be sure this doesn't get munged ! */ #define SENTINEL 055555 main(argc, argv) int argc; char *argv[]; { int i,c; int getchar(); /* Directed io version */ char inparg[16]; /* parameter from input */ checkurk(); /* check for memory overflow */ Sentinel = SENTINEL; /* unlikely value */ wildexp(&argc, &argv); /* do the Shell's bloody work */ dioinit(&argc, argv); /* obey directed to args */ nlmode = dispcnt = 0; /* Not in preview or nlmode */ /* Initialize output drive to default drive */ outdrv[0] = '\0'; /* But prepare for a specific drive */ outdrv[1] = ':'; outdrv[2] = '\0'; /* string terminator */ /* Process the parameters in order */ for(i = 1; i < argc; ++i) obey(argv[i]); if(argc < 2) { if(! _diflag) { fprintf(STDERR, "File unsqueezer version %s\n", VERSION); fprintf(STDERR,"Conceived by Richard Greenlaw Modified by Chuck Forsberg et al.\n"); fprintf(STDERR, "Accepts redirection and pipes.\n"); fprintf(STDERR, "Usage: usq [-count][-Fcount][-N] [file ...]\n"); fprintf(STDERR, "Parameters are from command line or one-at-a-time from standard\ninput and are output drives and input file names. Empty to quit.\n"); } do { fprintf(STDERR, "\n*"); for(i = 0; i < 16; ++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'); } dioflush(); /* clean up any directed io */ if (Sentinel != SENTINEL) fprintf(STDERR,"out of memory: translation suspect\007\n"); } obey(p) char *p; { char *q; if(*p == '-') { if('n' ==tolower(p[1])) { ++nlmode; return; } if(ffflag = (toupper(*(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; } 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; } unsqueeze(p); } unsqueeze(infile) char *infile; { struct _buf inbuff, outbuff; /* file buffers */ int i, c; char cc; char *p; unsigned filecrc; /* checksum */ int numnodes; /* size of decoding tree */ char outfile[257]; /* output file name */ unsigned linect; /* count of number of lines previewed */ if(fopen(infile, &inbuff) == ERROR) { fprintf(STDERR, "Can't open %s\n", infile); return; } /* Initialization */ linect = 0; crc = 0; init_cr(); init_huff(); /* Process header */ if(getw(&inbuff) != RECOGNIZE) { fprintf(STDERR, "%s is not a squeezed file\n", infile); goto closein; } filecrc = getw(&inbuff); /* Get original file name */ p = origname; /* send it to array */ do { *p = getc(&inbuff); } while(*p++ != '\0'); /* Combine with output drive */ outfile[0] = '\0'; /* empty */ strcat(outfile, outdrv); /* drive */ strcat(outfile, origname); /* name */ printf("\n%s -> %s: ", infile, outfile); numnodes = getw(&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] = getw(&inbuff); dnode[i].children[1] = getw(&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(fcreat(outfile, &outbuff) == ERROR) { fprintf(STDERR, "Can't create %s\n", outfile); goto closeall; } /* Get translated output bytes and write file */ while((c = getcr(&inbuff)) != EOF) { crc += c; if(nlmode && c=='\n') putc('\r', &outbuff); if((putc(c, &outbuff)) == ERROR) { fprintf(STDERR, "Write error in %s\n", outfile); goto closeall; } } if(filecrc != crc) { putc(CPMEOF, &outbuff); 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); } /* * Check for proper linking and sufficient memory to execute */ checkurk() { char *endext(), *topofmem(), *codend(), *externs(); if (codend() > externs() /* check for bad -e value! */ || (topofmem()-3000) < endext() ) { printf("checkurk(): bad memory layout\n"); exit(); } }