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


Quelle  BibTeX.gi   Sprache: unbekannt

 
#############################################################################
##
#W  BibTeX.gi                    GAPDoc                          Frank Lübeck
##
##
#Y  Copyright (C)  2000,  Frank Lübeck,  Lehrstuhl D für Mathematik,  
#Y  RWTH Aachen
##  
##  The files BibTeX.g{d,i} contain a parser for BibTeX files and some
##  functions for printing BibTeX entries in different formats.
##  

##  normalize author/editor name lists: last-name, initial(s) of first
##  name(s) and ...
##  see Lamport: LaTeX App.B 1.2
InstallGlobalFunction(NormalizedNameAndKey, function(str)
  local   isutf8, nbsp, ini, new,  pp,  p,  a,  i,  names,  norm,  keyshort,  
          keylong,  res, utf8initial, nstr;
  utf8initial := function(s)
    local i, n;
    i := 1;
    while Length(s) <= i and s[i] in "-.{}\\\"\'`\003" do
      i := i+1;
    od;
    if i > Length(s) then
      return fail;
    fi;
    n := UNICODE_RECODE.UnicodeUTF8Char(s, i);
    return Encode(Unicode([n]),"UTF-8");
  end;
  # do almost nothing if already list of strings (e.g., from BibXMLext tools
  if IsString(str) then
    isutf8 := (Unicode(str) <> fail);
    # first normalize white space inside braces { ... } and change
    # spaces to non-spaces (removed below)
    nbsp := '\003';
    new := "";
    pp := 0;
    p := Position(str, '{');
    while p <> fail do
      Append(new, str{[pp+1..p-1]});
      pp := PositionMatchingDelimiter(str, "{}", p);
      a := NormalizedWhitespace(str{[p..pp]});
      for i in [1..Length(a)] do
        if a[i] = ' ' then
          a[i] := nbsp;
        fi;
      od;
      Append(new, a);
      p := Position(str, '{', pp);
    od;
    if Length(new)>0 then
      str := Concatenation(new, str{[pp+1..Length(str)]});
    fi;
    
    # split into names:
    names := [];
    pp := 0;
    p := PositionSublist(str, "and");
    while p <> fail do
      # "and" is only delimiter if surrounded by white space
      if not (str[p-1] in WHITESPACE and Length(str)>p+2 and str[p+3] in
                 WHITESPACE) then
        p := PositionSublist(str, "and", p);
      else
        Add(names, str{[pp+1..p-2]});
        pp := p+3;
        p := PositionSublist(str, "and", pp);
      fi;
    od;
    Add(names, str{[pp+1..Length(str)]});
    
    # normalize a single name
    norm := function(str)
      local   n,  i,  lnam,  j,  fnam, fnamfull;
      # special case "et. al."
      if str="others" then
        return ["others", "", ""];
      fi;
     
      # first some normalization on the string
      RemoveCharacters(str,"[]");
      str := SubstitutionSublist(str, "\\~", "BSLTILDE");
      str := SubstitutionSublist(str, "~", " ");
      str := SubstitutionSublist(str, "BSLTILDE", "\\~");
      str := SubstitutionSublist(str, ".", ". ");
      StripBeginEnd(str, WHITESPACE);
      n := SplitString(str, "", WHITESPACE);
      # check if in "lastname, firstname" notation
      # find last ","
      i := Length(n);
      while i>0 and n[i]<>"," and n[i][Length(n[i])] <> ',' do
        i := i-1;
      od;
      if i>0 then
        # last name
        lnam := "";
        for j in [1..i] do
          Append(lnam, n[j]);
          if j < i then
            Add(lnam, ' ');
          fi;
          lnam := Filtered(lnam, x-> x<>',');
        od;
        # first name initials
        fnam := "";
        for j in [i+1..Length(n)] do
          if isutf8 then
            ini := utf8initial(n[j]);
          else
            ini := First(n[j], x-> not x in WHITESPACE 
                              and not x in "-.{}\\\"\'`\003");
            if ini <> fail then
              ini := [ini];
            fi;
          fi;
          if ini <> fail then
            Append(fnam, ini);
            Append(fnam, ". ");
          fi;
        od;
        fnamfull := JoinStringsWithSeparator(n{[i+1..Length(n)]}, " ");
      else
        # last name is last including words not starting with
        # capital letters
        i := Length(n);
        while i>1 and First(n[i-1], a-> a in LETTERS) in SMALLLETTERS do
          i := i-1;
        od;
        # last name 
        lnam := "";
        for j in [i..Length(n)] do
          Append(lnam, n[j]);
          if j < Length(n) then
            Add(lnam, ' ');
          fi;
        od;
        # first name initials
        fnam := "";
        for j in [1..i-1] do
          if isutf8 then
            ini := utf8initial(n[j]);
          else
            ini := First(n[j], x-> not x in WHITESPACE 
                              and not x in "-.{}\\\"\'`\003");
            if ini <> fail then
              ini := [ini];
            fi;
          fi;
          if ini <> fail then
            Append(fnam, ini);
            Append(fnam, ". ");
          fi;
        od;
        fnamfull := JoinStringsWithSeparator(n{[1..i-1]}, " ");
      fi;
      for j in [1..Length(lnam)] do
        if lnam[j] = '\003' then
          lnam[j] := ' ';
        fi;
      od;
      for j in [1..Length(fnamfull)] do
        if fnamfull[j] = '\003' then
          fnamfull[j] := ' ';
        fi;
      od;
      while Length(fnam) > 0 and fnam[Length(fnam)] in WHITESPACE do
        fnam := fnam{[1..Length(fnam)-1]};
      od;
      return [lnam, fnam, fnamfull];
    end;
    
    names := List(names, norm);
  else
    names := str;
  fi;
  keyshort := "";
  keylong := "";
  res := "";
  for a in names do
    if Length(res)>0 then
      Append(res, " and ");
    fi;
    Append(res, a[1]);
    Append(res, ", ");
    Append(res, a[2]);
    if a[1] = "others" then
      Add(keyshort, '+');
    else
      # simplify non-ASCII characters
      nstr := SimplifiedUnicodeString(Unicode(a[1], "UTF-8"), "ASCII");
      nstr := Encode(nstr, "ASCII");
      p := 1;
      while p <= Length(nstr) and not nstr[p] in CAPITALLETTERS do
        p := p+1;
      od;
      if p > Length(nstr) then
        p := 1;
      fi;
      if nstr[p] in LETTERS then
        Add(keyshort, nstr[p]);
      else
        Add(keyshort, 'X');
      fi;
      Append(keylong, STRING_LOWER(Filtered(nstr{[p..Length(nstr)]},
              x-> x in LETTERS)));
    fi;
  od;
  if Length(keyshort)>3 then
    keyshort := keyshort{[1,2]};
    Add(keyshort, '+');
  fi;
  return [res, keyshort, keylong, names];
end);

