########################################################################
# sgmlspl script for a *supplemented* version of SGMLS.pm that, when
#    reading an nsgmls ESIS with empty tag labels, provides detection
#    of defined-empty elements with the method  $element->defempty .
#
# Document Type: article (GELLMU)
# Output: text/xml
# Edited by: William F. Hammond
# Begun: 21 November 1998
#
# The design has become overloaded.  This script is serving two
# functions that should be performed by a pipeline of length 2.
#   1.  converting SGML to fleshed out XML
#   2.  central styling (such as section id management, label and
#       reference handling,  . . .)
########################################################################

$utf8On = 0;
if($ENV{"GELLMU_UTF8"} == 1){
    use utf8;
    $utf8On = 1;
    print STDERR "  ***  xmlgart.pl: UTF-8 Library\n";
}
else{
print STDERR $0, " *** ", $WhoAmI, "\n";
};
use SGMLS;			# Use the SGMLS package.
use SGMLS::Output;		# Use stack-based output.

$WhoAmI = "xmlgart.pl";

# Global variables
$allsecs = "section|subsection|subsubsection|paragraph|subparagraph";
$AllSecs = "Section|Subsection|Subsubsection|Paragraph|Subparagraph";
@Alphabet = qw(0 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z);
@alphabet = qw(0 a b c d e f g h i j k l m n o p q r s t u v w x y z);
@Roman = qw (0 I II III IV V VI VII VIII IX X XI XII XIII XIV XV XVI
	     XVII XVIII XIX XX);
@roman = qw (0 i ii iii iv v vi vii viii ix x xi xii xiii xiv xv xvi
	     xvii xviii xix xx);

$asstkey = "";
$asstname = "";
$asstid = "";
$asstlabel=""; # Computed label; formed at </asstname> but written
               # just before <assertion> rather than in <asstname> output.
               # A label in <asstname> could become a font-entangled anchor
               # in an HTML formatting.
$asstser = "";
$asstseq=0;
$asstlabelprefix="AssertLabel-";
$asststyle = "";
@attsidflag=(); # Logicals: current sectional unit has sid attribute set
$autoname = 0; # Suppress writing name of anonymous element
$autokey = 0; # counter for automatic key generation
$autoprefix = "KEY-";
$biblabelprefix="BibLabel-";
$bibprefix="BibRef-";
$bibliseq=0;
$bibkey="";
$biblabel="";
$blabel = 0;
$citekey = "";
$citenote = "";
$citetext = "";
$cssurl = "/~hammond/gellmu/gellmuart.css";
$discardflag = 0;
$dtdfpi = "-//GNU GPL: William F. Hammond//DTD GELLMU XML 0.7.0//EN";
$dtdurl = "http://www.albany.edu/~hammond/gellmu/xml/xgellmu.dtd";
$eltser=0;
$eltdepth=0;
$emath = 0;     # Signal for eqnline or eqnrow labeling
$encoding="ISO-8859-1";  # text encoding of XML output
@eqkey = ();    # $eqkey[$thiseq] = key for last explicit label in equation
$eqnautoprefix = "EqnKey-";
$eqnautoseries = "EqnAuto";
$eqnacellseq=0; # eqnarray cell sequence
$eqnintautoprefix = "EqnIntKey-";
$eqnintautoseries = "EqnAuto";
$eqnkey = "";   # label key, if any, for overall equation or eqnarray
$eqnlabel = ""; # stored label (for equation and eqnarray/eqnrow)
$eqnline= "";   # contents inside last eqnline
$eqnamode = 0;  # eqnarray mode,  0 <= value <= 7
   # Value dictionary for $eqnamode:
   #   Odd means the eqnarray attribute nonum is true
   #   0 or 1 means no eqnkey nor eqnser
   #   2 or 3 means eqnkey only
   #   4 or 5 means eqnser only
   #   6 or 7 means eqnkey and eqnser
$eqnintseries = ""; # label series, if any, for last label in eqnrow
$eqnser = "";   # label series, if any, for overall equation or eqnarray
$eqntag = "";   # author supplied visible tag for overall equation or eqnarray
$eqseq=0;       # sequence index for equation and eqnarray elements
$fgcnt="";
$fglbl="";
$gmath = 0;     # Inside math or not?
$internalopen = 0;
$intsubsetopen = 0;
$lgcnt=0;       # logical for existence of aux file for contents
$lgents = 0;    # logical for existence of aux file for entities
$lglbl=0;       # logical for existence of aux file for references
$labelhold = "";  # store all stuff for current label pending disposition
$labelinshead = 0;
$lastuserlabel = "";   # key of last label -- used for "popkey" and "sunit"
%labelkeys = ();  # num seq valued hash on label keys (for key uniqueness)
%labelloc = ();   # sectional unit location of label hash by key ??
%labelser=();     # series name hash from label series attribute, if any ??
$labelrun=0;  # num seq for last label including auto-label for sections
%labelseq=(); # num seq hash on label key
%labelsqr=(); # num seq runner hash on label series name
$llocprefix = "LabelSecRef-"; # ent. prefix to $key for $labelloc{$key}
$lserprefix = "LabelSer-"; # ent. prefix to $key for $labelser{$key}
$lseqprefix = "LabelSeq-"; # Was $sertagprefix
$makecontents=0;
$maxeltdepth=0;
$maxsecdepth=5; # for article
$minsecdepth=0; # 1 for doctype "article" -- set at 'start'
$popkey = 0; # to detect presence of <popkey/> in sectional unit head
             #    in case there is a timing problem finding the key
$sepchar = '\\';
$sepcharre = '\\\\';  # regexp for $sepchar
$sqrtdepth=0;
@radicflag=();        # radicand is not the total content of sqrt
$tabdepth=0;
@tabarg=();
@tabalen=();
@tabaseq=();
@tabasym=();
@taburowflag=();
@tabuhline=();
@tdname=();           # name for output table cell at current tabdepth
@currserial=();
$currserial[0] = 0;
@agpar=();
@agseq=();
@oppar=();
@opseq=();
$secdepth=-1;
$secnumdepth=3; # By default, parts, sections, subsections
@secname=();    # Name of current sectional unit at $secdepth
@secrefs=();    # Output names of sectional units
$secref[0] = "part";     # not yet wired
$secref[1] = "Section";
$secref[2] = "Subsection";
$secref[3] = "Subsubsection";
$secref[4] = "Paragraph";
$secref[5] = "Subparagraph";
@secser=();     # Sequence number of current sectional unit by $secdepth
$secser[0] = 0;
@secsid=();    # sid value for current Sectional unit, indexed on $secdepth
$secsid[0] = "";
@secunit=();
$secunit[0] = "";
$shead = "";
$srefprefix = "SecRef-";
$srefseq = 0;
$srefname = $srefprefix . $srefseq;
@sheadlabel=(); # seq. of queued labels in shead indexed by $labelinshead
$seckey = ""; # key for last-opened Section or section family element
$slabelprefix = "SU-"; # prefix for auto-generated section keys
$spassatt = "";
$sopt = "";
$sprefix = "";
$sunit = "";
$sunitflag = 0;
$sipdepth=0;
@sipsubseq=();
@sipsupseq=();
$stemname="";
$havecitekey=0;
$thislabel = ""; # string for last user label; used for <section>/shead
$thissecunit = 0;
$tocdepth=3;
$xmlinput = 0;   # Is input an xml document?

# Argument processing

$pname = $0;
$pname =~ s/^.*\///;
$usage = "Usage:  " . $pname . " < {nsgmls-ESIS}  " . "[ -e={text-encoding} ]\n";
$arglen = scalar(@ARGV);
print STDERR "No. of args: " . $arglen . "\n";
if ($arglen >= 2){
    print STDERR $usage;
    exit(1);
}
elsif(($arglen == 1) && ($ARGV[0] =~ /^-e=/ )){
    my $tenc = $ARGV[0];
    $tenc =~ s/^-e=//;
    $encoding = $tenc;
    print STDERR "Encoding argument: ", $encoding, "\n";
}
elsif($arglen == 1){
    print STDERR "Unrecognized first argument: ", $ARGV[0], "\n";
    exit(1);
}
else{
    if($ENV{"GELLMU_Encoding"} ne ""){
	$encoding = $ENV{"GELLMU_Encoding"};
	print STDERR "Using ENV-GELLMU_Encoding: ", $encoding, "\n";
    }
    elsif($utf8On == 1){
        print STDERR "UTF-8 Coding implied by use of UTF-8 library\n";
        $encoding = "UTF-8";
    };
};

print STDERR "Final encoding value: ", $encoding, "\n";

if($encoding eq "ISO-8859-1"){
    $dtdfpi = "-//GNU GPL: William F. Hammond//DTD GELLMU XML 0.7.5//EN";
    $dtdurl = "http://www.albany.edu/~hammond/gellmu/xml/xgellmu.dtd";
    print STDERR "Encoding switch for ISO-8859-1\n";
}
elsif($encoding eq "UTF-8"){
    $dtdfpi = "-//GNU GPL: William F. Hammond//DTD GELLMU XML 0.7.5U//EN";
    $dtdurl = "http://www.albany.edu/~hammond/gellmu/xml/uxgellmu.dtd";
    print STDERR "Encoding switch for UTF-8\n";
}
else{
    print STDERR '*** Encoding spec "' . $encoding . "\" not recognized\n";
    exit(2);
};

#
# Specific Element Handlers.
#

# The Empty String
sgml('<empty>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $eltdepth--;
    my $os = "<empty/>";
    # Pass it on so that the XML version is a usable source
    # But:
    my $par = $_[0]->parent;
    my $pan = $par->name;
    if($pan eq "sunit"){
	$os = " ";
    }
    elsif($pan eq "op0"){
	my $gpan = $par->parent->name;
	if($gpan =~ /^($AllSecs|$allsecs)$/){
	    $os = " ";
	};
    };
    output($os);
});
sgml('</empty>', "");

sgml('<Discard>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $currserial[$eltdepth] = $eltser;
    output('<!-- Discard');
    push_output('nul');
});
sgml('</Discard>', sub{
    $eltdepth--;
    my $pos = pop_output;
    output(' -->');
    $discardflag = 1; # eat a subsequent newline
});

sgml('<tableofcontents>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    if($lgcnt != 0){
	my $os = "&TableOfContentsFile;\n";
	output($os);
    }
    else{
	print STDERR "xmlgart.pl WARNING: No file $stemname.xcn\n",
	"cannot do <tableofcontents>\n";
    };
});
sgml('</tableofcontents>', sub{
    $eltdepth--;
});

sgml('<old-blabel>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $currserial[$eltdepth] = $eltser;
    $labelrun++;
    push_output('string');
});
sgml('</old-blabel>', sub{
    $eltdepth--;
    my $pos = pop_output;
    my $os="";
    $blabel++; # for use as default value
    if($pos ne ""){
	$os = $pos;
    }
    else{
	$os = "BL\%" . $blabel;
    };
    $lastuserlabel = $os;
    $os = "<label lseq=\"" . $labelrun;
    $os = $os . "\" series=\"blabel\"";
    $os = $os . " serseq=\"" . $blabel . "\"";
    $os = $os . "\">" . $os . "</label>";
    output($os);
});

sgml('<lg0>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $currserial[$eltdepth] = $eltser;
    $agseq[$eltser] = 0;
    $opseq[$eltser] = 0;
    push_output('string');
});
sgml('</lg0>', sub{
    $eltdepth--;
    my $pos = pop_output;
    my $par = $_[0]->parent;
    my $pan = $par->name;
    my $gpan = $par->parent->name;
    if(($pan eq "tabarg")
       || (($pan eq "ag0")
	   && ($gpan  =~ /^(table|tabular|tabuhead|array|arrhead)/))){
	# return;    # presumably a p-cell -- ignore a width spec for now
	my $os = "{" . $pos . "}";
	output($os);
    }
    else{
	my $os = "";
	if($gmath == 1){
	    $os = "<mlg\n>" . $pos . "</mlg>";
	}
	else{
	    $os = "<lgg\n>" . $pos . "</lgg>";
	};
	output($os);
    };
});

# This code for secnumdepth is here solely for the purpose of
#   saving the value of secnumdepth internally; it is passed on.
sgml('<secnumdepth>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $currserial[$eltdepth] = $eltser;
    $agseq[$eltser] = 0;
    $opseq[$eltser] = 0;
    push_output('string');
});
sgml('</secnumdepth>', sub{
    $eltdepth--;
    my $pos = pop_output;
    my $os = "<secnumdepth\n>" . $pos . "</secnumdepth>";
    output($os);
    $secnumdepth = int($pos);
});

sgml('<entref>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $currserial[$eltdepth] = $eltser;
    $agseq[$eltser] = 0;
    $opseq[$eltser] = 0;
    push_output('string');
});
sgml('</entref>', sub{
    $eltdepth--;
    my $pos = pop_output;
    my $key = $pos;
    my $os = "\[$lseqprefix$key\]";
    if($labelser{$key} ne ""){
	$os = '&' . $lseqprefix . $key . ';';
    };
    output($os);
});

