#
# r2b : convert a refer database to a BiBTeX database
# Copyright 1992-1994 by Dana Jacobsen (dana@acm.org)
# 2000-2002 changes and extensions by Frank Roth (roth@gfz-potsdam.de) and
#                                     Hartmut Palm (palm@gfz-potsdam.de)
#
#version = "0.1.1";# 17 Apr 92  jacobsd  Wrote original version
#version = "0.2.0";# 20 Apr 92  jacobsd  Added tib support
#version = "0.3.0";# 21 Apr 92  jacobsd  Rewrote heuristics
#version = "0.4.0";# 22 Apr 92  jacobsd  Revamped the rofftotex stuff
#version = "0.5.2";# 24 Apr 92  jacobsd  some cleanup
#version = "0.6.0";# 25 Apr 92  jacobsd  understands names
#version = "0.6.1";# 26 Apr 92  jacobsd  cleanup
#version = "0.6.2";# 27 Apr 92  jacobsd  added support for a few more fields
#version = "0.6.3";# 27 Apr 92  jacobsd  little more tib support
#version = "0.6.4";# 27 Apr 92  jacobsd  added Roman-8 chars and more options
#version = "0.6.5";# 27 Apr 92  jacobsd  integrated error routine
#version = "0.7.0";#  2 May 92  jacobsd  added groff chars and fixed bugs
#version = "0.7.1";#  2 May 92  jacobsd  fixed a few more things
#version = "0.7.2";# 10 Aug 92  jacobsd  changed key generation
#version = "0.7.3";# 16 Aug 92  jacobsd  added ISBN, 2 overstrikes, -q
#version = "0.7.4";# 19 Aug 92  jacobsd  overstrike, changes for proceedings
#version = "0.7.5";# 20 Aug 92  jacobsd  efficiency moves, month abbrevs
#version = "0.7.6";# 29 Aug 92  jacobsd  added eqn flag
#version = "0.7.7";#  2 Sep 92  jacobsd  changed name, edition, report parsing
#version = "0.8.0";#  4 Sep 92  jacobsd  added date and option field to header
#version = "0.8.1";#  7 Sep 92  jacobsd  added ibm option, corrected ms macros
#version = "0.8.2";#  5 Oct 92  jacobsd  fixed -ms/-mm macro confusion (again)
#version = "0.8.3";#  5 Oct 92  jacobsd  parsedate, edition, movements
#version = "0.8.4";#  8 Oct 92  jacobsd  added \s point size changing
#version = "0.8.5";# 14 May 93  jacobsd  literals, parsename, font changing
#version = "0.9.0";# 20 May 93  jacobsd
#version = "0.9.1";# 20 May 93  jacobsd  revamped refer input section
#version = "0.9.2";# 22 Oct 94  jacobsd  Changed to work with perl 5.000
#version = "0.9.3";# 23 Dec 94  jacobsd  Fixed {} caps problem with Perl 5.
$version = "0.9.4";# 08 Jul 02  roth&palm  added several features/spec.chars.
#
# todo: final debugging for release
#
# All bug-fixes, suggestions, flames, and compliments gladly accepted.
#

# These are site selected.
#
$maxflength = 2950;  # Bibtex doesn't want lines longer than this.
$maxllength = 14;    # maximum length of the text in a label (plus decade)
$prcontents = 0;     # print the contents (%Y) field.

# These are the program defaults that can be changed by command line options.
#
$roffconv   = 1;   # -n          : no roff-to-tex conversion
$ibmconv    = 0;   # -ibm        : convert ibm graphics characters
$nowarnings = 0;   # -q          : don't print warnings
$tibfmt     = 0;   # -tib        : tib bibliography format
$overstrike = 0;   # -overstrike : allow \:o = \(:o.  European troff??
$handleeqn  = 0;   # -eqn        : handle some eqn @@ delimited constructs
$ignorelabel= 0;   # -ignorelabel: don't use L field for citekey
$deroffonly = 0;   # -deroff-only
$protectTeX = 1;   # -noprotect  : don't protect TeX special characters
$nameconv   = 1;   # -noname-conv
$revauthor  = 0;   # -reverse-author
$capprotect = 1;   # -nocap-protect = 0. -cap-protect = 2.
$accedina   = 0;   # -acceditorina = 1: accept editor(s) in %A field(s)
#                                       added in version 0.9.4

$convertcommand = '';
$toterrors = 0;

while (@ARGV) {
  $_ = shift @ARGV;
  $convertcommand .= ' ' . $_;
  /^--$/  && do { push(@files, @ARGV); undef @ARGV; next; };
  /^-n$/  && do { $roffconv = 0;    next; };
  /^-ibm/ && do { $ibmconv = 1;     next; };
  /^-q$/  && do { $nowarnings = 1;  next; };
  /^-qq$/ && do { $nowarnings = 2;  next; };   # this turns off ALL messages
  /^-tib/ && do { $tibfmt = 1;      next; };
  /^-ove/ && do { $overstrike = 1;  next; };
  /^-eqn/ && do { $handleeqn = 1;   next; };
  /^-der/ && do { $deroffonly = 1;  next; };
  /^-non/ && do { $nameconv = 0;    next; };
  /^-rev/ && do { $revauthor = 1;   next; };
  /^-noc/ && do { $capprotect = 0;  next; };
  /^-cap/ && do { $capprotect = 2;  next; };
  /^-ign/ && do { $ignorelabel = 1; next; };
  /^-nop/ && do { $protectTeX = 0;  next; };
  /^-acc/ && do { $accedina = 1;    next; };   # added in version 0.9.4
  push (@files, $_);
}

if ($#files == -1) {
  push (@files, "-");
}

print "%\n";
print "% converted from ", ($tibfmt ? "tib" : "refer");
print " format by refer-to-bibtex $version";
@tarr = localtime(time);
# convert month from numeric to textual
$tarrmon = (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug,
            Sep, Oct, Nov, Dec)[$tarr[4]];
# add a leading 0 if the minute is only 1 digit.
$tarr[1] = '0' . $tarr[1] if length($tarr[1]) == 1;
# print date in format "21:09, 4 Sep 92"
$tarr[5]+=1900;                                 # changed in version 0.9.4
print " -- $tarr[2]:$tarr[1], $tarr[3] $tarrmon $tarr[5]\n";
# print the command line as they entered it, so we know special options
print "% r2b$convertcommand\n";
print "%\n\n";

# These are the accepted refer codes.
#
# let 0 be a valid identifier, but we ignore it.  EndNote Plus puts it
# out as a type identifier, but it's often wrong.  We'll figure it out.
# Organized these in likelihood order and get some speed improvement.
# A: 21%, DT: 11.3%, P: 10%, K: 8.7%, V: 7.1%, J: 6.3%, ICB: 4.0%
%allidents = ('A', ' and ',  'E', ' and ',  'Q', ' and ',
              'X', "\n\n",
              'D', ' ', 'T', ' ', 'P', ' ', 'K', ' ', 'V', ' ',
              'J', ' ', 'I', ' ', 'C', ' ', 'B', ' ', 'N', ' ',
              'S', ' ', 'L', ' ', 'R', ' ', 'O', ' ', '*', ' ',
              'H', ' ', 'G', ' ', 'Y', ' ', 'M', ' ', 'U', ' ',
              'Z', ' ', 'l', ' ', '$',
              '0', ' ',
             );

# These are the fields that are required to be present for each BibTeX
# type.  They will generate a syntax warning if they are not present.
# AE means A or E, BT means B or T.
%reqfields = ('article',       "A:T:J:Yr",
              'book',          "AE:T:I:Yr",
              'incollection',  "A:T:B:I:Yr",
              'inproceedings', "A:T:B:Yr",
              'mastersthesis', "A:T:Sch:Yr",
              'phdthesis',     "A:T:Sch:Yr",
              'proceedings',   "BT:Yr",
              'techreport',    "A:T:Ins:Yr",
              'unpublished',   "A:T:O",
             );