##  <#GAPDoc Label="ParseBibFiles">
##  <ManSection >
##  <Func Arg="bibfile1[, bibfile2[, ...]]" Name="ParseBibFiles" />
##  <Func Arg="str1[, str2[, ...]]" Name="ParseBibStrings" />
##  <Returns>list <C>[list of bib-records, list of abbrevs, list  of 
##  expansions]</C></Returns>
##  <Description>
##  The first function parses the files <A>bibfile1</A> and so on (if a file 
##  does not
##  exist the  extension <C>.bib</C> is appended)  in &BibTeX; format
##  and returns a list  as follows: <C>[entries, strings, texts]</C>.
##  Here <C>entries</C>  is a  list of records,  one record  for each
##  reference  contained in  <A>bibfile</A>.  Then <C>strings</C>  is
##  a  list of  abbreviations  defined  by <C>@string</C>-entries  in
##  <A>bibfile</A> and <C>texts</C>  is a list which  contains in the
##  corresponding position  the full  text for such  an abbreviation.
##  <P/>
##  The second function does the same, but the input is given as &GAP; strings
##  <A>str1</A> and so on.<P/>
##  
##  The records in <C>entries</C> store key-value pairs of a &BibTeX;
##  reference in the  form <C>rec(key1 = value1,  ...)</C>. The names
##  of  the  keys are  converted  to  lower  case.  The type  of  the
##  reference (i.e.,  book, article,  ...) and  the citation  key are
##  stored as  components <C>.Type</C> and <C>.Label</C>. The records
##  also have a   <C>.From</C> field that says that the data are read 
##  from a &BibTeX; source.<P/>
##  
##  As an example consider the following &BibTeX; file.
##  
##  <Listing Type="doc/test.bib">
##  @string{ j  = "Important Journal" }
##  @article{ AB2000, Author=  "Fritz A. First and Sec, X. Y.", 
##  TITLE="Short", journal = j, year = 2000 }
##  </Listing> 
##  
##  <Example>
##  gap> gddirs := DirectoriesPackageLibrary("gapdoc","doc");;
##  gap> f := Filename(gddirs, "test.bib");;
##  gap> bib := ParseBibFiles(f);
##  [ [ rec( From := rec( BibTeX := true ), Label := "AB2000", 
##            Type := "article", author := "Fritz A. First and Sec, X. Y."
##              , journal := "Important Journal", title := "Short", 
##            year := "2000" ) ], [ "j" ], [ "Important Journal" ] ]
##  </Example>
##  </Description>
##  </ManSection>
##  <#/GAPDoc>
##  
InstallGlobalFunction(ParseBibFiles, function(arg)
  local s, entries, stringlabels, strings, str, file;
  s := Filtered(arg, x-> IsList(x) and not IsString(x));
  if Length(s) > 0 then
    entries := s[1][1];
    stringlabels := s[1][2]; 
    strings := s[1][3];
    arg := Filtered(arg, IsString);
  else
    entries := [];
    stringlabels := []; 
    strings := [];
  fi;
  
  for file in arg do
    str := StringFile(file);
    if str=fail then
      str := StringFile(Concatenation(file, ".bib"));
    fi;
    if str=fail then 
      Info(InfoBibTools, 1, "#W WARNING: Cannot find bib-file ", 
                                                      file, "[.bib]\n");
      return fail;
    fi;
    ParseBibStrings(str, [entries, stringlabels, strings]);
  od;
  return [entries, stringlabels, strings];
end);

InstallGlobalFunction(ParseBibStrings, function(arg)
  local s, entries, stringlabels, strings, p, r, pb, Type, ende, comp, pos, str;
  s := Filtered(arg, x-> IsList(x) and not IsString(x));
  if Length(s) > 0 then
    entries := s[1][1];
    stringlabels := s[1][2]; 
    strings := s[1][3];
    arg := Filtered(arg, IsString);
  else
    entries := [];
    stringlabels := []; 
    strings := [];
  fi;
  
  for str in arg do
    # find entries
    p := Position(str, '@');
    while p<>fail do
      r := rec();
      # type 
      pb := Position(str, '{', p);
      s := LowercaseString(StripBeginEnd(str{[p+1..pb-1]}, WHITESPACE));
      p := pb;
      if s = "string" then
        # a string is normalized and stored for later substitutions 
        pb := Position(str, '=', p);
        Add(stringlabels, 
            LowercaseString(StripBeginEnd(str{[p+1..pb-1]}, WHITESPACE)));
        p := pb;
        pb := PositionMatchingDelimiter(str, "{}", p);
        s := StripBeginEnd(str{[p+1..pb-1]}, WHITESPACE);
        if (s[1]='\"' and s[Length(s)]='\"') or
           (s[1]='{' and s[Length(s)]='}') then
          s := s{[2..Length(s)-1]};
        fi;
        Add(strings, s);
        p := pb;
      else
        # type and label of entry
        r := rec(From := rec(BibTeX := true), Type := s);
        # end of bibtex entry, for better recovery from errors
        ende := PositionMatchingDelimiter(str, "{}", p);
        pb := Position(str, ',', p);
        if not IsInt(pb) or pb > ende then 
          # doesn't seem to be a correct entry, ignore
          p := Position(str, '@', ende);
          continue;
        fi;
        r.Label := StripBeginEnd(str{[p+1..pb-1]}, WHITESPACE);
        p := pb;
        # get the components
        pb := Position(str, '=', p);
        while pb<>fail and pb < ende do
          comp := LowercaseString(StripBeginEnd(str{[p+1..pb-1]}, 
                          Concatenation(",", WHITESPACE)));
          pb := pb+1;
          while str[pb] in WHITESPACE do
            pb := pb+1;
          od;
          p := pb;
          if str[p] = '\"' then
            pb := Position(str, '\"', p);
            # if double quote is escaped, then go to next one
            while str[pb-1]='\\' do
              pb := Position(str, '\"', pb);
            od;
            r.(comp) := str{[p+1..pb-1]};
          elif str[p] = '{' then
            pb := PositionMatchingDelimiter(str, "{}", p);
            r.(comp) := str{[p+1..pb-1]};
          else 
            pb := p+1;
            while (not str[pb] in WHITESPACE) and str[pb] <> ',' and 
                       str[pb] <> '}' do
              pb := pb+1;
            od;
            s := str{[p..pb-1]};
            # number 
            if Int(s)<>fail then
              r.(comp) := s;
            else
              # abbrev string, look up and substitute
              s := LowercaseString(s);
              pos := Position(stringlabels, s);
              if pos=fail then
                r.(comp) := Concatenation("STRING-NOT-KNOWN: ", s);
              else
                r.(comp) := strings[pos];
              fi;  
            fi;
          fi;
          p := pb+1;
          pb := Position(str, '=', p);
        od;
        Add(entries, r);
      fi;
      p := Position(str, '@', p);
    od;
  od;
  return [entries, stringlabels, strings];
end);

