home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume1 / 8707 / 55 < prev    next >
Encoding:
Internet Message Format  |  1990-07-13  |  22.4 KB

  1. From: ddl@husc6.UUCP (Dan Lanciani)
  2. Newsgroups: comp.sources.misc
  3. Subject: arc that UnSquashes 2/2
  4. Message-ID: <2934@ncoast.UUCP>
  5. Date: 18 Jul 87 00:39:22 GMT
  6. Sender: allbery@ncoast.UUCP
  7. Organization: Harvard University Computer Services
  8. Lines: 685
  9. Approved: allbery@ncoast.UUCP
  10. X-Archive: comp.sources.misc/8707/55
  11.  
  12. -----------continue here------------
  13.  
  14. static unsigned INT eolist(index)          /* find last duplicate */
  15. unsigned INT index;
  16. {
  17.  INT temp;
  18.  
  19.     while(temp=string_tab[index].next) /* while more duplicates */
  20.          index = temp;
  21.  
  22.     return index;
  23. }
  24.  
  25. /*  The hash() routine is used to find a spot in the hash table for a new
  26.     entry.  It performs a "hash and linear probe" lookup, using h() to
  27.     calculate the starting hash value and eolist() to perform the linear
  28.     probe.  This routine DOES NOT detect a table full condition.  That
  29.     MUST be checked for elsewhere.
  30. */
  31.  
  32. static unsigned INT hash(pred,foll)        /* find spot in the string table */
  33. unsigned INT pred;                     /* code for preceeding string */
  34. unsigned char foll;                    /* char following string */
  35. {
  36.     unsigned INT local, tempnext;      /* scratch storage */
  37.     struct entry *ep;                  /* allows faster table handling */
  38.  
  39.     local = (*h)(pred,foll);           /* get initial hash value */
  40.  
  41.     if(!string_tab[local].used)        /* if that spot is free */
  42.          return local;                 /* then that's all we need */
  43.  
  44.     else                               /* else a collision has occured */
  45.     {    local = eolist(local);        /* move to last duplicate */
  46.  
  47.          /*   We must find an empty spot. We start looking 101 places
  48.               down the table from the last duplicate.
  49.          */
  50.  
  51.          tempnext = (local+101) & 0x0FFF;
  52.          ep = &string_tab[tempnext];   /* initialize pointer */
  53.  
  54.          while(ep->used)               /* while empty spot not found */
  55.          {    if(++tempnext==TABSIZE)  /* if we are at the end */
  56.               {    tempnext = 0;       /* wrap to beginning of table*/
  57.                    ep = string_tab;
  58.               }
  59.               else ++ep;               /* point to next element in table */
  60.          }
  61.  
  62.          /*   local still has the pointer to the last duplicate, while
  63.               tempnext has the pointer to the spot we found.  We use
  64.               this to maintain the chain of pointers to duplicates.
  65.          */
  66.  
  67.          string_tab[local].next = tempnext;
  68.  
  69.          return tempnext;
  70.     }
  71. }
  72.  
  73. /*  The unhash() function is used to search the hash table for a given key.
  74.     Like hash(), it performs a hash and linear probe search.  It returns
  75.     either the number of the entry (if found) or NOT_FND (if not found).
  76. */
  77.  
  78. static unsigned INT unhash(pred,foll)      /* search string table for a key */
  79. unsigned INT pred;                     /* code of preceeding string */
  80. unsigned char foll;                    /* character following string */
  81. {
  82.     unsigned INT local, offset;        /* scratch storage */
  83.     struct entry *ep;                  /* this speeds up access */
  84.  
  85.     local = (*h)(pred,foll);           /* initial hash */
  86.  
  87.     while(1)
  88.     {    ep = &string_tab[local];      /* speed up table access */
  89.  
  90.          if((ep->predecessor==pred) && (ep->follower==foll))
  91.               return local;            /* we have a match */
  92.  
  93.          if(!ep->next)                 /* if no more duplicates */
  94.               return NOT_FND;          /* then key is not listed */
  95.  
  96.          local = ep->next;             /* move on to next duplicate */
  97.     }
  98. }
  99.  
  100. /*  The init_tab() routine is used to initialize our hash table.
  101.     You realize, of course, that "initialize" is a complete misnomer.
  102. */
  103.  
  104. static INT init_tab()                      /* set ground state in hash table */
  105. {
  106.     unsigned INT i;                    /* table index */
  107.     INT upd_tab();
  108.  
  109.     setmem((char *)string_tab,sizeof(string_tab),0);
  110.  
  111.     for(i=0; i<256; i++)               /* list all single byte strings */
  112.          upd_tab(NO_PRED,i);
  113.  
  114.     inbuf = EMPTY;                     /* nothing is in our buffer */
  115. }
  116.  
  117. /*  The upd_tab routine is used to add a new entry to the string table.
  118.     As previously stated, no checks are made to ensure that the table
  119.     has any room.  This must be done elsewhere.
  120. */
  121.  
  122. INT upd_tab(pred,foll)                     /* add an entry to the table */
  123. unsigned INT pred;                     /* code for preceeding string */
  124. unsigned INT foll;                     /* character which follows string */
  125. {
  126.     struct entry *ep;                  /* pointer to current entry */
  127.  
  128.     /* calculate offset just once */
  129.  
  130.     ep = &string_tab[hash(pred,foll)];
  131.  
  132.     ep->used = TRUE;                   /* this spot is now in use */
  133.     ep->next = 0;                      /* no duplicates after this yet */
  134.     ep->predecessor = pred;            /* note code of preceeding string */
  135.     ep->follower = foll;               /* note char after string */
  136. }
  137.  
  138. /*  This algorithm encoded a file into twelve bit strings (three nybbles).
  139.     The gocode() routine is used to read these strings a byte (or two)
  140.     at a time.
  141. */
  142.  
  143. static INT gocode(fd)                      /* read in a twelve bit code */
  144. FILE *fd;                              /* file to get code from */
  145. {
  146.     unsigned INT localbuf, returnval;
  147.  
  148.     if(inbuf==EMPTY)                   /* if on a code boundary */
  149.     {    if((localbuf=getc_unp(fd))==EOF)   /* get start of next code */
  150.               return EOF;              /* pass back end of file status */
  151.          localbuf &= 0xFF;             /* mask down to true byte value */
  152.          if((inbuf=getc_unp(fd))==EOF) /* get end of code, start of next */
  153.               return EOF;              /* this should never happen */
  154.          inbuf &= 0xFF;                /* mask down to true byte value */
  155.  
  156.          returnval = ((localbuf<<4)&0xFF0) + ((inbuf>>4)&0x00F);
  157.          inbuf &= 0x000F;              /* leave partial code pending */
  158.     }
  159.  
  160.     else                               /* buffer contains first nybble */
  161.     {    if((localbuf=getc_unp(fd))==EOF)
  162.               return EOF;
  163.          localbuf &= 0xFF;
  164.  
  165.          returnval = localbuf + ((inbuf<<8)&0xF00);
  166.          inbuf = EMPTY;                /* note no hanging nybbles */
  167.     }
  168.     return returnval;                  /* pass back assembled code */
  169. }
  170.  
  171. static INT push(c)                         /* push char onto stack */
  172. INT c;                                 /* character to push */
  173. {
  174.     stack[sp] = ((char) c);            /* coerce integer into a char */
  175.  
  176.     if(++sp >= TABSIZE)
  177.          abort("Stack overflow\n");
  178. }
  179.  
  180. static INT pop()                       /* pop character from stack */
  181. {
  182.     if(sp>0)
  183.          return ((INT) stack[--sp]);   /* leave ptr at next empty slot */
  184.  
  185.     else return EMPTY;
  186. }
  187.  
  188. /***** LEMPEL-ZEV DECOMPRESSION *****/
  189.  
  190. static INT code_count;                 /* needed to detect table full */
  191. static unsigned INT code;                  /* where we are so far */
  192. static INT firstc;                     /* true only on first character */
  193.  
  194. INT init_ucr(new)                          /* get set for uncrunching */
  195. INT new;                               /* true to use new hash function */
  196. {
  197.     if(new)                            /* set proper hash function */
  198.          h = newh;
  199.     else h = oldh;
  200.  
  201.     sp = 0;                            /* clear out the stack */
  202.     init_tab();                        /* set up atomic code definitions */
  203.     code_count = TABSIZE - 256;        /* note space left in table */
  204.     firstc = 1;                        /* true only on first code */
  205. }
  206.  
  207. INT getc_ucr(f)                        /* get next uncrunched byte */
  208. FILE *f;                               /* file containing crunched data */
  209. {
  210.     unsigned INT c;                    /* a character of input */
  211.  INT code, newcode;
  212.     static INT oldcode, finchar;
  213.     struct entry *ep;                  /* allows faster table handling */
  214.  
  215.     if(firstc)                         /* first code is always known */
  216.     {    firstc = FALSE;               /* but next will not be first */
  217.          oldcode = gocode(f);
  218.          return finchar = string_tab[oldcode].follower;
  219.     }
  220.  
  221.     if(!sp)                            /* if stack is empty */
  222.     {    if((code=newcode=gocode(f))==EOF)
  223.               return EOF;
  224.  
  225.          ep = &string_tab[code];       /* initialize pointer */
  226.  
  227.          if(!ep->used)                 /* if code isn't known */
  228.          {    code = oldcode;
  229.               ep = &string_tab[code];  /* re-initialize pointer */
  230.               push(finchar);
  231.          }
  232.  
  233.          while(ep->predecessor!=NO_PRED)
  234.          {    push(ep->follower);      /* decode string backwards */
  235.               code = ep->predecessor;
  236.               ep = &string_tab[code];
  237.          }
  238.  
  239.          push(finchar=ep->follower);   /* save first character also */
  240.  
  241.          /*   The above loop will terminate, one way or another,
  242.               with string_tab[code].follower equal to the first
  243.               character in the string.
  244.          */
  245.  
  246.          if(code_count)                /* if room left in string table */
  247.          {    upd_tab(oldcode,finchar);
  248.               --code_count;
  249.          }
  250.  
  251.          oldcode = newcode;
  252.     }
  253.  
  254.     return pop();                      /* return saved character */
  255. }
  256. SHAR_EOF
  257. fi # end of overwriting check
  258. if test -f 'arcm.h'
  259. then
  260.     echo shar: will not over-write existing file "'arcm.h'"
  261. else
  262. cat << \SHAR_EOF > 'arcm.h'
  263. /*
  264.  * $Header: arcm.h,v 1.2 86/07/15 07:53:40 turner Exp $
  265.  */
  266.  
  267. /*
  268.  * $Log:    arcm.h,v $
  269.  * Revision 1.2  86/07/15  07:53:40  turner
  270.  * 
  271.  * Revision 1.1  86/06/26  15:01:25  turner
  272.  * initial version
  273.  * 
  274.  */
  275.  
  276. /*
  277.  *
  278.  * ARC archive utility - standard MACRO insert file.
  279.  *
  280.  * parameters:
  281.  *
  282.  */
  283.  
  284. #define ARCMARK 26 /*                   special archive marker        */
  285. #define ARCVER 9   /*                   archive header version code   */
  286. #define STRLEN 100 /*                   system standard string length */
  287. #define FNLEN 13   /*                   file name length              */
  288. #define MAXARG 25  /*                   maximum number of arguments   */
  289.  
  290. #define ARC 1
  291. #define XARC 0
  292. SHAR_EOF
  293. fi # end of overwriting check
  294. if test -f 'arcmatch.c'
  295. then
  296.     echo shar: will not over-write existing file "'arcmatch.c'"
  297. else
  298. cat << \SHAR_EOF > 'arcmatch.c'
  299. static char *RCSid = "$Header: arcmatch.c,v 1.2 86/07/15 07:53:42 turner Exp $";
  300.  
  301. /*
  302.  * $Log:    arcmatch.c,v $
  303.  * Hack-attack 1.3  86/12/20  01:23:45  wilhite@usceast.uucp
  304.  *     Bludgeoned into submission for VAX 11/780 BSD4.2
  305.  *    (ugly code, but fewer core dumps)
  306.  *
  307.  * Revision 1.2  86/07/15  07:53:42  turner
  308.  * 
  309.  * Revision 1.1  86/06/26  15:00:34  turner
  310.  * initial version
  311.  * 
  312.  */
  313.  
  314. /*  ARC - Archive utility - ARCMATCH
  315.  
  316. $define(tag,$$segment(@1,$$index(@1,=)+1))#
  317. $define(version,Version $tag(
  318. TED_VERSION DB =2.17), created on $tag(
  319. TED_DATE DB =12/17/85) at $tag(
  320. TED_TIME DB =20:32:18))#
  321. $undefine(tag)#
  322.     $version
  323.  
  324. (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED
  325.  
  326.     By:  Thom Henderson
  327.  
  328.     Description:
  329.          This file contains service routines needed to maintain an archive.
  330.  
  331.     Language:
  332.          Computer Innovations Optimizing C86
  333. */
  334. #include <stdio.h>
  335. #include "arc.h"
  336.  
  337. INT match(n,t)                         /* test name against template */
  338. char *n;                               /* name to test */
  339. char *t;                               /* template to test against */
  340. {
  341.  
  342. #if MSDOS
  343.     upper(n); upper(t);                /* avoid case problems */
  344. #endif
  345.  
  346.     /* first match name part */
  347.  
  348.     while((*n && *n!='.') || (*t && *t!='.'))
  349.     {    if(*n!=*t && *t!='?')         /* match fail? */
  350.          {    if(*t!='*')              /* wildcard fail? */
  351.                    return 0;           /* then no match */
  352.               else                     /* else jump over wildcard */
  353.               {    while(*n && *n!='.')
  354.                         n++;
  355.                    while(*t && *t!='.')
  356.                         t++;
  357.                    break;              /* name part matches wildcard */
  358.               }
  359.          }
  360.          else                          /* match good for this char */
  361.          {    n++;                     /* advance to next char */
  362.               t++;
  363.          }
  364.     }
  365.  
  366.     if(*n && *n=='.') n++;             /* skip extension delimiters */
  367.     if(*t && *t=='.') t++;
  368.  
  369.     /* now match name part */
  370.  
  371.     while(*n || *t)
  372.     {    if(*n!=*t && *t!='?')         /* match fail? */
  373.          {    if(*t!='*')              /* wildcard fail? */
  374.                    return 0;           /* then no match */
  375.               else return 1;           /* else good enough */
  376.          }
  377.          else                          /* match good for this char */
  378.          {    n++;                     /* advance to next char */
  379.               t++;
  380.          }
  381.     }
  382.  
  383.     return 1;                          /* match worked */
  384. }
  385.  
  386. INT rempath(nargs,arg)                     /* remove paths from filenames */
  387. INT nargs;                             /* number of names */
  388. char *arg[];                           /* pointers to names */
  389. {
  390.     char *i, *rindex();                /* string index, reverse indexer */
  391.  INT n;                             /* index */
  392.  
  393.     for(n=0; n<nargs; n++)             /* for each supplied name */
  394.     {    if(!(i=rindex(arg[n],'\\')))  /* search for end of path */
  395.               if(!(i=rindex(arg[n],'/')))
  396.                    i=rindex(arg[n],':');
  397.          if(i)                         /* if path was found */
  398.               arg[n] = i+1;            /* then skip it */
  399.     }
  400. }
  401. SHAR_EOF
  402. fi # end of overwriting check
  403. if test -f 'arcmisc.c'
  404. then
  405.     echo shar: will not over-write existing file "'arcmisc.c'"
  406. else
  407. cat << \SHAR_EOF > 'arcmisc.c'
  408. #include <stdio.h>
  409. #include "arc.h"
  410.  
  411. /*    split up a file name (subroutine for makefnam)
  412.  *
  413.  * Hack-attack 1.3  86/12/20  01:23:45  wilhite@usceast.uucp
  414.  *     Bludgeoned into submission for VAX 11/780 BSD4.2
  415.  *    (ugly code, but fewer core dumps)
  416. */
  417.  
  418. static INT _makefn(source,dest)
  419. unsigned char *source;
  420. unsigned char *dest;
  421. {
  422.  INT j;
  423.  
  424.     setmem (dest, 17, 0);    /* clear result field */
  425.     if (strlen (source) > 1 && source[1] == ':')
  426.     for (j = 0; j < 2;)
  427.         dest[j++] = *source++;
  428.     for (j = 3; *source && *source != '.'; ++source)
  429.     if (j < 11)
  430.         dest[j++] = *source;
  431.     for (j = 12; *source; ++source)
  432.     if (j < 16)
  433.         dest[j++] = *source;
  434. }
  435. /*    make a file name using a template
  436. */
  437.  
  438. char *makefnam(rawfn,template,result)
  439. unsigned char *rawfn;            /* the original file name */
  440. unsigned char *template;        /* the template data */
  441. unsigned char *result;            /* where to place the result */
  442. {
  443.   unsigned char et[17],er[17];
  444.  
  445.   _makefn(template,et);
  446.   _makefn(rawfn,er);
  447.   *result=0;            /* assure no data */
  448.   strcat(result,er[0]?er:et);
  449.   strcat(result,er[3]?er+3:et+3);
  450.   strcat(result,er[12]?er+12:et+12);
  451.   return ((char *)&result[0]);
  452. }
  453.  
  454. INT freedir(dirs)
  455. register struct direct **dirs;
  456. {
  457.     register INT ii;
  458.  
  459.     if(dirs == (struct direct **)0)
  460.         return(-1);
  461.     for(ii = 0; dirs[ii] != (struct direct *)0; ii++)
  462.         free(dirs[ii]);
  463.     free(dirs);
  464.     return(0);
  465. }
  466.  
  467. #if MSDOS
  468. #include <dir.h>
  469.  
  470. INT alphasort(dirptr1, dirptr2)
  471. struct direct **dirptr1, **dirptr2;
  472. {
  473.     return(strcmp((*dirptr1)->d_name, (*dirptr2)->d_name));
  474. }
  475.  
  476. #endif
  477. SHAR_EOF
  478. fi # end of overwriting check
  479. if test -f 'arcpack.c'
  480. then
  481.     echo shar: will not over-write existing file "'arcpack.c'"
  482. else
  483. cat << \SHAR_EOF > 'arcpack.c'
  484. static char *RCSid = "$Header: arcpack.c,v 1.2 86/07/15 07:53:48 turner Exp $";
  485.  
  486. /*
  487.  * $Log:    arcpack.c,v $
  488.  * Hack-attack 1.3  86/12/20  01:23:45  wilhite@usceast.uucp
  489.  *     Bludgeoned into submission for VAX 11/780 BSD4.2
  490.  *    (ugly code, but fewer core dumps)
  491.  *
  492.  * Revision 1.2  86/07/15  07:53:48  turner
  493.  * 
  494.  * Revision 1.1  86/06/26  15:00:37  turner
  495.  * initial version
  496.  * 
  497.  */
  498.  
  499. /*  ARC - Archive utility - ARCPACK
  500.  
  501. $define(tag,$$segment(@1,$$index(@1,=)+1))#
  502. $define(version,Version $tag(
  503. TED_VERSION DB =3.37), created on $tag(
  504. TED_DATE DB =02/03/86) at $tag(
  505. TED_TIME DB =22:58:01))#
  506. $undefine(tag)#
  507.     $version
  508.  
  509. (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED
  510.  
  511.     By:  Thom Henderson
  512.  
  513.     Description:
  514.          This file contains the routines used to compress a file
  515.          when placing it in an archive.
  516.  
  517.     Language:
  518.          Computer Innovations Optimizing C86
  519. */
  520. #include <stdio.h>
  521. #include "arc.h"
  522.  
  523. /* stuff for non-repeat packing */
  524.  
  525. #define DLE 0x90                       /* repeat sequence marker */
  526.  
  527. static unsigned char state;            /* current packing state */
  528.  
  529. /* non-repeat packing states */
  530.  
  531. #define NOHIST  0                      /* don't consider previous input*/
  532. #define SENTCHAR 1                     /* lastchar set, no lookahead yet */
  533. #define SENDNEWC 2                     /* run over, send new char next */
  534. #define SENDCNT 3                      /* newchar set, send count next */
  535.  
  536. /* packing results */
  537.  
  538. static long stdlen;                    /* length for standard packing */
  539. static INT crcval;                     /* CRC check value */
  540.  
  541. INT pack(f,t,hdr)                          /* pack file into an archive */
  542. FILE *f, *t;                           /* source, destination */
  543. struct heads *hdr;                     /* pointer to header data */
  544. {
  545.  INT c;                             /* one character of stream */
  546.     long ncrlen;                       /* length after packing */
  547.     long huflen;                       /* length after squeezing */
  548.     long lzwlen;                       /* length after crunching */
  549.     long pred_sq(), file_sq();         /* stuff for squeezing */
  550.     long pred_cm();                    /* dynamic crunching cleanup */
  551.     char tnam[STRLEN];                /* temporary name buffer */
  552.     char *makefnam();                  /* filename fixer upper */
  553.     FILE *crn = NULL;                  /* temporary crunch file */
  554.     INT getch();
  555.     INT getc_ncr();
  556.     INT putc_pak();
  557.  
  558.     /* first pass - see which method is best */
  559.  
  560.     if(!nocomp)                        /* if storage kludge not active */
  561.     {    if(note)
  562.             { printf(" analyzing, "); fflush(stdout);}
  563.  
  564.          if(arctemp)                   /* use temp area if specified */
  565.               sprintf(tnam,"%s.CRN",arctemp);
  566.          else makefnam("$ARCTEMP.CRN",arcname,tnam);
  567. #if MSDOS
  568.          crn = fopen(tnam,"wrb");
  569. #endif
  570. #if BSD | ST
  571.          crn = fopen(tnam,"w+");
  572. #endif
  573.          state = NOHIST;               /* initialize ncr packing */
  574.          stdlen =  ncrlen = 0;         /* reset size counters */
  575.          crcval = 0;                   /* initialize CRC check value */
  576.          setcode();                    /* initialize encryption */
  577.  
  578.          init_cm(f,crn);               /* initialize for crunching */
  579.          init_sq();                    /* initialize for squeeze scan */
  580.  
  581.          while((c=getc_ncr(f))!=EOF)   /* for each byte of file */
  582.          {    ncrlen++;                /* one more packed byte */
  583.               scan_sq(c);              /* see what squeezing can do */
  584.               putc_cm(c,crn);          /* see what crunching can do */
  585.          }
  586.          huflen = pred_sq();           /* finish up after squeezing */
  587.          lzwlen = pred_cm(crn);        /* finish up after crunching */
  588.     }
  589.     else                               /* else kludge the method */
  590.     {    stdlen = 0;                   /* make standard look best */
  591.          ncrlen = huflen = lzwlen = 1;
  592.     }
  593.  
  594.     /* standard set-ups common to all methods */
  595.  
  596.     fseek(f,0L,0);                     /* rewind input */
  597.     hdr->crc = crcval;                 /* note CRC check value */
  598.     hdr->length = stdlen;              /* set actual file length */
  599.     state = NOHIST;                    /* reinitialize ncr packing */
  600.     setcode();                         /* reinitialize encryption */
  601.  
  602.     /* choose and use the shortest method */
  603.  
  604.     if(stdlen<=ncrlen && stdlen<=huflen && stdlen<=lzwlen)
  605.     {    if(kludge)                    /*DEBUG*/
  606.               printf("(%ld) ",lzwlen-stdlen);
  607.          if(note)
  608.           { printf("storing, "); fflush(stdout);}/* store w/out compression */
  609.          hdrver = 2;                   /* note packing method */
  610.          stdlen = crcval = 0;          /* recalc these for kludge */
  611.          while((c=getch(f))!=EOF)      /* store it straight */
  612.               putc_pak(c,t);
  613.          hdr->crc = crcval;
  614.          hdr->length = hdr->size = stdlen;
  615.     }
  616.  
  617.     else if(ncrlen<huflen && ncrlen<lzwlen)
  618.     {    if(kludge)                    /*DEBUG*/
  619.               printf("(%ld) ",lzwlen-ncrlen);
  620.          if(note)
  621.               { printf("packing, ");
  622.               fflush(stdout);} /* pack w/repeat suppression */
  623.          hdrver = 3;                   /* note packing method */
  624.          hdr->size = ncrlen;           /* set data length */
  625.          while((c=getc_ncr(f))!=EOF)
  626.               putc_pak(c,t);
  627.     }
  628.  
  629.     else if(huflen<lzwlen)
  630.     {    if(kludge)                    /*DEBUG*/
  631.               printf("(%ld) ",lzwlen-huflen);
  632.          if(note)
  633.             { printf("squeezing, "); fflush(stdout);}
  634.          hdrver = 4;                   /* note packing method */
  635.          hdr->size = file_sq(f,t);     /* note final size */
  636.     }
  637.  
  638.     else
  639.     {    if(kludge)                    /*DEBUG*/
  640.               printf("(%ld) ",huflen-lzwlen);
  641.          if(note)
  642.             { printf("crunching, "); fflush(stdout);}
  643.          hdrver = 8;
  644.          hdr->size = lzwlen;           /* size should not change */
  645.          if(crn)                       /* if temp was created */
  646.          {    fseek(crn,0L,0);         /* then copy over crunched temp */
  647.               while((c=fgetc(crn))!=EOF)
  648.                    putc_tst(c,t);
  649.          }
  650.          else                          /* else re-crunch */
  651.          {    init_cm(f,t);
  652.               while((c=getc_ncr(f))!=EOF)
  653.                    putc_cm(c,t);
  654.               pred_cm(t);              /* finish up after crunching */
  655.          }
  656.     }
  657.  
  658.     /* standard cleanups common to all methods */
  659.  
  660.     if(crn)                            /* get rid of crunch temporary */
  661.     {    fclose(crn);
  662.          if(unlink(tnam) && warn)
  663.          {    printf("Cannot delete temporary file %s\n",tnam);
  664.               nerrs++;
  665.          }
  666.     }
  667.     if(note)
  668.          printf("done.\n");
  669. }
  670.  
  671. /*  Non-repeat compression - text is passed through normally, except that
  672.     a run of more than two is encoded as:
  673.  
  674.          <char> <DLE> <count>
  675.  
  676.     Special case: a count of zero indicates that the DLE is really a DLE,
  677.     not a repeat marker.
  678. */
  679.  
  680. INT getc_ncr(f)                        /* get bytes with collapsed runs */
  681. FILE *f;                               /* file to get from */
  682. {
  683.     static INT lastc;                  /* value returned on last call */
  684.     static INT repcnt;                 /* repetition counter */
  685.     static INT c;                      /* latest value seen */
  686.  
  687.     switch(state)                      /* depends on our state */
  688.     {
  689.     case NOHIST:                       /* no relevant history */
  690.          state = S
  691.