############################################################################# ## #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)>0then
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>0then # 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)>0then
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)>3then
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) > 0then
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);
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 > 1then
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;
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");
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)=2then
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>=0then
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);
## 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) > 1then
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);
# 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) > 1then
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;
## <#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 = 9then
break; else
i := i+1; fi;
od; fi; if i = 9then
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) > 1then
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) > 0then
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);
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.73 Sekunden
(vorverarbeitet am 2026-10-12)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.