##  <#GAPDoc Label="NormalizeNameAndKey">
##  <ManSection >
##  <Func Arg="namestr" Name="NormalizedNameAndKey" />
##  <Returns>list of strings and names as lists</Returns>
##  <Func Arg="r" Name="NormalizeNameAndKey" />
##  <Returns>nothing</Returns>
##  <Description>
##  The argument <A>namestr</A> must be a string describing an author or a list
##  of authors as described in the &BibTeX; documentation in <Cite  Key="La85"
##  Where="Appendix  B 1.2"/>. The function <Ref Func="NormalizedNameAndKey"
##  /> returns a list of the form [ normalized name string, short key, long
##  key, names as lists]. The first entry is a normalized form
##  of the input where names are written as <Q>lastname, first name
##  initials</Q>. The second and third entry are the name parts of a short and
##  long key for the bibliography entry, formed from the (initials of) last
##  names. The fourth entry is a list of lists, one for each name, where a 
##  name is described by three strings for the last name, the first name
##  initials and the first name(s) as given in the input. <P/>
##  
##  The function <Ref Func="NormalizeNameAndKey"/> gets as argument <A>r</A> 
##  a record for a bibliography entry as returned by <Ref  Func="ParseBibFiles"
##  />. It substitutes  <C>.author</C> and <C>.editor</C> fields of <A>r</A> by
##  their normalized form, the original versions are stored in  fields
##  <C>.authororig</C> and <C>.editororig</C>.<P/> 
##  
##  Furthermore a short and a long citation key is generated and stored
##  in components <C>.printedkey</C> (only if no <C>.key</C> is already
##  bound) and <C>.keylong</C>.<P/> 
##  
##  We continue the example from <Ref  Func="ParseBibFiles"  />.
##  
##  <Example>
##  gap> gddirs := DirectoriesPackageLibrary("gapdoc","doc");;
##  gap> f := Filename(gddirs, "test.bib");;
##  gap> bib := ParseBibFiles(f);;
##  gap> NormalizedNameAndKey(bib[1][1].author);
##  [ "First, F. A. and Sec, X. Y.", "FS", "firstsec", 
##    [ [ "First", "F. A.", "Fritz A." ], [ "Sec", "X. Y.", "X. Y." ] ] ]
##  gap> NormalizeNameAndKey(bib[1][1]);
##  gap> bib[1][1];
##  rec( From := rec( BibTeX := true ), Label := "AB2000", 
##    Type := "article", author := "First, F. A. and Sec, X. Y.", 
##    authororig := "Fritz A. First and Sec, X. Y.", 
##    journal := "Important Journal", keylong := "firstsec2000", 
##    printedkey := "FS00", title := "Short", year := "2000" )
##  </Example>
##  </Description>
##  </ManSection>
##  <#/GAPDoc>
##  
InstallGlobalFunction(NormalizeNameAndKey, function(b)
  local   yy,  y,  names,  nn;
  if IsBound(b.year) then
    if IsInt(b.year) then
      yy := String(b.year);
      y := String(b.year mod 100);
    else
      yy := b.year;
      y := b.year{[Length(b.year)-1, Length(b.year)]};
    fi;
  else
    yy := "";
    y := "";
  fi;
  for names in ["author", "editor"] do
    if IsBound(b.(names)) then
      nn := NormalizedNameAndKey(b.(names));
      if nn[1] <> b.(names) then
        b.(Concatenation(names, "orig")) := b.(names);
        b.(names) := nn[1];
      fi;
      if not IsBound(b.key) then
        b.printedkey := Concatenation(nn[2], y);
      fi;
      if not IsBound(b.keylong) then
        b.keylong := Concatenation(nn[3], yy);
      fi;
    fi;
  od;
  if not IsBound(b.keylong) then
    b.keylong := "xxx";
  fi;
  if not (IsBound(b.key) or IsBound(b.printedkey)) then
    b.printedkey := "xxx";
  fi;
end);

# small utility
BindGlobal("AndToCommaNames", function(str)
  local n, p, i;
  str := NormalizedWhitespace(str);
  n := 0;
  p := PositionSublist(str, " and ");
  while p <> fail do
    n := n+1;
    p := PositionSublist(str, " and ", p);
  od;
  for i in [1..n-1] do
    str := SubstitutionSublist(str, " and ", ", ", false);
  od;
  if n > 1 then
    str := SubstitutionSublist(str, " and ", ", and ", false);
  fi;
  return str;
end);
  

# print out a bibtex entry, the ordering of fields is normalized and
# type and field names are in lowercase, also some formatting is done
# arg: entry[, abbrevs, texts]    where abbrevs and texts are lists
#      of same length abbrevs[i] is string macro for texts[i]
InstallGlobalFunction(StringBibAsBib, function(arg)
  local r, abbrevs, texts, res, ind, fieldlist, pos, lines, comp;
  
  # scan arguments
  r := arg[1];
  if Length(arg)>2 then
    abbrevs := arg[2];
    texts := arg[3];
  else
    abbrevs := [];
    texts := [];
  fi;

  res := "";
  
  if not IsBound(r.Label) then
    Info(InfoBibTools, 1, "#W WARNING: no .Label in Bib-record");
    Info(InfoBibTools, 2, ":\n", r);
    Info(InfoBibTools, 1, "\n");
    
    return fail;
  fi;
  ind := RepeatedString(' ', 22);
  fieldlist := [
                "author",
                "editor",
                "booktitle",
                "title",
                "journal",
                "month",
                "organization",
                "institution",
                "publisher",
                "school",
                "edition",
                "series",
                "volume",
                "number",
                "address",
                "year",
                "pages",
                "chapter",
                "crossref",
                "note",
                "notes",
                "howpublished", 
                "key",
                "coden", 
                "fjournal", 
                "isbn", 
                "issn", 
                "location", 
                "mrclass", 
                "mrnumber", 
                "mrreviewer", 
                "organisation", 
                "reviews", 
                "source", 
                "url",
                "keywords" ];

  Append(res, Concatenation("@", r.Type, "{ ", r.Label));
  for comp in Concatenation(fieldlist,
          Difference(NamesOfComponents(r), Concatenation(fieldlist,
                ["From", "Type", "Label","authorAsList", "editorAsList"]) )) do
    if IsBound(r.(comp)) then
      Append(res, Concatenation(",\n  ", comp, " = ", 
                              ListWithIdenticalEntries(16-Length(comp), ' ')));
      pos := Position(texts, r.(comp));
      if pos <> fail then
        Append(res, abbrevs[pos]);
      else
        Append(res, "{");
        lines := FormatParagraph(r.(comp), SizeScreen()[1]-26, 
                                 "both", [ind, ""]);
        Append(res, lines{[Length(ind)+1..Length(lines)-1]});
        Append(res, "}");
      fi;
    fi;
  od;
  Append(res, "\n}\n");
  return res;
end);
InstallGlobalFunction(PrintBibAsBib, function(arg)
  PrintFormattedString(CallFuncList(StringBibAsBib, arg));
end);

##  <#GAPDoc Label="WriteBibFile">
##  <ManSection >
##  <Func Arg="bibfile, bib" Name="WriteBibFile" />
##  <Returns>nothing</Returns>
##  <Description>
##  This  is   the  converse  of  <Ref  Func="ParseBibFiles"/>.  Here
##  <A>bib</A>  either must  have  a  format as list of three lists  
##  as  it  is  returned  by  <Ref
##  Func="ParseBibFiles"/>. Or <A>bib</A> can be a record as returned
##  by <Ref Func="ParseBibXMLextFiles"/>. 
##  A &BibTeX; file <A>bibfile</A> is written
##  and  the  entries are  formatted  in  a  uniform way.  All  given
##  abbreviations are used while writing this file.<P/>
##  
##  We continue the example from <Ref   Func="NormalizeNameAndKey"/>.
##  The command
##  
##  <Example>
##  gap> WriteBibFile("nicer.bib", bib);
##  </Example>
##  
##  produces a file <F>nicer.bib</F> as follows:
##  
##  <Listing Type="nicer.bib">
##  @string{j = "Important Journal" }
##  
##  @article{ AB2000,
##    author =           {First, F. A. and Sec, X. Y.},
##    title =            {Short},
##    journal =          j,
##    year =             {2000},
##    authororig =       {Fritz A. First and Sec, X. Y.},
##    keylong =          {firstsec2000},
##    printedkey =       {FS00}
##  }
##  </Listing>
##  </Description>
##  </ManSection>
##  <#/GAPDoc>
##  
InstallGlobalFunction(WriteBibFile, function(file, bib)
  local   p,  b3,  a,  b,  pos,  f;
  
  if IsRecord(bib) and IsBound(bib.entries) and IsBound(bib.strings) then
    b := bib;
    bib := [];
    bib[1] := List(b.entries, a-> RecBibXMLEntry(a, "BibTeX", b.strings));
    bib[2] := List(b.strings, a-> a[1]);
    bib[3] := List(b.strings, a-> a[2]);
  fi;

  # collect abbrevs 
  p := [];
  SortParallel(bib[3], bib[2]);
  b3 := Immutable(bib[3]);
  IsSet(b3);
  for a in bib[1] do
    for b in NamesOfComponents(a) do
      pos := Position(b3, a.(b));
      if pos <> fail then
        Add(p, pos);
      fi;
    od;
  od;
  p := Set(p);
  
  f := function()
    local   i,  a;
    Print("\n\n");
    # the `string's
    for i in p do
      Print("@string{", bib[2][i], " = \"", b3[i], "\" }\n");
    od;        
    Print("\n\n");  
    for a in bib[1] do
      PrintBibAsBib(a, bib[2], b3);
    od;
  end;
  
  PrintTo1(file, f);
end);

