#       enread - read RIPE database entry
#
# Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998, 1999 by RIPE NCC
#
# All Rights Reserved
#
# Permission to use, copy, modify, and distribute this software and its
# documentation for any purpose and without fee is hereby granted,
# provided that the above copyright notice appear in all copies and that
# both that copyright notice and this permission notice appear in
# supporting documentation, and that the name of the author not be
# used in advertising or publicity pertaining to distribution of the
# software without specific, written prior permission.
#
# THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
# AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
# AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# $Id: enread.pl,v 2.5 1999/10/06 16:41:08 marek Exp $
#
#	$RCSfile: enread.pl,v $
#	$Revision: 2.5 $
#	$Author: marek $
#	$Date: 1999/10/06 16:41:08 $
#
#       This routine reads RIPE database entries in %entry and returns the
#       type, "" when nothing has been found, $DELETEDOBJECT when
#       the object has been deleted, and an other invalid type when an 
#       invalid object has been found.
#       When no valid/deleted object has been found %entry is set to ().
#
#       file       file to read from

#
# enread
#
# Take care with changing anything in this routine.
# It is highly optimized for speed, especially for (sorted) big objects.
#

sub enread {
    local($file, *entry, $offset) = @_;

    local($line,$newtag,$tag,$shorttag);

    local($type)="";
    local(@lines)=();
    %entry=();

    # print $offset;

    seek($file, $offset, 0) if ($offset>=0);

    #
    # skip empty lines until we find the first data and
    # make sure that we store the offset in the object
    
    $entry{"offset"}=tell($file);
    while ((($line=<$file>)=~ s/\s/ /g) && (($line=~ /^ +$/) || ($line=~ /^ *\#/))) {
       $entry{"offset"}=tell($file);
       # print STDERR "skip lines: ", $line;
    }
    
    # print STDERR "first line: ", $line;
    
    if ($line) {
       
       #
       # skip deleted objects immediately
    
       if ($line=~ /^ *\*?$DELETEDOBJECT *\:/o) {
          # print STDERR "XX object $line";
       
          while (($line=<$file>) && ($line!~ /^\s+$/)) {}
                      
          return ($DELETEDOBJECT);

       }
       
       #
       # do the tag initialization
       
       $line=~ /^ *\*?([^\*\: ]+) *\:/;
       ($tag=$1)=~ tr/A-Z/a-z/;
       
       #
       # check for unknown attribute, but we read further if found
       
       $shorttag=$ATTR{$tag};
      
       if (!$shorttag) {
          &syslog("ERRLOG", "enread: unknown attribute: \'$tag\' found, (offset: ".$offset." ".$entry{"offset"}." ".tell($file).") in line: $tag: ".$line);
          $shorttag=$tag;
       }
       
       $type=$shorttag if ($OBJATSQ{$shorttag});
    
       while (1) {
          
          # print STDERR $line;
          
          if ($line=~ s/^ *\*?([^\*\: ]+) *\: *//) {
             
             ($newtag=$1)=~ tr/A-Z/a-z/;
             
             #
             # remove trailing spaces
             
             $line=~ s/ *$//;
             
             if ($tag eq $newtag) {
             
                # print STDERR "tag: ", $tag, "\n";
             
                # tag is same as previous one
             
                if ($line) {
                   # print STDERR "tag: $tag value: $line\n";
                   push(@lines,$line);
                }
                else {
                   push(@lines,"")  if ($lines[$#lines]);
                   #&syslog("ERRLOG", "enread: empty attribute, normal $tag (offset: ".$offset." ".$entry{"offset"}." ".tell($file).") in line: $newtag:");
                }
             
             }
             else {
                
                #
                # tag could have been changed
                
                #
                # store old tag
                
                if ($entry{$shorttag}) {
                   $entry{$shorttag}=join("\n",$entry{$shorttag},@lines) if (scalar(@lines));
                }
                else {
                   $entry{$shorttag}=join("\n",@lines) if (scalar(@lines));
                }
                
                $tag=$newtag;
                
                $shorttag=$ATTR{$tag};
                
                if (!$shorttag) {
                   &syslog("ERRLOG", "enread: unknown attribute: \'$tag\' found, (offset: ".$offset." ".$entry{"offset"}." ".tell($file).") in line: $tag: ".$line);
                   $shorttag=$tag;
                }
                
                #
                # we keep the type of the object
                
                # print STDERR "newtag: ", keys %OBJATSQ, $tag, "\n";
                
                $type=$shorttag if ((!$type) && ($OBJATSQ{$shorttag}));
                
                #
                # print STDERR "type: ", $type, "\n";
                
                if ($line) {
                   # print STDERR "newtag: $tag type: $type value: $value\n";
                   @lines=($line);
                }
                else {
                   @lines=("");
                   #&syslog("ERRLOG", "enread: empty attribute, newtag $newtag (offset: ".$offset." ".$entry{"offset"}." ".tell($file).") in line:".$line);
                }
             
             }
             
          }
          else {
             
             # now we have the following possibilties:
             #
             # - we are at the end of the object
             # - we found a comment
             # - we have an error condition
             #
             # let's assume the first possibility first since
             # it is most common
             
             if ($line=~ /^ *$/) {

                #   
                # end of object
                
                #
                # store old tag
                
                if ($entry{$shorttag}) {
                   $entry{$shorttag}=join("\n",$entry{$shorttag},@lines) if (scalar(@lines));
                }
                else {
                   $entry{$shorttag}=join("\n",@lines) if (scalar(@lines));
                }
                      
                # print STDERR "type: $type ",$entry{"so"}." $shorttag entry:\n", %entry, "\n";
                   
                return ($type) if ($type);
                
                &syslog("ERRLOG", "enread: object has no type (offset: ".$offset." ".$entry{"offset"}." ".tell($file).") in line: ".$line);  
                   
                %entry=();
                   
                # just create a type that is not the same as others and 
                # that is for sure invalid ...
                      
                return ($DELETEDOBJECT.$DELETEDOBJECT);
                      
             }
             elsif ($line!~ /^ *\#/) {
  
                #              
                # no comment, no end of object
                #
                # we have an error condition
                #
                
                # print STDERR "$offset $line";
                      
                &syslog("ERRLOG", "enread: no attribute in line (tag: $tag, type: $type) (offset: ".$offset." ".$entry{"offset"}." ".tell($file).") in line: ".$line);  
                
                # skip rest of object
                         
                while (($line=<$file>) && ($line!~ /^\s+$/)) {}
                     
                %entry=();
                      
                # just create a type that is not the same as others and 
                # that is for sure invalid ...
                      
                return ($DELETEDOBJECT.$DELETEDOBJECT);
                
             }
             
          }
       
          ($line=<$file>)=~ s/\s/ /g;
          
          # print STDERR $line;
       
       }  
    }
    else {
       return ("");
    }

}

1;