sgml('<evalref>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $currserial[$eltdepth] = $eltser;
    $agseq[$eltser] = 0;
    $opseq[$eltser] = 0;
    push_output('string');
});
sgml('</evalref>', sub{
    $eltdepth--;
    my $pos = pop_output;
    my $key = $pos;
    my $os = "\[labelseq($key)\]";
    if($labelseq{$key} > 0){
	$os = $labelseq{$key};
    }
    elsif($labelloc{$key} > 0){
	$os = $labelloc{$key};
    };
    output($os);
});

# sectional unit of parent where the label with given key occurs
#   empty key: the sectional unit where the sref occurs
sgml('<sref>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    push_output('string');
});
sgml('</sref>', sub{
    my $pos = pop_output;
    my $elt = $_[0];
    my $name = $elt->name;
    my $par = $elt->parent;
    my $pan = $par->name;
    my $os;
    if($pos =~ /^\s*$/){
	$os = '&' . $srefname . ';';
    }
    else{
	$os = '&' . $llocprefix . $pos . ';';
    };
    output($os);
    $eltdepth--;
});

sgml('<series>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $currserial[$eltdepth] = $eltser;
    $agseq[$eltser] = 0;
    $opseq[$eltser] = 0;
    push_output('string');
});
sgml('</series>', sub{
    $eltdepth--;
    my $pos = pop_output;
    my $os = "";
    my $npos = $pos;
    my $type = $_[0]->attribute("type")->value;
    if($npos > 0){
	if($type eq "A"){
	    $os = $Alphabet[$npos];
	}
	elsif($type eq "a"){
	    $os = $alphabet[$npos];
	}
	elsif($type eq "I"){
	    $os = $Roman[$npos];
	}
	elsif($type eq "i"){
	    $os = $roman[$npos];
	}
	else{  # type unsupported or unspecified
	    $os = $npos;
	};
    }
    else{  # Hope that the popped output is an appropriate cdata entity
	$os = '<series type="' . $type . '">' . $pos . "</series\n>";
    };
    output($os);
});

sgml('<tocdepth>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $currserial[$eltdepth] = $eltser;
    $agseq[$eltser] = 0;
    $opseq[$eltser] = 0;
    push_output('string');
});
sgml('</tocdepth>', sub{
    $eltdepth--;
    my $pos = pop_output;
    my $os = "<tocdepth\n>" . $pos . "</tocdepth>";
    output($os);
    $tocdepth = int($pos);
});

sgml('<tmath>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $currserial[$eltdepth] = $eltser;
    $agseq[$eltser] = 0;
    $opseq[$eltser] = 0;
    $gmath = 1;
    push_output('string');
});
sgml('</tmath>', sub{
    $eltdepth--;
    my $pos = pop_output;
    my $elt = $_[0];
    my $name = $elt->name;
    my $os = "<" . $name . "\n>" . $pos . "</" . $name . ">";
    output($os);
    $gmath = 0;
});

sgml('<math>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $currserial[$eltdepth] = $eltser;
    $agseq[$eltser] = 0;
    $opseq[$eltser] = 0;
    $gmath = 1;
    push_output('string');
});
sgml('</math>', sub{
    $eltdepth--;
    my $pos = pop_output;
    my $elt = $_[0];
    my $name = $elt->name;
    my $os = "<" . $name . "\n>" . $pos . "</" . $name . ">";
    output($os);
    $gmath = 0;
});

sgml('<displaymath>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $currserial[$eltdepth] = $eltser;
    $agseq[$eltser] = 0;
    $opseq[$eltser] = 0;
    $gmath = 1;
    push_output('string');
});
sgml('</displaymath>', sub{
    $eltdepth--;
    my $pos = pop_output;
    my $elt = $_[0];
    my $name = $elt->name;
    my $os = "<" . $name . "\n>" . $pos . "</" . $name . ">";
    output($os);
    $gmath = 0;
});

sgml('<equation>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $currserial[$eltdepth] = $eltser;
    $agseq[$eltser] = 0;
    $opseq[$eltser] = 0;
    $gmath = 1;
    $emath = 1;
    $eqseq++;
    $eqnkey = "";
    $eqnser = "";
    $eqntag = "";
    $eqnintseries = "";
    $eqnlabel = ""; # for passed inside labels
    push_output('string');
});
sgml('</equation>', sub{
    my ($elt, $ev) = @_;
    my $pos = pop_output; # Inside output apart from eqnline contents
    if($pos ne ""){
	print STDERR "xmlgart.pl WARNING: Loose content in eqn id $eqseq\n",
	$pos, " for equation at source line ", $ev->line, "\n";
    };
    my $os = "";
    my $nonum = $elt->attribute("nonum")->value;
    my $atteqseq = $elt->attribute("eqseq")->value;
    my $thiseqkey = "";
    my $thiseqser = "";
    # With nonum unset a label in eqnline can supersede the values,
    # if any, of $eqnkey and $eqnser from <eqnkey>, <eqnser>.
    # Handling for inside labels and nonum is in code for <label>.
    # If nonum is true, no inside labels are passed via $eqnlabel
    if($nonum ne "true"){
	$os = $os . $eqnlabel;
    };
    if($eqnkey ne ""){
	$thiseqkey = $eqnkey;
    }
    elsif($nonum ne "true"){
	$thiseqkey = $eqnautoprefix . $eqseq;
    };
    if($eqnser ne ""){
	$thiseqser = $eqnser;
    }
    else{
	$thiseqser = $eqnautoseries;
    };
    # If $eqnser was set to the series of an internal label, then
    #   we don't want an automatic label to bump serseq for that series.
    if(!($nonum eq "true")&&($thiseqser ne "")&&($eqnintseries eq "")){
	prepare_label($thiseqkey, $thiseqser);
	$os = $os . make_label($thiseqkey, "equation", $thiseqser);
    };
    $os = $os . "<equation";
    if(($atteqseq ne "") && ($atteqseq ne $eqseq)){
	print STDERR $WhoAmI, ": ** Replacing attribute-defined equation seq id ",
	$atteqseq, " with actual serial value ", $eqseq, " at source line: ",
	$ev->line, "\n";
    };
    $os = $os . ' eqseq="' . $eqseq . '"';
    my $inv = $elt->attribute("inv")->value;
    if($inv ne ""){
	$os = $os . ' inv="' . $inv . '"';
    };
    if(($nonum ne "") && ($nonum ne "false")){
	$os = $os . ' nonum="' . $nonum . '"';
    };
    $os = $os . ">";
    # Content of <eqnkey> and <eqnser>, if any, was diverted
    #   Here write what is actually being used.
    if(!($nonum eq "true")){
	$os = $os . "<eqnkey>" . $thiseqkey . "</eqnkey\n>";
	$os = $os . "<eqnser>" . $thiseqser . "</eqnser\n>";
	if($eqntag ne ""){
	    $os = $os . "<eqntag>" . $eqntag . "</eqntag\n>";
	};
    };
    $os = $os . "<eqnline>" . $eqnline . "</eqnline\n></equation>";
    output($os);
    $emath = 0;
    $gmath = 0;
    $eltdepth--;
});

sgml('<eqnline>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $currserial[$eltdepth] = $eltser;
    $eqnline = "";
    push_output('string');
});
sgml('</eqnline>', sub{
    $eqnline = pop_output;
    $eltdepth--;
});

sgml('<eqnarray>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $currserial[$eltdepth] = $eltser;
    $agseq[$eltser] = 0;
    $opseq[$eltser] = 0;
    $gmath = 1;
    $emath = 1;
    $eqseq++;
    $eqnkey = "";
    $eqnser = "";
    $eqntag = "";
    $eqnamode = 0;
    if($_[0]->attribute("nonum")->value eq "true"){
	$eqnamode = 1;
    };
    $tabdepth++;  # Is this necessary?
    push_output('string'); # This is popped at '<eqnabody>' so that
                           # <popkey> is available inside there.
});
sgml('</eqnarray>', sub{
    $tabdepth--;  # Is this necessary?
    my $os = "";
    $os = $os . "</eqnarray>";
    output($os);
    $eqnamode = 0; # to be sure not to confuse equation handling
    $emath = 0;
    $gmath = 0;
    $eltdepth--;
});

sgml('<eqnabody>', sub{
    my ($elt, $ev) = @_;
    my $pos = pop_output; # popped output from '<eqnarray>' (opentag)
    if($pos ne ""){
	print STDERR "xmlgart.pl WARNING:\n",
	"   stray content in <eqnarray> before <eqnabody>\n";
    };
    my $par = $elt->parent;  # should be eqnarray
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $currserial[$eltdepth] = $eltser;
    my $os = "";
    my $thiseqkey = "";
    my $thiseqser = "";
    # Does the whole eqnarray get a label?
    if(($eqnamode%2 == 0) && ($eqnamode > 1)){
	if($eqnkey ne ""){
	    $thiseqkey = $eqnkey;
	}
	else{
	    $thiseqkey = $eqnautoprefix . $eqseq;
	};
	if($eqnser ne ""){
	    $thiseqser = $eqnser;
	}
	else{
	    $thiseqser = $eqnautoseries;
	};
	if($thiseqser ne ""){
	    prepare_label($thiseqkey, $thiseqser);
	    $os = $os . make_label($thiseqkey, "eqnarray", $thiseqser);
	};
    };
    $os = $os . "<eqnarray";
    my $atteqseq = $par->attribute("eqseq")->value;
    if(($atteqseq ne "") && ($atteqseq ne $eqseq)){
	print STDERR $WhoAmI, ": ** Replacing attribute-defined eqnarray seq id ",
	$atteqseq, " with actual serial value ", $eqseq, " at source line: ",
	$ev->line, "\n";
    };
    $os = $os . ' eqseq="' . $eqseq . '"';
    my $inv = $par->attribute("inv")->value;
    if($inv ne ""){
	$os = $os . ' inv="' . $inv . '"';
    };
    my $nonum = $par->attribute("nonum")->value;
    if(($nonum ne "") && ($nonum ne "false")){
	$os = $os . ' nonum="' . $nonum . '"';
    };
    # "mode" (0-7) is for formatters.  It is ignored if present in source.
    #   These 3 bits  may be used to deduce what was found in source for
    #     presence of eqnser, presence of eqnkey, presence of nonum.
    if(!($eqnamode == 0)){  # mode 0 is default behavior (label every row)
	$os = $os . ' mode="' . $eqnamode . '"';
    };
    $os = $os . ">";
    if($thiseqkey ne ""){
	$os = $os . "<eqnkey>" . $thiseqkey . "</eqnkey\n>";
    };
    if($thiseqser ne ""){
	$os = $os . "<eqnser>" . $thiseqser . "</eqnser\n>";
    };
    if($eqntag ne ""){
	$os = $os . "<eqntag>" . $eqntag . "</eqntag\n>";
    };
    $os = $os . "<eqnabody\n>";
    output($os);
});
sgml('</eqnabody>', sub{
    $eltdepth--;
    my $os = "";
    $os = $os . "</eqnabody>";
    output($os);
});

# Code for eqnrow needs to be duped for brk0
sgml('<eqnrow>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $currserial[$eltdepth] = $eltser;
    $eqseq++;
    $eqnlabel = "";
    $eqnacellseq = 0;
    $eqnintseries = "";
    push_output('string');
});
# Code for eqnrow needs to be duped for brk0
sgml('</eqnrow>', sub{
    my $pos = pop_output;
    my $os = "";
    my $thiseqkey = "";
    my $thiseqser = "";
    $os = $os. "<eqnrow\n>";
    if($eqnlabel ne ""){
	$os = $os . $eqnlabel;
    }
    elsif($eqnamode == 0){   # each eqnrow gets a tag
	$thiseqkey = $eqnintautoprefix . $eqseq;
	$thiseqser = $eqnintautoseries;
	prepare_label($thiseqkey, $thiseqser);
	$os = $os . make_label($thiseqkey, "eqnrow", $thiseqser);
    };
    $os = $os . $pos;
    $os = $os . "</eqnrow>";
    output($os);
    $eltdepth--;
});

sgml('<popkey>', sub{  # An empty
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $eltdepth--;
    my $os = "";
    $popkey = 1; # popkey was here
    if($lastuserlabel ne ""){
	$os = $lastuserlabel;
    }
    else{
	$os = 0;
    };
    output($os);
});
sgml('</popkey>', "");

# an empty
sgml('<eqs>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $eltdepth--;
    my $elt = $_[0];
    my $name = $elt->name;
    my $pan = $elt->parent->name;
    my $os = "";
    if($gmath == 1){
	$os = "<equals\n/>";
    }
    elsif($pan =~
	  /^(anchref|latexcommand|secnumdepth|urlanch|base|baseloc|.?label)$/){
	$os = "=";
    }
    elsif(($pan eq "op0") && ($oppar[$eltdepth] eq "anch")){
	$os = "=";
    }
    else{
	$os = "<" . "eqc" . "\n/>";
    };
    output($os);
});
sgml('</eqs>', "");

