Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  GAPDoc2LaTeX.gi   Sprache: unbekannt

 
#############################################################################
##
#W  GAPDoc2LaTeX.gi                GAPDoc                        Frank Lübeck
##
##
#Y  Copyright (C)  2000,  Frank Lübeck,  Lehrstuhl D für Mathematik,  
#Y  RWTH Aachen
##
##  The  files GAPDoc2LaTeX.g{d,i}  contain a  conversion program  which
##  produces from a GAPDoc XML-document a version which can be processed
##  by LaTeX and pdfLaTeX.
##  

##  All  the work  is  done by  handler functions  for  each GAPDoc  XML
##  element.  These functions  are  bound as  components  to the  record
##  `GAPDoc2LaTeXProcs'. Most  element markup is easily  translated to a
##  corresponding LaTeX markup. It should  be easy to modify details for
##  some elements  by small local  changes of the  corresponding handler
##  function. The only slight complications  are in places where the XML
##  elements imply some labeling or  indexing. Also for all (sub)section
##  commands  we  add some  commands  which  cause  LaTeX to  produce  a
##  GAP  readable .pnr  file which  contains  the page  numbers for  all
##  subsections.
InstallValue(GAPDoc2LaTeXProcs, rec());

##  <#GAPDoc Label="GAPDoc2LaTeX">
##  <ManSection >
##  <Func Arg="tree" Name="GAPDoc2LaTeX" />
##  <Returns>&LaTeX; document as string</Returns>
##  <Func Name="SetGapDocLaTeXOptions" Arg="[...]" />
##  <Returns>Nothing</Returns>
##  <Description>
##  The   argument  <A>tree</A>   for   this  function   is  a   tree
##  describing  a   &GAPDoc;  XML   document  as  returned   by  <Ref
##  Func="ParseTreeXMLString"  /> (probably  also  checked with  <Ref
##  Func="CheckAndCleanGapDocTree"  />).  The   output  is  a  string
##  containing a  version of the document  which can be written  to a
##  file  and processed  with  &LaTeX; or  pdf&LaTeX;  (and  probably
##  &BibTeX; and <C>makeindex</C>). <P/>
##  
##  The   output   uses   the  <C>report</C>   document   class   and
##  needs    the   following    &LaTeX;   packages:
##  <C>amssymb</C>,  <C>inputenc</C>,  <C>makeidx</C>,  <C>color</C>,
##  <C>fancyvrb</C>,  <C>psnfss</C>,  <C>pslatex</C>, <C>enumitem</C>  
##  and  <C>hyperref</C>.   These are  for  example  provided by  the
##  <Package>texlive</Package>  distribution of &TeX; (which  in turn
##  is used for most &TeX; packages of current Linux  distributions);
##  see <URL>https://www.tug.org/texlive/</URL>. <P/>
##  
##  In  particular, the  resulting  <C>pdf</C>-output (and 
##  <C>dvi</C>-output)  
##  contains  (internal and  external) hyperlinks  which can  be very
##  useful for onscreen browsing of the document.<P/>
##  
##  The  &LaTeX;  processing  also  produces a  file  with  extension
##  <C>.pnr</C> which is &GAP; readable and contains the page numbers
##  for  all (sub)sections  of  the  document. This  can  be used  by
##  &GAP;'s online help; see <Ref Func="AddPageNumbersToSix" />.
##  
##  Non-ASCII characters in the &GAPDoc; document are translated to 
##  &LaTeX; input in ASCII-encoding with the help of <Ref Oper="Encode"/>
##  and the option <C>"LaTeX"</C>. See the documentation of 
##  <Ref Oper="Encode"/> for how to proceed if you have a character which 
##  is not handled (yet).<P/>
##  
##  This  function works  by  running recursively  through the  document
##  tree   and   calling   a   handler  function   for   each   &GAPDoc;
##  XML   element.  Many   of  these   handler  functions   (usually  in
##  <C>GAPDoc2LaTeXProcs.<ElementName></C>)  are not  difficult to
##  understand (the  greatest complications are some  commands for index
##  entries, labels  or the  output of page  number information).  So it
##  should be easy to adjust layout  details to your own taste by slight
##  modifications of the program. <P/>
##  
##  Former   versions  of   &GAPDoc;  supported   some  XML   processing
##  instructions to add some extra lines  to the preamble of the &LaTeX;
##  document. Its use is now deprecated, use the much more flexible <Ref
##  Func="SetGapDocLaTeXOptions" /> instead:
##  
##  The    default   layout    of    the    resulting   documents    can
##  be   changed   with    <Ref   Func="SetGapDocLaTeXOptions"/>.   This
##  changes    parts   of    the    header   of    the   &LaTeX;    file
##  produced   by    &GAPDoc;.   You    can   see   the    header   with
##  some   placeholders  by   <C>Page(GAPDoc2LaTeXProcs.Head);</C>.  The
##  placeholders   are   filled   with  components   from   the   record
##  <C>GAPDoc2LaTeXProcs.DefaultOptions</C>.   The  arguments   of  <Ref
##  Func="SetGapDocLaTeXOptions"/>   can  be   records  with   the  same
##  structure (or parts  of it) with different  values. As abbreviations
##  there  are   also  three  strings  supported   as  arguments.  These
##  are  <C>"nocolor"</C>  for  switching  all  colors  to  black;  then
##  <C>"nopslatex"</C>  to   use  standard  &LaTeX;  fonts   instead  of
##  postscript fonts; and finally <C>"utf8"</C> to choose UTF-8 as input
##  encoding for the &LaTeX; document.
##  
##  </Description>
##  </ManSection>
##  <#/GAPDoc>
##  
##  <!--  seems to be no longer needed
##  A hint for  large documents: In many &TeX;  installations one can
##  easily reach some memory limitations with documents which contain
##  many (cross-)references. In <Package>teTeX</Package> you can look
##  for  a  file <F>texmf.cnf</F>  which  allows  to enlarge  certain
##  memory sizes.<P/>
##  -->


# the basic call, used recursivly with a result r from GetElement 
# and a string str to which the output should be appended
# arg: r       (then a string is returned)
# or:  r, str  (then the output is appended to string str)
InstallGlobalFunction(GAPDoc2LaTeX, function(arg)
  local  r,  str,  name;
  r := arg[1];
  if Length(arg)>1 then
    str := arg[2];
  else
    AddRootParseTree(r);
    # reset to defaults in case of interrupted previous call
    GAPDoc2LaTeXProcs.verbatimPCDATA := false;
    GAPDoc2LaTeXProcs.recode := true;
    str := "";
  fi;
  name := r.name;
  if not IsBound(GAPDoc2LaTeXProcs.(name)) then
    Info(InfoGAPDoc, 1, "#W WARNING: Don't know how to process element ", name, 
          " ---- ignored\n");
  else
    GAPDoc2LaTeXProcs.(r.name)(r, str);
  fi;
  if Length(arg)=1 then
    return str;
  fi;
end);

##  a common recursion loop
BindGlobal("GAPDoc2LaTeXContent", function(r, str)
  local   a;
  for a in r.content do
    GAPDoc2LaTeX(a, str);
  od;
end);

# width of index entries, we use a trick to split longer command names
GAPDoc2LaTeXProcs.MaxIndexEntryWidth := 35;

# a flag for recoding to LaTeX
GAPDoc2LaTeXProcs.recode := true;

# two utilities for attribute values like labels or text with special
# XML or LaTeX characters which gets printed (always as \texttt text)
GAPDoc2LaTeXProcs.EscapeAttrValOld := function(str)
  local res, c;
  res := "";
  for c in str do
    if c = '\\' then
##        Append(res, "{\\gdttbs}");
      Append(res, "\\texttt{\\symbol{92}}");
    elif c = '_' then
      Append(res, "\\_");
    elif c = '{' then
##        Append(res, "{\\gdttob}");
      Append(res, "\\texttt{\\symbol{123}}");
    elif c = '}' then