foreach $infile (@files) {
 open (IN, $infile) || ((warn "Can't open $infile: $!\n"), next);
 $linenum    = 0;
 $lastfield  = 0;
 $errors     = 0;

 if ($deroffonly) {
   while (<IN>) {
     $linenum++;
     $_ = &doibmtoroff($_) if $ibmconv;
     $_ = &dorofftotex($_) if $roffconv;
     print $_;
   }
   next;
 }

 while (<IN>) {
  $linenum++;

  if (/^%(.)\s*(.*)$/) {
    $field = $1;
    $rest = $2;
    $lastfield = 0;

    # A '#' as the first character of text is taken to be a comment.
    next if ($rest =~ /^#/);

    # Convert 'o' and 'r' to O.  These are some of tib's translated fields,
    # as well as typos, where they really meant O.
    $field =~ s/[or]/O/;

    #   Abstracts, contents, and comments seem to be non-standard.  I have
    # assumed %X for abstract and %Y for contents.
    #   Refer, tib, and bib seem to have their own styles, and usually
    # people add on fields anyway.  This is reaching the limits of what I
    # can handle even by hand-translating.
    $lastfield = $field;

    # A '%' as the field is taken to be a comment.
    next if ($field eq '%');
    # HEY!  check this:  '\' or '\\' ?
    if ($field eq '\\') {
      print q/@preamble{ "/, substr($_, 1), qq/" }\n/;
      next;
    }

    if (defined $allidents{$field}) {
      $entry{$field} = join($allidents{$field}, $entry{$field}, $rest);
    } else {
      &anerror("Unknown field identifier: $_");
    }
  } else {
    if ( /^\s*$/ ) {
      &doentry() if $lastfield;
      %entry = ();
      $lastfield = '';
    } else {
      chop;
      if ( $lastfield) {
        if ( $lastfield =~ /X|Y/) {
          $entry{$lastfield} .= "\n" . $_;
        } else {
          $entry{$lastfield} .= " " . $_;
        }
      } else {
        print STDERR "line $linenum:";
        print STDERR "Line without field identifier: \n$_\n";
        $errors++;
      }
    }
  }

 }

 if (%entry) {
  &doentry();
 }

 foreach $type (sort keys(%number)) {
  ($nowarnings < 2) && printf STDERR "%5d %s\n", $number{$type}, $type;
  $totalentries += $number{$type};
 }

 if ($nowarnings < 2) {
   print STDERR "$totalentries entries, ";
   $errors == 0 ? print STDERR "no error" : print STDERR "$errors error";
   $errors == 1 ? print STDERR "\n" : print STDERR "s\n";
 }
 $toterrors += $errors;
}

exit $toterrors;




##########################################
#
sub doentry {

# do some processing on each field

  foreach $field (keys(%entry)) {
    $entry{$field} =~ s/^\s+//;
    $entry{$field} =~ s/\s+$//;

    $entry{$field} = &doibmtoroff($entry{$field}) if $ibmconv;
    $entry{$field} = &dorofftotex($entry{$field}) if $roffconv;;

    if (length($entry{$field}) > $maxflength) {
      $entry{$field} = substr($entry{$field}, 0, $maxflength-3);
      $entry{$field} .= "...";
      &anerror("field %$field longer than $maxflength characters.");
    }
    #$entry{$field} =~ s/(^|[^\\])~/$1\\ /g;  # ties (~) to literal space (\ )
  }


# Because the refer format does not have fields set aside for such things
# as edition, ISBN, ISSN, look for them in other fields.  Also, some people
# often put things like pages, techreport, and other information in the
# wrong field.  Once again, look for them and move them to the correct one.

  #   Look for Thesis or Dissertation in O and move to R
  if ($entry{O}) {
    $_ = $entry{O};
    if ( (!$entry{R}) && ( (/thesis/i) || /dissert/i) ) {
      $entry{R} = $entry{O};
      delete $entry{O};
    }
  }

  # Look for "Tech* Rep*" in S and move to R
  if ( ($entry{S} =~ /tech\w*\s+rep\w*/i) && (!$entry{R}) ) {
    $entry{R} = $entry{S};
    delete $entry{S};
  }

  # Look for "* No. *" in V and move to N
  if (($entry{V} =~ /(\d+)\s+(no\.?|numb?e?r?\.?)\s+(\d+)/i) && (!$entry{N})){
    $entry{N} = $3;
    $entry{V} =~ s/(\d+)\s+(no\.?|numb?e?r?\.?)\s+(\d+)/$1/i;
  }

  # Look for "* Edition" in some fields and move to Ed field
  foreach $field (V,S,R,T,O,B) {
    if ($entry{$field} =~ /([\w\d]+)\s+edition/i) {
      $entry{Ed} = $1;
      $entry{$field} =~ s/\s*[-,;(]?\s*([\w\d]+)\s+edition\s*[),;]?\s*//i;
      if ($entry{$field} =~ /^\s*$/) {
        delete $entry{$field};
      }
      last;
    }
  }

  #   Look for ISBN/ISSN # in some fields and move to ISBN/ISSN
  foreach $field (G,O) {
    if ($entry{$field} =~ /IS[BS]N/) {
      $entry{$field} =~ s/\\ /~/g;
      if ($entry{$field} =~ /ISBN\s*:?\s*(\d\S*)/i) {
        $entry{ISBN} = $1;
        $entry{ISBN} =~ s/[;.,]$//g;
        $entry{ISBN} =~ s/~/-/g;
        $entry{$field} =~ s/\s*[,;]?\s*ISBN\s*:?\s*(\d\S*)\s*[,;]?//i;
      }
      if ($entry{$field} =~ /ISSN\s*:?\s*(\d\S*)/i) {
        $entry{ISSN} = $1;
        $entry{ISSN} =~ s/[;.,]$//g;
        $entry{ISSN} =~ s/~/-/g;
        $entry{$field} =~ s/\s*[,;]?\s*ISSN\s*:?\s*(\d\S*)\s*[,;]?//i;
      }
      $entry{$field} =~ s/(^|[^\\])~/$1\\ /g;
    }
  }

  # look for pp or pages in O and move to P
  if ( (!$entry{P}) && ($entry{O} =~ /[XIVxiv]*\+?(\d+)\s*(pp\.?|pages),?/i) ) {
    $entry{P} = $1;
    $entry{O} =~ s/\s*[,;]?\s*[XIVxiv]*\+?(\d+)\s*(pp\.?|pages),?\s*//i;
  }

  # look for date in B if there is no D field
  if ( (!$entry{D}) && ($entry{B}) ) {
    if ($entry{B} =~ /\b(\d\d\d\d)\b/) {
      $entry{D} = $1;
    } elsif ($entry{B} =~ /'(\d\d)\b/) {
      $entry{D} = $1;
    }
  }

  # pick out reptype and repnumber
# undef ($reptype, $repnumber);
  undef $reptype;                                                # new in 0.9.4
  undef $repnumber;                                              # new in 0.9.4
  if ($entry{R}) {
    ($reptype, $repnumber) = $entry{R} =~ /(.+)\s+(\S+)$/;
    if ($repnumber !~ /\d/) {
      $reptype = $entry{R};
      undef $repnumber;
    }

#   As %R fields (as me, F. Roth use them) may contain more than 'report',
#   'thesis' etc., when e.g. a part of the 'US Natl. Rep. to the IUGG' is
#   referenced we extended cap-protection to these fields.
#   type fields:  cap-protect = 0, leave them alone.
#                 cap-protect = 1, protect multi-cap sequences, and singles.
#                                 (default)
#                 cap-protect = 2, protect all capitals.
    if ($capprotect == 1) {                                      # new in 0.9.4
      1 while $reptype =~                                        # new in 0.9.4
              s/([^{\\\w]|^)([A-Z]+)([^\{\}\\\w]|$)/$1\{$2\}$3/g; #new in 0.9.4
      $reptype =~ s/^\{([A-Z])\}/$1/;                            # new in 0.9.4
    } elsif ($capprotect == 2) {                                 # new in 0.9.4
      $reptype =~ s/(\\=[A-Z]+)/{$1}/g;                          # new in 0.9.4
      $reptype =~ s/(\\?[A-Z]+)/{$1}/g;                          # new in 0.9.4
    }                                                            # new in 0.9.4
  }

# titles:  cap-protect = 0, leave them alone.
#          cap-protect = 1, protect multi-cap sequences, and singles. (default)
#          cap-protect = 2, protect all capitals.
  if ($entry{T}) {
    if ($capprotect == 1) {
      1 while $entry{T} =~
               s/([^{\\\w]|^)([A-Z]+)([^\{\}\\\w]|$)/$1\{$2\}$3/g;
      $entry{T} =~ s/^\{([A-Z])\}/$1/;
    } elsif ($capprotect == 2) {
#     $entry{T} =~ s/(\\[A-Z]+)/{$1}/g;                     # off in 0.9.4
      $entry{T} =~ s/(\\=[A-Z]+)/{$1}/g;                    # new in 0.9.4
      $entry{T} =~ s/(\\?[A-Z]+)/{$1}/g;                    # new in 0.9.4
    }
  }

  # set date fields

  &parsedate();

  # convert names to BiBTeX format as best we can
  if ($entry{A}) {
    $entry{Key_A} = &parsename($entry{A}, A);
    $entry{A} = $fname;
    $aeditors = $editors;
    $acauthor = $corpauthors;
  }
  if ($entry{E}) {
    $entry{Key_E} = &parsename($entry{E}, E);
    $entry{E} = $fname;
  } elsif ($aeditors) {
    $entry{E}     = $entry{A};
    $entry{Key_E} = $entry{Key_A};
    delete $entry{Key_A};
    delete $entry{A};
  }
  if ($entry{Q} || $entry{I}) {
    if ($entry{Q}) {
      $entry{Q} =~ s/^and //;
      $entry{Q} =~ s/\s+/ /g;
      ($entry{Key_Q}) = split(/[\s~]/, $entry{Q});
    } else {
      ($entry{Key_I}) = split(/[\s~]/, $entry{I});
    }
    if ($acauthor) {
      ($entry{Key_A}) = split(/[\s~]/, $entry{A});
      $entry{Key_A} =~ s/^{([^}]*)}?.*$/$1/;
    }
  } elsif ($acauthor) {
    $entry{Q}     = $entry{A};
    ($entry{Key_Q}) = split(/[\s~]/, $entry{Q});
    $entry{Key_Q} =~ s/^{([^}]*)}?.*$/$1/;
    delete $entry{Key_A};
    delete $entry{A};
  }

  # set or generate key
  &genkey();

  # determine the Entry Type
  # This is where the heuristics really come into play.  We need to examine
  # what fields we were given, and occasionally the field contents, to
  # determine what type of entry this is.

  if ($entry{J} && !$entry{B}) {
    $type = 'article';
    $_ = $entry{J};
    if (/^proc\w*\.\s/i || /proceeding/i || /proc[.]?\s+of\s/i ||
        /conference/i || /symposium/i || /workshop/i ) {
      $type = 'inproceedings';
      $entry{B} = $entry{J};
      if ($entry{N}) {   # These should be %B Proc, %J Journal, but do anyway.
        # Hope they did "proceedings of ..., published as ..."
        if (/^(.*)published\s+(in|as)\s+(.*)$/i) {
          $entry{B} = $1;
          $entry{J} = $3;
          $entry{B} =~ s/,?\s*$//;
        }
        $entry{O} .= "Published as $entry{J}";
        if ($entry{V}) { $entry{O} .= ", volume $entry{V}"; }
        if ($entry{N}) { $entry{O} .= ", number $entry{N}"; }
        delete $entry{V};
        delete $entry{N};
      }
      delete $entry{J};
    }
  } elsif ($entry{B}) {
    $type = '';
    if ($entry{T}) {
      $type .= 'in';
    }
    $_ = $entry{B};
    if (/^proc\w*\.\s/i || /proceeding/i || /conference/i || /workshop/i) {
      $type .= 'proceedings';
    } else {
      $type .= 'collection';
    }
    if ($entry{J}) {
      $entry{O} .= "Published as $entry{J}";
      if ($entry{V}) { $entry{O} .= ", volume $entry{V}"; }
      if ($entry{N}) { $entry{O} .= ", number $entry{N}"; }
      delete $entry{J};
      delete $entry{V};
      delete $entry{N};
    }
  } elsif ($entry{R}) {
    $type = 'techreport';
    $_ = $reptype;
    s/^{\\[rbi][mft] //g;       # just in case someone changed the font
    tr/A-Za-z//cd;              # only A-z are left
    if (/^phd/i) {
      $type = 'phdthesis';
#     $reptype = "Ph.{D}. Thesis";               # will print as Ph.D. thesis !
      $reptype = "Ph.{D}. {T}hesis";             # T in braces in version 0.9.4
    }
    if (/^diploma/i) {
      $type = 'phdthesis';
#     $reptype = "Diploma Thesis";
      $reptype = "Diploma {T}hesis";             # T in braces in version 0.9.4
    }
    if (/^master/i || /^m[as]thes/i) {
      $type = 'mastersthesis';
#     $reptype = "Master's Thesis";
      $reptype = "Master's {T}hesis";            # T in braces in version 0.9.4
    }
    if (/^phd/i || /^master/i || /^m[as]thes/i || /^diploma/i) {
      if ($entry{R} =~ /thesis/i) {
        ($repnumber) = $entry{R} =~ /thesis\W*(.*)$/i;
      }
      if ($entry{R} =~ /dissert/i) {
        $reptype =~ s/Thesis/Dissertation/;
        ($repnumber) = $entry{R} =~ /dissert\w*\W*(.*)$/i;
      }
    }
    /^draft/i     && ($type = 'unpublished');
    /^unpublish/i && ($type = 'unpublished');

    if (!$entry{N}) {
      $entry{N} = $repnumber;
    }
    $entry{Type} = $reptype;
    undef $reptype;
    undef $repnumber;
    if ( (!$entry{Q}) && ($entry{I}) ) {
      $entry{Q} = $entry{I};
      $iinq = 1;                                                 # new in 0.9.4
      delete $entry{I};
    } else {                                                     # new in 0.9.4
      $entry{Ins} = $entry{I};                                   # new in 0.9.4
    }
  } elsif ($entry{I}) {
    $type = 'book';
  } else {
    $type = 'misc';
  }

  # BibTeX has no collection type, sigh.  We change 'collection' to 'book'.
  if ($type eq 'collection') {
    $type = 'book';
  }

  $number{$type}++;

  if ( ($entry{Q}) && ($entry{A}) && ($iinq == 0) ) {          # added in 0.9.4
    &anerror("%Warning: Corp. author (%Q) and person as author (%A)."); # -"-
    $qina = 1;                                           #             -"-
    if ($lina == 1) {                                    #           -"-
    $entry{A} = $entry{A} . " and {" . $entry{Q} . "}";  # to cover mixed %A %Q
    $lina = 0;                                           #       -"-
    } else {                                             #       -"-
    $entry{A} = "{" . $entry{Q} . "} and " . $entry{A};  # to cover mixed %Q %A
    $linq = 0;                                           #       -"-
    }
  }
  # if we have an institution but no author, the Inst. is the author
  if ( ($entry{Q}) && (!$entry{A}) ) {
    $entry{A} = "{" . $entry{Q} . "}";
  }

  # if there is no address, but a "header" field, assume H stands for "held in"
  if ( ($entry{H}) && (!$entry{C}) ) {
    $entry{C} = $entry{H};
    delete $entry{H};
  }
  # set institution to be the corporate author unless it's Anonymous
  if ($entry{Q} !~ /^anon\.?\w*$/i) {
    if ($qina == 0 && $iinq == 1) {                    # added in version 0.9.4
    $entry{Ins} = $entry{Q};
      $iinq = 0;                                       # added in version 0.9.4
    }                                                  # added in version 0.9.4
    $qina = 0;                                         # added in version 0.9.4
  }
  # if we have a reptype and number, but no "Type" entry, move to other.
  if ($reptype) {
    $entry{O} .= $entry{R};
    delete $entry{R};
  }


  # Change things around for some types
  if ( ($type eq 'mastersthesis') || ($type eq 'phdthesis') ) {
    $entry{Sch} = $entry{Ins};
    delete $entry{Ins};
  } elsif ($type eq 'unpublished') {
    $entry{O} .= $entry{Ins};
    delete $entry{Ins};
  }

  # Check for required fields
  foreach $field ( split(/:/, $reqfields{$type}) ) {
    if ($field eq AE) {
      $entry{A} || $entry{E} ||
                   &anerror("Missing A and E (Author and Editor) fields.");
    } elsif ($field eq BT) {
      $entry{B} || $entry{T} || &anerror("Missing T (Title) field.");
    } else {
      $entry{$field} || &anerror("Missing $field field.");
    }
  }

  # set up the entry output string

  $ent = '';
  $ent .= "\@$type\{$key,\n";

  if ($entry{Key}) { $ent .= "   key = \{$entry{Key}\},\n"; }
  if ($entry{A})   { $ent .= "   author = \{$entry{A}\},\n"; }
  if ($entry{E})   { $ent .= "   editor = \{$entry{E}\},\n"; }
  if ($entry{'T'})   { $ent .= "   title = \{$entry{'T'}\},\n"; }
  if ($entry{B})   {
    if ($entry{T}) {
                     $ent .= "   booktitle = \{$entry{B}\},\n";
    } else {
                     $ent .= "   title = \{$entry{B}\},\n";
    } }
  if ($entry{Ins}) { $ent .= "   institution = \{$entry{Ins}\},\n"; }
  if ($entry{Sch}) { $ent .= "   school = \{$entry{Sch}\},\n"; }
  if ($entry{J})   { $ent .= "   journal = \{$entry{J}\},\n"; }
  if ($entry{Type}){ $ent .= "   type = \{$entry{Type}\},\n"; }
  if ($entry{S})   { $ent .= "   series = \{$entry{S}\},\n"; }
  if ($entry{V})   { $ent .= "   volume = \{$entry{V}\},\n"; }
  if ($entry{N})   { $ent .= "   number = \{$entry{N}\},\n"; }
  if ($entry{Ed})  { $ent .= "   edition = \{$entry{Ed}\},\n"; }
  if ($entry{P})   { $ent .= "   pages = \{$entry{P}\},\n"; }
  if ($entry{I})   { $ent .= "   publisher = \{$entry{I}\},\n"; }
  if ($entry{C})   { $ent .= "   address = \{$entry{C}\},\n"; }
  # since we allow abbrevs for month, don't print {}s
  if ($entry{Mo})  { $ent .= "   month = $entry{Mo},\n"; }
  if ($entry{Yr})  { $ent .= "   year = \{$entry{Yr}\},\n"; }
  if ($entry{'$'}) { $ent .= "   price = \{$entry{'$'}\},\n"; }
  if ($entry{'*'}) { $ent .= "   copyright = \{$entry{'*'}\},\n"; }
# if ($entry{K})   { $ent .= "   keywords = \{$entry{K}\},\n"; }
  if ($entry{K})   { $ent .= "   keywords = \{$entry{K}\},\n"; # added in 0.9.4
                     $extname = ''; }                          #      - " -
  if ($entry{M})   { $ent .= "   mrnumber = \{$entry{M}\},\n"; }
  if ($entry{'l'}) { $ent .= "   language = \{$entry{'l'}\},\n"; }
  if ($entry{U})   { $ent .= "   annote = \{$entry{U}\},\n"; }
  if ($entry{ISBN}){ $ent .= "   ISBN = \{$entry{ISBN}\},\n"; }
  if ($entry{ISSN}){ $ent .= "   ISSN = \{$entry{ISSN}\},\n"; }
  if ($entry{X})   { $ent .= "   abstract = \{$entry{X}\},\n"; }
  if ($entry{G})   { $ent .= "   note = \{$entry{G}\},\n"; }
  if ($entry{H})   { $ent .= "   note = \{$entry{H}\},\n"; }
  if ($entry{O})   { $ent .= "   note = \{$entry{O}\},\n"; }
  if ($entry{Z})   { $ent .= "   note = \{$entry{Z}\},\n"; }
  if ($entry{Y})   { if (!$prcontents) { $entry{Y} = "(not listed)"; }
                     $ent .= "   contents = \{$entry{Y}\},\n"; }

  substr($ent, -2, 1) = '';
  $ent .= "\}\n\n";

  &printerrors();
  print $ent;
}

##########################################
#
# date looks like                   month                dec  year
# --------------------------------  -------------------  --  ---------------
# 1984                                                   84  1984
# 1974-1975                                              74  1974-1975
# August 1984                       aug                  84  1984
# May 1984 May 1984                 may                  84  1984
# 1976 November                     nov                  76  1976
# 1976 November 1976                nov                  76  1976
# 21 August 1984                    {21 August}          84  1984
# August 18-21, 1984                {August 18-21}       84  1984
# 18-21 August 1991                 {18-21 August}       91  1991
# July 31-August 4, 1984 1984       {July 31-August 4}   84  1984
# July-August 1980                  {July-August}        80  1980
# February 1984 (revised May 1991)  feb                  84  1984
# Winter 1990                       {Winter}             90  1990
# 1988 (in press)                                        88  1988 (in press)
# to appear                                              ??  to appear
#
sub parsedate {
  local($date) = $entry{D};

# These were done earlier for each field
#  $date =~ s/^\s+//;
#  $date =~ s/\s+$//;
  $date =~ s/(\S+)\s+(\d+)\s+\1\s+\2/$1 $2/;   # handle duplicate dates
  $date =~ s/^\s*(\d\d\d+)\s+(\S+)/$2 $1/;     # handle 1976 November
  while ($date =~ /\s*[(]?((\d\d\d\d[-\/])?\d\d\d\d)[).]?\s*(\(.*\))?$/) {
    $entry{Yr} = $1;
    $date =~ s/,?\s*[(]?(\d\d\d\d[-\/])?\d\d\d\d[).]?\s*(\(.*\))?$//;
  }
#  $entry{YrKey} = $entry{Yr} ? $entry{Yr} : "????";
  if ($entry{Yr}) {
    $entry{YrKey} = $entry{Yr};
  } elsif ($date =~ /(\d\d\d\d)/) {
    $entry{YrKey} = $1;
  } else {
    $entry{YrKey} = "????";
  }
  $entry{Decade} = substr($entry{YrKey}, 2, 2);
  return unless length($date);

  $_ = $date;
  if (!/[-\d]/) {
    /^jan/i && do { $entry{Mo} = "jan"; };
    /^feb/i && do { $entry{Mo} = "feb"; };
    /^mar/i && do { $entry{Mo} = "mar"; };
    /^apr/i && do { $entry{Mo} = "apr"; };
    /^may/i && do { $entry{Mo} = "may"; };
    /^jun/i && do { $entry{Mo} = "jun"; };
    /^jul/i && do { $entry{Mo} = "jul"; };
    /^aug/i && do { $entry{Mo} = "aug"; };
    /^sep/i && do { $entry{Mo} = "sep"; };
    /^oct/i && do { $entry{Mo} = "oct"; };
    /^nov/i && do { $entry{Mo} = "nov"; };
    /^dec/i && do { $entry{Mo} = "dec"; };
  }

  if (!$entry{Mo}) {
    if (!$entry{Yr}) {
      $entry{Yr} = $entry{D};
    }
    else {
      $entry{Mo} = '{' . $date . '}';
    }
  }
  $entry{Decade} = substr($entry{YrKey}, 2, 2);
}

##########################################
# key is Author's last name followed by last 2 digits of year.
# in corporate author's case, key is first word and first 2 digits.
# order is L, A, Q, E, I, "Anonymous"
# In case of conflict, ascending letters are added to the end
# Perl knows that "z"+1 == "aa" and "az"+1 == "ba".  Uskomatonta!
#
# BiBTeX's cite keys are case-INsensitive.  We want to keep the
# pretty looking capitalization though, so we modify key and lkey.
# We now check Label fields for duplicate keys
sub genkey {
  local($noadd) = @_;
  local($name, $lenkey);
  local($keysav);                                      # added in version 0.9.4

  if ($entry{L} && (!$ignorelabel) ) {
    $key = $entry{L};
  } else {
    $name = $entry{Key_A} || $entry{Key_Q} || $entry{Key_E}
            || $entry{Key_I} || $noadd || "Anonymous";

    $name = substr($name,0,$maxllength);
    $key = $name . $entry{Decade};
  }

  $key =~ s/,//g;
      $keysav=$key;                                    # added in version 0.9.4
      $key =~ s/\\ae/ae/g;                             # added in version 0.9.4
      $key =~ s/\\AE/Ae/g;                             # added in version 0.9.4
      $key =~ s/\\oe/oe/g;                             # added in version 0.9.4
      $key =~ s/\\OE/Oe/g;                             # added in version 0.9.4
      $key =~ s/\\[acduv]//g;                          # added in version 0.9.4
      $key =~ s/\\ecr\\symbol\{157\}/I/g;              # added in version 0.9.4
      $key =~ s/\\ecr\\symbol\{208\}/D/g;              # added in version 0.9.4
      $key =~ s/\\ecr\\symbol\{240\}/d/g;              # added in version 0.9.4
      $key =~ s/\\ecr\\symbol\{222\}/Th/g;             # added in version 0.9.4
      $key =~ s/\\ecr\\symbol\{254\}/th/g;             # added in version 0.9.4
      $key =~ s/\\"([AOUaou])/$1e/g;                   # added in version 0.9.4
      $key =~ s/[\s\{\}]//g;                           # added in version 0.9.4
      $key =~ tr/A-Za-z0-9\/\-//cd;                    # added in version 0.9.4
      if ($key ne $keysav) {$extname = ' ' . $key;}    # added in version 0.9.4
  $lenkey = length($key);
  $lkey = $key;
  $lkey =~ tr/A-Z/a-z/;         # citekeys are case-insensitive

  if ($allkeys{$lkey}) {
    $key .= 'a';
    $lkey = $key;
    $lkey =~ tr/A-Z/a-z/;
    while ($allkeys{$lkey}) {
      substr($key,$lenkey)++;   # increment all chars past Decade
      $lkey = $key;
      $lkey =~ tr/A-Z/a-z/;
    }
  }

  if (!$noadd) {
    $allkeys{$lkey} = $key;
    if ($name eq "Anonymous") {
      $entry{Key} = $key;
    }
  }
  $key;
}


##########################################
# parsename parses names into BiBTeX format
#
# This uses heuristics to parse a name into First, von, Last, and Jr
# parts.  It handles multiple names (John doe, jane doe) on a line.
# It does not handle names in "last, first" format.
# it returns a key (last name of author or editor, first name of corp).
# It sets $fname to the full bibtex name.
# It sets $editors or $corpauthors if it thinks the name is one.
#
sub parsename {
  local($allnames, $ntype) = @_;
  local($firstn, $vonn, $lastn, $jrn);
  local(@names, $keyn, $oname, $nname, $rest);

  $editors = $corpauthors = "";

  # handle unpaddable spaces (\ ) in names as if they were ties (\0)
  $allnames =~ s/\\ /~/g;     # the ties (~) get converted back later.
  $allnames =~ s/\s+/ /g;
  $allnames =~ s/^and //;
  $allnames =~ s/^and$//;

  if ( ($allnames !~ /\s/) && ($allnames !~ /anonymous/i) ){
    $corpauthors = 1;
  }
  @names = split(/ and /, $allnames);
  if (!$nameconv) {
    $fname = $allnames;
    $_ = shift @names;
    # if we're leaving names alone, they're probably already in "Last, First"
    # format, so use the first part of the name as the key.
    ($name) = /^\s*(\S*)/;
    #  ($name) = /(\S*)\s*$/;
    $name =~ tr/A-Za-z0-9\/\-//cd;
    return $name;
  }
  $fname = "";
  while (@names) {
    $oname = $name = shift @names;
    $firstn = $vonn = $lastn = '';

    if ( $revauthor && ($ntype eq A) && ($name =~ /,/) ) {
      $jrn = "";
      if ($name =~ s/[,\s]+([sj]r\.?|I+)\s*$//i) {
        $jrn = ", " . $1;
      }
      $name =~ s/^(.*)\s*,\s*(.*)/$2 $1$jrn/g;
    }
    $jrn = "";

#   $name =~ s/[\s~]+([sj]r\.?|\(?edi?t?o?r?s?\.?\)?|I+)(,|$)/, $1/i;
    $name =~ s/[\s~]+([sj]r\.?|\(?edi?t?o?r?s?\.?\)?|\(?he?ra?u?sge?b?e?r?\.?\)|I+)(,|$)/, $1/i;                                    # extended in version 0.9.4
    $name =~ s/,,/,/g;
    ($nname, $jrn) = split(/,[^~]/, $name, 2);
#    print "name: $name  -> $nname : $jrn\n";
    $nname =~ s/\s+$//;
    $jrn =~ s/^[\s~]+//;
    $jrn =~ s/,$//;
    if ($jrn =~ /\s/) {
#     ($jrn, $rest) = $jrn =~ /([sj]r\.?|\(?edi?t?o?r?s?\.?\)?|I+)?,?\s*(.*)$/i;
      ($jrn, $rest) = $jrn =~ /([sj]r\.?|\(?edi?t?o?r?s?\.?\)?|\(?he?ra?u?sge?b?e?r?\.?\)|I+)?,?\s*(.*)$/i;                         # extended in version 0.9.4
      unshift(@names, $rest);
    }
    $jrn =~ s/([^\\])~/$1 /g;
    ($firstn) = $nname =~ /^((\S* )*)/;
    $nname = substr($nname, length($firstn));
    $lastn = $nname;
    $lastn =~ s/([^\\])~/$1 /g;
    $firstn =~ s/([^\\])~/$1 /g;
    while ($firstn =~ / ([a-z]+ )$/) {
      $rest = $1;
      $vonn = $rest . $vonn;
      $firstn = substr($firstn, 0, length($firstn) - length($rest));
    }
    while ($lastn =~ /^([a-z]+ )/) {
      $rest = $1;
      $vonn .= $rest;
      $lastn = substr($lastn, length($rest));
    }

    if ($jrn) {
      if ($jrn =~ /^(et\.?\s*al\.?)|(others)$/i) {
        undef $jrn;
        unshift(@names, "others");
      }
#     BibTeX suppresses Editors in the output, if the publication type is an
#     'article' or 'techreport'. This does not always fit. Therefore the
#     following was added in version 0.9.4:
      if (!$accedina || (!$entry{J}) && (!$entry{R}) ) {
        if ($jrn =~ /^[(]?edi?t?o?r?s?[\.]?[)]?$/i) {
          undef $jrn;
          $editors = 1;
        }
        if ($jrn =~ /^[(]?he?ra?u?sge?b?e?r?[\.]?[)]?$/i) { # added in 0.9.4
          $editors = 1;                                     #  - " -
        }                                                   #  - " -
      }                                                     #  - " -
      if ($jrn =~ /^inc[\.]?$/i) {
        $lastn .= ", " . $jrn;
        undef $jrn;
        $corpauthors = 1;
      }
    }
    if ($lastn =~ /^(et\s*al)|(others)$/i) {
      $lastn = "others";
    }
    if ($lastn =~ /\s/) {
      $lastn = "{" . $lastn . "}";
    }

    if (!$keyn) {
      if ($corpauthors) {
        ($keyn) = $lastn =~ /^(\S+)/;
      } else {
        ($keyn) = $lastn;       # =~ /(\S+)$/;  # if you want last of Last
      }
    }

    if ($jrn) {
      $fname .= " and " . $vonn . $lastn . ", " . $jrn . ", " . $firstn;
    } else {
      $fname .= " and " . $firstn . $vonn . $lastn;
    }
  }
  $fname =~ s/^ and\s+//;
  $fname =~ s/\s+$//;
  $fname =~ s/\s+/ /g;
  if ($ntype eq A) {
    if ($corpauthors) {
      &anerror("Corporate Author (%Q) in %A.");
    } elsif ($editors) {
      &anerror("Editors (%E) in %A.");
    }
  } elsif ($ntype eq Q) {
    if ($editors) {
      &anerror("Editors (%E) in %Q.");
    }
  } elsif ($ntype eq E) {
    if ($corpauthors && (!$entry{A})) {
      &anerror("Corporate Author (%Q) in %E.");
    }
  }
  $keyn;
}




##########################################
# stores error information until it gets printed
#
# This allows us to fully process the entry so we can print out
# valid key information without having to go through ugly gyrations.
#
sub anerror {
  local($err) = @_;

  push(@errorstring, $err);
  $errors++;
}



##########################################
# prints out stored error information
#
sub printerrors {
  local($klen, $errst);

  if (@errorstring && (!$nowarnings)) {
    $klen = $maxllength;  # a little short, but most labels aren't this long
    foreach $_ (@errorstring) {
      $errst .= sprintf("%-${klen}s (%5d): %s\n", $key, $errline, $_);
    }
    print STDERR $errst;
  }
  undef @errorstring;
  $errline = $linenum+1;
}



##########################################
# converts *roff characters to TeX characters
#
# If anyone has any corrections or additions, I'd be happy to see them.
#
# Is there a better way to do this?  (i.e. eval)
#
sub dorofftotex {
  local($_) = @_;
  local($fbraces, $nchanges);

  study;                        # presumably this will help us.

  # tib: refer format, TeX formatting.
  #      This should probably be set up to read a configuration file into
  #      a variable then use eval.  If there is such a beast as a "detibify"
  #      program, then this won't be necessary.
  if ($tibfmt) {
    1 while s#\\egroup(.*)\\bgroup#{\\Reffont $1}#g;
    s/\\Citefont//g;
    s/\\ACitefont//g;
    s/\\Authfont//g;
    s/\\Titlefont//g;
    s/\\Tomefont/\\sl/g;
    s/\\Volfont//g;
    s/\\Flagfont//g;
    s/\\Reffont/\\rm/g;
    s/\\Smallcapsfont/\\sevenrm/g;
    s/\\Flagstyle//g;            # This should be smarter

    if (/\|/) {
      s/\|JAN\|/January/g;       # yes, the parsedate routine can handle
      s/\|FEB\|/February/g;      # these most of the time, but sometimes
      s/\|MAR\|/March/g;         # they're put in the middle of non-date
      s/\|APR\|/April/g;         # strings, so we'd better convert them.
      s/\|MAY\|/May/g;
      s/\|JUN\|/June/g;
      s/\|JUL\|/July/g;
      s/\|AUG\|/August/g;
      s/\|SEP\|/September/g;
      s/\|OCT\|/October/g;
      s/\|NOV\|/November/g;
      s/\|DEC\|/December/g;

      # My example of tib format is AGbib from INRIA, so this is set up to
      # handle the common cases for that bibliography.

      s/\|UNIV\|/University/g;
      s/\|DEPT\|/Department/g;
      s/\|DCS\|/Department of Computer Science/g;
      s/\|PCS\|/Progr. and Computer Science/g;
      s/\|CSD\|/Computer Science Department/g;
      s/\|TR\|/Technical Report/g;

      s/\|COMPJ\|/The Computer Journal/g;
      s/\|JACM\|/Journal of the ACM/g;
      s/\|CACM\|/Communications of the ACM/g;
      s/\|SGPLN\|/Sigplan Notices/g;
      s/\|SIAJC1\|/SIAM Journal on Computing/g;
      s/\|ACTAI2\|/Acta Informatica/g;
      s/\|IEETS1\|/IEEE Transactions on Software Engineering/g;
      s/\|INFPL2\|/Information Processing Letters/g;
      if (s/\|LNCS\|/Lecture Notes in Computer Science/g) {
        $entry{I} .= " " . "Springer-Verlag";
        $entry{C} .= " " . "New York--Heidelberg--Berlin"; }
      if (s/\|IFBSV\|/Inf. Fachb./g) {
        $entry{I} .= " " . "Springer-Verlag";
        $entry{C} .= " " . "New York--Heidelberg--Berlin"; }
      s/\|SCICP\|/Science of Computer Programming/g;
      s/\|SP&E\|/Software---Practice and Experience/g;
      s/\|POPL\|/ACM Symp. on Principles of Progr. Languages/g;
      s/\|TOPLAS\|/ACM Trans. Progr. Languages and Systems/g;

      if (s/\|Addison\|/Addison Wesley/g) {
        $entry{C} .= " " . "Reading, MA"; }
      if (s/\|PrHall\|/Prentice Hall/g) {
        $entry{C} .= " " . "Englewood Cliffs, NJ"; }
      if (s/\|NHoll\|/North-Holland/g) {
        $entry{C} .= " " . "Amsterdam"; }
      if (s/\|Cambridge\|/Cambridge University Press/g) {
        $entry{C} .= " " . "New York"; }
      if (s/\|Springer\|/Springer-Verlag/g) {
        $entry{C} .= " " . "New York--Heidelberg--Berlin"; }

      s/\|TWEINF\|/Onderafdeling der Informatica, Tech. Hogeschool Twente/g;
      s/\|TUMINF\|/Institut f{\"u}r Informatik, Tech. University M{\"u}nchen/g;
      s/\|HELDCS\|/Department of Computer Science, University of Helsinki/g;
      if (s/\|IBMTJW\|/IBM T.J. Watson Research Center/g) {
        $entry{C} .= " " . "Yorktown Heights, NY"; }
      if (s/\|INRIA\|/INRIA/g) {
        $entry{C} .= " " . "Rocquencourt"; }
      if (s/\|IRIAL\|/IRIA-Laboria/g) {
        $entry{C} .= " " . "Rocquencourt"; }
      $entry{C} =~ s/^\s+//;
      $entry{I} =~ s/^\s+//;
    }
    return $_;
  }

  s#_#_U#g;   # _ will be the escape character

  # don't do troff character conversion if there aren't any backslashes
  # in the string.  Hopefully this will save a little work.
  if (/\\/) {

    # to make commands, we need command characters, but we don't want
    # any of the command characters that they use to be passed through
    # or we'll end up with invalid input.  So, _ is the escape character.

    # _U is _
    # _B is a backslash
    # _I is a literal backslash
    # _S is a space
    # _C is {\
    # _L is {
    # _R is }
    # _l is <
    # _g is >
    # _T is ~
    # _A is ^
    # _D is $
    # _M is $\
    # _V is |
    # _E is ${}^
    # _H is \hbox{
    # _h is \leavevmode
    # _c is a special continuation character for long lines

    # I'm not sure I quite get this -- refer strips off one \ for most
    # characters it seems.  But other times it doesn't.  Argh!  I'll
    # go ahead and replace \\ with \ to handle this.  It shouldn't ever
    # come up that this is bad since \e and \(rs are a real backslashes.

    s#\\\\#\\#g;                             #  \\    -> \

    # font changes
    # if one uses \fP, everything is fine -- otherwise we need to get complex
    $fbraces = 0;
    $fbraces += s#\\f[1R]#_Crm_S#g;          #  \f1   -> {\rm
    $fbraces += s#\\f[2I]#_Cit_S#g;          #  \f2   -> {\it
    $fbraces += s#\\f[3B]#_Cbf_S#g;          #  \f3   -> {\bf
    $fbraces -= s#\\fP#_R#g;                 #  \fP   -> }
    while ($fbraces) {                       # too many {'s
      if ($fbraces < 0) {
        $nchanges = s#_R##;
        &anerror("Used \\fP with no previous font.");
        $fbraces += $nchanges;
      } else {    # Changed newline matching because 4.019 had problems
#        $nchanges = s#(_Cit_S)([\s\S]*)_Crm_S#$1$2_R#;
        $nchanges = s#(_Cit_S)((.|\n)*)_Crm_S#$1$2_R#;
        if (!$nchanges)
          { $nchanges = s#(_Cbf_S)([\s\S]*)_Crm_S#$1$2_R#; }
        if (!$nchanges)
          { $nchanges = s#(_C\w\w_S)([\s\S]*)_C\w\w_S#$1$2_R#; }
        if (!$nchanges) {
          $_ .= "_R";                        # couldn't get it, so stick a } on
          $fbraces--;
          &anerror("Problems with font changing.  Suggest using \\fP.");
        }
        $fbraces -= ($nchanges * 2);
      }
    }

    # point size changes
    # first,  U\s-2NIX\s0   ->   {\sc Unix}
    s/\b([A-Z])\\s-[12]([A-Z]+)\\s0/_Csc_S$1\L$2\E_R/g;
    # very similar to font changes.  If \s0 is used, everything is fine.
    $fbraces = 0;
    $fbraces += s#\\s-1#_Csmall_S#g;          #  \s-1   -> {\small
    $fbraces += s#\\s-2#_Cfootnotesize_S#g;   #  \s-2   -> {\footnotesize
    $fbraces += s#\\s-3#_Cscriptsize_S#g;     #  \s-3   -> {\scriptsize
    $fbraces += s#\\s-4#_Ctiny_S#g;           #  \s-4   -> {\tiny
    $fbraces += s#\\s+1#_Clarge_S#g;          #  \s+1   -> {\large
    $fbraces += s#\\s+2#_CLarge_S#g;          #  \s+2   -> {\Large
    $fbraces += s#\\s+3#_CLARGE_S#g;          #  \s+3   -> {\LARGE
    $fbraces += s#\\s+4#_Chuge_S#g;           #  \s+4   -> {\huge
    $fbraces -= s#\\s0#_R#g;                  #  \s0    -> }
    while ($fbraces) {                        # too many {'s
      if ($fbraces < 0) {
        $nchanges = s#_R##;
        &anerror("Used \\s0 with no previous point size change.");
        $fbraces += $nchanges;
      } else {
        $nchanges = s#(_Csmall_S)(.*)_Clarge_S#$1$2_R#;
        if (!$nchanges)
          { $nchanges = s#(_Cfootnotesize_S)(.*)_CLarge_S#$1$2_R#; }
        if (!$nchanges)
          { $nchanges = s#(_Cscriptsize_S)(.*)_CLARGE_S#$1$2_R#; }
        if (!$nchanges)
          { $nchanges = s#(_Clarge_S)(.*)_Csmall_S#$1$2_R#; }
        if (!$nchanges)
          { $nchanges = s#(_CLarge_S)(.*)_Cfootnotesize_S#$1$2_R#; }
        if (!$nchanges)
          { $nchanges = s#(_CLARGE_S)(.*)_Cscriptsize_S#$1$2_R#; }
        if (!$nchanges) {
          $_ .= "_R";                         # last resort.  Add an }.
          $fbraces--;
          &anerror("Problems with point size changing.  Suggest using \\s0.");
        }
        $fbraces -= ($nchanges * 2);
      }
    }


    # other troff special characters
    # some of these aren't available as standard TeX, so I made up replacements.
    # Perhaps they should be def'ed in a preamble and used that way, but I
    # doubt most files use \(rg, \(ct, and such, so why waste resources.
    # If you're really concerned about eth, thorn, yogh, or ogonek, go get
    # the cmoer fonts -- they do the characters right.

    # grab some common overstrikes made by people who don't have a real
    # troff manual or implementation.

    s#\\o'(\w)\\\(aa'#_C'$1_R#g;             # \o'e\(aa'  -> {\'e}
    s#\\o'(\w)\\\(ga'#_C`$1_R#g;             # \o'e\(ga'  -> {\`e}

    # Lots of bibliographies from Europe use \:o to mean \(o:, etc.  Both
    # Elan troff and groff don't know what this means, so I don't do the
    # conversion by default.  Use '-overstrike' to get this behaviour.

    if ($overstrike) {
      s#\\([:`'^~,v/o])([AEIOUYaeiouyNnCcSs])#\\\($2$1#g;
    }

    s#\\\(bu#_Mbullet_D#g;                   # \(bu  -> $\bullet$
    s#\\\(ci#_Mbigcirc_D#g;                  # \(ci  -> $\bigcirc$
    s#\\\(sq#_MBox_D#g;                      # \(sq  -> $\Box$
    s#\\\(ct#_h_Brm_Brlap/c_R#g;             # \(ct  -> \hbox{\rm\rlap/c}
    s#\\\(rg#_h_Braise.6em_H_Booalign_L_L_Bmathhexbox20D_R_Bcrcr\n_Bhfil_Braise.07ex_Hr_R_Bhfil_R_R_R#g;
    s#\\\(co#_h_Braise.6em_H_Bcopyright_R_R#g;
    s#\\\(lh#_MLongleftarrow_D#g;            # \(lh  -> $\Longleftarrow$ #wrong!
    s#\\\(rh#_MLongrightarrow_D#g;           # \(rh  -> $\Longrightarrow$
    s#\\\(dg#_Bdag #g;                       # \(dg  -> \dag
    s#\\\(dd#_Bddag #g;                      # \(dd  -> \ddag
    s#\\\(sc#_BS #g;                         # \(sc  -> \S
    s#\\\(br#_D_V_D#g;                       # \(br  -> $|$
    s#\\\(fm#_E_Bprime_D#g;                  # \(fm  -> ${}^\prime$
    s#\\\(de#_E_Bcirc_D#g;                   # \(de  -> ${}^\circ$
    s#\\\(em#--#g;                           # \(em  -> --
    s#\\\(hy#-#g;                            # \(hy  -> -
    s#\\\(ru#_Cvrule width1.2ex height0.1ex depth0ex_R#g;
    s#\\\(ul#_Cvrule width1.2ex height-.3ex depth.4ex_R#g;
    s#\\\-#---#g;                            # \-    -> --
    s#\\\(aa#_C'_L _R_R#g;                   # \(aa  -> {\'{ }}
    s#\\'#_C'_L _R_R#g;                      # \'    -> {\'{ }}
    s#\\\(ga#_C`_L _R_R#g;                   # \(ga  -> {\`{ }}
    s#\\`#_C`_L _R_R#g;                      # \`    -> {\`{ }}
    s#\\\(sl#/#g;                            # \(sl  -> /
    s#\\e#_I#g;                              # \e    -> $\backslash$
    s#\\0#_T#g;                              # \0    -> ~
    s#\\ #_B #g;                             # '\ '  -> '\ '
    s#\\\^#_D_B,_D#g;                        # \^    -> $\,$
    s#\\\|#_D_B:_D#g;                        # \|    -> $\:$
    s#\\\(fi#fi#g;                           # \(fi  -> fi
    s#\\\(fl#fl#g;                           # \(fl  -> fl
    s#\\\(ff#ff#g;                           # \(ff  -> ff
    s#\\\(Fi#ffi#g;                          # \(Fi  -> ffi
    s#\\\(Fl#ffl#g;                          # \(Fl  -> ffl

    s#\\\(pl#_D+_D#g;                        # \(pl  -> $+$
    s#\\\(mi#_D-_D#g;                        # \(mi  -> $-$
    s#\\\(mu#_Mtimes_D#g;                    # \(mu  -> $\times$
    s#\\\(di#_Mdiv_D#g;                      # \(di  -> $\div$
    s#\\\(\+\-#_Mpm_D#g;                     # \(+-  -> $\pm$
    s#\\\(no#_Mneg_D#g;                      # \(no  -> $\neg$
    s#\\\(\*\*#_Mast_D#g;                    # \(**  -> $\ast$
    s#\\\(eq#_D=_D#g;                        # \(eq  -> $=$
    s#\\\(>=#_Mgeq_D#g;                      # \(>=  -> $\geq$
    s#\\\(<=#_Mleq_D#g;                      # \(<=  -> $\leq$
    s#\\\(==#_Mequiv_D#g;                    # \(==  -> $\equiv$
    s#\\\(~=#_Msimeq_D#g;                    # \(~=  -> $\simeq$
    s#\\\(ap#_Msim_D#g;                      # \(ap  -> $\sim$
    s#\\\(!e#_Mneq_D#g;                      # \(!e  -> $\neq$
    s#\\\(\->#_Mrightarrow_D#g;              # \(->  -> $\rightarrow$
    s#\\\(<\-#_Mleftarrow_D#g;               # \(<-  -> $\leftarrow$
    s#\\\(ua#_Muparrow_D#g;                  # \(ua  -> $\uparrow$
    s#\\\(da#_Mdownarrow_D#g;                # \(da  -> $\downarrow$
    s#\\\(cu#_Mcup_D#g;                      # \(cu  -> $\cup$
    s#\\\(ca#_Mcap_D#g;                      # \(ca  -> $\cap$
    s#\\\(sb#_Msubset_D#g;                   # \(sb  -> $\subset$
    s#\\\(sp#_Msupset_D#g;                   # \(sp  -> $\supset$
    s#\\\(ib#_Msubseteq_D#g;                 # \(ib  -> $\subseteq$
    s#\\\(ip#_Msupseteq_D#g;                 # \(ip  -> $\supseteq$
    s#\\\(if#_Minfty_D#g;                    # \(if  -> $\infty$
    s#\\\(es#_Memptyset_D#g;                 # \(es  -> $\emptyset$
    s#\\\(is#_Mint_D#g;                      # \(is  -> $\int$
    s#\\\(pd#_Mpartial_D#g;                  # \(pd  -> $\partial$
    s#\\\(sr#_Msurd_D#g;                     # \(sr  -> $\surd$
    s#\\\(gr#_Mnabla_D#g;                    # \(gr  -> $\nabla$
    s#\\\(pt#_Mpropto_D#g;                   # \(pt  -> $\propto$
    s#\\\(mo#_Min_D#g;                       # \(mo  -> $\in$
    s#\\\(or#_Mmid_D#g;                      # \(or  -> $\mid$
    s#\\\((\d)(\d)#_D$1_Bover$2_D#g;         # \(14  -> $1\over4$

    s#\\\(m\.#_Mcdot_D#g;                    # \(m.  -> $\cdot$
    s#\\\(!s#_Mnot_Bsubset_D#g;              # \(!s  -> $\not\subset$
    s#\\\(an#_Mwedge_D#g;                    # \(an  -> $\wedge$
    s#\\\(lo#_Mvee_D#g;                      # \(lo  -> $\vee$
    s#\\\(tf#_D_H._R_Braise.9ex_H._R_H._R_D#g;# \(tf -> .:.
    s#\\\(cm#_Mni_D#g;                       # \(cm  -> $\ni$
    s#\\\(fa#_Mforall_D#g;                   # \(fa  -> $\forall$
    s#\\\(te#_Mexists_D#g;                   # \(te  -> $\exists$
    s#\\\(!m#_Mnotin_D#g;                    # \(!m  -> $\notin$
    s#\\\(a\+#_Moplus_D#g;                   # \(a+  -> $\oplus$
    s#\\\(ax#_Motimes_D#g;                   # \(ax  -> $\otimes$
    s#\\\(ag#_Mangle_D#g;                    # \(ag  -> $\angle$
    s#\\\(rn#_Moverline_L _R_D#g;            # \(rn  -> $\overline{ }$
    s#\\\(<<#_Mll_D#g;                       # \(<<  -> $\ll$
    s#\\\(>>#_Mgg_D#g;                       # \(>>  -> $\gg$
    s#\\\(<>#_Mleftrightarrow_D#g;           # \(<>  -> $\leftrightarrow$
    s#\\\(//#_D/_D#g;                        # \(//  -> $/$
    s#\\\(L<#_Mlangle_D#g;                   # \(L<  -> $\langle$
    s#\\\(R>#_Mrangle_D#g;                   # \(R>  -> $\rangle$
    s#\\\(dm#_Mdiamond_D#g;                  # \(dm  -> $\diamond$
    s#\\\(lt#_Mlbrace_D#g;                   # \(lt  -> $\lbrace$
    s#\\\(rt#_Mrbrace_D#g;                   # \(rt  -> $\rbrace$
    s#\\\(lb#_Mlfloor_D#g;                   # \(lb  -> $\lfloor$
    s#\\\(rt#_Mrfloor_D#g;                   # \(rt  -> $\rfloor$
    s#\\\(lk#_Mlbrace_D#g;                   # \(lk  -> $\lbrace$
    s#\\\(rk#_Mrbrace_D#g;                   # \(rk  -> $\rbrace$
    s#\\\(lf#_Mlfloor_D#g;                   # \(lf  -> $\lfloor$
    s#\\\(rf#_Mrfloor_D#g;                   # \(rf  -> $\rfloor$
    s#\\\(lc#_Mlceil_D#g;                    # \(lc  -> $\lceil$
    s#\\\(rc#_Mrceil_D#g;                    # \(rc  -> $\rceil$

    s#\\\(bv#_Cmbox_Cboldmath_Mmid_D_R_R#g;  # \(bv  -> {\mbox{\boldmath$\mid$}}
    s#\\\(bx#_Cvrule width.5em height.6em depth-.1em_R#g;
    s#\\\(cf#^#g;                            # \(cf  -> ^
    s#\\\(al#_Maleph_D#g;                    # \(al  -> $\aleph$
    s#\\\(If#_MIm_D#g;                       # \(If  -> $\Im$
    s#\\\(Rf#_MRe_D#g;                       # \(Rf  -> $\Re$
    s#\\\(ws#_Mwp_D#g;                       # \(ws  -> $\wp$
    s#\\\(mt#_E_Bprime_D#g;                  # \(mt  -> ${}^\prime$
    s#\\\(sd#_E_L_Bprime_B!_Bprime_R_D#g;    # \(sd  -> ${}^{\prime\!\prime}$
    s#\\\(pa#_BP#g;                          # \(pa  -> \P
    s#\\\(Cc#_Mclubsuit_D#g;                 # \(Cc  -> $\clubsuit$
    s#\\\(Cd#_Mdiamondsuit_D#g;              # \(Cd  -> $\diamondsuit$
    s#\\\(Ch#_Mheartsuit_D#g;                # \(Ch  -> $\heartsuit$
    s#\\\(Cs#_Mspadesuit_D#g;                # \(Cs  -> $\spadesuit$
    s#\\\(bt#_Mperp_D#g;                     # \(bt  -> $\perp$
    s#\\\(<:#_MLeftarrow_D#g;                # \(<:  -> $\Leftarrow$
    s#\\\(:>#_MRightarrow_D#g;               # \(:>  -> $\Rightarrow$
    s#\\\(io#_MLeftrightarrow_D#g;           # \(io  -> $\Leftrightarrow$
    s#\\\(u=#_MUparrow_D#g;                  # \(u=  -> $\Uparrow$
    s#\\\(d=#_MDownarrow_D#g;                # \(d=  -> $\Downarrow$
    s#\\\(r1#_Mrightleftharpoons_D#g;        # \(r1  -> $\rightleftharpoons$
    s#\\\(r2#_Mleftharpoondown_D#g;          # \(r2  -> $\leftharpoondown$
    s#\\\(cr#_Mhookleftarrow_D#g;            # \(cr  -> $\hookleftarrow$
    s#\\\(AL#_M_D#g;                # \(AL  ->
    s#\\\(DL#_M_D#g;                # \(DL  ->

    s#\\\(\*a#_Malpha_D#g;                   # \(*a  -> $\alpha$
    s#\\\(\*b#_Mbeta_D#g;                    # \(*b  -> $\beta$
    s#\\\(\*c#_Mxi_D#g;                      # \(*c  -> $\xi$
    s#\\\(\*d#_Mdelta_D#g;                   # \(*d  -> $\delta$
    s#\\\(\*e#_Mvarepsilon_D#g;              # \(*e  -> $\varepsilon$
    s#\\\(\*f#_Mphi_D#g;                     # \(*f  -> $\phi$
    s#\\\(\*g#_Mgamma_D#g;                   # \(*g  -> $\gamma$
    s#\\\(\*h#_Mtheta_D#g;                   # \(*h  -> $\theta$
    s#\\\(\*([ij])\\\*(['`])#_C$2_B$1_R#g;   # \\(*i\\*' -> {\'\i}    new 0.9.4
    s#\\\(\*i#_Miota_D#g;                    # \(*i  -> $\iota$
    s#\\\(\*k#_Mkappa_D#g;                   # \(*k  -> $\kappa$
    s#\\\(\*l#_Mlambda_D#g;                  # \(*l  -> $\lambda$
    s#\\\(\*m#_Mmu_D#g;                      # \(*m  -> $\mu$
    s#\\\(\*n#_Mnu_D#g;                      # \(*n  -> $\nu$
    s#\\\(\*o#_Do_D#g;                       # \(*o  -> $o$
    s#\\\(\*p#_Mpi_D#g;                      # \(*p  -> $\pi$
    s#\\\(\*q#_Mpsi_D#g;                     # \(*q  -> $\psi$
    s#\\\(\*r#_Mrho_D#g;                     # \(*r  -> $\rho$
    s#\\\(\*s#_Msigma_D#g;                   # \(*s  -> $\sigma$
    s#\\\(\*t#_Mtau_D#g;                     # \(*t  -> $\tau$
    s#\\\(\*u#_Mupsilon_D#g;                 # \(*u  -> $\upsilon$
    s#\\\(\*w#_Momega_D#g;                   # \(*w  -> $\omega$
    s#\\\(\*x#_Mchi_D#g;                     # \(*x  -> $\chi$
    s#\\\(\*y#_Meta_D#g;                     # \(*y  -> $\eta$
    s#\\\(\*z#_Mzeta_D#g;                    # \(*z  -> $\zeta$
    s#\\\(ts#_Mvarsigma_D#g;                 # \(ts  -> $\varsigma$
    s#\\\(\*C#_MXi_D#g;                      # \(*C  -> $\Xi$
    s#\\\(\*D#_MDelta_D#g;                   # \(*D  -> $\Delta$
    s#\\\(\*F#_MPhi_D#g;                     # \(*F  -> $\Phi$
    s#\\\(\*G#_MGamma_D#g;                   # \(*G  -> $\Gamma$
    s#\\\(\*H#_MTheta_D#g;                   # \(*H  -> $\Theta$
    s#\\\(\*L#_MLambda_D#g;                  # \(*L  -> $\Lambda$
    s#\\\(\*P#_MPi_D#g;                      # \(*P  -> $\Pi$
    s#\\\(\*Q#_MPsi_D#g;                     # \(*Q  -> $\Psi$
    s#\\\(\*R#_Crm_SP_R#g;                   # \(*R  -> {\rm P}
    s#\\\(\*S#_MSigma_D#g;                   # \(*S  -> $\Sigma$
    s#\\\(\*U#_Crm_SY_R#g;                   # \(*U  -> {\rm Y}
    s#\\\(\*W#_MOmega_D#g;                   # \(*W  -> $\Omega$
    s#\\\(\*Y#_Crm_SH_R#g;                   # \(*Y  -> {\rm H}
    s#\\\(\*(\w)#_Crm_S$1_R#g;               # \(*_  -> {\rm _}

    # from the -mm macros

    s#\\\*\(Tm#_E_Crm_Buppercase_LTM_R_R_D#g;# \*(Tm -> ${}^{\rm\uppercase{TM}}$

    # I am SO disgusted with troff.  It seems that unless the -ms option is
    # given, all accents are done in the -mm way e\*'.  In fact, when the
    # -ms option is given, only the original 7 accents are done postfix.

    # (ij) changed to ([ij])                                   in version 0.9.4
    #
#   s#(ij)\\\*(['`])#_C$1_B$2_R#g;           # i\*'  -> {\'\i}
    s#([ij])\\\*(['`])#_C$2_B$1_R#g;         # i\*'  -> {\'\i}
#   s#(ij)\\\*:#_C"_B$1_R#g;                 # i\*:  -> {\"\i}
    s#([ij])\\\*:#_C"_B$1_R#g;               # i\*:  -> {\"\i}
#   s#(ij)\\\*\^#_C_A_B$1_R#g;               # i\*^  -> {\^\i}
    s#([ij])\\\*\^#_C_A_B$1_R#g;             # i\*^  -> {\^\i}
#
    s#(\w)\\\*(['`])#_C$2$1_R#g;             # e\*'  -> {\'e}
    s#(\w)\\\*\^#_C_A$1_R#g;                 # e\*^  -> {\^e}
    s#(\w)\\\*~#_C_T$1_R#g;                  # e\*~  -> {\~e}
    s#(\w)\\\*:#_C"$1_R#g;                   # e\*:  -> {\"e}
    s#(\w)\\\*;#_C"$1_R#g;                   # U\*;  -> {\"U}
    s#(\w)\\\*,#_Cc_L$1_R_R#g;               # e\*,  -> {\c{e}}
#
#   added but suspended as they are old versions:
#   s#\\\*\(D-#_Cecr_Bsymbol_L208_R_R#g; # \*(D- -> {\ecr\symbol{208}} in 0.9.4
#   s#\\\*\(d-#_Cecr_Bsymbol_L240_R_R#g; # \*(d- -> {\ecr\symbol{240}} in 0.9.4
#   s#\\\*\(Th#_Cecr_Bsymbol_L222_R_R#g; # \*(Th -> {\ecr\symbol{222}} in 0.9.4
#   s#\\\*\(th#_Cecr_Bsymbol_L254_R_R#g; # \*(th -> {\ecr\symbol{254}} in 0.9.4
#
#   new TC fonts [T1] allow \DH, \dh, \TH, \th  in BibTeX !!!      new in 0.9.4
    s#\\\*\(D-#_CDH_R#g;                     # \*(D- -> {\DH}      new in 0.9.4
    s#\\\*\(d-#_Cdh_R#g;                     # \*(d- -> {\dh}      new in 0.9.4
    s#\\\*\(Th#_CTH_R#g;                     # \*(Th -> {\TH}      new in 0.9.4
    s#\\\*\(th#_Cth_R#g;                     # \*(th -> {\th}      new in 0.9.4
    s#u\\\*o#_Cecr_Bsymbol_L183_R_R#g; # u\*o  -> {\ecr\symbol{183}} " in 0.9.4

    # from the Berkeley -ms macros

    s#\\\*\-#--#g;                           # \*-   -> --
    s#\\\*Q#``#g;                            # \*Q   -> ``
    s#\\\*U#''#g;                            # \*U   -> ''
    s#\\\*\(BU#_Mbullet_D#g;                 # \*(BU -> $\bullet$
    s#\\\*\(EM#--#g;                         # \*(EM -> --

    # changed in 0.8.1, from e\*' to \*'e.
    # These only get used if the above fail (which they don't).
    #  An '-ms' option?  What a hack..

    s#\\\*(['`])(ij)#_C$2_B$1_R#g;           # \*'i  -> {\'\i}
    s#\\\*:(ij)#_C"_B$1_R#g;                 # \*:i  -> {\"\i}
    s#\\\*\^(ij)#_C_A_B$1_R#g;               # \*^i  -> {\^\i}
    s#\\\*(['`])(\w)#_C$1$2_R#g;             # \*'e  -> {\'e}
    s#\\\*\^(\w)#_C_A$1_R#g;                 # \*^e  -> {\^e}
    s#\\\*~(\w)#_C_T$1_R#g;                  # \*~e  -> {\~e}
    s#\\\*C(\w)#_Cv_L$1_R_R#g;               # \*Cc  -> {\v{c}}
    s#\\\*,(\w)#_Cc_L$1_R_R#g;               # \*,e  -> {\c{e}}
    s#\\\*:(\w)#_C"$1_R#g;                   # \*:e  -> {\"e}

    s#(\w)\\\*v#_Cv_L$1_R_R#g;               # c\*v  -> {\v{c}}
    s#(\w)\\\*_U#_C=$1_R#g;                  # e\*_  -> {\=e}
    s#([Oo])\\\*/#_C$1_R#g;                  # o\*/  -> {\o}
    s#([Ll])\\\*/#_C$1_R#g;                  # L\\*/  -> {\L}      new in 0.9.4
    s#(\w)\\\*\.#_Cd_L$1_R_R#g;              # e\*.  -> {\d{e}}
    s#([Aa])\\\*o#_C$1$1_R#g;                # a\*o  -> {\aa}

    s#\\\(-D#_CDH_R#g;                     # \*(D- -> {\DH}        new in 0.9.4
    s#\\\(Sd#_Cdh_R#g;                     # \*(d- -> {\dh}        new in 0.9.4
    s#\\\(TP#_CTH_R#g;                     # \*(Th -> {\TH}        new in 0.9.4
    s#\\\(Tp#_Cth_R#g;                     # \*(th -> {\th}        new in 0.9.4
    s#\\\(ID#_Cecr_Bsymbol_L157_R_R#g; # \*(IDot -> {\ecr\symbol{157}} "  0.9.4

    s#\\\*([!?])#$1`#g;                      # \*?   -> ?`
    s#\\s-[123]\\\*8\\s0#_Css_R#g;           # \*8   -> {\ss}      new in 0.9.4
    s#\\\*8#_Css_R#g;                        # \*8   -> {\ss}
    s#\\\*3#_h_Blower.5ex_H3_R_R#g;          # \*3   -> \hbox{\lower.5ex 3}
    s#\\\*\(Th#_hI_Bhskip-.6ex_Braise.5ex_H_Mscriptscriptstyle_Bsupset_D_R_R#g;
    s#\\\*\(th#_h_Clower.3ex_H_Blarge l_R_R_Bhskip-.52ex o_R#g;
    s#\\\*D\-#_h_Booalign_L_LD_R_Bcrcr\n_Bhskip.2ex_Braise.25ex_H-_R_Bhfil_R_R#g;
    s#\\\*d\-#_h_Booalign_L_Mpartial_D_Bcrcr\n_Bhskip.55ex_Braise.7ex_H-_R_Bhfil_R_R#g;
    s#\\\*\(([AO])e#_C$1E_R#g;               # \*(Ae -> {\AE}
    s#\\\*\(([ao])e#_C$1e_R#g;               # \*(ae -> {\ae}
    s#\\\*q#_Cc_Lo_R_R#g;                    # \*q   -> {\c{o}}  # wrong

    # International (Roman-8) symbols

    s#\\\(\.\.#_C"_B _R#g;                   # \(..  -> {\"\ }
    s#\\\(([AEIOUYaeouy]):#_C"$1_R#g;        # \(A:  -> {\"A}      Umlaute
    s#\\\(([AEIOUaceouy])'#_C'$1_R#g;        # \(A'  -> {\'A}
    s#\\\(([AEIOUaeouy])`#_C`$1_R#g;         # \(A`  -> {\`A}
    s#\\\(([AEIOUaeouy])\^#_C_A$1_R#g;       # \(A^  -> {\^A}
    s#\\\(i:#_C"_Bi_R#g;                     # \(i:  -> {\"\i}
    s#\\\(i(['`])#_C$1_Bi_R#g;               # \(i'  -> {\'\i}
    s#\\\(i\^#_C_A_Bi_R#g;                   # \(i^  -> {\^\i}
    s#\\\(([ANOano])~#_C_T$1_R#g;            # \(A~  -> {\~A}
    s#\\\(([CcOo]),#_Cc_L$1_R_R#g;           # \(c,  -> {\c{c}}
    s#\\\(([Ss])v#_Cv_L$1_R_R#g;             # \(sv  -> {\v{s}}
    s#\\\(([Oo])/#_C$1_R#g;                  # \(O/  -> {\O}
    s#\\\(ss#_Css_R#g;                       # \(ss  -> {\ss}
    s#\\\(L\-#_Cpounds_R#g;                  # \(L-  -> {\pounds}
    s#\\\(L=#_Cpounds_R#g;                   # \(L=  -> {\pounds}   # (Wrong!)
    s#\\\(Y=#_h_Brm_Brlap=Y_R#g;             # \(Y=  -> \hbox{\rm\rlap=Y}
    s#\\\(I([!?])#$1`#g;                     # \I!   -> !`
    s#\\\((AE|ae|OE|oe)#_C$1_R#g;            # \(AE  -> {\AE}
    s#\\\(([Aa])o#_C$1$1_R#g;                # \(Ao  -> {\AA}
    s#\\\(TH#_hI_Bhskip-.6ex_Braise.5ex_H_Mscriptscriptstyle_Bsupset_D_R_R#g;
    s#\\\(th#_h_Clower.3ex_H_Blarge l_R_R_Bhskip-.52ex o_R#g;
    s#\\\(D\-#_h_Booalign_L_LD_R_Bcrcr\n_Bhskip.2ex_Braise.25ex_H-_R_Bhfil_R_R#g;
    s#\\\(d\-#_h_Booalign_L_Mpartial_D_Bcrcr\n_Bhskip.55ex_Braise.7ex_H-_R_Bhfil_R_R#g;
    s#\\\(([ao])_U#_E_Cb_Cscriptsize $1_R_R_D#g;

    # The "Scandinavian currency sign" is made with a bold \circ rlap'ed
    # with 8 .'s.  Big, long, and ugly, but the result is not too bad.

    s#\\\(ox#_h_Booalign_Cmbox_Cboldmath_Mcirc_D_R_Bcrcr\n_Bhskip-.04ex_Braise.78ex_H._R_Bhfil_Bcrcr\n_Bhskip-.04ex_Braise.08ex_H._R_Bhfil_Bcrcr\n_c#g;
    s#_c#_Bhskip.7ex_Braise.78ex_H._R_Bhfil_Bcrcr\n_Bhskip.7ex_Braise.08ex_H._R_Bhfil_Bcrcr\n_c#g;
    s#_c#_Bhskip-.14ex_Braise.89ex_H._R_Bhfil_Bcrcr\n_Bhskip-.14ex_Braise-.02ex_H._R_Bhfil_Bcrcr\n_c#g;
    s#_c#_Bhskip.8ex_Braise.89ex_H._R_Bhfil_Bcrcr\n_Bhskip.8ex_Braise-.02ex_H._R_Bhfil_Bcrcr\n_R_R#g;

    # All the symbols from groff chars.tr that aren't listed above.
    #   What the heck is this??  not only is a\*: an a umlaut, but so is
    #   \(a: and also \(:a !  God, I wish troff would get it together!
    #   Oh, some people ignore all this and use \o to overlap it themselves!
    #   \(ao is Ao in Roman-8, and an  o in groff.
    #   \(Cs is Cards Spades in Roman-8 and Currency Scandanavian in groff.
    #   How do I know which they meant??

    s#\\\(bs##g;                             # \(bs  -> (not implemented)
    s#\\\(%0#_h%_Bhskip-.16ex_Blower.15ex_H_Bscriptsize 0_R_R#g;
    s#\\\(f/#/#g;                            # \(f/  -> /
    s#\\\(ha#_h_Braise.3em_H_Mscriptstyle_Bwedge_D_R_R#g;
    s#\\\(ti#_Msim_D#g;                      # \(ti  -> $\sim$
    s#\\\(\-D#_h_Booalign_L_LD_R_Bcrcr\n_Bhskip.2ex_Braise.25ex_H-_R_Bhfil_R_R#g;
    s#\\\(Sd#_h_Booalign_L_Mpartial_D_Bcrcr\n_Bhskip.8ex_Braise.7ex_H-_R_Bhfil_R_R#g;
    s#\\\(TP#_hI_Bhskip-.6ex_Braise.5ex_H_Mscriptscriptstyle_Bsupset_D_R_R#g;
    s#\\\(Tp#_h_Clower.3ex_H_Blarge l_R_R_Bhskip-.52ex o_R#g;
    s#\\\(IJ#_LI_Bhskip-.2ex J_R#g;          # \(IJ  -> {I\hskip-.2ex J}
    s#\\\(ij#_Li_Bhskip-.2ex j_R#g;          # \(ij  -> {i\hskip-.2ex j}
    s#\\\('([ACEIOUaceou])#_C'$1_R#g;        # \('A  -> {\'A}
    s#\\\(:([AEIOUYaeouy])#_C"$1_R#g;        # \(:A  -> {\"A}     Umlaute
    s#\\\(\^([AEIOUaeou])#_C_A$1_R#g;        # \(^A  -> {\^A}
    s#\\\(`([AEIOUaeou])#_C`$1_R#g;          # \(`A  -> {\`A}
    s#\\\((['`])i#_C$1_Bi_R#g;               # \('i  -> {\'\i}
    s#\\\(\^i#_C_A_Bi_R#g;                   # \(^i  -> {\^\i}
    s#\\\(:i#_C"_Bi_R#g;                     # \(:i  -> {\"\i}
    s#\\\(~([ANOano])#_C_T$1_R#g;            # \(~A  -> {\~A}
    s#\\\(v([CcgSsZz])#_Cv_L$1_R_R#g;        # \(vs  -> {\v{s}} + g    in 0.9.4
    s#\\\(,([CcSst])#_Cc_L$1_R_R#g;          # \(,c  -> {\c{c}} + Sst  in 0.9.4
    s#\\\(/([OoLl])#_C$1_R#g;                # \(/O  -> {\O}
    s#\\\(o([Aa])#_C$1$1_R#g;                # \(oA  -> {\AA}
    s#\\\(a"#_CH_L _R_R#g;                   # \(a"  -> {\H{ }}
#   s#\\\(a\-#_C=_L _R_R#g;                  # \(a-  -> {\={ }} new in 0.9.4:
    s#([A-Za-z])\\\(a\-#_Mbar_L$1_R_D#g;     # {[a-z]}\(a-  -> $\bar{.}$
    s#\\\(a\.#_C._L _R_R#g;                  # \(a.  -> {\.{ }}
    s#\\\(a\^#_C_A_L _R_R#g;                 # \(a^  -> {\^{ }}
    s#\\\(ab#_Cu_L _R_R#g;                   # \(ab  -> {\u{ }}
#   s#\\\(ac#_Cc_L _R_R#g;                   # \(ac  -> {\c{ }} new in 0.9.4:
    s#([Ss])\\\(ac#_Cc_L$1_R_R#g;            # \(,S  -> {\c{[Ss]}}
    s#\\\(ad#_C"_L _R_R#g;                   # \(ad  -> {\"{ }}
#   s#\\\(ah#_Cv_L _R_R#g;                   # \(ah  -> {\v{ }} new in 0.9.4:
    s#(\w)\\\(ah#_Cv_L$1_R_R#g;              # .\(ah  -> {\v{.}}
    s#\\\(a~#_C_T_L _R_R#g;                  # \(a~  -> {\~{ }}
    s#\\\(ho#_Cc_L _R_R#g;                   # \(ho  -> {\c{ }}  # (wrong!)
    s#\\\(\.([ij])#_C$1_R#g;                 # \(.i  -> {\i}
    s#\\\(Do#\$#g;                           # \(Do  -> $
    s#\\\(Po#_Cpounds_R#g;                   # \(Po  -> {\pounds}
    s#\\\(Ye#_h_Brm_Brlap=Y_R#g;             # \(Ye  -> \hbox{\rm\rlap=Y}
    s#\\\(Fo#_Mscriptscriptstyle_Bll_D#g;    # \(Fo  -> $\scriptscriptstyle\ll$
    s#\\\(Fc#_Mscriptscriptstyle_Bgg_D#g;    # \(Fc  -> $\scriptscriptstyle\gg$
    s#\\\(fo#_Mscriptscriptstyle_l_D#g;      # \(fo  -> $\scriptscriptstyle<$
    s#\\\(fc#_Mscriptscriptstyle_g_D#g;      # \(fc  -> $\scriptscriptstyle>$
    s#\\\(r([!?])#$1`#g;                     # \(r!  -> !`
    s#\\\(OK#_Cmbox_Cboldmath_Msurd_D_R_R#g; # \(OK  ->{\mbox{\boldmath$\surd$}}
    s#\\\(Of#_E_Cb_Cscriptsize a_R_R_D#g;    # \(Of  -> ${}^{\scriptsize a}}$
    s#\\\(Om#_E_Cb_Cscriptsize o_R_R_D#g;    # \(Om  -> ${}^{\scriptsize o}}$
    s#\\\(S(\d)#_E$1_D#g;                    # \(S1  -> ${}^1$
    s#\\\(lA#_MLeftarrow_D#g;                # \(lA  -> $\Leftarrow$
    s#\\\(rA#_MRightarrow_D#g;               # \(rA  -> $\Rightarrow$
    s#\\\(hA#_MLeftrightarrow_D#g;           # \(hA  -> $\Leftrightarrow$
    s#\\\(dA#_MDownarrow_D#g;                # \(dA  -> $\Downarrow$
    s#\\\(uA#_MUparrow_D#g;                  # \(uA  -> $\Uparrow$
    s#\\\(vA#_MUpdownarrow_D#g;              # \(vA  -> $\Updownarrow$
    s#\\\(va#_Mupdownarrow_D#g;              # \(va  -> $\updownarrow$
    s#\\\(ba#_Chskip.4ex_Bvrule width.2ex height1.7ex depth0ex_R#g;
    s#\\\(bb#_h_Bhskip.4ex_H_Booalign_Cvrule width.2ex height.5ex depth.4ex_Bcrcr\n_Bhfil_Braise.8ex_H_Bvrule width.2ex height.9ex depth0ex_R_Bhfil_R_R_R#g;
    s#\\\(tm#_E_Crm_Buppercase_LTM_R_R_D#g;  # \(tm  -> ${}^{\rm\uppercase{TM}}$
    s#\\\(ps#_BP#g;                          # \(ps  -> \P
    s#\\\(en#-#g;                            # \(en  -> -
    s#\\\(lB#_L_R[#g;                        # \(lB  -> {}[
    s#\\\(rB#]#g;                            # \(rB  -> ]
    s#\\\(lC#{#g;                            # \(lC  -> {
    s#\\\(rC#}#g;                            # \(rC  -> }
    s#\\\(la#_Mlangle_D#g;                   # \(la  -> $\langle$
    s#\\\(ra#_Mrangle_D#g;                   # \(ra  -> $\rangle$
    s#\\\(lq#``#g;                           # \(lq  -> ``
    s#\\\(rq#''#g;                           # \(rq  -> ''
    s#\\\(oq#`#g;                            # \(oq  -> `
    s#\\\(at#@#g;                            # \(at  -> @
    s#\\\(sh#\##g;                           # \(sh  -> #
    s#\\\(rs#_I#g;                           # \(rs  -> $\backslash$
    s#\\\(3d#_D_H._R_Braise.9ex_H._R_H._R_D#g;# \(3d -> .:.
    s#\\\(~~#_Mapprox_D#g;                   # \(~~  -> $\approx$
    s#\\\(!=#_Mneq_D#g;                      # \(!=  -> $\neq$
    s#\\\(=~#_Mcong_D#g;                     # \(=~  -> $\cong$
    s#\\\(AN#_Mwedge_D#g;                    # \(AN  -> $\wedge$
    s#\\\(OR#_Mvee_D#g;                      # \(OR  -> $\vee$
    s#\\\(Ah#_Maleph_D#g;                    # \(Ah  -> $\aleph$
    s#\\\(Im#_MIm_D#g;                       # \(Im  -> $\Im$
    s#\\\(Re#_MRe_D#g;                       # \(Re  -> $\Re$
    s#\\\(md#_Mcdot_D#g;                     # \(md  -> $\cdot$
    s#\\\(nm#_Mnotin_D#g;                    # \(nm  -> $\notin$
    s#\\\(pp#_Mperp_D#g;                     # \(pp  -> $\perp$
    s#\\\(c\*#_Motimes_D#g;                  # \(c*  -> $\otimes$
    s#\\\(c\+#_Moplus_D#g;                   # \(c+  -> $\oplus$
    s#\\\(\-h#_Mhbar_D#g;                    # \(-h  -> $\hbar$
    s#\\\(CL#_Mclubsuit_D#g;                 # \(CL  -> $\clubsuit$
    s#\\\(SP#_Mspadesuit_D#g;                # \(SP  -> $\spadesuit$
    s#\\\(HE#_Mheartsuit_D#g;                # \(HE  -> $\heartsuit$
    s#\\\(DI#_Mdiamondsuit_D#g;              # \(DI  -> $\diamondsuit$
    s#\\\(CR#_Mhookleftarrow_D#g;            # \(CR  -> $\hookleftarrow$
    s#\\\(st#_Mni_D#g;                       # \(st  -> $\ni$
    s#\\\(/_U#_Mangle_D#g;                   # \(/_  -> $\angle$
    s#\\\(\-\+#_Mmp_D#g;                     # \(-+  -> $\mp$
    s#\\\(nc#_Mnot_Bsupset_D#g;              # \(nc  -> $\not\supset$
    s#\\\(ne#_Mnot_Bequiv_D#g;               # \(ne  -> $\not\equiv$


    # misc

    s#\\u([^\\]*)\\d#_Braisebox_L1ex_R_L$1_R#g;
    s#\\d([^\\]*)\\u#_Braisebox_L-1ex_R_L$1_R#g;
    s#\\z(.)#_Brlap_L$1_R#g;                 # \z|_   -> L
    s#\\\*\(mm#mm#g;                         # \*(mm  -> mm

    s#\\&##g;                                # \&     ->

  }   # done with troff special chars

  # finally, do eqn processing if they asked for it.
  #
  # This is very crude, and handles only the very simple eqn constructs.
  # We should have some support for reading in eqn definitions rather
  # than hard-coding some.
  #
  if ($handleeqn) {
    local ($oldline);
    # print STDERR "\nfrom: $_\n" if /@.*@/;
    # replace  @blah $\foo$ bar@   with   @blah \foo bar@
    1 while s/\@([^@]* su[bp] [^@]*)_M([^@]*)_D([^@]*)\@/\@$1_B$2$3\@/g;
    1 while s/\@([^@]*)_M([^@]*)_D([^@]* su[bp] [^@]*)\@/\@$1_B$2$3\@/g;
    while (/\@.*\@/) {
      $oldline = $_;
      s/\@\s*roman\s+([^\@]*)\@/\@$1\@/g;
      s/\@\s*{\s*([^\s@]+)\s*sub\s+([^\s@]+)\s*}\s*sup\s+([^\s@]+)\s*([^@]*)\@/_L_D_Crm_S$1_R__L$2_R_A_L$3_R_D_R\@$4\@/g;
      s/\@\s*([^\s@]+)\s*sub\s+([^\s@]+)\s*([^@]*)@/_L_D_Crm_S$1_R__L$2_R_D_R\@$3\@/g;
      s/\@\s*([^\s@]+)\s*sup\s+([^\s@]+)\s*([^@]*)@/_L_D_Crm_S$1_R_A_L$2_R_D_R\@$3\@/g;
      s/_L_D_Crm_S""_R/_L_D_L_R/g;   # handle @ "" sub 18 @
      s/\@mu\@/_Mmu_D/g;
      s/\@angstrom\@/_CAA_R/g;
      s/\@co2\@/\@CO sub 2\@/g;
      s/\@no2\@/\@NO sub 2\@/g;
      s/\@nox\@/\@NO sub x\@/g;
      s/\@n2\@/\@N sub 2\@/g;
      s/\@so2\@/\@SO sub 2\@/g;
      s/\@so4\@/\@{SO sub 4} sup 2-\@/g;
      s/\@no3\@/\@{NO sub 3} sup -\@/g;
      s/\@hno3\@/\@HNO sub 3\@/g;
      if ($oldline eq $_) {
        s/\@\s*([^\s@]+)\s*([^@]*)\@/_L$1_R\@$2\@/g;
      }
      s/\@\s*\@//g;
      # print STDERR "  to: $_\n";
    }
  }

  # protect TeX characters
  if ($protectTeX) {
    s/\\/_I/g;
    s/#/\\#/g;
    s/\$/\\\$/g;
    s/%/\\%/g;
    s/&/\\&/g;
    s/{/_D\\lbrace_D/g;
    s/}/_D\\rbrace_D/g;
    s/\|/\$|\$/g;
    s/</\$<\$/g;
    s/>/\$>\$/g;
    s/\^/\\^{}/g;
    s/~/\\~{}/g;
  }

  # now convert our escaped characters back to their real selves
  s/_B/\\/g;
  s/_I/\$\\backslash\$/g;
  s/_C/{\\/g;
  s/_S/ /g;
  s/_L/{/g;
  s/_R/}/g;
  s/_l/</g;
  s/_g/>/g;
  s/_T/~/g;
  s/_A/^/g;
  s/_D/\$/g;
  s/_M/\$\\/g;
  s/_V/|/g;
  s/_E/\${}^/g;
  s/_H/\\hbox{/g;
  s/_h/\\leavevmode\n\\hbox{/g;
  s/_U/\\_/g;
  s/\n\n/\\par\n/g;           # this is for fields that want paragraphs
  $_;
}

##########################################
# This converts IBMish control character combinations into troff
# This is new and mostly untested.
# Why troff?  We convert ibm to troff, then troff to TeX.  That
# way people can use this program to convert refer w/controls into
# plain refer.  Or they can get the full blown refer->TeX.
#
# refer(c) -> refer     r2b -n -der -ibm
# refer(c) -> TeX       r2b -ibm
# refer(c) -> tib       r2b -der -ibm
#
sub doibmtoroff {
  local($_) = @_;

  if (/[\200-\376]/) {
    # use the -ms i\*' for accents, as all troff's can handle that.
    # I'd rather use \('i, but that works for groff, while eroff wants \(i'

    s/[\200]/C\\*,/g;
    s/[\201]/u\\*:/g;
    s/[\202]/e\\*'/g;
    s/[\203]/a\\*^/g;
    s/[\204]/a\\*:/g;
    s/[\205]/a\\*`/g;
    s/[\206]/a\\*o/g;
    s/[\207]/c\\*,/g;
    s/[\210]/e\\*^/g;
    s/[\211]/e\\*:/g;
    s/[\212]/e\\*`/g;
    s/[\213]/i\\*:/g;
    s/[\214]/i\\*^/g;
    s/[\215]/i\\*`/g;
    s/[\216]/A\\*:/g;
    s/[\217]/A\\*o/g;
    s/[\220]/E\\*'/g;
    s/[\221]//g;      # Can't make out what this is supposed to be.
    s/[\222]//g;      # Ditto
    s/[\223]/o\\*^/g;
    s/[\224]/o\\*:/g;
    s/[\225]/o\\*`/g;
    s/[\226]/u\\*^/g;
    s/[\227]/u\\*`/g;
    s/[\230]/y\\*:/g;
    s/[\231]/o\\*:/g;
    s/[\232]/u\\*:/g;
    s/[\233]/\\\(ct/g;
    s/[\234]/\\\(L-/g;
    s/[\235]/\\\(Y=/g;
    s/[\236]//g;      # should handle this
    s/[\237]//g;      # and this
    s/[\240]/a\\*'/g;
    s/[\241]/i\\*'/g;
    s/[\242]/o\\*'/g;
    s/[\243]/u\\*'/g;
    s/[\244]/n\\*~/g;
    s/[\245]/N\\*~/g;
    s/[\246]/\\\(a_/g;
    s/[\247]/\\\(o_/g;

    s/[\250]/\\*?/g;
    s/[\251]//g;
    s/[\252]/\\\(no/g;
    s/[\253]/\\\(12/g;
    s/[\254]/\\\(14/g;
    s/[\255]/\\*!/g;
    s/[\256]/\\\(<</g;
    s/[\257]/\\\(>>/g;

   s/[\360]/\\\(==/g;
    s/[\361]/\\\(+-/g;
    s/[\362]/\\\(>=/g;
    s/[\363]/\\\(<=/g;
    s/[\364]//g;
    s/[\365]//g;
    s/[\366]/\\\(di/g;
    s/[\367]/\\\(~~/g;

    s/[\373]/\\\(sr/g;

    # I'm taking a guess that \376 is supposed to be the R set.
    s/[\376]/\\\(Re/g;
  }

  $_;
}