home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / cpm / cpm86 / uudecode.pas < prev    next >
Pascal/Delphi Source File  |  1986-09-29  |  8KB  |  304 lines

  1. program uudecode;
  2.  
  3.   CONST defaultSuffix = '.uue';
  4.         offset = 32;
  5.  
  6.   TYPE string80 = string[80];
  7.  
  8.   VAR infile: text;
  9.       outf : file;
  10.       lineNum: integer;
  11.       line: string80;
  12.       outfilename : string80;
  13.  
  14. {Binary file read added by Ross Alford,  ...!mcnc!ecsvax!alford.  The original
  15.  MSDOS versions of uuencode/decode just use read/write on a FILE OF BYTE.
  16.  CP/M Turbo expects some file info to be stored in the first 4 bytes of files
  17.  of any type other than TEXT.  Putbyte (below) and Getbyte (in UUENCODE)
  18.  bypass this 'feature' by using blockread and blockwrite.  The only global
  19.  variables either use are  'infilename' and 'inf' or 'outfilename' and 'outf'}
  20.  
  21. procedure putbyte(b : byte; flush : boolean);
  22.  
  23. type bufptr = ^bufrec;
  24.      bufrec = record
  25.                 next : bufptr;
  26.                 buffer : array[1..128] of byte
  27.               end;
  28.  
  29. const sectstobuf = 8;                {max number of sectors to buffer}
  30.       sectswritten : integer = 1;    {constants are essentially statics}
  31.       bytptr : integer = 1;
  32.       notopen : boolean = TRUE;
  33.       infsize : integer = 0;
  34.       listsaveofs : integer = 0;
  35.       listsaveseg : integer = 0;
  36.       tempsaveofs : integer = 0;
  37.       tempsaveseg : integer = 0;
  38.  
  39. var list,temp,temp2 : bufptr;
  40.     i : integer;
  41.  
  42. begin
  43.   if flush then
  44.     begin
  45.       list := ptr(listsaveseg,listsaveofs);
  46.       temp := list;
  47.       for i := 1 to sectswritten do
  48.         begin
  49.           blockwrite(outf,temp^.buffer,1);
  50.           temp := temp^.next
  51.         end;
  52.       close(outf)
  53.     end
  54.     else begin
  55.       if notopen then
  56.         begin
  57.           notopen := FALSE;
  58.           assign(outf,outfilename);
  59.           {$i-}
  60.           reset(outf);
  61.           {$i+}
  62.           if ioresult = 0 then
  63.             begin
  64.               writeln('File ',outfilename,' exists.  Cannot overwrite.');
  65.               halt
  66.             end;
  67.           {$i-}
  68.           rewrite(outf);
  69.           {$i+}
  70.           if ioresult <> 0 then
  71.             begin
  72.               writeln('Cannot open file ',outfilename,' for output.');
  73.               halt
  74.             end;
  75.           new(list);
  76.           temp := list;
  77.           for i := 1 to sectstobuf - 1 do
  78.             begin
  79.               new(temp2);
  80.               temp2^.next := NIL;
  81.               temp^.next := temp2;
  82.               temp := temp2
  83.             end;
  84.           listsaveofs := ofs(list^);
  85.           listsaveseg := seg(list^);
  86.           tempsaveofs := listsaveofs;
  87.           tempsaveseg := listsaveseg;
  88.         end;
  89.       temp := ptr(tempsaveseg,tempsaveofs);
  90.       if bytptr > 128 then
  91.         begin
  92.           if temp^.next <> NIL then
  93.             begin
  94.               sectswritten := succ(sectswritten);
  95.               temp := temp^.next;
  96.               bytptr := 1
  97.             end
  98.             else begin
  99.               temp := ptr(listsaveseg,listsaveofs);
  100.               for i := 1 to sectstobuf do
  101.                 begin
  102.                   blockwrite(outf,temp^.buffer,1);
  103.                   temp := temp^.next
  104.                 end;
  105.               temp := ptr(listsaveseg,listsaveofs);
  106.               sectswritten := 1;
  107.               bytptr := 1
  108.             end
  109.         end;
  110.       temp^.buffer[bytptr] := b;
  111.       bytptr := succ(bytptr);
  112.       tempsaveofs := ofs(temp^);
  113.       tempsaveseg := seg(temp^)
  114.     end
  115. end;
  116.  
  117.   procedure Abort(message: string80);
  118.  
  119.     begin {abort}
  120.       writeln;
  121.       if lineNum > 0 then write('Line ', lineNum, ': ');
  122.       writeln(message);
  123.       halt
  124.     end; {Abort}
  125.  
  126.   procedure NextLine(var s: string80);
  127.  
  128.     begin {NextLine}
  129.       LineNum := succ(LineNum);
  130.       write('.');
  131.       readln(infile, s)
  132.     end; {NextLine}
  133.  
  134.   procedure Init;
  135.  
  136.     procedure GetInFile;
  137.  
  138.       VAR infilename: string80;
  139.  
  140.       begin {GetInFile}
  141.         if ParamCount = 0 then abort ('Usage: uudecode <filename>');
  142.         infilename := ParamStr(1);
  143.         if pos('.', infilename) = 0
  144.           then infilename := concat(infilename, defaultSuffix);
  145.         assign(infile, infilename);
  146.         {$i-}
  147.         reset(infile);
  148.         {$i+}
  149.         if IOresult > 0 then abort (concat('Can''t open ', infilename));
  150.         writeln ('Decoding ', infilename)
  151.       end; {GetInFile}
  152.  
  153.     procedure GetOutFile;
  154.  
  155.       var header, mode : string80;
  156.           ch: char;
  157.  
  158.       procedure ParseHeader;
  159.  
  160.         VAR index: integer;
  161.  
  162.         Procedure NextWord(var word:string80; var index: integer);
  163.  
  164.           begin {nextword}
  165.             word := '';
  166.             while header[index] = ' ' do
  167.               begin
  168.                 index := succ(index);
  169.                 if index > length(header) then abort ('Incomplete header')
  170.               end;
  171.             while header[index] <> ' ' do
  172.               begin
  173.                 word := concat(word, header[index]);
  174.                 index := succ(index)
  175.               end
  176.           end; {NextWord}
  177.  
  178.         begin {ParseHeader}
  179.           header := concat(header, ' ');
  180.           index := 7;
  181.           NextWord(mode, index);
  182.           NextWord(outfilename, index)
  183.         end; {ParseHeader}
  184.  
  185.       begin {GetOutFile}
  186.         if eof(infile) then abort('Nothing to decode.');
  187.         NextLine (header);
  188.         while not ((copy(header, 1, 6) = 'begin ') or eof(infile)) do
  189.           NextLine(header);
  190.         writeln;
  191.         if eof(infile) then abort('Nothing to decode.');
  192.         ParseHeader;
  193.       end; {GetOutFile}
  194.  
  195.     begin {init}
  196.       lineNum := 0;
  197.       GetInFile;
  198.       GetOutFile;
  199.     end; { init}
  200.  
  201.   Function CheckLine: boolean;
  202.  
  203.     begin {CheckLine}
  204.       if line = '' then abort ('Blank line in file');
  205.       CheckLine := not (line[1] in [' ', '`'])
  206.     end; {CheckLine}
  207.  
  208.  
  209.   procedure DecodeLine;
  210.  
  211.     VAR lineIndex, byteNum, count, i: integer;
  212.         chars: array [0..3] of byte;
  213.         hunk: array [0..2] of byte;
  214.  
  215. {    procedure debug;
  216.  
  217.       var i: integer;
  218.  
  219.       procedure writebin(x: byte);
  220.  
  221.         var i: integer;
  222.  
  223.         begin
  224.           for i := 1 to 8 do
  225.             begin
  226.               write ((x and $80) shr 7);
  227.               x := x shl 1
  228.             end;
  229.           write (' ')
  230.         end;
  231.  
  232.       begin
  233.         writeln;
  234.         for i := 0 to 3 do writebin(chars[i]);
  235.         writeln;
  236.         for i := 0 to 2 do writebin(hunk[i]);
  237.         writeln
  238.       end;      }
  239.  
  240.     function nextch: char;
  241.  
  242.       begin {nextch}
  243.       {}  lineIndex := succ(lineIndex);
  244.         if lineIndex > length(line) then abort('Line too short.');
  245.         if not (line[lineindex] in [' '..'`'])
  246.           then abort('Illegal character in line.');
  247. {        write(line[lineindex]:2);}
  248.         if line[lineindex] = '`' then nextch := ' '
  249.                                   else nextch := line[lineIndex]
  250.       end; {nextch}
  251.  
  252.     procedure DecodeByte;
  253.  
  254.       procedure GetNextHunk;
  255.  
  256.         VAR i: integer;
  257.  
  258.         begin {GetNextHunk}
  259.           for i := 0 to 3 do chars[i] := ord(nextch) - offset;
  260.           hunk[0] := (chars[0] shl 2) + (chars[1] shr 4);
  261.           hunk[1] := (chars[1] shl 4) + (chars[2] shr 2);
  262.           hunk[2] := (chars[2] shl 6) + chars[3];
  263.           byteNum := 0  {;
  264.           debug          }
  265.         end; {GetNextHunk}
  266.  
  267.       begin {DecodeByte}
  268.         if byteNum = 3 then GetNextHunk;
  269.         putbyte(hunk[byteNum],FALSE);
  270.         {writeln(bytenum, ' ', hunk[byteNum]);}
  271.         byteNum := succ(byteNum)
  272.       end; {DecodeByte}
  273.  
  274.     begin {DecodeLine}
  275.       lineIndex := 0;
  276.       byteNum := 3;
  277.       count := (ord(nextch) - offset);
  278.       for i := 1 to count do DecodeByte
  279.     end; {DecodeLine}
  280.  
  281.   procedure terminate;
  282.  
  283.     var trailer: string80;
  284.  
  285.     begin {terminate}
  286.       if eof(infile) then abort ('Abnormal end.');
  287.       NextLine (trailer);
  288.       if length (trailer) < 3 then abort ('Abnormal end.');
  289.       if copy (trailer, 1, 3) <> 'end' then abort ('Abnormal end.');
  290.       close (infile);
  291.       putbyte(26,TRUE)
  292.     end;
  293.  
  294.   begin {uudecode}
  295.     init;
  296.     NextLine(line);
  297.     while CheckLine do
  298.       begin
  299.         DecodeLine;
  300.         NextLine(line)
  301.       end;
  302.     terminate
  303.   end.
  304.