require "flush.pl";

sub parse {

  local($configFile,$lineNumber,$COUNT,@CONFIG,@ELEMENT,$TITLE,$DEFAULT,$BEGIN,  
        $END,$FILE,$i,$token,$buffer,$length,$index,$foundTokenInConfig, 
        $endToken);

  $configFile   = $_[0];
  $lineNumber   = $_[1];
  $bufferLength = 65536;
    
  #
  # Check arguments to script
  #
    
  unless ($configFile) {
    $errorMessage = "usage: parse <config file> <line number>";
    return -1;
  }
  unless ($lineNumber > 0) {
    $errorMessage = "usage: parse <config file> <line number>";
    return -1;
  }
    
  #
  # First read configuration file into arrays
  #
    
  if (-s $configFile) {
    (@CONFIG = `cat $configFile`) || die;
  }
  $COUNT = -1;
  foreach (@CONFIG) {
    $COUNT++;
    @ELEMENT = split(/:/);
    
    #
    # Remove white space from begin/end/file tokens
    #
    
    $ELEMENT[2] =~ (s/\s//g);
    $ELEMENT[3] =~ (s/\s//g);
    $ELEMENT[4] =~ (s/\s//g);
    
    #
    # Fill arrays
    #
    
    $TITLE[$COUNT]   =    $ELEMENT[0];
    $DEFAULT[$COUNT] =    $ELEMENT[1];
    $BEGIN[$COUNT]   = "\U$ELEMENT[2]";
    $END[$COUNT]     = "\U$ELEMENT[3]";
    $FILE[$COUNT]    =    $ELEMENT[4];
  }
  
  #
  # Add the "help" token for the help solver
  #
  
  $COUNT++;
  $BEGIN[$COUNT] = "HELP";
  $END[$COUNT]   = "NULL";
  $FILE[$COUNT]  = "help.type";
  
  #
  # Add the "forward" token for forwarding results
  #
  
  $COUNT++;
  $BEGIN[$COUNT] = "FORWARD";
  $END[$COUNT]   = "NULL";
  $FILE[$COUNT]  = "job.forward"; 
  
  
  #
  # Parse job.received line by line after skipping past "solver=" 
  #
  
  open(handle, "job.received") or die;
  
  #
  # skip to <lineNumber>
  #
    
  for ($i=1;$i<$lineNumber;$i++) {
    <handle>;
  }
  
  #
  # Start parsing.  For every "begin token" we search for and "end token"
  # saving all text in between as data. If the "end token" is null, then
  # we don't look for and "end token." Instead we just get the data from 
  # same line as the "begin token." 
  #
  
  $doneflag = 0;
  
  while (<handle>) {
    
    $binary = 0;
    
    if (/END-(SOLVER|SERVER|NEOS)-INPUT/) {
      $doneflag = 1;
    }
    
    unless( $doneflag ) {
      $lineNumber++;
      next unless (/\S+/);
      
      /\s*(([^\=|\s])+)/;
      $token  = "\U$1";
      $buffer = "";
      $length = 0;
      if ($token  =~ /(\S+)\[(\d+)\]/) {
        $token  = $1;
        $length = $2;
        if($token =~ /BINARY$/) {
          $binary = 1;
        }
      }		     
      
      # 
      # Find token in BEGIN array
      #
      
      $index = 0; 
      $foundTokenInConfig = 0;
      foreach $beginToken (@BEGIN) {
        if ($token eq $beginToken) {
		$foundTokenInConfig = 1;
		last;
        }
        $index++;
      }
      unless ($foundTokenInConfig) {
        $errorMessage = "\"$token\" is not a valid beginning token.";
        return -1;
      }
      
      #
      # Read <length> bytes into buffer if a <length>
      # was provided with the token.
      # 
      
      if ($length > 0) {
        open (fileHandle, ">$FILE[$index]");
        for ($i=1;($i*$bufferLength)<=$length;$i++) {
		read(handle, $buffer, $bufferLength);
		print fileHandle $buffer;
		$total = $i*$bufferLength;
        }
        if ($length%$bufferLength>0) {
		read(handle, $buffer, $length%$bufferLength);
		print fileHandle $buffer;
        }
        close (fileHandle);
        printf jobHandle ("%9d bytes written to $FILE[$index] ($TITLE[$index])\n", $length);
        $FILES{$FILE[$index]} = 1;
        #
        # Check for compressed file 
        #
        
        $typecomp = `gzip --list --verbose $FILE[$index] 2>/dev/null`;
        # if it is a compressed file...
        
        if ($typecomp =~ /\w/)
        {
		&compressed();
        } 
        &convert($FILE[$index]);
        
      } 

      #
      # Else read until <endToken>, unless <endToken> is NULL 
      # in which case the data is whatever follows <beginToken>.
      #
      
      else {
        $endToken = $END[$index];
        if ($endToken eq "NULL") {
		if (/\s*(([^\=|\s])+)\s*=?\s*((\S|\s)*)/) {
            $buffer = $3; 
            #
            # Write buffer to file
            #
            
            open (fileHandle, ">$FILE[$index]");
            if ($length == 0) {
              $length = length($buffer);
            }
            printf jobHandle ("%9d bytes written to $FILE[$index] ($TITLE[$index])\n", $length); 
            &flush(jobHandle);
            print fileHandle $buffer;
            close (fileHandle);
            &convert($FILE[$index]);
            
            $FILES{$FILE[$index]} = 1;
		}
        } else {
		while (<handle>) {
            if (/^\s*$endToken/i) {
              $endTokenFound = 1;
              last;
            }
            $buffer .= $_; 
		} 
		unless ($endTokenFound) {
            $errorMessage = "EOF encountered when \"$endToken\" was expected.";
            return -1;
		}
          
		#
		# Write file input buffer to file 
		#
		
		open (fileHandle, ">$FILE[$index]");
		if ($length == 0) {
            $length = length($buffer);
		}
		
		printf jobHandle ("%9d bytes written to $FILE[$index] ($TITLE[$index])\n", $length); 
		&flush(jobHandle);
		print fileHandle $buffer;
		close (fileHandle);
		
		$FILES{$FILE[$index]} = 1;
		#
		# Check for compressed file 
		#
		
		$typecomp = `gzip --list --verbose $FILE[$index] 2>/dev/null`;
		# if it is a compressed file...
		
		if ($typecomp =~ /\w/)
		{
            open (fileHandle, ">$FILE[$index]");
            chomp($buffer);
            print fileHandle $buffer;
            close (fileHandle);		
            &compressed();
		} 
		&convert($FILE[$index]);
          
        }
      }
    }
    $endTokenFound = 0;
  }
  unless (keys %FILES) {
    print jobHandle "  No data parsed.\n";
    &flush(jobHandle);
  } 
  foreach $file (keys %FILES) {
    $files .= " $file";
  }
  open(handle, ">PARSED_FILES");
  print handle "$files\n";
  close(handle);
}

sub compressed {
	
  #
  # defla ffffffff indicates a file by zip or WinZip
  #
  if ($typecomp =~ /defla ffffffff/)
  {
    system ("mv $FILE[$index] $FILE[$index].z");
    system ("gunzip -f $FILE[$index].z 2>/dev/null");
  }
  else 
  {
    #
    # defla without ffffffff indicates a real gzip file
    # only deflated gzip files are allowed
    #
    if ($typecomp =~ /defla/)
    {
      system ("mv $FILE[$index] $FILE[$index].gz");
      system ("gunzip -f $FILE[$index].gz 2>/dev/null");
    }
    else
    {
      #
      # compr ffffffff indicates a compress file 
      #
      if($typecomp =~ /compr ffffffff/)
      {
        system("mv $FILE[$index] $FILE[$index].Z");
        system("gunzip -f $FILE[$index].Z 2>/dev/null");
      }	
      else
      {
      }
    }
  }
}

#
# Conversion of DOS or Mac to UNIX must come
# after file decompression.  Otherwise the compressed
# files are corrupted.
#

sub convert {

  my $file = $_[0];
  my $line;
  my $offset;

  if(!$binary) {
    open (convhandle, "$file");
    open (convtemp, ">$file.tmp");
    $offset = 0;
    $i = read(convhandle,$line,1024); 
    while(defined($i) and ($i > 0)) {
      $line =~ s/\r\n/\n/g;  
      if($line =~ s/\r$//==1) {
        $offset = 1;
      } 
      $line =~ s/\r/\n/g;
      print convtemp $line;
      if($offset) {
        $line = "\r";
      } 
      $i = read(convhandle,$line,1024,$offset); 
      $offset = 0;
    }
    close convhandle;
    close convtemp;
    rename("$file.tmp", "$file");
  }
}

1
