home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / CPM / TURBOPAS / TP / UTL3 / DEARC5.PZS / DEARC5.PAS
Pascal/Delphi Source File  |  2000-06-30  |  28KB  |  1,091 lines

  1. {$R-}
  2. {$U-}
  3. {$C-}
  4. {$K-}
  5.  
  6. program dearc512;
  7.  
  8. { REVISION -  Now supports ARC 5.12 and earlier files - 6-10-86 by DWC }
  9.  
  10. { DEARC.PAS - Program to extract all files from an archive created by version
  11.   5.12 or earlier of the ARC utility.
  12.  
  13.   ARC is COPYRIGHT 1985 by System Enhancement Associates.
  14.  
  15.   This program requires Turbo Pascal Version 3.01A. It should work in all
  16.   supported environments (PCDOS, CPM, etc.) but I have only tested it on
  17.   an IBM PC running PC DOS version 3.10.
  18.  
  19.   Usage:
  20.  
  21.     DEARC arcname
  22.  
  23.     arcname is the path/file name of the archive file. All files contained
  24.     in the archive will be extracted into the current directory.
  25.  
  26.    *** ORIGINAL AUTHOR UNKNOWN ***
  27.  
  28.   Version 1.01 - 10/19/85. Changed end-of-file processing to, hopefully, be
  29.                            more compatible with CPM (whatever that is).
  30.   Version 1.01A - 12/19/85 By Roy Collins
  31.                            Mail: TechMail BBS @ 703-430-2535
  32.                                  - or -
  33.                                  P.O.Box 1192, Leesburg, Va 22075
  34.                            Modified V1.01 to work with Turbo Pascal Version 2
  35.                            Added functions ARGC (argument count) and ARGV
  36.                            (argument value)
  37.                            Modified all references to "EXIT" command to be
  38.                            GOTO EXIT, with EXIT defined as a LABEL, at the
  39.                            end of the function/procedure involved.
  40.                            Will not accept path names - archives must be in
  41.                            the current directory.
  42.   Version 2.00 - 6/11/86   By David W. Carroll
  43.                            Mail: High Sierra RBBS-PC @ 209/296-3534
  44.                            Now supports ARC version 5.12 files, compression
  45.                            types 7 and 8.
  46. }
  47. (************************* ARGC & ARGV functions **************************)
  48. type
  49.     arglist_string = string[100];
  50. const
  51.     arglist_max = 20;
  52.     arglist_number : integer = -1;
  53. var
  54.     argvlist : array[1..arglist_max] of ^arglist_string;
  55.  
  56. function argv(num : integer) : arglist_string;
  57. var
  58.   argument : arglist_string absolute cseg:$80;
  59.   newparm,
  60.   parmline : arglist_string;
  61.   i,
  62.   j        : integer;
  63.   state    : (leading_ws, non_quote, quoted, end_quote);
  64.   inchar   : char;
  65.  
  66.   procedure saveparm;
  67.   begin
  68.     if arglist_number < arglist_max then begin
  69.       arglist_number := arglist_number+1;
  70.       new(argvlist[arglist_number]);
  71.       argvlist[arglist_number]^ := newparm;
  72.       newparm := '';
  73.       end;
  74.   end; (* proc saveparm *)
  75.  
  76. begin
  77.   if arglist_number = -1 then begin
  78.     arglist_number := 0;
  79.     parmline := argument+' ';
  80.     state := leading_ws;
  81.     newparm := '';
  82.     for i := 1 to length(parmline) do begin
  83.       inchar := parmline[i];
  84.        case state of
  85.          leading_ws: begin
  86.              if inchar = '''' then
  87.                state := quoted
  88.              else
  89.              if inchar <> ' ' then begin
  90.                newparm := newparm+inchar;
  91.                state := non_quote;
  92.                end;
  93.              end; (* leading_ws *)
  94.          non_quote: begin
  95.              if inchar = ' ' then begin
  96.                saveparm;
  97.                state := leading_ws;
  98.                end
  99.              else
  100.                newparm := newparm+inchar;
  101.              end; (* non_quote *)
  102.          quoted: begin
  103.              if inchar = '''' then
  104.                state := end_quote
  105.              else
  106.                 newparm := newparm+inchar;
  107.              end; (* quoted *)
  108.          end_quote: begin
  109.              if inchar = '''' then begin
  110.                newparm := newparm+inchar;
  111.                state := quoted;
  112.                end
  113.              else
  114.              if inchar <> ' ' then begin
  115.                newparm := newparm+inchar;
  116.                state := non_quote;
  117.                end
  118.              else begin
  119.                saveparm;
  120.                state := leading_ws;
  121.                end;
  122.              end; (* end_quote *)
  123.             end; (* case state *)
  124.         end; (* for *)
  125.     end; (* if arglist_number = -1 *)
  126.   if (num > 0) and (num <= arglist_number) then
  127.     argv := argvlist[num]^
  128.   else
  129.     argv := '';
  130. end; (* func argv *)
  131.  
  132. function argc : integer;
  133. var
  134.   dummy : arglist_string;
  135. begin
  136.   if arglist_number = -1 then
  137.     dummy := argv(1); {force evaluation}
  138.   argc := arglist_number;
  139. end; (* func argc *)
  140. (****************** end of ARGC & ARGV functions **************************)
  141.  
  142. const BLOCKSIZE = 128;
  143.       arcmarc   = 26;              { special archive marker }
  144.       arcver    = 8;               { max archive header version code }
  145.       strlen    = 100;             { standard string length }
  146.       fnlen     = 12;              { file name length - 1 }
  147.  
  148. const crctab : array [0..255] of integer =
  149.   ( $0000, $C0C1, $C181, $0140, $C301, $03C0, $0280, $C241,
  150.     $C601, $06C0, $0780, $C741, $0500, $C5C1, $C481, $0440,
  151.     $CC01, $0CC0, $0D80, $CD41, $0F00, $CFC1, $CE81, $0E40,
  152.     $0A00, $CAC1, $CB81, $0B40, $C901, $09C0, $0880, $C841,
  153.     $D801, $18C0, $1980, $D941, $1B00, $DBC1, $DA81, $1A40,
  154.     $1E00, $DEC1, $DF81, $1F40, $DD01, $1DC0, $1C80, $DC41,
  155.     $1400, $D4C1, $D581, $1540, $D701, $17C0, $1680, $D641,
  156.     $D201, $12C0, $1380, $D341, $1100, $D1C1, $D081, $1040,
  157.     $F001, $30C0, $3180, $F141, $3300, $F3C1, $F281, $3240,
  158.     $3600, $F6C1, $F781, $3740, $F501, $35C0, $3480, $F441,
  159.     $3C00, $FCC1, $FD81, $3D40, $FF01, $3FC0, $3E80, $FE41,
  160.     $FA01, $3AC0, $3B80, $FB41, $3900, $F9C1, $F881, $3840,
  161.     $2800, $E8C1, $E981, $2940, $EB01, $2BC0, $2A80, $EA41,
  162.     $EE01, $2EC0, $2F80, $EF41, $2D00, $EDC1, $EC81, $2C40,
  163.     $E401, $24C0, $2580, $E541, $2700, $E7C1, $E681, $2640,
  164.     $2200, $E2C1, $E381, $2340, $E101, $21C0, $2080, $E041,
  165.     $A001, $60C0, $6180, $A141, $6300, $A3C1, $A281, $6240,
  166.     $6600, $A6C1, $A781, $6740, $A501, $65C0, $6480, $A441,
  167.     $6C00, $ACC1, $AD81, $6D40, $AF01, $6FC0, $6E80, $AE41,
  168.     $AA01, $6AC0, $6B80, $AB41, $6900, $A9C1, $A881, $6840,
  169.     $7800, $B8C1, $B981, $7940, $BB01, $7BC0, $7A80, $BA41,
  170.     $BE01, $7EC0, $7F80, $BF41, $7D00, $BDC1, $BC81, $7C40,
  171.     $B401, $74C0, $7580, $B541, $7700, $B7C1, $B681, $7640,
  172.     $7200, $B2C1, $B381, $7340, $B101, $71C0, $7080, $B041,
  173.     $5000, $90C1, $9181, $5140, $9301, $53C0, $5280, $9241,
  174.     $9601, $56C0, $5780, $9741, $5500, $95C1, $9481, $5440,
  175.     $9C01, $5CC0, $5D80, $9D41, $5F00, $9FC1, $9E81, $5E40,
  176.     $5A00, $9AC1, $9B81, $5B40, $9901, $59C0, $5880, $9841,
  177.     $8801, $48C0, $4980, $8941, $4B00, $8BC1, $8A81, $4A40,
  178.     $4E00, $8EC1, $8F81, $4F40, $8D01, $4DC0, $4C80, $8C41,
  179.     $4400, $84C1, $8581, $4540, $8701, $47C0, $4680, $8641,
  180.     $8201, $42C0, $4380, $8341, $4100, $81C1, $8081, $4040 );
  181.  
  182. type long    = record           { used to simulate long (4 byte) integers }
  183.                  l, h : integer
  184.                end;
  185.  
  186. type strtype = string[strlen];
  187.      fntype  = array [0..fnlen] of char;
  188.      buftype = array [1..BLOCKSIZE] of byte;
  189.      heads   = record
  190.                  name   : fntype;
  191.                  size   : long;
  192.                  date   : integer;
  193.                  time   : integer;
  194.                  crc    : integer;
  195.                  length : long
  196.                end;
  197.  
  198. var hdrver   : byte;
  199.     arcfile  : file;
  200.     arcbuf   : buftype;
  201.     arcptr   : integer;
  202.     arcname  : strtype;
  203.     endfile  : boolean;
  204.  
  205.     extfile  : file;
  206.     extbuf   : buftype;
  207.     extptr   : integer;
  208.     extname  : strtype;
  209.  
  210. { definitions for unpack }
  211.  
  212. const DLE = $90;
  213.  
  214. var state  : (NOHIST, INREP);
  215.     crcval : integer;
  216.     size   : real;
  217.     lastc  : integer;
  218.  
  219. { definitions for unsqueeze }
  220.  
  221. const ERROR   = -1;
  222.       SPEOF   = 256;
  223.       NUMVALS = 256;               { 1 less than the number of values }
  224.  
  225. type nd = record
  226.             child : array [0..1] of integer
  227.           end;
  228.  
  229. var node     : array [0..NUMVALS] of nd;
  230.     bpos     : integer;
  231.     curin    : integer;
  232.     numnodes : integer;
  233.  
  234. { definitions for uncrunch }
  235.  
  236. const TABSIZE   = 4096;
  237.       TABSIZEM1 = 4095;
  238.       NO_PRED   = $FFFF;
  239.       EMPTY     = $FFFF;
  240.  
  241. type entry = record
  242.                used         : boolean;
  243.                next         : integer;
  244.                predecessor  : integer;
  245.                follower     : byte
  246.              end;
  247.  
  248. var stack       : array [0..TABSIZEM1] of byte;
  249.     sp          : integer;
  250.     string_tab  : array [0..TABSIZEM1] of entry;
  251.  
  252. var code_count : integer;
  253.     code       : integer;
  254.     firstc     : boolean;
  255.     oldcode    : integer;
  256.     finchar    : integer;
  257.     inbuf      : integer;
  258.     outbuf     : integer;
  259.     newhash    : boolean;
  260.  
  261. { definitions for dynamic uncrunch }
  262.  
  263. const
  264.   BITS = 12;
  265.   HSIZE = 5003;
  266.   INIT_BITS = 9;
  267.   FIRST = 257;
  268.   CLEAR = 256;
  269.   HSIZEM1 = 5002;
  270.   BITSM1 = 11;
  271.  
  272.   RMASK : array[0..8] of byte =
  273.   ($00, $01, $03, $07, $0f, $1f, $3f, $7f, $ff);
  274.  
  275. var
  276.   n_bits,
  277.   maxcode : integer;
  278.   prefix : array[0..HSIZEM1] of integer;
  279.   suffix : array[0..TABSIZEM1] of byte;
  280.   buf : array[0..BITSM1] of byte;
  281.   clear_flg : integer;
  282.   stack1 : array[0..HSIZEM1] of byte;
  283.   free_ent : integer;
  284.   maxcodemax : integer;
  285.   offset, sizex : integer;
  286.   firstch : boolean;
  287.  
  288. procedure abort(s : strtype);
  289. { terminate the program with an error message }
  290. begin
  291.   writeln('ABORT: ', s);
  292.   halt;
  293. end; (* proc abort *)
  294.  
  295. function fn_to_str(var fn : fntype) : strtype;
  296. { convert strings from C format (trailing 0) to Turbo Pascal format (leading
  297.     length byte). }
  298. var s : strtype;
  299.     i : integer;
  300. begin
  301.   s := '';
  302.   i := 0;
  303.   while fn[i] <> #0 do begin
  304.     s := s + fn[i];
  305.     i := i + 1
  306.     end;
  307.   fn_to_str := s
  308. end; (* func fn_to_str *)
  309.  
  310. function unsigned_to_real(u : integer) : real;
  311. { convert unsigned integer to real }
  312. { note: INT is a function that returns a REAL!!!}
  313. begin
  314.   if u >= 0 then
  315.     unsigned_to_real := Int(u)
  316.   else
  317.   if u = $8000 then
  318.     unsigned_to_real := 32768.0
  319.   else
  320.     unsigned_to_real := 65536.0 + u
  321. end; (* func unsigned_to_real *)
  322.  
  323. function long_to_real(l : long) : real;
  324. { convert long integer to a real }
  325. { note: INT is a function that returns a REAL!!! }
  326. var r : real;
  327.     s : (POS, NEG);
  328. const rcon = 65536.0;
  329. begin
  330.   if l.h >= 0 then begin
  331.     r := Int(l.h) * rcon;
  332.     s := POS
  333.     end
  334.   else begin
  335.     s := NEG;
  336.     if l.h = $8000 then
  337.       r := rcon * rcon
  338.     else
  339.       r := Int(-l.h) * rcon
  340.     end;
  341.   r := r + unsigned_to_real(l.l);
  342.   if s = NEG then
  343.     long_to_real := -r
  344.   else
  345.     long_to_real := r
  346. end; (* func long_to_real *)
  347.  
  348. procedure Read_Block;
  349. { read a block from the archive file }
  350. begin
  351.   if EOF(arcfile) then
  352.     endfile := TRUE
  353.   else
  354.     BlockRead(arcfile, arcbuf, 1);
  355.   arcptr := 1
  356. end; (* proc read_block *)
  357.  
  358. procedure Write_Block;
  359. { write a block to the extracted file }
  360. begin
  361.   BlockWrite(extfile, extbuf, 1);
  362.   extptr := 1
  363. end; (* proc write_block *)
  364.  
  365. procedure open_arc;
  366. { open the archive file for input processing }
  367. begin
  368.   {$I-} assign(arcfile, arcname); {$I+}
  369.   if ioresult <> 0 then
  370.     abort('Cannot open archive file.');
  371.   {$I-} reset(arcfile); {$I+}
  372.   if ioresult <> 0 then
  373.     abort('Cannot open archive file.');
  374.   endfile := FALSE;
  375.   Read_Block
  376. end; (* proc open_arc *)
  377.  
  378. procedure open_ext;
  379. { open the extracted file for writing }
  380. begin
  381.   {$I-} assign(extfile, extname); {$I+}
  382.   if ioresult <> 0 then
  383.     abort('Cannot open extract file.');
  384.   {$I-} rewrite(extfile); {$I+}
  385.   if ioresult <> 0 then
  386.     abort('Cannot open extract file.');
  387.   extptr := 1;
  388. end; (* proc open_ext *)
  389.  
  390. function get_arc : byte;
  391. { read 1 character from the archive file }
  392. begin
  393.   if endfile then
  394.     get_arc := 0
  395.   else begin
  396.     get_arc := arcbuf[arcptr];
  397.     if arcptr = BLOCKSIZE then
  398.       Read_Block
  399.     else
  400.       arcptr := arcptr + 1
  401.     end
  402. end; (* func get_arc *)
  403.  
  404. procedure put_ext(c : byte);
  405. { write 1 character to the extracted file }
  406. begin
  407.   extbuf[extptr] := c;
  408.   if extptr = BLOCKSIZE then
  409.     Write_Block
  410.   else
  411.     extptr := extptr + 1
  412. end; (* proc put_ext *)
  413.  
  414. procedure close_arc;
  415. { close the archive file }
  416. begin
  417.   close(arcfile)
  418. end; (* proc close_arc *)
  419.  
  420. procedure close_ext;
  421. { close the extracted file }
  422. begin
  423.   while extptr <> 1 do
  424.     put_ext(Ord(^Z));          { pad last block w/ Ctrl-Z (EOF) }
  425.   close(extfile)
  426. end; (* proc close_ext *)
  427.  
  428. procedure fseek(offset : real; base : integer);
  429. { re-position the current pointer in the archive file }
  430. var b           : real;
  431.     i, ofs, rec : integer;
  432.     c           : byte;
  433. begin
  434.   case base of
  435.     0 : b := offset;
  436.     1 : b := offset + (unsigned_to_real(FilePos(arcfile)) - 1.0) * BLOCKSIZE
  437.               + arcptr - 1.0;
  438.     2 : b := offset + unsigned_to_real(FileSize(arcfile)) * BLOCKSIZE - 1.0
  439.     else
  440.       abort('Invalid parameters to fseek')
  441.     end;
  442.   rec := Trunc(b / BLOCKSIZE);
  443.   ofs := Trunc(b - (Int(rec) * BLOCKSIZE));  { Int converts to Real }
  444.   seek(arcfile, rec);
  445.   Read_Block;
  446.   for i := 1 to ofs do
  447.     c := get_arc
  448. end; (* proc fseek *)
  449.  
  450. procedure fread(var buf; reclen : integer);
  451. { read a record from the archive file }
  452. var i : integer;
  453.     b : array [1..MaxInt] of byte absolute buf;
  454. begin
  455.   for i := 1 to reclen do
  456.     b[i] := get_arc
  457. end; (* proc fread *)
  458.  
  459. procedure GetArcName;
  460. { get the name of the archive file }
  461. var i : integer;
  462. begin
  463. (*****************************************
  464.   if ParamCount > 1 then
  465.     abort('Too many parameters');
  466.   if ParamCount = 1 then
  467.     arcname := ParamStr(1)
  468. *****************************************)
  469.   if argc > 1 then
  470.     abort('Too many parameters');
  471.   if argc = 1 then
  472.     arcname := argv(1)
  473.   else begin
  474.     write('Enter archive filename: ');
  475.     readln(arcname);
  476.     if arcname = '' then
  477.       abort('No file name entered');
  478.     writeln;
  479.     writeln;
  480.     end;
  481.   for i := 1 to length(arcname) do
  482.     arcname[i] := UpCase(arcname[i]);
  483.   if pos('.', arcname) = 0 then
  484.     arcname := arcname + '.ARC'
  485. end; (* proc GetArcName *)
  486.  
  487. function readhdr(var hdr : heads) : boolean;
  488. { read a file header from the archive file }
  489. { FALSE = eof found; TRUE = header found }
  490. label exit;
  491. var name : fntype;
  492.     try  : integer;
  493. begin
  494.   try := 10;
  495.   if endfile then begin
  496.     readhdr := FALSE;
  497.     goto exit               (******** was "exit" ************)
  498.     end;
  499.   while get_arc <> arcmarc do begin
  500.     if try = 0 then
  501.       abort(arcname + ' is not an archive');
  502.     try := try - 1;
  503.     writeln(arcname, ' is not an archive, or is out of sync');
  504.     if endfile then
  505.       abort('Archive length error')
  506.     end; (* while *)
  507.  
  508.   hdrver := get_arc;
  509.   if hdrver < 0 then
  510.     abort('Invalid header in archive ' + arcname);
  511.   if hdrver = 0 then begin   { special end of file marker }
  512.     readhdr := FALSE;
  513.     goto exit               (******** was "exit" ************)
  514.     end;
  515.   if hdrver > arcver then begin
  516.     fread(name, fnlen);
  517.     writeln('I dont know how to handle file ', fn_to_str(name),
  518.             ' in archive ', arcname);
  519.     writeln('I think you need a newer version of DEARC.');
  520.     halt;
  521.     end;
  522.  
  523.   if hdrver = 1 then begin
  524.     fread(hdr, sizeof(heads) - sizeof(long));
  525.     hdrver := 2;
  526.     hdr.length := hdr.size
  527.     end
  528.   else
  529.     fread(hdr, sizeof(heads));
  530.  
  531.   readhdr := TRUE;
  532. exit:
  533. end; (* func readhdr *)
  534.  
  535. procedure putc_unp(c : integer);
  536. begin
  537.   crcval := ((crcval shr 8) and $00FF) xor crctab[(crcval xor c) and $00FF];
  538.   put_ext(c)
  539. end; (* proc putc_unp *)
  540.  
  541. procedure putc_ncr(c : integer);
  542. begin
  543.   case state of
  544.     NOHIST : if c = DLE then
  545.                state := INREP
  546.              else begin
  547.                lastc := c;
  548.                putc_unp(c)
  549.                end;
  550.     INREP  : begin
  551.              if c = 0 then
  552.                putc_unp(DLE)
  553.              else begin
  554.                c := c - 1;
  555.                while (c <> 0) do begin
  556.                  putc_unp(lastc);
  557.                  c := c - 1
  558.                  end
  559.                end;
  560.              state := NOHIST
  561.              end;
  562.     end; (* case *)
  563. end; (* proc putc_ncr *)
  564.  
  565. function getc_unp : integer;
  566. begin
  567.   if size = 0.0 then
  568.     getc_unp := -1
  569.   else begin
  570.     size := size - 1.0;
  571.     getc_unp := get_arc
  572.     end;
  573. end; (* func getc_unp *)
  574.  
  575. procedure init_usq;
  576. { initialize for unsqueeze }
  577. var i : integer;
  578. begin
  579.   bpos := 99;
  580.   fread(numnodes, sizeof(numnodes));
  581.   if (numnodes < 0) or (numnodes > NUMVALS) then
  582.     abort('File has an invalid decode tree');
  583.   node[0].child[0] := -(SPEOF + 1);
  584.   node[0].child[1] := -(SPEOF + 1);
  585.   for i := 0 to numnodes-1 do begin
  586.     fread(node[i].child[0], sizeof(integer));
  587.     fread(node[i].child[1], sizeof(integer))
  588.     end;
  589. end; (* proc init_usq; *)
  590.  
  591. function getc_usq : integer;
  592. { unsqueeze }
  593. label exit;
  594. var i : integer;
  595. begin
  596.   i := 0;
  597.   while i >= 0 do begin
  598.     bpos := bpos + 1;
  599.     if bpos > 7 then begin
  600.       curin := getc_unp;
  601.       if curin = ERROR then begin
  602.         getc_usq := ERROR;
  603.         goto exit                   (******** was "exit" ************)
  604.         end;
  605.       bpos := 0;
  606.       i := node[i].child[1 and curin]
  607.       end
  608.     else begin
  609.       curin := curin shr 1;
  610.       i := node[i].child[1 and curin]
  611.       end
  612.     end; (* while *)
  613.   i := - (i + 1);
  614.   if i = SPEOF then
  615.     getc_usq := -1
  616.   else
  617.     getc_usq := i;
  618.   exit:
  619. end; (* func getc_usq *)
  620.  
  621. function h(pred, foll : integer) : integer;
  622. { calculate hash value }
  623. { thanks to Bela Lubkin }
  624. var Local : Real;
  625.     S     : String[20];
  626.     I, V  : integer;
  627.     C     : char;
  628.  
  629. begin
  630. if not newhash then
  631. begin
  632.   Local := (pred + foll) or $0800;
  633.   if Local < 0.0 then
  634.     Local := Local + 65536.0;
  635.   Local := (Local * Local) / 64.0;
  636.  
  637. { convert Local to an integer, truncating high order bits. }
  638. { there ***MUST*** be a better way to do this!!! }
  639.   Str(Local:15:5, S);
  640.   V := 0;
  641.   I := 1;
  642.   C := S[1];
  643.   while C <> '.' do begin
  644.     if (C >= '0') and (C <= '9') then
  645.       V := V * 10 + (Ord(C) - Ord('0'));
  646.     I := I + 1;
  647.     C := S[I]
  648.     end;
  649.   h := V and $0FFF
  650. end (* func h *)
  651. else
  652. begin
  653.   Local := (pred + foll) * 15073;
  654.  
  655. { convert Local to an integer, truncating high order bits. }
  656. { there ***MUST*** be a better way to do this!!! }
  657.   Str(Local:15:5, S);
  658.   V := 0;
  659.   I := 1;
  660.   C := S[1];
  661.   while C <> '.' do begin
  662.     if (C >= '0') and (C <= '9') then
  663.       V := V * 10 + (Ord(C) - Ord('0'));
  664.     I := I + 1;
  665.     C := S[I]
  666.     end;
  667.   h := V and $0FFF
  668.  
  669. end;
  670. end;
  671.  
  672. function eolist(index : integer) : integer;
  673. var temp : integer;
  674. begin
  675.   temp := string_tab[index].next;
  676.   while temp <> 0 do begin
  677.     index := temp;
  678.     temp := string_tab[index].next
  679.     end;
  680.   eolist := index
  681. end; (* func eolist *)
  682.  
  683. function hash(pred, foll : integer) : integer;
  684. var local     : integer;
  685.     tempnext  : integer;
  686. begin
  687.   local := h(pred, foll);
  688.   if not string_tab[local].used then
  689.     hash := local
  690.   else begin
  691.     local := eolist(local);
  692.     tempnext := (local + 101) and $0FFF;
  693.     while string_tab[tempnext].used do begin
  694.       tempnext := tempnext + 1;
  695.       if tempnext = TABSIZE then
  696.         tempnext := 0
  697.       end;
  698.     string_tab[local].next := tempnext;
  699.     hash := tempnext
  700.     end;
  701. end; (* func hash *)
  702.  
  703. procedure upd_tab(pred, foll : integer);
  704. begin
  705.   with string_tab[hash(pred, foll)] do begin
  706.     used := TRUE;
  707.     next := 0;
  708.     predecessor := pred;
  709.     follower := foll
  710.     end
  711. end; (* proc upd_tab *)
  712.  
  713. function gocode : integer;
  714. label exit;
  715. var localbuf  : integer;
  716.     returnval : integer;
  717. begin
  718.   if inbuf = EMPTY then begin
  719.     localbuf := getc_unp;
  720.     if localbuf = -1 then begin
  721.       gocode := -1;
  722.       goto exit                       (******** was "exit" ************)
  723.       end;
  724.     localbuf := localbuf and $00FF;
  725.     inbuf := getc_unp;
  726.     if inbuf = -1 then begin
  727.       gocode := -1;
  728.       goto exit                       (******** was "exit" ************)
  729.       end;
  730.     inbuf := inbuf and $00FF;
  731.     returnval := ((localbuf shl 4) and $0FF0) + ((inbuf shr 4) and $000F);
  732.     inbuf := inbuf and $000F
  733.     end
  734.   else begin
  735.     localbuf := getc_unp;
  736.     if localbuf = -1 then begin
  737.       gocode := -1;
  738.       goto exit                       (******** was "exit" ************)
  739.       end;
  740.     localbuf := localbuf and $00FF;
  741.     returnval := localbuf + ((inbuf shl 8) and $0F00);
  742.     inbuf := EMPTY
  743.     end;
  744.   gocode := returnval;
  745. exit:
  746. end; (* func gocode *)
  747.  
  748. procedure push(c : integer);
  749. begin
  750.   stack[sp] := c;
  751.   sp := sp + 1;
  752.   if sp >= TABSIZE then
  753.     abort('Stack overflow')
  754. end; (* proc push *)
  755.  
  756. function pop : integer;
  757. begin
  758.   if sp > 0 then begin
  759.     sp := sp - 1;
  760.     pop := stack[sp]
  761.   end else
  762.     pop := EMPTY
  763. end; (* func pop *)
  764.  
  765. procedure init_tab;
  766. var i : integer;
  767. begin
  768.   FillChar(string_tab, sizeof(string_tab), 0);
  769.   for i := 0 to 255 do
  770.     upd_tab(NO_PRED, i);
  771.   inbuf := EMPTY;
  772.   { outbuf := EMPTY }
  773. end; (* proc init_tab *)
  774.  
  775. procedure init_ucr(i:integer);
  776. begin
  777.   newhash := i = 1;
  778.   sp := 0;
  779.   init_tab;
  780.   code_count := TABSIZE - 256;
  781.   firstc := TRUE
  782. end; (* proc init_ucr *)
  783.  
  784. function getc_ucr : integer;
  785. label exit;
  786. var c       : integer;
  787.     code    : integer;
  788.     newcode : integer;
  789. begin
  790.   if firstc then begin
  791.     firstc := FALSE;
  792.     oldcode := gocode;
  793.     finchar := string_tab[oldcode].follower;
  794.     getc_ucr := finchar;
  795.     goto exit                         (******** was "exit" ************)
  796.     end;
  797.   if sp = 0 then begin
  798.     newcode := gocode;
  799.     code := newcode;
  800.     if code = -1 then begin
  801.       getc_ucr := -1;
  802.       goto exit                       (******** was "exit" ************)
  803.       end;
  804.     if not string_tab[code].used then begin
  805.       code := oldcode;
  806.       push(finchar)
  807.       end;
  808.     while string_tab[code].predecessor <> NO_PRED do
  809.       with string_tab[code] do begin
  810.         push(follower);
  811.         code := predecessor
  812.         end;
  813.     finchar := string_tab[code].follower;
  814.     push(finchar);
  815.     if code_count <> 0 then begin
  816.       upd_tab(oldcode, finchar);
  817.       code_count := code_count - 1
  818.       end;
  819.     oldcode := newcode
  820.     end;
  821.   getc_ucr := pop;
  822. exit:
  823. end; (* func getc_ucr *)
  824.  
  825. function getcode : integer;
  826. label
  827.   next, exit;
  828. var
  829.   code, r_off, bitsx : integer;
  830.   bp : byte;
  831. begin
  832.   if firstch then
  833.   begin
  834.     offset := 0;
  835.     sizex := 0;
  836.     firstch := false;
  837.   end;
  838.   bp := 0;
  839.   if (clear_flg > 0) or (offset >= sizex) or (free_ent > maxcode) then
  840.   begin
  841.     if free_ent > maxcode then
  842.     begin
  843.       n_bits := n_bits + 1;
  844.       if n_bits = BITS then
  845.         maxcode := maxcodemax
  846.       else
  847.         maxcode := (1 shl n_bits) - 1;
  848.     end;
  849.     if clear_flg > 0 then
  850.     begin
  851.       n_bits := INIT_BITS;
  852.       maxcode := (1 shl n_bits) - 1;
  853.       clear_flg := 0;
  854.     end;
  855.     for sizex := 0 to n_bits-1 do
  856.     begin
  857.       code := getc_unp;
  858.       if code = -1 then
  859.         goto next
  860.       else
  861.         buf[sizex] := code;
  862.     end;
  863.     sizex := sizex + 1;
  864. next:
  865.     if sizex <= 0 then
  866.     begin
  867.       getcode := -1;
  868.       goto exit;
  869.     end;
  870.     offset := 0;
  871.     sizex := (sizex shl 3) - (n_bits - 1);
  872.   end;
  873.   r_off := offset;
  874.   bitsx := n_bits;
  875.  
  876.   { get first byte }
  877.   bp := bp + (r_off shr 3);
  878.   r_off := r_off and 7;
  879.  
  880.   { get first parft (low order bits) }
  881.   code := buf[bp] shr r_off;
  882.   bp := bp + 1;
  883.   bitsx := bitsx - (8 - r_off);
  884.   r_off := 8 - r_off;
  885.  
  886.   if bitsx >= 8 then
  887.   begin
  888.     code := code or (buf[bp] shl r_off);
  889.     bp := bp + 1;
  890.     r_off := r_off + 8;
  891.     bitsx := bitsx - 8;
  892.   end;
  893.  
  894.   code := code or ((buf[bp] and rmask[bitsx]) shl r_off);
  895.   offset := offset + n_bits;
  896.   getcode := code;
  897. exit:
  898. end;
  899.  
  900. procedure decomp;
  901. label
  902.   next,exit;
  903. var
  904.   stackp,
  905.   finchar :integer;
  906.   code, oldcode, incode : integer;
  907.  
  908. begin
  909.   { INIT var }
  910.   if firstch then
  911.     maxcodemax := 1 shl bits;
  912.  
  913.   code := getc_unp;
  914.   if code <> BITS then
  915.   begin
  916.     writeln('File packed with ',code,' bits, I can only handle ',BITS);
  917.     halt;
  918.   end;
  919.   clear_flg := 0;
  920.  
  921.   n_bits := INIT_BITS;
  922.   maxcode := (1 shl n_bits ) - 1;
  923.   for code := 255 downto 0 do
  924.   begin
  925.     prefix[code] := 0;
  926.     suffix[code] := code;
  927.   end;
  928.  
  929.   free_ent := FIRST;
  930.   oldcode := getcode;
  931.   finchar := oldcode;
  932.   if oldcode = -1 then
  933.     goto exit;
  934.   putc_ncr(finchar);
  935.   stackp := 0;
  936.  
  937.   code := getcode;
  938.   while code  > -1 do
  939.   begin
  940.     if code = CLEAR then
  941.     begin
  942.       for code := 255 downto 0 do
  943.         prefix[code] := 0;
  944.       clear_flg := 1;
  945.       free_ent := FIRST - 1;
  946.       code := getcode;
  947.       if code = -1 then
  948.         goto next;
  949.     end;
  950. next:
  951.     incode := code;
  952.     if code >= free_ent then
  953.     begin
  954.       stack1[stackp] := finchar;
  955.       stackp := stackp + 1;
  956.       code := oldcode;
  957.     end;
  958.     while code >= 256 do
  959.     begin
  960.       stack1[stackp] := suffix[code];
  961.       stackp := stackp + 1;
  962.       code := prefix[code];
  963.     end;
  964.     finchar := suffix[code];
  965.     stack1[stackp] := finchar;
  966.     stackp := stackp + 1;
  967.     repeat
  968.       stackp := stackp - 1;
  969.       putc_ncr(stack1[stackp]);
  970.     until stackp <= 0;
  971.     code := free_ent;
  972.     if code < maxcodemax then
  973.     begin
  974.       prefix[code] := oldcode;
  975.       suffix[code] := finchar;
  976.       free_ent := code + 1;
  977.     end;
  978.     oldcode := incode;
  979.     code := getcode;
  980.   end;
  981. exit:
  982. end;
  983.  
  984. procedure unpack(var hdr : heads);
  985. label exit;
  986. var c : integer;
  987. begin
  988.   crcval := 0;
  989.   size := long_to_real(hdr.size);
  990.   state := NOHIST;
  991.   case hdrver of
  992.     1, 2 : begin
  993.            c := getc_unp;
  994.            while c <> -1 do begin
  995.              putc_unp(c);
  996.              c := getc_unp
  997.              end
  998.            end;
  999.     3    : begin
  1000.            c := getc_unp;
  1001.            while c <> -1 do begin
  1002.              putc_ncr(c);
  1003.              c := getc_unp
  1004.              end
  1005.            end;
  1006.     4    : begin
  1007.            init_usq;
  1008.            c := getc_usq;
  1009.            while c <> -1 do begin
  1010.              putc_ncr(c);
  1011.              c := getc_usq
  1012.              end
  1013.            end;
  1014.     5    : begin
  1015.            init_ucr(0);
  1016.            c := getc_ucr;
  1017.            while c <> -1 do begin
  1018.              putc_unp(c);
  1019.              c := getc_ucr
  1020.              end
  1021.            end;
  1022.     6    : begin
  1023.            init_ucr(0);
  1024.            c := getc_ucr;
  1025.            while c <> -1 do begin
  1026.              putc_ncr(c);
  1027.              c := getc_ucr
  1028.              end
  1029.            end;
  1030.     7    : begin
  1031.            init_ucr(1);
  1032.            c := getc_ucr;
  1033.            while c <> -1 do begin
  1034.              putc_ncr(c);
  1035.              c := getc_ucr
  1036.              end
  1037.            end;
  1038.  
  1039.     8    : begin
  1040.              decomp;
  1041.            end;
  1042.     else
  1043.            writeln('I dont know how to unpack file ', fn_to_str(hdr.name));
  1044.            writeln('I think you need a newer version of DEARC');
  1045.            fseek(long_to_real(hdr.size), 1);
  1046.            goto exit                         (******** was "exit" ************)
  1047.     end; (* case *)
  1048.   if crcval <> hdr.crc then
  1049.     writeln('WARNING: File ', fn_to_str(hdr.name), ' fails CRC check');
  1050. exit:
  1051. end; (* proc unpack *)
  1052.  
  1053. procedure extract_file(var hdr : heads);
  1054. begin
  1055.   extname := fn_to_str(hdr.name);
  1056.   writeln('Extracting file : ', extname);
  1057.   open_ext;
  1058.   unpack(hdr);
  1059.   close_ext
  1060. end; (* proc extract *)
  1061.  
  1062. procedure extarc;
  1063. var hdr : heads;
  1064. begin
  1065.   open_arc;
  1066.   while readhdr(hdr) do
  1067.     extract_file(hdr);
  1068.   close_arc
  1069. end; (* proc extarc *)
  1070.  
  1071. procedure PrintHeading;
  1072. begin
  1073.   writeln;
  1074.   writeln('Turbo Pascal DEARC Utility');
  1075.   writeln('Version 2.0, 6/11/86');
  1076.   writeln('Supports ARC version 5.12 files');
  1077.   writeln;
  1078. end; (* proc PrintHeading *)
  1079.  
  1080. begin
  1081.   firstch := true;
  1082.   PrintHeading; { print a heading }
  1083.   GetArcName;   { get the archive file name }
  1084.   extarc        { extract all files from the archive }
  1085. end.
  1086. end;
  1087.     3    : begin
  1088.            c := getc_unp;
  1089.            while c <> -1 do begin
  1090.              putc_ncr(c);
  1091.