##        Append(res, "{\\gdttcb}");
      Append(res, "\\texttt{\\symbol{125}}");
    elif c = '^' then
##        Append(res, "{\\gdttht}");
      Append(res, "\\texttt{\\symbol{94}}");
    elif c = '~' then
##        Append(res, "{\\gdttti}");
      Append(res, "\\texttt{\\symbol{126}}");
    elif c = '<' then
      Append(res, "{\\textless}");
    elif c = '>' then
      Append(res, "{\\textgreater}");
    elif c = '&' then
      Append(res, "\\&");
    elif c = '%' then
      Append(res, "\\%");
    elif c = '$' then
      Append(res, "\\$");
    elif c = '#' then
      Append(res, "\\#");
    else
      Add(res, c);
    fi;
  od;
  return res;
end;
# now via Unicode, handle many more characters as well
GAPDoc2LaTeXProcs.EscapeAttrVal := function(str)
  return Encode(Unicode(str), GAPDoc2LaTeXProcs.Encoder);
end;

GAPDoc2LaTeXProcs.DeleteUsBs := function(str)
  local res, c;
  if ForAny(str, c-> c in "\\_") then
    res := "";
    for c in str do
      if c = '\\' then
        Append(res, "bSlash");
      elif c = '_' then
        Append(res, "uScore");
      else
        Add(res, c);
      fi;
    od;
    return res;
  fi;
  return str;
end;

##  this is for getting a string "[ \"A\", 1, 1 ]" from [ "A", 1, 1 ]
GAPDoc2LaTeXProcs.StringNrs := function(ssnr)
  if IsInt(ssnr[1]) then
    return String(ssnr);
  else
    return Concatenation("[ \"", ssnr[1], "\", ", String(ssnr[2]), ", ",
                   String(ssnr[3]), " ]");
  fi;
end;

GAPDoc2LaTeXProcs.Head := StringFile(
            Filename(DirectoriesPackageLibrary("gapdoc"),"latexhead.tex"));
                                   
GAPDoc2LaTeXProcs.Tail := Concatenation( 
"\\newpage\n",
"\\immediate\\write\\pagenrlog{[\"End\"], \\arabic{page}];}\n",
"\\immediate\\closeout\\pagenrlog\n",
"\\end{document}\n");

GAPDoc2LaTeXProcs.Options := rec();
GAPDoc2LaTeXProcs.DefaultOptions := rec(
  EarlyExtraPreamble := "",
  LateExtraPreamble := "",
  InputEncoding := "latin1",
  ColorDefinitions := rec(
             link := "0.0,0.0,0.554",
             cite := "0.0,0.0,0.554",
             file := "0.0,0.0,0.554",
             url := "0.0,0.0,0.554",
             prompt := "0.0,0.0,0.589",
             brkprompt := "0.589,0.0,0.0",
             gapinput := "0.589,0.0,0.0",
             gapoutput := "0.0,0.0,0.0",
             funcdefs := "0.0,0.0,0.0",
             chapter := "0.0,0.0,0.0"
             ),
  MoreColors := "\\definecolor{DarkOlive}{rgb}{0.1047,0.2412,0.0064}\n",
  FontPackages := "\\usepackage{mathptmx,helvet}\n\\usepackage[T1]{fontenc}\n\
\\usepackage{textcomp}\n",
  HyperrefOptions := rec(
             pdftex := "true",
             bookmarks := "true",
             a4paper := "true",
             pdftitle := "{Written with GAPDoc}",
             pdfcreator := "{LaTeX with hyperref package / GAPDoc}",
             colorlinks := "true",
             backref := "page",
             breaklinks := "true",
             pdfpagemode := "{UseNone}",
             MoreHyperrefOptions := "" 
             ),
  TocDepth := "\\setcounter{tocdepth}{1}",
  Maintitlesize := "\\fontsize{50}{55}\\selectfont",
);

# helper function to apply the options to the generic LaTeX head
GAPDoc2LaTeXProcs.HeadWithOptions := function(extra)
  local head, opt, f, ff;
  head := GAPDoc2LaTeXProcs.Head;
  opt := GAPDoc2LaTeXProcs.Options;
  for f in RecNames(opt) do
    if f = "ColorDefinitions" then
      for ff in RecNames(opt.(f)) do
        head := SubstitutionSublist(head, 
                               Concatenation("CONFIGCOLOR",ff), opt.(f).(ff));
      od;
    elif f = "HyperrefOptions" then
      for ff in RecNames(opt.(f)) do
        head := SubstitutionSublist(head, 
                               Concatenation("CONFIGHR",ff), opt.(f).(ff));
      od;
    else
      head := SubstitutionSublist(head, 
                               Concatenation("CONFIG", f), opt.(f));
    fi;
  od;
  head := SubstitutionSublist(head, "PIExtraPreamble", extra);
  return head;
end;

##  arg: a list of strings
##  for now only the output type (one of "dvi", "pdf" or "ps") is used
# to be enhanced
SetGapDocLaTeXOptions := function(arg)    
  local new, recs, r, f, ff;
  GAPDoc2LaTeXProcs.Options := StructuralCopy(GAPDoc2LaTeXProcs.DefaultOptions);
  new := GAPDoc2LaTeXProcs.Options;
  recs := Filtered(arg, IsRecord);
  # handle some abbreviations
  if "nocolor" in arg then
    Add(recs, rec(
           ColorDefinitions := rec(
             link := "0.0,0.0,0.0",
             cite := "0.0,0.0,0.0",
             file := "0.0,0.0,0.0",
             url := "0.0,0.0,0.0",
             prompt := "0.0,0.0,0.0",
             brkprompt := "0.0,0.0,0.0",
             gapinput := "0.0,0.0,0.0",
             gapoutput := "0.0,0.0,0.0",
             funcdefs := "0.0,0.0,0.0",
             chapter := "0.0,0.0,0.0"
                        ) ) );
  fi;
  if "utf8" in arg then
    Add(recs, rec(InputEncoding := "utf8"));
  fi;
  if "nopslatex" in arg then
    Add(recs, rec(FontPackages := "\n"));
  fi;

  # now overwrite the defaults
  for r in recs do
    for f in RecNames(r) do
      if IsRecord(r.(f)) then
        if IsBound(new.(f)) then
          for ff in RecNames(r.(f)) do
            if IsBound(new.(f).(ff)) then
              new.(f).(ff) := r.(f).(ff);
            fi;
          od;
        fi;
      else
        if IsBound(new.(f)) then
          new.(f) := r.(f);
        fi;
      fi;
    od;
  od;
  # set encoder accordingly
  if new.InputEncoding = "utf8" then
    GAPDoc2LaTeXProcs.Encoder := "LaTeXUTF8";
  else
    GAPDoc2LaTeXProcs.Encoder := "LaTeX";
  fi;
end;
# set defaults
SetGapDocLaTeXOptions();

GAPDoc2LaTeXProcs.firstsix := function(r, count)
  local a;
  a := PositionSet(r.root.sixcount, count{[1..3]});
  if a <> fail then
    a := r.root.six[r.root.sixindex[a]];
  fi;
  return a;
