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