Back to index

texmacs  1.0.7.15
bibtex_functions.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : bibtex_functions.cpp
00004 * DESCRIPTION: BiBTeX internal functions
00005 * COPYRIGHT  : (C) 2010 David MICHEL
00006 *******************************************************************************
00007 * This software falls under the GNU general public license version 3 or later.
00008 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
00009 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
00010 ******************************************************************************/
00011 
00012 #include "bibtex_functions.hpp"
00013 #include "vars.hpp"
00014 
00015 /******************************************************************************
00016 * Helper functions
00017 ******************************************************************************/
00018 
00019 static string
00020 bib_parse_char (string s, int& pos, int& depth, bool& special, int& math) {
00021   switch (s[pos]) {
00022     case '{': {
00023       pos++;
00024       if (pos < N(s) && s[pos] == '\\' && depth == 0) special= true;
00025       depth++;
00026       return "{";
00027     }
00028     case '}': {
00029       pos++;
00030       depth--;
00031       if (special && depth == 0) special= false;
00032       return "}";
00033     }
00034     case '\\': {
00035       string r= "\\";
00036       pos++;
00037       if (pos < N(s) && (s[pos] == '{' || s[pos] == '}')) {
00038         r << s[pos];
00039         pos++;
00040       }
00041       else /* if (special) */ {
00042         if (pos < N(s) && !is_alpha (s[pos]) && !is_digit (s[pos])) {
00043           r << s[pos];
00044           pos++;
00045         }
00046         else {
00047           while (pos < N(s) && (is_alpha (s[pos]) || is_digit (s[pos]))) {
00048             r << s[pos];
00049             pos++;
00050           }
00051         }
00052         if (pos < N(s) && (is_alpha (s[pos]) || is_digit (s[pos]))) {
00053           r << s[pos];
00054           pos++;
00055         }
00056         else if (pos < N(s) && s[pos] == '{') {
00057           int d= 1;
00058           r << s[pos];
00059           pos++;
00060           while (pos < N(s) && d > 0) {
00061             if (s[pos] == '{') d++;
00062             if (s[pos] == '}') d--;
00063             r << s[pos];
00064             pos++;
00065           }
00066         }
00067       }
00068       return r;
00069     }
00070     case '$': {
00071       pos++;
00072       if (pos < N(s) && s[pos] == '$') {
00073         if (math == 2) math= 0;
00074         else math= 2;
00075         pos++;
00076         return "$$";
00077       }
00078       else {
00079         if (math == 1) math= 0;
00080         else math= 1;
00081         return "$";
00082       }
00083     }
00084     default: {
00085       string r;
00086       r << s[pos];
00087       pos++;
00088       return r;
00089     }
00090   }
00091 }
00092 
00093 static string
00094 bib_get_char (string s, int pos) {
00095   int d= 0;
00096   bool sp= false;
00097   int m= 0;
00098   int p= pos;
00099   return bib_parse_char (s, p, d, sp, m);
00100 }
00101 
00102 static bool
00103 bib_is_normal (string s) {
00104   return (N(s) == 1) && (s[0] != '{') && (s[0] != '}') &&
00105          (s[0] != '\\') && !is_space (s[0]);
00106 }
00107 
00108 static bool
00109 bib_is_space (string s) {
00110   return (N(s) == 1) && is_space (s[0]);
00111 }
00112 
00113 /*
00114 static bool
00115 bib_is_iso_alpha (string s) {
00116   return (N(s) == 1) && is_iso_alpha (s[0]);
00117 }
00118 
00119 static bool
00120 bib_is_digit (string s) {
00121   return (N(s) == 1) && is_digit (s[0]);
00122 }
00123 */
00124 
00125 static bool
00126 bib_is_char (string s, char c) {
00127   return (N(s) == 1) && (s[0] == c);
00128 }
00129 
00130 static string
00131 bib_to_latex (string s) {
00132   string r= "{";
00133   int pos= 0;
00134   int depth= 0;
00135   bool special= false;
00136   bool specialsav= special;
00137   int math= 0;
00138   int keepcase= -1;
00139   while (pos < N(s)) {
00140     specialsav= special;
00141     string ch= bib_parse_char (s, pos, depth, special, math);
00142     //    cerr << ch << " " << as_string (keepcase) << " " << as_string (depth) << "\n";
00143     if (ch == "$$") r << "$";
00144     else if (special || math) r << ch;
00145     else if (bib_is_space (ch)) {
00146       if (keepcase == depth+1) {
00147         r << "} ";
00148         keepcase= -1;
00149       }
00150       else r << " ";
00151     }
00152     else if (ch == "%") r << "\\%";
00153     else if (bib_is_char (ch, '{') && depth > 0 &&
00154              bib_get_char (s, pos) != "\\") {
00155       if (keepcase == -1) {
00156         r << "\\keepcase{";
00157         keepcase= depth;
00158       }
00159       else if (keepcase < depth) r << "{";
00160     }
00161     else if (bib_is_char (ch, '}')) {
00162       if (keepcase <= depth || specialsav) r << ch;
00163     }
00164     else  r << ch;
00165   }
00166   for (int i= keepcase; i>0; i--) r << "}";
00167   r << "}";
00168   //  cerr << r << "\n";
00169   return r;
00170 }
00171 
00172 /******************************************************************************
00173 * BibTeX add.period$
00174 ******************************************************************************/
00175 
00176 bool
00177 bib_is_bad (tree t) {
00178   if (is_atomic(t)) {
00179     string s= t->label;
00180     for (int i= N(s); i >= 0; i--)
00181       if (!is_space (s[i])) return false;
00182     return true;
00183   }
00184   else return (N(t) == 0);
00185 }
00186 
00187 char*
00188 bib_last_char (tree t) {
00189   if (is_atomic (t)) {
00190     string s= t->label;
00191     int end= N(s)-1;
00192     while ((end >= 0) && is_space (s[end])) end--;
00193     if (end >= 0) return &(s[end]);
00194     else return 0;
00195   }
00196   else {
00197     int pos= N(t)-1;
00198     while ((pos >= 0) && bib_is_bad (t[pos])) pos--;
00199     if (pos >= 0) return bib_last_char (t[pos]);
00200     else return 0;
00201   }
00202 }
00203 
00204 scheme_tree
00205 bib_add_period (scheme_tree st) {
00206   tree t= simplify_correct (scheme_tree_to_tree (st));
00207   char* ch= bib_last_char (t);
00208   if (ch == 0) return tree_to_scheme_tree (t);
00209   if (*ch == ',' || *ch == ';') {
00210     *ch= '.';
00211     return tree_to_scheme_tree (t);
00212   }
00213   else if (*ch != '!' && *ch != '?' && *ch != '.') {
00214     tree res (CONCAT);
00215     res << t;
00216     res << ".";
00217     return tree_to_scheme_tree (res);
00218   }
00219   else return tree_to_scheme_tree (t);
00220 }
00221 
00222 /******************************************************************************
00223 * Change case of the first letter
00224 ******************************************************************************/
00225 
00226 char*
00227 bib_first_char (tree t) {
00228   if (is_atomic (t)) {
00229     string s= t->label;
00230     int beg= 0;
00231     while ((beg < N(s)) && is_space (s[beg])) beg++;
00232     if (beg < N(s)) return &(s[beg]);
00233     else return 0;
00234   }
00235   else if (is_compound (t, "verbatim"))
00236     return 0;
00237   else if (is_func (t, WITH, 3) && t[0] == FONT_FAMILY && t[1] == "tt")
00238     return 0;
00239   else {
00240     int pos= 0;
00241     if (L(t) == WITH) pos= N(t)-1;
00242     else while ((pos < N(t)) && bib_is_bad (t[pos])) pos++;
00243     if (pos < N(t)) return bib_first_char (t[pos]);
00244     else return 0;
00245   }
00246 }
00247 
00248 scheme_tree
00249 bib_upcase_first (scheme_tree st) {
00250   tree t= simplify_correct (scheme_tree_to_tree (st));
00251   char* ch= bib_first_char (t);
00252   if (ch != 0) *ch= upcase (*ch);
00253   return tree_to_scheme_tree (t); 
00254 }
00255 
00256 /******************************************************************************
00257 * BibTeX change.case$
00258 ******************************************************************************/
00259 
00260 /*
00261 static string
00262 bib_change_case_aux (string s, bool keep_first, char (*change_case) (char)) {
00263   string r;
00264   int pos= 0;
00265   int depth= 0;
00266   bool special= false;
00267   bool first= true;
00268   while (pos < N(s)) {
00269     string ch= bib_parse_char (s, pos, depth, special);
00270     if (bib_is_normal (ch)) {
00271       if ((keep_first && first) || (!special && depth > 0)) r << ch[0];
00272       else r << change_case (ch[0]);
00273       first= false;
00274     }
00275     else r << ch;
00276   }
00277   return r;
00278 }
00279 
00280 string
00281 bib_change_case (string s, string op) {
00282   if (op == "t") return bib_change_case_aux (s, true, locase);
00283   else if (op == "l") return bib_change_case_aux (s, false, locase);
00284   else if (op == "u") return bib_change_case_aux (s, false, upcase);
00285   else return copy (s);
00286 }
00287 */
00288 
00289 void
00290 bib_change_case (tree& t, string (*change_case) (string)) {
00291   if (is_atomic (t) && change_case) t->label= change_case (t->label);
00292   else if (is_compound (t, "verbatim"));
00293   else if (L(t) == WITH) bib_change_case (t[N(t)-1], change_case);
00294   else if (L(t) == as_tree_label ("keepcase")) t= t[0];
00295   else if (L(t) == CONCAT || L(t) == DOCUMENT)
00296     for (int i= 0; i<N(t); i++) bib_change_case (t[i], change_case);
00297 }
00298 
00299 scheme_tree
00300 bib_locase (scheme_tree st) {
00301   tree t= simplify_correct (scheme_tree_to_tree (st));
00302   bib_change_case (t, locase_all);
00303   return tree_to_scheme_tree (t); 
00304 }
00305 
00306 scheme_tree
00307 bib_upcase (scheme_tree st) {
00308   tree t= simplify_correct (scheme_tree_to_tree (st));
00309   bib_change_case (t, upcase_all);
00310   return tree_to_scheme_tree (t); 
00311 }
00312 
00313 scheme_tree
00314 bib_default (scheme_tree st) {
00315   tree t= simplify_correct (scheme_tree_to_tree (st));
00316   bib_change_case (t, 0);
00317   return tree_to_scheme_tree (t); 
00318 }
00319 
00320 /******************************************************************************
00321 * BibTeX num.names$
00322 ******************************************************************************/
00323 
00324 static bool
00325 search_and_keyword (string s, int& pos) {
00326   int depth= 0;
00327   bool special= false;
00328   int math= 0;
00329   while (pos < N(s)) {
00330     string ch= bib_parse_char (s, pos, depth, special, math);
00331     if (bib_is_space (ch) && depth == 0) {
00332       while (pos < N(s) && is_space (s[pos])) pos++;
00333       if (pos < N(s)-3 && s (pos, pos+3) == "and" && is_space (s[pos+3])) {
00334         pos += 4;
00335         return true;
00336       }
00337     }
00338   }
00339   return false;
00340 }
00341 
00342 int
00343 bib_num_names (string s) {
00344   int pos= 0;
00345   int nband= 0;
00346   while (pos < N(s))
00347     if (search_and_keyword (s, pos)) nband++;
00348   return nband+1;
00349 }
00350 
00351 /******************************************************************************
00352 * Helper functions for BibTeX trees
00353 ******************************************************************************/
00354 
00355 static bool
00356 bib_is_entry (tree t) {
00357   return (as_string (L (t)) == "bib-entry") && (arity (t) == 3) &&
00358          is_atomic (t[0]) && is_atomic (t[1]) && (L(t[2]) == DOCUMENT); 
00359 }
00360 
00361 static bool
00362 bib_is_field (tree t) {
00363   return (as_string (L (t)) == "bib-field") && (arity (t) == 2) &&
00364          is_atomic (t[0]); 
00365 }
00366 
00367 static bool
00368 bib_is_comment (tree t) {
00369   return (as_string (L (t)) == "bib-comment"); 
00370 }
00371 
00372 static bool
00373 bib_is_var (tree t) {
00374   return as_string (L(t)) == "bib-var" && arity (t) == 1 && is_atomic (t[0]);
00375 }
00376 
00377 static bool
00378 bib_is_string (tree t) {
00379   return as_string (L(t)) == "bib-string" && arity (t) == 1 &&
00380          L(t[0]) == DOCUMENT;
00381 }
00382 
00383 static bool
00384 bib_is_assign (tree t) {
00385   return as_string (L(t)) == "bib-assign" && arity (t) == 2 &&
00386          is_atomic (t[0]);
00387 }
00388 
00389 static bool
00390 bib_is_preamble (tree t) {
00391   return as_string (L(t)) == "bib-preamble" && arity (t) == 1 &&
00392          L(t[0]) == DOCUMENT;
00393 }
00394 
00395 static bool
00396 bib_is_latex (tree t) {
00397   return as_string (L(t)) == "bib-latex" && arity (t) == 1 &&
00398          is_atomic (t[0]);
00399 }
00400 
00401 
00402 static bool
00403 bib_is_blank_string (string s) {
00404   for (int i= 0; i<N(s); i++)
00405     if (!is_space (s[i])) return false;
00406   return true;
00407 }
00408 
00409 static tree
00410 bib_assoc (tree entry, string key) {
00411   if (bib_is_entry (entry)) {
00412     tree doc= entry[2];
00413     for (int i= 0; i<N(doc); i++)
00414       if (bib_is_field (doc[i]) && doc[i][0]->label == key)
00415        return doc[i][1];
00416   }
00417   return "";
00418 }
00419 
00420 /******************************************************************************
00421 * BibTeX format.name$ - only returns first, von, jr and last
00422 ******************************************************************************/
00423 
00424 static list<string>
00425 get_words (string s) {
00426   list<string> words;
00427   string curr;
00428   int pos= 0;
00429   int depth= 0;
00430   bool special= false;
00431   int math= 0;
00432   while (pos < N(s) && is_space (s[pos])) pos++;
00433   while (pos < N(s)) {
00434     string ch= bib_parse_char (s, pos, depth, special, math);
00435     if (bib_is_space (ch) && depth == 0) {
00436       while (pos < N(s) && is_space (s[pos])) pos++;
00437       curr >> words;
00438       curr= "";
00439     }
00440     else curr << ch;
00441   }
00442   if (curr != "") curr >> words;
00443   return words;
00444 }
00445 
00446 static bool
00447 first_is_locase (string s) {
00448   int pos= 0;
00449   int depth= 0;
00450   bool special= false;
00451   int math= 0;
00452   while (pos < N(s) && is_space (s[pos])) pos++;
00453   while (pos < N(s)) {
00454     string ch= bib_parse_char (s, pos, depth, special, math);
00455     if (bib_is_normal (ch))
00456       return (special || depth == 0) && is_locase (ch[0]);
00457   }
00458   return false;
00459 }
00460 
00461 static string
00462 get_fvl (string sfvl) {
00463   string w, res, f, v, l;
00464   list<string> words= get_words (sfvl);
00465   if (!is_nil (words)) l << words;
00466   bool all_up= true;
00467   for (int i= 0; i<N(words); i++)
00468     all_up= all_up && !first_is_locase (words[i]);
00469   if (!all_up) {
00470     while (!is_nil (words) && !first_is_locase (words[0])) {
00471       w << words;
00472       l= w << " " << l;
00473     }
00474     words= reverse (words);
00475     if (!is_nil (words) && !first_is_locase (words[0])) f << words;
00476     while (!is_nil (words) && !first_is_locase (words[0])) {
00477       w << words;
00478       f << " " << w;
00479     }
00480     if (!is_nil (words)) v << words;
00481     while (!is_nil (words)) {
00482       w << words;
00483       v << " " << w;
00484     }
00485   }
00486   else {
00487     if (!is_nil (words)) f << words;
00488     while (!is_nil (words)) {
00489       w << words;
00490       f= w << " " << f;
00491     }
00492   }
00493   res << "\\nextbib{}" << bib_to_latex (f);
00494   res << "\\nextbib{}" << bib_to_latex (v);
00495   res << "\\nextbib{}" << bib_to_latex (l);
00496   return res;
00497 }
00498 
00499 static string
00500 get_vl_f (string svl, string sf) {
00501   string w, res, f, v, l;
00502   list<string> words= get_words (svl);
00503   if (!is_nil (words)) l << words;
00504   while (!is_nil (words) && !first_is_locase (words[0])) {
00505     w << words;
00506     l= w <<  " " << l;
00507   }
00508   if (!is_nil (words)) v << words;
00509   while (!is_nil (words)) {
00510     w << words;
00511     v= w << " " << v;
00512   }
00513   words= get_words (sf);
00514   if (!is_nil (words)) f << words;
00515   while (!is_nil (words)) {
00516     w << words;
00517     f= w << " " << f;
00518   }
00519   res << "\\nextbib{}" << bib_to_latex (f);
00520   res << "\\nextbib{}" << bib_to_latex (v);
00521   res << "\\nextbib{}" << bib_to_latex (l);
00522   return res;
00523 }
00524 
00525 static string
00526 get_vl_j_f (string svl, string sj, string sf) {
00527   string res, j;
00528   res << get_vl_f (svl, sf);
00529   string w;
00530   list<string> words= get_words (sj);
00531   if (!is_nil (words)) j << words;
00532   while (!is_nil (words)) {
00533     w << words;
00534     j= w << " " << j;
00535   }
00536   res << "\\nextbib{}" << bib_to_latex (j);
00537   return res;
00538 }
00539 
00540 static string
00541 get_until_char (string s, int& pos, string c) {
00542   string res;
00543   int depth= 0;
00544   bool special= false;
00545   int math= 0;
00546   while (pos < N(s)) {
00547     string ch= bib_parse_char (s, pos, depth, special, math);
00548     if (ch == c && depth == 0 && !special && math == 0) return res;
00549     else res << ch;
00550   }
00551   return res;
00552 }
00553 
00554 static string
00555 get_first_von_last (string s) {
00556   string a, b, c;
00557   int pos= 0;
00558   a= get_until_char (s, pos, ",");
00559   b= get_until_char (s, pos, ",");
00560   c= get_until_char (s, pos, "");
00561   if (a != "" && b == "" && c == "") {
00562     string res= get_fvl (a);
00563     res << "\\nextbib{}";
00564     return res;
00565   }
00566   if (a != "" && b != "" && c == "") {
00567     string res= get_vl_f (a, b);
00568     res << "\\nextbib{}";
00569     return res;
00570   }
00571   if (a != "" && b != "" && c != "") return get_vl_j_f (a, b, c);
00572   return "";
00573 }
00574 
00575 string
00576 bib_names (string s, int& nbfields) {
00577   string res;
00578   int pos= 0;
00579   nbfields++;
00580   res << "\\nextbib{}{\\bibnames}";
00581   while (pos < N(s)) {
00582     string name;
00583     int deb= pos;
00584     search_and_keyword (s, pos);
00585     int pos2= pos;
00586     if (pos < N(s)) pos -= 5;
00587     if (pos <= N(s) && deb < pos) name= s (deb, pos);
00588     res << "\\nextbib{}{\\bibname}";
00589     res << get_first_von_last (name);
00590     nbfields += 5;
00591     pos= pos2;
00592   }
00593   return res;
00594 }
00595 
00596 /******************************************************************************
00597 * BibTeX purify$
00598 ******************************************************************************/
00599 
00600 void
00601 bib_purify_tree (tree t, string& res) {
00602   if (is_atomic (t)) res << t->label;
00603   else if (L(t) == WITH) bib_purify_tree (t[N(t)-1], res);
00604   else if (L(t) == as_tree_label ("keepcase")) bib_purify_tree (t[0], res);
00605   else if (L(t) == CONCAT || L(t) == DOCUMENT) {
00606     for (int i= 0; i<N(t); i++) bib_purify_tree (t[i], res);
00607   }
00608   cout << UNINDENT;
00609 }
00610 
00611 string
00612 bib_purify (scheme_tree st) {
00613   tree t= simplify_correct (scheme_tree_to_tree (st));
00614   string res;
00615   bib_purify_tree (t, res);
00616   return res; 
00617 }
00618 
00619 /*
00620 string
00621 bib_purify (string s) {
00622   string r;
00623   int pos= 0;
00624   int depth= 0;
00625   bool special= false;
00626   while (pos < N(s)) {
00627     string ch= bib_parse_char (s, pos, depth, special);
00628     if (bib_is_space (ch) || bib_is_char (ch, '~') || bib_is_char (ch, '-'))
00629       r << ' ';
00630     else if (bib_is_iso_alpha (ch) || bib_is_digit (ch)) r << ch;
00631     else if (ch == "\\{" || ch == "\\}") r << ch[1];
00632   }
00633   return r;
00634 }
00635 */
00636 
00637 /******************************************************************************
00638 * BibTeX text.length$
00639 ******************************************************************************/
00640 
00641 /*
00642 int
00643 bib_text_length (string s) {
00644   int length= 0;
00645   int pos= 0;
00646   int depth= 0;
00647   bool oldspecial= false;
00648   bool special= false;
00649   while (pos < N(s)) {
00650     string ch= bib_parse_char (s, pos, depth, special);
00651     if (N(ch) == 1 && ch[0] != '{' && ch[0] != '}') length++;
00652     else if (!oldspecial && special) length++;
00653     oldspecial= special;
00654   }
00655   return length;
00656 }
00657 */
00658 
00659 static int
00660 bib_tree_length (tree t) {
00661   if (is_atomic (t)) return N(t->label);
00662   else if (L(t) == WITH) return bib_tree_length (t[N(t)-1]);
00663   else if (L(t) == CONCAT || L(t) == DOCUMENT) {
00664     int s= 0;
00665     for (int i= 0; i<N(t); i++) s += bib_tree_length (t[i]);
00666   }
00667   return 0;
00668 }
00669 
00670 int
00671 bib_text_length (scheme_tree st) {
00672   tree t= simplify_correct (scheme_tree_to_tree (st));
00673   return bib_tree_length (t); 
00674 }
00675 
00676 /******************************************************************************
00677 * BibTeX text.prefix$
00678 ******************************************************************************/
00679 
00680 static void
00681 bib_get_prefix (tree t, string& pre, int& i) {
00682   if (i > 0) {
00683     if (is_atomic (t)) {
00684       string s= t->label;
00685       int beg= 0;
00686       while ((beg < N(s)) && (i > 0)) {
00687         pre << s[beg];
00688         beg++;
00689         i--;
00690       }
00691       return;
00692     }
00693     else {
00694       int pos= 0;
00695       if (L(t) == WITH) pos= N(t)-1;
00696       else if (L(t) == CONCAT || L(t) == DOCUMENT)
00697         for (int j= pos; j<N(t); j++) bib_get_prefix (t[j], pre, i);
00698     }
00699   }
00700 }
00701 
00702 string
00703 bib_prefix (scheme_tree st, int i) {
00704   tree t= simplify_correct (scheme_tree_to_tree (st));
00705   string pre;
00706   int j= i;
00707   bib_get_prefix (t, pre, j);
00708   return pre; 
00709 }
00710 
00711 /*
00712 string
00713 bib_text_prefix (string s, int i) {
00714   string chars;
00715   int nb= 0;
00716   int pos= 0;
00717   int depth= 0;
00718   bool oldspecial= false;
00719   bool special= false;
00720   while (pos < N(s)) {
00721     string ch= bib_parse_char (s, pos, depth, special);
00722     chars << ch;
00723     bool not_braces= (N(ch) == 1 && ch[0] != '{' && ch[0] != '}');
00724     if (!special && (oldspecial || not_braces || ch == "\\{" || ch == "\\}")) {
00725       nb++;
00726       if (nb == i) break;
00727     }
00728     oldspecial= special;
00729   }
00730   for (int k=0; k<depth; k++) chars << '}';
00731   return chars;
00732 }
00733 */
00734 
00735 /******************************************************************************
00736 * Abbreviate names
00737 ******************************************************************************/
00738 
00739 static void
00740 get_first_letters (tree t, tree s1, tree s2, tree& l) {
00741   if (is_atomic (t)) {
00742     string s= t->label;
00743     int beg= 0;
00744     while (beg < N(s)) {
00745       while (beg < N(s) && is_space (s[beg])) beg++;
00746       if (beg < N(s)) {
00747         if (N(l) > 0) l << s2;
00748         l << s(beg, beg+1) << s1;
00749         while (beg < N(s) && !is_space (s[beg])) {
00750           beg++;
00751           if (beg < N(s) && s[beg] == '-') {
00752             beg++;
00753             l << "-" << s(beg, beg+1) << s1;
00754           }
00755         }
00756       }
00757     }
00758   }
00759   else {
00760     if (L(t) == WITH) get_first_letters (t[N(t)-1], s1, s2, l);
00761     else
00762       for (int pos= 0; pos<N(t); pos++)
00763         get_first_letters (t[pos], s1, s2, l);
00764   }
00765 }
00766 
00767 scheme_tree
00768 bib_abbreviate (scheme_tree st, scheme_tree s1, scheme_tree s2) {
00769   tree t= simplify_correct (scheme_tree_to_tree (st));
00770   tree ts1= simplify_correct (scheme_tree_to_tree (s1));
00771   tree ts2= simplify_correct (scheme_tree_to_tree (s2));
00772   tree l (CONCAT);
00773   get_first_letters (t, ts1, ts2, l);
00774   return tree_to_scheme_tree (l);
00775 }
00776 
00777 /******************************************************************************
00778 * Convert all fields to texmacs tree
00779 ******************************************************************************/
00780 
00781 tree
00782 bib_field_pages (string p) {
00783   tree res= compound ("bib-pages");;
00784   int p1, p2;
00785   int pos= 0;
00786   if (read_int (p, pos, p1)) {
00787     res << as_string (p1);
00788     while (pos < N(p) && !is_digit (p[pos])) pos++;
00789     if (read_int (p, pos, p2))
00790       res << as_string (p2);
00791     return res;
00792   }
00793   res << "0";
00794   return res;
00795 }
00796 
00797 static int
00798 bib_get_fields (tree t, string& latex) {
00799   int nbfields= 0;
00800   for (int i= 0; i<N(t); i++) {
00801     if (bib_is_entry (t[i])) {
00802       for (int j= 0; j<N(t[i][2]); j++) {
00803         tree f= t[i][2][j];
00804         if (bib_is_field (f)) {
00805           if ((f[0]->label == "author" || f[0]->label == "editor") &&
00806               is_atomic (f[1])) {
00807             latex << bib_names (f[1]->label, nbfields);
00808           }
00809           else if (is_atomic (f[1]) && f[0]->label != "pages") {
00810             if (!bib_is_blank_string (f[1]->label)) {
00811               latex << "\\nextbib{}" << bib_to_latex (f[1]->label);
00812               nbfields++;;
00813             }
00814             else {
00815               latex << "\\nextbib{}";
00816               nbfields++;
00817             }
00818           }
00819         }
00820       }
00821     }
00822     else if (bib_is_comment (t[i]))
00823       nbfields += bib_get_fields (t[i], latex);
00824   }
00825   return nbfields;
00826 }
00827 
00828 static void
00829 bib_set_fields (tree& t, array<tree> latex, int& ind) {
00830   for (int i= 0; i<N(t); i++) {
00831     if (bib_is_entry (t[i])) {
00832       //cout << "Changing " << t[i] << "\n";
00833       for (int j= 0; j<N(t[i][2]); j++) {
00834         tree f= t[i][2][j];
00835         //cout << "  Field " << f << "\n";
00836         if (bib_is_field (f)) {
00837           if ((f[0]->label == "author" || f[0]->label == "editor") &&
00838               is_atomic (f[1])) {
00839             tree res= compound ("bib-names"); ind++;
00840             while (latex[ind] == compound ("bibname")) {
00841               tree name= compound ("bib-name"); ind++;
00842               name << latex[ind]; ind++;
00843               name << latex[ind]; ind++;
00844               name << latex[ind]; ind++;
00845               name << latex[ind]; ind++;
00846               res << name;
00847             }
00848             f[1]= res;
00849           }
00850           else if (f[0]->label == "pages" && is_atomic (f[1]))
00851             f[1]= bib_field_pages (f[1]->label);
00852           else {
00853             f[1]= latex[ind];
00854             ind++;
00855           }
00856         }
00857       }
00858     }
00859     else if (bib_is_comment (t[i]))
00860       bib_set_fields (t[i], latex, ind);
00861   }
00862 }
00863 
00864 static array<tree>
00865 bib_latex_array (tree latex) {
00866   int i= 0;
00867   array<tree> res;
00868   while (i < N(latex) && latex[i] == compound ("nextbib", "")) {
00869     i++;
00870     if (i < N(latex)) {
00871       if (latex[i] == compound ("bibnames")
00872           || latex[i] == compound ("bibname")) {
00873         res << simplify_correct (latex[i]);
00874         i++;
00875       }
00876       else {
00877         tree elt (CONCAT);
00878         while (i < N(latex) && latex[i] != compound ("nextbib", "")) {
00879           elt << latex[i];
00880           i++;
00881         }
00882         res << simplify_correct (elt);
00883       }
00884     }
00885   }
00886   return res;
00887 }
00888 
00889 void
00890 bib_parse_fields (tree& t) {
00891   string fields;
00892   int i= 0;
00893   int nb= bib_get_fields (t, fields);
00894   array<tree> latex= bib_latex_array (latex_to_tree (parse_latex (fields)));
00895   if (nb == N(latex)) bib_set_fields (t, latex, i);
00896 }
00897 
00898 /******************************************************************************
00899 * Return the value of a field
00900 ******************************************************************************/
00901 
00902 scheme_tree
00903 bib_field (scheme_tree st, string field) {
00904   tree t= scheme_tree_to_tree (st);
00905   if (bib_is_entry (t)) {
00906     tree doc= t[2];
00907     for (int i= 0; i<N(doc); i++) {
00908       if (bib_is_field (doc[i]) && doc[i][0] == field)
00909         return tree_to_scheme_tree (doc[i][1]);
00910     }
00911   }
00912   return "";
00913 }
00914 
00915 /******************************************************************************
00916 * Is a field empty?
00917 ******************************************************************************/
00918 
00919 bool
00920 bib_empty (scheme_tree st, string f) {
00921   return (bib_field (st, f) == "");
00922 }
00923 
00924 /******************************************************************************
00925 * BibTeX preamble$
00926 ******************************************************************************/
00927 
00928 string
00929 bib_preamble (tree t) {
00930   string pre;
00931   if (bib_is_preamble (t)) {
00932     tree doc= t[0];
00933     for (int i= 0; i<N(doc); i++)
00934       if (bib_is_latex (doc[i]))
00935        pre << "\n" << doc[i][0]->label;
00936   }
00937   return pre;
00938 }
00939 
00940 /******************************************************************************
00941 * Entries selection
00942 ******************************************************************************/
00943 
00944 hashmap<string,string>
00945 bib_strings_dict (tree t) {
00946   hashmap<string,string> dict ("");
00947   dict("acmcs")= "ACM Computing Surveys";
00948   dict("acta")= "Acta Informatica";
00949   dict("cacm")= "Communications of the ACM";
00950   dict("ibmjrd")= "IBM Journal of Research and Development";
00951   dict("ibmsj")= "IBM Systems Journal";
00952   dict("ieeese")= "IEEE Transactions on Software Engineering";
00953   dict("ieeetc")= "IEEE Transactions on Computers";
00954   dict("ieeetcad")= "IEEE Transactions on Computer-Aided Design of Integrated Circuits";
00955   dict("ipl")= "Information Processing Letters";
00956   dict("jacm")= "Journal of the ACM";
00957   dict("jcss")= "Journal of Computer and System Sciences";
00958   dict("scp")= "Science of Computer Programming";
00959   dict("sicomp")= "SIAM Journal on Computing";
00960   dict("tocs")= "ACM Transactions on Computer Systems";
00961   dict("tods")= "ACM Transactions on Database Systems";
00962   dict("tog")= "ACM Transactions on Graphics";
00963   dict("toms")= "ACM Transactions on Mathematical Software";
00964   dict("toois")= "ACM Transactions on Office Information Systems";
00965   dict("toplas")= "ACM Transactions on Programming Languages and Systems";
00966   dict("tcs")= "Theoretical Computer Science";
00967   if (L(t) == DOCUMENT) {
00968     tree str (DOCUMENT);
00969     for (int i= 0; i<N(t); i++) {
00970       if (bib_is_string (t[i])) {
00971         str= t[i][0];
00972         break;
00973       }
00974     }
00975     for (int i= 0; i<N(str); i++) {
00976       if (bib_is_assign (str[i])) {
00977         string key= locase_all (str[i][0]->label);
00978         tree val= str[i][1];
00979         if (L(val) == CONCAT) {
00980           string sval;
00981           for (int j= 0; j<N(val); j++) {
00982             if (is_atomic (val[j])) sval << val[j]->label;
00983             else if (bib_is_var (val[j])) sval << dict[val[j][0]->label];
00984           }
00985           dict(key)= sval;
00986         }
00987         else if (is_atomic (val))
00988           dict(key)= val->label;
00989       }
00990     }
00991   }
00992   return dict;
00993 }
00994 
00995 static string
00996 bib_subst_str (tree t, hashmap<string,string> dict) {
00997   if (is_atomic (t)) return t->label;
00998   else if (L(t) == CONCAT) {
00999     string s;
01000     for (int i= 0; i<N(t); i++) {
01001       if (bib_is_var (t[i])) s << dict[locase_all (t[i][0]->label)];
01002       else if (is_atomic (t[i])) s << t[i]->label;
01003       else s << bib_subst_str (t[i], dict);
01004     }
01005     return s;
01006   }
01007   else if (bib_is_var (t)) {
01008     string key= locase_all (t[0]->label);
01009     if (dict->contains (key)) return dict[locase_all (t[0]->label)];
01010     else return t[0]->label;
01011   }
01012   else return "";
01013 }
01014 
01015 tree
01016 bib_subst_vars (tree t, hashmap<string,string> dict) {
01017   if (is_atomic (t) || L(t) == CONCAT || bib_is_var (t))
01018     return tree (copy (bib_subst_str (t, dict)));
01019   else {
01020     tree r (L(t), N(t));
01021     for (int i= 0; i<N(t); i++)
01022       r[i]= bib_subst_vars (t[i], dict);
01023     return r;
01024   }
01025 }
01026 
01027 static tree
01028 bib_select_entries (tree t, tree bib_t) {
01029   hashmap<string, tree> h;
01030   hashset<string> r;
01031   tree entries (DOCUMENT);
01032   tree bt= copy (bib_t);
01033   for (int i= 0; i<N(t); i++)
01034     if (bib_is_entry (t[i]))
01035       h(t[i][1]->label)= t[i];
01036   for (int i= 0; i < arity (bt); i++) {
01037     string b= as_string (bt[i]);
01038     if (h->contains (b) && !r->contains (b)) {
01039       r->insert (b);
01040       entries << h[b];
01041       tree cr= bib_assoc (h[b], string ("crossref"));
01042       if (cr != "") bt << as_string (cr);
01043     }
01044   }
01045   return entries;
01046 }
01047 
01048 tree
01049 bib_entries (tree t, tree bib_t) {
01050   hashmap<string,string> dict= bib_strings_dict (t);
01051   tree res= bib_select_entries (t, bib_t);
01052   return res;
01053 }
01054