end;
##  write head and foot of LaTeX file.
GAPDoc2LaTeXProcs.WHOLEDOCUMENT := function(r, str)
  local   i,  pi,  t,  el,  a;
  
  ##  add internal paragraph numbering
  AddParagraphNumbersGapDocTree(r);
  
  ##  checking for processing instructions
  i := 1;
  pi := rec();
  while not r.content[i].name = "Book" do
    if r.content[i].name = "XMLPI" then
      t := r.content[i].content;
      if Length(t) > 5 and t{[1..6]} = "LaTeX " then
        el := GetSTag(Concatenation("<", t, ">"), 2);
        for a in NamesOfComponents(el.attributes) do
          pi.(a) := el.attributes.(a);
        od;
      fi;
    fi;
    i := i+1;
  od;
  ##  collect headings of labeled sections, here we must run through the
  ##  whole parse tree first to know the headings of text style forward
  ##  references
  GAPDoc2LaTeXProcs._labeledSections := rec();
  r.root.norecursion := true;
  ApplyToNodesParseTree(r, function(rr) 
    if IsRecord(rr) and IsBound(rr.name)
       and rr.name in ["Chapter", "Section", "Subsection", "Appendix"] then
      # save heading for "Text" style references to section
      GAPDoc2LaTeXProcs.(rr.name)(rr,"");
    fi;
  end);
  Unbind(r.root.norecursion);

  ##  warn if no labels via .six available
  if not IsBound(r.six) then
    Info(InfoGAPDoc, 1, "#W WARNING: No labels for section number independent ",
      "anchors available.\n", 
      "#W Consider running the converter for the text version first!\n");
  fi;

  ##  now the actual work starts, we give the found processing instructions
  ##  to the Book handler
  GAPDoc2LaTeXProcs.Book(r.content[i], str, pi);
  Unbind(GAPDoc2LaTeXProcs._labeledSections);
end;

##  comments and processing instructions are generally ignored
GAPDoc2LaTeXProcs.XMLPI := function(r, str);
end;
GAPDoc2LaTeXProcs.XMLCOMMENT := function(r, str);
end;

# do nothing with Ignore
GAPDoc2LaTeXProcs.Ignore := function(arg)
end;

##  this makes head and foot of the LaTeX output
##  - the only processing instructions handled currently are
##    - options for the report class (german, papersize, ...) and 
##    - extra entries in the preamble (\usepackage, macro definitions, ...)
GAPDoc2LaTeXProcs.Book := function(r, str, pi)
  local   a;
 
  if not IsBound(pi.ExtraPreamble) then
    pi.ExtraPreamble := "";
  fi;

  Append(str, GAPDoc2LaTeXProcs.HeadWithOptions(pi.ExtraPreamble));
  
  # and now the text of the document
  GAPDoc2LaTeXContent(r, str);
  
  # that's it
  Append(str, GAPDoc2LaTeXProcs.Tail);
end;

##  the Body  just prints its content
GAPDoc2LaTeXProcs.Body := GAPDoc2LaTeXContent;

##  the title page,  the most complicated looking function
GAPDoc2LaTeXProcs.TitlePage := function(r, str)
  local   l,  ll, a,  s,  cont;
  
  # page number info for online help
  Append(str, Concatenation("\\logpage{", 
          GAPDoc2LaTeXProcs.StringNrs(r.count{[1..3]}), "}\n"));
  Append(str, "\\begin{titlepage}\n\\mbox{}\\vfill\n\n\\begin{center}");
  
  # title
  l := Filtered(r.content, a-> a.name = "Title");
  Append(str, "{\\maintitlesize \\textbf{");
  s := "";
  GAPDoc2LaTeXContent(l[1], s);
  Append(str, s);
  Append(str, "\\mbox{}}}\\\\\n\\vfill\n\n");
  # set title in info part of PDF document
  Append(str, "\\hypersetup{pdftitle=");
  Append(str, s);
  Append(str, "}\n");
  
  # the title is also used for the page headings
  Append(str, "\\markright{\\scriptsize \\mbox{}\\hfill ");
  Append(str, s);
  Append(str, " \\hfill\\mbox{}}\n");

  # subtitle
  l := Filtered(r.content, a-> a.name = "Subtitle");
  if Length(l)>0 then
    Append(str, "{\\Huge \\textbf{");
    GAPDoc2LaTeXContent(l[1], str);
    Append(str, "\\mbox{}}}\\\\\n\\vfill\n\n");
  fi;
  
  # version
  l := Filtered(r.content, a-> a.name = "Version");
  if Length(l)>0 then
    Append(str, "{\\Huge ");
    GAPDoc2LaTeXContent(l[1], str);
    Append(str, "\\mbox{}}\\\\[1cm]\n");
  fi;

  # date
  l := Filtered(r.content, a-> a.name = "Date");
  if Length(l)>0 then
    Append(str, "{");
    GAPDoc2LaTeXContent(l[1], str);
    Append(str, "\\mbox{}}\\\\[1cm]\n");
  fi;
  Append(str, "\\mbox{}\\\\[2cm]\n");

  # author name(s)
  l := Filtered(r.content, a-> a.name = "Author");
  # collect author list for PDF info
  ll := [];
  for a in l do
    Append(str, "{\\Large \\textbf{");
    s := "";
    GAPDoc2LaTeXContent(rec(content := Filtered(a.content, b->
                   not b.name in ["Email", "Homepage", "Address"])), s);
    Append(str, s);
    Add(ll, s);
    Append(str, "\\mbox{}}}\\\\\n");
  od;
  Append(str, "\\hypersetup{pdfauthor=");
  Append(str, JoinStringsWithSeparator(ll, "; "));
  Append(str, "}\n");

  # extra comment for front page
  l := Filtered(r.content, a-> a.name = "TitleComment");
  if Length(l) > 0 then
    Append(str, "\\mbox{}\\\\[2cm]\n\\begin{minipage}{12cm}\\noindent\n");
    GAPDoc2LaTeXContent(l[1], str);
    Append(str, "\\end{minipage}\n\n");
  fi;
  Append(str, "\\end{center}\\vfill\n\n\\mbox{}\\\\\n");
  
  # email, WWW-homepage and address of author(s), if given
  l := Filtered(r.content, a-> a.name = "Author");
  for a in l do
    cont := List(a.content, b-> b.name);
    if "Email" in cont or "Homepage" in cont or "Address" in cont then
      Append(str, "{\\mbox{}\\\\\n\\small \\noindent \\textbf{");
      GAPDoc2LaTeXContent(rec(content := Filtered(a.content, b->
                   not b.name in ["Email", "Homepage", "Address"])), str);
      Append(str, "}");
      if "Email" in cont then
        Append(str, Concatenation("  ", GAPDocTexts.d.Email, ": "));
        GAPDoc2LaTeX(a.content[Position(cont, "Email")], str);
      fi;
      if "Homepage" in cont then
        Append(str, "\\\\\n");
        Append(str, Concatenation("  ", GAPDocTexts.d.Homepage, ": "));
        GAPDoc2LaTeX(a.content[Position(cont, "Homepage")], str);
      fi;
      if "Address" in cont then
        Append(str, "\\\\\n");
        Append(str, Concatenation("  ", GAPDocTexts.d.Address, 
                                  ": \\begin{minipage}[t]{8cm}\\noindent\n"));
        GAPDoc2LaTeX(a.content[Position(cont, "Address")], str);
        Append(str, "\\end{minipage}\n");
      fi;
      Append(str, "}\\\\\n");
    fi;
  od;

  # Address outside the Author elements
  l := Filtered(r.content, a-> a.name = "Address");
  if Length(l)>0 then
    Append(str, "\n\\noindent ");
    Append(str, Concatenation("\\textbf{", GAPDocTexts.d.Address, 
                              ": }\\begin{minipage}[t]{8cm}\\noindent\n"));
    GAPDoc2LaTeXContent(l[1], str);
    Append(str, "\\end{minipage}\n");
  fi;
  
  Append(str, "\\end{titlepage}\n\n\\newpage");
  
  #  to make physical page numbers same as document page numbers
  Append(str, "\\setcounter{page}{2}\n");

  # abstract
  l := Filtered(r.content, a-> a.name = "Abstract");
  if Length(l)>0 then
    Append(str, Concatenation("{\\small \n\\section*{", GAPDocTexts.d.Abstract,
                              "}\n"));
    # page number info for online help
    Append(str, Concatenation("\\logpage{", 
            GAPDoc2LaTeXProcs.StringNrs(l[1].count{[1..3]}), "}\n"));
    GAPDoc2LaTeXContent(l[1], str);
    Append(str, "\\mbox{}}\\\\[1cm]\n");
  fi;
  
  # copyright page
  l := Filtered(r.content, a-> a.name = "Copyright");
  if Length(l)>0 then
    Append(str, Concatenation("{\\small \n\\section*{", GAPDocTexts.d.Copyright,
                              "}\n"));
    # page number info for online help
    Append(str, Concatenation("\\logpage{", 
            GAPDoc2LaTeXProcs.StringNrs(l[1].count{[1..3]}), "}\n"));
    GAPDoc2LaTeXContent(l[1], str);
    Append(str, "\\mbox{}}\\\\[1cm]\n");
  fi;

  # acknowledgement page
  l := Filtered(r.content, a-> a.name = "Acknowledgements");
  if Length(l)>0 then
    Append(str, Concatenation("{\\small \n\\section*{", 
                              GAPDocTexts.d.Acknowledgements, "}\n"));
    # page number info for online help
    Append(str, Concatenation("\\logpage{", 
            GAPDoc2LaTeXProcs.StringNrs(l[1].count{[1..3]}), "}\n"));
    GAPDoc2LaTeXContent(l[1], str);
    Append(str, "\\mbox{}}\\\\[1cm]\n");
  fi;

  # colophon page
  l := Filtered(r.content, a-> a.name = "Colophon");
  if Length(l)>0 then
    Append(str, Concatenation("{\\small \n\\section*{", GAPDocTexts.d.Colophon,
                              "}\n"));
    # page number info for online help
    Append(str, Concatenation("\\logpage{", 
            GAPDoc2LaTeXProcs.StringNrs(l[1].count{[1..3]}), "}\n"));
    GAPDoc2LaTeXContent(l[1], str);
    Append(str, "\\mbox{}}\\\\[1cm]\n");
  fi;  
  Append(str,"\\newpage\n\n");