# an empty
sgml('<plu>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $eltdepth--;
    my $elt = $_[0];
    my $name = $elt->name;
    my $pan = $elt->parent->name;
    my $os = "";
    if($gmath == 1){
	$os = "<plus\n/>";
    }
    elsif($pan =~ /^(anchref|latexcommand|secnumdepth|urlanch|base|baseloc|.?label|.?ref|pageref)$/){
	$os = "+";
    }
    elsif(($pan eq "op0") && ($oppar[$eltdepth] eq "anch")){
	$os = "+";
    }
    else{
	$os = "<" . $name . "\n/>";
    };
    output($os);
});
sgml('</plu>', "");

# an empty
sgml('<hyp>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $eltdepth--;
    my $elt = $_[0];
    my $name = $elt->name;
    my $pan = $elt->parent->name;
    my $os = "";
    if($pan =~ /^(anchref|latexcommand|secnumdepth|urlanch|base|baseloc|.?label|.?ref|pageref|bibkey|citekey|cite)$/){
	$os = "-";
    }
    elsif(($pan eq "op0") && ($oppar[$eltdepth] =~ /^(anch|bibhead|equation|eqnarray)$/)){
	$os = "-";
    }
    elsif(($pan eq "ag0") && ($agpar[$eltdepth] =~ /^(bibhead|cite)$/)){
	$os = "-";
    }
    elsif(($gmath == 1) && ($pan ne "mbox") && ($elt->within("text") eq "")
	  && ($pan ne "regch") && ($pan ne "label")){
	$os = "<minus\n/>";
    }
    else{
	$os = "<" . $name . "\n/>";
    };
    output($os);
});
sgml('</hyp>', "");

# an empty
sgml('<sol>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $eltdepth--;
    my $elt = $_[0];
    my $name = $elt->name;
    my $pan = $elt->parent->name;
    my $os = "";
    if(($gmath == 1) && ($pan ne "mbox") && ($elt->within("text") eq "")){
	$os = "<quotient\n/>";
	if(($pan eq "csep")
	   || (($pan eq "op0") && ($oppar[$eltdepth] eq "vect"))){
	    $os = "<sol\n/>";
	};
    }
    elsif($pan =~
	/^(anchref|latexcommand|secnumdepth|urlanch|base|baseloc|.?label|)$/){
	$os = "/";
    }
    elsif(($pan eq "op0") && ($oppar[$eltdepth] eq "anch")){
	$os = "/";
    }
    else{
	$os = "<" . $name . "\n/>";
    };
    output($os);
});
sgml('</sol>', "");

# an empty
sgml('<atc>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $eltdepth--;
    my $elt = $_[0];
    my $name = $elt->name;
    my $pan = $elt->parent->name;
    my $os = "";
    if($pan =~ /^(anchref|latexcommand|secnumdepth|urlanch|.?label|.?ref|pageref|tabarg|arrcols)$/){
	$os = "@";
    }
    elsif(($pan eq "ag0") && ($agpar[$eltdepth] =~ /^(table|tabular|tabuhead|array|arrhead)/)){
	$os = "@";
    }
    elsif(($pan eq "op0") && ($oppar[$eltdepth] eq "anch")){
	$os = "@";
    }
    else{
	$os = "<" . $name . "\n/>";
    };
    output($os);
});
sgml('</atc>', "");

# an empty
sgml('<exc>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $eltdepth--;
    my $elt = $_[0];
    my $name = $elt->name;
    my $pan = $elt->parent->name;
    my $os = "";
    if($pan =~ /^(anchref|latexcommand|secnumdepth|urlanch|.?label)$/){
	$os = "!";
    }
    elsif(($pan eq "op0") && ($oppar[$eltdepth] eq "anch")){
	$os = "!";
    }
    else{
	$os = "<" . $name . "\n/>";
    };
    output($os);
});
sgml('</exc>', "");

sgml('<sup>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $currserial[$eltdepth] = $eltser;
    $agseq[$eltser] = 0;
    $opseq[$eltser] = 0;
    push_output('string');
});
sgml('</sup>', sub{
    $eltdepth--;
    my $pos = pop_output;
    my $elt = $_[0];
    my $name = $elt->name;
    my $pan = $elt->parent->name;
    if($gmath == 1){
	$name = "pow";
	if($pan =~ /^(sum|int|prod)$/){
	    $sipsupseq[$sipdepth]++;
	    if($sipsupseq[$sipdepth] == 1){
		$name = "msup";
	    };
	};
    };
    my $os = "<" . $name . "\n>" . $pos . "</" . $name . ">";
    output($os);
});

sgml('<sub>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $currserial[$eltdepth] = $eltser;
    $agseq[$eltser] = 0;
    $opseq[$eltser] = 0;
    push_output('string');
});
sgml('</sub>', sub{
    $eltdepth--;
    my $pos = pop_output;
    my $elt = $_[0];
    my $name = $elt->name;
    if($gmath == 1){
	$name = "msub";
	if($pan =~ /^(sum|int|prod)$/){
	    $sipsubseq[$sipdepth]++;
	};
    };
    my $os = "<" . $name . "\n>" . $pos . "</" . $name . ">";
    output($os);
});

sgml('<tabular>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $currserial[$eltdepth] = $eltser;
    $agseq[$eltser] = 0;
    $opseq[$eltser] = 0;
    $tabdepth++;
    $taburowflag[$tabdepth] = 0;
});
sgml('</tabular>', sub{
    output("</table\n>");
    $tabdepth--;
    $eltdepth--;
});

sgml('<tabuhead>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    push_output('string');
    $tabuhline[$tabdepth] = 0;
});
sgml('</tabuhead>', sub{
    my $pos = pop_output;
    my $os = "<table\n>";
    $os = $os . $pos;
    my $nhlines = $tabuhline[$tabdepth];
    if($nhlines > 0){
	my $hos = "";
	while($nhlines > 0){
	    $hos = $hos . "<trule\n/>";
	    $nhlines--;
	};
	$os = $os . $hos;
	$tabuhline[$tabdepth] = 0;
    };
    output($os);
    $eltdepth--;
});

sgml('<tabubody>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
});
sgml('</tabubody>', sub{
    my $os = "";
    my $nhlines= $tabuhline[$tabdepth];
    if($nhlines > 0){
	my $hos = "";
	while($nhlines > 0){
	    $hos = $hos . "<trule\n/>";
	    $nhlines--;
	};
	$tabuhline[$tabdepth] = 0;
	$os = $os . $hos;
    };
    output($os);
    $eltdepth--;
});

sgml('<taburow>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $currserial[$eltdepth] = $eltser;
    $taburowflag[$tabdepth] = 1;
});
sgml('</taburow>', sub{
    $taburowflag[$tabdepth] = 0;
    $eltdepth--;
    output("</tr\n>");
});

# brk0 is created when the string "\\" appears followed by white space
#    in GELLMU source.  It's content in SGML is "(firstcell,(tabampcell)*)",
#    which is identical to the content model for "taburow".
#    Both "firstcell" and "tabampcell" are allowed to be empty, and
#    none of "brk0", "firstcell", tabampcell", and "taburow" are required
#    to have open or close tags (except for the standard rule in SGML
#    about when an opentag can be omitted, i.e., only where it is required).
#    So "brk0" can be defacto empty.
#
# The meaning for "article" XML of "brk0" and friends depends on the parent
#    of "brk0" as follows:
#
#      Parent         Meaning of "brk0"       Meaning of "firstcell"
#
#      tabubody          taburow                (real) firstcell
#      tabampcell        taburow                (real) firstcell
#      firstcell         taburow                (real) firstcell
#      verblist          nln                    contains nln content    
#      addr              aln                    contains aln content
#      arraybody         arrayrow               firstacell
#      matrix            mxrow                  firstacell
#      eqnabody          eqnrow                 eqnleft
#      [other]           brk [an empty]         [nil]
#
# The content of "brk0" is not pushed, though the content of "firstcell"
# is pushed, except when its parent is "arrbody" or "eqnabody".
#
# Please note that the contents of "verlist" must be safe, not raw
# verbatim.  However, the front "gellmu-verblist" for "gellmu-trans" will
# convert a raw section "\n\\begin{verbatim}\n . . . \n\\end{verbatim}\n"
# to a "verblist" automatically.  (With "gellmu-verblist" just use "\n"
# inside the raw zone for a newline.  Do not use "\\" there for a newline.
#
# GELLMU also has a regular pre-historic "verbatim", whose contents must
# also be safe, that should not be confused with "verblist".  The use of
# "verblist" is recommended.
#
# See also the code for "firstcell" below.
#
sgml('<brk0>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    my $pan = $_[0]->parent->name;
    if($pan =~ /^(tabubody|verblist|addr)$/){
	;
    }
    #  this next branch should not occur
    # elsif(($tabdepth > 0) && (($pan eq "firstcell")
    #         || ($pan eq "tabampcell"))){
    #       output("</td></tr\n>");
    #  }
    elsif($pan eq "arrbody"){
	push_output('string');
    }
    elsif($pan eq "eqnabody"){  # cf. code for eqnrow
	$eqseq++;
	$eqnacellseq = 0;
	$eqnlabel = "";
	$eqnintseries = "";
	push_output('string');
    }
    else{
	output("<brk\n/> ");
    };
});
sgml('</brk0>', sub{
    my $pan = $_[0]->parent->name;
    if(($pan eq "tabubody")&($taburowflag[$tabdepth] == 1)){
	$taburowflag[$tabdepth] = 0;
	output("</tr\n>");
    }
    elsif($pan eq "arrbody"){
	my $os = "";
	my $pos = pop_output;
	$os = $os . "<arrayrow\n>" . $pos . "</arrayrow>";
	output($os);
    }
    elsif($pan eq "eqnabody"){
	my $pos = pop_output;
	my $os = "";
	my $thiseqkey = "";
	my $thiseqser = "";
	$os = $os . "<eqnrow\n>";
	if($eqnlabel ne ""){
	    $os = $os . $eqnlabel;
	}
	elsif($eqnamode == 0){   # each eqnrow gets a tag
	    $thiseqkey = $eqnintautoprefix . $eqseq;
	    $thiseqser = $eqnintautoseries;
	    prepare_label($thiseqkey, $thiseqser);
	    $os = $os . make_label($thiseqkey, "eqnrow", $thiseqser);
	};
	$os = $os . $pos;
	$os = $os . "</eqnrow\n>";
	output($os);
    };
    $eltdepth--;
});

#  firstcell: This can appear strangely when "\\" is used in source as
#             forced newline inasmuch as it is the required first element
#             of "brk0".  Its parent can be either "brk0" or "taburow".
#             Possible grandparent values include: "tabubody", "verblist",
#             "addr", and, because of shadowing, "firstcell" or "tabampcell".
#
sgml('<firstcell>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    my $par = $_[0]->parent;
    my $pan = $par->name;
    my $gpan=$par->parent->name;
    # if following brk usage of brk0, leave no trace
    unless($gpan =~ /^(tabubody|arrbody|eqnabody|matrix|verblist|addr)$/){
	return;
    };
    if($gpan eq tabubody){
	$taburowflag[$tabdepth] = 1;
    };
    push_output('string');
});
sgml('</firstcell>', sub{
    my $os = "";
    my $par = $_[0]->parent;
    my $pan = $par->name;
    my $gpan = $par->parent->name;
    # if following brk usage of brk0, leave no trace
    unless($gpan =~ /^(tabubody|arrbody|eqnabody|matrix|verblist|addr)$/){
	$eltdepth--;
	return;
    };
    my $pos = pop_output;
    $pos =~ s/^\s+//;
    $pos =~ s/\s+$//;
    if($gpan eq "tabubody"){
	if((($pan eq "brk0")||($pan eq "taburow")) && ($tabdepth > 0)){
	    $tabaseq[$tabdepth] = 1;
	    my $jj = $tabaseq[$tabdepth];
	    if($tabasym[$tabdepth][$jj] eq "p"){
		$tdname[$tabdepth] = "tdp";
	    }
	    else{
		$tdname[$tabdepth] = "tdr";
	    };
	    my $openit = "<tr><" . $tdname[$tabdepth] . ">";
	    my $closeit = "</" . $tdname[$tabdepth] . ">";
	    my $nhlines = $tabuhline[$tabdepth];
	    if($nhlines > 0){
		my $hos = "";
		while($nhlines > 0){
		    $hos = $hos . "<trule\n/>";
		    $nhlines--;
		}
		$os = $hos . $os;
		if($tabuhline[$tabdepth] > 0){
		    if($pos ne ""){
			$os = $os . $openit . $pos . $closeit;
			# $os = $os . "<tr><td>" . $pos . "</td>";
		    }
		    else{
			$taburowflag[$tabdepth] = 0;
			# Maybe there is no actual row here
			# reset this if there is a subsequent tabucell
			# and generate an empty firstcell
		    };
		}
		$tabuhline[$tabdepth] = 0;
	    }
	    else{
		$os = $os . $openit . $pos . $closeit;
		# $os = $os . "<tr><td>" . $pos . "</td>";
	    };

	};
    }
    elsif(($pan eq "eqnrow")||(($pan eq "brk0")&&($gpan eq "eqnabody"))){
	$eqnacellseq++;
	$os = "<eqnleft>" . $pos . "</eqnleft\n>";
    }
    elsif($pan eq "mxrow"){
	$os = "<firstmcell>" . $pos . "</firstmcell\n>";
    }
    elsif(($pan eq "arrayrow")||(($pan eq "brk0")&&($gpan eq "arrbody"))){
	$os = "<firstacell>" . $pos . "</firstacell\n>";
    }
    elsif($gpan eq "verblist"){
	$os = "<nln>" . $pos . "</nln\n>";
    }
    elsif($gpan eq "addr"){
	$os = "<aln>" . $pos . "</aln\n>";
    }
    else{
	$os = $pos;
    };
    output($os);
    $eltdepth--;
});