# a utility for translating LaTeX macros for non ascii characters into
# HTML entities; also removing {}'s, and "\-" hyphenation hints.
BindGlobal("LaTeXToHTMLString", function(str)
  local trans_bs, trans_qq, i, pos;
  # macros for accents starting with '\', add new entries - somehow more
  # frequent ones first - as they become necessary
  trans_bs := [ ["\\\"a","ä"], ["\\\"o","ö"], ["\\\"u","ü"],
                ["\\\"{a}","ä"], ["\\\"{o}","ö"], 
                ["\\\"{u}","ü"], ["\\\"{s}","ß"], 
                ["\\\"s","ß"], ["\\3","ß"], ["\\ss","ß"],
                ["\\\"A","Ä"], ["\\\"O","Ö"], ["\\\"U","Ü"],
                ["\\'e","é"], ["\\`e","è"], 
                ["\\'E","É"], ["\\`E","È"],
                ["\\'a","á"], ["\\`a","à"],
                ["\\c{c}", "ç"], ["\\c c", "ç"], 
                # long Hungarian umlaut, substituted by unicode entity
                #    (see https://www.unicode.org/charts/)
                ["\\H{o}", "ő"], ["\\H o", "ő"],
                ["\\'A","Á"], ["\\'I","Í"], ["\\'O","Ó"],
                ["\\'U","Ú"], ["\\'i","í"],
                ["\\'o","ó"], ["\\'u","ú"],
                ["\\`A","À"], ["\\`I","Ì"], ["\\`O","Ò"],
                ["\\`U","Ù"], ["\\`i","ì"],
                ["\\`o","ò"], ["\\`u","ù"] 
                ];
  # and some starting with '"' from 'german' styles
  trans_qq := [ ["\"a","ä"], ["\"o","ö"], ["\"u","ü"],
                ["\"s","ß"],  ["\"A","Ä"], ["\"O","Ö"], 
                ["\"U","Ü"] ];
                
  i := 0; pos := Position(str, '\\');
  while pos <> fail and i < Length(trans_bs) do
    i := i + 1;
    str := ReplacedString(str, trans_bs[i][1], trans_bs[i][2]);
    pos := Position(str, '\\');
  od;
  i := 0; pos := Position(str, '\"');
  while pos <> fail and i < Length(trans_qq) do
    i := i + 1;
    str := ReplacedString(str, trans_qq[i][1], trans_qq[i][2]);
    pos := Position(str, '\"');
  od;
  # throw away {}'s and "\-"'s
  if Position(str, '{') <> fail then
    str := Filtered(str, c-> c <> '{' and c <> '}');
  fi;
  str := ReplacedString(str, "\\-", "");

  return str;
end);
                
##  arg: r[, escape]  (with escape = false it is assumed that entries are
##                     already HTML)
InstallGlobalFunction(StringBibAsHTML, function(arg)
  local   r,  i, str, res, esc, key, mrnumber, booklike;
  r := arg[1];
  if Length(arg)=2 then
    esc := arg[2];
  else
    if IsBound(r.From) and IsBound(r.From.BibXML) and r.From.BibXML = true then
      esc := false;
    else
      esc := true;
    fi;
  fi;
  
  if not IsBound(r.Label) then
    Info(InfoBibTools, 1, "#W WARNING: no .Label in Bib-record");
    Info(InfoBibTools, 2, ":\n", r);
    Info(InfoBibTools, 1, "\n");
    return fail;
  fi;

  # some details are set differently for book-like references
  if r.Type in [ "book", "booklet", "manual", "techreport", "mastersthesis", 
                 "phdthesis", "proceedings" ] then
    booklike := true;
  else
    booklike := false;
  fi;

  res := "";

  # remove SGML markup characters in entries and translate
  # LaTeX macros for accented characters to HTML, remove {}'s
  if esc = true then
    r := ShallowCopy(r);
    for i in NamesOfComponents(r) do
      if IsString(r.(i)) then
        str := "";
        GAPDoc2HTMLProcs.PCDATAFILTER(rec(content := r.(i)), str);
        if str <> r.(i) then
          r.(i) := str;
        fi;
        r.(i) := LaTeXToHTMLString(r.(i));
        if i in ["title", "subtitle", "booktitle"] then
          r.(i) := Filtered(r.(i), x -> not x in "{}");
        fi;
      fi;
    od;
  fi;
  
  if IsBound(r.key) then
    key := r.key;
  elif IsBound(r.printedkey) then
    key := r.printedkey;
  else
    key := r.Label;
  fi;
  if IsBound(r.mrnumber) then
    mrnumber:= r.mrnumber;
    if ' ' in mrnumber then
      mrnumber:= mrnumber{ [ 1 .. Position( mrnumber, ' ' ) - 1 ] };
    fi;
    Append(res, Concatenation(
      "<p class='BibEntry'>\n[<span class='BibKeyLink'><a href=\"https://www.ams.org/mathscinet-getitem?mr=",
      mrnumber, "\">", key, "</a></span>]   "));
  else
    Append(res, Concatenation("<p class='BibEntry'>\n[<span class='BibKey'>", 
                    key, "</span>]   "));
  fi;
  # standard BibTeX-styles typeset a type if not given
  if r.Type = "phdthesis" and not IsBound(r.type) then
    r := ShallowCopy(r);
    r.type := "Ph.D. thesis";
  elif r.Type = "mastersthesis" and not IsBound(r.type) then
    r := ShallowCopy(r);
    r.type := "Master's thesis";
  fi;
  # we assume with the "," delimiters that at least one of .author,
  # .editor or .title exist
  if IsBound(r.author) then
    Append(res, Concatenation("<b class='BibAuthor'>", 
                AndToCommaNames(r.author),"</b>"));
  fi;
  if IsBound(r.editor) then
  if PositionSublist( r.editor, " and " ) = fail then
      Append(res, Concatenation(" (<span class='BibEditor'>", 
                  AndToCommaNames(r.editor), "</span>, Ed.)"));
  else
      Append(res, Concatenation(" (<span class='BibEditor'>", 
                  AndToCommaNames(r.editor), "</span>, Eds.)"));
  fi;
  fi;
  if IsBound(r.title) then
    if ForAny(["author", "editor"], a-> IsBound(r.(a))) then
      Add(res, ',');
    fi;
    # make title a link if .url is given
    if IsBound( r.url ) then
      Append( res, Concatenation( "\n<a href=\"", r.url, "\">",
                       "<i class='BibTitle'>", r.title, "</i></a>" ) );
    else
      Append(res, Concatenation("\n <i class='BibTitle'>", r.title, "</i>"));
    fi;
  fi;
  if IsBound(r.booktitle) then
    Append( res, ",\n " );
    if r.Type in ["inproceedings", "incollection"] then
      Append(res, " in ");
    fi;
    Append(res, Concatenation(" <i class='BibBooktitle'>", 
                r.booktitle, "</i>"));
  fi;
  if IsBound(r.subtitle) then
    Append(res, Concatenation("\n <i class='BibSubtitle'>–", 
                r.subtitle, "</i>"));
  fi;
  if IsBound(r.journal) then
    Append(res, Concatenation(",\n <span class='BibJournal'>", 
                r.journal, "</span>"));
  fi;
  if IsBound(r.type) then
    Append(res, Concatenation(",\n <span class='BibType'>", 
                r.type, "</span>"));
  fi;
  if IsBound(r.organization) then
    Append(res, Concatenation(",\n <span class='BibOrganization'>", 
                r.organization, "</span>"));
  fi;
  if IsBound(r.institution) then
    Append(res, Concatenation(",\n <span class='BibOrganization'>", 
                r.institution, "</span>"));
  fi;
  if IsBound(r.publisher) then
    Append(res, Concatenation(",\n <span class='BibPublisher'>", 
                r.publisher, "</span>"));
  fi;
  if IsBound(r.school) then
    Append(res, Concatenation(",\n <span class='BibSchool'>", r.school, "</span>"));
  fi;
  if IsBound(r.edition) then
    Append(res, Concatenation(",\n <span class='BibEdition'>", 
                r.edition, " edition", "</span>"));
  fi;
  if IsBound(r.series) then
    Append(res, Concatenation(",\n <span class='BibSeries'>", 
                r.series, "</span>"));
  fi;
  if IsBound(r.volume) then
    Append(res, Concatenation(",\n <em class='BibVolume'>", 
                r.volume, "</em>"));
  fi;
  if IsBound(r.number) then
    Append(res, Concatenation(" (<span class='BibNumber'>", 
                r.number, "</span>)"));
  fi;
  if IsBound(r.address) then
    Append(res, Concatenation(",\n <span class='BibAddress'>", 
                r.address, "</span>"));
  fi;
  if IsBound(r.year) then
    Append(res, Concatenation("\n (<span class='BibYear'>", 
                r.year, "</span>)"));
  fi;
  if IsBound(r.pages) then
    if booklike then
      Append(res, Concatenation(",\n <span class='BibPages'>", 
                  r.pages, " pages</span>"));
    else
      Append(res, Concatenation(",\n <span class='BibPages'>", 
                  r.pages, "</span>"));
    fi;
  fi;
  if IsBound(r.chapter) then
    Append(res, Concatenation(",\n <span class='BibChapter'>Chapter ", 
                r.chapter, "</span>"));
  fi;
  if IsBound(r.note) then
    Append(res, Concatenation("<br />\n(<span class='BibNote'>", 
                r.note, "</span>", ")"));
  fi;
  if IsBound(r.notes) then
    Append(res, Concatenation("<br />\n(<span class='BibNotes'>", 
                r.notes, "</span>", ")"));
  fi;
  if IsBound(r.howpublished) then
    Append(res, Concatenation(",\n<span class='BibHowpublished'>", 
                r.howpublished, "</span>"));
  fi;
  # a private extension of the author
  if IsBound(r.BUCHSTABE) then
    Append(res, Concatenation("<br />\nEinsortiert unter ", 
                r.BUCHSTABE, ".<br />\n"));
  fi;
  if IsBound(r.LDFM) then
    Append(res, Concatenation("Signatur ", r.LDFM, ".<br />\n"));
  fi;
  if IsBound(r.BUCHSTABE) and i>=0 then
    Append(res, Concatenation("<a href=\"HTMLldfm", r.BUCHSTABE, ".html#", i, 
          "\"><span style=\"color: red;\">BibTeX Eintrag</span></a>\n<br />"));
  elif not ( IsBound( r.BUCHSTABE ) or IsBound( r.LDFM ) ) then
    Append( res, ".\n" );
  fi;
  Append(res, "</p>\n\n");
  return res;
end);