end;

## this allows line breaks in URL strings s for use with \texttt{s} by
## inserting some "}\discretionary{}{}{}\texttt{" 
GAPDoc2LaTeXProcs.URLBreaks := function(s)
  local pos, ss, old;
  # not after ://
  pos := PositionSublist(s, "://");
  if pos = fail then
    pos := Minimum(3, Length(s));
  else
    pos := pos + 2;
  fi;
  ss := s{[1..pos]};
  old := pos;
  pos := Position(s, '/', old);
  while pos <> fail and pos+3 < Length(s) do
    Append(ss, s{[old+1..pos]});
    Append(ss, "}\\discretionary {}{}{}\\texttt{");
    old := pos;
    pos := Position(s, '/', old);
  od;
  Append(ss, s{[old+1..Length(s)]});
  return ss;
end;

##  ~ and # characters are correctly escaped
##  arg:  r, str[, pre]
GAPDoc2LaTeXProcs.Link := GAPDoc2LaTeXContent;
GAPDoc2LaTeXProcs.LinkText := GAPDoc2LaTeXContent;
GAPDoc2LaTeXProcs.URL := function(arg)
  local r, str, pre, rr, txt, s;
  r := arg[1];
  str := arg[2];
  if Length(arg)>2 then
    pre := arg[3];
  else
    pre := "";
  fi;
  rr := First(r.content, a-> a.name = "LinkText");
  if rr <> fail then
    txt := "";
    GAPDoc2LaTeXContent(rr, txt);
    rr := First(r.content, a-> a.name = "Link");
    if rr = fail then
      Info(InfoGAPDoc, 1, "#W missing <Link> element for text ", txt, "\n");
      s := "MISSINGLINK";
    else
      s := "";
      # must avoid recoding for first argument of \href
      GAPDoc2LaTeXProcs.recode := false;
      GAPDoc2LaTeXContent(rr, s);
      GAPDoc2LaTeXProcs.recode := true;
    fi;
  else
    s := "";
    GAPDoc2LaTeXProcs.recode := false;
    GAPDoc2LaTeXContent(r, s);
    GAPDoc2LaTeXProcs.recode := true;
    if IsBound(r.attributes.Text) then
      txt := r.attributes.Text;
    else
      # need recode in second argument of \href
      txt := Encode(Unicode(s, "UTF-8"), GAPDoc2LaTeXProcs.Encoder);
      txt := Concatenation("\\texttt{", txt, "}");
    fi;
  fi;
  Append(str, Concatenation("\\href{", pre, s, "} {", txt, "}"));
end;

GAPDoc2LaTeXProcs.Homepage := GAPDoc2LaTeXProcs.URL;

GAPDoc2LaTeXProcs.Email := function(r, str)
  # we add the `mailto://' phrase
  GAPDoc2LaTeXProcs.URL(r, str, "mailto://");
end;

##  the sectioning commands are just translated and labels are
##  generated, if given as attribute
GAPDoc2LaTeXProcs.ChapSect := function(r, str, sect)
  local   posh,  a,  s;
  posh := Position(List(r.content, a-> a.name), "Heading");
  # heading
  Append(str, Concatenation("\n\\", sect, "{"));
  s := "";
  if posh <> fail then      
    GAPDoc2LaTeXProcs.Heading1(r.content[posh], s);
  fi;
  Append(str, "\\textcolor{Chapter }{");
  Append(str, s);
  Append(str, "}}");
  # label for references
  if IsBound(r.attributes.Label) then
    Append(str, "\\label{");
    Append(str, r.attributes.Label);
    Append(str, "}\n");
    # save heading for "Text" style references to section
    GAPDoc2LaTeXProcs._labeledSections.(r.attributes.Label) := s;
  fi;
  # page number info for online help (no r.count below Ignore),
  # we also add a section number and page number independent label,
  # if available
  if IsBound(r.count) then
    Append(str, Concatenation("\\logpage{", 
            GAPDoc2LaTeXProcs.StringNrs(r.count{[1..3]}), "}\n"));
    if IsBound(r.root.six) then
##        a := First(r.root.six, x-> x[3] = r.count{[1..3]});
      a := GAPDoc2LaTeXProcs.firstsix(r, r.count);
      if a <> fail and IsBound(a[7]) then
        Append(str, Concatenation("\\hyperdef{L}{", a[7], "}{}\n"));
      fi;
    fi;
    # the actual content
    if not IsBound(r.root.norecursion) then
      Append(str, "{\n");
      GAPDoc2LaTeXContent(r, str);
      Append(str, "}\n\n");
    fi;
  fi;
end;

##  this really produces the content of the heading
GAPDoc2LaTeXProcs.Heading1 := function(r, str)
  GAPDoc2LaTeXContent(r, str);
end;
##  and this ignores the heading (for simpler recursion)
GAPDoc2LaTeXProcs.Heading := function(r, str)
end;

GAPDoc2LaTeXProcs.Chapter := function(r, str)
  GAPDoc2LaTeXProcs.ChapSect(r, str, "chapter");
end;

GAPDoc2LaTeXProcs.Appendix := function(r, str)
  if r.count[1] = "A" then
    Append(str, "\n\n\\appendix\n\n");
  fi;
  GAPDoc2LaTeXProcs.ChapSect(r, str, "chapter");
end;

GAPDoc2LaTeXProcs.Section := function(r, str)
  GAPDoc2LaTeXProcs.ChapSect(r, str, "section");
end;

GAPDoc2LaTeXProcs.Subsection := function(r, str)
  GAPDoc2LaTeXProcs.ChapSect(r, str, "subsection");
end;

##  table of contents, the job is completely delegated to LaTeX
GAPDoc2LaTeXProcs.TableOfContents := function(r, str)
  # page number info for online help
  Append(str, Concatenation("\\def\\contentsname{", GAPDocTexts.d.Contents, 
          "\\logpage{", GAPDoc2LaTeXProcs.StringNrs(r.count{[1..3]}), "}}\n"));
  Append(str, "\n\\tableofcontents\n\\newpage\n\n");
end;

