[net.micro.atari16] Uudecode in OSS Pascal

beatyr@pur-ee.UUCP (Robert Beaty) (09/12/86)

<<<<<>>>>>

  I worked up this version of uudecode for the ST after getting
the turbo pascal version to work on my PC. It is the full
featured version, except that it will write only even numbered
binary files. This is because OSS Pascal can only write integers
to files and an integer is two bytes. This is not a functional
problem, only a theoretical one.
  The original author should probably stand forward, as should
the copywrite info for OSS Pascal, but since this is the net,
and you need the Compiler to get it running, I think it is
good enough.
  I don't guarantee anything other than it works for me, and it
does use the GEM interface (I added that). If you need the 
executable then mail me at the address at the end of this posting,
I will try to work something out. Have fun!

****** cut here ******
program uudecode;

  CONST
    {$I gemconst }
    defaultSuffix = '.UUE';
    offset = 32;

  TYPE
    {$I gemtype }
    string80 = string[80];

  VAR infile: text;
      outfile: file of integer;
      lineNum: integer;
      uuline, mess : string80;
      path, name : Path_Name;
      double_byte : integer;
      Got_High_Byte : Boolean;
      i : integer;
      x : Str255;

  {$I gemsubs }

  procedure OutputWord( std_byte : byte );
    { This procedure is for the ST where the smallest thing is a word }
    begin
      if Got_High_Byte then
        begin
          double_byte:=double_byte + (std_byte & $00ff);
          outfile^:=double_byte;
          Put(outfile);
          Got_High_Byte:=False;
        end
      else
        begin
          double_byte:=ShL(std_byte, 8) & $ff00;
          Got_High_Byte:=True;
        end;
    end;

  procedure Abort(message: string80);
    var
      x : str255;
      a, b : integer;
      i : integer;
    begin {abort}
      x:='[3][ ';        { make it a stop sign }
      if lineNum > 0 then
        begin
          x:=Concat(x,'Line ');
          a:=lineNum;
          for i:=4 downto 1 do
            begin
              b:=Trunc(a/PwrOfTen(i));
              a:=a-Trunc(b*PwrOfTen(i));
              x:=Concat(x,Chr(b+48));
            end;
          x:=Concat(x,Chr(a+48),' : | ');
        end;
      x:=Concat(x,message,' ]');
      x:=Concat(x,'[ Exit ]');
      i:=Do_Alert(x,1);
      Exit_GEM;
      Halt;
    end; {Abort}

  procedure NextLine(var s: string80);

    begin {NextLine}
      LineNum := LineNum+1;
      readln(infile, s);
    end; {NextLine}

  procedure Init;

    procedure GetInFile;

      VAR infilename: string80;
          i : integer;

      begin {GetInFile}
        path:='A:\*.UUE';
        name:='';
        if (Get_In_File( path, name )) then
          begin
            IO_Check( False );
            reset(infile, name);
            if IO_Result <> 0 then
              begin
                mess:=Concat( 'Cannot open ',name );
                abort( mess );
              end;
            IO_Check( True );
            infilename:=name;
          end
        else
          abort( 'No input file specified' );
      end; {GetInFile}

    procedure GetOutFile;

      var header, mode, outfilename, test: string80;
          ch: char;
          i : integer;
          x : str255;

      procedure ParseHeader;

        VAR index: integer;

        Procedure NextWord(var word:string80; var index: integer);

          begin {nextword}
            word := '';
            while header[index] = ' ' do
              begin
                index := index+1;
                if index > length(header) then abort ('Incomplete header');
              end;
            while header[index] <> ' ' do
              begin
                word := concat(word, header[index]);
                index := index+1;
              end;
          end; {NextWord}

        begin {ParseHeader}
          header := concat(header, ' ');
          index := 7;
          NextWord(mode, index);
          NextWord(outfilename, index);
        end; {ParseHeader}

      begin {GetOutFile}
        if EOF(infile) then abort('Nothing to decode.');
        NextLine(header);
        test:=Copy( header, 1, 6 );
        while not ((test = 'begin ') or EOF(infile)) do
          begin
            NextLine(header);
            test:=Copy( header, 1, 6 );
          end;
        if eof(infile) then abort('Nothing to decode.');
        ParseHeader;
        x:=Concat( '[0][   Destination is ', outfilename,'   ]' );
        x:=Concat( x, '[ Fine ]' );
        i:=Do_Alert(x,1);    { do the message }
        IO_Check( False );
        reset(outfile, outfilename);
        if IO_Result = 0 then
          begin
            x:='[2][';
            x:=Concat(x,' Overwrite current |');
            x:=Concat(x,outfilename,'? ]');
            x:=Concat(x,'[ Yes | No ]');
            i:=Do_Alert( x, 0 );
            if i = 2 then abort ('Overwrite cancelled.');
          end;
        IO_Check( True );
        rewrite (outfile, outfilename);
      end; {GetOutFile}

    begin {init}
      lineNum := 0;
      GetInFile;
      GetOutFile;
    end; { init}

  Function CheckLine: boolean;

    begin {CheckLine}
      if uuline = '' then abort ('Blank line in file');
      CheckLine := not (uuline[1] in [' ', '`']);
    end; {CheckLine}


  procedure DecodeLine;

    VAR lineIndex, byteNum, count, i: integer;
        chars: array [0..3] of integer;
        hunk: array [0..2] of byte;

    function nextch: char;
      begin {nextch}
        lineIndex := lineIndex+1;
        if lineIndex > length(uuline) then abort('Line too short.');
        if not (uuline[lineindex] in [' '..'`']) then
          abort('Illegal character in line.');
        if uuline[lineindex] = '`' then
          nextch := ' '
        else
          nextch := uuline[lineIndex];
      end; {nextch}

    procedure DecodeByte;

      procedure GetNextHunk;

        VAR i : integer;
            a,b,c,d,e,f : byte;

        begin {GetNextHunk}
          for i := 0 to 3 do
            chars[i]:=ord(nextch)-offset;
          a:=ShL(chars[0],2) & $00fc;
          b:=ShR(chars[1],4) & $000f;
          c:=ShL(chars[1],4) & $00f0;
          d:=ShR(chars[2],2) & $003f;
          e:=ShL(chars[2],6) & $00c0;
          f:=chars[3];
          hunk[0] := a + b;
          hunk[1] := c + d;
          hunk[2] := e + f;
          byteNum := 0;
        end; {GetNextHunk}

      begin {DecodeByte}
        if byteNum = 3 then GetNextHunk;
        OutputWord( hunk[byteNum] );       { this is ST specific!! }
        byteNum := byteNum+1;
      end; {DecodeByte}

    begin {DecodeLine}
      lineIndex := 0;
      byteNum := 3;
      count := (ord(nextch) - offset);
      for i := 1 to count do
        DecodeByte;
    end; {DecodeLine}

  procedure terminate;

    var trailer, test: string80;

    begin {terminate}
      if eof(infile) then abort ('Abnormal end.');
      NextLine (trailer);
      if length (trailer) < 3 then abort ('Abnormal end.');
      test:=Copy( trailer, 1, 3 );
      if test <> 'end' then abort ('Abnormal end.');
      if Got_High_Byte then              { rescue the lost byte }
        begin
          outfile^:=double_byte;
          Put(outfile);
        end;
      close (infile);
      close (outfile);
    end;

  begin {uudecode}
    if Init_GEM >= 0 then
      begin
        init;
        NextLine(uuline);
        while CheckLine do
          begin
            DecodeLine;
            NextLine(uuline);
          end;
        terminate;
        Exit_GEM;
      end;
  end.
****** cut here ******
----------
   ... ihnp4!pur-ee!beatyr      <- usenet
  ... beatyr@ed.ecn.purdue.edu  <- arpa-net
   ... beatyr@pur-ee.UUCP       <- UUCP
----------