InstallGlobalFunction(PrintBibAsHTML, function(arg)
  PrintFormattedString(CallFuncList(StringBibAsHTML, arg));
end);

##  arg: r[, ansi]  (for link to BibTeX)
InstallGlobalFunction(StringBibAsText, function(arg)
  local r, ansi, str, txt, s, f, field, booklike;
  r := arg[1];
  ansi := rec(
    Bib_reset := TextAttr.reset,
    Bib_author := Concatenation(TextAttr.bold, TextAttr.1),
##      Bib_editor := ~.Bib_author,
    Bib_title := TextAttr.4,
##      Bib_subtitle := ~.Bib_title,
    Bib_journal := "",
    Bib_volume := TextAttr.4,
    Bib_Label := TextAttr.3,
    Bib_edition := ["", ""],
    Bib_year := ["", ""],
    Bib_note := ["(", ")"],
    Bib_chapter := ["Chapter ", ""],
  );
  ansi.Bib_editor := ansi.Bib_author;
  ansi.Bib_subtitle := ansi.Bib_title;
  if Length(arg) = 2  and arg[2] <> true then
    for f in RecNames(arg[2]) do
      ansi.(f) := arg[2].(f);
    od;
  elif IsBound(r.From) and IsBound(r.From.options) and
            IsBound(r.From.options.ansi) then
    for f in RecNames(r.From.options.ansi) do
      ansi.(f) := r.From.options.ansi.(f);
    od;
  else
    for f in RecNames(ansi) do
      ansi.(f) := "";
    od;
  fi;
  # some details are set differently for book-like references
  if r.Type in [ "book", "booklet", "manual", "techreport", "mastersthesis",
                 "phdthesis", "proceedings" ] then
    booklike := true;
  else
    booklike := false;
  fi;
  
  if not IsBound(r.Label) then
    Info(InfoBibTools, 1, "#W WARNING: no .Label in Bib-record");
    Info(InfoBibTools, 2, ":\n", r);
    Info(InfoBibTools, 1, "\n");
    return;
  fi;
  str := "";
  # helper adds markup
  txt := function(arg)
    local field, s, pp, pre, post;
    field := arg[1];
    if Length(arg) > 1 then
      s := arg[2];
    elif IsBound(r.(field)) then
      s := r.(field);
    else
      return;
    fi;
    if not IsBound(ansi.(Concatenation("Bib_", field))) then
      Append(str, s);
    else
      pp := ansi.(Concatenation("Bib_", field));
      if not IsString(pp) then
        pre := pp[1];
        post := pp[2];
      else
        pre := pp;
        post := ansi.Bib_reset;
      fi;
      Append(str, pre);
      Append(str, s);
      Append(str, post);
    fi;
  end;
  if IsBound(r.key) then
    s := r.key;
  elif IsBound(r.printedkey) then
    s := r.printedkey;
  else
    s := r.Label;
  fi;
  Add(str, '['); txt("Label", s); Append(str, "] ");

  # we assume with the "," delimiters that at least one of .author,
  # .editor or .title exist
  txt("author");
  if IsBound(r.editor) then
    Append(str, " ("); txt("editor"); 
    if PositionSublist( r.editor, " and " ) = fail then
      Append(str, ", Ed.)");
    else
      Append(str, ", Eds.)");
    fi;
  fi;
  if IsBound(r.title) then
    if IsBound(r.author) or IsBound(r.editor) then
      Append(str, ", ");
    fi;
    txt("title");
  fi;
  if IsBound(r.booktitle) then
    Append(str, ", ");
    if r.Type in ["inproceedings", "incollection"] then
      Append(str, " in ");
    fi;
    txt("booktitle");
  fi;
  if IsBound(r.subtitle) then
    Append(str, "–"); txt("subtitle");
  fi;

  # standard BibTeX-styles typeset a type if not given
  if r.Type = "phdthesis" and not IsBound(r.type) then
    r := ShallowCopy(r);
    r.type := "Ph.D. thesis";
  elif r.Type = "mastersthesis" and not IsBound(r.type) then
    r := ShallowCopy(r);
    r.type := "Master's thesis";
  fi;
  for field in [ "journal", "type", "organization", "institution", 
                 "publisher", "school",
                 "edition", "series", "volume", "number", "address",
                 "year", "pages", "chapter", "note", "notes", 
                 "howpublished" ] do
    if IsBound(r.(field)) then
      if field = "year" then
        Append(str, " (");
        txt(field);
        Append(str, ")");
        continue;
      elif field = "pages" then
        if booklike then
          Append(str, ", ");
          txt(field);
          Append(str, " pages");
        else
##            Append(str, ", p. ");
          Append(str, ", ");
          txt(field);
        fi;
        continue;
      elif field = "edition" then
        Append(str, ", ");
        txt(field);
        Append(str, " edition");
        continue;
      elif field in ["note", "notes"] then
        Append(str, ",\n ");
        txt(field);
        continue;
      elif field = "chapter" then
        Append(str, ", Chapter ");
        txt(field);
        continue;
      else
        Append(str, ", "); 
      fi;
      txt(field);
    fi;
  od;
  
  # some LDFM specific
  if IsBound(r.BUCHSTABE) then
    Append(str, Concatenation(", Einsortiert unter ", r.BUCHSTABE));
  fi;
  if IsBound(r.LDFM) then
    Append(str, Concatenation(", Signatur ", r.LDFM));
  fi;

##    str := FormatParagraph(Filtered(str, x-> not x in "{}"), 72);
  Add(str, '.');
  if Unicode(str, "UTF-8") <> fail then
    str := FormatParagraph(str, SizeScreen()[1]-4, WidthUTF8String);
  else
    str := FormatParagraph(str, SizeScreen()[1]-4);
  fi;
  Add(str, '\n');
  return str;
end);