##  bibliography, the job is completely delegated to LaTeX and BibTeX
GAPDoc2LaTeXProcs.Bibliography := function(r, str)
  local dat, fname, t, b, st, a;
  # check if bib data are in BibXMLext format, in that case produce a 
  # BibTeX file
  dat := r.attributes.Databases;
  dat := SplitString(dat, "", ", \n\t\b");
  dat := Filtered(dat, a-> Length(a) > 3 and 
                                     a{[Length(a)-3..Length(a)]} = ".xml");
  dat := List(dat, a-> Filename(r.root.bibpath, a));
  for fname in dat do
    b := ParseBibXMLextFiles(fname);
    b := List(b.entries, a-> RecBibXMLEntry(a, b.strings, "BibTeX"));
    WriteBibFile(Concatenation(fname, ".bib"), [b, [], []]);
  od;
  if IsBound(r.attributes.Style) then
    st := r.attributes.Style;
  else
    st := "alpha";
  fi;

  # page number info for online help
  Append(str, Concatenation("\\def\\bibname{", GAPDocTexts.d.References,
          "\\logpage{", 
          GAPDoc2LaTeXProcs.StringNrs(r.count{[1..3]}), "}\n"));
  if IsBound(r.root.six) then
##      a := First(r.root.six, x-> x[3] = r.count{[1..3]});
    a := GAPDoc2LaTeXProcs.firstsix(r, r.count);
    if a <> fail and IsBound(a[7]) then
      Append(str, Concatenation("\\hyperdef{L}{", a[7], "}{}\n"));
    fi;
  fi;
  Append(str, "}\n");
  Append(str, "\n\\bibliographystyle{");
  Append(str, st);
  Append(str,"}\n\\bibliography{");
  Append(str, r.attributes.Databases);
  Append(str, "}\n\n");
  # toc entry
  Append(str, "\\addcontentsline{toc}{chapter}{");
  Append(str, GAPDocTexts.d.References);
  Append(str, "}\n\n");
end;

##  as default we normalize white space in text and split the result 
##  into lines (leading and trailing white space is also substituted 
##  by one space).
GAPDoc2LaTeXProcs.PCDATA := function(r, str)
  local   lines,  i;
  if GAPDoc2LaTeXProcs.verbatimPCDATA then
    # no reformatting at all, used for <Alt Only="LaTeX"> content
    Append(str, r.content);
    return;
  fi;
  if Length(r.content)>0 and r.content[1] in WHITESPACE then
    Add(str, ' ');
  fi;
  lines := r.content;
  if GAPDoc2LaTeXProcs.recode = true then
    lines := Encode(Unicode(lines), GAPDoc2LaTeXProcs.Encoder);
  fi;
  lines := FormatParagraph(lines, "left");
  if Length(lines)>0 then
    if r.content[Length(r.content)] in WHITESPACE then
      lines[Length(lines)] := ' ';
    else
      Unbind(lines[Length(lines)]);
    fi;
  fi;
  Append(str, lines);
end;

##  end of paragraph 
GAPDoc2LaTeXProcs.P := function(r, str)
  Append(str, "\n\n");
end;

##  forced line break
GAPDoc2LaTeXProcs.Br := function(r, str)
  Append(str, "\\\\\n");
end;

##  generic function to get content and wrap by some markup
GAPDoc2LaTeXProcs.WrapMarkup := function(r, str, pre, post)
  local s;
  s := "";
  GAPDoc2LaTeXContent(r, s);
  Append(str, Concatenation(pre, s, post));
end;

##  setting in typewriter
GAPDoc2LaTeXProcs.WrapTT := function(r, str)
  GAPDoc2LaTeXProcs.WrapMarkup(r, str, "\\texttt{", "}");
end;

##  GAP keywords 
GAPDoc2LaTeXProcs.K := function(r, str)
  GAPDoc2LaTeXProcs.WrapTT(r, str);
end;

##  verbatim GAP code
GAPDoc2LaTeXProcs.C := function(r, str)
  GAPDoc2LaTeXProcs.WrapTT(r, str);
end;

##  file names
GAPDoc2LaTeXProcs.F := function(r, str)
  GAPDoc2LaTeXProcs.WrapTT(r, str);
end;

##  argument names
GAPDoc2LaTeXProcs.A := function(r, str)
  Append(str, "\\mbox{");
##    GAPDoc2LaTeXProcs.WrapTT(r, str);
  ## the \mdseries is necessary because there is no bold-sl which
  ## LaTeX substitutes by bold-normal, but we want medium-sl
  GAPDoc2LaTeXProcs.WrapMarkup(r, str, "\\texttt{\\mdseries\\slshape ", "}");
  Append(str, "}");
end;

##  simple maths
GAPDoc2LaTeXProcs.M := function(r, str)
  local saveenc;
  Append(str, "$");
  # here the input is already coded in LaTeX
  saveenc := GAPDoc2LaTeXProcs.Encoder;
  GAPDoc2LaTeXProcs.Encoder := "LaTeXleavemarkup";
  GAPDoc2LaTeXContent(r, str);
  GAPDoc2LaTeXProcs.Encoder := saveenc;
  Append(str, "$");
end;

##  in LaTeX same as <M>
GAPDoc2LaTeXProcs.Math := GAPDoc2LaTeXProcs.M;

##  displayed maths
GAPDoc2LaTeXProcs.Display := function(r, str)
  local saveenc;
  if Length(str)>0 and str[Length(str)] <> '\n' then
    Add(str, '\n');
  fi;
  Append(str, "\\[");
  saveenc := GAPDoc2LaTeXProcs.Encoder;
  GAPDoc2LaTeXProcs.Encoder := "LaTeXleavemarkup";
  GAPDoc2LaTeXContent(r, str);
  GAPDoc2LaTeXProcs.Encoder := saveenc;
  Append(str, "\\]\n");
end;

##  emphazised text
GAPDoc2LaTeXProcs.Emph := function(r, str)
  local   a;
  Append(str, "\\emph{");
  GAPDoc2LaTeXContent(r, str);
  Append(str, "}");
end;

##  quoted text
GAPDoc2LaTeXProcs.Q := function(r, str)
  local   a;
  Append(str, "``");
  GAPDoc2LaTeXContent(r, str);
  Append(str, "''");
end;

##  Package names
GAPDoc2LaTeXProcs.Package := function(r, str)
  local   a;
  Append(str, "\\textsf{");
  GAPDoc2LaTeXContent(r, str);
  Append(str, "}");
end;

##  menu items
GAPDoc2LaTeXProcs.B := function(r, str)
  local   a;
  Append(str, "\\textsc{");
  GAPDoc2LaTeXContent(r, str);
  Append(str, "}");
end;

GAPDoc2LaTeXProcs.verbcontent := function(r, delfirst)
  local cont;
  # here we cannot use recoding, fall back to SimplifiedUnicodeString (latin1)
  # first collect content without recoding or reformatting
  cont := GetTextXMLTree(r);
  if GAPDoc2LaTeXProcs.Options.InputEncoding = "latin1" then
    cont := Encode(SimplifiedUnicodeString(Unicode(cont), "latin1"), "latin1");
  fi;
  cont := SplitString(cont, "\n", "");
  # if first line has white space only, we remove it
  if delfirst and Length(cont) > 0 and ForAll(cont[1], x-> x in WHITESPACE) then
    cont := cont{[2..Length(cont)]};
  fi;
  cont := Concatenation(List(cont, a-> Concatenation("  ", a, "\n")));
  return cont;
end;

##  verbatim GAP session
GAPDoc2LaTeXProcs.Verb := function(r, str)
  local   cont,  a,  s;
  Append(str, "\n\\begin{verbatim}");
  Append(str, GAPDoc2LaTeXProcs.verbcontent(r, false));
  Append(str, "\\end{verbatim}\n");
end;