sgml('<tabampcell>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    my $os = "";
    my $par = $_[0]->parent;
    my $pan = $par->name;
    my $gpan = $par->parent->name;
    if(($pan eq "eqnrow") || (($pan eq "brk0") && ($gpan eq "eqnabody"))){
	$eqnacellseq++;
	if($eqnacellseq == 2){
	    $os = $os . "<eqncenter>";
	}
	elsif($eqnacellseq == 3){
	    $os = $os . "<eqnright>";
	}
	elsif($eqnacellseq == 4){
	    $os = $os . "<tag>";
	}
	else{
	    print STDERR "xmlgart.pl WARNING: incorrect value ",
	    $eqnacellseq, " of eqnacellseq, eqseq = ", $eqseq ,"\n";
	};
    }
    elsif($pan eq "mxrow"){
	$os = $os . "<mxcell>";
    }
    elsif(($pan eq "arrayrow") || (($pan eq "brk0")&&($gpan eq "arrbody"))){
	$os = $os . "<arraycell>";
    }
    else{  # tabular cell
	if(($taburowflag[$tabdepth] == 0)&&($pan eq "taburow")){
	    # first cell was empty but for hlines and row was not begun
	    $os = "<tr>";
	    $tabaseq[$tabdepth] = 1;
	    my $jj = $tabaseq[$tabdepth];
	    if($tabasym[$tabdepth][$jj] eq "p"){
		$tdname[$tabdepth] = "tdp";
	    }
	    else{
		$tdname[$tabdepth] = "tdr";
	    };
	    $os = $os . "<" . $tdname[$tabdepth] . "></"
		. $tdname[$tabdepth] . ">";
	    $taburowflag[tabdepth] = 1;
	};
	$tabaseq[$tabdepth]++;
	my $jj = $tabaseq[$tabdepth];
	if($tabasym[$tabdepth][$jj] eq "p"){
	    $tdname[$tabdepth] = "tdp";
	}
	else{
	    $tdname[$tabdepth] = "tdr";
	};
	$os = $os . "<" . $tdname[$tabdepth] . ">";
    };
    output($os);
    push_output('string');
});
sgml('</tabampcell>', sub{
    my $os = pop_output;
    $os =~ s/^\s+//;
    $os =~ s/\s+$//;
    my $par = $_[0]->parent;
    my $pan = $par->name;
    my $gpan = $par->parent->name;
    if(($pan eq "eqnrow") || (($pan eq "brk0") && ($gpan eq "eqnabody"))){
	if($eqnacellseq == 2){
	    $os = $os . "</eqncenter\n>";
	}
	elsif($eqnacellseq == 3){
	    $os = $os . "</eqnright\n>";
	}
	elsif($eqnacellseq == 4){
	    $os = $os . "</tag>";
	}
	else{
	    print STDERR "xmlgart.pl WARNING: incorrect value ",
	    $eqnacellseq, " of eqnacellseq, eqseq = ", $eqseq ,"\n";
	};
    }
    elsif($pan eq "mxrow"){
	$os = $os . "</mxcell\n>";
    }
    elsif(($pan eq "arrayrow") || (($pan eq "brk0")&&($gpan eq "arrbody"))){
	$os = $os . "</arraycell\n>";
    }
    else{  # tabular cell
	$os = $os . "</" . $tdname[$tabdepth] . ">";
    };
    output($os);
    $eltdepth--;
});

sgml('<hline>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $eltdepth--;
    my $pan = $_[0]->parent->name;
    if($pan =~ /^(tabuhead|firstcell|tabampcell)$/){
	$tabuhline[$tabdepth]++;
    }
    else{
	print STDERR "Error: hline not in tabular";
    };
});
sgml('</hline>', "");


sgml('<vbr>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $eltdepth--;
    my $elt = $_[0];
    my $name = $elt->name;
    my $pan = $elt->parent->name;
    my $os = "";
    if($pan =~ /^(anchref|latexcommand|secnumdepth|urlanch|.?label|.?ref|pageref|tabarg|arrcols)$/){
	$os = "|";
    }
    elsif(($pan eq "ag0") && ($agpar[$eltdepth] =~ /^(table|tabular|tabuhead|array|arrhead)/)){
	$os = "|";
    }
    elsif(($pan eq "op0") && ($oppar[$eltdepth] eq "anch")){
	$os = "|";
    }
    else{
	$os = "<" . $name . "\n/>";
    };
    output($os);
});
sgml('</vbr>', "");
sgml('<vbr0>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $eltdepth--;
output("<vbr\n/>");
});

sgml('<lbr>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $eltdepth--;
    my $elt = $_[0];
    my $name = $elt->name;
    my $pan = $elt->parent->name;
    my $os = "";
    if($pan =~ /^(tabarg|arrcols)$/){
	$os = "{";
    }
    elsif(($pan eq "ag0") && ($agpar[$eltdepth] =~ /^(table|tabular|tabuhead|array|arrhead)/)){
	$os = "{";
    }
    else{
	$os = "<" . $name . "\n/>";
    };
    output($os);
});
sgml('</lbr>', "");

sgml('<rbr>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $eltdepth--;
    my $elt = $_[0];
    my $name = $elt->name;
    my $pan = $elt->parent->name;
    my $os = "";
    if($pan =~ /^(tabarg|arrcols)$/){
	$os = "}";
    }
    elsif(($pan eq "ag0") && ($agpar[$eltdepth] =~ /^(table|tabular|tabuhead|array|arrhead)/)){
	$os = "}";
    }
    else{
	$os = "<" . $name . "\n/>";
    };
    output($os);
});
sgml('</rbr>', "");

sgml('<hsf>', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $eltdepth--;
output("<hsf\n/>");
});
sgml('</hsf>', "");

sgml('<sqrt>', sub{
    push_output('string');
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $currserial[$eltdepth] = $eltser;
    $agseq[$eltser] = 0;
    $opseq[$eltser] = 0;
    $sqrtdepth++;
    $radicflag[$sqrtdepth] = 0;
});
sgml('</sqrt>', sub{
    my $pos = pop_output;
    my $os = "";
    if($radicflag[$sqrtdepth] == 0){
	$os = "<sqrt\n><radicand\n>" . $pos . "</radicand\n></sqrt\n>";
    }
    else{
	$os = "<sqrt\n>" . $pos . "</sqrt\n>";
    };
    output($os);
    $sqrtdepth--;
    $eltdepth--;
});

sgml('<documentclass>', sub{
    push_output('string');
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $currserial[$eltdepth] = $eltser;
    $agseq[$eltser] = 0;
    $opseq[$eltser] = 0;
    $autoname = 1;  # for anonymous elements dstyle, dclass
});
sgml('</documentclass>', sub{
    my $pos = pop_output;
    my $os = "";
    my $myser = $currserial[$eltdepth];
    if(($autoname > 1)||($agseq[$myser] > 0)){
	$os = "<documentclass\n>" . $pos . "</documentclass\n>";
    }
    else{
	$os = "<documentclass\n><dclass\n>" . $pos .
	    "</dclass\n></documentclass\n>";
    };
    output($os);
    $eltdepth--;
    $autoname = 0;
});