InstallGlobalFunction(PrintBibAsText, function(arg)
  PrintFormattedString(CallFuncList(StringBibAsText, arg));
end);

# Finally a conversion of bib entries to markdown
##  arg: r[, markup] 
InstallGlobalFunction(StringBibAsMarkdown, function( arg )
  local r, markup, str, txt, s, f, field, booklike;

  r := arg[1];
  markup := rec(
    Bib_author := [ "**", "**" ],  # emphasize
    Bib_title := [ "", "" ],
    Bib_journal := [ "", "" ],
    Bib_volume := [ "*", "*" ],    # italic
    Bib_edition := ["", ""],
    Bib_year := ["", ""],
    Bib_note := ["", ""],
    Bib_number:= [ "(", ")" ],   # HTML version has brackets, Text version not?
    Bib_chapter := ["Chapter ", ""],
  );
  markup.Bib_editor := markup.Bib_author;
  markup.Bib_subtitle := markup.Bib_title;
  if Length(arg) = 2  and arg[2] <> true then
    for f in RecNames(arg[2]) do
      markup.(f) := arg[2].(f);
    od;
  elif IsBound(r.From) and IsBound(r.From.options) and
            IsBound(r.From.options.markup) then
    for f in RecNames(r.From.options.markup) do
      markup.(f) := r.From.options.markup.(f);
    od;
  else
  fi;
  # some details are set differently for book-like references
  if r.Type in [ "book", "booklet", "manual", "techreport", "mastersthesis",
                 "phdthesis", "proceedings" ] then
    booklike := true;
  else
    booklike := false;
  fi;
  
  if not IsBound(r.Label) then
    Info(InfoBibTools, 1, "#W WARNING: no .Label in Bib-record");
    Info(InfoBibTools, 2, ":\n", r);
    Info(InfoBibTools, 1, "\n");
    return;
  fi;
  str := "";
  # helper adds markup
  txt := function(arg)
    local field, s, pp, pre, post;
    field := arg[1];
    if Length(arg) > 1 then
      s := arg[2];
    elif IsBound(r.(field)) then
      s := r.(field);
    else
      return;
    fi;
    if not IsBound(markup.(Concatenation("Bib_", field))) then
      Append(str, s);
    else
      pp := markup.(Concatenation("Bib_", field));
      if not IsString(pp) then
        pre := pp[1];
        post := pp[2];
      else
        Error( "this should not happen" );
      fi;
      Append(str, pre);
      Append(str, s);
      Append(str, post);
    fi;
  end;

  # Start with the key in square brackets.
  # If an MR number is available then create a link to the MR entry.
  if IsBound(r.key) then
    s := r.key;
  elif IsBound(r.printedkey) then
    s := r.printedkey;
  else
    s := r.Label;
  fi;
  Append(str, "\\[");
  if IsBound( r.mrnumber ) then
    Append( str, "[" );
    txt( "Label", s );
    Append( str, "](https://www.ams.org/mathscinet-getitem?mr=" );
    if ' ' in r.mrnumber then
      Append( str, r.mrnumber{ [ 1 .. Position( r.mrnumber, ' ' )-1 ] } );
    else
      Append( str, r.mrnumber );
    fi;
    Append( str, ")" );
  else
    txt("Label", s);
  fi;
  Append(str, "\\] ");
  # we assume with the "," delimiters that at least one of .author,
  # .editor or .title exist
  txt("author");
  if IsBound(r.editor) then
    Append(str, " ("); txt("editor"); 
    if PositionSublist( r.editor, " and " ) = fail then
      Append(str, ", Ed.)");
    else
      Append(str, ", Eds.)");
    fi;
  fi;
  if IsBound(r.title) then
    if IsBound(r.author) or IsBound(r.editor) then
      Append(str, ", ");
    fi;
    if IsBound( r.url ) then
      # Add a link from the title to the location of the paper.
      Append( str, "[" );
      txt( "title" );
      Append( str, "](" );
      Append( str, r.url );
      Append( str, ")" );
    else
      txt("title");
    fi;
  fi;

  if IsBound(r.booktitle) then
    Append(str, ", ");
    if r.Type in ["inproceedings", "incollection"] then
      Append(str, " in ");
    fi;
    txt("booktitle");
  fi;
  if IsBound(r.subtitle) then
    Append(str, "–"); txt("subtitle");
  fi;

  # standard BibTeX-styles typeset a type if not given
  if r.Type = "phdthesis" and not IsBound(r.type) then
    r := ShallowCopy(r);
    r.type := "Ph.D. thesis";
  elif r.Type = "mastersthesis" and not IsBound(r.type) then
    r := ShallowCopy(r);
    r.type := "Master's thesis";
  fi;
  for field in [ "journal", "type", "organization", "institution", 
                 "publisher", "school",
                 "edition", "series", "volume", "number", "address",
                 "year", "pages", "chapter", "note", "notes", 
                 "howpublished" ] do
    if IsBound(r.(field)) then
      if field = "year" then
        Append(str, " (");
        txt(field);
        Append(str, ")");
      elif field = "pages" then
        if booklike then
          Append(str, ", ");
          txt( field, ReplacedString( r.( field ), "--", "–" ) );
          Append(str, " pages");
        else
          Append(str, ", ");
          txt( field, ReplacedString( r.( field ), "--", "–" ) );
        fi;
      elif field = "edition" then
        Append(str, ", ");
        txt(field);
        Append(str, " edition");
      elif field in ["note", "notes"] then
        Append(str, ", (");
        txt(field);
        Append(str, ")");
      elif field = "chapter" then
        Append(str, ", Chapter ");
        txt(field);
      elif field = "number" then   # Text version has comma before, HTML not
        Append(str, " "); 
        txt(field);
      else
        Append(str, ", "); 
        txt(field);
      fi;
    fi;
  od;
  
  # some LDFM specific
  if IsBound(r.BUCHSTABE) then
    Append(str, Concatenation(", Einsortiert unter ", r.BUCHSTABE));
  fi;
  if IsBound(r.LDFM) then
    Append(str, Concatenation(", Signatur ", r.LDFM));
  fi;

  Add(str, '.');
  NormalizeWhitespace( str );
  Add(str, '\n');
  return str;
end);

