home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 181.lha / Backup_v2.01 / backup.c < prev    next >
C/C++ Source or Header  |  1988-11-05  |  37KB  |  1,795 lines

  1.  
  2. /*
  3.  * BACKUP.C
  4.  *
  5.  * (C)Copyright 1986-88, Matthew Dillon, All Rights Reserved.
  6.  * Permission is granted to distribute for non-profit only.
  7.  *
  8.  *  Thanks to Jan Sven Trabandt for finding some major bugs!
  9.  *
  10.  * This program will backup a filesystem or directory, creating a single
  11.  * output file which can later be RESTORE'd from.  It is a quick way to
  12.  * backup your work to a 'backup' disk.
  13.  *
  14.  *  backup [options] path path path ... path [-ooutputfile]
  15.  *
  16.  *    NOTE:    if -o is not specified, not output file will be created
  17.  *
  18.  *  options:
  19.  *
  20.  *    -A       ARCHIVE.  Clear the archive bit on backed up files
  21.  *
  22.  *    -U       UPDATE.     Backup only those files which have the archive bit
  23.  *           cleared.
  24.  *
  25.  *    -f[#KB]  Floppy... actually, this option is used to force the backup
  26.  *           program to automatically split up the backup files in #KB
  27.  *           sections (default 800).  I.E.  -f with nothing else will
  28.  *           use 800KB chunks.  -f200 would use 200KB chunks, etc...
  29.  *
  30.  *           PLEASE SEE THE DOCS FOR MORE INFORMATION ON FLOPPY BACKUP
  31.  *           AND RESTORE
  32.  *
  33.  *    -Fvol    example: -FDF0: -FDF1:  This command specifies the ordering
  34.  *           and number of (floppy) drives to backup to.  This allows
  35.  *           one to change floppies in one drive while it is backing up
  36.  *           to another.  It automatically cycles through the drives but
  37.  *           you still must specify an initial output file (-ofile) to
  38.  *           determine the base name for the files.
  39.  *
  40.  *           This command also forces user prompting.
  41.  *
  42.  *           PLEASE SEE THE DOCS FOR MORE INFORMATION ON FLOPPY BACKUP
  43.  *           AND RESTORE
  44.  *
  45.  *    -b       backup    (default if executable name is 'backup')
  46.  *
  47.  *    -r       restore    (default if executable nam is 'restore')
  48.  *
  49.  *    -a       append to the destination file.
  50.  *
  51.  *    -c       Compress files during backup
  52.  *
  53.  *    -s       Only display directories as we go along.
  54.  *
  55.  *    -l/-t    (either option) Causes a RESTORE to only LIST the files,
  56.  *           not do an actual restore.
  57.  *
  58.  *    -T       (Restore) TIMESTAMP, COMMENT, AND PROTECTION BITS ONLY.
  59.  *           NO files are created.  It is assumed the files already
  60.  *           exist.  The timestamp and other fields are transfered
  61.  *           from the backup file to the already-restored files (useful
  62.  *           if the files were restored with a copy command that did
  63.  *           non copy the timestamps.  Even if the backup file is old,
  64.  *           you can recover most of your time data).
  65.  *
  66.  *    -S       Silent.    Don't display files or directories.
  67.  *
  68.  *    -nKB     Set buffer size to use, in KB.
  69.  *
  70.  *    -v       Verbose... Additionaly, display those files which will NOT
  71.  *           be backed up.
  72.  *
  73.  *    -pPAT    only file-paths matching this pattern are backed up.  You
  74.  *           may specify more than one '-p' option.
  75.  *
  76.  *    -dPAT    file-paths matching this pattern are NOT backed up.  you
  77.  *           may specify more than one '-d' option.
  78.  *
  79.  *    -ofile   Output File
  80.  *
  81.  * ---------------------------------------------------------------------
  82.  *
  83.  * destination file format:
  84.  *
  85.  *  HDR = <HDR><N.B><datestamp>             -Backup Date
  86.  *  VOL = <VOL><name_size.B><name>            -VOLUME base
  87.  *  DDS = <DDS><name_size.B><name>            -down-directory
  88.  *  END = <END><0.B>                    -up directory
  89.  *  DAT = <DAT><N.B><datestamp>             -datestamp for file
  90.  *  PRO = <PRO><4.B><protection>            -protection for file
  91.  *  COM = <COM><N.B><comment>                -comment for file
  92.  *  FIL0= <FIL0><N.B><name><size.L><data>        -uncompressed file
  93.  *  FIL1= <FIL1><N.B><name><size.L><usize.L><data>  -compressed form #1
  94.  *  INC = <INC><12.B><ttlsize><strt><segsize>        -next file is part of an
  95.  *                             incomplete file
  96.  */
  97.  
  98. #include <stdio.h>
  99. #include <fcntl.h>
  100. #include <local/typedefs.h>
  101.  
  102. #define SDIR    struct _SDIR
  103. #define SCOMP    struct _SCOMP
  104.  
  105. SCOMP {
  106.     MNODE   Node;
  107.     uword   Bytes;    /*  allocated bytes            */
  108.     uword   N;
  109. };
  110.  
  111. SDIR {
  112.     MNODE   Node;    /*  node in dir tree            */
  113.     ubyte   Type;    /*  XDDS or XVOL            */
  114.     ubyte   HaveFile;    /*  Something was backed up in here */
  115.     char    *Element;    /*  path element            */
  116. };
  117.  
  118. #define XVOL    0x01
  119. #define XDDS    0x02
  120. #define XEND    0x03
  121. #define XDAT    0x04
  122. #define XPRO    0x05
  123. #define XCOM    0x06
  124. #define XFIL0    0x87
  125. #define XFIL1    0x88
  126. #define XHDR    0x09
  127. #define XINC    0x0A
  128.  
  129. ubyte    Break;
  130. ubyte    Restore;
  131. ubyte    ListOnly;
  132. ubyte    ShowFiles = 1;
  133. ubyte    ShowDirs  = 1;
  134. ubyte    Verbose;
  135. ubyte    Archive;
  136. ubyte    Update;
  137. ubyte    Append;
  138. ubyte    Compress;
  139. ubyte    TimeStampOnly;
  140. char    *OutFile;
  141. long    BacBytes;
  142. short    BacCnt = 1;
  143.  
  144. uword    NumPicks;
  145. uword    NumDels;
  146. char    *Picks[32];
  147. char    *Dels[32];
  148.  
  149. char DirPath[256];
  150. short DPLen;
  151.  
  152. long    BufSize = 65536;
  153. long    BufI;
  154. ubyte    *Buf;
  155. long    InBufSize = 8192;
  156. long    InBufI, InBufN;
  157. ubyte    *InBuf;
  158.  
  159. MLIST    VList;        /*    Volume list (-F), of NODEs              */
  160. MLIST    DList;        /*    Directory Stack             */
  161. long    CLen;        /*    Actual compressed file output length    */
  162. MLIST    CList;        /*    List of memory buffers            */
  163. SCOMP    *CWrite;    /*    Current memory buffer pointer        */
  164.  
  165. extern int Enable_Abort;
  166. extern void seekinputend();
  167. extern FIB *GetFileInfo();
  168. extern SCOMP *NewSComp();
  169. extern void *malloc(), *GetHead(), *GetTail(), *GetSucc(), *GetPred();
  170.  
  171. main(ac, av)
  172. char *av[];
  173. {
  174.     register short i, notdone;
  175.     register char  *str;
  176.  
  177.     NewList(&VList);
  178.     NewList(&DList);
  179.     NewList(&CList);
  180.  
  181.     Enable_Abort = 0;
  182.  
  183.  
  184.     for (str = av[0] + strlen(av[0]); str >= av[0] && *str != '/' && *str != ':'; --str);
  185.     ++str;
  186.     if ((*str|0x20) == 'r')
  187.     Restore = 1;
  188.  
  189.     if (ac == 1) {
  190.     printf("Backup/Restore V2.01, (c)Copyright 1988 Matthew Dillon, All Rights Reserved\n", str);
  191.     printf("%s -rbactlvASTU -d<pat> -p<pat> -f[#kb] -F<vol> -n<#kb> -ofile\n", str);
  192.     }
  193.  
  194.     for (i = 1; i < ac; ++i) {
  195.     str = av[i];
  196.     if (*str != '-')
  197.         continue;
  198.     notdone = 1;
  199.     ++str;
  200.     while (notdone && *str) {
  201.         switch(*str) {
  202.         case 'r':
  203.         Restore = 1;
  204.         break;
  205.         case 'b':
  206.         Restore = 0;
  207.         break;
  208.         case 'a':
  209.         Append = 1;
  210.         break;
  211.         case 'c':
  212.         Compress = 1;
  213.         break;
  214.         case 'd':
  215.         Dels[NumDels++] = str + 1;
  216.         notdone = 0;
  217.         break;
  218.         case 'f':
  219.         BacBytes = 800 * 1024;
  220.         if (str[1] >= '0' && str[1] <= '9') {
  221.             BacBytes = atoi(str+1) * 1024;
  222.             notdone = 0;
  223.         }
  224.         break;
  225.         case 'F':
  226.         {                    /*    strlen(str+1)+1 */
  227.             register NODE *node = malloc(sizeof(NODE)+strlen(str));
  228.             node->ln_Name = (char *)(node+1);
  229.             strcpy(node+1, str+1);
  230.             AddTail(&VList, node);
  231.         }
  232.         notdone = 0;
  233.         break;
  234.         case 'n':
  235.         BufSize = atoi(str+1) * 1024;
  236.         if (BufSize <= 0)
  237.             BufSize = 65536;
  238.         notdone = 0;
  239.         break;
  240.         case 'o':
  241.         OutFile = str + 1;
  242.         notdone = 0;
  243.         break;
  244.         case 'p':
  245.         Picks[NumPicks++] = str + 1;
  246.         notdone = 0;
  247.         break;
  248.         case 's':
  249.         ShowFiles = 0;
  250.         break;
  251.         case 't':
  252.         case 'l':
  253.         ListOnly = 1;
  254.         break;
  255.         case 'v':
  256.         Verbose= 1;
  257.         break;
  258.         case 'A':
  259.         Archive= 1;
  260.         break;
  261.         case 'S':
  262.         ShowFiles = 0;
  263.         ShowDirs  = 0;
  264.         break;
  265.         case 'T':
  266.         TimeStampOnly = 1;
  267.         break;
  268.         case 'U':
  269.         Update = 1;
  270.         break;
  271.         default:
  272.         puts("failure");
  273.         exit(20);
  274.         }
  275.         ++str;
  276.     }
  277.     }
  278.     Buf = malloc(BufSize);
  279.     if (Buf == NULL) {
  280.     printf("Unable to malloc %ld bytes\n", BufSize);
  281.     exit(20);
  282.     }
  283.     if (ListOnly)
  284.     InBufSize = 512;    /*  small buffer to avoid read overhead */
  285.                 /*  since we are skipping the meat    */
  286.  
  287.     InBuf = malloc(InBufSize);
  288.     if (InBuf == NULL) {
  289.     printf("Unable to malloc %ld bytes\n", InBufSize);
  290.     exit(20);
  291.     }
  292.  
  293.     if (Restore)
  294.     RestoreFiles(ac,av);
  295.     else
  296.     BackupFiles(ac,av);
  297. }
  298.  
  299. long SaveLock;
  300.  
  301. BackupFiles(ac, av)
  302. char *av[];
  303. {
  304.     register short i;
  305.     register char *str, *ptr;
  306.     char notdone;
  307.  
  308.     if (OutFile && openoutput(OutFile, Append, ((BacBytes)?1:0)) == 0)
  309.     exit(20);
  310.     if (OutFile) {      /*  write header    */
  311.     DATESTAMP Date;
  312.     DateStamp(&Date);
  313.     outentry(XHDR, sizeof(DATESTAMP), &Date);
  314.     }
  315.  
  316.     SaveLock = CurrentDir(DupLock(((PROC *)FindTask(NULL))->pr_CurrentDir));
  317.  
  318.     for (i = 1; i < ac; ++i) {
  319.     str = av[i];
  320.     if (*str == '-')
  321.         continue;
  322.     /*
  323.      *  Push DDS entries for each name segment of the path
  324.      */
  325.  
  326.     notdone = 1;
  327.     while (notdone) {
  328.         for (ptr = str; *ptr && *ptr != ':' && *ptr != '/'; ++ptr);
  329.         switch(*ptr) {
  330.         case '/':   /*  normal directory    */
  331.         *ptr = 0;
  332.         PushDir(str, XDDS);
  333.         str = ptr + 1;
  334.         *ptr = '/';
  335.         break;
  336.         case ':':   /*  volume              */
  337.         *ptr = 0;
  338.         PushDir(str, XVOL);
  339.         str = ptr + 1;
  340.         *ptr = ':';
  341.         break;
  342.         default:    /*  directory or file    */
  343.         {
  344.             char *path = av[i];
  345.             FIB *fib;
  346.             long lock;
  347.  
  348.             if (fib = GetFileInfo(path, &lock)) {
  349.             if (fib->fib_DirEntryType > 0) {
  350.                 if (str[0])
  351.                 PushDir(str, XDDS);
  352.                 lock = scan_directory(fib, lock);
  353.                 if (str[0])
  354.                 PopDirs(1);
  355.             } else {
  356.                 lock = scan_file(fib, lock);
  357.             }
  358.             FreeFileInfo(fib, lock);
  359.             } else {
  360.             printf("Unable to get info for %s\n", av[i]);
  361.             }
  362.         }
  363.         notdone = 0;
  364.         break;
  365.         }
  366.     }
  367.     PopDirs(-1);
  368.     }
  369.  
  370.     UnLock(CurrentDir(SaveLock));
  371.     if (OutFile)
  372.     closeoutput();
  373. }
  374.  
  375. DATESTAMP Date;
  376. char Comment[256];
  377. char Scr[256];
  378. long Protection;
  379. long IncSize;        /*  Size of entire file     */
  380. long IncSeek;        /*  Seek offset into file   */
  381. long IncLen;        /*  # bytes in this segment */
  382.  
  383. RestoreFiles(ac, av)
  384. char *av[];
  385. {
  386.     register short i;
  387.     register char *str;
  388.     char notdone;
  389.     char havedate;
  390.     char havepro;
  391.     char havecom;
  392.     char haveinc;
  393.     long bytes;
  394.     long actual;
  395.     long lock;
  396.  
  397.     SaveLock = CurrentDir(lock = DupLock(((PROC *)FindTask(NULL))->pr_CurrentDir));
  398.  
  399.     for (i = 1; i < ac; ++i) {
  400.     str = av[i];
  401.     if (*str == '-')
  402.         continue;
  403.     if (openinput(str) == 0) {
  404.         printf("Unable to open %s for input\n", str);
  405.         continue;
  406.     }
  407.     notdone = 1;
  408.     havedate = havepro = havecom = haveinc = 0;
  409.     while (notdone) {
  410.         short c = oreadchar();
  411.         short l = oreadchar();
  412.         switch(c) {
  413.         case -1:
  414.         notdone = 0;
  415.         break;
  416.         case XVOL:
  417.         oread(Scr, l);
  418.         Scr[l] = 0;
  419.         if (OutFile) {      /*  Restore to OutFile instead  */
  420.             register short j = strlen(OutFile);
  421.             strcpy(Scr, OutFile);
  422.             if (j && OutFile[j-1] == '/') {
  423.             c = XDDS;
  424.             Scr[j-1] = 0;
  425.             } else if (j && OutFile[j-1] == ':') {
  426.             c = XVOL;
  427.             Scr[j-1] = 0;
  428.             } else
  429.             c = XDDS;
  430.         }
  431.         PushDir(Scr, c);
  432.         if (ListOnly)
  433.             break;
  434.         lock = Lock(DirPath, SHARED_LOCK);  /*  DirPath incs ':'    */
  435.         if (lock == NULL && c == XDDS) {
  436.             if (lock = CreateDir(Scr))      /*  Scr excludes '/'    */
  437.             UnLock(lock);
  438.             lock = Lock(Scr, SHARED_LOCK);
  439.         }
  440.         {
  441.             SDIR *sd = GetTail(&DList);
  442.             sd->HaveFile = 1;            /*    don't remove dir    */
  443.         }
  444.         if (lock == NULL) {
  445.             printf("Unable to create directory %s\n", Scr);
  446.             notdone = 0;
  447.         } else {
  448.             UnLock(CurrentDir(lock));
  449.         }
  450.         break;
  451.         case XDDS:
  452.         oread(Scr, l);
  453.         Scr[l] = 0;
  454.         PushDir(Scr, XDDS);
  455.         if (ListOnly)
  456.             break;
  457.         lock = Lock(Scr, SHARED_LOCK);
  458.         if (lock == NULL) {
  459.             if (lock = CreateDir(Scr))
  460.             UnLock(lock);
  461.             lock = Lock(Scr, SHARED_LOCK);
  462.         } else {
  463.             SDIR *sd = GetTail(&DList);
  464.             sd->HaveFile = 1;            /*    don't remove dir    */
  465.         }
  466.         if (lock == NULL) {
  467.             printf("Unable to create directory %s\n", Scr);
  468.             notdone = 0;
  469.         } else {
  470.             UnLock(CurrentDir(lock));
  471.         }
  472.         break;
  473.         case XEND:
  474.         {
  475.             SDIR *sd = GetTail(&DList);
  476.             ubyte type;
  477.  
  478.             c = 1;
  479.             if (!sd)
  480.             break;
  481.             type = sd->Type;
  482.             strcpy(Scr, sd->Element);
  483.             c = PopDirs(1);
  484.             if (ListOnly)
  485.             break;
  486.             if (type == XVOL)   /*  no parent directory */
  487.             break;
  488.             lock = ParentDir(lock);
  489.             if (lock == NULL) {
  490.             puts("Unable to ParentDir!");
  491.             notdone = 0;
  492.             } else {
  493.             if (c == 0)
  494.                 DeleteFile(Scr);
  495.             UnLock(CurrentDir(lock));
  496.             }
  497.         }
  498.         break;
  499.         case XDAT:
  500.         if (l != sizeof(DATESTAMP)) {
  501.             puts("expected sizeof datestamp");
  502.             notdone = 0;
  503.             break;
  504.         }
  505.         oread(&Date, l);
  506.         havedate = 1;
  507.         break;
  508.         case XPRO:
  509.         if (l != 4) {
  510.             puts("Expected 4 bytes for protection");
  511.             notdone = 0;
  512.             break;
  513.         }
  514.         oread(&Protection, l);
  515.         havepro = 1;
  516.         break;
  517.         case XCOM:
  518.         oread(Comment, l);
  519.         Comment[l] = 0;
  520.         havecom = 1;
  521.         break;
  522.         case XFIL0:
  523.         case XFIL1:
  524.         if (!havepro)
  525.             Protection = 0;
  526.         if (!havecom)
  527.             Comment[0] = 0;
  528.         if (!havedate)
  529.             DateStamp(&Date);
  530.         if (!haveinc)
  531.             IncSize = 0;
  532.  
  533.         oread(Scr, l);
  534.         Scr[l] = 0;
  535.         oread(&bytes, 4);       /*  length of file  */
  536.         actual = bytes;
  537.         if (c == XFIL1) {
  538.             oread(&actual, 4);
  539.             bytes -= 4;
  540.         }
  541.         setinputbound(bytes);
  542.         {
  543.             short res = read_file(c, Scr, bytes, actual);
  544.             seekinputend();
  545.             if (res < 0)
  546.             goto bend;
  547.         }
  548.         if (ListOnly)
  549.             goto bend;
  550.         if (Archive)
  551.             SetProtection(Scr, Protection|FIBF_ARCHIVE);
  552.         else
  553.             SetProtection(Scr, Protection&~FIBF_ARCHIVE);
  554.         if (havedate)
  555.             setfiledate(Scr, &Date);
  556.         if (havecom && Comment[0])
  557.             SetComment(Scr, Comment);
  558. bend:
  559.         havecom = havedate = havepro = haveinc = 0;
  560.         break;
  561.         case XHDR:
  562.         if (l != sizeof(DATESTAMP)) {
  563.             puts("expected sizeof datestamp");
  564.             notdone = 0;
  565.             break;
  566.         }
  567.         oread(&Date, l);
  568.         printf(" ----- BACKUP ----- BACKUP DATE: %s\n", datetos(&Date, Scr, NULL));
  569.         break;
  570.         case XINC:
  571.         if (l != 12) {
  572.             puts("expected 12 bytes for XINC");
  573.             notdone = 0;
  574.             break;
  575.         }
  576.         oread(&IncSize, 4);
  577.         oread(&IncSeek, 4);
  578.         oread(&IncLen,  4);
  579.         haveinc = 1;
  580.         break;
  581.         default:
  582.         printf("Unknown Record Type: %02x\n", c);
  583.         notdone = 0;
  584.         break;
  585.         }
  586.         setinputbound(-1);
  587.         if (mycheckbreak()) {
  588.         Break = 1;
  589.         notdone = 0;
  590.         break;
  591.         }
  592.     }
  593.     if (Break)
  594.         break;
  595.     }
  596.     UnLock(CurrentDir(SaveLock));
  597. }
  598.  
  599. FIB *
  600. GetFileInfo(path, plock)
  601. char *path;
  602. long *plock;
  603. {
  604.     register long lock;
  605.     register FIB *fib;
  606.  
  607.     *plock = NULL;
  608.     if (lock = Lock(path, SHARED_LOCK)) {
  609.     if (fib = malloc(sizeof(FIB))) {
  610.         if (Examine(lock, fib)) {
  611.         *plock = lock;
  612.         return(fib);
  613.         }
  614.         free(fib);
  615.     }
  616.     UnLock(lock);
  617.     }
  618.     return(NULL);
  619. }
  620.  
  621. FreeFileInfo(fib, lock)
  622. FIB *fib;
  623. long lock;
  624. {
  625.     if (fib)
  626.     free(fib);
  627.     if (lock)
  628.     UnLock(lock);
  629. }
  630.  
  631.  
  632. PushDir(element, type)
  633. char *element;
  634. {
  635.     register SDIR *sd = malloc(sizeof(SDIR));
  636.     register char *str = malloc(strlen(element)+1);
  637.  
  638.     strcpy(str, element);
  639.     sd->Type = type;
  640.     sd->HaveFile = 0;
  641.     sd->Element = str;
  642.     AddTail(&DList, sd);
  643.     strcat(DirPath+DPLen, str);
  644.     if (type == XVOL)
  645.     strcat(DirPath+DPLen, ":");
  646.     else
  647.     strcat(DirPath+DPLen, "/");
  648.     DPLen += strlen(DirPath+DPLen);
  649. }
  650.  
  651. PopDirs(num)
  652. uword num;
  653. {
  654.     register SDIR *sd, *sp;
  655.     char lasthave = 0;
  656.  
  657.     while (num && (sd = GetTail(&DList))) {
  658.     lasthave |= sd->HaveFile;
  659.     if (sd->HaveFile)       /*  MUST write end-block    */
  660.         outentry(XEND, 0, NULL);
  661.     if (sp = GetPred(sd))
  662.         sp->HaveFile |= sd->HaveFile;
  663.     Remove(sd);
  664.     DPLen -= strlen(sd->Element) + 1;
  665.     if (DPLen < 0) {
  666.         puts("DPLEN ERROR");
  667.         DPLen = 0;
  668.     }
  669.     DirPath[DPLen] = 0;
  670.     free(sd->Element);
  671.     free(sd);
  672.     --num;
  673.     }
  674.     return(lasthave);
  675. }
  676.  
  677. /*
  678.  *  SCAN_DIRECTORY()        (CORE OF BACKUP)
  679.  */
  680.  
  681. scan_directory(dirfib, dirlock)
  682. FIB *dirfib;
  683. long dirlock;
  684. {
  685.     register FIB *fib;
  686.     long lock;
  687.     long save = CurrentDir(dirlock);
  688.  
  689.     while (ExNext(dirlock, dirfib) && (fib = GetFileInfo(dirfib->fib_FileName, &lock))) {
  690.     if (fib->fib_DirEntryType > 0) {
  691.         PushDir(fib->fib_FileName, XDDS);
  692.         if (ShowDirs)
  693.         printf("%-40s (DIR)\n", DirPath);
  694.         lock = scan_directory(fib, lock);
  695.         PopDirs(1);
  696.     } else {
  697.         lock = scan_file(fib, lock);
  698.     }
  699.     FreeFileInfo(fib, lock);
  700.     if (Break || mycheckbreak()) {
  701.         Break = 1;
  702.         break;
  703.     }
  704.     }
  705.     CurrentDir(save);
  706.     return(dirlock);
  707. }
  708.  
  709. mycheckbreak()
  710. {
  711.     if (SetSignal(0, (SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D)) & (SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D)) {
  712.     puts(" ***** BREAK *****");
  713.     return(1);
  714.     }
  715.     return(0);
  716. }
  717.  
  718. /*
  719.  *  SCAN_FILE()
  720.  *
  721.  *  If the file is accepted, write out pending directory entries, do
  722.  *  compression if any, and write out the file.
  723.  */
  724.  
  725. scan_file(fib, lock)
  726. FIB *fib;
  727. long lock;
  728. {
  729.     long save;
  730.     long n;
  731.     char dbuf[32];
  732.  
  733.     strcat(DirPath, fib->fib_FileName);
  734.  
  735.     if (Update && (fib->fib_Protection & FIBF_ARCHIVE))
  736.     goto nomatch;
  737.     {
  738.     register short i;
  739.  
  740.     for (i = 0; i < NumPicks; ++i) {
  741.         if (wildcmp(Picks[i], DirPath))
  742.         break;
  743.     }
  744.     if (i && i == NumPicks)
  745.         goto nomatch;
  746.  
  747.     for (i = 0; i < NumDels; ++i) {
  748.         if (wildcmp(Dels[i], DirPath))
  749.         goto nomatch;
  750.     }
  751.     }
  752.  
  753.     if (ShowFiles)
  754.     printf("%-40s %6ld %s\n", DirPath, fib->fib_Size, datetos(&fib->fib_Date, dbuf, NULL));
  755.  
  756.     {
  757.     register SDIR *sd;
  758.     SDIR *sdb = NULL;
  759.  
  760.     for (sd = GetTail(&DList); sd; sd = GetPred(sd)) {
  761.         if (sd->HaveFile == 0)
  762.         sdb = sd;
  763.     }
  764.     for (sd = sdb; sd; sd = GetSucc(sd)) {
  765.         sd->HaveFile = 1;
  766.         outentry(sd->Type, strlen(sd->Element), sd->Element);
  767.     }
  768.     }
  769.     if (OutFile) {
  770.     save = CurrentDir(lock);
  771.     if (openinput("") == 0) {
  772.         CurrentDir(save);
  773.         printf("Unable to open %s\n", fib->fib_FileName);
  774.         goto nomatch;
  775.     }
  776.     if (Compress && CompressFile(fib->fib_FileName, fib->fib_Size)) {
  777.         if (OutFile && BacBytes && outbytes() + CLen > BacBytes) {
  778.         if (newfile() == 0)
  779.             goto skip1;
  780.         }
  781.         writeheaders(fib);
  782.         outentry(XFIL1, strlen(fib->fib_FileName), fib->fib_FileName);
  783.         CLen += 4;
  784.         owrite(&CLen, 4);
  785.         CLen -= 4;
  786.         owrite(&fib->fib_Size, 4);
  787.         transfer1(fib->fib_Size);
  788.     } else {
  789.         if (OutFile && BacBytes && outbytes() + fib->fib_Size > BacBytes) {
  790.         if (newfile() == 0)
  791.             goto skip1;
  792.         }
  793.         if (Compress)
  794.         rollbackinput();
  795.         writeheaders(fib);
  796.         outentry(XFIL0, strlen(fib->fib_FileName), fib->fib_FileName);
  797.         owrite(&fib->fib_Size, 4);
  798.         transfer0(fib->fib_Size);
  799.     }
  800. skip1:
  801.     closeinput();
  802.     CurrentDir(save);
  803.     }
  804.     if (Break)
  805.     goto nomatch;
  806.     if (Archive && !(fib->fib_Protection & FIBF_ARCHIVE)) {
  807.     if (save = ParentDir(lock)) {
  808.         UnLock(lock);
  809.         save = CurrentDir(save);
  810.         SetProtection(fib->fib_FileName, fib->fib_Protection | FIBF_ARCHIVE);
  811.         lock = CurrentDir(save);
  812.     }
  813.     }
  814.     DirPath[DPLen] = 0;
  815.     return(lock);
  816. nomatch:
  817.     if (Verbose)
  818.     printf("%-40s (NOT ACCEPTED)\n", DirPath, fib->fib_Size, datetos(&fib->fib_Date, dbuf, NULL));
  819.  
  820.     DirPath[DPLen] = 0;
  821.     return(lock);
  822. }
  823.  
  824. writeheaders(fib)
  825. register FIB *fib;
  826. {
  827.     outentry(XDAT, sizeof(DATESTAMP), &fib->fib_Date);
  828.     outentry(XPRO, 4, &fib->fib_Protection);
  829.     if (fib->fib_Comment[0])
  830.     outentry(XCOM, strlen(fib->fib_Comment), fib->fib_Comment);
  831. }
  832.  
  833. /*
  834.  *  (1) Write out XEND's to finish this archive,
  835.  *  (2) Open a new output file
  836.  *  (3) Write out XDDS's to build back to the current position
  837.  */
  838.  
  839. newfile()
  840. {
  841.     {
  842.     register SDIR *sd;
  843.  
  844.     for (sd = GetTail(&DList); sd; sd = GetPred(sd)) {
  845.         if (sd->HaveFile)
  846.         outentry(XEND, 0, NULL);
  847.     }
  848.     }
  849.     ++BacCnt;
  850.     if (OutFile && openoutput(OutFile, Append, 1) == 0) {
  851.     Break = 1;
  852.     return(0);
  853.     }
  854.     {
  855.     register SDIR *sd;
  856.     DATESTAMP Date;
  857.     DateStamp(&Date);
  858.     outentry(XHDR, sizeof(DATESTAMP), &Date);
  859.     for (sd = GetHead(&DList); sd; sd = GetSucc(sd)) {
  860.         if (sd->HaveFile)
  861.         outentry(sd->Type, strlen(sd->Element), sd->Element);
  862.     }
  863.     }
  864.     return(1);
  865. }
  866.  
  867. read_file(type, fname, inbytes, outbytes)
  868. short type;
  869. char *fname;
  870. {
  871.     char dbuf[32];
  872.  
  873.     strcat(DirPath, fname);
  874.     {
  875.     register short i;
  876.  
  877.     for (i = 0; i < NumPicks; ++i) {
  878.         if (wildcmp(Picks[i], DirPath))
  879.         break;
  880.     }
  881.     if (i && i == NumPicks) {
  882.         if (Verbose)
  883.         printf("%-40s (NOT ACCEPTED)\n", DirPath);
  884.         goto nomatch;
  885.     }
  886.  
  887.     for (i = 0; i < NumDels; ++i) {
  888.         if (wildcmp(Dels[i], DirPath)) {
  889.         if (Verbose)
  890.             printf("%-40s (NOT ACCEPTED)\n", DirPath);
  891.         goto nomatch;
  892.         }
  893.     }
  894.     }
  895.  
  896.     printf("%-40s %6ld %6ld %s %s\n", DirPath, inbytes, outbytes, datetos(&Date, dbuf, NULL), Comment);
  897.  
  898.     if (ListOnly)
  899.     goto nomatch;
  900.     if (TimeStampOnly)
  901.     goto matchskip;
  902.  
  903.     openoutput(fname, 0, 0);
  904.     switch(type) {
  905.     case XFIL0:
  906.     transfer0(inbytes);
  907.     break;
  908.     case XFIL1:
  909.     UnCompressFile(inbytes);
  910.     transfer1(outbytes);
  911.     break;
  912.     }
  913.     closeoutput();
  914. matchskip:
  915.     DirPath[DPLen] = 0;
  916.     return(1);
  917. nomatch:
  918.     DirPath[DPLen] = 0;
  919.     return(-1);
  920. }
  921.  
  922. /*
  923.  *  FILE SUPPORT
  924.  */
  925.  
  926. static int Infd = -1;
  927. static int Outfd = -1;
  928. static long OutBytes;
  929.  
  930. openoutput(name, append, enabtail)
  931. char *name;
  932. {
  933.     char *ptr = name;
  934.     static NODE *VNode;     /*    Volume node */
  935.     long lock;
  936.     extern int errno;
  937.  
  938.     if (Outfd >= 0) {
  939.     dumpoutput();
  940.     close(Outfd);
  941.     Outfd = -1;
  942.     }
  943.     if (enabtail) {
  944.     if (VNode)
  945.         VNode = GetSucc(VNode);
  946.     if (!VNode)
  947.         VNode = GetHead(&VList);
  948.     if (VNode) {
  949.         ptr = malloc(strlen(VNode->ln_Name)+strlen(name)+8);
  950.         sprintf(ptr, "%s%s.%02ld", VNode->ln_Name, name, BacCnt);
  951.     } else {
  952.         ptr = malloc(strlen(name)+8);
  953.         sprintf(ptr, "%s.%02ld", name, BacCnt);
  954.     }
  955.     }
  956.     OutBytes = 0;
  957.     while (GetHead(&VList)) {
  958.     short c;
  959.     short d;
  960.  
  961.     fprintf(stderr, "Ready for %s (y=go,n=abort) -", ptr);
  962.     fflush(stderr);
  963.     if ((c = getc(stdin)) == EOF) {
  964.         fprintf(stderr, "EOF, aborted\n");
  965.         c = 'n';
  966.     }
  967.     while ((d = getc(stdin)) != EOF && d != '\n');
  968.     if ((c|0x20) == 'y')
  969.         break;
  970.     if ((c|0x20) == 'n')
  971.         goto skip;
  972.     }
  973.     if (enabtail && SaveLock)                 /*  original directory  */
  974.     lock = CurrentDir(SaveLock);
  975.     if (append) {
  976.     Outfd = open(ptr, O_WRONLY|O_CREAT|O_APPEND);
  977.     if (Outfd >= 0) {
  978.         OutBytes = lseek(Outfd, 0L, 2);
  979.         if (!append)
  980.         lseek(Outfd, 0L, 0);
  981.     }
  982.     } else {
  983.     Outfd = open(ptr, O_WRONLY|O_CREAT|O_TRUNC);
  984.     }
  985.     if (enabtail && SaveLock)                 /*  back to before      */
  986.     CurrentDir(lock);
  987.     if (Outfd < 0)
  988.     printf("Unable to open output file %s (%ld)\n", ptr, errno);
  989. skip:
  990.     BufI = 0;
  991.     if (enabtail)
  992.     free(ptr);
  993.     return(Outfd >= 0);
  994. }
  995.  
  996. oputc(v)
  997. char v;
  998. {
  999.     ++OutBytes;
  1000.     if (Outfd >= 0) {
  1001.     if (BufI == BufSize)
  1002.         dumpoutput();
  1003.     Buf[BufI++] = v;
  1004.     }
  1005. }
  1006.  
  1007. owrite(buf, n)
  1008. register char *buf;
  1009. register long n;
  1010. {
  1011.     register long avail;
  1012.  
  1013.     OutBytes += n;
  1014.     if (Outfd >= 0) {
  1015.     while (BufI + n > BufSize) {
  1016.         avail = BufSize - BufI;
  1017.         bmov(buf, Buf + BufI, avail);
  1018.         n  -= avail;
  1019.         buf+= avail;
  1020.         BufI = BufSize;
  1021.         dumpoutput();
  1022.     }
  1023.     bmov(buf, Buf + BufI, n);
  1024.     BufI += n;
  1025.     }
  1026. }
  1027.  
  1028. dumpoutput()
  1029. {
  1030.     if (Outfd >= 0 && BufI) {
  1031.     write(Outfd, Buf, BufI);
  1032.     BufI = 0;
  1033.     }
  1034. }
  1035.  
  1036. closeoutput()
  1037. {
  1038.     if (Outfd >= 0) {
  1039.     dumpoutput();
  1040.     close(Outfd);
  1041.     Outfd = -1;
  1042.     }
  1043. }
  1044.  
  1045. outbytes()
  1046. {
  1047.     return(OutBytes);
  1048. }
  1049.  
  1050. /*
  1051.  *  <type><len><buf>
  1052.  */
  1053.  
  1054. outentry(type, len, buf)
  1055. ubyte type;
  1056. ubyte len;
  1057. ubyte *buf;
  1058. {
  1059.     OutBytes += len + 2;
  1060.     if (Outfd >= 0) {
  1061.     if (BufI + len + 2 >= BufSize)
  1062.         dumpoutput();
  1063.     Buf[BufI+0] = type;
  1064.     Buf[BufI+1] = len;
  1065.     bmov(buf, Buf+BufI+2, len);
  1066.     BufI += len + 2;
  1067.     }
  1068. }
  1069.  
  1070. ulong OMax;
  1071.  
  1072. openinput(name)
  1073. char *name;
  1074. {
  1075.     if (Infd >= 0)
  1076.     close(Infd);
  1077.     Infd = open(name, O_RDONLY);
  1078.     InBufI = InBufN = 0;
  1079.     OMax = -1;
  1080.     return(Infd >= 0);
  1081. }
  1082.  
  1083. closeinput()
  1084. {
  1085.     if (Infd >= 0)
  1086.     close(Infd);
  1087.     Infd = -1;
  1088. }
  1089.  
  1090. void
  1091. seekinputend()
  1092. {
  1093.     register long inbuf   = InBufI - InBufN;
  1094.     register long forward = OMax;
  1095.  
  1096.     if (forward > inbuf) {
  1097.     lseek(Infd, forward - inbuf, 1);
  1098.     OMax = InBufI = InBufN = 0;
  1099.     return;
  1100.     }
  1101.     InBufN += forward;
  1102. }
  1103.  
  1104. setinputbound(max)
  1105. {
  1106.     OMax = max;
  1107. }
  1108.  
  1109. oread(buf, n)
  1110. char *buf;
  1111. long n;
  1112. {
  1113.     long x = 0;
  1114.     long avail;
  1115.  
  1116.     if (Infd < 0)
  1117.     return(0);
  1118.     if (n > OMax)
  1119.     n = OMax;
  1120.  
  1121.     while (n > (avail = InBufI - InBufN)) {
  1122.     if (InBufN == -1)
  1123.         return(0);
  1124.     bmov(InBuf + InBufN, buf, avail);
  1125.     OMax-= avail;
  1126.     n   -= avail;
  1127.     buf += avail;
  1128.     x   += avail;
  1129.     InBufI = read(Infd, InBuf, InBufSize);
  1130.     InBufN = 0;
  1131.     if (InBufI <= 0) {
  1132.         InBufI = 0;
  1133.         return(x);
  1134.     }
  1135.     }
  1136.     bmov(InBuf + InBufN, buf, n);
  1137.     InBufN += n;
  1138.     x += n;
  1139.     OMax -= n;
  1140.     return(x);
  1141. }
  1142.  
  1143. oreadchar()
  1144. {
  1145.     if (!OMax || Infd < 0)
  1146.     return(-1);
  1147.     if (InBufN == InBufI) {
  1148.     if (InBufN < 0)
  1149.         return(EOF);
  1150.     InBufI = read(Infd, InBuf, InBufSize);
  1151.     InBufN = 0;
  1152.     if (InBufI == 0) {
  1153.         InBufN = InBufI = -1;
  1154.         return(-1);
  1155.     }
  1156.     }
  1157.     return(InBuf[InBufN++]);
  1158. }
  1159.  
  1160. rollbackinput()
  1161. {
  1162.     if (Infd >= 0)
  1163.     lseek(Infd, 0L, 0);
  1164.     InBufI = InBufN = 0;
  1165. }
  1166.  
  1167. mputc(v)
  1168. char v;
  1169. {
  1170.     register SCOMP *sc = CWrite;
  1171.  
  1172.     ++CLen;
  1173.     if (sc->N == sc->Bytes) {
  1174.     sc = GetSucc(sc);
  1175.     if (sc == NULL);
  1176.         sc = NewSComp();
  1177.     if (sc == NULL) {
  1178.         puts("SCOMP FAILED");
  1179.         return(0);
  1180.     }
  1181.     sc->N = 0;
  1182.     CWrite = sc;
  1183.     }
  1184.     ((char *)(sc + 1))[sc->N++] = v;
  1185. }
  1186.  
  1187. mwrite(buf, n)
  1188. char *buf;
  1189. long n;
  1190. {
  1191.     register SCOMP *sc = CWrite;
  1192.     register long avail;
  1193.  
  1194.     CLen += n;
  1195.     while ((avail = sc->Bytes - sc->N) < n) {
  1196.     bmov(buf, (char *)(sc + 1) + sc->N, avail);
  1197.     buf += avail;
  1198.     n -= avail;
  1199.     sc->N = sc->Bytes;
  1200.     sc = GetSucc(sc);
  1201.     if (sc == NULL)
  1202.         sc = NewSComp();
  1203.     if (sc == NULL) {
  1204.         puts("SCOMP FAILED");
  1205.         return(0);
  1206.     }
  1207.     sc->N = 0;
  1208.     }
  1209.     bmov(buf, (char *)(sc + 1) + sc->N, n);
  1210.     sc->N += n;
  1211.     CWrite = sc;
  1212. }
  1213.  
  1214. SCOMP *
  1215. NewSComp()
  1216. {
  1217.     register SCOMP *sc = malloc(sizeof(SCOMP) + 8192);
  1218.  
  1219.     if (sc) {
  1220.     sc->Bytes = 8192;
  1221.     sc->N = 0;
  1222.     AddTail(&CList, sc);
  1223.     }
  1224.     return(sc);
  1225. }
  1226.  
  1227. transfer0(n)
  1228. long n;
  1229. {
  1230.     register long len;
  1231.  
  1232.     if (Outfd < 0)
  1233.     return(n);
  1234.     for (len = BufSize - BufI; n; len = BufSize - BufI) {
  1235.     if (len == 0) {
  1236.         dumpoutput();
  1237.         len = BufSize;
  1238.     }
  1239.     if (n < len)
  1240.         len = n;
  1241.     oread(Buf + BufI, len);
  1242.     BufI += len;
  1243.     n -= len;
  1244.     OutBytes += len;
  1245.     }
  1246. }
  1247.  
  1248. /*
  1249.  *  Compression Routines
  1250.  *
  1251.  *  transfer1(n)    : Backup:   copy compression buffer to output file
  1252.  */
  1253.  
  1254. transfer1(a)
  1255. {
  1256.     register long len;
  1257.     register SCOMP *sc = GetHead(&CList);
  1258.     register ubyte *ptr;
  1259.     long n = CLen;
  1260.  
  1261.     if (Outfd < 0)
  1262.     return(n);
  1263.     for (sc = GetHead(&CList); sc && n; sc = GetSucc(sc)) {
  1264.     len = sc->Bytes;
  1265.     ptr = (ubyte *)(sc + 1);
  1266.     if (n < len)
  1267.         len = n;
  1268.     n -= len;
  1269.     while (len > BufSize - BufI) {
  1270.         bmov(ptr, Buf + BufI, BufSize - BufI);
  1271.         ptr += BufSize - BufI;
  1272.         len -= BufSize - BufI;
  1273.         OutBytes += BufSize - BufI;
  1274.         BufI = BufSize;
  1275.         dumpoutput();
  1276.     }
  1277.     bmov(ptr, Buf + BufI, len);
  1278.     BufI += len;
  1279.     OutBytes += len;
  1280.     }
  1281.     if (n)
  1282.     puts("Unexpected EOF in compression file");
  1283. }
  1284.  
  1285. #asm
  1286.  
  1287.         ;    Taken from my DRES.LIBRARY so we don't have to open the
  1288.         ;    library.
  1289.  
  1290.         public  _GetHead
  1291.         public  _GetTail
  1292.         public  _GetSucc
  1293.         public  _GetPred
  1294.  
  1295. _GetSucc:
  1296. _GetHead:   move.l  4(sp),A0
  1297.         move.l  (A0),A0
  1298.         tst.l   (A0)
  1299.         bne     .gh1
  1300. .ghz        sub.l   A0,A0
  1301. .gh1        move.l  A0,D0
  1302.         rts
  1303.  
  1304. _GetTail:   move.l  4(sp),A0
  1305.         move.l  8(A0),A0
  1306.         tst.l   4(A0)
  1307.         beq     .ghz
  1308.         move.l  A0,D0
  1309.         rts
  1310.  
  1311. _GetPred:   move.l  4(sp),A0
  1312.         move.l  4(A0),A0
  1313.         tst.l   4(A0)
  1314.         beq     .ghz
  1315.         move.l  A0,D0
  1316.         rts
  1317.  
  1318. #endasm
  1319.  
  1320. #define ngetchar()  oreadchar()
  1321. #define nputchar(n) mputc(n)
  1322.  
  1323. #ifndef min
  1324. #define min(a,b)        ((a>b) ? b : a)
  1325. #endif
  1326.  
  1327. #define BITS        13
  1328.  
  1329. #if BITS == 16
  1330. #define HSIZE  69001           /* 95% occupancy */
  1331. #endif
  1332. #if BITS == 15
  1333. #define HSIZE  35023           /* 94% occupancy */
  1334. #endif
  1335. #if BITS == 14
  1336. #define HSIZE  18013           /* 91% occupancy */
  1337. #endif
  1338. #if BITS == 13
  1339. #define HSIZE  9001           /* 91% occupancy */
  1340. #endif
  1341. #if BITS <= 12
  1342. #define HSIZE  5003           /* 80% occupancy */
  1343. #endif
  1344.  
  1345. typedef long        code_int;
  1346. typedef long        count_int;
  1347. typedef unsigned char    char_type;
  1348.  
  1349. #define MAXCODE(n_bits)  ((1 << (n_bits)) - 1)
  1350. #define INIT_BITS 9            /* initial number of bits/code */
  1351.  
  1352. int n_bits;                /* number of bits/code            */
  1353. int maxbits;                /* user settable max # bits/code    */
  1354. code_int maxcode;            /* maximum code, given n_bits        */
  1355. code_int maxmaxcode;            /* should NEVER generate this code  */
  1356.  
  1357. count_int   htab[HSIZE];
  1358. uword        codetab[HSIZE];
  1359.  
  1360. #define htabof(i)       htab[i]
  1361. #define codetabof(i)    codetab[i]
  1362.  
  1363. code_int hsize = HSIZE;         /* for dynamic table sizing */
  1364.  
  1365. #define tab_prefixof(i)     codetabof(i)
  1366. #define tab_suffixof(i)     ((char_type *)(htab))[i]
  1367. #define de_stack        ((char_type *)&tab_suffixof(1<<BITS))
  1368.  
  1369. code_int free_ent;            /* first unused entry */
  1370.  
  1371. code_int getcode();
  1372.  
  1373. #define CHECK_GAP 10000 /* ratio check interval */
  1374.  
  1375. int    block_compress = 1;
  1376. int    clear_flg;
  1377. long    ratio;
  1378. count_int checkpoint;
  1379.  
  1380. /*
  1381.  * the next two codes should not be changed lightly, as they must not
  1382.  * lie within the contiguous general code space.
  1383.  */
  1384.  
  1385. #define FIRST    257    /* first free entry */
  1386. #define CLEAR    256    /* table clear output code */
  1387.  
  1388. static int offset;
  1389. long int in_count = 1;            /* length of input */
  1390.  
  1391. /*
  1392.  *  Compress a file to memory-buffers and return TRUE if the compressed
  1393.  *  size is smaller than the actual size.
  1394.  */
  1395.  
  1396. CompressFile(name, fsize)
  1397. {
  1398.     long fcode;
  1399.     code_int i = 0;
  1400.     int c;
  1401.     code_int ent;
  1402.     int disp;
  1403.     code_int hsize_reg;
  1404.     int hshift;
  1405.  
  1406.     if (wildcmp("*.Z", name) || wildcmp("*.ARC", name) || wildcmp("*.ZOO", name)) {
  1407.     printf("  Will not compress %s\n", name);
  1408.     return(0);
  1409.     }
  1410.  
  1411.     CLen = 0;
  1412.     CWrite = GetHead(&CList);
  1413.     if (CWrite == NULL)
  1414.     CWrite = NewSComp();
  1415.     CWrite->N = 0;
  1416.  
  1417.     bzero(htab, sizeof(htab));
  1418.     bzero(codetab, sizeof(codetab));
  1419.  
  1420.     hsize = HSIZE;
  1421.     if ( fsize < (1 << 12) )
  1422.     hsize = min ( 5003, HSIZE );
  1423.     else if ( fsize < (1 << 13) )
  1424.     hsize = min ( 9001, HSIZE );
  1425.     else if ( fsize < (1 << 14) )
  1426.     hsize = min ( 18013, HSIZE );
  1427.     else if ( fsize < (1 << 15) )
  1428.     hsize = min ( 35023, HSIZE );
  1429.     else if ( fsize < 47000 )
  1430.     hsize = min ( 50021, HSIZE );
  1431.  
  1432.     offset = clear_flg = ratio = 0;
  1433.     in_count = 1;
  1434.     checkpoint = CHECK_GAP;
  1435.     n_bits  = INIT_BITS;        /* number of bits/code            */
  1436.     maxbits = BITS;            /* user settable max # bits/code    */
  1437.     maxcode = MAXCODE(INIT_BITS);       /* maximum code, given n_bits       */
  1438.     maxmaxcode = 1 << BITS;        /* should NEVER generate this code  */
  1439.     free_ent = ((block_compress) ? FIRST : 256 );
  1440.  
  1441.     ent = ngetchar();
  1442.  
  1443.     hshift = 0;
  1444.     for ( fcode = (long) hsize;  fcode < 65536L; fcode *= 2L )
  1445.     hshift++;
  1446.     hshift = 8 - hshift;        /* set hash code range bound */
  1447.  
  1448.     hsize_reg = hsize;
  1449.     cl_hash((count_int)hsize_reg);      /* clear hash table */
  1450.  
  1451.     while ((c = ngetchar()) != EOF) {
  1452.     in_count++;
  1453.     fcode = (long) (((long) c << maxbits) + ent);
  1454.     i = ((c << hshift) ^ ent);      /* xor hashing */
  1455.  
  1456.     if (htabof (i) == fcode) {
  1457.         ent = codetabof(i);
  1458.         continue;
  1459.     } else if ((long)htabof (i) < 0)    /* empty slot */
  1460.         goto nomatch;
  1461.     disp = hsize_reg - i;        /* secondary hash (after G. Knott) */
  1462.     if (i == 0)
  1463.         disp = 1;
  1464. probe:
  1465.     if ((i -= disp) < 0)
  1466.         i += hsize_reg;
  1467.  
  1468.     if (htabof (i) == fcode) {
  1469.         ent = codetabof(i);
  1470.         continue;
  1471.     }
  1472.     if ((long)htabof (i) > 0)
  1473.         goto probe;
  1474. nomatch:
  1475.     output ((code_int) ent);
  1476.     ent = c;
  1477.     if (free_ent < maxmaxcode) {
  1478.         codetabof(i) = free_ent++; /* code -> hashtable */
  1479.         htabof(i) = fcode;
  1480.     }
  1481.     else if ((count_int)in_count >= checkpoint && block_compress)
  1482.         cl_block ();
  1483.     }
  1484.  
  1485.     /*
  1486.      * Put out the final code.
  1487.      */
  1488.  
  1489.     output((code_int)ent);
  1490.     output((code_int)-1);
  1491.  
  1492.     return(CLen < fsize);
  1493. }
  1494.  
  1495. static char buf[BITS];
  1496.  
  1497. char_type lmask[9] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00};
  1498. char_type rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
  1499.  
  1500. output( code )
  1501. code_int  code;
  1502. {
  1503.     register int r_off = offset, bits= n_bits;
  1504.     register char * bp = buf;
  1505.  
  1506.     if ( code >= 0 ) {
  1507.     /*
  1508.      * Get to the first byte.
  1509.      */
  1510.     bp += (r_off >> 3);
  1511.     r_off &= 7;
  1512.     /*
  1513.      * Since code is always >= 8 bits, only need to mask the first
  1514.      * hunk on the left.
  1515.      */
  1516.     *bp = (*bp & rmask[r_off]) | (code << r_off) & lmask[r_off];
  1517.     bp++;
  1518.     bits -= (8 - r_off);
  1519.     code >>= 8 - r_off;
  1520.     /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
  1521.     if ( bits >= 8 ) {
  1522.         *bp++ = code;
  1523.         code >>= 8;
  1524.         bits -= 8;
  1525.     }
  1526.     /* Last bits. */
  1527.     if(bits)
  1528.         *bp = code;
  1529.  
  1530.     offset += n_bits;
  1531.     if (offset == (n_bits << 3)) {
  1532.         bp = buf;
  1533.         bits = n_bits;
  1534.         mwrite(bp, bits);
  1535.         bp += bits;
  1536.         bits = 0;
  1537.         offset = 0;
  1538.     }
  1539.  
  1540.     /*
  1541.      * If the next entry is going to be too big for the code size,
  1542.      * then increase it, if possible.
  1543.      */
  1544.  
  1545.     if (free_ent > maxcode || (clear_flg > 0)) {
  1546.         /*
  1547.          * Write the whole buffer, because the input side won't
  1548.          * discover the size increase until after it has read it.
  1549.          */
  1550.         if (offset > 0)
  1551.         mwrite(buf, n_bits);
  1552.         offset = 0;
  1553.  
  1554.         if (clear_flg) {
  1555.         n_bits = INIT_BITS;
  1556.         maxcode = MAXCODE(INIT_BITS);
  1557.         clear_flg = 0;
  1558.         } else {
  1559.         n_bits++;
  1560.         if (n_bits == maxbits)
  1561.             maxcode = maxmaxcode;
  1562.         else
  1563.             maxcode = MAXCODE(n_bits);
  1564.         }
  1565.     }
  1566.     } else {
  1567.     /*
  1568.      * At EOF, write the rest of the buffer.
  1569.      */
  1570.     if (offset > 0)
  1571.         mwrite(buf, (offset + 7) / 8);
  1572.     offset = 0;
  1573.     }
  1574. }
  1575.  
  1576.  
  1577. char *
  1578. xrindex(s, c)            /* For those who don't have it in libc.a */
  1579. register char *s, c;
  1580. {
  1581.     char *p;
  1582.     for (p = NULL; *s; s++) {
  1583.     if (*s == c)
  1584.         p = s;
  1585.     }
  1586.     return(p);
  1587. }
  1588.  
  1589.  
  1590. cl_block()             /* table clear for block compress */
  1591. {
  1592.     register long int rat;
  1593.  
  1594.     checkpoint = in_count + CHECK_GAP;
  1595.  
  1596.     if (in_count > 0x007fffff) { /* shift will overflow */
  1597.     rat = CLen >> 8;
  1598.     if (rat == 0) {          /* Don't divide by zero */
  1599.         rat = 0x7fffffff;
  1600.     } else {
  1601.         rat = in_count / rat;
  1602.     }
  1603.     } else {
  1604.     rat = (in_count << 8) / CLen;      /* 8 fractional bits */
  1605.     }
  1606.     if (rat > ratio) {
  1607.     ratio = rat;
  1608.     } else {
  1609.     ratio = 0;
  1610.     cl_hash ( (count_int) hsize );
  1611.     free_ent = FIRST;
  1612.     clear_flg = 1;
  1613.     output ( (code_int) CLEAR );
  1614.     }
  1615. }
  1616.  
  1617. cl_hash(hsize)          /* reset code table */
  1618.     register count_int hsize;
  1619. {
  1620.     register count_int *htab_p = htab+hsize;
  1621.     register long i;
  1622.     register long m1 = -1;
  1623.  
  1624.     i = hsize - 16;
  1625.     do {                /* might use Sys V memset(3) here */
  1626.         *(htab_p-16) = m1;
  1627.         *(htab_p-15) = m1;
  1628.         *(htab_p-14) = m1;
  1629.         *(htab_p-13) = m1;
  1630.         *(htab_p-12) = m1;
  1631.         *(htab_p-11) = m1;
  1632.         *(htab_p-10) = m1;
  1633.         *(htab_p-9) = m1;
  1634.         *(htab_p-8) = m1;
  1635.         *(htab_p-7) = m1;
  1636.         *(htab_p-6) = m1;
  1637.         *(htab_p-5) = m1;
  1638.         *(htab_p-4) = m1;
  1639.         *(htab_p-3) = m1;
  1640.         *(htab_p-2) = m1;
  1641.         *(htab_p-1) = m1;
  1642.         htab_p -= 16;
  1643.     } while ((i -= 16) >= 0);
  1644.     for ( i += 16; i > 0; i-- )
  1645.         *--htab_p = m1;
  1646. }
  1647.  
  1648. UnCompressFile(insize)
  1649. {
  1650.     register char_type *stackp;
  1651.     register int finchar;
  1652.     register code_int code, oldcode, incode;
  1653.  
  1654.     /*
  1655.      * As above, initialize the first 256 entries in the table.
  1656.      */
  1657.  
  1658.     bzero(htab, sizeof(htab));
  1659.     bzero(codetab, sizeof(codetab));
  1660.  
  1661.     offset = clear_flg = ratio = 0;
  1662.     in_count = 1;
  1663.     checkpoint = CHECK_GAP;
  1664.     n_bits  = INIT_BITS;        /* number of bits/code            */
  1665.     maxbits = BITS;            /* user settable max # bits/code    */
  1666.     maxcode = MAXCODE(INIT_BITS);       /* maximum code, given n_bits       */
  1667.     maxmaxcode = 1 << BITS;        /* should NEVER generate this code  */
  1668.  
  1669.     for ( code = 255; code >= 0; code-- ) {
  1670.     tab_prefixof(code) = 0;
  1671.     tab_suffixof(code) = (char_type)code;
  1672.     }
  1673.     free_ent = ((block_compress) ? FIRST : 256 );
  1674.  
  1675.     finchar = oldcode = getcode();
  1676.     if (oldcode == -1)          /* EOF already? */
  1677.     return;         /* Get out of here */
  1678.     oputc((char)finchar);       /* first code must be 8 bits = char */
  1679.     stackp = de_stack;
  1680.  
  1681.     while ((code = getcode()) > -1) {
  1682.     if ((code == CLEAR) && block_compress) {
  1683.         for (code = 255; code >= 0; code--)
  1684.         tab_prefixof(code) = 0;
  1685.         clear_flg = 1;
  1686.         free_ent = FIRST - 1;
  1687.         if ((code = getcode()) == -1)   /* O, untimely death! */
  1688.         break;
  1689.     }
  1690.     incode = code;
  1691.     /*
  1692.      * Special case for KwKwK string.
  1693.      */
  1694.     if (code >= free_ent) {
  1695.         *stackp++ = finchar;
  1696.         code = oldcode;
  1697.     }
  1698.  
  1699.     /*
  1700.      * Generate output characters in reverse order
  1701.      */
  1702.     while ( code >= 256 ) {
  1703.         *stackp++ = tab_suffixof(code);
  1704.         code = tab_prefixof(code);
  1705.     }
  1706.     *stackp++ = finchar = tab_suffixof(code);
  1707.  
  1708.     /*
  1709.      * And put them out in forward order
  1710.      */
  1711.     do
  1712.         oputc (*--stackp);
  1713.     while (stackp > de_stack);
  1714.  
  1715.     /*
  1716.      * Generate the new entry.
  1717.      */
  1718.     if ((code=free_ent) < maxmaxcode) {
  1719.         tab_prefixof(code) = (unsigned short)oldcode;
  1720.         tab_suffixof(code) = finchar;
  1721.         free_ent = code+1;
  1722.     }
  1723.     /*
  1724.      * Remember previous code.
  1725.      */
  1726.     oldcode = incode;
  1727.     }
  1728. }
  1729.  
  1730. code_int
  1731. getcode()
  1732. {
  1733.     /*
  1734.      * On the VAX, it is important to have the register declarations
  1735.      * in exactly the order given, or the asm will break.
  1736.      */
  1737.  
  1738.     register code_int code;
  1739.     static int offset = 0, size = 0;
  1740.     static char_type buf[BITS];
  1741.     register int r_off, bits;
  1742.     register char_type *bp = buf;
  1743.  
  1744.     if (clear_flg > 0 || offset >= size || free_ent > maxcode) {
  1745.     /*
  1746.      * If the next entry will be too big for the current code
  1747.      * size, then we must increase the size.  This implies reading
  1748.      * a new buffer full, too.
  1749.      */
  1750.     if ( free_ent > maxcode ) {
  1751.         n_bits++;
  1752.         if ( n_bits == maxbits )
  1753.         maxcode = maxmaxcode;    /* won't get any bigger now */
  1754.         else
  1755.         maxcode = MAXCODE(n_bits);
  1756.     }
  1757.     if ( clear_flg > 0) {
  1758.         maxcode = MAXCODE (n_bits = INIT_BITS);
  1759.         clear_flg = 0;
  1760.     }
  1761.     size = oread(buf, n_bits);
  1762.     if (size <= 0)
  1763.         return -1;            /* end of file */
  1764.     offset = 0;
  1765.     size = (size << 3) - (n_bits - 1);
  1766.     }
  1767.     r_off = offset;
  1768.     bits = n_bits;
  1769.  
  1770.     /*
  1771.      * Get to the first byte.
  1772.      */
  1773.     bp += (r_off >> 3);
  1774.     r_off &= 7;
  1775.     /* Get first part (low order bits) */
  1776.  
  1777.     code = (*bp++ >> r_off);
  1778.  
  1779.     bits -= (8 - r_off);
  1780.     r_off = 8 - r_off;        /* now, offset into code word */
  1781.     /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
  1782.     if ( bits >= 8 ) {
  1783.         code |= *bp++ << r_off;
  1784.         r_off += 8;
  1785.         bits -= 8;
  1786.     }
  1787.     /* high order bits. */
  1788.     code |= (*bp & rmask[bits]) << r_off;
  1789.  
  1790.     offset += n_bits;
  1791.  
  1792.     return code;
  1793. }
  1794.  
  1795.