sgml('<ag0>', sub{
    my $parentser = $currserial[$eltdepth];
    $agseq[$parentser]++;
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $currserial[$eltdepth] = $eltser;
    $agseq[$eltser] = 0;
    $opseq[$eltser] = 0;
    $agpar[$eltdepth] = $_[0]->parent->name;
    push_output('string');
});
sgml('</ag0>', sub{
    $eltdepth--;
    my $parentser = $currserial[$eltdepth];
    my $pos = pop_output;
    my $agname = "";
    my $os = "";
    my ($elt, $ev) = @_;
    my $pan = $elt->parent->name;
    if($pan eq "frac"){
	if($agseq[$parentser] == 1){
	    $agname = "numr";
	}
	elsif($agseq[$parentser] == 2){
	    $agname = "denm";
	}
	else{
	    print STDERR "ERROR: Too many arguments for frac";
	};
    }
    elsif($pan eq "binom"){
	if($agseq[$parentser] == 1){
	    $agname = "binu";
	}
	elsif($agseq[$parentser] == 2){
	    $agname = "binl";
	}
	else{
	    print STDERR "ERROR: Too many arguments for binom";
	};
    }
    elsif($pan eq "mscript"){
	if($agseq[$parentser] == 1){
	    $agname = "expr";
	}
	elsif($agseq[$parentser] == 2){
	    $agname = "uleft";
	}
	elsif($agseq[$parentser] == 3){
	    $agname = "lleft";
	}
	elsif($agseq[$parentser] == 4){
	    $agname = "lright";
	}
	elsif($agseq[$parentser] == 5){
	    $agname = "uright";
	}
	else{
	    print STDERR $WhoAmI, ': ERROR -- Too many args (',
	    $agseq[$parentser] , ') for mscript at line ', $ev->line, "\n";
	};
    }
    elsif($pan eq "setOf"){
	if($agseq[$parentser] == 1){
	    $agname = "parm";
	}
	elsif($agseq[$parentser] == 2){
	    $agname = "cond";
	}
	else{
	    print STDERR $WhoAmI, ': ERROR -- Too many args (',
	    $agseq[$parentser], ') for setOf at line ', $ev->line, "\n";
	};
    }
    elsif($pan =~ /^(overset|underset)$/){
	if($agseq[$parentser] == 1){
	    $agname = "deco";
	}
	elsif($agseq[$parentser] == 2){
	    $agname = "expr";
	}
	else{
	    print STDERR $WhoAmI, ': ERROR -- Too many args (',
	    $agseq[$parentser], ") for $pan at line ", $ev->line, "\n";
	};
    }
    elsif($pan eq "assthead"){
	$agname = "asstname";
	$asstname = $pos;
	my $myasstkey = "";
	my $myasstser = "";
	if($asstkey ne ""){
	    $myasstkey = $asstkey;
	}
	else{
	    $myasstkey = $asstlabelprefix . $asstseq;
	};
	if($asstser ne ""){
	    $myasstser = $asstser;
	}
	else{
	    $myasstser = "AssertDefault";
	};
	prepare_label($myasstkey, $myasstser);
	$os = make_label($myasstkey, "assertion", $myasstser);
	$os = $os . "<assertion";
	if($asststyle ne ""){
	    $os = $os . ' style="' . $asststyle . '"';
	    $asststyle = "";  # re-initialize
	};
	$os = $os . "><assthead>";
	$os = $os . "<asstkey>" . $myasstkey . "</asstkey\n>";
	$os = $os . "<asstser>" . $myasstser . "</asstser\n>";
	$os = $os . "<asstname>" . $asstname . "</asstname\n>";
	# Feed popkey just to be sure.
	if($lastuserlabel eq ""){
	    $lastuserlabel = $myasstkey;
	};
	output($os);
	return;
    }
    elsif($pan eq "documentclass"){
	$agname = "dclass";
    }
    elsif($pan eq "cite"){
	$agname = "citekey";
	$havecitekey = 1;
	$citekey = $pos;
	return;
    }
    elsif($pan eq "sqrt"){
	$agname = "radicand";
	$radicflag[$sqrtdepth] = 1;
    }
    elsif($pan eq "bibhead"){
	$agname = "bibkey";
	$bibkey = $pos;
	return;
    }
    elsif($pan =~ /^($AllSecs)$/){
	# This ag0 stands in for shead
	$os = "";
	$shead = $pos;  # needs to be saved for contents aux file
	my $oshead;     # what is output in new <shead>

    # Compute secunit
	if($secdepth <= $secnumdepth){
	    if($sunitflag != 0){
		if(($sunit eq "")||($sunit == -1)){
		    my $tkey = $lastuserlabel;
		    if(($tkey ne "")&&($labelseq{tkey} != 0)){
			$secunit[$secdepth] = $labelseq{$tkey};
		    }
		    else{
			$secunit[$secdepth] = -2;
		    };
		}
		else{
		    $secunit[$secdepth] = $sunit;
		};
	    }
	    elsif($secunit[$secdepth-1] ne ""){
		$secunit[$secdepth] = $secunit[$secdepth-1] . "."
		    . $secser[$secdepth];
	    }
	    else{
		$secunit[$secdepth] = $secsid[$secdepth];
	    };
	}
	else{
	    $secunit[$secdepth] = "";
	};

    # Write sprefix and sunit
	if($sprefix ne ""){
	    $os = $os ."<sprefix>". $sprefix ."</sprefix\n>";
	};
	if($secunit[$secdepth] ne ""){
	    if($sunitflag != 0){
		$os = $os ."<sunit>". $secunit[$secdepth] ."</sunit\n>";
	    }
	    else{
		$os = $os ."<sunit>". "&$srefname;" ."</sunit\n>";
	    }
	};
	if(($secunit[$secdepth] ne "")&&($secunit[$secdepth] != -2)){
	    $thissecunit = $secunit[$secdepth];
	    if($lgents != 0){
		print FGENTS "<!ENTITY $srefname \"$thissecunit\">\n";
	    };
	};
	$os = $os . "<shead\n>";

    # Handle stored user labels
	if($labelhold ne ""){
	    print STDERR "xmlgart.pl: logical error --",
	    " global use of labelhold\n", "  Contents: \"", $labelhold, "\"\n";
	    $labelhold = "";
	};
	if($labelinshead > 0){
	    my $jl = 1;
	    while($jl <= $labelinshead){
		my $compact = $sheadlabel[$jl];
		$labelhold = $labelhold . make_label($compact);
		$jl++;
	    };
	};

    # Automatic sectional label and contents line
	if(($seckey ne "") && ($secdepth <= $tocdepth)){
	    if($lgcnt != 0){
		my $cntline = make_cntline();
		print FGCNT $cntline;
	    };
	    prepare_label($seckey);
	    $os = $os . make_label($seckey, $pan);
	};

    # Wrap up the new <shead>
	$oshead = $labelhold . $shead;
	$labelhold = "";   # while left global
	$os = $os . $oshead . "</shead>";
	output($os);
	return;
    }
    elsif($pan =~ /^($allsecs)$/){
	$shead = $pos;
	return;
    }
    elsif(($pan =~ /[Tt]abular/)||($pan =~ /[Tt]able/)||($pan eq "tabuhead")){
	$agname = "tabarg"; # for "table" in output
	$tabarg[$tabdepth] = $pos;
	my @tbargv = split(//, $tabarg[$tabdepth]);
	my $len = scalar @tbargv;
	my $jj = 0;
	my $kk = 0;
	while($jj < $len){
	    if($tbargv[$jj] =~ /[clpr]/){
		$kk++;
		$tabasym[$tabdepth][$kk] = $tbargv[$jj];
	    };
	    $jj++;
	};
	$tabalen[$tabdepth] = $kk;
	my $os = "<tabarg\n>" . $tabarg[$tabdepth] . "</tabarg>";
	output($os);
	return;
    }
    elsif($pan eq "arrhead"){
	$agname = "arrcols";
    }
    elsif($pan eq "anch"){
	$agname = "anchv";
    }
    elsif($pan eq "ftanch"){
	$agname = "ftanchv";
    }
    elsif($pan eq "alabel"){
	$agname = "anchv";
    }
    elsif($pan eq "vect"){
	$agname = "coord";
    }
    else{
	print STDERR "xmlgart.pl WARNING: Unknown argument (ag0) in ",
	$pan, "\n";
	$agname = "UnKnownArgument";
    };
    $os = "<" . $agname . "\n>" . $pos . "</" . $agname . ">";
    output($os);
});

sgml('<op0>', sub{
    my $parentser = $currserial[$eltdepth];
    $opseq[$parentser]++;
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $currserial[$eltdepth] = $eltser;
    $agseq[$eltser] = 0;
    $opseq[$eltser] = 0;
    $oppar[$eltdepth] = $_[0]->parent->name;
    push_output('string');
});
sgml('</op0>', sub{
    $eltdepth--;
    my $parentser = $currserial[$eltdepth];
    my $pos = pop_output;
    my $opname = "";
    my $opattrs = "";
    my $os = "";
    my $elt = $_[0];
    my $pan = $elt->parent->name;
    if($pan eq "documentclass"){
	$opname = "dstyle";
    }
    elsif($pan eq "vect"){
	$opname = "csep";
    }
    elsif($pan eq "cite"){
	$opname = "citenote";
	$citenote = $pos;
	return;
    }
    elsif($pan eq "sqrt"){
	$opname = "radx";
    }
    elsif($pan eq "bibhead"){
	$opname = "biblabel";
	$biblabel = $pos;
	return;
    }
    elsif($pan eq "item"){
	my $gpan = $_[0]->parent->parent->name;
	if($gpan =~ /^(description|booklist)$/){
	    $os = "<itemlabel" . $opattrs . "\n>" . $pos
		. "</itemlabel\n>";
	    output($os);
	    return;
	}
	else{
	    $opname = "itemlabel";
	};
    }
    elsif($pan eq "eqnarray"){
	if($opseq[$parentser] == 1){
	    $opname = "eqnkey";
	    $eqnamode += 2;  # to 2 or 3
	    $eqnkey = $pos;
	    return;
	}
	elsif($opseq[$parentser] == 2){
	    $opname = "eqnser";
	    $eqnamode += 4;  # to 4, 5, 6, or 7
	    $eqnser = $pos;
	    return;
	}
	elsif($opseq[$parentser] == 3){
	    $opname = "eqntag";
	    $eqntag = $pos;
	    return;
	}
	else{
	    print STDERR "xmlgart WARNING: incorrect value of opseq in ",
	    $pan, " eqn sequence = ", $eqseq, "\n";
	};
    }
    elsif($pan eq "equation"){
	if($opseq[$parentser] == 1){
	    $opname = "eqnkey";
	    $eqnkey = $pos;
	    return;
	}
	elsif($opseq[$parentser] == 2){
	    $opname = "eqnser";
	    $eqnser = $pos;
	    return;
	}
	elsif($opseq[$parentser] == 3){
	    $opname = "eqntag";
	    $eqntag = $pos;
	    return;
	}
	else{
	    print STDERR "xmlgart WARNING: incorrect value of opseq in ",
	    $pan, " eqn sequence = ", $eqseq, "\n";
	};
    }
    elsif($pan eq "assthead"){
	if($agseq[$parentser] > 0){
	    $opname = "asstid";
	    $asstid = $pos;
	}
	else{
	    if($opseq[$parentser] == 1){
		$opname = "asstkey";
		$asstkey = $pos;
	    }
	    elsif($opseq[$parentser] == 2){
		$opname = "asstser";
		$asstser = $pos;
	    }
	    else{
		print STDERR "xmlgart.pl WARNING: Element $pan (ser. ",
		$parentser, "): Incorrect calling sequence\n";
	    };
	};
	return;
    }
    elsif($pan =~ /^($allsecs|$AllSecs)$/){
	if($opseq[$parentser] == 1){
	    $sopt = $pos;
	}
	elsif($opseq[$parentser] == 2){
	    $sprefix = $pos;
	}
	elsif($opseq[$parentser] == 3){
	    $sunitflag = 1;
	    $sunit = $pos;
	}
	else{
	    print STDERR "xmlgart.pl WARNING: Element $pan (ser. ",
              $parentser, "): too many option tags -- $opseq[$parentser]\n";
	};
	return;
    }
    elsif(($pan =~ /[Tt]abular/) || ($pan =~ /[Tt]able/)
                 || ($pan =~ /[Mm]atrix/)){
	$opname = "tabopt";
    }
    elsif($pan eq "anch"){
	$opname = "anchref";
    }
    elsif($pan eq "ftanch"){
	$opname = "ftancht";
    }
    elsif($pan eq "alabel"){
	$opname = "intref";
    }
    else{
	print STDERR "xmlgart.pl WARNING: Unknown option (op0) in ",
	$pan, "\n";
	$opname = "UnKnownOption";
    };
    $os = "<" . $opname . $opattrs . "\n>" . $pos . "</" . $opname . ">";
    output($os);
});

#
# Generic Element Handlers.
#
sgml('start', sub{
    $eltdepth = 0;
    $minsecdepth = 1;   # the value for article
    $secdepth++;               # At this time do not have explicit "parts"
    $secser[$secdepth]++;      # Presumably the sole part
    $secser[1+$secdepth] = 0;  # No section yet
    $secname[0] = "";   # reserved
    $secname[1] = "";   # Section or section
    $secname[2] = "";   # Subsection or subsection
    $secname[3] = "";   # Subsubsection or subsubsection
    $secname[4] = "";   # Paragraph or paragraph
    $secname[5] = "";   # Subparagraph or subparagraph
    $secname[6] = "";   # reserved
    my $jj = 0;
    while($jj <= $maxsecdepth){
	$attsidflag[$jj] = 0;
	$jj++;
    };
    my $os = "";
    $os = $os . "<?xml version=\"1.0\" encoding=\"" . $encoding . "\"?>\n";
    $os = $os . "<?xml-stylesheet type=\"text/css\"\n";
    $os = $os . "   href=\"" . $cssurl . "\"?>\n";
    $os = $os . "<!DOCTYPE article\n  PUBLIC \"" . $dtdfpi . "\"\n  \""
              . $dtdurl . "\"";
    output($os);
});
sgml('end', sub{
    if (!($eltdepth == 0)){
	print STDERR "WARNING: Coding error in sgmlspl file: ", $WhoAmI,
        "\n    eltdepth not balanced; ending with value ", $eltdepth, ".\n";
    };
    if($secdepth != 0){
	print STDERR "WARNING: Coding error in sgmlspl file: ", $WhoAmI,
        "\n    secdepth not balanced; ending with value ", $secdepth, ".\n";
    };
    if($tabdepth != 0){
	print STDERR "WARNING: Coding error in sgmlspl file: ", $WhoAmI,
        "\n    tabdepth not balanced; ending with value ", $tabdepth, ".\n";
    };
    if($sipdepth != 0){
	print STDERR "WARNING: Coding error in sgmlspl file: ", $WhoAmI,
        "\n    sipdepth not balanced; ending with value ", $sipdepth, ".\n";
    };
    print STDERR "  No. of elts.: ", $eltser,
                 "; max elt. depth ", $maxeltdepth, "\n";
    output("\n");
});

sgml('start_element', sub{
    $eltser++;
    $eltdepth++;
    if($maxeltdepth < $eltdepth){$maxeltdepth = $eltdepth;};
    $currserial[$eltdepth] = $eltser;
    my ($element, $event) = @_;
    my $name = $element->name;
    my $oname = $name;
    my $os = "";
#
#  We may need to close one of Section, Subsection, ... in the XML output
#  in order to open the current element when the former arises from 
#  section, subsection, . . . and we have previously written Section,
#  Subsection, ... in the output from here.
#
#  So $os will be the concatenation of $close, empty for most things,
#  and $open.
#
    my $close = "";
    my $post = "";
    if(($name eq "trb") || ($name eq "trc")){
	$oname = "tr";
    };
    if(($name eq "tdb") || ($name eq "tdc")){
	$oname = "td";
    };
    if($name eq "taburow"){
	return;
    };
    my $open= "<" . $oname;
    my $osatt = "";
#    my $clcn = ">\n";
    my $clcm = "\n>";
    my $clc = $clcm;
    my @attn = ();
    my @atty = ();
    my @attv = ();
    my $jj = 0;
    my $nat = get_attributes($element, \@attn, \@atty, \@attv);
    if($nat > 0){
	$jj = 0;
	while($jj < $nat){
	    if($atty[$jj] =~ /CDATA/){
	    };
	    if(($atty[$jj] =~ /CDATA|IMPLIED|TOKEN/ ) && ($attv[$jj] ne "")){
		#  This next line wrongly had $gmath == 0:  060116
		if(!(($gmath == 1) &&
                     (($attn[$jj] eq "mml") || ($attn[$jj] eq "mtype")))){
		    $osatt = $osatt . " " . $attn[$jj] 
                                    . '="' . $attv[$jj] . '"';
		    if($name eq "assertion"){
			# <assertion> output is deferred
			if(($attn[$jj] eq "style") && ($attv[$jj] ne "")){
			    $asststyle = $attv[$jj];
			};
		    };
		}
	    };
	    $jj++;
	};
    };
    if($element->defempty){
	if( ($name eq "nul") && ($pan eq "mathsym") ){
	    return;
	};
#	$clcn = " />\n";
	$clcm = "\n/>";
	$clc = $clcm;
    }
    else{
	$agseq[$eltser] = 0;
	$opseq[$eltser] = 0;
	if($name eq "article"){
	    # article has no other attributes to consider
	    $osatt = "";
	    my $stem = $_[0]->attribute("stem")->value;
	    if($stem ne ""){
		$stemname = $stem;
		# my $stempat = "^.*/";
		# $stemname =~ s/$stempat//;
		$osatt = " stem=\"" . $stemname . "\"";
		$fgcnt = ">" . $stemname . ".xcn";
		$fgents = ">" . $stemname . ".xet";
		$fglbl = ">" . $stemname . ".xlb";
		$lgcnt = open(FGCNT, $fgcnt);
		if($lgcnt == 0){
		    print STDERR "xmlgart.pl: Cannot open \"", $stemname,
                        ".xcn\" for output\n";
		};
		$lgents = open(FGENTS, $fgents);
		if($lgents == 0){
		    print STDERR "xmlgart.pl: Cannot open \"", $stemname,
		    ".xet\" for output\n";
		};
		$lglbl = open(FGLBL, $fglbl);
		if($lglbl == 0){
		    print STDERR "xmlgart.pl: Cannot open \"", $stemname,
                        ".xlb\" for output\n";
		};
	    }
	    else{
		print STDERR
         "xmlgart.pl WARNING: \"stem\" attribute of root element not found\n";
	    };
	    if(($intsubsetopen == 0) && (($lgcnt != 0)||($lgents != 0))){
		$close = $close . " \[\n";
		$intsubsetopen = 1;
	    };
	    if($lgcnt != 0){
		$close = $close . "<!ENTITY TableOfContentsFile SYSTEM \""
		    . $stemname . ".xcn\">\n";
		print FGCNT "<TableOfContents\n>";
	    }
	    if($lgents != 0){
		$close = $close . "<!ENTITY % ComputedEntitiesFile SYSTEM \""
		    . $stemname . ".xet\">\n";
		$close = $close . "%" . ComputedEntitiesFile . ";\n";
	    }
	    if($intsubsetopen == 1){
		$close = $close . "\]";
	    };
	    $close = $close . ">\n";
	}
	elsif($name =~ /^(eqnleft|eqncenter|eqnright)$/){
	    $eqnacellseq++;
	}
	elsif($name eq "eqnkey"){
	    push_output('string');
	    return;
	}
	elsif($name eq "eqnser"){
	    push_output('string');
	    return;
	}
	elsif($name eq "eqntag"){
	    push_output('string');
	    return;
	}
	elsif($name eq "assertion"){
	    # Need to put calculated label just before "<assertion>"
	    # May need to add code to catch attributes later.
	    return;
	}
	elsif($name eq "assthead"){
	    $asstseq++;
	    $asstkey = "";
	    $asstname = "";
	    $asstid = "";
	    $asstser = "";
	    $lastuserlabel = "";
	    push_output('string');
	    return;
	}
	elsif($name eq "asstkey"){
	    push_output('string');
	    return;
	}
	elsif($name eq "asstname"){
	    push_output('string');
	    return;
	}
	elsif($name eq "asstid"){
	    push_output('string');
	    return;
	}
	elsif($name eq "asstser"){
	    push_output('string');
	    return;
	}
	elsif($name eq "table"){
	    $tabdepth++;
	}
	elsif($name eq "tabarg"){
	    push_output('string');
	    return;
	}
	elsif($name eq "tr"){
	    $tabaseq[$tabdepth] = 0;
	}
	elsif($name eq "td"){
	    $tabaseq[$tabdepth]++;
	    my $jj = $tabaseq[$tabdepth];
	    if($jj > $tabalen[$tabdepth]){
		$jj = $tabalen[$tabdepth];
	    };
	    if($tabasym[$tabdepth][$jj] eq "p"){
		$oname = "tdp";
	    }
	    else{
		$oname = "tdr";
	    };
	    $os = "<" . $oname . $osatt . ">";
	    output($os);
	    return;
	}
	elsif($name eq "bibhead"){
	    $bibliseq++;
	    $bibkey = "";
	    $biblabel = "";
	    push_output('string');
	    return;
	}
	elsif($name eq "biblabel"){
	    push_output('string');
	    return;
	}
	elsif($name eq "bibkey"){
	    push_output('string');
	    return;
	}
	elsif($name eq "cite"){
	    $havecitekey = 0;
	    $citekey = "";
	    $citenote = "";
	    $citetext = "";
	    push_output('string');
	    return;
	}
	elsif($name eq "citekey"){
	    $havecitekey = 1;
	    push_output('string');
	    return;
	}
	elsif($name eq "citenote"){
	    push_output('string');
	    return;
	}
	elsif($name eq "tocdepth"){
	    ;
	}
	elsif($name eq "radicand"){
	    $radicflag[$sqrtdepth] = 1;
	}
	elsif($name =~ /^(sum|int|prod)$/){
	    $sipdepth++;
	    $sipsubseq[$sipdepth] = 0;
	    $sipsupseq[$sipdepth] = 0;
	}
	elsif($name =~ /^.?label$/){
	    push_output('string');
	    return;
	}
	elsif($name =~ /^(sopt|sprefix|sunit)$/){
	    push_output('string');
	    return;
	}
	elsif($name eq "item"){
	    my $pan = $_[0]->parent->name;
	    if($pan =~ /^(description|booklist)$/){
		$os = "<ditem" . $osatt . "\n>";
		output($os);
		return;
	    };
	}
	elsif($name eq "shead"){
	    push_output('string');
	    return;  # no output with <shead>
	}
	elsif($name =~ 
	      /^($AllSecs)$/){
	    $srefseq++;
	    $srefname = $srefprefix . $srefseq;
	    $seckey = "";
	    $thissecunit = -1;
	    if($secname[$secdepth] =~ /^($AllSecs)$/){
		$secdepth++;
	    }
	    else{
		my $nsdepth = 0;
		if($name eq "Section"){
		    $nsdepth = 1;
		}
		elsif($name eq "Subsection"){
		    $nsdepth = 2;
		}
		elsif($name eq "Subsubsection"){
		    $nsdepth = 3;
		}
		elsif($name eq "Paragraph"){
		    $nsdepth = 4;
		}
		elsif($name eq "Subparagraph"){
		    $nsdepth = 5;
		}
		else{
		    print STDERR $WhoAmI,
		    ": Coding error on nsdepth\n Name: ", $name, "\n";
		};
		while($secdepth >= $nsdepth){
		    $close = $close . "</" . $secref[$secdepth] . $clcm;
		    $secname[$secdepth] = "";
		    $secdepth--;
		};
		# taken to one less than section depth of current opentag
		$secdepth = $nsdepth;
		# new current value
	    };
	    $popkey = 0;
	    $shead = "";
	    $labelinshead = 0;
	    $sopt = "";
	    $sprefix = "";
	    $sunitflag = 0;
	    $secser[$secdepth]++;
	    $secname[$secdepth] = $name;
	    $secser[1+$secdepth] = 0;
	    if($xmlinput == 0){
		$osatt = $osatt . " depth=\"" . $secdepth . "\" seq=\""
		    . $secser[$secdepth] . "\"";
	    }
	    else{
		if($element->attribute("depth")->value != $secdepth){
		    print STDERR "xmlgart.pl: depth mismatch on $name\n";
		};
		if($element->attribute("seq")->value != $secser[$secdepth]){
		    print STDERR "xmlgart.pl: seq mismatch on $name\n";
		};
	    };
	    my $attsid = $element->attribute("sid")->value;
	    my $sid = "";
            # Obey the author: don't overrule an sid in input
            # Planning ahead: this computation should be recursive
            # If we understand sid to be strictly logical, then it
            #   should not be bound by secnumdepth though secunit should.
	    if($attsid eq ""){
		$attsidflag[$secdepth] = 0;
		if($secdepth <= $maxsecdepth){
		    my $jj = $minsecdepth;
		    $sid = $sid . "$secser[$jj]";
		    $jj++;
		    while($jj <= $secdepth){
			$sid = $sid . "." . $secser[$jj];
			$jj++;
		    };
		};
		$osatt = $osatt . " sid=\"" . $sid . "\"";
	    }
	    else{
		$attsidflag[$secdepth] = 1;
		$sid = $attsid;
	    };
	    $secsid[$secdepth] = $sid;
	    $thissecunit = $secsid[$secdepth];
	    # No automatic section label if sid was input as attribute
	    if($attsidflag[$secdepth] == 0){
	    	$seckey = $slabelprefix . $sid;
	    };
	}
	elsif($name =~ 
	      /^($allsecs)$/){
          # usually need to get the section title from basic content
          # sopt, shead are not being handled -- what about op0, ag0?
	    $srefseq++;
	    $srefname = $srefprefix . $srefseq;
	    $seckey = "";
	    $thissecunit = -1;
	    $popkey = 0;
	    $shead = "";
	    $labelinshead = 0;
	    $sopt = "";
	    $sprefix = "";
	    $sunitflag = 0;
	    $spassatt = $osatt;  # for passing the pre-existing attributes
          # Cannot compute sid value here
	    $open = "";
	    $osatt = "";
	    $clc = "";
	    push_output('string');
	}
	elsif($name eq "mathsym"){
	    push_output('string');
	    return;
	}
	elsif($name
          =~/^(hrule|maketitle|abstract|legalnotice|feed|thebibliography)$/){
	    while($secdepth > 0){
		$close = $close . "</" . $secref[$secdepth] . $clcm;
		$secname[$secdepth] = "";
		$secdepth--;
	    };
	    if($name eq "thebibliography"){
		# This is for the table of contents
		# Maybe thebibliography should be a formal sectional
		#   unit whose contents are a "biblilist"
		$secdepth++;
		# Write a label for the table of contents reference
		$seckey = $slabelprefix . "TheBibLiog";
		prepare_label($seckey, "thebibliog");
		# Write a tocentry
		$post = $post . make_label($seckey, "thebibliog");
		# $secdepth, used by make_ctline, should be OK
		$sopt = "";
		$sprefix = "References";
		$secunit[$secdepth] = "";
		$shead = "";
		if($lgcnt != 0){
		    my $cntline = make_cntline();
		    print FGCNT $cntline;
		};
	    };
	};
    };
    if($autoname > 0){$autoname++;};
    $open = $open . $osatt . $clc;
    $os = $close . $open . $post;
    output($os);
});
sgml('end_element', sub{
    $eltdepth--;
    my ($element, $event) = @_;
    my $name = $element->name;
    my $oname = $name;
    my $pan = "";
    my $pos = "";
    my $os = "";   # But mainly here use $pclose and $close
    my $pclose = ""; # Popped output and consequences
    my $close = "";  # Output string beginning with closetag
    my $clcm = "\n>";     # was:   my $clcn = ">\n";
    my $clc = ">";
    if(!$element->defempty){
	if(($name eq "trb") || ($name eq "trc") || ($name eq "taburow")){
	    $oname = "tr";
	};
	if(($name eq "tdb") || ($name eq "tdc")){
	    $oname = "tdr";
	};
	$close = $close . "</" . $oname;
	if($name eq "article"){
	    if($lgcnt != 0){
		print FGCNT "</TableOfContents>\n";
		close(FGCNT);
	    };
	    if($lgents != 0){
		close(FGENTS);
	    };
	    if($lglbl != 0){
		close(FGLBL);
	    };
	}
	elsif($name eq "thebibliography"){
	    $secdepth--;
	}
	elsif($name eq "eqnkey"){
	    $eqnkey = pop_output;
	    if($element->parent->name eq "eqnarray"){
		$eqnamode += 2; # to 2 or 3
	    };
	    return;
	}
	elsif($name eq "eqnser"){
	    $eqnser = pop_output;
	    if($element->parent->name eq "eqnarray"){
		$eqnamode += 4; # to 4, 5, 6, or 7
	    };
	    return;
	}
	elsif($name eq "eqntag"){
	    $eqntag = pop_output;
	    return;
	}
	elsif($name eq "assthead"){
	    $pos = pop_output;
	    $os = $pos;
	    $myasstid = $asstid;
	    if($asstid ne ""){
		$myasstid = $asstid;
	    }
	    else{
		$myasstid = $asstseq;
	    };
	    $os = $os . "<asstid>" . $myasstid . "</asstid></assthead\n>";
	    output($os);
	    return;
	}
	elsif($name eq "asstkey"){
	    $pos = pop_output;
	    $asstkey = $pos;
	    return;
	}
	elsif($name eq "asstser"){
	    $pos = pop_output;
	    $asstser = $pos;
	    return;
	}
	elsif($name eq "table"){
	    $tabdepth--;
	}
	elsif($name eq "tabarg"){
	    $tabarg[$tabdepth] = pop_output;
	    my @tbargv = split(//, $tabarg[$tabdepth]);
	    my $len = scalar @tbargv;
	    my $jj = 0;
	    my $kk = 0;
	    while($jj < $len){
		if($tbargv[$jj] =~ /[clpr]/){
		    $kk++;
		    $tabasym[$tabdepth][$kk] = $tbargv[$jj];
		};
		$jj++;
	    };
	    $tabalen[$tabdepth] = $kk;
	    my $os = "<tabarg>" . $tabarg[$tabdepth] . "</tabarg>";
	    output($os);
	    return;
	}
	elsif($name eq "tr"){
	    ;
	}
	elsif($name eq "td"){
	    my $jj = $tabaseq[$tabdepth];
	    if($jj > $tabalen[$tabdepth]){
		$jj = $tabalen[$tabdepth];
	    };
	    if($tabasym[$tabdepth][$jj] eq "p"){
		$oname = "tdp";
	    }
	    else{
		$oname = "tdr";
	    };
	    $os = "</" . $oname . ">";
	    output($os);
	    return;
	}
	elsif($name eq "asstname"){
	    $pos = pop_output;
	    $asstname = $pos;
	    my $myasstkey = "";
	    my $myasstser = "";
	    if($asstkey ne ""){
		$myasstkey = $asstkey;
	    }
	    else{
		$myasstkey = $asstlabelprefix . $asstseq;
	    };
	    if($asstser ne ""){
		$myasstser = $asstser;
	    }
	    else{
		$myasstser = "assertion";
	    };
	    prepare_label($myasstkey, $myasstser);
	    $os = make_label($myasstkey, "assertion", $myasstser);
	    $os = $os . "<assertion";
	    if($asststyle ne ""){
		$os = $os . ' style="' . $asststyle . '"';
		$asststyle = "";  # re-initialize
	    };
	    $os = $os . "><assthead>";
	    $os = $os . "<asstkey>" . $myasstkey . "</asstkey\n>";
	    $os = $os . "<asstser>" . $myasstser . "</asstser\n>";
	    $os = $os . "<asstname>" . $asstname . "</asstname\n>";
	    # Feed popkey just to be sure.
	    if($lastuserlabel eq ""){
		$lastuserlabel = $myasstkey;
	    };
	    output($os);
	    return;
	}
	elsif($name eq "asstid"){
	    $pos = pop_output;
	    $asstid = $pos;
	    return;
	}
	elsif($name eq "bibhead"){
	    $pos = pop_output;
	    if($pos ne ""){
		print STDERR "xmlgart.pl WARNING: Loose output in <bibhead>\n";
	    };
	    $os = "";
	    my $bibentline = "";
	    my $bibvis = $bibliseq;
	    if($biblabel ne ""){
		$bibvis = $biblabel;
	    };

	    if ($bibkey =~ /^\s*$/){
		$autokey++;
		$bibkey = $autoprefix . $autokey;
	    }

	    $bibentline = "<!ENTITY " . $bibprefix . $bibkey . " \""
		. $bibvis . "\">";
	    if($lgents != 0){
		print FGENTS $bibentline, "\n";
	    }
	    else{
		print STDERR "Cannot write entity line for bibkey \"",
		$bibkey, "\"\n";
	    };
	    $os = $os . "<bibhead><biblabel>";
	    my $biblblkey = $biblabelprefix . $bibkey;
	    prepare_label($biblblkey, "thebibliog");
	    $os = $os. make_label($biblblkey, "thebibliog");
	    $os = $os . "&" . $bibprefix . $bibkey . ";</biblabel>";
	    $os = $os. "<bibkey>" . $bibkey . "</bibkey></bibhead\n>";
	    output($os);
	    return;
	}
	elsif($name eq "biblabel"){
	    $pos = pop_output;
	    $biblabel = $pos;
	    return;
	}
	elsif($name eq "bibkey"){
	    $pos = pop_output;
	    $bibkey = $pos;
	    return;
	}
	elsif($name eq "citekey"){
	    $citekey = pop_output;
	    return;
	}
	elsif($name eq "citenote"){
	    $citenote = pop_output;
	    return;
	}
	elsif($name eq "cite"){
	    $os = "<cite>";
	    $pos = pop_output;
	    my $thiscite = $pos;
	    if($havecitekey == 0){
		if($citekey ne ""){
		    print STDERR "xmlgart.pl WARNING: \$citekey not empty \"",
		    $citekey, "\" while \$havecitekey is not set\n";
		}
		else{
		    $citekey = $thiscite;
		};
	    };
	    if($citenote ne ""){
		$os = $os . "<citenote>" . $citenote . "</citenote\n>";
	    };
	    $os = $os . "<citetext>&" . $bibprefix . $citekey
		. ";</citetext\n>";
	    $os = $os . "<citekey>" . $citekey . "</citekey></cite\n>";
	    output($os);
	    return;
	}
	elsif($name =~ /^.?label$/){
	    # Label file (.xlb) format:
	    #    key label-seq elt-name sec-id sunit [series series-seq]
	    # Output was pushed
	    my $key = "";
	    $pos = pop_output;
	    if($pos eq ""){
                # We must supply a key
		$autokey++;
		$key = $autoprefix . $autokey;
	    }
	    else{
		$key = $pos;
	    };
	    # $lastuserlabel is used for <popkey/> (tricky)
	    # Putting it here makes it  possible for a label in sprefix
	    #   to be popped in sunit
	    $lastuserlabel = $key;
	    my $seratt = $element->attribute("series")->value;
	    my $series = "";
	    my $serseq = -3; # previously was initializing this as -1
	    if($seratt ne ""){
		$series = $seratt;
		my $tserseq = $element->attribute("serseq")->value;
		if($tserseq ne ""){
		    $serseq = $tserseq;
		};
	    };
	    my $par = $element->parent;
	    $pan = $par->name;  # already a "my" variable
	    my $nonum = "";
	    if($emath == 1){
		# Should this label in equation or eqnarray be discarded?
		if($pan eq "eqnline"){
		    $nonum = $par->parent->attribute("nonum")->value;
		    if($nonum eq "true"){
			return;
		    }
		}
		elsif(($pan eq "eqnrow") || ($pan eq "brk0")){
		    # Various options could be followed here ...
		    if($eqnamode > 0){      # nonum set for eqnarray
			return;
		    }
		    else{ # Allow the label for this row, as for equation
			;
		    };
		}
		else{
		    print STDERR 'xmlgart WARNING: label, key="', $key,
		    '", inside "', $pan, "\"; logical error, emath not set\n";
		};
		# What default series for this label?  Do not allow blank.
		if($series =~ /^\s*$/){
		    if(!($eqnser =~ /^\s*$/)){
			$series = $eqnser;
		    }
		    else{
			$series = $eqnintautoseries;
		    };
		};
		if(($pan eq "eqnline")||($pan eq "eqnrow")){
		    $eqnintseries = $series;
		};
		# This was used while leaning on LaTeX:
		#     $serseq = $eqseq;
		$eqkey[$eqseq] = $key;  # not used ?
	    }
	    elsif($pan =~ /^(eqnline|eqnrow)$/){
		print STDERR 'xmlgart WARNING: key="' , $key, '", inside "',
		$pan, "\"; logic error, missing emath flag.\n";
	    };
	    my $refkey = $element->attribute("refkey")->value;
	    # non-empty refkey overrides serseq attribute value, if any
	    if(($refkey ne "") && ($labelkeys{$refkey} != 0)
	       && !($series =~ /^\s*$/)){
		if($labelseq{$refkey}){
		    $serseq = $labelseq{$refkey};
		}
		elsif($labelloc{$refkey} > 0){
		    $serseq = $labelloc{$refkey};
		};
	    };
	    if($serseq == 0){
		# Cannot effectively pass 0 as a value here, so use -1 for 0.
		$serseq = -1;
	    };
	    if($serseq < -3){
		$serseq = -2;
	    };  # meaning either serseq or refkey was set to a value < -3
            my $sheadflag = 0;
	    # Is this label in a section header ?
	    my $pan = $element->parent->name;
	    if($pan =~ /^(shead|sprefix)$/){
		$sheadflag = 1;
	    }
	    elsif($pan =~ /^($allsecs)$/){
		$sheadflag = 1;
	    }
	    elsif($pan =~ /^(ag0|op0)$/){  # ag0 or op0 must have a parent
		my $gpan = $element->parent->parent->name;
		if($gpan =~ /^($allsecs|$AllSecs)$/){
		    $sheadflag = 1;
		};
	    };
	    if(($serseq > 0) || ($serseq == -1)){
		prepare_label($key, $series, $serseq);
	    }
	    else{
		prepare_label($key, $series, 0);
	    };
	    my $compact = $key . $sepchar . $name;
	    if(!($series =~ /^\s*$/)){
		$compact = $compact . $sepchar . $series;
	    }
	    if($sheadflag == 1){
		$labelinshead++;
		$sheadlabel[$labelinshead] = $compact;
	    }
	    elsif($emath == 1){
		$eqnlabel = $eqnlabel . make_label($compact);
		$eqnkey = $key;
		$eqnser = $series;
	    }
	    else{
		output(make_label($compact));
	    };
	    return;
	}
	elsif($name =~ /^(sopt|sprefix|sunit)$/){
	    $pos = pop_output;
	    if($name eq "sopt"){
		$sopt = $pos;
	    }
	    elsif($name eq "sprefix"){
		$sprefix = $pos;
	    }
	    elsif($name eq "sunit"){
		$sunitflag = 1;
		$sunit = $pos;
		# Watch out for re-cycled XML: then the presence of <sunit>
		#       is not a signal to suppress sunit output
		if(($sunit eq "")&&($xmlinput == 1)){
		    $sunitflag = 0;
		};
	    }
	    else{
		die "Code error in xmlgart.pl: impossible value for\n",
		"  elt. name $name, not one of sopt, sprefix, or sunit\n";
	    };
	    return;
	}
	elsif($name eq "item"){
	    my $pan = $_[0]->parent->name;
	    if($pan =~ /^(description|booklist)$/){
		$os = "</ditem\n>";
		output($os);
		return;
	    };
	}
	elsif($name eq "shead"){
	    $pos = pop_output;
	    $pclose = "";
	    my $pan = $element->parent->name;
	    if($pan =~ 
	       /^($AllSecs)$/){
                # In this case $seckey is available
		$shead = $pos;  # save for <tableofcontents/>

	# Compute secunit
		if($secdepth <= $secnumdepth){
		    if($sunitflag != 0){
			if(($sunit eq "")||($sunit == -1)){
			    my $tkey = $lastuserlabel;
			    if(($tkey ne "")&&($labelseq{tkey} != 0)){
				$secunit[$secdepth] = $labelseq{$tkey};
			    }
			    else{
				$secunit[$secdepth] = -2;
			    };
			}
			else{
			    $secunit[$secdepth] = $sunit;
			};
		    }
		    elsif($secunit[$secdepth-1] ne ""){
			$secunit[$secdepth] = $secunit[$secdepth-1] . "."
			    . $secser[$secdepth];
		    }
		    else{
			$secunit[$secdepth] = $secsid[$secdepth];
		    };
		}
		else{
		    $secunit[$secdepth] = "";
		};

	# Write sprefix and sunit
		if($sprefix ne ""){
		    $pclose = $pclose ."<sprefix>". $sprefix ."</sprefix\n>";
		};
		if($secunit[$secdepth] ne ""){
		    if($sunitflag != 0){
			$pclose = $pclose ."<sunit>" . $secunit[$secdepth]
			    . "</sunit\n>";
		    }
		    else{
			$pclose = $pclose . "<sunit>" . "&$srefname;"
			    . "</sunit\n>";
		    };
		};
		if(($secunit[$secdepth] ne "")&&($secunit[$secdepth] != -2)){
		    $thissecunit = $secunit[$secdepth];
		    if($lgents != 0){
			print FGENTS "<!ENTITY $srefname \"$thissecunit\">\n";
		    };
		};
		$pclose = $pclose . "<shead\n>";

	# Handle stored labels
		if($labelhold ne ""){
		    print STDERR "xmlgart.pl: logical error --",
		    " global use of labelhold\n", "  Contents: \"",
		    $labelhold, "\"\n";
		    $labelhold = "";
		};
		if($labelinshead > 0){
		    my $jl = 1;
		    while($jl <= $labelinshead){
			my $compact = $sheadlabel[$jl];
			$labelhold = $labelhold . make_label($compact);
			$jl++;
		    };
		};

	# Make automatic sectional label and contents line
		if(($seckey ne "")&&($secdepth <= $tocdepth)){
		    if($lgcnt != 0){
			my $cntline = make_cntline();
			print FGCNT $cntline;
		    };
		    prepare_label($seckey);
		    $pclose = $pclose . make_label($seckey, $pan);
		};

		# Wrap up new <shead>
		$pclose = $pclose . $labelhold;
		$labelhold = "";   # while still kept global
		$pclose = $pclose . $shead;
	    }
	    elsif($pan =~
	       /^($allsecs)$/){
                # For this case $seckey is not available yet
		$shead = $pos;
	    }
	    else{
		print STDERR "xmlgart.pl WARNING: Found \"$name\" in "
                      . "\"$pan\";\n  element seq. no. $eltseq\n";
	    };
	}
	elsif($name =~ /^(sum|int|prod)$/){
	    $sipdepth--;
	}
	elsif($name =~ 
	      /^($AllSecs)$/){
	    if($name ne $secname[$secdepth]){
		print STDERR "Coding error in ", $WhoAmI,
                             ": Sectional unit name mismatch ??\n";
	    };
	    $secname[$secdepth] = "";
	    $secdepth--;
	    $clc = $clcm;
	}
	elsif($name =~
	      /^($allsecs)$/){
	    # Output was pushed to get the title
	    $pos = pop_output;
	    $pclose = "";

	# Compute value of $secdepth
	    my $nsdepth = 0;
	    $oname =~ s/^s/S/;
	    if($name eq "section"){
		$nsdepth = 1;
	    }
	    elsif($name eq "subsection"){
		$nsdepth = 2;
	    }
	    elsif($name eq "subsubsection"){
		$nsdepth = 3;
	    }
	    elsif($name eq "paragraph"){
		$nsdepth = 4;
	    }
	    elsif($name eq "subparagraph"){
		$nsdepth = 5;
	    }
	    else{
		print STDERR $WhoAmI, ": Coding error on nsdepth\n Name:
                             ", $name, "\n";
	    };
	    while($secdepth >= $nsdepth){
		$pclose = $pclose . "</" . $secref[$secdepth] . $clcm;
		$secname[$secdepth] = "";
		$secdepth--;
	    }; # taken to one less than section depth of current opentag
	    $secdepth = $nsdepth; # new current value
	    $secser[$secdepth]++;
	    $secser[1+$secdepth] = 0;
	    $pclose = $pclose . "<" . $secref[$secdepth] . " depth=\""
                 . $secdepth . "\" seq = \"" . $secser[$secdepth] . "\"";

        # Handle passed attributes on section, subsection, ...
	    $pclose = $pclose . $spassatt;
	    my $attsid = $element->attribute("sid")->value;
	    my $sid = "";

	# $secsid[$secdepth] is about the logical hierarchy
            #      Don't overrule a (rare?) value of sid as input attribute
	    if($attsid eq ""){
		$attsidflag[$secdepth] = 0;
		if($secdepth <= $maxsecdepth){
		    my $jj = $minsecdepth;
		    $sid = $sid . "$secser[$jj]";
		    $jj++;
		    while($jj <= $secdepth){
			$sid = $sid . "." . $secser[$jj];
			$jj++;
		    };
		};
		$pclose = $pclose . " sid=\"" . $sid . "\"";
	    }
	    else{
		$attsidflag[$secdepth] = 1;
		$sid = $attsid;
	    };
	    $secsid[$secdepth] = $sid;
	    $thissecunit = $secsid[$secdepth];

	# $secunit[$secdepth] is the manifest sectional unit label
	#     consistent with $secnumdepth
	    #
	    if($secdepth <= $secnumdepth){
		if($sunitflag != 0){
		    if(($sunit eq "")||($sunit == -1)){
			my $tkey = $lastuserlabel;
			if(($tkey ne "")&&($labelseq{tkey} != 0)){
			    $secunit[$secdepth] = $labelseq{$tkey};
			}
			else{
			    $secunit[$secdepth] = -2;
			};
		    }
		    else{
			$secunit[$secdepth] = $sunit;
		    };
		}
		elsif($secunit[$secdepth-1] ne ""){
		    $secunit[$secdepth] = $secunit[$secdepth-1] . "."
			. $secser[$secdepth];
		}
		else{
		    $secunit[$secdepth] = $secsid[$secdepth];
		};
	    }
	    else{
		$secunit[$secdepth] = "";
	    };
	    if(($secunit[$secdepth] ne "")&&($secunit[$secdepth] != -2)){
	     	$thissecunit = $secunit[$secdepth];
		if($lgents != 0){
		    print FGENTS "<!ENTITY $srefname \"$thissecunit\">\n";
	    	};
	    };
	    # End of code for computing output sunit

	    # Label key for automatic section label
	# No automatic section label if sid was input as attribute
	    if($attsidflag[$secdepth] == 0){
	    	$seckey = $slabelprefix . $sid;
	    };
	    $pclose = $pclose . "\n>";

	# Gather all pieces of the section head
                # $shead does not contain any author labels placed in <shead>,
                #  which are stored in the $sheadlabel[$labelinshead]
	    if(($shead ne "") || ($sopt ne "") ||($sprefix ne "")
	       || ($sunitflag != 0)){
		if($sprefix ne ""){
		    $pclose = $pclose . "<sprefix>" . $sprefix .
			"</sprefix\n>";
		};
	    }
	    else{
                # case where \section has no subelements
		$shead = $pos;  # (This *could* still be the empty string.)
	    };

	# Handle stored labels
	    if($labelhold ne ""){
		print STDERR "xmlgart.pl: logical error --",
		" global use of labelhold\n", "  Contents: \"",
		$labelhold, "\"\n";
		$labelhold = "";
	    };
	    if($labelinshead > 0){
		my $jl = 1;
		while($jl <= $labelinshead){
		    my $compact = $sheadlabel[$jl];
		    $labelhold = $labelhold . make_label($compact);
		    $jl++;
		};
	    };

	# Write output sunit tag
	    if($secdepth <= $secnumdepth){
		if($sunitflag != 0){
		    $pclose = $pclose . "<sunit>" . $secunit[$secdepth]
			. "</sunit\n>";
		}
		else{
		    $pclose = $pclose ."<sunit>". "&$srefname;" ."</sunit\n>";
		};
	    };
	    my $oshead = $shead;
	    $pclose = $pclose . "<shead\n>";

	# Automatic section label (for ref from contents)
	#   and contents line
	    if(($seckey ne "")&& ($secdepth <= $tocdepth)){
		# $labelrun++;
		prepare_label($seckey);
		$pclose = $pclose . make_label($seckey, $name);
		if($lgcnt != 0){
		    my $cntline = make_cntline();
		    print FGCNT $cntline;
		};
	    };
	    $oshead = $labelhold . $shead;
	    $labelhold = "";   # while left global

	# Wrap up the new <shead>
	    $pclose = $pclose . $oshead . "</shead>";
	    $close = "";
	    $clc = "";
	}
	elsif($name eq "mathsym"){
	    $pos = pop_output;
	    $close =  $pos;
	    $close =~ s/\s+/ /g;
	    $close = $close . "</mathsym\n>";
	    $pclose = "<mathsym>";
	    $clc = "";
	}
	elsif($name =~ /^(body|document)$/){
	    $clc = $clcm;
	    while($secdepth > 0){
		$pclose = $pclose . "</" . $secref[$secdepth] . $clcm;
		$secname[$secdepth] = "";
		$secdepth--;
	    };
	};
	$close = $close . $clc;
	$os = $pclose . $close;
	output($os);
    };
});

sgml('pi',sub{
    my $inst = $_[0];
    if($inst =~ /^xml /){
	$xmlinput = 1;
    }
    else{
	die "Unknown processing instruction: " . $_[0];
    };
});

sgml('re', sub{
    my $os;
    if($xmlinput == 1){
	return;
    }
    elsif($discardflag == 1){
	$discardflag = 0;
	$os = " ";  # replace this newline with a space
    }
    else{
	$os = "\n";
    };
    output($os);
});

#
# Default handlers (uncomment these if needed).  Right now, these are set
# up to gag on any unrecognised elements, sdata, processing-instructions,
# or entities.
#
# sgml('start_element',sub { die "Unknown element: " . $_[0]->name; });
# sgml('end_element','');
# sgml('cdata',sub { output $_[0]; });
# sgml('sdata',sub { die "Unknown SDATA: " . $_[0]; });
# The next line is commented in the default output of Megginson's "skel.pl"
# sgml('re',"\n");
# sgml('pi',sub { die "Unknown processing instruction: " . $_[0]; });
# sgml('entity',sub { die "Unknown external entity: " . $_[0]->name; });
# sgml('start_subdoc',sub { die "Unknown subdoc entity: " . $_[0]->name; });
# sgml('end_subdoc','');
# sgml('conforming','');

sub get_attributes {
    my ($elt, $rattn, $ratty, $rattv) = @_;
    # $rattn, $rattv are references to passed arrays
    my $attref = $elt->attributes;
    my %atts = %$attref;
    my @atns = keys(%atts);
    my $nat = scalar @atns;
    my $jj = 0;
    my $jty = "";
    my $jvs = "";
    while($jj < $nat){
	$$rattn[$jj] = $atns[$jj];
	$jty = $atts{$atns[$jj]}->type;
	$$ratty[$jj] = $jty;
	if($jty eq "CDATA"){
	    $jvs = $atts{$atns[$jj]}->value;
	}
	elsif($jty eq "TOKEN"){
	    $jvs = $atts{$atns[$jj]}->value;
	}
        elsif($jty eq "IMPLIED"){
	    $jvs = $atts{$atns[$jj]}->value;
	}
	elsif(($jty eq "NOTATION")||($jty eq "ENTITY")){
	    $jvs = "WARNING: attribute type " . $jty
                   . " not supported by this code";
	}
	else{
	    $jvs = "WARNING: ATTRIBUTE TYPE ERROR: " . $jty;
	}
	$$rattv[$jj] = $jvs;
	$jj++;
    };
    return $nat;
};

# might as well use the globals rather than pass arguments
sub make_cntline {
    my $cline = "<tocitem depth=\"" . $secdepth . "\"><tocunit>";
    if($sprefix ne ""){
	$cline = $cline . $sprefix;
    };
    $cline = $cline . $secunit[$secdepth] . "</tocunit\n>" . "<tocentry>";
    # Is there a sopt to substitute for $shead ?
    my $ctitle = $shead;
    if($sopt ne ""){
	$ctitle = $sopt;
    };
    $cline = $cline . $ctitle . "<dotfill/><nbs/><pageref>" . $seckey
	. "</pageref></tocentry></tocitem\n>";
    return $cline;
};

sub prepare_label {
    my ($key, $series, $seq) = @_;
    my $serseq = 0;
    # Register the label key
    $labelrun++;
    if($labelkeys{$key} != 0){
	print STDERR "xmlgart.pl WARNING: Label seq. $labelrun\n",
	" -- key \"$key\" is already in use, seq. ",
	"$labelkeys{$key}\n";
    }
    else{
	$labelkeys{$key} = $labelrun;
    };
    # Set the label series sequence value for the key if it is in a series
    if(!($series =~ /^\s*$/)){
	if($seq > 0){
	    $labelsqr{$series} = $seq;
	}
	elsif($seq == -1){
	    # -1 pinch hits for 0 since 0 is the default value of $seq
	    $labelsqr{$series} = 0;
	}
	else{
	    $labelsqr{$series}++;
	};
	$serseq = $labelsqr{$series};
	my $serent = "<!ENTITY $lserprefix$key \"$series\">\n";
	my $seqent = "<!ENTITY $lseqprefix$key \"$serseq\">\n";
	if($lgents != 0){
	    print FGENTS $serent, $seqent;
	};
	# If serseq is to be used for a sectional unit value, e.g., evalref,
	# then we need to have it fully evaluated our XML output.
	$labelseq{$key} = $serseq;
    };
    return;
};

sub make_label {
    my $argc = scalar @_;
    my $key;
    my $type;
    my $series;
    if($argc == 1){
	my $compactlabel = $_[0];
	my @args = split(/$sepcharre/, $compactlabel);
	my $n = scalar @args;
	if( !( ($n == 2) || ($n == 3)) ){
	    die "xmlgart.pl: Call to make_label has only one argument",
	    " that is not compactified\n", "  Arg: ", join(" ",(@_)) , "\n";
	};
	($key, $type, $series) = @args;
    }
    elsif(($argc == 2)||($argc == 3)){
	($key, $type, $series) = @_;
    }
    else{
	die "xmlgart.pl: logical error.  Incorrect call to  make_label\n",
	"  Args: ", @_, "\n";
    };
    my $thisrun = $labelkeys{$key};
    # LBL aux file line -- becoming obsolete ??
    my $thislabel = $key . $sepchar . $thisrun . $sepchar . $type;
    my $lname = "label";
    if($type =~ /^.?label$/){
	$lname = $type;
    };
    # line for XML output
    my $outlabel = "<" . $lname . " lseq=\"" . $thisrun . "\"";
    $thislabel = $thislabel . $sepchar . $secsid[$secdepth];
    my $susd = $thissecunit;
    $thislabel = $thislabel . $sepchar . $susd;
    if(!($series =~ /^\s*$/)){
	$thislabel = $thislabel . $sepchar . $series;
	$outlabel = $outlabel . " series=\"" . $series . "\"";
	$thislabel = $thislabel . $sepchar . $labelseq{$key};
	$outlabel = $outlabel . " serseq=\"" . $labelseq{$key} . "\"";
    }
    else{

	# ;
    };
    # if(($type eq "label")&&($lgents != 0)){   changed 20050110
    if($lgents != 0){
	print FGENTS "<!ENTITY ", $llocprefix, $key, " \"", $thissecunit,
	"\">\n";
    };
    $labelloc{$key} = $thissecunit;
    if($lglbl != 0){
	print FGLBL $thislabel, "\n";
    };
    $outlabel = $outlabel . ">" . $key . "</" . $lname . "\n>";
    return $outlabel;
};

1;