InstallGlobalFunction(PrintBibAsMarkdown, function(arg)
  PrintFormattedString(CallFuncList(StringBibAsMarkdown, arg));
end);

##  <#GAPDoc Label="SearchMRSection">
##  <Section Label="MathSciNet">
##  <Heading>Getting &BibTeX; entries from 
##           <Package>MathSciNet</Package></Heading>
##  We provide utilities to access the <URL
##  ><Link>https://www.ams.org/mathscinet/</Link><LinkText><Package>
##  MathSciNet</Package></LinkText></URL> 
##  data base from within GAP. The first condition for this to work is that 
##  one of the programs <C>wget</C> or <C>curl</C> is installed on your system.
##  The second is,
##  of course, that you use these functions from a computer which has access to
##  <Package>MathSciNet</Package>.<P/>
##  
##  Please note, that the usual license for <Package>MathSciNet</Package> 
##  access does not allow for automated searches in the database. Therefore,
##  only use the <Ref Func="SearchMR" /> function for single queries, as you 
##  would do using your webbrowser.<P/>
##  
##  <ManSection >
##  <Func Arg="qurec" Name="SearchMR" />
##  <Func Arg="bib" Name="SearchMRBib" />
##  <Returns>a list of strings, a string or <K>fail</K></Returns>
##  <Description>
##  The first function <Ref Func="SearchMR"/> provides the same functionality 
##  as the Web interface <URL
##  ><Link>https://www.ams.org/mathscinet/</Link><LinkText><Package>
##  MathSciNet</Package></LinkText></URL>. The query strings must be given as
##  a record, and the following components of this record are recognized:
##  <C>Author</C>, <C>AuthorRelated</C>, <C>Title</C>, <C>ReviewText</C>, 
##  <C>Journal</C>, <C>InstitutionCode</C>, <C>Series</C>, <C>MSCPrimSec</C>, 
##  <C>MSCPrimary</C>, <C>MRNumber</C>, <C>Anywhere</C>, <C>References</C>
##  and <C>Year</C>.
##  <P/>
##  Furthermore, the component <C>type</C> can be specified. It can be one of 
##  <C>"bibtex"</C> (the default if not given), <C>"pdf"</C>, <C>"html"</C> and
##  probably others. In the last  cases the function returns a string with
##  the content of the web page returned by <Package>MathSciNet</Package>.
##  In the first case the <Package>MathSciNet</Package> interface returns a web
##  page with  &BibTeX; entries, for convenience this function returns a list
##  of strings,  each containing the &BibTeX; text for a single result entry.
##  <P/>
##  If a component <C>uri</C> is bound and set to <K>true</K> the function 
##  does not actually send a request to <Package>MathSciNet</Package> but
##  returns a string with the URI that can be called for the request.
##  <P/>
##  The format of a <C>.Year</C> component can be either a four digit number,
##  optionally preceded by  one of the characters <C>'<'</C>,
##  <C>'>'</C> or <C>'='</C>, or it can be two four digit numbers 
##  separated by a <C>-</C> to specify a year range.<P/>
##  
##  The function <Ref Func="SearchMRBib"/> gets a record of a parsed &BibTeX;
##  entry as input as returned by <Ref Func="ParseBibFiles"/> or <Ref
##  Func="ParseBibStrings"/>. It tries to generate some sensible input from this
##  information for <Ref Func="SearchMR"/> and calls that function. <P/>
##  
##  <Log>
##  gap> ll := SearchMR(rec(Author:="Gauss", Title:="Disquisitiones"));;
##  gap> ll2 := List(ll, HeuristicTranslationsLaTeX2XML.Apply);;
##  gap> bib := ParseBibStrings(Concatenation(ll2));;
##  gap> bibxml := List(bib[1], StringBibAsXMLext);;
##  gap> bib2 := ParseBibXMLextString(Concatenation(bibxml));;
##  gap> for b in bib2.entries do 
##  >          PrintFormattedString(StringBibXMLEntry(b, "Text")); od;     
##  [Gau95]   Gauss,   C.   F.,  Disquisitiones  arithmeticae,  Academia
##  Colombiana   de  Ciencias  Exactas,  Físicas  y  Naturales,  Bogotá,
##  Colección   Enrique   Pérez   Arbeláez   [Enrique   Pérez   Arbeláez
##  Collection],  10  (1995), xliv+495 pages, (Translated from the Latin
##  by  Hugo  Barrantes  Campos,  Michael Josephy and Ángel Ruiz Zúñiga,
##  With a preface by Ruiz Zúñiga).
##  
##  [Gau86]  Gauss, C. F., Disquisitiones arithmeticae, Springer-Verlag,
##  New  York  (1986),  xx+472  pages, (Translated and with a preface by
##  Arthur  A.  Clarke,  Revised  by  William  C.  Waterhouse, Cornelius
##  Greither and A. W. Grootendorst and with a preface by Waterhouse).
##  
##  [Gau66]  Gauss,  C. F., Disquisitiones arithmeticae, Yale University
##  Press, New Haven, Conn.-London, Translated into English by Arthur A.
##  Clarke, S. J (1966), xx+472 pages.
##  
##  </Log>
##  </Description>
##  
##  
##  </ManSection>
##  
##  
##  </Section>
##  <#/GAPDoc>

InstallGlobalFunction(GetByWgetOrCurl, function(url)
  local res, out, fn;
  res := "";
  out := OutputTextString(res, false);
  fn := Filename(DirectoriesSystemPrograms(), "wget");
  if not fn = fail and IsExecutableFile(fn) then
    Process(Directory("."), fn, InputTextNone(), out, 
            ["--quiet", "-O", "-", url]);
    CloseStream(out);
    return res;
  fi;
  fn := Filename(DirectoriesSystemPrograms(), "curl");
  if not fn = fail and IsExecutableFile(fn) then
    Process(Directory("."), fn, InputTextNone(), out, 
            ["--silent", "--output", "-", url]);
    CloseStream(out);
    return res;
  fi;
  Error("Cannot find 'wget' or 'curl' on this system.\n");
end
);

