home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume15 / arc5.21 / part04 < prev    next >
Encoding:
Internet Message Format  |  1988-06-30  |  65.4 KB

  1. Subject:  v15i080:  ARC (PC compression program), v5.21, Part04/05
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: hyc@math.lsa.umich.edu
  7. Posting-number: Volume 15, Issue 80
  8. Archive-name: arc5.21/part04
  9.  
  10. #--------------------------------CUT HERE-------------------------------------
  11. #! /bin/sh
  12. #
  13. # This is a shell archive.  Save this into a file, edit it
  14. # and delete all lines above this comment.  Then give this
  15. # file to sh by executing the command "sh file".  The files
  16. # will be extracted into the current directory owned by
  17. # you with default permissions.
  18. #
  19. # The files contained herein are:
  20. #
  21. # -rw-r--r--  1 hyc         22109 Jun  1 20:01 arclzw.c
  22. # -rw-r--r--  1 hyc          3026 Jun  1 19:41 arcmatch.c
  23. # -rw-r--r--  1 hyc          8418 Jun 13 14:17 arcmisc.c
  24. # -rw-r--r--  1 hyc          7376 Jun  2 16:27 arcpack.c
  25. # -rw-r--r--  1 hyc          3838 Jun  1 19:57 arcrun.c
  26. # -rw-r--r--  1 hyc          1645 Apr 17 18:53 arcs.h
  27. # -rw-------  1 hyc         14613 Jun  2 16:27 arcsq.c
  28. #
  29. echo 'x - arclzw.c'
  30. if test -f arclzw.c; then echo 'shar: not overwriting arclzw.c'; else
  31. sed 's/^X//' << '________This_Is_The_END________' > arclzw.c
  32. X/*
  33. X * $Header: arclzw.c,v 1.4 88/06/01 16:27:59 hyc Locked $
  34. X */
  35. X
  36. X/*
  37. X * ARC - Archive utility - ARCLZW
  38. X * 
  39. X * Version 2.03, created on 10/24/86 at 11:46:22
  40. X * 
  41. X * (C) COPYRIGHT 1985,86 by System Enhancement Associates; ALL RIGHTS RESERVED
  42. X * 
  43. X * By:  Thom Henderson
  44. X * 
  45. X * Description: This file contains the routines used to implement Lempel-Zev
  46. X * data compression, which calls for building a coding table on the fly.
  47. X * This form of compression is especially good for encoding files which
  48. X * contain repeated strings, and can often give dramatic improvements over
  49. X * traditional Huffman SQueezing.
  50. X * 
  51. X * Language: Computer Innovations Optimizing C86
  52. X * 
  53. X * Programming notes: In this section I am drawing heavily on the COMPRESS
  54. X * program from UNIX.  The basic method is taken from "A Technique for High
  55. X * Performance Data Compression", Terry A. Welch, IEEE Computer Vol 17, No 6
  56. X * (June 1984), pp 8-19.  Also see "Knuth's Fundamental Algorithms", Donald
  57. X * Knuth, Vol 3, Section 6.4.
  58. X * 
  59. X * As best as I can tell, this method works by tracing down a hash table of code
  60. X * strings where each entry has the property:
  61. X * 
  62. X * if <string> <char> is in the table then <string> is in the table.
  63. X */
  64. X#include <stdio.h>
  65. X#include "arc.h"
  66. X
  67. Xvoid    putc_pak(), abort(), putc_ncr();
  68. Xint    getc_unp();
  69. X#if    MSDOS
  70. Xchar    *setmem();
  71. X#else
  72. Xchar    *memset();
  73. X#endif
  74. X
  75. Xstatic void    putcode();
  76. X/* definitions for older style crunching */
  77. X
  78. X#define FALSE    0
  79. X#define TRUE     !FALSE
  80. X#define TABSIZE  4096
  81. X#define NO_PRED  0xFFFF
  82. X#define EMPTY    0xFFFF
  83. X#define NOT_FND  0xFFFF
  84. X
  85. Xstatic unsigned short inbuf;    /* partial input code storage */
  86. Xstatic int      sp;        /* current stack pointer */
  87. X
  88. Xstruct entry {        /* string table entry format */
  89. X    char            used;    /* true when this entry is in use */
  90. X    unsigned char   follower;    /* char following string */
  91. X    unsigned short  next;    /* ptr to next in collision list */
  92. X    unsigned short  predecessor;    /* code for preceeding string */
  93. X};            /* string_tab[TABSIZE];    /* the code string table */
  94. X
  95. X
  96. X/* definitions for the new dynamic Lempel-Zev crunching */
  97. X
  98. X#define BITS   12        /* maximum bits per code */
  99. X#define HSIZE  5003        /* 80% occupancy */
  100. X#define INIT_BITS 9        /* initial number of bits/code */
  101. X
  102. Xstatic int      n_bits;        /* number of bits/code */
  103. Xstatic int      maxcode;    /* maximum code, given n_bits */
  104. X#define MAXCODE(n)      ((1<<(n)) - 1)    /* maximum code calculation */
  105. Xstatic int      maxcodemax = 1 << BITS;    /* largest possible code (+1) */
  106. X
  107. Xstatic char     buf[BITS];    /* input/output buffer */
  108. X
  109. Xstatic unsigned char lmask[9] =    /* left side masks */
  110. X{
  111. X 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00
  112. X};
  113. Xstatic unsigned char rmask[9] =    /* right side masks */
  114. X{
  115. X 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
  116. X};
  117. X
  118. Xstatic int      offset;        /* byte offset for code output */
  119. Xstatic long     in_count;    /* length of input */
  120. Xstatic long     bytes_out;    /* length of compressed output */
  121. Xstatic long     bytes_ref;    /* output quality reference */
  122. Xstatic long     bytes_last;    /* output size at last checkpoint */
  123. Xstatic unsigned short ent;
  124. X
  125. X/*
  126. X * To save much memory (which we badly need at this point), we overlay the
  127. X * table used by the previous version of Lempel-Zev with those used by the
  128. X * new version.  Since no two of these routines will be used together, we can
  129. X * safely do this.
  130. X */
  131. X
  132. Xextern long     htab[HSIZE];        /* hash code table   (crunch) */
  133. Xextern unsigned short codetab[HSIZE];    /* string code table (crunch) */
  134. Xstatic struct    entry *string_tab=(struct entry *)htab;    /* old crunch string table */
  135. X
  136. Xstatic unsigned short *prefix=codetab;    /* prefix code table (uncrunch) */
  137. Xstatic unsigned char *suffix=(unsigned char *)htab;    /* suffix table (uncrunch) */
  138. X
  139. Xstatic int      free_ent;    /* first unused entry */
  140. Xstatic int      firstcmp;    /* true at start of compression */
  141. Xextern unsigned char stack[HSIZE];    /* local push/pop stack */
  142. X
  143. X/*
  144. X * block compression parameters -- after all codes are used up, and
  145. X * compression rate changes, start over.
  146. X */
  147. X
  148. Xstatic int      clear_flg;
  149. X#define CHECK_GAP 2048        /* ratio check interval */
  150. Xstatic long     checkpoint;
  151. Xvoid            upd_tab();
  152. X
  153. X/*
  154. X * the next two codes should not be changed lightly, as they must not lie
  155. X * within the contiguous general code space.
  156. X */
  157. X#define FIRST   257        /* first free entry */
  158. X#define CLEAR   256        /* table clear output code */
  159. X
  160. X/*
  161. X * The cl_block() routine is called at each checkpoint to determine if
  162. X * compression would likely improve by resetting the code table.  The method
  163. X * chosen to determine this is based on empirical observation that, in
  164. X * general, every 2k of input data should compress at least as well as the
  165. X * first 2k of input.
  166. X */
  167. X
  168. Xstatic          void
  169. Xcl_block(t)            /* table clear for block compress */
  170. X    FILE           *t;    /* our output file */
  171. X{
  172. X    checkpoint = in_count + CHECK_GAP;
  173. X
  174. X    if (bytes_ref) {
  175. X        if (bytes_out - bytes_last > bytes_ref) {
  176. X            setmem(htab, HSIZE * sizeof(long), 0xff);
  177. X            free_ent = FIRST;
  178. X            clear_flg = 1;
  179. X            putcode(CLEAR, t);
  180. X            bytes_ref = 0;
  181. X        }
  182. X    } else
  183. X        bytes_ref = bytes_out - bytes_last;
  184. X
  185. X    bytes_last = bytes_out;    /* remember where we were */
  186. X}
  187. X
  188. X/*****************************************************************
  189. X *
  190. X * Output a given code.
  191. X * Inputs:
  192. X *      code:   A n_bits-bit integer.  If == -1, then EOF.  This assumes
  193. X *              that n_bits =< (LONG)wordsize - 1.
  194. X * Outputs:
  195. X *      Outputs code to the file.
  196. X * Assumptions:
  197. X *      Chars are 8 bits long.
  198. X * Algorithm:
  199. X *      Maintain a BITS character long buffer (so that 8 codes will
  200. X * fit in it exactly).  When the buffer fills up empty it and start over.
  201. X */
  202. X
  203. Xstatic          void
  204. Xputcode(code, t)        /* output a code */
  205. X    int             code;    /* code to output */
  206. X    FILE           *t;    /* where to put it */
  207. X{
  208. X    int             r_off = offset;    /* right offset */
  209. X    int             bits = n_bits;    /* bits to go */
  210. X    char           *bp = buf;    /* buffer pointer */
  211. X    int             n;    /* index */
  212. X
  213. X    register int    ztmp;
  214. X
  215. X    if (code >= 0) {    /* if a real code *//* Get to the first byte. */
  216. X        bp += (r_off >> 3);
  217. X        r_off &= 7;
  218. X
  219. X        /*
  220. X         * Since code is always >= 8 bits, only need to mask the
  221. X         * first hunk on the left. 
  222. X         */
  223. X        ztmp = (code << r_off) & lmask[r_off];
  224. X        *bp = (*bp & rmask[r_off]) | ztmp;
  225. X        bp++;
  226. X        bits -= (8 - r_off);
  227. X        code >>= (8 - r_off);
  228. X
  229. X        /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
  230. X        if (bits >= 8) {
  231. X            *bp++ = code;
  232. X            code >>= 8;
  233. X            bits -= 8;
  234. X        }
  235. X        /* Last bits. */
  236. X        if (bits)
  237. X            *bp = code;
  238. X        offset += n_bits;
  239. X
  240. X        if (offset == (n_bits << 3)) {
  241. X            bp = buf;
  242. X            bits = n_bits;
  243. X            bytes_out += bits;
  244. X            do
  245. X                putc_pak(*bp++, t);
  246. X            while (--bits);
  247. X            offset = 0;
  248. X        }
  249. X        /*
  250. X         * If the next entry is going to be too big for the code
  251. X         * size, then increase it, if possible. 
  252. X         */
  253. X        if (free_ent > maxcode || clear_flg > 0) {
  254. X            /*
  255. X             * Write the whole buffer, because the input side
  256. X             * won't discover the size increase until after
  257. X             * it has read it. 
  258. X             */
  259. X            if (offset > 0) {
  260. X                bp = buf;    /* reset pointer for writing */
  261. X                bytes_out += n = n_bits;
  262. X                while (n--)
  263. X                    putc_pak(*bp++, t);
  264. X            }
  265. X            offset = 0;
  266. X
  267. X            if (clear_flg) {    /* reset if clearing */
  268. X                maxcode = MAXCODE(n_bits = INIT_BITS);
  269. X                clear_flg = 0;
  270. X            } else {/* else use more bits */
  271. X                n_bits++;
  272. X                if (n_bits == BITS)
  273. X                    maxcode = maxcodemax;
  274. X                else
  275. X                    maxcode = MAXCODE(n_bits);
  276. X            }
  277. X        }
  278. X    } else {        /* dump the buffer on EOF */
  279. X        bytes_out += n = (offset + 7) / 8;
  280. X
  281. X        if (offset > 0)
  282. X            while (n--)
  283. X                putc_pak(*bp++, t);
  284. X        offset = 0;
  285. X    }
  286. X}
  287. X
  288. X/*****************************************************************
  289. X *
  290. X * Read one code from the standard input.  If EOF, return -1.
  291. X * Inputs:
  292. X *      cmpin
  293. X * Outputs:
  294. X *      code or -1 is returned.
  295. X */
  296. X
  297. Xstatic          int
  298. Xgetcode(f)            /* get a code */
  299. X    FILE           *f;    /* file to get from */
  300. X{
  301. X    int             code;
  302. X    static int      offset = 0, size = 0;
  303. X    int             r_off, bits;
  304. X    unsigned char  *bp = (unsigned char *) buf;
  305. X
  306. X    if (clear_flg > 0 || offset >= size || free_ent > maxcode) {
  307. X        /*
  308. X         * If the next entry will be too big for the current code
  309. X         * size, then we must increase the size. This implies
  310. X         * reading a new buffer full, too. 
  311. X         */
  312. X        if (free_ent > maxcode) {
  313. X            n_bits++;
  314. X            if (n_bits == BITS)
  315. X                maxcode = maxcodemax;    /* won't get any bigger
  316. X                             * now */
  317. X            else
  318. X                maxcode = MAXCODE(n_bits);
  319. X        }
  320. X        if (clear_flg > 0) {
  321. X            maxcode = MAXCODE(n_bits = INIT_BITS);
  322. X            clear_flg = 0;
  323. X        }
  324. X        for (size = 0; size < n_bits; size++) {
  325. X            if ((code = getc_unp(f)) == EOF)
  326. X                break;
  327. X            else
  328. X                buf[size] = (char) code;
  329. X        }
  330. X        if (size <= 0)
  331. X            return -1;    /* end of file */
  332. X
  333. X        offset = 0;
  334. X        /* Round size down to integral number of codes */
  335. X        size = (size << 3) - (n_bits - 1);
  336. X    }
  337. X    r_off = offset;
  338. X    bits = n_bits;
  339. X
  340. X    /*
  341. X     * Get to the first byte. 
  342. X     */
  343. X    bp += (r_off >> 3);
  344. X    r_off &= 7;
  345. X
  346. X    /* Get first part (low order bits) */
  347. X    code = (*bp++ >> r_off);
  348. X    bits -= 8 - r_off;
  349. X    r_off = 8 - r_off;    /* now, offset into code word */
  350. X
  351. X    /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
  352. X    if (bits >= 8) {
  353. X        code |= *bp++ << r_off;
  354. X        r_off += 8;
  355. X        bits -= 8;
  356. X    }
  357. X    /* high order bits. */
  358. X    code |= (*bp & rmask[bits]) << r_off;
  359. X    offset += n_bits;
  360. X
  361. X    return code & MAXCODE(BITS);
  362. X}
  363. X
  364. X/*
  365. X * compress a file
  366. X * 
  367. X * Algorithm:  use open addressing double hashing (no chaining) on the prefix
  368. X * code / next character combination.  We do a variant of Knuth's algorithm D
  369. X * (vol. 3, sec. 6.4) along with G. Knott's relatively-prime secondary probe.
  370. X * Here, the modular division first probe is gives way to a faster
  371. X * exclusive-or manipulation.  Also do block compression with an adaptive
  372. X * reset, where the code table is cleared when the compression ratio
  373. X * decreases, but after the table fills.  The variable-length output codes
  374. X * are re-sized at this point, and a special CLEAR code is generated for the
  375. X * decompressor.
  376. X */
  377. X
  378. Xvoid
  379. Xinit_cm(t)            /* initialize for compression */
  380. X    FILE           *t;    /* where compressed file goes */
  381. X{
  382. X    offset = 0;
  383. X    bytes_out = bytes_last = 1;
  384. X    bytes_ref = 0;
  385. X    clear_flg = 0;
  386. X    in_count = 1;
  387. X    checkpoint = CHECK_GAP;
  388. X    maxcode = MAXCODE(n_bits = INIT_BITS);
  389. X    free_ent = FIRST;
  390. X    setmem(htab, HSIZE * sizeof(long), 0xff);
  391. X    n_bits = INIT_BITS;    /* set starting code size */
  392. X
  393. X    putc_pak(BITS, t);    /* note our max code length */
  394. X
  395. X    firstcmp = 1;        /* next byte will be first */
  396. X}
  397. X
  398. Xvoid
  399. Xputc_cm(c, t)            /* compress a character */
  400. X    unsigned char   c;    /* character to compress */
  401. X    FILE           *t;    /* where to put it */
  402. X{
  403. X    static long     fcode;
  404. X    static int      hshift;
  405. X    int             i;
  406. X    int             disp;
  407. X
  408. X    if (firstcmp) {        /* special case for first byte */
  409. X        ent = c;    /* remember first byte */
  410. X
  411. X        hshift = 0;
  412. X        for (fcode = (long) HSIZE; fcode < 65536L; fcode *= 2L)
  413. X            hshift++;
  414. X        hshift = 8 - hshift;    /* set hash code range bound */
  415. X
  416. X        firstcmp = 0;    /* no longer first */
  417. X        return;
  418. X    }
  419. X    in_count++;
  420. X
  421. X    fcode = (long) (((long) c << BITS) + ent);
  422. X    i = (c << hshift) ^ ent;/* xor hashing */
  423. X
  424. X    if (htab[i] == fcode) {
  425. X        ent = codetab[i];
  426. X        return;
  427. X    } else if (htab[i] < 0)    /* empty slot */
  428. X        goto nomatch;
  429. X    disp = HSIZE - i;    /* secondary hash (after G.Knott) */
  430. X    if (i == 0)
  431. X        disp = 1;
  432. X
  433. Xprobe:
  434. X    if ((i -= disp) < 0)
  435. X        i += HSIZE;
  436. X
  437. X    if (htab[i] == fcode) {
  438. X        ent = codetab[i];
  439. X        return;
  440. X    }
  441. X    if (htab[i] > 0)
  442. X        goto probe;
  443. X
  444. Xnomatch:
  445. X    putcode(ent, t);
  446. X    ent = c;
  447. X    if (free_ent < maxcodemax) {
  448. X        codetab[i] = free_ent++;    /* code -> hashtable */
  449. X        htab[i] = fcode;
  450. X    }
  451. X    if (in_count >= checkpoint)
  452. X        cl_block(t);    /* check for adaptive reset */
  453. X}
  454. X
  455. Xlong
  456. Xpred_cm(t)            /* finish compressing a file */
  457. X    FILE           *t;    /* where to put it */
  458. X{
  459. X    putcode(ent, t);    /* put out the final code */
  460. X    putcode(-1, t);        /* tell output we are done */
  461. X
  462. X    return bytes_out;    /* say how big it got */
  463. X}
  464. X
  465. X/*
  466. X * Decompress a file.  This routine adapts to the codes in the file building
  467. X * the string table on-the-fly; requiring no table to be stored in the
  468. X * compressed file.  The tables used herein are shared with those of the
  469. X * compress() routine.  See the definitions above.
  470. X */
  471. X
  472. Xvoid
  473. Xdecomp(f, t)            /* decompress a file */
  474. X    FILE           *f;    /* file to read codes from */
  475. X    FILE           *t;    /* file to write text to */
  476. X{
  477. X    unsigned char  *stackp;
  478. X    int             finchar;
  479. X    int             code, oldcode, incode;
  480. X
  481. X    if ((code = getc_unp(f)) != BITS)
  482. X        abort("File packed with %d bits, I can only handle %d", code, BITS);
  483. X
  484. X    n_bits = INIT_BITS;    /* set starting code size */
  485. X    clear_flg = 0;
  486. X
  487. X    /*
  488. X     * As above, initialize the first 256 entries in the table. 
  489. X     */
  490. X    maxcode = MAXCODE(n_bits = INIT_BITS);
  491. X    setmem(prefix, 256 * sizeof(short), 0);    /* reset decode string table */
  492. X    for (code = 255; code >= 0; code--)
  493. X        suffix[code] = (unsigned char) code;
  494. X
  495. X    free_ent = FIRST;
  496. X
  497. X    finchar = oldcode = getcode(f);
  498. X    if (oldcode == -1)    /* EOF already? */
  499. X        return;        /* Get out of here */
  500. X    putc_ncr((unsigned char) finchar, t);    /* first code must be 8 bits=char */
  501. X    stackp = stack;
  502. X
  503. X    while ((code = getcode(f)) > -1) {
  504. X        if (code == CLEAR) {    /* reset string table */
  505. X            setmem(prefix, 256 * sizeof(short), 0);
  506. X            clear_flg = 1;
  507. X            free_ent = FIRST - 1;
  508. X            if ((code = getcode(f)) == -1)    /* O, untimely death! */
  509. X                break;
  510. X        }
  511. X        incode = code;
  512. X        /*
  513. X         * Special case for KwKwK string. 
  514. X         */
  515. X        if (code >= free_ent) {
  516. X            if (code > free_ent) {
  517. X                if (warn) {
  518. X                    printf("Corrupted compressed file.\n");
  519. X                    printf("Invalid code %d when max is %d.\n",
  520. X                        code, free_ent);
  521. X                }
  522. X                nerrs++;
  523. X                return;
  524. X            }
  525. X            *stackp++ = finchar;
  526. X            code = oldcode;
  527. X        }
  528. X        /*
  529. X         * Generate output characters in reverse order 
  530. X         */
  531. X        while (code >= 256) {
  532. X            *stackp++ = suffix[code];
  533. X            code = prefix[code];
  534. X        }
  535. X        *stackp++ = finchar = suffix[code];
  536. X
  537. X        /*
  538. X         * And put them out in forward order 
  539. X         */
  540. X        do
  541. X            putc_ncr(*--stackp, t);
  542. X        while (stackp > stack);
  543. X
  544. X        /*
  545. X         * Generate the new entry. 
  546. X         */
  547. X        if ((code = free_ent) < maxcodemax) {
  548. X            prefix[code] = (unsigned short) oldcode;
  549. X            suffix[code] = finchar;
  550. X            free_ent = code + 1;
  551. X        }
  552. X        /*
  553. X         * Remember previous code. 
  554. X         */
  555. X        oldcode = incode;
  556. X    }
  557. X}
  558. X
  559. X
  560. X/*************************************************************************
  561. X * Please note how much trouble it can be to maintain upwards            *
  562. X * compatibility.  All that follows is for the sole purpose of unpacking *
  563. X * files which were packed using an older method.                        *
  564. X *************************************************************************/
  565. X
  566. X
  567. X/*
  568. X * The h() pointer points to the routine to use for calculating a hash value.
  569. X * It is set in the init routines to point to either of oldh() or newh().
  570. X * 
  571. X * oldh() calculates a hash value by taking the middle twelve bits of the square
  572. X * of the key.
  573. X * 
  574. X * newh() works somewhat differently, and was tried because it makes ARC about
  575. X * 23% faster.  This approach was abandoned because dynamic Lempel-Zev
  576. X * (above) works as well, and packs smaller also.  However, inadvertent
  577. X * release of a developmental copy forces us to leave this in.
  578. X */
  579. X
  580. Xstatic unsigned short(*h) ();    /* pointer to hash function */
  581. X
  582. Xstatic unsigned short
  583. Xoldh(pred, foll)        /* old hash function */
  584. X    unsigned short  pred;    /* code for preceeding string */
  585. X    unsigned char   foll;    /* value of following char */
  586. X{
  587. X    long            local;    /* local hash value */
  588. X
  589. X    local = ((pred + foll) | 0x0800) & 0xFFFF; /* create the hash key */
  590. X    local *= local;        /* square it */
  591. X    return (local >> 6) & 0x0FFF;    /* return the middle 12 bits */
  592. X}
  593. X
  594. Xstatic unsigned short
  595. Xnewh(pred, foll)        /* new hash function */
  596. X    unsigned short  pred;    /* code for preceeding string */
  597. X    unsigned char   foll;    /* value of following char */
  598. X{
  599. X    return (((pred + foll) & 0xFFFF) * 15073) & 0xFFF; /* faster hash */
  600. X}
  601. X
  602. X/*
  603. X * The eolist() function is used to trace down a list of entries with
  604. X * duplicate keys until the last duplicate is found.
  605. X */
  606. X
  607. Xstatic unsigned short
  608. Xeolist(index)            /* find last duplicate */
  609. X    unsigned short  index;
  610. X{
  611. X    int             temp;
  612. X
  613. X    while (temp = string_tab[index].next)    /* while more duplicates */
  614. X        index = temp;
  615. X
  616. X    return index;
  617. X}
  618. X
  619. X/*
  620. X * The hash() routine is used to find a spot in the hash table for a new
  621. X * entry.  It performs a "hash and linear probe" lookup, using h() to
  622. X * calculate the starting hash value and eolist() to perform the linear
  623. X * probe.  This routine DOES NOT detect a table full condition.  That MUST be
  624. X * checked for elsewhere.
  625. X */
  626. X
  627. Xstatic unsigned short
  628. Xhash(pred, foll)        /* find spot in the string table */
  629. X    unsigned short  pred;    /* code for preceeding string */
  630. X    unsigned char   foll;    /* char following string */
  631. X{
  632. X    unsigned short  local, tempnext;    /* scratch storage */
  633. X    struct entry   *ep;    /* allows faster table handling */
  634. X
  635. X    local = (*h) (pred, foll);    /* get initial hash value */
  636. X
  637. X    if (!string_tab[local].used)    /* if that spot is free */
  638. X        return local;    /* then that's all we need */
  639. X
  640. X    else {            /* else a collision has occured */
  641. X        local = eolist(local);    /* move to last duplicate */
  642. X
  643. X        /*
  644. X         * We must find an empty spot. We start looking 101 places
  645. X         * down the table from the last duplicate. 
  646. X         */
  647. X
  648. X        tempnext = (local + 101) & 0x0FFF;
  649. X        ep = &string_tab[tempnext];    /* initialize pointer */
  650. X
  651. X        while (ep->used) {    /* while empty spot not found */
  652. X            if (++tempnext == TABSIZE) {    /* if we are at the end */
  653. X                tempnext = 0;    /* wrap to beginning of table */
  654. X                ep = string_tab;
  655. X            } else
  656. X                ++ep;    /* point to next element in table */
  657. X        }
  658. X
  659. X        /*
  660. X         * local still has the pointer to the last duplicate, while
  661. X         * tempnext has the pointer to the spot we found.  We use
  662. X         * this to maintain the chain of pointers to duplicates. 
  663. X         */
  664. X
  665. X        string_tab[local].next = tempnext;
  666. X
  667. X        return tempnext;
  668. X    }
  669. X}
  670. X
  671. X/*
  672. X * The init_tab() routine is used to initialize our hash table. You realize,
  673. X * of course, that "initialize" is a complete misnomer.
  674. X */
  675. X
  676. Xstatic          void
  677. Xinit_tab()
  678. X{                /* set ground state in hash table */
  679. X    unsigned int    i;    /* table index */
  680. X
  681. X    setmem((char *) string_tab, sizeof(string_tab), 0);
  682. X
  683. X    for (i = 0; i < 256; i++)    /* list all single byte strings */
  684. X        upd_tab(NO_PRED, i);
  685. X
  686. X    inbuf = EMPTY;        /* nothing is in our buffer */
  687. X}
  688. X
  689. X/*
  690. X * The upd_tab routine is used to add a new entry to the string table. As
  691. X * previously stated, no checks are made to ensure that the table has any
  692. X * room.  This must be done elsewhere.
  693. X */
  694. X
  695. Xvoid
  696. Xupd_tab(pred, foll)        /* add an entry to the table */
  697. X    unsigned short  pred;    /* code for preceeding string */
  698. X    unsigned short  foll;    /* character which follows string */
  699. X{
  700. X    struct entry   *ep;    /* pointer to current entry */
  701. X
  702. X    /* calculate offset just once */
  703. X
  704. X    ep = &string_tab[hash(pred, foll)];
  705. X
  706. X    ep->used = TRUE;    /* this spot is now in use */
  707. X    ep->next = 0;        /* no duplicates after this yet */
  708. X    ep->predecessor = pred;    /* note code of preceeding string */
  709. X    ep->follower = foll;    /* note char after string */
  710. X}
  711. X
  712. X/*
  713. X * This algorithm encoded a file into twelve bit strings (three nybbles). The
  714. X * gocode() routine is used to read these strings a byte (or two) at a time.
  715. X */
  716. X
  717. Xstatic          int
  718. Xgocode(fd)            /* read in a twelve bit code */
  719. X    FILE           *fd;    /* file to get code from */
  720. X{
  721. X    unsigned short  localbuf, returnval;
  722. X    int             temp;
  723. X
  724. X    if (inbuf == EMPTY) {    /* if on a code boundary */
  725. X        if ((temp = getc_unp(fd)) == EOF)    /* get start of next
  726. X                             * code */
  727. X            return EOF;    /* pass back end of file status */
  728. X        localbuf = temp & 0xFF;    /* mask down to true byte value */
  729. X        if ((temp = getc_unp(fd)) == EOF)
  730. X            /* get end of code, * start of next */
  731. X            return EOF;    /* this should never happen */
  732. X        inbuf = temp & 0xFF;    /* mask down to true byte value */
  733. X
  734. X        returnval = ((localbuf << 4) & 0xFF0) + ((inbuf >> 4) & 0x00F);
  735. X        inbuf &= 0x000F;/* leave partial code pending */
  736. X    } else {        /* buffer contains first nybble */
  737. X        if ((temp = getc_unp(fd)) == EOF)
  738. X            return EOF;
  739. X        localbuf = temp & 0xFF;
  740. X
  741. X        returnval = localbuf + ((inbuf << 8) & 0xF00);
  742. X        inbuf = EMPTY;    /* note no hanging nybbles */
  743. X    }
  744. X    return returnval;    /* pass back assembled code */
  745. X}
  746. X
  747. Xstatic          void
  748. Xpush(c)                /* push char onto stack */
  749. X    int             c;    /* character to push */
  750. X{
  751. X    stack[sp] = ((char) c);    /* coerce integer into a char */
  752. X
  753. X    if (++sp >= TABSIZE)
  754. X        abort("Stack overflow\n");
  755. X}
  756. X
  757. Xstatic          int
  758. Xpop()
  759. X{                /* pop character from stack */
  760. X    if (sp > 0)
  761. X        return ((int) stack[--sp]);    /* leave ptr at next empty
  762. X                         * slot */
  763. X
  764. X    else
  765. X        return EMPTY;
  766. X}
  767. X
  768. X/***** LEMPEL-ZEV DECOMPRESSION *****/
  769. X
  770. Xstatic int      code_count;    /* needed to detect table full */
  771. Xstatic int      firstc;        /* true only on first character */
  772. X
  773. Xvoid
  774. Xinit_ucr(new)            /* get set for uncrunching */
  775. X    int             new;    /* true to use new hash function */
  776. X{
  777. X    if (new)        /* set proper hash function */
  778. X        h = newh;
  779. X    else
  780. X        h = oldh;
  781. X
  782. X    sp = 0;            /* clear out the stack */
  783. X    init_tab();        /* set up atomic code definitions */
  784. X    code_count = TABSIZE - 256;    /* note space left in table */
  785. X    firstc = 1;        /* true only on first code */
  786. X}
  787. X
  788. Xint
  789. Xgetc_ucr(f)            /* get next uncrunched byte */
  790. X    FILE           *f;    /* file containing crunched data */
  791. X{
  792. X    int             code, newcode;
  793. X    static int      oldcode, finchar;
  794. X    struct entry   *ep;    /* allows faster table handling */
  795. X
  796. X    if (firstc) {        /* first code is always known */
  797. X        firstc = FALSE;    /* but next will not be first */
  798. X        oldcode = gocode(f);
  799. X        return finchar = string_tab[oldcode].follower;
  800. X    }
  801. X    if (!sp) {        /* if stack is empty */
  802. X        if ((code = newcode = gocode(f)) == EOF)
  803. X            return EOF;
  804. X
  805. X        ep = &string_tab[code];    /* initialize pointer */
  806. X
  807. X        if (!ep->used) {/* if code isn't known */
  808. X            code = oldcode;
  809. X            ep = &string_tab[code];    /* re-initialize pointer */
  810. X            push(finchar);
  811. X        }
  812. X        while (ep->predecessor != NO_PRED) {
  813. X            push(ep->follower);    /* decode string backwards */
  814. X            code = ep->predecessor;
  815. X            ep = &string_tab[code];
  816. X        }
  817. X
  818. X        push(finchar = ep->follower);    /* save first character also */
  819. X
  820. X        /*
  821. X         * The above loop will terminate, one way or another, with
  822. X         * string_tab[code].follower equal to the first character in
  823. X         * the string. 
  824. X         */
  825. X
  826. X        if (code_count) {    /* if room left in string table */
  827. X            upd_tab(oldcode, finchar);
  828. X            --code_count;
  829. X        }
  830. X        oldcode = newcode;
  831. X    }
  832. X    return pop();        /* return saved character */
  833. X}
  834. ________This_Is_The_END________
  835. if test `wc -c < arclzw.c` -ne    22109; then
  836.     echo 'shar: arclzw.c was damaged during transit (should have been    22109 bytes)'
  837. fi
  838. fi        ; : end of overwriting check
  839. echo 'x - arcmatch.c'
  840. if test -f arcmatch.c; then echo 'shar: not overwriting arcmatch.c'; else
  841. sed 's/^X//' << '________This_Is_The_END________' > arcmatch.c
  842. X/*
  843. X * $Header: arcmatch.c,v 1.5 88/06/01 19:41:08 hyc Locked $
  844. X */
  845. X
  846. X/*
  847. X * ARC - Archive utility - ARCMATCH
  848. X * 
  849. X * Version 2.17, created on 12/17/85 at 20:32:18
  850. X * 
  851. X * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED
  852. X * 
  853. X * By:  Thom Henderson
  854. X * 
  855. X * Description: This file contains service routines needed to maintain an
  856. X * archive.
  857. X * 
  858. X * Language: Computer Innovations Optimizing C86
  859. X */
  860. X#include <stdio.h>
  861. X#include "arc.h"
  862. X
  863. Xint    strcmp(), strlen();
  864. Xvoid    abort();
  865. Xchar    *strcpy();
  866. X
  867. Xint
  868. Xmatch(n, t)            /* test name against template */
  869. X    char           *n;    /* name to test */
  870. X    char           *t;    /* template to test against */
  871. X{
  872. X#if    MTS
  873. X    fortran         patbuild(), patmatch(), patfree();
  874. X    static int      patlen = (-1);
  875. X    static int      patwork = 0;
  876. X    static int      patswch = 0;
  877. X    char            patccid[4];
  878. X    static char     patchar[2] = "?";
  879. X    static char     oldtemp[16] = 0;
  880. X    int             namlen, RETCODE;
  881. X
  882. X    if (strcmp(t, oldtemp)) {
  883. X        if (patwork)
  884. X            patfree(&patwork);
  885. X        strcpy(oldtemp, t);
  886. X        patlen = strlen(oldtemp);
  887. X        patbuild(oldtemp, &patlen, &patwork, &patswch, patccid, patchar, _retcode RETCODE);
  888. X        if (RETCODE > 8) {
  889. X            printf("MTS: patbuild returned %d\n", RETCODE);
  890. X            abort("bad wildcard in filename");
  891. X        }
  892. X    }
  893. X    namlen = strlen(n);
  894. X    patmatch(n, &namlen, &patwork, _retcode RETCODE);
  895. X    switch (RETCODE) {
  896. X    case 0:
  897. X        return (1);
  898. X    case 4:
  899. X        return (0);
  900. X    default:
  901. X        abort("wildcard pattern match failed");
  902. X    }
  903. X}
  904. X
  905. X#else
  906. X#if    !UNIX
  907. X    upper(n);
  908. X    upper(t);        /* avoid case problems */
  909. X#endif    /* UNIX */
  910. X#if    GEMDOS
  911. X    return(pnmatch(n, t, 0));
  912. X#else
  913. X    /* first match name part */
  914. X
  915. X    while ((*n && *n != '.') || (*t && *t != '.')) {
  916. X        if (*n != *t && *t != '?') {    /* match fail? */
  917. X            if (*t != '*')    /* wildcard fail? */
  918. X                return 0;    /* then no match */
  919. X            else {    /* else jump over wildcard */
  920. X                while (*n && *n != '.')
  921. X                    n++;
  922. X                while (*t && *t != '.')
  923. X                    t++;
  924. X                break;    /* name part matches wildcard */
  925. X            }
  926. X        } else {    /* match good for this char */
  927. X            n++;    /* advance to next char */
  928. X            t++;
  929. X        }
  930. X    }
  931. X
  932. X    if (*n && *n == '.')
  933. X        n++;        /* skip extension delimiters */
  934. X    if (*t && *t == '.')
  935. X        t++;
  936. X
  937. X    /* now match name part */
  938. X
  939. X    while (*n || *t) {
  940. X        if (*n != *t && *t != '?') {    /* match fail? */
  941. X            if (*t != '*')    /* wildcard fail? */
  942. X                return 0;    /* then no match */
  943. X            else
  944. X                return 1;    /* else good enough */
  945. X        } else {    /* match good for this char */
  946. X            n++;    /* advance to next char */
  947. X            t++;
  948. X        }
  949. X    }
  950. X
  951. X    return 1;        /* match worked */
  952. X#endif    /* GEMDOS */
  953. X}
  954. X#endif
  955. X
  956. Xvoid
  957. Xrempath(nargs, arg)        /* remove paths from filenames */
  958. X    int             nargs;    /* number of names */
  959. X    char           *arg[];    /* pointers to names */
  960. X{
  961. X    char           *i, *rindex();    /* string index, reverse indexer */
  962. X    int             n;    /* index */
  963. X
  964. X    for (n = 0; n < nargs; n++) {    /* for each supplied name */
  965. X        if (!(i = rindex(arg[n], '\\')))    /* search for end of
  966. X                             * path */
  967. X            if (!(i = rindex(arg[n], '/')))
  968. X                i = rindex(arg[n], ':');
  969. X        if (i)        /* if path was found */
  970. X            arg[n] = i + 1;    /* then skip it */
  971. X    }
  972. X}
  973. ________This_Is_The_END________
  974. if test `wc -c < arcmatch.c` -ne     3026; then
  975.     echo 'shar: arcmatch.c was damaged during transit (should have been     3026 bytes)'
  976. fi
  977. fi        ; : end of overwriting check
  978. echo 'x - arcmisc.c'
  979. if test -f arcmisc.c; then echo 'shar: not overwriting arcmisc.c'; else
  980. sed 's/^X//' << '________This_Is_The_END________' > arcmisc.c
  981. X/*
  982. X * Miscellaneous routines to get ARC running on non-MSDOS systems...
  983. X * $Header: arcmisc.c,v 1.7 88/06/12 19:23:13 hyc Locked $ 
  984. X */
  985. X
  986. X#include <stdio.h>
  987. X#include <ctype.h>
  988. X#include "arc.h"
  989. X
  990. X#if    MSDOS
  991. X#include <dir.h>
  992. X#include <stat.h>
  993. X#endif
  994. X
  995. X#if    GEMDOS
  996. X#include <osbind.h>
  997. X#include <stat.h>
  998. Xchar           *index(), *rindex();
  999. X
  1000. Xvoid 
  1001. Xexitpause()
  1002. X{
  1003. X    while (Cconis())
  1004. X        Cnecin();
  1005. X    fprintf(stderr, "Press any key to continue: ");
  1006. X    fflush(stderr);
  1007. X    Cnecin();
  1008. X    fprintf(stderr, "\n");
  1009. X}
  1010. X
  1011. Xint
  1012. Xchdir(dirname)
  1013. X    char           *dirname;
  1014. X{
  1015. X    char           *i;
  1016. X    int             drv;
  1017. X
  1018. X    i = dirname;
  1019. X    if ((i = index(dirname, ':')) != NULL) {
  1020. X        drv = i[-1];
  1021. X        i++;        /* Move past device spec */
  1022. X        if (drv > '\'')
  1023. X            drv -= 'a';
  1024. X        else
  1025. X            drv -= 'A';
  1026. X        if (drv >= 0 && drv < 16)
  1027. X            Dsetdrv(drv);
  1028. X    }
  1029. X    if (*i != '\0')
  1030. X        return (Dsetpath(i));
  1031. X}
  1032. X#endif
  1033. X
  1034. X#if    UNIX
  1035. X#include <sys/types.h>
  1036. X#include <sys/dir.h>
  1037. X#include <sys/stat.h>
  1038. X    int    rename();
  1039. X#endif
  1040. X
  1041. X#if    SYSV
  1042. X#include <dirent.h>
  1043. X#define DIRECT dirent
  1044. X#else
  1045. X#define DIRECT direct
  1046. X#endif
  1047. X
  1048. Xchar           *strcpy(), *strcat(), *malloc();
  1049. Xint             strlen();
  1050. X
  1051. Xint
  1052. Xmove(oldnam, newnam)
  1053. X    char           *oldnam, *newnam;
  1054. X{
  1055. X    FILE           *fopen(), *old, *new;
  1056. X    struct stat     oldstat;
  1057. X    char           *strcpy();
  1058. X    void        filecopy();
  1059. X#if    GEMDOS
  1060. X    if (Frename(0, oldnam, newnam))
  1061. X#else
  1062. X    if (rename(oldnam, newnam))
  1063. X#endif
  1064. X    {
  1065. X        if (stat(oldnam, &oldstat))    /* different partition? */
  1066. X            return (-1);
  1067. X        old = fopen(oldnam, "rb");
  1068. X        if (old == NULL)
  1069. X            return (-1);
  1070. X        new = fopen(newnam, "wb");
  1071. X        if (new == NULL)
  1072. X            return (-1);
  1073. X        filecopy(old, new, oldstat.st_size);
  1074. X        unlink(oldnam);
  1075. X    }
  1076. X    return 0;
  1077. X}
  1078. X
  1079. Xstatic void
  1080. X_makefn(source, dest)
  1081. X    char           *source;
  1082. X    char           *dest;
  1083. X{
  1084. X    int             j;
  1085. X#if    MSDOS
  1086. X    char           *setmem();
  1087. X#else
  1088. X    char           *memset();
  1089. X#endif
  1090. X
  1091. X    setmem(dest, 17, 0);    /* clear result field */
  1092. X    for (j = 0; *source && *source != '.'; ++source)
  1093. X        if (j < 8)
  1094. X            dest[j++] = *source;
  1095. X    for (j = 9; *source; ++source)
  1096. X        if (j < 13)
  1097. X            dest[j++] = *source;
  1098. X}
  1099. X/*
  1100. X * make a file name using a template 
  1101. X */
  1102. X
  1103. Xchar           *
  1104. Xmakefnam(rawfn, template, result)
  1105. X    char           *rawfn;    /* the original file name */
  1106. X    char           *template;    /* the template data */
  1107. X    char           *result;    /* where to place the result */
  1108. X{
  1109. X    char            et[17], er[17], rawbuf[STRLEN], *i, *rindex();
  1110. X
  1111. X    *rawbuf = 0;
  1112. X    strcpy(rawbuf, rawfn);
  1113. X#if    MTS
  1114. X    i = rawbuf;
  1115. X    if (rawbuf[0] == tmpchr[0]) {
  1116. X        i++;
  1117. X        strcpy(rawfn, i);
  1118. X    } else
  1119. X#endif
  1120. X    if ((i = rindex(rawbuf, CUTOFF))) {
  1121. X        i++;
  1122. X        strcpy(rawfn, i);
  1123. X    }
  1124. X#if    DOS
  1125. X    else if ((i = rindex(rawbuf, ':'))) {
  1126. X        i++;
  1127. X        strcpy(rawfn, i);
  1128. X    }
  1129. X#endif
  1130. X    if (i)
  1131. X        *i = 0;
  1132. X    else
  1133. X        *rawbuf = 0;
  1134. X
  1135. X    _makefn(template, et);
  1136. X    _makefn(rawfn, er);
  1137. X    *result = 0;        /* assure no data */
  1138. X    strcat(result, rawbuf);
  1139. X    strcat(result, er[0] ? er : et);
  1140. X    strcat(result, er[9] ? er + 9 : et + 9);
  1141. X    return ((char *) &result[0]);
  1142. X}
  1143. X
  1144. X#if    MSDOS || SYSV
  1145. X
  1146. Xint
  1147. Xalphasort(dirptr1, dirptr2)
  1148. X    struct DIRECT **dirptr1, **dirptr2;
  1149. X{
  1150. X    return (strcmp((*dirptr1)->d_name, (*dirptr2)->d_name));
  1151. X}
  1152. X
  1153. X#endif
  1154. X
  1155. Xvoid
  1156. Xupper(string)
  1157. X    char           *string;
  1158. X{
  1159. X    char           *p;
  1160. X
  1161. X    for (p = string; *p; p++)
  1162. X        if (islower(*p))
  1163. X            *p = toupper(*p);
  1164. X}
  1165. X/* VARARGS1 */
  1166. Xvoid
  1167. Xabort(s, arg1, arg2, arg3)
  1168. X    char           *s;
  1169. X{
  1170. X    fprintf(stderr, "ARC: ");
  1171. X    fprintf(stderr, s, arg1, arg2, arg3);
  1172. X    fprintf(stderr, "\n");
  1173. X#if    UNIX
  1174. X    perror("UNIX");
  1175. X#endif
  1176. X#if    GEMDOS
  1177. X    exitpause();
  1178. X#endif
  1179. X    exit(1);
  1180. X}
  1181. X
  1182. X#if    !MTS
  1183. X
  1184. Xchar           *
  1185. Xgcdir(dirname)
  1186. X    char           *dirname;
  1187. X
  1188. X{
  1189. X    char           *getwd();
  1190. X#if    GEMDOS
  1191. X    int             drv;
  1192. X    char           *buf;
  1193. X#endif
  1194. X    if (dirname == NULL || strlen(dirname) == 0)
  1195. X        dirname = (char *) malloc(1024);
  1196. X
  1197. X#if    !GEMDOS
  1198. X    getwd(dirname);
  1199. X#else
  1200. X    buf = dirname;
  1201. X    *buf++ = (drv = Dgetdrv()) + 'A';
  1202. X    *buf++ = ':';
  1203. X    Dgetpath(buf, 0);
  1204. X#endif
  1205. X    return (dirname);
  1206. X}
  1207. X
  1208. X#if    UNIX
  1209. Xchar           *pattern;    /* global so that fmatch can use it */
  1210. X#endif
  1211. X
  1212. Xchar           *
  1213. Xdir(filename)        /* get files, one by one */
  1214. X    char           *filename;    /* template, or NULL */
  1215. X{
  1216. X#if    GEMDOS
  1217. X    static int      Nnum = 0;
  1218. X    static DMABUFFER dbuf, *saved;
  1219. X    char           *name;
  1220. X
  1221. X    if (Nnum == 0) {    /* first call */
  1222. X        saved = (DMABUFFER *) Fgetdta();
  1223. X        Fsetdta(&dbuf);
  1224. X        if (Fsfirst(filename, 0) == 0) {
  1225. X            name = malloc(FNLEN);
  1226. X            strcpy(name, dbuf.d_fname);
  1227. X            Nnum++;
  1228. X            return (name);
  1229. X        } else {
  1230. X            Fsetdta(saved);
  1231. X            return (NULL);
  1232. X        }
  1233. X    } else {
  1234. X        if (Fsnext() == 0) {
  1235. X            name = malloc(FNLEN);
  1236. X            strcpy(name, dbuf.d_fname);
  1237. X            return (name);
  1238. X        } else {
  1239. X            Nnum = 0;
  1240. X            Fsetdta(saved);
  1241. X            return (NULL);
  1242. X        }
  1243. X    }
  1244. X}
  1245. X#else
  1246. X    static struct DIRECT **namelist;
  1247. X    static char   **NameList;
  1248. X    static char    namecopy[STRLEN], *dirname;
  1249. X#if    UNIX
  1250. X    int             alphasort();
  1251. X    int             scandir();
  1252. X#endif                /* UNIX */
  1253. X    int             fmatch();
  1254. X    static int      Nnum = 0, ii;
  1255. X    char        *rindex();
  1256. X
  1257. X
  1258. X    if (Nnum == 0) {    /* first call */
  1259. X        strcpy(namecopy,filename);
  1260. X        if(pattern=rindex(namecopy,CUTOFF)) {
  1261. X            *pattern = 0;
  1262. X            pattern++;
  1263. X            dirname = namecopy;
  1264. X        } else {
  1265. X            pattern = filename;
  1266. X            dirname = ".";
  1267. X        }
  1268. X        Nnum = scandir(dirname, &namelist, fmatch, alphasort);
  1269. X        NameList = (char **) malloc(Nnum * sizeof(char *));
  1270. X        for (ii = 0; ii < Nnum; ii++) {
  1271. X            (NameList)[ii] = malloc(strlen(namelist[ii]->d_name) + 1);
  1272. X            strcpy((NameList)[ii], namelist[ii]->d_name);
  1273. X        }
  1274. X        ii = 0;
  1275. X    }
  1276. X    if (ii >= Nnum) {    /* all out of files */
  1277. X        if (Nnum) {    /* there were some files found */
  1278. X            for (ii = 0; ii < Nnum; ii++)
  1279. X                free(namelist[ii]);
  1280. X            free(namelist);
  1281. X        }
  1282. X        Nnum = 0;
  1283. X        return (NULL);
  1284. X    } else {
  1285. X        return ((NameList)[ii++]);
  1286. X    }
  1287. X}
  1288. X
  1289. X/*
  1290. X * Filename match - here, * matches everything 
  1291. X */
  1292. X
  1293. Xint
  1294. Xfmatch(direntry)
  1295. X    struct DIRECT  *direntry;
  1296. X{
  1297. X    char           *string;
  1298. X
  1299. X    string = direntry->d_name;
  1300. X
  1301. X    if (!strcmp(pattern, "") || !strcmp(pattern, "*.*") || !strcmp(pattern, "*"))
  1302. X        return (1);
  1303. X    return (match(string, pattern));
  1304. X}
  1305. X#endif                /* GEMDOS */
  1306. X#else
  1307. X/* dir code for MTS under Bell Labs C... */
  1308. X
  1309. Xchar           *
  1310. Xdir(filepattern)
  1311. X    char           *filepattern;    /* template or NULL */
  1312. X{
  1313. X    char           *malloc(), *index();
  1314. X#if    USECATSCAN
  1315. X    fortran void    catscan(), fileinfo();
  1316. X
  1317. X    struct catname {
  1318. X        short           len;
  1319. X        char            name[257];
  1320. X    }               pattern;
  1321. X
  1322. X    struct catval {
  1323. X        int             maxlen;
  1324. X        int             actlen;
  1325. X        char            name[257];
  1326. X    }               catreturn;
  1327. X
  1328. X    char           *i;
  1329. X    int             j, RETCODE;
  1330. X
  1331. X    static int      catptr = 0;
  1332. X    static int      catflag = 0x200;
  1333. X    static int      cattype = 1;
  1334. X    static int      patflag = 0;
  1335. X
  1336. X    catreturn.maxlen = 256;
  1337. X
  1338. X    if (patflag) {
  1339. X        patflag = 0;
  1340. X        catptr = 0;
  1341. X        return (NULL);
  1342. X    }
  1343. X    if (filepattern) {
  1344. X        strcpy(pattern.name, filepattern);
  1345. X        pattern.len = strlen(filepattern);
  1346. X        if (!index(filepattern, '?'))
  1347. X            patflag = 1;
  1348. X    }
  1349. X    if (patflag) {
  1350. X        fileinfo(&pattern, &cattype, "CINAME  ", &catreturn, _retcode RETCODE);
  1351. X        catptr = RETCODE ? 0 : 1;
  1352. X    } else
  1353. X        catscan(&pattern, &catflag, &cattype, &catreturn, &catptr);
  1354. X
  1355. X    if (!catptr)
  1356. X        return (NULL);
  1357. X    else {
  1358. X        char           *k;
  1359. X
  1360. X        k = index(catreturn.name, ' ');
  1361. X        if (k)
  1362. X            *k = 0;
  1363. X        else {
  1364. X            j = catreturn.actlen;
  1365. X            catreturn.name[j] = 0;
  1366. X        }
  1367. X        k = catreturn.name;
  1368. X        if (catreturn.name[0] == tmpchr[0])
  1369. X            k++;
  1370. X        else if ((k = index(catreturn.name, sepchr[0])))
  1371. X            k++;
  1372. X        else
  1373. X            k = catreturn.name;
  1374. X        j = strlen(k);
  1375. X        i = malloc(++j);
  1376. X        strcpy(i, k);
  1377. X        return (i);
  1378. X    }
  1379. X#else
  1380. X    fortran void    gfinfo();
  1381. X    static char     gfname[24];
  1382. X    static char     pattern[20];
  1383. X    static int      gfdummy[2] = {
  1384. X                      0, 0
  1385. X    },              gfflags;
  1386. X    int             i, RETCODE;
  1387. X    char           *j, *k;
  1388. X
  1389. X    if (filepattern) {
  1390. X        strcpy(pattern, filepattern);
  1391. X        strcat(pattern, " ");
  1392. X        for (i = 20; i < 24; i++)
  1393. X            gfname[i] = '\0';
  1394. X        if (index(pattern, '?'))
  1395. X            gfflags = 0x0C;
  1396. X        else
  1397. X            gfflags = 0x09;
  1398. X    } else if (gfflags == 0x09)
  1399. X        return (NULL);
  1400. X
  1401. X    gfinfo(pattern, gfname, &gfflags, gfdummy, gfdummy, gfdummy, _retcode RETCODE);
  1402. X    if (RETCODE)
  1403. X        return (NULL);
  1404. X    else {
  1405. X        k = index(gfname, ' ');
  1406. X        *k = '\0';
  1407. X        k = gfname;
  1408. X        if (gfname[0] == tmpchr[0])
  1409. X            k++;
  1410. X        else if ((k = index(gfname, sepchr[0])))
  1411. X            k++;
  1412. X        else
  1413. X            k = gfname;
  1414. X        i = strlen(k);
  1415. X        j = malloc(++i);
  1416. X        strcpy(j, k);
  1417. X        return (j);
  1418. X    }
  1419. X#endif
  1420. X}
  1421. X
  1422. Xint
  1423. Xunlink(path)
  1424. X    char           *path;    /* name of file to delete */
  1425. X{
  1426. X    fortran void    destroy();
  1427. X    int             RETCODE;
  1428. X
  1429. X    char            name[258];
  1430. X
  1431. X    strcpy(name, path);
  1432. X    strcat(name, " ");
  1433. X    destroy(name, _retcode RETCODE);
  1434. X    if (RETCODE)
  1435. X        return (-1);
  1436. X    else
  1437. X        return (0);
  1438. X}
  1439. X#endif
  1440. ________This_Is_The_END________
  1441. if test `wc -c < arcmisc.c` -ne     8418; then
  1442.     echo 'shar: arcmisc.c was damaged during transit (should have been     8418 bytes)'
  1443. fi
  1444. fi        ; : end of overwriting check
  1445. echo 'x - arcpack.c'
  1446. if test -f arcpack.c; then echo 'shar: not overwriting arcpack.c'; else
  1447. sed 's/^X//' << '________This_Is_The_END________' > arcpack.c
  1448. X/*
  1449. X * $Header: arcpack.c,v 1.9 88/06/02 16:27:36 hyc Locked $
  1450. X */
  1451. X
  1452. X/*  ARC - Archive utility - ARCPACK
  1453. X
  1454. X    Version 3.49, created on 04/21/87 at 11:26:51
  1455. X
  1456. X(C) COPYRIGHT 1985-87 by System Enhancement Associates; ALL RIGHTS RESERVED
  1457. X
  1458. X    By:     Thom Henderson
  1459. X
  1460. X    Description:
  1461. X     This file contains the routines used to compress a file
  1462. X     when placing it in an archive.
  1463. X
  1464. X    Language:
  1465. X     Computer Innovations Optimizing C86
  1466. X*/
  1467. X#include <stdio.h>
  1468. X#include "arc.h"
  1469. X#if    MTS
  1470. X#include <ctype.h>
  1471. X#endif
  1472. X
  1473. Xvoid    setcode(), sqinit_cm(), sqputc_cm(), init_cm(), putc_cm();
  1474. Xvoid    filecopy(), abort(), putc_tst();
  1475. Xint    getch(), addcrc();
  1476. X
  1477. X/* stuff for non-repeat packing */
  1478. X
  1479. X#define DLE 0x90        /* repeat sequence marker */
  1480. X
  1481. Xstatic unsigned char state;    /* current packing state */
  1482. X
  1483. X/* non-repeat packing states */
  1484. X
  1485. X#define NOHIST  0        /* don't consider previous input */
  1486. X#define SENTCHAR 1        /* lastchar set, no lookahead yet */
  1487. X#define SENDNEWC 2        /* run over, send new char next */
  1488. X#define SENDCNT 3        /* newchar set, send count next */
  1489. X
  1490. X/* packing results */
  1491. X
  1492. Xstatic long     stdlen;        /* length for standard packing */
  1493. Xstatic short    crcval;        /* CRC check value */
  1494. X
  1495. Xvoid
  1496. Xpack(f, t, hdr)            /* pack file into an archive */
  1497. X    FILE           *f, *t;    /* source, destination */
  1498. X    struct heads   *hdr;    /* pointer to header data */
  1499. X{
  1500. X    int             c;    /* one character of stream */
  1501. X    long            ncrlen;    /* length after packing */
  1502. X    long        huflen;    /* length after squeezing */
  1503. X    long            lzwlen;    /* length after crunching */
  1504. X    long        pred_sq(), file_sq();    /* stuff for squeezing */
  1505. X    long            pred_cm(), sqpred_cm();    /* dynamic crunching cleanup */
  1506. X    long            tloc, ftell();    /* start of output */
  1507. X    int        getch();
  1508. X    int             getc_ncr();
  1509. X    void            putc_pak();
  1510. X
  1511. X    /* first pass - see which method is best */
  1512. X
  1513. X    tloc = ftell(t);    /* note start of output */
  1514. X
  1515. X    if (!nocomp) {        /* if storage kludge not active */
  1516. X        if (note) {
  1517. X            printf(" analyzing, ");
  1518. X            fflush(stdout);
  1519. X        }
  1520. X        state = NOHIST;    /* initialize ncr packing */
  1521. X        stdlen = ncrlen = 0;    /* reset size counters */
  1522. X        crcval = 0;    /* initialize CRC check value */
  1523. X        setcode();    /* initialize encryption */
  1524. X        init_sq();    /* initialize for squeeze scan */
  1525. X
  1526. X        if (dosquash) {
  1527. X            sqinit_cm();
  1528. X            while ((c = getch(f)) != EOF) {    /* for each byte of file */
  1529. X                ncrlen++;    /* one more packed byte */
  1530. X                scan_sq(c);    /* see what squeezing can do */
  1531. X                sqputc_cm(c, t);    /* see what squashing
  1532. X                             * can do */
  1533. X            }
  1534. X            lzwlen = sqpred_cm(t);
  1535. X        } else {
  1536. X            init_cm(t);    /* initialize for crunching */
  1537. X    
  1538. X            while ((c = getc_ncr(f)) != EOF) {    /* for each byte of file */
  1539. X                ncrlen++;    /* one more packed byte */
  1540. X                scan_sq(c);    /* see what squeezing can do */
  1541. X                putc_cm(c, t);    /* see what crunching can do */
  1542. X            }
  1543. X            lzwlen = pred_cm(t);    /* finish up after crunching */
  1544. X        }
  1545. X        huflen = pred_sq();    /* finish up after squeezing */
  1546. X    } else {        /* else kludge the method */
  1547. X        stdlen = 0;    /* make standard look best */
  1548. X        ncrlen = huflen = lzwlen = 1;
  1549. X    }
  1550. X
  1551. X    /* standard set-ups common to all methods */
  1552. X
  1553. X    fseek(f, 0L, 0);    /* rewind input */
  1554. X    hdr->crc = crcval;    /* note CRC check value */
  1555. X    hdr->length = stdlen;    /* set actual file length */
  1556. X    state = NOHIST;        /* reinitialize ncr packing */
  1557. X    setcode();        /* reinitialize encryption */
  1558. X
  1559. X    /* choose and use the shortest method */
  1560. X
  1561. X    if (kludge && note)
  1562. X        printf("\n\tS:%ld  P:%ld  S:%ld  C:%ld,\t ",
  1563. X            stdlen, ncrlen, huflen, lzwlen);
  1564. X
  1565. X    if (stdlen <= ncrlen && stdlen <= huflen && stdlen <= lzwlen) {
  1566. X        if (note) {
  1567. X            printf("storing, ");    /* store without compression */
  1568. X            fflush(stdout);
  1569. X        }
  1570. X        hdrver = 2;    /* note packing method */
  1571. X        fseek(t, tloc, 0);    /* reset output for new method */
  1572. X        stdlen = crcval = 0;    /* recalc these for kludge */
  1573. X        while ((c = getch(f)) != EOF)    /* store it straight */
  1574. X            putc_pak(c, t);
  1575. X        hdr->crc = crcval;
  1576. X        hdr->length = hdr->size = stdlen;
  1577. X    } else if (ncrlen < lzwlen && ncrlen < huflen) {
  1578. X        if (note) {
  1579. X            printf("packing, ");    /* pack with repeat
  1580. X            fflush(stdout);         * suppression */
  1581. X        }
  1582. X        hdrver = 3;    /* note packing method */
  1583. X        hdr->size = ncrlen;    /* set data length */
  1584. X        fseek(t, tloc, 0);    /* reset output for new method */
  1585. X        while ((c = getc_ncr(f)) != EOF)
  1586. X            putc_pak(c, t);
  1587. X    } else if (huflen < lzwlen) {
  1588. X        if (note) {
  1589. X            printf("squeezing, ");
  1590. X            fflush(stdout);
  1591. X        }
  1592. X        hdrver = 4;    /* note packing method */
  1593. X        fseek(t, tloc, 0);    /* reset output for new method */
  1594. X        hdr->size = file_sq(f, t);    /* note final size */
  1595. X    } else {
  1596. X        if (note)
  1597. X            printf(dosquash ? "squashed, " : "crunched, ");
  1598. X        hdrver = dosquash ? 9 : 8;
  1599. X        hdr->size = lzwlen;    /* size should not change */
  1600. X    }
  1601. X
  1602. X    /* standard cleanups common to all methods */
  1603. X
  1604. X    if (note)
  1605. X        printf("done. (%ld%%)\n",100L - (100L*hdr->size)/hdr->length);
  1606. X}
  1607. X
  1608. X/*
  1609. X * Non-repeat compression - text is passed through normally, except that a
  1610. X * run of more than two is encoded as:
  1611. X * 
  1612. X * <char> <DLE> <count>
  1613. X * 
  1614. X * Special case: a count of zero indicates that the DLE is really a DLE, not a
  1615. X * repeat marker.
  1616. X */
  1617. X
  1618. Xint
  1619. Xgetc_ncr(f)            /* get bytes with collapsed runs */
  1620. X    FILE           *f;    /* file to get from */
  1621. X{
  1622. X    static int      lastc;    /* value returned on last call */
  1623. X    static int      repcnt;    /* repetition counter */
  1624. X    static int      c;    /* latest value seen */
  1625. X
  1626. X    switch (state) {    /* depends on our state */
  1627. X    case NOHIST:        /* no relevant history */
  1628. X        state = SENTCHAR;
  1629. X        return lastc = getch(f);    /* remember the value next
  1630. X                         * time */
  1631. X
  1632. X    case SENTCHAR:        /* char was sent. look ahead */
  1633. X        switch (lastc) {/* action depends on char */
  1634. X        case DLE:    /* if we sent a real DLE */
  1635. X            state = NOHIST;    /* then start over again */
  1636. X            return 0;    /* but note that the DLE was real */
  1637. X
  1638. X        case EOF:    /* EOF is always a special case */
  1639. X            return EOF;
  1640. X
  1641. X        default:    /* else test for a repeat */
  1642. X            for (repcnt = 1; (c = getch(f)) == lastc && repcnt < 255; repcnt++);
  1643. X            /* find end of run */
  1644. X
  1645. X            switch (repcnt) {    /* action depends on run size */
  1646. X            case 1:/* not a repeat */
  1647. X                return lastc = c;    /* but remember value
  1648. X                             * next time */
  1649. X
  1650. X            case 2:/* a repeat, but too short */
  1651. X                state = SENDNEWC;    /* send the second one
  1652. X                             * next time */
  1653. X                return lastc;
  1654. X
  1655. X            default:    /* a run - compress it */
  1656. X                state = SENDCNT;    /* send repeat count
  1657. X                             * next time */
  1658. X                return DLE;    /* send repeat marker this
  1659. X                         * time */
  1660. X            }
  1661. X        }
  1662. X
  1663. X    case SENDNEWC:        /* send second char of short run */
  1664. X        state = SENTCHAR;
  1665. X        return lastc = c;
  1666. X
  1667. X    case SENDCNT:        /* sent DLE, now send count */
  1668. X        state = SENDNEWC;
  1669. X        return repcnt;
  1670. X
  1671. X    default:
  1672. X        abort("Bug - bad ncr state\n");
  1673. X    }
  1674. X}
  1675. X
  1676. Xint
  1677. Xgetch(f)            /* special get char for packing */
  1678. X    FILE           *f;    /* file to get from */
  1679. X{
  1680. X    int        c;    /* a char from the file */
  1681. X#if    !DOS
  1682. X    static int      cr = 0;    /* add \r before \n ? */
  1683. X
  1684. X    if (cr) {
  1685. X        c = '\n';
  1686. X#if    MTS
  1687. X        c = toascii(c);
  1688. X#endif
  1689. X        crcval = addcrc(crcval, c);
  1690. X        stdlen++;
  1691. X        cr = 0;
  1692. X        return (c);
  1693. X    }
  1694. X#endif
  1695. X
  1696. X    if ((c = fgetc(f)) != EOF) {    /* if not the end of file */
  1697. X#if    !DOS
  1698. X        if (!image && (c == '\n')) {
  1699. X            c = '\r';
  1700. X            cr = 1;
  1701. X        }
  1702. X#endif
  1703. X#if    MTS
  1704. X        if (!image)
  1705. X            c = toascii(c);
  1706. X#endif
  1707. X        crcval = addcrc(crcval, c);    /* then update CRC check
  1708. X                         * value */
  1709. X        stdlen++;    /* and bump length counter */
  1710. X    }
  1711. X    return c;
  1712. X}
  1713. X
  1714. Xvoid
  1715. Xputc_pak(c, f)            /* put a packed byte into archive */
  1716. X    char            c;    /* byte to put */
  1717. X    FILE           *f;    /* archive to put it in */
  1718. X{
  1719. X    unsigned char        code();
  1720. X    putc_tst(code(c), f);    /* put encoded byte, with checks */
  1721. X}
  1722. ________This_Is_The_END________
  1723. if test `wc -c < arcpack.c` -ne     7376; then
  1724.     echo 'shar: arcpack.c was damaged during transit (should have been     7376 bytes)'
  1725. fi
  1726. fi        ; : end of overwriting check
  1727. echo 'x - arcrun.c'
  1728. if test -f arcrun.c; then echo 'shar: not overwriting arcrun.c'; else
  1729. sed 's/^X//' << '________This_Is_The_END________' > arcrun.c
  1730. X/*
  1731. X * $Header: arcrun.c,v 1.3 88/06/01 19:57:16 hyc Locked $
  1732. X */
  1733. X
  1734. X/*
  1735. X * ARC - Archive utility - ARCRUN
  1736. X * 
  1737. X * Version 1.20, created on 03/24/86 at 19:34:31
  1738. X * 
  1739. X * (C) COPYRIGHT 1985,85 by System Enhancement Associates; ALL RIGHTS RESERVED
  1740. X * 
  1741. X * By:  Thom Henderson
  1742. X * 
  1743. X * Description: This file contains the routines used to "run" a file which is
  1744. X * stored in an archive.  At present, all we really do is (a) extract a
  1745. X * temporary file, (b) give its name as a system command, and then (c) delete
  1746. X * the file.
  1747. X * 
  1748. X * Language: Computer Innovations Optimizing C86
  1749. X */
  1750. X#include <stdio.h>
  1751. X#include "arc.h"
  1752. X
  1753. Xvoid    rempath(), openarc(), closearc(), abort();
  1754. Xchar    *strcat();
  1755. X
  1756. Xvoid
  1757. Xrunarc(num, arg)        /* run file from archive */
  1758. X    int             num;    /* number of arguments */
  1759. X    char           *arg[];    /* pointers to arguments */
  1760. X{
  1761. X    struct heads    hdr;    /* file header */
  1762. X    char           *makefnam();    /* filename fixer */
  1763. X    char            buf[STRLEN];    /* filename buffer */
  1764. X    FILE           *fopen();/* file opener */
  1765. X    int             runfile();
  1766. X    char           *dummy[2];
  1767. X
  1768. X    dummy[0]="dummy";
  1769. X    dummy[1]=NULL;
  1770. X    rempath(num, arg);    /* strip off paths */
  1771. X
  1772. X    openarc(0);        /* open archive for reading */
  1773. X
  1774. X    if (num) {        /* if files were named */
  1775. X        while (readhdr(&hdr, arc)) {    /* while more files to check */
  1776. X            if (match(hdr.name, makefnam(arg[0], ".*", buf)))
  1777. X                runfile(&hdr, num, arg);
  1778. X            else
  1779. X                fseek(arc, hdr.size, 1);
  1780. X        }
  1781. X    } else
  1782. X        while (readhdr(&hdr, arc))    /* else run all files */
  1783. X            runfile(&hdr, 1, dummy);
  1784. X
  1785. X    closearc(0);        /* close archive after changes */
  1786. X}
  1787. X
  1788. Xstatic          int
  1789. Xrunfile(hdr, num, arg)        /* run a file */
  1790. X    struct heads   *hdr;    /* pointer to header data */
  1791. X    int             num;    /* number of arguments */
  1792. X    char           *arg[];    /* pointers to arguments */
  1793. X{
  1794. X    FILE           *tmp, *fopen();    /* temporary file */
  1795. X    char           *dir, *gcdir();    /* directory stuff */
  1796. X    char            buf[STRLEN], *makefnam();    /* temp file name, fixer */
  1797. X#if    DOS
  1798. X    char        nbuf[64], *i, *rindex();
  1799. X#endif
  1800. X#if    !GEMDOS
  1801. X    int             n;    /* index */
  1802. X    char            sys[STRLEN];    /* invocation command buffer */
  1803. X#endif
  1804. X
  1805. X    /* makefnam("$ARCTEMP",hdr->name,buf); */
  1806. X#if    UNIX
  1807. X    sprintf(buf, "%s.RUN", arctemp);
  1808. X    strcpy(sys, buf);
  1809. X#else
  1810. X    strcpy(nbuf, arctemp);
  1811. X    makefnam(nbuf,hdr->name,buf);
  1812. X    i = rindex(buf,'.');
  1813. X#endif
  1814. X#if    MSDOS
  1815. X    if (!strcmp(i, ".BAS")) {
  1816. X        strcpy(sys, "BASICA ");
  1817. X        strcat(sys, buf);
  1818. X    }
  1819. X    else if (!strcmp(i, ".BAT")
  1820. X         || !strcmp(i, ".COM")
  1821. X         || !strcmp(i, ".EXE"))
  1822. X        strcpy(sys, buf);
  1823. X
  1824. X    else {
  1825. X        if (warn) {
  1826. X            printf("File %s is not a .BAS, .BAT, .COM, or .EXE\n",
  1827. X                   hdr->name);
  1828. X            nerrs++;
  1829. X        }
  1830. X        fseek(arc, hdr->size, 1);    /* skip this file */
  1831. X        return;
  1832. X    }
  1833. X#endif
  1834. X#if    GEMDOS
  1835. X      if (strcmp(i, ".PRG")
  1836. X              && strcmp(i, ".TTP")
  1837. X              && strcmp(i, ".TOS"))
  1838. X      {
  1839. X              if (warn) {
  1840. X                      printf("File %s is not a .PRG, .TOS, or .TTP\n",
  1841. X                              hdr->name);
  1842. X                      nerrs++;
  1843. X              }
  1844. X              fseek(arc, hdr->size, 1);       /* skip this file */
  1845. X              return;
  1846. X      }
  1847. X#endif
  1848. X
  1849. X    if (warn)
  1850. X        if (tmp = fopen(buf, "r"))
  1851. X            abort("Temporary file %s already exists", buf);
  1852. X    if (!(tmp = fopen(buf, "wb")))
  1853. X        abort("Unable to create temporary file %s", buf);
  1854. X
  1855. X    if (note)
  1856. X        printf("Invoking file: %s\n", hdr->name);
  1857. X
  1858. X    dir = gcdir("");    /* see where we are */
  1859. X    unpack(arc, tmp, hdr);    /* unpack the entry */
  1860. X    fclose(tmp);        /* release the file */
  1861. X    chmod(buf, "700");    /* make it executable */
  1862. X#if    GEMDOS
  1863. X    execve(buf, arg, NULL);
  1864. X#else
  1865. X    for (n = 1; n < num; n++) {    /* add command line arguments */
  1866. X        strcat(sys, " ");
  1867. X        strcat(sys, arg[n]);
  1868. X    }
  1869. X    system(buf);        /* try to invoke it */
  1870. X#endif
  1871. X    chdir(dir);
  1872. X    free(dir);        /* return to whence we started */
  1873. X    if (unlink(buf) && warn) {
  1874. X        printf("Cannot unsave temporary file %s\n", buf);
  1875. X        nerrs++;
  1876. X    }
  1877. X}
  1878. ________This_Is_The_END________
  1879. if test `wc -c < arcrun.c` -ne     3838; then
  1880.     echo 'shar: arcrun.c was damaged during transit (should have been     3838 bytes)'
  1881. fi
  1882. fi        ; : end of overwriting check
  1883. echo 'x - arcs.h'
  1884. if test -f arcs.h; then echo 'shar: not overwriting arcs.h'; else
  1885. sed 's/^X//' << '________This_Is_The_END________' > arcs.h
  1886. X/*
  1887. X * $Header: arcs.h,v 1.2 88/04/17 18:53:19 hyc Exp $
  1888. X */
  1889. X
  1890. X/*
  1891. X * ARC - Archive utility - Archive file header format
  1892. X * 
  1893. X * Version 2.12, created on 12/17/85 at 14:40:26
  1894. X * 
  1895. X * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED
  1896. X * 
  1897. X * By:  Thom Henderson
  1898. X * 
  1899. X * Description: This file defines the format of an archive file header,
  1900. X * excluding the archive marker and the header version number.
  1901. X * 
  1902. X * Each entry in an archive begins with a one byte archive marker, which is set
  1903. X * to 26.  The marker is followed by a one byte header type code, from zero
  1904. X * to 7.
  1905. X * 
  1906. X * If the header type code is zero, then it is an end marker, and no more data
  1907. X * should be read from the archive.
  1908. X * 
  1909. X * If the header type code is in the range 2 to 7, then it is followed by a
  1910. X * standard archive header, which is defined below.
  1911. X * 
  1912. X * If the header type code is one, then it is followed by an older format
  1913. X * archive header.  The older format header does not contain the true length.
  1914. X * A header should be read for a length of sizeof(struct heads)-sizeof(long).
  1915. X * Then set length equal to size and change the header version to 2.
  1916. X * 
  1917. X * Programming note: The crc value given in the header is based on the unpacked
  1918. X * data.
  1919. X * 
  1920. X * Language: Computer Innovations Optimizing C86
  1921. X */
  1922. X
  1923. Xstruct heads {            /* archive entry header format */
  1924. X    char    name[FNLEN];        /* file name */
  1925. X            long size;        /* size of file, in bytes */
  1926. X    unsigned    short date;    /* creation date */
  1927. X    unsigned    short time;    /* creation time */
  1928. X                short crc;    /* cyclic redundancy check */
  1929. X                long length;    /* true file length */
  1930. X};
  1931. ________This_Is_The_END________
  1932. if test `wc -c < arcs.h` -ne     1645; then
  1933.     echo 'shar: arcs.h was damaged during transit (should have been     1645 bytes)'
  1934. fi
  1935. fi        ; : end of overwriting check
  1936. echo 'x - arcsq.c'
  1937. if test -f arcsq.c; then echo 'shar: not overwriting arcsq.c'; else
  1938. sed 's/^X//' << '________This_Is_The_END________' > arcsq.c
  1939. X/*
  1940. X * $Header: arcsq.c,v 1.2 88/06/02 16:27:38 hyc Locked $
  1941. X */
  1942. X
  1943. X/*
  1944. X * ARC - Archive utility - ARCSQ 
  1945. X *
  1946. X * Version 3.10, created on 01/30/86 at 20:10:46
  1947. X *
  1948. X * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED 
  1949. X *
  1950. X * By:  Thom Henderson 
  1951. X *
  1952. X * Description: This file contains the routines used to squeeze a file when
  1953. X * placing it in an archive. 
  1954. X *
  1955. X * Language: Computer Innovations Optimizing C86 
  1956. X *
  1957. X * Programming notes: Most of the routines used for the Huffman squeezing
  1958. X * algorithm were lifted from the SQ program by Dick Greenlaw, as adapted to
  1959. X * CI-C86 by Robert J. Beilstein. 
  1960. X */
  1961. X#include <stdio.h>
  1962. X#include "arc.h"
  1963. X
  1964. X/* stuff for Huffman squeezing */
  1965. X
  1966. X#define TRUE 1
  1967. X#define FALSE 0
  1968. X#define ERROR (-1)
  1969. X#define SPEOF 256        /* special endfile token */
  1970. X#define NOCHILD (-1)        /* marks end of path through tree */
  1971. X#define NUMVALS 257        /* 256 data values plus SPEOF */
  1972. X#define NUMNODES (NUMVALS+NUMVALS-1)    /* number of nodes */
  1973. X#define MAXCOUNT (unsigned short) 65535    /* biggest unsigned integer */
  1974. X
  1975. X/*
  1976. X * The following array of structures are the nodes of the binary trees. The
  1977. X * first NUMVALS nodes become the leaves of the final tree and represent the
  1978. X * values of the data bytes being encoded and the special endfile, SPEOF. The
  1979. X * remaining nodes become the internal nodes of the final tree. 
  1980. X */
  1981. X
  1982. Xstruct nd {            /* shared by unsqueezer */
  1983. X    unsigned short    weight;    /* number of appearances */
  1984. X    short        tdepth;    /* length on longest path in tree */
  1985. X    short        lchild, rchild;    /* indices to next level */
  1986. X}               node[NUMNODES];    /* use large buffer */
  1987. X
  1988. Xstatic int      dctreehd;    /* index to head of final tree */
  1989. X
  1990. X/*
  1991. X * This is the encoding table: The bit strings have first bit in low bit.
  1992. X * Note that counts were scaled so code fits unsigned integer. 
  1993. X */
  1994. X
  1995. Xstatic int      codelen[NUMVALS];    /* number of bits in code */
  1996. Xstatic unsigned short code[NUMVALS];    /* code itself, right adjusted */
  1997. Xstatic unsigned short tcode;    /* temporary code value */
  1998. Xstatic long     valcount[NUMVALS];    /* actual count of times seen */
  1999. X
  2000. X/* Variables used by encoding process */
  2001. X
  2002. Xstatic int      curin;        /* value currently being encoded */
  2003. Xstatic int      cbitsrem;    /* # of code string bits left */
  2004. Xstatic unsigned short ccode;    /* current code right justified */
  2005. X
  2006. Xint 
  2007. Xinit_sq()
  2008. X{                /* prepare for scanning pass */
  2009. X    int             i;    /* node index */
  2010. X
  2011. X    /*
  2012. X     * Initialize all nodes to single element binary trees with zero
  2013. X     * weight and depth. 
  2014. X     */
  2015. X
  2016. X    for (i = 0; i < NUMNODES; ++i) {
  2017. X        node[i].weight = 0;
  2018. X        node[i].tdepth = 0;
  2019. X        node[i].lchild = NOCHILD;
  2020. X        node[i].rchild = NOCHILD;
  2021. X    }
  2022. X
  2023. X    for (i = 0; i < NUMVALS; i++)
  2024. X        valcount[i] = 0;
  2025. X}
  2026. X
  2027. Xint 
  2028. Xscan_sq(c)            /* add a byte to the tables */
  2029. X    int             c;    /* byte to add */
  2030. X{
  2031. X    unsigned short *wp;    /* speeds up weight counting */
  2032. X
  2033. X    /* Build frequency info in tree */
  2034. X
  2035. X    if (c == EOF)        /* it's traditional */
  2036. X        c = SPEOF;    /* dumb, but traditional */
  2037. X
  2038. X    if (*(wp = &node[c].weight) != MAXCOUNT)
  2039. X        ++(*wp);    /* bump weight counter */
  2040. X
  2041. X    valcount[c]++;        /* bump byte counter */
  2042. X}
  2043. X
  2044. Xlong 
  2045. Xpred_sq()
  2046. X{                /* predict size of squeezed file */
  2047. X    int             i;
  2048. X    int             btlist[NUMVALS];    /* list of intermediate
  2049. X                         * b-trees */
  2050. X    int             listlen;/* length of btlist */
  2051. X    unsigned short    ceiling;/* limit for scaling */
  2052. X    long            size = 0;    /* predicted size */
  2053. X    int             numnodes;    /* # of nodes in simplified tree */
  2054. X    int             scale();
  2055. X    int             heap();
  2056. X    int             bld_tree();
  2057. X    int             buildenc();
  2058. X    int             init_enc();
  2059. X
  2060. X    scan_sq(EOF);        /* signal end of input */
  2061. X
  2062. X    ceiling = MAXCOUNT;
  2063. X
  2064. X    /* Keep trying to scale and encode */
  2065. X
  2066. X    do {
  2067. X        scale(ceiling);
  2068. X        ceiling /= 2;    /* in case we rescale */
  2069. X
  2070. X        /*
  2071. X         * Build list of single node binary trees having leaves for
  2072. X         * the input values with non-zero counts 
  2073. X         */
  2074. X
  2075. X        for (i = listlen = 0; i < NUMVALS; ++i) {
  2076. X            if (node[i].weight != 0) {
  2077. X                node[i].tdepth = 0;
  2078. X                btlist[listlen++] = i;
  2079. X            }
  2080. X        }
  2081. X
  2082. X        /*
  2083. X         * Arrange list of trees into a heap with the entry indexing
  2084. X         * the node with the least weight at the top. 
  2085. X         */
  2086. X
  2087. X        heap(btlist, listlen);
  2088. X
  2089. X        /* Convert the list of trees to a single decoding tree */
  2090. X
  2091. X        bld_tree(btlist, listlen);
  2092. X
  2093. X        /* Initialize the encoding table */
  2094. X
  2095. X        init_enc();
  2096. X
  2097. X        /*
  2098. X         * Try to build encoding table. Fail if any code is > 16 bits
  2099. X         * long. 
  2100. X         */
  2101. X    } while (buildenc(0, dctreehd) == ERROR);
  2102. X
  2103. X    /* Initialize encoding variables */
  2104. X
  2105. X    cbitsrem = 0;        /* force initial read */
  2106. X    curin = 0;        /* anything but endfile */
  2107. X
  2108. X    for (i = 0; i < NUMVALS; i++)    /* add bits for each code */
  2109. X        size += valcount[i] * codelen[i];
  2110. X
  2111. X    size = (size + 7) / 8;    /* reduce to number of bytes */
  2112. X
  2113. X    numnodes = dctreehd < NUMVALS ? 0 : dctreehd - (NUMVALS - 1);
  2114. X
  2115. X    size += sizeof(short) + 2 * numnodes * sizeof(short);
  2116. X
  2117. X    return size;
  2118. X}
  2119. X
  2120. X/*
  2121. X * The count of number of occurrances of each input value have already been
  2122. X * prevented from exceeding MAXCOUNT. Now we must scale them so that their
  2123. X * sum doesn't exceed ceiling and yet no non-zero count can become zero. This
  2124. X * scaling prevents errors in the weights of the interior nodes of the
  2125. X * Huffman tree and also ensures that the codes will fit in an unsigned
  2126. X * integer. Rescaling is used if necessary to limit the code length. 
  2127. X */
  2128. X
  2129. Xstatic int 
  2130. Xscale(ceil)
  2131. X    unsigned short    ceil;    /* upper limit on total weight */
  2132. X{
  2133. X    register int    i;
  2134. X    int             ovflw, divisor;
  2135. X    unsigned short    w, sum;
  2136. X    unsigned char   increased;    /* flag */
  2137. X
  2138. X    do {
  2139. X        for (i = sum = ovflw = 0; i < NUMVALS; ++i) {
  2140. X            if (node[i].weight > (ceil - sum))
  2141. X                ++ovflw;
  2142. X            sum += node[i].weight;
  2143. X        }
  2144. X
  2145. X        divisor = ovflw + 1;
  2146. X
  2147. X        /* Ensure no non-zero values are lost */
  2148. X
  2149. X        increased = FALSE;
  2150. X        for (i = 0; i < NUMVALS; ++i) {
  2151. X            w = node[i].weight;
  2152. X            if (w < divisor && w != 0) {    /* Don't fail to provide
  2153. X                             * a code if it's used
  2154. X                             * at all */
  2155. X
  2156. X                node[i].weight = divisor;
  2157. X                increased = TRUE;
  2158. X            }
  2159. X        }
  2160. X    } while (increased);
  2161. X
  2162. X    /* Scaling factor chosen, now scale */
  2163. X
  2164. X    if (divisor > 1)
  2165. X        for (i = 0; i < NUMVALS; ++i)
  2166. X            node[i].weight /= divisor;
  2167. X}
  2168. X
  2169. X/*
  2170. X * heap() and adjust() maintain a list of binary trees as a heap with the top
  2171. X * indexing the binary tree on the list which has the least weight or, in
  2172. X * case of equal weights, least depth in its longest path. The depth part is
  2173. X * not strictly necessary, but tends to avoid long codes which might provoke
  2174. X * rescaling. 
  2175. X */
  2176. X
  2177. Xstatic int 
  2178. Xheap(list, length)
  2179. X    int             list[], length;
  2180. X{
  2181. X    register int    i;
  2182. X    int             adjust();
  2183. X
  2184. X    for (i = (length - 2) / 2; i >= 0; --i)
  2185. X        adjust(list, i, length - 1);
  2186. X}
  2187. X
  2188. X/* Make a heap from a heap with a new top */
  2189. X
  2190. Xstatic int 
  2191. Xadjust(list, top, bottom)
  2192. X    int             list[], top, bottom;
  2193. X{
  2194. X    register int    k, temp;
  2195. X    int             cmptrees();
  2196. X
  2197. X    k = 2 * top + 1;    /* left child of top */
  2198. X    temp = list[top];    /* remember root node of top tree */
  2199. X
  2200. X    if (k <= bottom) {
  2201. X        if (k < bottom && cmptrees(list[k], list[k + 1]))
  2202. X            ++k;
  2203. X
  2204. X        /* k indexes "smaller" child (in heap of trees) of top */
  2205. X        /* now make top index "smaller" of old top and smallest child */
  2206. X
  2207. X        if (cmptrees(temp, list[k])) {
  2208. X            list[top] = list[k];
  2209. X            list[k] = temp;
  2210. X
  2211. X            /* Make the changed list a heap */
  2212. X
  2213. X            adjust(list, k, bottom);    /* recursive */
  2214. X        }
  2215. X    }
  2216. X}
  2217. X
  2218. X/*
  2219. X * Compare two trees, if a > b return true, else return false. Note
  2220. X * comparison rules in previous comments. 
  2221. X */
  2222. X
  2223. Xstatic int 
  2224. Xcmptrees(a, b)
  2225. X    int             a, b;    /* root nodes of trees */
  2226. X{
  2227. X    if (node[a].weight > node[b].weight)
  2228. X        return TRUE;
  2229. X    if (node[a].weight == node[b].weight)
  2230. X        if (node[a].tdepth > node[b].tdepth)
  2231. X            return TRUE;
  2232. X    return FALSE;
  2233. X}
  2234. X
  2235. X/*
  2236. X * HUFFMAN ALGORITHM: develops the single element trees into a single binary
  2237. X * tree by forming subtrees rooted in interior nodes having weights equal to
  2238. X * the sum of weights of all their descendents and having depth counts
  2239. X * indicating the depth of their longest paths. 
  2240. X *
  2241. X * When all trees have been formed into a single tree satisfying the heap
  2242. X * property (on weight, with depth as a tie breaker) then the binary code
  2243. X * assigned to a leaf (value to be encoded) is then the series of left (0)
  2244. X * and right (1) paths leading from the root to the leaf. Note that trees are
  2245. X * removed from the heaped list by moving the last element over the top
  2246. X * element and reheaping the shorter list. 
  2247. X */
  2248. X
  2249. Xstatic int 
  2250. Xbld_tree(list, len)
  2251. X    int             list[];
  2252. Xint             len;
  2253. X{
  2254. X    register int    freenode;    /* next free node in tree */
  2255. X    register struct nd *frnp;    /* free node pointer */
  2256. X    int             lch, rch;    /* temps for left, right children */
  2257. X    int             maxchar();
  2258. X
  2259. X    /*
  2260. X     * Initialize index to next available (non-leaf) node. Lower numbered
  2261. X     * nodes correspond to leaves (data values). 
  2262. X     */
  2263. X
  2264. X    freenode = NUMVALS;
  2265. X
  2266. X    while (len > 1) {    /* Take from list two btrees with least
  2267. X                 * weight and build an interior node pointing
  2268. X                 * to them. This forms a new tree. */
  2269. X
  2270. X        lch = list[0];    /* This one will be left child */
  2271. X
  2272. X        /* delete top (least) tree from the list of trees */
  2273. X
  2274. X        list[0] = list[--len];
  2275. X        adjust(list, 0, len - 1);
  2276. X
  2277. X        /* Take new top (least) tree. Reuse list slot later */
  2278. X
  2279. X        rch = list[0];    /* This one will be right child */
  2280. X
  2281. X        /*
  2282. X         * Form new tree from the two least trees using a free node
  2283. X         * as root. Put the new tree in the list. 
  2284. X         */
  2285. X
  2286. X        frnp = &node[freenode];    /* address of next free node */
  2287. X        list[0] = freenode++;    /* put at top for now */
  2288. X        frnp->lchild = lch;
  2289. X        frnp->rchild = rch;
  2290. X        frnp->weight = node[lch].weight + node[rch].weight;
  2291. X        frnp->tdepth = 1 + maxchar(node[lch].tdepth, node[rch].tdepth);
  2292. X
  2293. X        /* reheap list  to get least tree at top */
  2294. X
  2295. X        adjust(list, 0, len - 1);
  2296. X    }
  2297. X    dctreehd = list[0];    /* head of final tree */
  2298. X}
  2299. X
  2300. Xstatic int 
  2301. Xmaxchar(a, b)
  2302. X{
  2303. X    return a > b ? a : b;
  2304. X}
  2305. X
  2306. Xstatic int 
  2307. Xinit_enc()
  2308. X{
  2309. X    register int    i;
  2310. X
  2311. X    /* Initialize encoding table */
  2312. X
  2313. X    for (i = 0; i < NUMVALS; ++i)
  2314. X        codelen[i] = 0;
  2315. X}
  2316. X
  2317. X/*
  2318. X * Recursive routine to walk the indicated subtree and level and maintain the
  2319. X * current path code in bstree. When a leaf is found the entire code string
  2320. X * and length are put into the encoding table entry for the leaf's data value
  2321. X * . 
  2322. X *
  2323. X * Returns ERROR if codes are too long. 
  2324. X */
  2325. X
  2326. Xstatic int 
  2327. Xbuildenc(level, root)
  2328. X    int             level;    /* level of tree being examined, from zero */
  2329. X    int             root;    /* root of subtree is also data value if leaf */
  2330. X{
  2331. X    register int    l, r;
  2332. X
  2333. X    l = node[root].lchild;
  2334. X    r = node[root].rchild;
  2335. X
  2336. X    if (l == NOCHILD && r == NOCHILD) {    /* Leaf. Previous path
  2337. X                         * determines bit string code
  2338. X                         * of length level (bits 0 to
  2339. X                         * level - 1). Ensures unused
  2340. X                         * code bits are zero. */
  2341. X
  2342. X        codelen[root] = level;
  2343. X        code[root] = tcode & (((unsigned short    ) ~0) >> (16 - level));
  2344. X        return (level > 16) ? ERROR : 0;
  2345. X    } else {
  2346. X        if (l != NOCHILD) {    /* Clear path bit and continue deeper */
  2347. X
  2348. X            tcode &= ~(1 << level);
  2349. X            if (buildenc(level + 1, l) == ERROR)
  2350. X                return ERROR;    /* pass back bad statuses */
  2351. X        }
  2352. X        if (r != NOCHILD) {    /* Set path bit and continue deeper */
  2353. X
  2354. X            tcode |= 1 << level;
  2355. X            if (buildenc(level + 1, r) == ERROR)
  2356. X                return ERROR;    /* pass back bad statuses */
  2357. X        }
  2358. X    }
  2359. X    return NULL;        /* it worked if we reach here */
  2360. X}
  2361. X
  2362. Xstatic int 
  2363. Xput_int(n, f)            /* output an integer */
  2364. X    short        n;    /* integer to output */
  2365. X    FILE           *f;    /* file to put it to */
  2366. X{
  2367. X    putc_pak(n & 0xff, f);    /* first the low byte */
  2368. X    putc_pak(n >> 8, f);    /* then the high byte */
  2369. X}
  2370. X
  2371. X/* Write out the header of the compressed file */
  2372. X
  2373. Xstatic long 
  2374. Xwrt_head(ob)
  2375. X    FILE           *ob;
  2376. X{
  2377. X    register int    l, r;
  2378. X    int             i, k;
  2379. X    int             numnodes;    /* # of nodes in simplified tree */
  2380. X
  2381. X    /*
  2382. X     * Write out a simplified decoding tree. Only the interior nodes are
  2383. X     * written. When a child is a leaf index (representing a data value)
  2384. X     * it is recoded as -(index + 1) to distinguish it from interior
  2385. X     * indexes which are recoded as positive indexes in the new tree. 
  2386. X     *
  2387. X     * Note that this tree will be empty for an empty file. 
  2388. X     */
  2389. X
  2390. X    numnodes = dctreehd < NUMVALS ? 0 : dctreehd - (NUMVALS - 1);
  2391. X    put_int(numnodes, ob);
  2392. X
  2393. X    for (k = 0, i = dctreehd; k < numnodes; ++k, --i) {
  2394. X        l = node[i].lchild;
  2395. X        r = node[i].rchild;
  2396. X        l = l < NUMVALS ? -(l + 1) : dctreehd - l;
  2397. X        r = r < NUMVALS ? -(r + 1) : dctreehd - r;
  2398. X        put_int(l, ob);
  2399. X        put_int(r, ob);
  2400. X    }
  2401. X
  2402. X    return sizeof(short) + numnodes * 2 * sizeof(short);
  2403. X}
  2404. X
  2405. X/*
  2406. X * Get an encoded byte or EOF. Reads from specified stream AS NEEDED. 
  2407. X *
  2408. X * There are two unsynchronized bit-byte relationships here. The input stream
  2409. X * bytes are converted to bit strings of various lengths via the static
  2410. X * variables named c... These bit strings are concatenated without padding to
  2411. X * become the stream of encoded result bytes, which this function returns one
  2412. X * at a time. The EOF (end of file) is converted to SPEOF for convenience and
  2413. X * encoded like any other input value. True EOF is returned after that. 
  2414. X */
  2415. X
  2416. Xstatic int 
  2417. Xgethuff(ib)            /* Returns bytes except for EOF */
  2418. X    FILE           *ib;
  2419. X{
  2420. X    int             rbyte;    /* Result byte value */
  2421. X    int             need;    /* number of bits */
  2422. X
  2423. X    rbyte = 0;
  2424. X    need = 8;        /* build one byte per call */
  2425. X
  2426. X    /*
  2427. X     * Loop to build a byte of encoded data. Initialization forces read
  2428. X     * the first time. 
  2429. X     */
  2430. X
  2431. Xloop:
  2432. X    if (cbitsrem >= need) {    /* if current code is big enough */
  2433. X        if (need == 0)
  2434. X            return rbyte;
  2435. X
  2436. X        rbyte |= ccode << (8 - need);    /* take what we need */
  2437. X        ccode >>= need;    /* and leave the rest */
  2438. X        cbitsrem -= need;
  2439. X        return rbyte & 0xff;
  2440. X    }
  2441. X    /* We need more than current code */
  2442. X
  2443. X    if (cbitsrem > 0) {
  2444. X        rbyte |= ccode << (8 - need);    /* take what there is */
  2445. X        need -= cbitsrem;
  2446. X    }
  2447. X    /* No more bits in current code string */
  2448. X
  2449. X    if (curin == SPEOF) {    /* The end of file token has been encoded. If
  2450. X                 * result byte has data return it and do EOF
  2451. X                 * next time. */
  2452. X
  2453. X        cbitsrem = 0;
  2454. X        return (need == 8) ? EOF : rbyte + 0;
  2455. X    }
  2456. X    /* Get an input byte */
  2457. X
  2458. X    if ((curin = getc_ncr(ib)) == EOF)
  2459. X        curin = SPEOF;    /* convenient for encoding */
  2460. X
  2461. X    ccode = code[curin];    /* get the new byte's code */
  2462. X    cbitsrem = codelen[curin];
  2463. X
  2464. X    goto loop;
  2465. X}
  2466. X
  2467. X/*
  2468. X * This routine is used to perform the actual squeeze operation.  It can only
  2469. X * be called after the file has been scanned.  It returns the true length of
  2470. X * the squeezed entry. 
  2471. X */
  2472. X
  2473. Xlong 
  2474. Xfile_sq(f, t)            /* squeeze a file into an archive */
  2475. X    FILE           *f;    /* file to squeeze */
  2476. X    FILE           *t;    /* archive to receive file */
  2477. X{
  2478. X    int             c;    /* one byte of squeezed data */
  2479. X    long            size;    /* size after squeezing */
  2480. X
  2481. X    size = wrt_head(t);    /* write out the decode tree */
  2482. X
  2483. X    while ((c = gethuff(f)) != EOF) {
  2484. X        putc_pak(c, t);
  2485. X        size++;
  2486. X    }
  2487. X
  2488. X    return size;        /* report true size */
  2489. X}
  2490. ________This_Is_The_END________
  2491. if test `wc -c < arcsq.c` -ne    14613; then
  2492.     echo 'shar: arcsq.c was damaged during transit (should have been    14613 bytes)'
  2493. fi
  2494. fi        ; : end of overwriting check
  2495. exit 0
  2496.  
  2497.