GAPDoc2LaTeXProcs.ExampleLike := function(r, str, label, findprompts)
  local cont, comopt, comchars, sp, pos, c;
  cont := GAPDoc2LaTeXProcs.verbcontent(r, true);
  comopt := "";
  if findprompts then
    comchars := "";
    for c in Concatenation("!@|", LETTERS) do
      if not c in cont and 
         # avoid letters in used command names
         not c in "Vabdegikmnoprtu" then
        Add(comchars, c);
        if Length(comchars) = 3 then
          break;
        fi;
      fi;
    od;
    if Length(comchars) = 3 then
      comopt := Concatenation("commandchars=",comchars,",");
      sp := SplitString(cont, "\n", "");
      cont := "";
      for r in sp do
        if Length(r) > 6 and r{[1..7]} = "  gap> " then
          Append(cont, Concatenation("  ",comchars{[1]},
                 "gapprompt",comchars{[2]},
                 "gap>",comchars{[3]}," ",comchars{[1]},"gapinput",
                 comchars{[2]},r{[8..Length(r)]},comchars{[3]},"\n"));
        elif Length(r) > 3 and r{[1..4]} = "  > " then
          Append(cont, Concatenation("  ",comchars{[1]},
                 "gapprompt",comchars{[2]},
                 ">",comchars{[3]}," ",comchars{[1]},"gapinput",
                 comchars{[2]},r{[5..Length(r)]},comchars{[3]},"\n"));
        elif Length(r) > 5 and r{[1..5]} = "  brk" then
          pos := Position(r, '>');
          Append(cont, Concatenation("  ",comchars{[1]},
                 "gapbrkprompt",comchars{[2]},
                 r{[3..pos]},comchars{[3]}," ",comchars{[1]},"gapinput",
                 comchars{[2]},r{[pos+2..Length(r)]},comchars{[3]},"\n"));
        else
          Append(cont, r);
          Add(cont, '\n');
        fi;
      od;
    fi;
  fi;
  Append(str, Concatenation("\n\\begin{Verbatim}[",comopt,
          "fontsize=\\small,",
          "frame=single,label=", label, "]\n"));
  Append(str, cont);
  Append(str, "\\end{Verbatim}\n");
end;

##  log of session and GAP code is typeset the same way as <Example>
GAPDoc2LaTeXProcs.Example := function(r, str)
  GAPDoc2LaTeXProcs.ExampleLike(r, str, GAPDocTexts.d.Example, true);
end;
GAPDoc2LaTeXProcs.Log := function(r, str)
  GAPDoc2LaTeXProcs.ExampleLike(r, str, GAPDocTexts.d.Log, true);
end;
GAPDoc2LaTeXProcs.Listing := function(r, str)
  if IsBound(r.attributes.Type) then
    GAPDoc2LaTeXProcs.ExampleLike(r, str, r.attributes.Type, true);
  else
    GAPDoc2LaTeXProcs.ExampleLike(r, str, "", true);
  fi;
end;

##  explicit labels
GAPDoc2LaTeXProcs.Label := function(r, str)
  Append(str, "\\label{");
  Append(str, r.attributes.Name);
  Append(str, "}");
end;

##  citations
GAPDoc2LaTeXProcs.Cite := function(r, str)
  Append(str, "\\cite");
  if IsBound(r.attributes.Where) then
    Add(str, '[');
    Append(str, Encode(Unicode(r.attributes.Where), GAPDoc2LaTeXProcs.Encoder));
    Add(str, ']');
  fi;
  Add(str, '{');
  Append(str, r.attributes.Key);
  Add(str, '}');
end;

##  explicit index entries
GAPDoc2LaTeXProcs.Subkey := GAPDoc2LaTeXContent;
##  'makeindex' has the following rule to include its special characters
GAPDoc2LaTeXProcs.EscapeIndexChars := function(str)
  str := ReplacedString(str, "\"", "\"\"");
  str := ReplacedString(str, "@", "\"@");
  str := ReplacedString(str, "!", "\"!");
  str := ReplacedString(str, "|", "\"|");
  return str;
end;
GAPDoc2LaTeXProcs.Index := function(r, str)
  local s, sub, a, esc;
  esc := GAPDoc2LaTeXProcs.EscapeIndexChars;
  s := "";
  sub := "";
  for a in r.content do
    if a.name = "Subkey" then
      GAPDoc2LaTeX(a, sub);
    else
      GAPDoc2LaTeX(a, s);
    fi;
  od;
  NormalizeWhitespace(s);
  NormalizeWhitespace(sub);
  if IsBound(r.attributes.Key) then
    s := Concatenation(esc(r.attributes.Key), "@", esc(s));
  fi;
  if Length(sub) > 0 then
    s := Concatenation(s, "!", esc(sub));
  elif IsBound(r.attributes.Subkey) then
    s := Concatenation(s, "!", esc(r.attributes.Subkey));
  fi;
  Append(str, "\\index{");
  Append(str, s);
  Append(str, "}");
end;

##  this produces an implicit index entry and a label entry
GAPDoc2LaTeXProcs.LikeFunc := function(r, str, typ)
  local nam, namclean, lab, inam, i;
  Append(str, "\\noindent\\textcolor{FuncColor}{$\\triangleright$\\enspace\\texttt{");
  nam := r.attributes.Name;
  namclean := GAPDoc2LaTeXProcs.DeleteUsBs(nam);
  # we allow _,  \ and so on here
  nam := GAPDoc2LaTeXProcs.EscapeAttrVal(nam);
  Append(str, nam);
  if IsBound(r.attributes.Arg) then
    Append(str, "({\\mdseries\\slshape ");
    Append(str, GAPDoc2LaTeXProcs.EscapeAttrVal(
                NormalizedArgList(r.attributes.Arg)));
    Append(str, "})");
  fi;
  # possible label
  if IsBound(r.attributes.Label) then
    lab := Concatenation("!", r.attributes.Label);
  else
    lab := "";
  fi;
  # index entry
  # handle extremely long names
  if Length(nam) > GAPDoc2LaTeXProcs.MaxIndexEntryWidth then
    inam := nam{[1..3]};
    for i in [4..Length(nam)-3] do
      if nam[i] in CAPITALLETTERS then
        Append(inam, "}\\-\\texttt{");
      fi;
      Add(inam, nam[i]);
    od;
    Add(inam, nam[Length(nam)-2]); Add(inam, nam[Length(nam)-1]);
    Add(inam, nam[Length(nam)]);
  else
    inam := nam;
  fi;
  Append(str, Concatenation("\\index{", 
          GAPDoc2LaTeXProcs.EscapeIndexChars(nam), "@\\texttt{",
          inam, "}", lab, "}\n"));
  # label (if not given, the default is the Name)
  if IsBound(r.attributes.Label) then
    namclean := Concatenation(namclean, ":", r.attributes.Label);
  fi;
  Add(GAPDoc2LaTeXProcs._currentSubsection, namclean);
  Append(str, Concatenation("\\label{", namclean, "}\n"));
  # some hint about the type of the variable
  Append(str, "}\\hfill{\\scriptsize (");
  Append(str, typ);
  Append(str, ")}}\\\\\n");
end;

GAPDoc2LaTeXProcs.Func := function(r, str)
  GAPDoc2LaTeXProcs.LikeFunc(r, str, GAPDocTexts.d.Func);
end;

GAPDoc2LaTeXProcs.Oper := function(r, str)
  GAPDoc2LaTeXProcs.LikeFunc(r, str, GAPDocTexts.d.Oper);
end;

GAPDoc2LaTeXProcs.Constr := function(r, str)
  GAPDoc2LaTeXProcs.LikeFunc(r, str, GAPDocTexts.d.Constr);
end;

GAPDoc2LaTeXProcs.Meth := function(r, str)
  GAPDoc2LaTeXProcs.LikeFunc(r, str, GAPDocTexts.d.Meth);
end;

GAPDoc2LaTeXProcs.Filt := function(r, str)
  # r.attributes.Type could be "representation", "category", ...
  if IsBound(r.attributes.Type) then
    GAPDoc2LaTeXProcs.LikeFunc(r, str, r.attributes.Type);
  else
    GAPDoc2LaTeXProcs.LikeFunc(r, str, GAPDocTexts.d.Filt);
  fi;
