home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume25 / freeze / part01 / freeze.c < prev    next >
C/C++ Source or Header  |  1991-11-04  |  21KB  |  923 lines

  1. #include "freeze.h"
  2. #include "lz.h"
  3. #include "huf.h"
  4. #include "patchlevel.h"
  5.  
  6. /*
  7.  * Freeze - data freezing program
  8.  * Version 1.0:
  9.  * This program is made from GNU compress.c and Yoshizaki/Tagawa's
  10.  * lzhuf.c. (Thanks to all of them.)
  11.  * The algorithm is modified for using in pipe
  12.  * (added ENDOF symbol in Huffman table).
  13.  * Version 1.1:
  14.  * Check for lack of bytes in frozen file when melting.
  15.  * Put the GetBit routine into DecodeChar for reduce function-
  16.  * call overhead when melting.
  17.  * Version 1.2:
  18.  * Added delayed coding a la COMIC.
  19.  * Now freeze works on Intels (*NIX, Microsoft, Turbo),
  20.  * Sun (SunOS).
  21.  * Version 2.0:
  22.  * Buffer size is now 8192 bytes, maximum match length - 256 bytes.
  23.  * Improved hash function (with tuning of hash-table)
  24.  * Version 2.1: Noticeable speedup: Insert_Node and Get_Next_Match
  25.  * are now separated. (Boyer-Moore string matching)
  26.  * Version 2.2: Tunable static Huffman table for position information,
  27.  * this info may be given in the command string now.
  28.  * Version 2.2.3: Bug fixes, 10% freezing speedup.
  29.  * Version 2.3: Minor bug fixes (DOS filenames handling, backward
  30.  * compatibility feature improved, "bits" compression ratio display,
  31.  * preventive check for special files), speedups, more comments added.
  32.  */
  33.  
  34. static char ident[] = "@(#) freeze.c 2.3.%d %s leo@s514.ipmce.su\n";
  35.  
  36. int exit_stat = 0;
  37.  
  38. void Usage() {
  39. #ifdef DEBUG
  40.  
  41. # ifdef MSDOS
  42.     fprintf(stderr,"Usage: freeze [-cdDfitvVg] [file | +type ...]\n");
  43. # else
  44.     fprintf(stderr,"Usage: freeze [-cdDfvVg] [file | +type ...]\n");
  45. # endif /* MSDOS */
  46.  
  47. #else
  48.  
  49. # ifdef MSDOS
  50.     fprintf(stderr,"Usage: freeze [-cdfitvVg] [file | +type ...]\n");
  51. # else
  52.     fprintf(stderr,"Usage: freeze [-cdfvVg] [file | +type ...]\n");
  53. # endif /* MSDOS */
  54.  
  55. #endif /* DEBUG */
  56. }
  57.  
  58. void (*meltfunc)();     /* To call something for melting */
  59.  
  60. short topipe = 0,       /* Write output on stdout, suppress messages */
  61.       precious = 1,     /* Don't unlink output file on interrupt */
  62.       quiet = 1,        /* Don't tell me about freezing */
  63.       do_melt = 0,      /* freeze means "freeze" */
  64.       greedy = 0,       /* GREEDY parsing */
  65.       force = 0;        /* "Force" flag */
  66.  
  67. char ofname [MAXNAMLEN];
  68. struct stat statbuf;    /* Used by 'main' and 'copystat' routines */
  69.  
  70. #ifdef MSDOS
  71.    char *last_sep();    /* last slash, backslash, or colon */
  72.    char tail[2];        /* 2nd and 3rd chars of file extension */
  73. # ifdef BIN_DEFAULT
  74.     short image = O_BINARY;
  75. # else
  76.     short image = O_TEXT;
  77. # endif
  78. #else
  79. #  define last_sep(s) rindex((s), '/')    /* Unix always uses slashes */
  80. char deffile[] = "/etc/default/freeze";
  81. #endif
  82.  
  83. #ifdef DEBUG
  84. short debug = 0;
  85. short verbose = 0;
  86. char * pr_char();
  87. long symbols_out = 0, refers_out = 0;
  88. #endif /* DEBUG */
  89.  
  90. /* Do not sleep when freeze works :-) */
  91. long indc_count, indc_threshold;
  92.  
  93. #ifdef INT_SIG
  94. int
  95. #else
  96. void
  97. #endif
  98. (*bgnd_flag)();
  99.  
  100. void writeerr(), copystat(), version(), tune_table();
  101.  
  102. /*****************************************************************
  103.  *
  104.  * Usage: freeze [-cdfivV] [-t type] [file ...]
  105.  * Inputs:
  106.  *
  107.  *      -c:         Write output on stdout, don't remove original.
  108.  *
  109.  *      -d:         If given, melting is done instead.
  110.  *
  111.  *      -g:         Use "greedy" parsing (1.5% worse, 40% faster).
  112.  *                  (Means nothing when melting)
  113.  *
  114.  *      -f:         Forces output file to be generated, even if one already
  115.  *                  exists, and even if no space is saved by freezeing.
  116.  *                  If -f is not used, the user will be prompted if stdin is
  117.  *                  a tty, otherwise, the output file will not be overwritten.
  118.  *
  119.  *      -i:         Image mode (defined only under MS-DOS).  Prevents
  120.  *                  conversion between UNIX text representation (LF line
  121.  *                  termination) in frozen form and MS-DOS text
  122.  *                  representation (CR-LF line termination) in melted
  123.  *                  form.  Useful with non-text files.  Default if
  124.  *                  BIN_DEFAULT specified.
  125.  *
  126.  *      -b:         Binary mode.  Synonym for -i.  MS-DOS only.
  127.  *
  128.  *      -t:         Text mode (defined only under MS-DOS).  Treat file
  129.  *                  as text (CR-LF and ^Z special) in melted form.  Default
  130.  *                  unless BIN_DEFAULT specified.
  131.  *
  132.  *      -v:         Write freezing statistics
  133.  *
  134.  *      -V:         Write version and compilation options.
  135.  *
  136.  *      file ...:   Files to be frozen.  If none specified, stdin
  137.  *            is used.
  138.  * Outputs:
  139.  *      file.F:     Frozen form of file with same mode, owner, and utimes
  140.  *    or stdout   (if stdin used as input)
  141.  *
  142.  * Assumptions:
  143.  *      When filenames are given, replaces with the frozen version
  144.  *      (.F suffix) only if the file decreases in size.
  145.  * Algorithm:
  146.  *      Modified Lempel-Ziv-SS method (LZSS), adaptive Huffman coding
  147.  *      for literal symbols and length info.
  148.  *      Static Huffman coding for position info. (Is it optimal ?)
  149.  *      Lower bits of position info are put in output
  150.  *      file without any coding because of their random distribution.
  151.  */
  152.  
  153. /* From compress.c. Replace .Z --> .F etc */
  154.  
  155. void main( argc, argv )
  156. register int argc; char **argv;
  157. {
  158.     short overwrite = 0;  /* Do not overwrite unless given -f flag */
  159.     char tempname[100];
  160.     char **filelist, **fileptr;
  161.     char *cp, *rindex();
  162.  
  163. #ifndef MSDOS
  164.     char *malloc();
  165. #endif
  166.  
  167. #if defined(__TURBOC__) || !defined(INT_SIG)
  168.     extern void onintr();
  169. #else
  170.     extern onintr();
  171. #endif
  172.  
  173. #ifdef MSDOS
  174.     char *sufp;
  175. #else
  176. #ifdef INT_SIG
  177.     extern oops();
  178. #else
  179.     extern void oops();
  180. #endif
  181. #endif
  182.  
  183. #ifndef MSDOS
  184.     if ( (bgnd_flag = signal ( SIGINT, SIG_IGN )) != SIG_IGN )
  185. #endif
  186.     {
  187.     signal ( SIGINT, onintr );
  188. #ifdef __TURBOC__
  189.     setcbrk(1);
  190. #endif
  191. #ifndef MSDOS
  192.     signal ( SIGSEGV, oops );
  193. #endif
  194.     }
  195.  
  196.     filelist = fileptr = (char **)(malloc(argc * sizeof(*argv)));
  197.     *filelist = NULL;
  198.  
  199.     if((cp = last_sep(argv[0])) != 0) {
  200.     cp++;
  201.     } else {
  202.     cp = argv[0];
  203.     }
  204.  
  205. #ifdef MSDOS
  206.  
  207. /* use case-insensitive match: parent may not be command.com */
  208.     if(stricmp(cp, "melt.exe") == 0) {
  209. #else
  210.     if(strcmp(cp, "melt") == 0) {
  211. #endif
  212.  
  213.     do_melt = 1;
  214.     
  215. #ifdef MSDOS
  216.     } else if(stricmp(cp, "fcat.exe") == 0) {
  217. #else
  218.     } else if(strcmp(cp, "fcat") == 0) {
  219. #endif
  220.  
  221.     do_melt = 1;
  222.     topipe = 1;
  223.  
  224.     } else {
  225.     /* Freezing */
  226. #ifndef MSDOS
  227.     defopen(deffile);
  228. #else
  229.     cp = rindex(cp, '.');
  230.     *++cp = 'C';
  231.     *++cp = 'N';
  232.     *++cp = 'F';
  233.     *++cp = '\0';
  234.     defopen(argv[0]);
  235. #endif
  236.     }
  237. #ifdef BSD4_2
  238.     /* 4.2BSD dependent - take it out if not */
  239.     setlinebuf( stderr );
  240. #endif /* BSD4_2 */
  241.  
  242.     /* Argument Processing
  243.      * All flags are optional.
  244.      * -D => debug
  245.      * -V => print Version; debug verbose
  246.      * -d => do_melt
  247.      * -v => unquiet
  248.      * -g => greedy
  249.      * -f => force overwrite of output file
  250.      * -c => cat all output to stdout
  251.      * if a string is left, must be an input filename.
  252.      */
  253.     for (argc--, argv++; argc > 0; argc--, argv++) {
  254.     if (**argv == '-') {    /* A flag argument */
  255.         while (*++(*argv)) {    /* Process all flags in this arg */
  256.         switch (**argv) {
  257. #ifdef DEBUG
  258.             case 'D':
  259.             debug = 1;
  260.             break;
  261.             case 'V':
  262.             verbose = 1;
  263. #else
  264.             case 'V':
  265.             version();
  266. #endif /* DEBUG */
  267.             break;
  268. #ifdef MSDOS
  269.             case 'i':
  270.             case 'b':
  271.             image = O_BINARY;    /* binary (aka image) mode */
  272.             break;
  273.  
  274.             case 't':            /* text mode */
  275.             image = O_TEXT;
  276.             break;
  277. #endif
  278.             case 'v':
  279.             quiet--;
  280.             break;
  281.             case 'g':
  282.             greedy = 1;
  283.             break;
  284.             case 'd':
  285.             do_melt = 1;
  286.             break;
  287.             case 'f':
  288.             case 'F':
  289.             overwrite = 1;
  290.             force = 1;
  291.             break;
  292.             case 'c':
  293.             topipe = 1;
  294.             break;
  295.             case 'q':
  296.             quiet = 1;
  297.             break;
  298.             default:
  299.             fprintf(stderr, "Unknown flag: '%c'; ", **argv);
  300.             Usage();
  301.             exit(1);
  302.         }
  303.         }
  304.     }
  305.     else {        /* Input file name */
  306.         *fileptr++ = *argv; /* Build input file list */
  307.         *fileptr = NULL;
  308.     }
  309.     }
  310.  
  311. # ifdef DEBUG
  312.     if (verbose && !debug)
  313.     version();
  314. #endif
  315.  
  316.     if (*filelist != NULL) {
  317.     for (fileptr = filelist; *fileptr; fileptr++) {
  318.         if (**fileptr == '+' && do_melt == 0) {
  319.         tune_table(*fileptr + 1);
  320.     /* If a file type is given, but no file names */
  321.         if (filelist[1] == NULL)
  322.             goto Pipe;
  323.         continue;
  324.         }
  325.         exit_stat = 0;
  326.         if (do_melt != 0) {               /* MELTING */
  327.  
  328. #ifdef MSDOS
  329.         /* Check for .F or XF suffix; add one if necessary */
  330.         cp = *fileptr + strlen(*fileptr) - 2;
  331.         if ((*cp != '.' && *cp != 'X' && *cp != 'x') ||
  332.             (*(++cp) != 'F' && *cp != 'f')) {
  333.             strcpy(tempname, *fileptr);
  334.             *tail = '\0';
  335.             if ((cp=rindex(tempname,'.')) == NULL)
  336.             strcat(tempname, ".F");
  337.             else if(*(++cp) == '\0')
  338.             /* pseudo-extension: FOOBAR. */
  339.             strcat(tempname, "F");
  340.             else {
  341.             /* cp now points to file extension */
  342.             tail[0] = cp[1];        /* save two chars */
  343.             tail[1] = cp[2];
  344.             *(++cp) = '\0';
  345.             strcat(tempname, "XF");
  346.             }
  347.             *fileptr = tempname;
  348.         }
  349. #else
  350.         /* Check for .F suffix */
  351.         if (strcmp(*fileptr + strlen(*fileptr) - 2, ".F") != 0) {
  352.             /* No .F: tack one on */
  353.             strcpy(tempname, *fileptr);
  354.             strcat(tempname, ".F");
  355.             *fileptr = tempname;
  356.         }
  357. #endif /*MSDOS */
  358.  
  359.         /* Open input file for melting */
  360.  
  361.         if (checkstat(*fileptr))
  362.             continue;
  363.  
  364. #ifdef MSDOS
  365.         if ((freopen(*fileptr, "rb", stdin)) == NULL)
  366. #else
  367.         if ((freopen(*fileptr, "r", stdin)) == NULL)
  368. #endif
  369.         {
  370.             perror(*fileptr); continue;
  371.         }
  372.  
  373.         /* Check the magic number */
  374.         if (getchar() != MAGIC1)
  375.             goto reject;
  376.         switch (getchar()) {
  377. #ifdef COMPAT
  378.         case MAGIC2_1:
  379.             meltfunc = melt1;
  380.             break;
  381. #endif
  382.         case MAGIC2_2:
  383.             meltfunc = melt2;
  384.             break;
  385.         default: reject:
  386.             fprintf(stderr, "%s: not in frozen format\n",
  387.                 *fileptr);
  388.             continue;
  389.         }
  390.  
  391.         /* Generate output filename */
  392.         strcpy(ofname, *fileptr);
  393.         ofname[strlen(*fileptr) - 2] = '\0';  /* Strip off .F */
  394. #ifdef MSDOS
  395.         strcat(ofname, tail);
  396. #endif
  397.         } else {
  398.  
  399.             /* FREEZING */
  400. #ifdef MSDOS
  401.         cp = *fileptr + strlen(*fileptr) - 2;
  402.         if ((*cp == '.' || *cp == 'X' || *cp == 'x') &&
  403.             (*(++cp) == 'F' || *cp == 'f')) {
  404.             fprintf(stderr,"%s: already has %s suffix -- no change\n",
  405.             *fileptr,--cp); /* } */
  406. #else
  407.         if (strcmp(*fileptr + strlen(*fileptr) - 2, ".F") == 0) {
  408.             fprintf(stderr, "%s: already has .F suffix -- no change\n",
  409.             *fileptr);
  410. #endif /* MSDOS */
  411.  
  412.             continue;
  413.         }
  414.         /* Open input file for freezing */
  415.  
  416.         if (checkstat(*fileptr))
  417.             continue;
  418.  
  419. #ifdef MSDOS
  420.         if ((freopen(*fileptr, image == O_TEXT ? "rt" : "rb", stdin))
  421.             == NULL)
  422. #else
  423.         if ((freopen(*fileptr, "r", stdin)) == NULL)
  424. #endif
  425.         {
  426.             perror(*fileptr); continue;
  427.         }
  428.  
  429.         /* Generate output filename */
  430.         strcpy(ofname, *fileptr);
  431. #ifndef BSD4_2        /* Short filenames */
  432.         if ((cp = last_sep(ofname)) != NULL) cp++;
  433.         else cp = ofname;
  434. # ifdef MSDOS
  435.         if (topipe == 0 && (sufp = rindex(cp, '.')) != NULL &&
  436.             strlen(sufp) > 2) fprintf(stderr,
  437.             "%s: part of filename extension will be replaced by XF\n",
  438.             cp);
  439. # else
  440.         if (topipe == 0 && strlen(cp) > 12) {
  441.             fprintf(stderr,"%s: filename too long to tack on .F\n",cp);
  442.             continue;
  443.         }
  444. # endif /* MSDOS */
  445. #endif    /* BSD4_2        Long filenames allowed */
  446.                              
  447. #ifdef MSDOS
  448.         /* There is no difference between FOOBAR and FOOBAR. names */
  449.         if ((cp = rindex(ofname, '.')) == NULL)
  450.             strcat(ofname, ".F");
  451.         else if (cp[1] == '\0')
  452.             /* FOOBAR. case */
  453.             strcat(ofname, "F");
  454.         else {
  455.             cp[2] = '\0';
  456.             strcat(ofname, "XF");
  457.         }
  458. #else
  459.         strcat(ofname, ".F");
  460. #endif /* MSDOS */
  461.  
  462.         }
  463.         precious = 0;
  464.         /* Check for overwrite of existing file */
  465.         if (overwrite == 0 && topipe == 0) {
  466.         if (stat(ofname, &statbuf) == 0) {
  467.             char response[2];
  468.             response[0] = 'n';
  469.             fprintf(stderr, "%s already exists;", ofname);
  470. #ifndef MSDOS
  471.             if (foreground()) {
  472. #endif
  473.             fprintf(stderr,
  474.                 " do you wish to overwrite %s (y or n)? ", ofname);
  475.             fflush(stderr);
  476.             read(2, response, 2);
  477.             while (response[1] != '\n') {
  478.                 if (read(2, response+1, 1) < 0) {    /* Ack! */
  479.                 perror("stderr"); break;
  480.                 }
  481.             }
  482. #ifndef MSDOS
  483.             }
  484. #endif
  485.             if (response[0] != 'y') {
  486.             fprintf(stderr, "\tnot overwritten\n");
  487.             continue;
  488.             }
  489.         }
  490.         }
  491.         if(topipe == 0) {  /* Open output file */
  492.  
  493. #ifdef DEBUG
  494.         if (do_melt == 0 || debug == 0) {
  495. #endif
  496. #ifdef MSDOS
  497.         if (freopen(ofname, do_melt && image == O_TEXT ? "wt" : "wb",
  498.             stdout) == NULL)
  499. #else         
  500.         if (freopen(ofname, "w", stdout) == NULL)
  501. #endif
  502.         {
  503.             perror(ofname); continue;
  504.         }
  505. #ifdef DEBUG
  506.         }
  507. #endif
  508.         if(quiet != 1)  {
  509.             fprintf(stderr, "%s:", *fileptr);
  510.             indc_threshold = 2048;
  511.             indc_count = 1024;
  512.         }
  513.         }
  514.         else {    /* output is to stdout */
  515. #ifdef MSDOS
  516.             /* freeze output always binary; melt output
  517.                is binary if image == O_BINARY
  518.             */
  519.         if (do_melt == 0 || image == O_BINARY)
  520.             setmode(fileno(stdout), O_BINARY);
  521. #endif
  522.         }
  523.         /* Actually do the freezing/melting */
  524.         if (do_melt == 0)
  525.         freeze();
  526. #ifndef DEBUG
  527.         else
  528.         meltfunc();
  529. #else
  530.         else if (debug && verbose)
  531.         printcodes(meltfunc == (void(*)()) melt2);
  532.         else
  533.         meltfunc();
  534. #endif /* DEBUG */
  535.  
  536.     /* check output status, and close to make sure data is written */
  537.         if ( ferror(stdout) || (!topipe && fclose(stdout) < 0))
  538.         writeerr();
  539.  
  540.         if(topipe == 0)
  541.         copystat(*fileptr);     /* Copy stats */
  542.      }
  543.     } else {        /* Standard input */
  544. Pipe:
  545.     if (fstat(fileno(stdin), &statbuf)) {
  546.         perror("stdin");
  547.         exit(1);
  548.     }
  549.     file_length = statbuf.st_size;
  550.  
  551.     indc_threshold = file_length / 100;
  552.     if (indc_threshold < 4096)
  553.         indc_threshold = 4096;
  554. #ifdef DEBUG
  555.     fprintf(stderr, "File length: %ld\n", file_length);
  556. #endif
  557.  
  558.     topipe = 1;
  559.     if (do_melt == 0) {
  560. #ifdef MSDOS
  561.             /* freeze output always binary */
  562.             /* freeze input controlled by -i -t -b switches */
  563.         setmode(fileno(stdout), O_BINARY);
  564.         setmode(fileno(stdin), image);
  565. #endif
  566.         freeze();
  567.         if(quiet != 1)
  568.             putc('\n', stderr);
  569.     } else {
  570. #ifdef MSDOS
  571.             /* melt input always binary */
  572.             /* melt output to stdout binary if so requested */
  573.         setmode(fileno(stdin), O_BINARY);
  574.         setmode(fileno(stdout), image);
  575. #endif
  576.         /* Check the magic number */
  577.         if (getchar() != MAGIC1)
  578.             goto badstdin;
  579.         switch (getchar()) {
  580. #ifdef COMPAT
  581.         case MAGIC2_1:
  582.             meltfunc = melt1;
  583.             break;
  584. #endif
  585.         case MAGIC2_2:
  586.             meltfunc = melt2;
  587.             break;
  588.         default: badstdin:
  589.             fprintf(stderr, "stdin: not in frozen format\n");
  590.             exit(1);
  591.         }
  592.  
  593. #ifndef DEBUG
  594.         meltfunc();
  595. #else
  596.         if (debug && verbose)
  597.         printcodes(meltfunc == (void(*)()) melt2);
  598.         else
  599.         meltfunc();
  600. #endif /* DEBUG */
  601.     }
  602.     }
  603.     exit(exit_stat);
  604.     /*NOTREACHED*/
  605. }
  606.  
  607. long in_count = 1;      /* length of input */
  608. long bytes_out;         /* length of frozen output */
  609. long file_length = 0;   /* initial length of file */
  610.  
  611. /* Calculates and prints the compression ratio w/o floating point OPs */
  612.  
  613. void prratio(stream, was, is)
  614. FILE *stream;
  615. long was, is;
  616. {
  617.     register long q;        /* This works everywhere */
  618.  
  619.     if (!is) is++;
  620.  
  621.     if(was > 214748L) {     /* 2147483647/10000 */
  622.         q = was / (is / 10000L);
  623.     } else {
  624.         q = 10000L * was / is; /* Long calculations, though */
  625.     }
  626.     if (q < 0) {
  627.         putc('-', stream);
  628.         q = -q;
  629.     }
  630.     fprintf(stream, "%d.%02d%%", (int)(q / 100), (int)(q % 100));
  631. #ifdef GATHER_STAT
  632.     fprintf(stream, "(%ld / %ld)", was, is);
  633. #endif
  634. }
  635.  
  636. /* Calculates and prints bits/byte compression ratio as above */
  637.  
  638. void prbits(stream, was, is)
  639. FILE *stream;
  640. long was, is;
  641. {
  642.     register long q;
  643.  
  644.     if (!was) was++;
  645.  
  646.     if(is > 2684354L) {     /*  2147483647/800 */
  647.         q = is / (was / 800L);
  648.     } else {
  649.         q = 800L * is / was;             
  650.     }
  651.     fprintf(stream, " (%d.%02d bits)", (int)(q / 100), (int)(q % 100));
  652. }
  653.  
  654. /* From compress.c */
  655.  
  656. char *
  657. rindex(s, c)        /* For those who don't have it in libc.a */
  658. register char *s, c;
  659. {
  660.     char *p;
  661.     for (p = NULL; *s; s++)
  662.         if (*s == c)
  663.         p = s;
  664.     return(p);
  665. }
  666.  
  667. /* There was an error when reading or writing files */
  668.  
  669. void writeerr()
  670. {
  671.     if (!topipe) {
  672.     perror ( ofname );
  673.     unlink ( ofname );
  674.     }
  675.     exit ( 1 );
  676. }
  677.  
  678. void copystat(ifname)
  679. char *ifname;
  680. {
  681. #ifdef __TURBOC__
  682. struct ftime utimbuf;
  683. #endif
  684.     int mode;
  685. #ifndef __TURBOC__
  686.     time_t timep[2];
  687. #endif
  688.  
  689. #ifdef MSDOS
  690.     if (_osmajor < 3) freopen("CON","at",stdout); else      /* MS-DOS 2.xx bug */
  691. #endif
  692.  
  693.     fclose(stdout);
  694.  
  695.     if (exit_stat == 2 && (!force)) { /* No freezing: remove file.F */
  696.  
  697.     if(quiet != 1)
  698.         fprintf(stderr, "-- file unchanged\n");
  699.  
  700.     } else {            /* ***** Successful Freezing ***** */
  701.  
  702.     if (stat (ifname, &statbuf)) {  /* file disappeared ?! */
  703.         perror(ifname);
  704.         exit_stat = 1;
  705.         return;
  706.     }
  707.  
  708.     exit_stat = 0;
  709.     mode = statbuf.st_mode & 07777;
  710.     if (chmod(ofname, mode))        /* Copy modes */
  711.         perror(ofname);
  712.  
  713. #ifndef MSDOS
  714.     /* Copy ownership */
  715.     chown(ofname, (int) statbuf.st_uid, (int) statbuf.st_gid);
  716. #endif
  717.  
  718. #ifdef __TURBOC__
  719.         getftime(fileno(stdin),&utimbuf);
  720.         freopen(ofname,"rb",stdout);
  721.         setftime(fileno(stdout),&utimbuf);
  722.         fclose(stdout);
  723. #else
  724.     timep[0] = statbuf.st_atime;
  725.     timep[1] = statbuf.st_mtime;
  726.     utime(ofname, timep);    /* Update last accessed and modified times */
  727. #endif
  728.     precious = 1;
  729.     if (unlink(ifname))    /* Remove input file */
  730.         perror(ifname);
  731.     if(quiet != 1)
  732.         fprintf(stderr, " -- replaced with %s\n", ofname);
  733.     return;        /* Successful return */
  734.     }
  735.  
  736.     /* Unsuccessful return -- one of the tests failed */
  737.     if (unlink(ofname))
  738.     perror(ofname);
  739. }
  740.  
  741. /* Checks status of a file, returns 0 if the file may be frozen,
  742.     or 1 otherwise; assigns this value to exit_stat
  743. */
  744. int checkstat(ifname)
  745. char *ifname;
  746. {
  747.     if (stat (ifname, &statbuf)) {
  748.         perror(ifname);
  749.         return exit_stat = 1;
  750.     }
  751.  
  752.     /* Do NOT try to freeze /dev/null or /dev/tty ... */
  753.  
  754. #ifndef MSDOS
  755.     if ((statbuf.st_mode & S_IFMT) != S_IFREG) {
  756.         fprintf(stderr, "%s: ", ifname);
  757.         fprintf(stderr, " not a regular file -- unchanged\n");
  758.         return exit_stat = 1;
  759.  
  760.     } else if (statbuf.st_nlink > 1) {
  761.         fprintf(stderr, "%s: ", ifname);
  762.         fprintf(stderr, " has %d other links -- unchanged\n",
  763.         statbuf.st_nlink - 1);
  764.         return exit_stat = 1;
  765.     }
  766. #endif /* MSDOS */
  767.  
  768.     file_length = statbuf.st_size;
  769.  
  770.     indc_threshold = file_length / 100;
  771.     if (indc_threshold < 4096)
  772.         indc_threshold = 4096;
  773.  
  774.     return exit_stat = 0;
  775. }
  776.  
  777. #ifndef MSDOS
  778. /*
  779.  * This routine returns 1 if we are running in the foreground and stderr
  780.  * is a tty. (as in compress(1))
  781.  */
  782. int foreground()
  783. {
  784.     if(bgnd_flag != SIG_DFL)  /* background? */
  785.         return(0);
  786.     else {                          /* foreground */
  787.         if(isatty(2)) {        /* and stderr is a tty */
  788.             return(1);
  789.         } else {
  790.             return(0);
  791.         }
  792.     }
  793. }
  794. #endif
  795.  
  796. #if defined(__TURBOC__) || !defined(INT_SIG)
  797. void
  798. #endif
  799.  
  800. /* Exception handler (SIGINT) */
  801.  
  802. onintr ( ) {
  803.     if (!precious) {
  804.     fclose(stdout);
  805.     unlink ( ofname );
  806.     }
  807.     exit ( 1 );
  808. }
  809.  
  810. #if defined(__TURBOC__) || !defined(INT_SIG)
  811. void
  812. #endif
  813.  
  814. /* Exception handler (SIGSEGV) */
  815.  
  816. oops ( )        /* file is corrupt or internal error */
  817. {
  818.     fflush(stdout);
  819.     fprintf(stderr, "Segmentation violation occured...\n");
  820.     exit ( 1 );
  821. }
  822.  
  823. /* Prints version and compilation options */
  824.  
  825. void version()
  826. {
  827.     fprintf(stderr, ident, PATCHLEVEL, PATCHDATE);
  828.     fprintf(stderr, "LZSS 8192/256 + Huffman coding\nOptions: ");
  829. #ifdef COMPAT
  830.     fprintf(stderr, "compatible with vers. 1.0, ");
  831. #endif
  832. #ifdef DEBUG
  833.     fprintf(stderr, "DEBUG, ");
  834. #endif
  835. #ifdef BSD4_2
  836.     fprintf(stderr, "BSD4_2, ");
  837. #endif
  838. #ifdef  __XENIX__
  839.     fprintf(stderr, "XENIX, ");
  840. #endif
  841. #ifdef  __TURBOC__
  842.     fprintf(stderr, "TURBO, ");
  843. #endif
  844. #ifdef GATHER_STAT
  845.     fprintf(stderr, "GATHER_STAT, ");
  846. #endif
  847.     fprintf(stderr, "HASH: %d bits\n", BITS);
  848.     fprintf(stderr, "Static Huffman table: %d %d %d %d %d %d %d %d\n",
  849.         Table2[1], Table2[2], Table2[3], Table2[4],
  850.         Table2[5], Table2[6], Table2[7], Table2[8]);
  851. #ifdef MSDOS
  852.     fprintf(stderr, "Default melted mode: %s\n",
  853.             image == O_BINARY ? "binary" : "text");
  854. #endif
  855.     exit(0);
  856. }
  857.  
  858. /* Deals with static Huffman table parameters.
  859.     Input: command line option w/o leading `+'.
  860.     Output: fills the array `Table2' if OK, exit(1) otherwise.
  861. */
  862.  
  863. void tune_table(type) char *type;
  864. {
  865.     extern char * defread();
  866.     register char *s = defread(type), *t;
  867.     static int v[8];
  868.     int i, is_list = 0;
  869.     if(!s) {
  870.     /* try to consider 'type' as a list of values: n1,n2, ... */
  871.         if(rindex(type, ','))
  872.             is_list = 1;
  873.         else {
  874.             fprintf(stderr, "\"%s\" - no such file type\n", type);
  875.             exit(1);
  876.         }
  877.         if(sscanf(type, "%d,%d,%d,%d,%d,%d,%d,%d",
  878.             v, v+1, v+2, v+3, v+4, v+5, v+6, v+7) != 8) {
  879.             fprintf(stderr,
  880.                 "%s - a list of 8 numbers expected\n", type);
  881.             exit(1);
  882.         }
  883.     }
  884.     if(!is_list && (!(t = rindex(s, '=')) ||
  885.         sscanf(++t, "%d %d %d %d %d %d %d %d",
  886.         v, v+1, v+2, v+3, v+4, v+5, v+6, v+7) != 8)) {
  887.         fprintf(stderr,
  888.             "\"%s\" - invalid entry\n", type);
  889.         exit(1);
  890.     }
  891.     for(i = 0; i < 8; i++)
  892.         Table2[i+1] = v[i];
  893.     if(quiet < 0) {
  894.         if(!is_list) {
  895.             t = s;
  896.         /* make full word */
  897.             while(*s != '=' && *s != ' ' && *s != '\t') s++;
  898.             *s = '\0';
  899.         } else
  900.             t = "";
  901.         fprintf(stderr, "Using \"%s%s\" type\n", type, t);
  902.     }
  903. }
  904.  
  905. #ifdef MSDOS
  906.  
  907. /* MSDOS typically has ':' and '\\' separators, but some command
  908.   processors (and the int 21h function handler) support '/' too.
  909.   Find the last of these.
  910. */
  911.  
  912. char * last_sep(s)
  913. register char *s;
  914. {
  915.     char *p;
  916.     for (p = NULL; *s; s++)
  917.         if (*s == '/' || *s == '\\' || *s == ':')
  918.         p = s;
  919.     return(p);
  920. }
  921.  
  922. #endif    /* MSDOS */
  923.