SEARCHMRHOST := "www.ams.org";
##  SEARCHMRHOST := "ams.math.uni-bielefeld.de";
InstallGlobalFunction(SearchMR, function(r)
  local trans, uri, i, l, res, extr, a, b;
  trans := [["Author", "AUCN"], ["AuthorRelated","ICN"], ["Title","TI"],
            ["ReviewText","RT"],["Journal","JOUR"],["InstitutionCode","IC"],
            ["Series","SE"],["MSCPrimSec","CC"],["MSCPrimary","PC"],
            ["MRNumber","MR"],["Anywhere","ALLF"],["References","REFF"]];
  if not IsBound(r.type) then
    r.type := "bibtex";
  fi;
  uri := Concatenation("/mathscinet/search/publications.html?fmt=", 
                       r.type);
  if IsBound(r.Year) then
    if '-' in r.Year then
      extr := SplitString(r.Year,"","- ");
      Append(uri, "&dr=yearrange&yearRangeFirst=");
      Append(uri, extr[1]);
      Append(uri, "&yearRangeSecond=");
      Append(uri, extr[2]);
    else 
      Append(uri, "&dr=pubyear&arg3=");
      Append(uri, Filtered(r.Year, c-> not c in "<>="));
      if r.Year[1] = '<' then
        Append(uri, "&yrop=lt");
      elif r.Year[1] = '>' then
        Append(uri, "&yrop=gt");
      else
        Append(uri, "&yrop=eq");
      fi;
    fi;
  fi;
  i := 4;
  for a in trans do
    if IsBound(r.(a[1])) then
      if IsString(r.(a[1])) then
        l := [r.(a[1])];
      else
        l := r.(a[1]);
      fi;
      for b in l do 
        Append(uri, Concatenation("&pg", String(i), "=", a[2], "&s",
                      String(i), "=", Encode(Unicode(b),"URL")));
        if i = 9 then
          break;
        else
          i := i+1;
        fi;
      od;
    fi;
    if i = 9 then
      break;
    fi;
  od;
  # get all entries
  Append(uri, "&extend=1");
  uri := Concatenation("https://",SEARCHMRHOST,uri);
  if IsBound(r.uri) and r.uri = true then
    return uri;
  fi;
  res := GetByWgetOrCurl(uri);
  if r.type <> "bibtex" then
    # just return the content of the returned web page 
    return res;
  fi;
  # by default we extract BibTeX source from <pre> element
  i := PositionSublist(res, "<pre>\n@");
  extr := [];
  while i <> fail do
    Add(extr, res{[i+5..PositionSublist(res, "</pre>", i)-1]});
    i := PositionSublist(res, "<pre>\n@", i);
  od;
  return extr;
end);
# args: record[, type]
# records like entry from ParseBibStrings/Files, default for type is "bibtex"
InstallGlobalFunction(SearchMRBib, function(arg)
  local nn, tt, r, a, f;
  a := arg[1];
  if IsBound(a.mrnumber) then
    r := rec(MRNumber := a.mrnumber);
    if ' ' in r.MRNumber then
      r.MRNumber := r.MRNumber{[1..Position(r.MRNumber, ' ')-1]};
    fi;
  else
    a := ShallowCopy(a);
    for f in RecNames(a) do
      if IsString(a.(f)) then
        a.(f) := HeuristicTranslationsLaTeX2XML.Apply(a.(f));
      fi;
    od;
    if IsBound(a.author) then
      a.author := SubstitutionSublist(a.author, "~", " ");
      nn := NormalizedNameAndKey(a.author)[4];
    elif IsBound(a.editor) then
      a.editor := SubstitutionSublist(a.editor, "~", " ");
      nn := NormalizedNameAndKey(a.editor)[4];
    else
      nn := [[""]];
    fi;
    # up to three longest words from title
    tt := SubstitutionSublist(a.title, "{", "");
    tt := SubstitutionSublist(tt, "}", "");
    tt := NormalizedWhitespace(tt);
    tt := WordsString(tt);
    SortParallel(List(tt, w-> 1000-Length(w)), tt);
    tt := tt{[1..Minimum(3, Length(tt))]};
    r := rec( Author := List(nn, a->a[1]),
                                  Title := tt);
  fi;
  if Length(arg) > 1 then
    r.type := arg[2];
  fi;
  return SearchMR(r);
end);

##  <#GAPDoc Label="LabelsFromBibTeX">
##  <ManSection >
##  <Func Arg="path, keys, bibfiles, style" Name="LabelsFromBibTeX" />
##  <Returns>a list of pairs of strings <C>[key, label]</C></Returns>
##  <Description>
##  This function uses  <C>bibtex</C> to determine the ordering  of a list
##  of  references and  a label  for each  entry which  is typeset  in   a
##  document citing these references.
##  <P/>
##  The  argument  <A>path</A>  is  a directory  specified  as  string  or
##  directory object. The argument <A>bibfiles</A> must be a list of files
##  in  &BibTeX;  format,  each  specified  by  a  path  relative  to  the
##  first  argument, or  an absolute  path (starting  with <C>'/'</C>)  or
##  relative to the &GAP; roots  (starting with <C>"gap://"</C>). The list
##  <A>keys</A>  must contain  strings which  occur as  keys in  the given
##  &BibTeX; files. Finally the string <A>style</A>  must be the name of a
##  bibliography style (like <C>"alpha"</C>). <P/>
##  
##  The list returned by this  function contains pairs <C>[key, label]</C>
##  where <C>key</C> is one of the entries of <A>keys</A> and <C>label</C>
##  is  a string  used  for  citations  of the   bibliography  entry  in a
##  document. These  pairs are ordered  as the reference list  produced by
##  &BibTeX;.
##  <Example>
##  gap> f := Filename(DirectoriesPackageLibrary("gapdoc","doc"), "test.bib");;
##  gap> LabelsFromBibTeX(".", ["AB2000"], [f], "alpha");
##  [ [ "AB2000", "FS00" ] ]
##  </Example>
##  </Description>
##  </ManSection>
##  <#/GAPDoc>
##  
InstallGlobalFunction(LabelsFromBibTeX, function(path, keys, bibfiles, style)
  local aux, flist, poss, d, dstr, auxfile, out, res, lab, pos, k, n, i;
  aux := "";
  # keys of citations
  for k in keys do
    Append(aux, "\\citation{");
    Append(aux, k);
    Append(aux, "}\n");
  od;
  if IsString(path) then
    path := Directory(path);
  fi;

  # file names of bib-files
  flist := [];
  for n in bibfiles do
    if Length(n) > 0 and n[1] = '/' then
      Add(flist, n);
    elif Length(n) > 5 and n{[1..6]} = "gap://" then
      Add(flist, FilenameGAP(n));
    else
      Add(flist, n);
    fi;
  od;
  poss := Positions(flist, fail);
  if Length(poss) > 0 then
    Error("Cannot generate path for bibfiles ",bibfiles{poss},".\n");
    return fail;
  fi;
  Append(aux, "\\bibdata{");
  Append(aux, JoinStringsWithSeparator(flist, ","));
  Append(aux, "}\n");

  # bibstyle of result
  Append(aux, "\\bibstyle{");
  Append(aux, style);
  Append(aux, "}\n");

  # write out, call bibtex, filter \bibitem lines from result
  d := DirectoryTemporary();
  dstr := Filename(d, "");
  auxfile := Filename(d, "temp.aux");
  FileString(auxfile, aux);
  Exec(Concatenation("(export TEXMFOUTPUT=", dstr, "; cd ", Filename(path, ""), 
                 "; bibtex ", dstr, "/temp > /dev/null 2>&1 ; ",
                 "grep '^\\\\bibitem' ", dstr, "/temp.bbl > ", dstr, "/out )"));
  out := StringFile(Filename(d, "out"));
  if out = fail then
    Error("Call of 'bibtex' was not successful.\n");
    return fail;
  fi;
  
  # clean temporary directory
  for n in DirectoryContents(d) do 
    if not n in [".", ".."] then
      RemoveFile(Filename(d, n)); 
    fi; 
  od;
  # ???  RemoveDir(Filename(d,""));

  # parse result
  out := SplitString(out, "", "\n");
  res := [];
  for i in [1..Length(out)] do
    n := out[i];
    if n[9] = '[' then
      pos := Position(n, ']', 9);
      lab := n{[10..pos-1]};
      pos := Position(n, '{', pos);
    else
      lab := String(i);
      pos := Position(n, '{', 8);
    fi;
    Add(res, [n{[pos+1..PositionMatchingDelimiter(n, "{}", pos)-1]}, lab]);
  od;
  return res;
end);


[ Dauer der Verarbeitung: 0.45 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