end;

GAPDoc2LaTeXProcs.Prop := function(r, str)
  GAPDoc2LaTeXProcs.LikeFunc(r, str, GAPDocTexts.d.Prop);
end;

GAPDoc2LaTeXProcs.Attr := function(r, str)
  GAPDoc2LaTeXProcs.LikeFunc(r, str, GAPDocTexts.d.Attr);
end;

GAPDoc2LaTeXProcs.Var := function(r, str)
  GAPDoc2LaTeXProcs.LikeFunc(r, str, GAPDocTexts.d.Var);
end;

GAPDoc2LaTeXProcs.Fam := function(r, str)
  GAPDoc2LaTeXProcs.LikeFunc(r, str, GAPDocTexts.d.Fam);
end;

GAPDoc2LaTeXProcs.InfoClass := function(r, str)
  GAPDoc2LaTeXProcs.LikeFunc(r, str, GAPDocTexts.d.InfoClass);
end;

##  using the HelpData(.., .., "ref") interface
GAPDoc2LaTeXProcs.ResolveExternalRef := function(bookname,  label, nr)
  local info, match, res;
  info := HELP_BOOK_INFO(bookname);
  if info = fail then
    return fail;
  fi;
  match := Concatenation(HELP_GET_MATCHES(info, SIMPLE_STRING(label), true));
  #   maybe change, and check if there are matches to several subsections?
  #ssecs := List(match, i-> HELP_BOOK_HANDLER.(info.handler).HelpData(info,
  #         match[i][2], "ref")[7]);
  if Length(match) < nr then
    return fail;
  fi;
  res := GetHelpDataRef(info, match[nr][2]);
  res[1] := SubstitutionSublist(res[1], " (not loaded): ", ": ", "one");
  return res;
end;

GAPDoc2LaTeXProcs.Ref := function(r, str)
  local   funclike,  int,  txt,  ref,  lab,  sectlike, slab;
  
  # function like cases
  funclike := [ "Func", "Oper", "Constr", "Meth", "Filt", "Prop", "Attr", 
                "Var", "Fam", "InfoClass" ];
  int := Intersection(funclike, NamesOfComponents(r.attributes));
  if Length(int)>0 then
    txt := r.attributes.(int[1]);
    if IsBound(r.attributes.Label) then
      lab := Concatenation(txt, ":", r.attributes.Label);
    else
      lab := txt;
    fi;
    if IsBound(r.attributes.BookName) then
      slab := txt;
      if IsBound(r.attributes.Label) then
        slab := Concatenation(slab, " (", r.attributes.Label, ")");
      fi;
      ref := GAPDoc2LaTeXProcs.ResolveExternalRef(
                                             r.attributes.BookName, slab, 1);
      if ref = fail then
        Info(InfoGAPDoc, 1, "#W WARNING: non resolved reference: ",
                            r.attributes, "\n");
        ref := Concatenation(" (", Encode(Unicode(lab),
               GAPDoc2LaTeXProcs.Encoder)
               , "???)");
      else
        # the search text for online help including book name
        ref := Concatenation(" (\\textbf{", 
                              GAPDoc2LaTeXProcs.EscapeAttrVal(ref[1]), "})");
      fi;
    else
      ref := Concatenation(" (\\ref{", GAPDoc2LaTeXProcs.DeleteUsBs(lab), "})");
    fi;
    # delete ref, if pointing to current subsection
    if not IsBound(r.attributes.BookName) and 
                 IsBound(GAPDoc2LaTeXProcs._currentSubsection) and 
                 lab in GAPDoc2LaTeXProcs._currentSubsection then
      ref := "";
    fi;
    Append(str, Concatenation("\\texttt{", GAPDoc2LaTeXProcs.EscapeAttrVal(txt), 
            "}", ref));
    return;
  fi;
  
  # section like cases
  sectlike := ["Chap", "Sect", "Subsect", "Appendix"];
  int := Intersection(sectlike, NamesOfComponents(r.attributes));
  if Length(int)>0 then
    txt := r.attributes.(int[1]);
    if IsBound(r.attributes.Label) then
      lab := r.attributes.Label;
    else
      lab := txt;
    fi;
    if IsBound(r.attributes.BookName) then
      ref := GAPDoc2LaTeXProcs.ResolveExternalRef(
                                          r.attributes.BookName, lab, 1);
      if ref = fail then
        Info(InfoGAPDoc, 1, "#W WARNING: non resolved reference: ",
                            r.attributes, "\n");
        ref := Concatenation(" (", lab, "???)");
      else
        # the search text for online help including book name
        ref := Concatenation(" (\\textbf{", GAPDoc2LaTeXProcs.EscapeAttrVal(ref[1]), "})");
      fi;
    elif IsBound(r.attributes.Style) and r.attributes.Style = "Text" then
      if IsBound(GAPDoc2LaTeXProcs._labeledSections.(lab)) then
        ref := Concatenation("\\hyperref[",lab,"]{`", StripBeginEnd(
                GAPDoc2LaTeXProcs._labeledSections.(lab), WHITESPACE), "'}"); 
      else
        Info(InfoGAPDoc, 1, "#W WARNING: non resolved reference: ",
                            r.attributes, "\n");
        ref := "`???'";
      fi;
    else
      # with sectioning references Label must be given
      lab := r.attributes.(int[1]);
      #ref := Concatenation("\\ref{", GAPDoc2LaTeXProcs.EscapeAttrVal(lab), "}");
      ref := Concatenation("\\ref{", lab, "}");
    fi;
    Append(str, ref);
    return;
  fi;
  
  # neutral reference to a label
  if IsBound(r.attributes.BookName) then
    if IsBound(r.attributes.Label) then
      lab := r.attributes.Label;
    else
      lab := "_X_X_X";
    fi;
    ref := GAPDoc2LaTeXProcs.ResolveExternalRef(
                                        r.attributes.BookName, lab, 1);
    if ref = fail then
      Info(InfoGAPDoc, 1, "#W WARNING: non resolved reference: ",
                            r.attributes, "\n");
      ref := Concatenation(" ", GAPDoc2LaTeXProcs.EscapeAttrVal(lab), "??? ");
    else
      # the search text for online help including book name
      ref := Concatenation(" \\textbf{", GAPDoc2LaTeXProcs.EscapeAttrVal(ref[1]), "}");
    fi;
  else
    lab := r.attributes.Label;
    ref := Concatenation("\\ref{", GAPDoc2LaTeXProcs.EscapeAttrVal(lab), "}");
  fi;
  Append(str, ref);
  return;
end;

# just process
GAPDoc2LaTeXProcs.Address := function(r, str)
  GAPDoc2LaTeXContent(r, str);
end;

GAPDoc2LaTeXProcs.Description := function(r, str)
  Append(str, "\n\n");
  GAPDoc2LaTeXContent(r, str);
end;

GAPDoc2LaTeXProcs.Returns := function(r, str)
  Append(str, Concatenation("\\textbf{\\indent ", GAPDocTexts.d.Returns, 
                            ":\\ }\n"));
  GAPDoc2LaTeXContent(r, str); 
  Append(str,"\n\n");
end;

