#!perl
##  Version 2.0.1    
##  Laurence R. Taylor  taylor.2@nd.edu www.nd.edu/~taylor
##  Copyright (C) 2000
##  Freely distributed under the standard GNU Copyleft agreement


my($pst_folder,$dot_folder,$dotbibfile,@dotbibs,@files,$preambleString);

my(@bibentry, %bib_entry,$citelist,$tmpS,$citeall,%stringHash);

####  Make sure $pst_folder is set correctly.
####  This code works in MacOS if the .pst files are in a folder
####  in the same folder as the Perlography Droplet and if that
####  folder is called "pst files". This will not work in UNIX.
####  Just set $pst_folder to a complete path to the desired directory.

$pst_folder=`pwd`;chomp($pst_folder);$pst_folder.=':pst files:';

$citeall=0;
$preambleString="";
foreach $xx (@ARGV) {
  $uu=rindex($xx,':');
  if($uu<0) {$dot_folder=`pwd`;chomp($dot_folder);$dot_folder.=':';}
  else {$dot_folder=substr($xx,0,$uu+1);}
  $dotbibfile="";
  $dotpstfile="";
  $citelist="";
  $tmpS="";
  if($xx=~m/.aux$/) {
    if( open(IN,$xx) ) {
      @lines=;
      close(IN);
      for($ii=0;$ii<=$#lines;$ii++) {
        if($lines[$ii]=~m/\\bibdata/) {
          $dotbibfile=$lines[$ii];chomp($dotbibfile);
          $dotbibfile=~s/^.*\{//;
          $dotbibfile=~s/\}.*$//;
          if($dotbibfile eq "*" ) {
            if( opendir(DIR,':') ){
              @files=readdir(DIR);
              closedir(DIR);chomp(@files);
              foreach $tmpS (@files) {
                if($tmpS=~m/\.bib$/) {push(@dotbibs,$tmpS);}
                }
              }
            }
          else{
            if($dotbibfile!~m/.bib/){$dotbibfile.='.bib';}
            if( -f $dotbibfile) {push( @dotbibs,$dot_folder.$dotbibfile);}
            }
          }
        elsif($lines[$ii]=~m/\\bibstyle/) {
          $dotpstfile=$lines[$ii];chomp($dotpstfile);
          $dotpstfile=~s/^.*\{//;
          $dotpstfile=~s/\}.*$//;
          $dotpstfile=~s/\.bst$/\.pst/; # if it's a .bst make it a .pst
          if($dotpstfile!~m/.pst/){$dotpstfile.='.pst';}
          $dotpstfile=$pst_folder.$dotpstfile;
          }
        elsif($lines[$ii]=~m/\\citation/) {
          $tmpS=$lines[$ii];chomp($tmpS);
          $tmpS=~s/^.*\{//;$tmpS=~s/\}.*$//;
          if( $citeall==0 && $tmpS ne "*"){$citelist.='¥'.$tmpS.'¥';}
          elsif( $tmpS eq "*"){$citeall=1;$citelist="";}
          }
        }
      }
    }
  elsif($xx=~m/.bib$/) {
   $dotbibfile=$xx;
    if(open(IN,$xx) ) {
      push(@dotbibs,$dotbibfile);
      $dotpstfile=;
      close(IN);
      chomp($dotpstfile);
      $dotpstfile=~s/\t//g;
      $dotpstfile=~s/ *//g;
      if($dotpstfile!~m/.pst/){$dotpstfile.='.pst';}
      $dotpstfile=$pst_folder.$dotpstfile;
      }
    }
  if( -f $dotpstfile ) {$AOK=0;}
  else{ print "$dotpstfile not an acceptable pst file.\n";$AOK=1;}
  if($AOK==0) {
    foreach $dotbibfile (@dotbibs) {
      undef(@bibentry);undef(%bib_entry);
      if( -f $dotbibfile ) {&do_one_file($dotbibfile,$dotpstfile,$citelist);}
      else{ print "$dotbibfile not an acceptable data file.\n";}
      $dotpstfile="";
      }
    }
  }
exit(0);


sub do_one_file {
my($file,$dotpstfile,$tag,$citelist,@lines,$data,$entryNumber,$lastentry,$outfile);
$entryNumber=1;
$file=shift(@_);
$dotpstfile=shift(@_);
$citelist=shift(@_);
$data="";
undef(@lines);undef(@bibentry);undef(%bib_entry);
##  Read in routines to do the formating ONCE
{{ package Perlography;
if( -f $dotpstfile) {
  open(IN,$dotpstfile) or die($!);
  @lines=;
  close(IN);
  $xx=join("\n",@lines);
  if(!eval($xx) ) {print $@;}
  }
}}
###
if( open(IN,$file) ) {
  @lines=;
  close(IN);
  chomp(@lines);
  $data=join(' ',@lines);
  $data=~s/[\000-\024]/ /g; # kill low value ASCII's
  $data=~s/\t/ /g;$data=~s/ +/ /g; # kill tabs and double spaces
## escaped braces and double quotes can cause problems so get rid of them for now.
  $data=~s/\\\\/\004/g; # first kill escaped \'s so we really see escaped quotes and braces.
  $data=~s/\\\{/\001/g;
  $data=~s/\\\}/\002/g;
  $data=~s/\\\"/\003/g;
  $xx=index($data,'@');
  while($xx>=0) { # collect the entries 
    $data=substr($data,$xx);
    $yy=close_brace($data);
    $entry=substr($data,0,$yy);
    $data=substr($data,$yy+1);
    &collect_entry($entry,$citelist);
    $xx=index($data,'@',);
    }
  }
undef($entry);
##
## loop through the format subroutines
for($ii=0;$ii<=$#bibentry;$ii++) {
  foreach $xx (keys(%{$bibentry[$ii]})) {
    $subroutine="Perlography::format_".$xx;
    if( defined(&{$subroutine}) ) { &{$subroutine}(\$bibentry[$ii]);}
    }
  }
## compute sort hash
&hash_sort(\@bibentry);
$entryNumber=0;
foreach $xx (sort(keys(%bib_entry))) {
  ${$bib_entry{$xx}}{"read_in"}=$entryNumber++." ".$#bibentry;
  }
## sort the records and output the data.
$outfile=$file;
if( defined(&Perlography::BBL) ){$outfile=&Perlography::BBL($outfile);} else {$outfile=~s/\.bib//;$outfile.='.bbl';}
if( open(OUT,">$outfile") ) {
  if( defined(&Perlography::Prolog) ) {&Perlography::Prolog($file);}
  if( $preambleString ne "" ) {print OUT $preambleString;}
  $lastentry="";
  foreach $xx (sort(keys(%bib_entry))) {
    if( defined(&Perlography::EachEntry) ) {&Perlography::EachEntry($bib_entry{$xx},$bib_entry{$lastentry});}
    $subroutine="Perlography::output_".${$bib_entry{$xx}}{"KOE"};
    if( defined(&{$subroutine}) ) {&{$subroutine}($bib_entry{$xx});}
    $lastentry=$xx;
    }
  if( defined(&Perlography::Epilog) ) {&Perlography::Epilog($file);}
  close(OUT);
   if( defined(&MacPerl::SetFileInfo) ){&MacPerl::SetFileInfo('R*ch','TEXT',$outfile);}
  }
}

sub do_String{
my($entry,$type,$value);
$entry=shift(@_);
if($entry=~m/=/){$type=$`;$value=$';
  $type=~s/^ +//;$type=~s/ +$//;
  $type=uc($type);
  $value=~s/^ +//;$value=~s/ +$//;
  $value=~s/^\{//;$value=~s/^\"//;
  $value=~s/\}$//;$value=~s/\"$//;
  if($type=~m/(\{|\()/) {$type=$';}
  $type=~s/^ +//;$type=~s/ +$//;
  $stringHash{$type}=$value;
  }
}

sub do_Preamble{
my($entry,$zz,$rr,$start,$fld_lngth,$field_type,$comma);
$entry=shift(@_);
if($entry=~m/(\(|\{)/) {
  $entry=$';$entry=~s/^ +//;$entry=~s/ +$//;
  $zz="";$rr=0;
  while($rr>=0) {
    ($start,$fld_lngth,$field_type,$comma)=&next_string($entry,$rr);
    if( $field_type==1 || $field_type==2 ) {
      $zz.=substr($entry,$start,$fld_lngth);
      }
    else {
      $zz.=$stringHash{uc(substr($entry,$start,$fld_lngth))};
      }
    if( substr($entry,$comma,1) eq "#") {$rr=$comma+1;}
    elsif( substr($entry,$comma,1) eq "," || $comma>length($entry) ) {$rr=-1;}
    else{print"Entry ",$this_one{"bib_entry"}," has formatting problems.\n",$entry,"\n";}
    }
  }
$preambleString.=$zz;
}

sub next_string{
my($inputStr,$start,$rr,$field_bdy,$field_type,$bcount,$comma_char);
($inputStr,$start)=@_;
while( (substr($inputStr,$start,1) eq " ") && ($rr<=length($inputStr)) ) {$start++;}
$rr=$start;
if( substr($inputStr,$rr,1) eq "\"" ) {# look for closing "
  $rr++;$start++;
  while( (substr($inputStr,$rr,1)!~m/\"/) && ($rr<=length($inputStr)) ) {$rr++;}
  $field_bdy=$rr; #points to closing quote
  $field_type=1;
  }
elsif( substr($inputStr,$rr,1) eq "\{" ) {# look for closing }
  $rr++;$start++;
  $bcount=1;
  while($bcount>0 && $rr<=length($inputStr) ){
    if(substr($inputStr,$rr,1) eq "{") {$bcount++;}
    elsif(substr($inputStr,$rr,1) eq "}") {$bcount--;}
    $rr++;
    }
  $field_bdy=$rr; # points to closing brace
  $field_type=1;
  }
elsif( substr($inputStr,$rr,1)=~m/[0-9]/ ) {# should be number string to next whitespace or comma
  while( (substr($inputStr,$rr,1)=~m/[0-9]/) && ($rr<=length($inputStr)) ) {$rr++;}
  $field_bdy=$rr; #points to last digit+1
  $field_type=2;
  }
elsif( substr($inputStr,$rr,1)=~m/[A-Za-z]/ ) {# should be @string to next whitespace or comma
  while( (substr($inputStr,$rr,1)!~m/( |,)/) && ($rr<=length($inputStr)) ) {$rr++;}
  $field_bdy=$rr; #points to last character in our string+1
  $field_type=3;
  }
if($field_type==1) {$comma_char=$field_bdy+1;}
elsif($field_type==2) {$comma_char=$field_bdy;}
elsif($field_type==3) {$comma_char=$field_bdy;}
while( substr($inputStr,$comma_char,1) eq " ") {$comma_char++;}
return($start,$field_bdy-$start,$field_type,$comma_char);
}

sub collect_entry{
my($entry,%this_one,$xx,$yy,$zz,$ii,@lines,$field_bdy,$bcount,$rr,$citelist,$comma_char);
my($start,$fld_lngth,$field_type,$comma);
undef(%this_one);
$entry=shift(@_);
$citelist=shift(@_);
if($entry eq "") {return;}
if( $entry=~m/\} *$/) {$entry=$`;}
if($entry eq "") {return;}
$entry=~m/(\{| |\()/;
$this_one{"KOE"}=substr(uc($`),1); # KOE = kind of entry - ARTICLE, BOOK whatever - forced upper case
## if it's an @string process it here and return
if( $this_one{"KOE"} eq "STRING" ) {
  do_String($entry);
  return;
  }
if( $this_one{"KOE"} eq "PREAMBLE" ) {
  do_Preamble($entry);
  return;
  }
$entry=~m/(\{|\()/;$entry=$';$entry=~s/^ +//g;
$entry=~m/,/;
$this_one{"bib_entry"}=$`;
$zz="Perlography::output_".$this_one{"KOE"};
if( !defined(&{$zz}) ) {
  $rr=rindex($dotpstfile,':');
  print "Have an entry type of \"",$this_one{"KOE"},"\" which \"",substr($dotpstfile,$rr+1),"\" is not equipped to handle.\nSkipping ",$this_one{"bib_entry"},".\n\n";
  return;
  }
## $entry is now stuff after first comma.
$entry=$';$entry=~s/^ +//;
while( $entry ne "" ) {
## find the closing comma. There are no escaped braces or escaped quotes
## look for first equal sign
  $rr=index($entry,"=")+1;
  if($rr>0) {
    if( $entry=~m/=/) {
      $type=$`;$type=~s/^ +//g;
      $type=~s/ +$//g;$type=lc($type);
      }
    $zz="";
    while($rr>0) {
      ($start,$fld_lngth,$field_type,$comma)=&next_string($entry,$rr);
      if( $field_type==1 || $field_type==2 ) {
        $zz.=substr($entry,$start,$fld_lngth);
        }
      else {
        $zz.=$stringHash{uc(substr($entry,$start,$fld_lngth))};
        }
      if( substr($entry,$comma,1) eq "#") {$rr=$comma+1;}
      elsif( substr($entry,$comma,1) eq ",") {$rr=-1;}
      else{print"Entry ",$this_one{"bib_entry"}," has formatting problems.\n",$entry,"\n";}
      }
    ## restore escaped braces and double quotes.
    $zz=~s/\001/\\\{/g;
    $zz=~s/\002/\\\}/g;
    $zz=~s/\003/\\\"/g;
    $zz=~s/\004/\\\\/g;
    $this_one{$type}=$zz;
    $entry=substr($entry,$comma+1);
    }
  else{
    $entry="";
    }
  }
$zz='¥'.$this_one{bib_entry}.'¥';
if($citelist eq "" || $citelist=~m/$zz/) {push(@bibentry,\%this_one);}
}


sub close_brace{
my($str,$xx,$ll,$bcount,$fb,$bb);
$str=shift(@_);
if($str!~m/(\{|\()/) {return -1;}
$fb=$1;if($fb eq "{") {$bb="}";} else {$bb=")";}
$xx=index($str,$fb)+1;$bcount=1;
$ll=length($str);
while($bcount>0 && $xx<=$ll ) {
  if( substr($str,$xx,1)  eq $fb  ) {$bcount++;}
  elsif( substr($str,$xx,1)  eq $bb ) {$bcount--;}
  $xx++;
  }
if($xx>$ll) {print"Braces not balanced - no closing brace starting with,\n",$str,"\n";exit;}
return ($xx-1);
}

sub hash_sort {
my($bibentry,$ii,$xx,$key,$kk);
undef($bibentry);undef(%bib_entry);
$bibentry=shift(@_);
if(defined(&Perlography::compute_sort_hash) ) {
  for($ii=0;$ii<=$#$bibentry;$ii++) {
    $key=&Perlography::compute_sort_hash(\${$bibentry}[$ii],$ii);
    if( defined($bib_entry{$key}) ){
      print"\n********************************\n";
      print"Hash key \"$key\" already defined  - clobber the following:\n";
      foreach $xx (keys(%{$$bibentry[$ii]})) { print $xx,"--",${$$bibentry[$ii]}{$xx},"\n";}
      print"\nEnd of clobber for hash key \"$key\".";
      print"\n********************************\n";
      }
    $bib_entry{$key}=$$bibentry[$ii];
    }
  }
else {
  $key=10000;
  for($ii=0;$ii<=$#$bibentry;$ii++) { # no hash - use input order
    $bib_entry{$key}=$$bibentry[$ii];
    $key++;
    }
  }
}

########################################
########################################

sub crack_name{
# count commas 
# 0 = first von last
# 1 = first von last, IX or von last, first
# 2 = von last, Jr., first
my($name,$last,$first,$von,$ii,@words,$fc,$jr,$sc,$jj,$bcount,$jjr);
$name=shift(@_);
$name=~s/^ +//g;$name=~s/ +$//g;
$jj=($name=~s/,/,/g);
$jr="";
if($jj==2) {
  @words=split(',',$name);
  $name=$words[2].' '.$words[0].' '.$words[1];
  $name=~s/ +/ /g;$name=~s/^ +//;$name=~s/ +$//;
  }
elsif($jj==1) {
  @words=split(',',$name);
  $jjr=lc($words[1]);$jjr=~s/(i|v|x|\.| )//g;
  if( $jjr eq "jr" || $jjr eq "" ) {
    $jr=$words[1];
    $name=$words[0];
    $name=~s/ +/ /g;$name=~s/^ +//;$name=~s/ +$//;
    }
  else {
    $name=$words[1].' '.$words[0];
   }
  }
## string now in standard order first von last or first von last, XII
$first="";$last="";$von="";
if($name=~m/,/) {$jr=$`;$name=$';$name=~s/^ +//;$jr=~s/ +$//;}
@words=split(' ',$name);
$first=$words[0];
for($jj=1;$jj<$#words;$jj++) {
  if($words[$jj]=~m/[A-Z]/) {$first.=' '.$words[$jj];} else {last;}
  }
if($jj<$#words) {
  $von=$words[$jj];
  for($jj++;$jj<$#words;$jj++) {
    if($words[$jj]=~m/[a-z]/) {$von.=' '.$words[$jj];} else {last;}
    }
  }
$last=$words[$jj];
for($jj++;$jj<=$#words;$jj++) {
  $last.=' '.$words[$jj];
  }
return($first."\t".$von."\t".$last."\t".$jr);
}

sub string_name_field{
my(@namestrings,$moose,$ii,$bcount,$initialize);
undef(@namestrings);
$xx=shift(@_);$initialize=shift(@_);
###   if the author string has braces in it, hide all spaces and commas occurring inside a brace pair
###   outer brace pair is removed so chunks of the name begin with space-letter (or letter for first)
if($$xx=~m/{/) {
  $bcount=0;
  for($ii=0;$ii<=length($$xx);$ii++) {
    if( substr($$xx,$ii,1)  eq "{" ){
      $bcount++;
      if($bcount=1) {substr($$xx,$ii,1)='';}
      }
    elsif( substr($$xx,$ii,1)  eq "}" ){
      $bcount--;
      if($bcount==0) {substr($$xx,$ii,1)='';}
      }
        ###    hide spaces and commas inside brace pairs
    elsif( (substr($$xx,$ii,1)  eq " ") && $bcount>0 ){ substr($$xx,$ii,1)="\010";}
    elsif( (substr($$xx,$ii,1)  eq ",") && $bcount>0 ){ substr($$xx,$ii,1)="\007";}
    }
  }
@namestrings=split(' and ',$$xx);
$moose="";
for($ii=0;$ii<$#namestrings;$ii++) {
  $moose.=&crack_name($namestrings[$ii])."\t";
  }
$moose.=&crack_name($namestrings[$ii]);
undef(@namestrings);
$moose=~s/\010/ /g;$moose=~s/\007/,/g; ## restore spaces and commas inside brace pairs
@namestrings=split("\t",$moose);
if($initialize eq "Y") {
  for($ii=0;$ii<=$#namestrings;$ii+=4) {
    $namestrings[$ii]=&names_to_initials($namestrings[$ii]);
    }
  }
$$xx=\@namestrings;
}

sub reverse_input_hash{
my($ii);
$ii=shift(@_);
$ii=shift(@_);
return(999999-$ii);
}

sub names_to_initials{
my($first);
  $first=shift(@_);
  $first=~s/[a-z]//g;
  $first.=' ';
  $first=~s/ +/ /g;
  $first=~s/ /\. /g;
  $first=~s/-/\.-/g;
  $first=~s/\.\./\./g;
  $first=~s/ $//;
  $first=~s/\. /\.~/g;
  return($first);
}

sub standard_hash{
my($entry_address,$ii,@names,$key,%entry_hash);
($entry_address,$ii)=@_;
%entry_hash=%{$$entry_address};
@names=@{$entry_hash{"author"}};
$key="";
for($ii=0;$ii<=$#names;$ii+=4) {
  $key.=$names[$ii+2].$names[$ii+1].$names[$ii+3].$names[$ii];
  }
$key.=$entry_hash{"year"}.$entry_hash{"bib_entry"};
return($key);
}