GAPDoc2LaTeXProcs.ManSection := function(r, str)
  local   funclike,  f,  lab,  i, a;
  
  # if there is a Heading then handle as subsection
  if ForAny(r.content, a-> IsRecord(a) and a.name = "Heading") then
    GAPDoc2LaTeXProcs._currentSubsection := r.count{[1..3]};
    GAPDoc2LaTeXProcs.ChapSect(r, str, "subsection");
    Unbind(GAPDoc2LaTeXProcs._currentSubsection);
    return;
  fi;
  # function like elements
  funclike := [ "Func", "Oper", "Constr", "Meth", "Filt", "Prop", "Attr",
                "Var", "Fam", "InfoClass" ];
  
  # heading comes from name of first function like element
  i := 1;
  while not r.content[i].name in funclike do
    i := i+1;
  od;
  f := r.content[i];
  if IsBound(f.attributes.Label) then
    lab := Concatenation(" (", f.attributes.Label, ")");
  else
    lab := "";
  fi;
  Append(str, Concatenation("\n\n\\subsection{\\textcolor{Chapter }{", 
          GAPDoc2LaTeXProcs.EscapeAttrVal(f.attributes.Name), lab, "}}\n"));
  # page number info for online help
  Append(str, Concatenation("\\logpage{", 
          GAPDoc2LaTeXProcs.StringNrs(r.count{[1..3]}), "}\\nobreak\n"));
  # label for references
  if IsBound(r.attributes.Label) then
    Append(str, "\\label{");
    Append(str, r.attributes.Label);
    Append(str, "}\n");
    # save heading for "Text" style references to section
    GAPDoc2LaTeXProcs._labeledSections.(r.attributes.Label) := Concatenation(
                       GAPDoc2LaTeXProcs.EscapeAttrVal(f.attributes.Name), lab);
  fi;
  if IsBound(r.root.six) then
##      a := First(r.root.six, x-> x[3] = r.count{[1..3]});
    a := GAPDoc2LaTeXProcs.firstsix(r, r.count);
    if a <> fail and IsBound(a[7]) then
      Append(str, Concatenation("\\hyperdef{L}{", a[7], "}{}\n"));
    fi;
  fi;
  # to avoid references to local subsection in description:
  GAPDoc2LaTeXProcs._currentSubsection := r.count{[1..3]};
  Append(str, "{");
  GAPDoc2LaTeXContent(r, str);
  Append(str, "}\n\n");
  Unbind(GAPDoc2LaTeXProcs._currentSubsection);
end;

GAPDoc2LaTeXProcs.Mark := function(r, str)
  Append(str, "\n\\item[{");
  GAPDoc2LaTeXContent(r, str);
  Append(str, "}] ");
end;

GAPDoc2LaTeXProcs.Item := function(r, str)
  Append(str, "\n\\item ");
  GAPDoc2LaTeXContent(r, str);
end;

GAPDoc2LaTeXProcs.List := function(r, str)
  local   item,  type,  a;
  if "Mark" in List(r.content, a-> a.name) then
    item := "";
    type := "description";
  else
    item := "\n\\item ";
    type := "itemize";
  fi;
  Append(str, Concatenation("\n\\begin{", type, "}"));
  for a in r.content do
    if a.name = "Mark" then
      GAPDoc2LaTeXProcs.Mark(a, str);
    elif a.name = "Item" then
      Append(str, item);
      GAPDoc2LaTeXContent(a, str);
    fi;
  od;
  Append(str, Concatenation("\n\\end{", type, "}\n"));
end;

GAPDoc2LaTeXProcs.Enum := function(r, str)
  Append(str, "\n\\begin{enumerate}");
  GAPDoc2LaTeXContent(r, str);
  Append(str, "\n\\end{enumerate}\n");
end;

GAPDoc2LaTeXProcs.TheIndex := function(r, str)
  local a;
  # page number info for online help
  Append(str, Concatenation("\\def\\indexname{", GAPDocTexts.d.Index, 
            "\\logpage{", GAPDoc2LaTeXProcs.StringNrs(r.count{[1..3]}), "}\n"));
  if IsBound(r.root.six) then
##      a := First(r.root.six, x-> x[3] = r.count{[1..3]});
    a := GAPDoc2LaTeXProcs.firstsix(r, r.count);
    if a <> fail and IsBound(a[7]) then
      Append(str, Concatenation("\\hyperdef{L}{", a[7], "}{}\n"));
    fi;
  fi;
  Append(str, "}\n\n");
  # toc entry
  Append(str, "\\cleardoublepage\n\\phantomsection\n");
  Append(str, "\\addcontentsline{toc}{chapter}{");
  Append(str, GAPDocTexts.d.Index);
  Append(str, "}\n");
  Append(str, "\n\n\\printindex\n\n");
end;

# like PCDATA
GAPDoc2LaTeXProcs.EntityValue := GAPDoc2LaTeXProcs.PCDATA;

GAPDoc2LaTeXProcs.Table := function(r, str)
  local cap;
  if (IsBound(r.attributes.Only) and r.attributes.Only <> "LaTeX") or
     (IsBound(r.attributes.Not) and r.attributes.Not = "LaTeX") then
    return;
  fi;
  # head part of table and tabular
  if IsBound(r.attributes.Label) then
    Append(str, "\\mbox{}\\label{");
    Append(str, r.attributes.Label);
    Add(str, '}');
  fi;
  Append(str, "\\begin{center}\n\\begin{tabular}{");
  Append(str, r.attributes.Align);
  Add(str, '}');
  # the rows of the table
  GAPDoc2LaTeXContent(r, str);
  # the trailing part with caption, if given
  Append(str, "\\end{tabular}\\\\[2mm]\n");
  cap := Filtered(r.content, a-> a.name = "Caption");
  if Length(cap) > 0 then
    GAPDoc2LaTeXProcs.Caption1(cap[1], str);
  fi;
  Append(str, "\\end{center}\n\n");
end;

# do nothing, we call .Caption1 directly in .Table
GAPDoc2LaTeXProcs.Caption := function(r, str)
  return;
end;

# here the caption text is produced
GAPDoc2LaTeXProcs.Caption1 := function(r, str)
  Append(str, Concatenation("\\textbf{", GAPDocTexts.d.Table, ": }"));
  GAPDoc2LaTeXContent(r, str);
end;

GAPDoc2LaTeXProcs.HorLine := function(r, str)
  Append(str, "\\hline\n");
end;

GAPDoc2LaTeXProcs.Row := function(r, str)
  local i, l;
  l := Filtered(r.content, a-> a.name = "Item");
  for i in [1..Length(l)-1] do
    GAPDoc2LaTeXContent(l[i], str);
    Append(str, "&\n");
  od;
  GAPDoc2LaTeXContent(l[Length(l)], str);
  Append(str, "\\\\\n");
end;

GAPDoc2LaTeXProcs.Alt := function(r, str)
  local take, types;
  take := false;
  if IsBound(r.attributes.Only) then
    NormalizeWhitespace(r.attributes.Only);
    types := SplitString(r.attributes.Only, "", " ,");
    if "LaTeX" in types or "BibTeX" in types then
      take := true;
      GAPDoc2LaTeXProcs.recode := false;
      GAPDoc2LaTeXProcs.verbatimPCDATA := true;
    fi;
  fi;
  if IsBound(r.attributes.Not) then
    NormalizeWhitespace(r.attributes.Not);
    types := SplitString(r.attributes.Not, "", " ,");
    if not "LaTeX" in types then
      take := true;
    fi;
  fi;
  if take then
    GAPDoc2LaTeXContent(r, str);
  fi;
  GAPDoc2LaTeXProcs.recode := true;
  GAPDoc2LaTeXProcs.verbatimPCDATA := false;
end;

# copy a few entries with two element names
GAPDoc2LaTeXProcs.E := GAPDoc2LaTeXProcs.Emph;
GAPDoc2LaTeXProcs.Keyword := GAPDoc2LaTeXProcs.K;
GAPDoc2LaTeXProcs.Code := GAPDoc2LaTeXProcs.C;
GAPDoc2LaTeXProcs.File := GAPDoc2LaTeXProcs.F;
GAPDoc2LaTeXProcs.Button := GAPDoc2LaTeXProcs.B;
GAPDoc2LaTeXProcs.Arg := GAPDoc2LaTeXProcs.A;
GAPDoc2LaTeXProcs.Quoted := GAPDoc2LaTeXProcs.Q;
GAPDoc2LaTeXProcs.Par := GAPDoc2LaTeXProcs.P;


[ Dauer der Verarbeitung: 0.41 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge