Back to index

texmacs  1.0.7.15
upgradetm.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : upgradetm.cpp
00004 * DESCRIPTION: upgrade old TeXmacs formats
00005 * COPYRIGHT  : (C) 1999  Joris van der Hoeven
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 "convert.hpp"
00013 #include "hashset.hpp"
00014 #include "path.hpp"
00015 #include "vars.hpp"
00016 #include "drd_std.hpp"
00017 #include <stdio.h>
00018 #include "scheme.hpp"
00019 #include "tree_correct.hpp"
00020 #include "merge_sort.hpp"
00021 
00022 static bool upgrade_tex_flag= false;
00023 double get_magnification (string s);
00024 
00025 /******************************************************************************
00026 * Retrieve older operator hashmap
00027 ******************************************************************************/
00028 
00029 static void
00030 rename_feature (hashmap<string,int>& H, string old_name, string new_name) {
00031   H (old_name)= H [new_name];
00032   H->reset (new_name);
00033 }
00034 
00035 static void
00036 new_feature (hashmap<string,int>& H, string new_name) {
00037   H->reset (new_name);
00038 }
00039 
00040 /*static*/ hashmap<string,int>
00041 get_codes (string version) {
00042   hashmap<string,int> H (UNKNOWN);
00043   H->join (STD_CODE);
00044 
00045   if (version_inf ("1.0.7.6", version)) return H;
00046 
00047   rename_feature (H, "group", "rigid");
00048   rename_feature (H, "postscript", "image");
00049 
00050   if (version_inf ("1.0.6.9", version)) return H;
00051 
00052   rename_feature (H, "frozen", "freeze");
00053 
00054   if (version_inf ("1.0.6.2", version)) return H;
00055 
00056   new_feature (H, "expand-as");
00057   new_feature (H, "locus");
00058   new_feature (H, "id");
00059   new_feature (H, "hard-id");
00060   new_feature (H, "link");
00061   new_feature (H, "url");
00062   new_feature (H, "script");
00063 
00064   if (version_inf ("1.0.4.1", version)) return H;
00065 
00066   new_feature (H, "copy");
00067   new_feature (H, "cm-length");
00068   new_feature (H, "mm-length");
00069   new_feature (H, "in-length");
00070   new_feature (H, "pt-length");
00071   new_feature (H, "bp-length");
00072   new_feature (H, "dd-length");
00073   new_feature (H, "pc-length");
00074   new_feature (H, "cc-length");
00075   new_feature (H, "fs-length");
00076   new_feature (H, "fbs-length");
00077   new_feature (H, "em-length");
00078   new_feature (H, "ln-length");
00079   new_feature (H, "sep-length");
00080   new_feature (H, "yfrac-length");
00081   new_feature (H, "ex-length");
00082   new_feature (H, "fn-length");
00083   new_feature (H, "fns-length");
00084   new_feature (H, "bls-length");
00085   new_feature (H, "spc-length");
00086   new_feature (H, "xspc-length");
00087   new_feature (H, "par-length");
00088   new_feature (H, "pag-length");
00089   new_feature (H, "tmpt-length");
00090   new_feature (H, "px-length");
00091   new_feature (H, "tmlen");
00092 
00093   if (version_inf ("1.0.3.12", version)) return H;
00094 
00095   new_feature (H, "unquote*");
00096 
00097   if (version_inf ("1.0.3.4", version)) return H;
00098 
00099   new_feature (H, "for-each");
00100   new_feature (H, "quasi");
00101   rename_feature (H, "hold", "quasiquote");
00102   rename_feature (H, "release", "unquote");
00103 
00104   if (version_inf ("1.0.3.3", version)) return H;
00105 
00106   new_feature (H, "quote-value");
00107   new_feature (H, "quote-arg");
00108   new_feature (H, "mark");
00109   new_feature (H, "use-package");
00110   new_feature (H, "style-only");
00111   new_feature (H, "style-only*");
00112   new_feature (H, "rewrite-inactive");
00113   new_feature (H, "inline-tag");
00114   new_feature (H, "open-tag");
00115   new_feature (H, "middle-tag");
00116   new_feature (H, "close-tag");
00117 
00118   if (version_inf ("1.0.2.8", version)) return H;
00119 
00120   rename_feature (H, "raw_data", "raw-data");
00121   rename_feature (H, "sub_table", "subtable");
00122   rename_feature (H, "drd_props", "drd-props");
00123   rename_feature (H, "get_label", "get-label");
00124   rename_feature (H, "get_arity", "get-arity");
00125   rename_feature (H, "map_args", "map-args");
00126   rename_feature (H, "eval_args", "eval-args");
00127   rename_feature (H, "find_file", "find-file");
00128   rename_feature (H, "is_tuple", "is-tuple");
00129   rename_feature (H, "look_up", "look-up");
00130   rename_feature (H, "var_if", "if*");
00131   rename_feature (H, "var_inactive", "inactive*");
00132   rename_feature (H, "var_active", "active*");
00133   rename_feature (H, "text_at", "text-at");
00134   rename_feature (H, "var_spline", "spline*");
00135   rename_feature (H, "old_matrix", "old-matrix");
00136   rename_feature (H, "old_table", "old-table");
00137   rename_feature (H, "old_mosaic", "old-mosaic");
00138   rename_feature (H, "old_mosaic_item", "old-mosaic-item");
00139   rename_feature (H, "var_expand", "expand*");
00140   rename_feature (H, "hide_expand", "hide-expand");
00141 
00142   rename_feature (H, "with_limits", "with-limits");
00143   rename_feature (H, "line_break", "line-break");
00144   rename_feature (H, "new_line", "new-line");
00145   rename_feature (H, "line_separator", "line-sep");
00146   rename_feature (H, "next_line", "next-line");
00147   rename_feature (H, "no_line_break", "no-break");
00148   rename_feature (H, "no_first_indentation", "no-indent");
00149   rename_feature (H, "enable_first_indentation", "yes-indent");
00150   rename_feature (H, "no_indentation_after", "no-indent*");
00151   rename_feature (H, "enable_indentation_after", "yes-indent*");
00152   rename_feature (H, "page_break_before", "page-break*");
00153   rename_feature (H, "page_break", "page-break");
00154   rename_feature (H, "no_page_break_before", "no-page-break*");
00155   rename_feature (H, "no_page_break_after", "no-page-break");
00156   rename_feature (H, "new_page_before", "new-page*");
00157   rename_feature (H, "new_page", "new-page");
00158   rename_feature (H, "new_double_page_before", "new-dpage*");
00159   rename_feature (H, "new_double_page", "new-dpage");
00160 
00161   if (version_inf ("1.0.2.5", version)) return H;
00162 
00163   new_feature (H, "compound");
00164   new_feature (H, "xmacro");
00165   new_feature (H, "get_label");
00166   new_feature (H, "get_arity");
00167   new_feature (H, "map_args");
00168   new_feature (H, "eval_args");
00169   new_feature (H, "drd_props");
00170 
00171   if (version_inf ("1.0.2.0", version)) return H;
00172 
00173   new_feature (H, "with_limits");
00174   new_feature (H, "line_break");
00175   new_feature (H, "new_line");
00176   new_feature (H, "line_separator");
00177   new_feature (H, "next_line");
00178   new_feature (H, "no_line_break");
00179   new_feature (H, "no_first_indentation");
00180   new_feature (H, "enable_first_indentation");
00181   new_feature (H, "no_indentation_after");
00182   new_feature (H, "enable_indentation_after");
00183   new_feature (H, "page_break_before");
00184   new_feature (H, "page_break");
00185   new_feature (H, "no_page_break_before");
00186   new_feature (H, "no_page_break_after");
00187   new_feature (H, "new_page_before");
00188   new_feature (H, "new_page");
00189   new_feature (H, "new_double_page_before");
00190   new_feature (H, "new_double_page");
00191 
00192   if (version_inf ("1.0.1.25", version)) return H;
00193 
00194   new_feature (H, "active");
00195   new_feature (H, "var_inactive");
00196   new_feature (H, "var_active");
00197   new_feature (H, "attr");
00198 
00199   if (version_inf ("1.0.0.20", version)) return H;
00200 
00201   new_feature (H, "text_at");
00202 
00203   if (version_inf ("1.0.0.19", version)) return H;
00204 
00205   new_feature (H, "find_file");
00206 
00207   if (version_inf ("1.0.0.14", version)) return H;
00208 
00209   rename_feature (H, "paragraph", "para");
00210 
00211   if (version_inf ("1.0.0.5", version)) return H;
00212 
00213   new_feature (H, "var_if");
00214   new_feature (H, "hide_expand");
00215 
00216   if (version_inf ("1.0.0.2", version)) return H;
00217 
00218   new_feature (H, "superpose");
00219   new_feature (H, "spline");
00220   new_feature (H, "var_spline");
00221   new_feature (H, "cspline");
00222   new_feature (H, "fill");
00223 
00224   if (version_inf ("0.3.5.2", version)) return H;
00225 
00226   new_feature (H, "raw_data");
00227   new_feature (H, "include");
00228 
00229   if (version_inf ("0.3.5.1", version)) return H;
00230 
00231   new_feature (H, "var_expand");
00232 
00233   if (version_inf ("0.3.4.12", version)) return H;
00234 
00235   new_feature (H, "range");
00236   new_feature (H, "is_tuple");
00237   new_feature (H, "look_up");
00238 
00239   if (version_inf ("0.3.4.11", version)) return H;
00240 
00241   new_feature (H, "float");
00242   new_feature (H, "datoms");
00243   new_feature (H, "dlines");
00244   new_feature (H, "dpages");
00245   new_feature (H, "pageref");
00246 
00247   if (version_inf ("0.3.4.7", version)) return H;
00248 
00249   rename_feature (H, "matrix", "old_matrix");
00250   rename_feature (H, "table", "old_table");
00251   rename_feature (H, "mosaic", "old_mosaic");
00252   rename_feature (H, "mosaic_item", "old_mosaic_item");
00253 
00254   if (version_inf ("0.3.4.6", version)) return H;
00255 
00256   new_feature (H, "tformat");
00257   new_feature (H, "twith");
00258   new_feature (H, "cwith");
00259   new_feature (H, "tmarker");
00260   new_feature (H, "row");
00261   new_feature (H, "cell");
00262   new_feature (H, "sub_table");
00263 
00264   if (version_inf ("0.3.4.0", version)) return H;
00265 
00266   new_feature (H, "tag");
00267   new_feature (H, "syntax");
00268 
00269   if (version_inf_eq ("0.3.3.15", version)) return H;
00270 
00271   new_feature (H, "uninit");
00272   new_feature (H, "error");
00273   new_feature (H, "surround");
00274   new_feature (H, "hold");
00275   new_feature (H, "release");
00276   new_feature (H, "arg");
00277 
00278   if (version_inf_eq ("0.3.3.0", version)) return H;
00279 
00280   new_feature (H, "with");
00281   new_feature (H, "macro");
00282   new_feature (H, "eval");
00283   new_feature (H, "value");
00284   new_feature (H, "or");
00285   new_feature (H, "xor");
00286   new_feature (H, "and");
00287   new_feature (H, "not");
00288   new_feature (H, "over");
00289   new_feature (H, "divide");
00290   new_feature (H, "modulo");
00291   new_feature (H, "length");
00292   new_feature (H, "date");
00293   new_feature (H, "equal");
00294   new_feature (H, "unequal");
00295   new_feature (H, "less");
00296   new_feature (H, "lesseq");
00297   new_feature (H, "greater");
00298   new_feature (H, "greatereq");
00299   new_feature (H, "if");
00300   new_feature (H, "case");
00301   new_feature (H, "for");
00302   new_feature (H, "while");
00303   new_feature (H, "extern");
00304   new_feature (H, "authorize");
00305 
00306   if (version_inf_eq ("0.3.1.8", version)) return H;
00307 
00308   rename_feature (H, "mosaic item", "mosaic_item");
00309   rename_feature (H, "<>", "symbol");
00310   rename_feature (H, ";", "backup");
00311   rename_feature (H, "'", "quote");
00312   rename_feature (H, ":=", "assign");
00313   rename_feature (H, "\\", "apply");
00314   rename_feature (H, "()", "tuple");
00315   rename_feature (H, "{,}", "collection");
00316   rename_feature (H, "->", "associate");
00317   rename_feature (H, "+", "plus");
00318   rename_feature (H, "-", "minus");
00319   rename_feature (H, "x", "times");
00320   rename_feature (H, "*", "merge");
00321   rename_feature (H, "nr", "number");
00322   H ("style")= H ["()"];
00323 
00324   return H;
00325 }
00326 
00327 /******************************************************************************
00328 * Old style is_expand predicates
00329 ******************************************************************************/
00330 
00331 static bool
00332 is_expand (tree t) {
00333   return ((L(t) == EXPAND) || (L(t) == VAR_EXPAND) || (L(t) == HIDE_EXPAND));
00334 }
00335 
00336 static bool
00337 is_expand (tree t, string s, int n) {
00338   return is_expand (t) && (N(t) == n+1) && (t[0] == s);
00339 }
00340 
00341 /******************************************************************************
00342 * Old style conversion from TeXmacs strings to TeXmacs trees
00343 ******************************************************************************/
00344 
00345 static tree
00346 string_to_tree (string s, int& pos, hashmap<string,int> codes) {
00347   string l ("");
00348   while ((pos<N(s)) && (s[pos]!='(') && (s[pos]!=',') && (s[pos]!=')')) {
00349     if ((s[pos]=='\\') && (pos<N(s)-1)) pos++;
00350     l << s[pos++];
00351   }
00352   tree t (l);
00353   tree_label code= (tree_label) codes [l];
00354   if ((l == "style") || (code == COLLECTION)) t= tree (code);
00355   if ((pos<N(s)) && (s[pos]=='(')) {
00356     if (code != UNKNOWN) t= tree (code);
00357     else t= tuple (l);
00358     do {
00359       pos++;
00360       t << string_to_tree (s, pos, codes);
00361     } while ((pos<N(s)) && (s[pos]==','));
00362     if ((pos<N(s)) && (s[pos]==')')) pos++;
00363   }
00364   return t;
00365 }
00366 
00367 static tree
00368 un_paragraph (tree t) {
00369   if (is_atomic (t)) return t;
00370   if (is_func (t, PARA, 1)) return t[0];
00371   else {
00372     int i, n= N(t);
00373     tree r (t, n);
00374     for (i=0; i<n; i++) r[i]= un_paragraph (t[i]);
00375     return r;
00376   }
00377 }
00378 
00379 /*static*/ tree
00380 string_to_tree (string s, string version) {
00381   int pos=0;
00382   return un_paragraph (string_to_tree (s, pos, get_codes (version)));
00383 }
00384 
00385 /******************************************************************************
00386 * Upgrade large delimiters, big operators and primes
00387 ******************************************************************************/
00388 
00389 tree
00390 upgrade_textual (tree t, path& mode_stack) {
00391   if (t == "") return t;
00392   if (is_atomic (t)) {
00393     int i, n= N(t->label);
00394     string s;
00395     tree r (CONCAT);
00396     for (i=0; i<n; ) {
00397       if (t->label[i] == '<') {
00398        int start= i;
00399        for (i++; i<n; i++)
00400          if (t->label[i-1] == '>') break;
00401        string ss= t->label (start, i);
00402        if (t->label[i-1] != '>') ss << '>';
00403        if (starts (ss, "<left-")) {
00404          if (s != "") r << s; s= "";
00405          r << tree (LEFT, ss (6, N(ss)-1));
00406        }
00407        else if (starts (ss, "<mid-")) {
00408          if (s != "") r << s; s= "";
00409          r << tree (MID, ss (5, N(ss)-1));
00410        }
00411        else if (starts (ss, "<right-")) {
00412          if (s != "") r << s; s= "";
00413          r << tree (RIGHT, ss (7, N(ss)-1));
00414        }
00415        else if (starts (ss, "<big-")) {
00416          if (s != "") r << s; s= "";
00417          r << tree (BIG, ss (5, N(ss)-1));
00418        }
00419        else s << ss;
00420       }
00421       else if (((t->label[i] == '\'') || (t->label[i] == '`')) &&
00422               (!is_nil (mode_stack)) && (mode_stack->item == 1))
00423        {
00424          int start= i++;
00425          while ((i<n) && (t->label[i] == t->label[i-1])) i++;
00426          if (s != "") r << s; s= "";
00427          tree_label op= t->label[start] == '`'? LPRIME: RPRIME;
00428          r << tree (op, t->label (start, i));
00429        }
00430       else s << t->label[i++];
00431     }
00432     if (s != "") r << s;
00433     if (N(r) == 1) return r[0];
00434     return r;
00435   }
00436   else {
00437     int i, n= arity (t);
00438     tree r (t, 0);
00439     for (i=0; i<n; i++) {
00440       tree u= upgrade_textual (t[i], mode_stack);
00441       if (is_func (u, SET)) {
00442        if (u == tree (SET, "mode", "text")) mode_stack= path (0, mode_stack);
00443        if (u == tree (SET, "mode", "math")) mode_stack= path (1, mode_stack);
00444        if (u == tree (SET, "mode", "prog")) mode_stack= path (2, mode_stack);
00445       }
00446       else if (is_func (u, RESET)) {
00447        if (u == tree (RESET, "mode"))
00448          if (!is_nil (mode_stack))
00449            mode_stack= mode_stack->next;
00450       }
00451       else if (is_func (u, BEGIN, 1)) {
00452        if ((u[0] == "equation") ||
00453            (u[0] == "equation*") ||
00454            (u[0] == "eqnarray*") ||
00455            (u[0] == "leqnarray*"))
00456          mode_stack= path (1, mode_stack);
00457       }
00458       else if (is_func (u, END, 1)) {
00459        if ((u[0] == "equation") ||
00460            (u[0] == "equation*") ||
00461            (u[0] == "eqnarray*") ||
00462            (u[0] == "leqnarray*"))
00463          if (!is_nil (mode_stack))
00464            mode_stack= mode_stack->next;
00465       }
00466       if (is_concat (t) && is_concat (u)) r << A(u);
00467       else r << u;
00468     }
00469     return r;
00470   }
00471 }
00472 
00473 /******************************************************************************
00474 * Upgrade lambda application -> macro expansion and value keyword
00475 ******************************************************************************/
00476 
00477 tree
00478 upgrade_apply_expand_value (tree t, hashset<string> H) {
00479   if (is_atomic (t)) return t;
00480   else {
00481     int i, n= arity (t);
00482     tree r (t, n);
00483     if (is_func (t, APPLY))
00484       if ((n >= 1) && is_atomic (t[0]) && H->contains (t[0]->label)) {
00485        if (n == 1) r= tree (VALUE, n);
00486        else r= tree (EXPAND, n);
00487       }
00488     for (i=0; i<n; i++)
00489       r[i]= upgrade_apply_expand_value (t[i], H);
00490     return r;
00491   }
00492 }
00493 
00494 typedef const char* charp;
00495 static charp apply_expand_value_strings[]= {
00496   "part", "part*", "chapter", "chapter*", "appendix",
00497   "section", "section*", "subsection", "subsection*",
00498   "subsubsection", "subsubsection*",
00499   "paragraph", "paragraph*", "subparagraph", "subparagraph*",
00500   "footnote", "item*", "overline", "underline",
00501   "mathord", "mathbin", "mathopen", "mathpunct",
00502   "mathop", "mathrel", "mathclose", "mathalpha",
00503   "op", "strong", "em", "tt", "name", "samp", "abbr",
00504   "dfn", "kbd", "var", "acronym", "person",
00505   "menu", "submenu", "subsubmenu", "tmdef", "tmref",
00506   "key", "skey", "ckey", "akey", "mkey", "hkey",
00507   "include-document", "include-project", "globalize-variable",
00508   "localize-variable", "assign-variable",
00509   "gb", "cgb", "gbt", "cgbt", "head", "tail", "hm", "tm", "binom",
00510   "ma", "mb", "md", "me", "mf", "mg", "mh", "mi", "mj", "mk",
00511   "mm", "mn", "mu", "mv", "mw", "my", "mz",
00512   "MA", "MB", "MD", "ME", "MF", "MG", "MH", "MI", "MJ", "MK",
00513   "MM", "MN", "MU", "MV", "MW", "MY", "MZ",
00514   ""
00515 };
00516 
00517 tree
00518 upgrade_apply_expand_value (tree t) {
00519   int i;
00520   hashset<string> H;
00521   for (i=0; apply_expand_value_strings[i][0] != '\0'; i++)
00522     H->insert (apply_expand_value_strings[i]);
00523   return upgrade_apply_expand_value (t, H);
00524 }
00525 
00526 /******************************************************************************
00527 * Subroutines for upgrading set/reset -> with, begin/end -> apply
00528 ******************************************************************************/
00529 
00530 static bool
00531 matching (tree open, tree close) {
00532   if (is_func (open, SET, 2))
00533     return is_func (close, RESET, 1) && (open[0] == close[0]);
00534   if (is_func (open, BEGIN))
00535     return is_func (close, END, 1) && (open[0] == close[0]);
00536   return false;
00537 }
00538 
00539 static tree
00540 with_replace (tree var, tree val, tree body) {
00541   if (is_func (body, WITH)) {
00542     int i, n= N(body);
00543     tree t= tree (WITH, n+2);
00544     t[0]= var;
00545     t[1]= val;
00546     for (i=0; i<n; i++) t[i+2]= body[i];
00547     return t;
00548   }
00549   else return tree (WITH, var, val, body);
00550 }
00551 
00552 static tree
00553 expand_replace (tree begin, tree body) {
00554   int i, k= N(begin);
00555   tree expand (EXPAND, k+1);
00556   for (i=0; i<k; i++) expand[i]= begin[i];
00557   expand[i]= body;
00558   return expand;
00559 }
00560 
00561 static void
00562 concat_search (tree t, int& i, tree open= "") {
00563   bool set_reset= (open == "") || is_func (open, SET) || is_func (open, RESET);
00564   bool begin_end= (open == "") || is_func (open, BEGIN) || is_func (open, END);
00565   int n= N(t);
00566   while (i<n) {
00567     if (set_reset && is_func (t[i], SET, 2)) return;
00568     if (set_reset && is_func (t[i], RESET, 1)) return;
00569     if (begin_end && is_func (t[i], BEGIN)) return;
00570     if (begin_end && is_func (t[i], END, 1)) return;
00571     i++;
00572   }
00573 }
00574 
00575 static tree
00576 concat_replace (tree t, int i1, int i2) {
00577   int i;
00578   tree v (CONCAT);
00579   for (i=i1+1; i<i2; i++) v << t[i];
00580   if (N(v)==0) v= "";
00581   else if (N(v)==1) v= v[0];
00582   if (is_func (t[i1], SET))
00583     return with_replace (t[i1][0], t[i1][1], v);
00584   else return expand_replace (t[i1], v);
00585 }
00586 
00587 static tree
00588 document_explode (tree t) {
00589   int i, n= N(t);
00590   tree u (t, n);
00591   for (i=0; i<n; i++)
00592     if (is_concat (t[i])) u[i]= t[i];
00593     else u[i]= tree (CONCAT, t[i]);
00594   return u;
00595 }
00596 
00597 static tree
00598 document_contract (tree t) {
00599   int i, n= N(t);
00600   tree u (t, n);
00601   for (i=0; i<n; i++)
00602     if (N(t[i]) == 0) u[i]= "";
00603     else if (N(t[i]) == 1) u[i]= t[i][0];
00604     else u[i]= t[i];
00605   return u;
00606 }
00607 
00608 static void
00609 document_search (tree t, int& i, int& j, tree open= "") {
00610   bool set_reset= (open == "") || is_func (open, SET) || is_func (open, RESET);
00611   bool begin_end= (open == "") || is_func (open, BEGIN) || is_func (open, END);
00612   int n= N(t);
00613   while (i<n) {
00614     int k= N(t[i]);
00615     while (j<k) {
00616       if (set_reset && is_func (t[i][j], SET, 2)) return;
00617       if (set_reset && is_func (t[i][j], RESET, 1)) return;
00618       if (begin_end && is_func (t[i][j], BEGIN)) return;
00619       if (begin_end && is_func (t[i][j], END, 1)) return;
00620       j++;
00621     }
00622     i++;
00623     j=0;
00624   }
00625 }
00626 
00627 static void
00628 document_inc (tree doc_t, int& doc_i, int& con_i) {
00629   con_i++;
00630   if (con_i == N(doc_t[doc_i])) {
00631     doc_i++;
00632     con_i= 0;
00633   }
00634 }
00635 
00636 static void
00637 document_inc (tree& doc, tree& con, tree doc_t, int& doc_i, int& con_i) {
00638   con_i++;
00639   if (con_i == N(doc_t[doc_i])) {
00640     doc << con;
00641     con= tree (CONCAT);
00642     doc_i++;
00643     con_i= 0;
00644   }
00645 }
00646 
00647 static void
00648 document_merge (tree& doc, tree& con, tree doc_t,
00649               int doc_1, int con_1, int doc_2, int con_2)
00650 {
00651   int doc_i= doc_1, con_i= con_1;
00652   while ((doc_i<doc_2) || ((doc_i==doc_2) && (con_i<con_2))) {
00653     con << doc_t[doc_i][con_i];
00654     document_inc (doc, con, doc_t, doc_i, con_i);
00655   }
00656 }
00657 
00658 static tree
00659 document_replace (tree doc_t, int doc_1, int con_1, int doc_2, int con_2) {
00660   tree doc_b (DOCUMENT), con_b (CONCAT);
00661   int doc_i= doc_1, con_i= con_1;
00662   document_inc (doc_b, con_b, doc_t, doc_i, con_i);
00663   document_merge (doc_b, con_b, doc_t, doc_i, con_i, doc_2, con_2);
00664   doc_b << con_b;
00665   doc_b= document_contract (doc_b);
00666   bool flag= (doc_1!=doc_2) || ((con_1==0) && (con_2==N(doc_t[doc_2])-1));
00667   /*
00668   if (N(doc_b) != (doc_2-doc_1+1))
00669     cout << (doc_2-doc_1+1) << ", " << doc_b << "\n";
00670   */
00671   if ((!flag) && (N(doc_b)==1)) doc_b= doc_b[0];
00672   if (is_func (doc_t[doc_1][con_1], SET))
00673     return with_replace (doc_t[doc_1][con_1][0],
00674                       doc_t[doc_1][con_1][1],
00675                       doc_b);
00676   else return expand_replace (doc_t[doc_1][con_1], doc_b);
00677 }
00678 
00679 /******************************************************************************
00680 * Upgrade set/reset -> with, begin/end -> apply
00681 ******************************************************************************/
00682 
00683 static tree upgrade_set_begin (tree t);
00684 
00685 static tree
00686 upgrade_set_begin_default (tree t) {
00687   int i, n= N(t);
00688   tree u (t, n);
00689   for (i=0; i<n; i++)
00690     u[i]= upgrade_set_begin (t[i]);
00691   return u;
00692 }
00693 
00694 static tree
00695 upgrade_set_begin_concat_once (tree t) {
00696   // cout << "in : " << t << "\n";
00697   int i=0, n= N(t);
00698   tree u (CONCAT);
00699   while (i<n) {
00700     int i0=i, i1, i2;
00701     concat_search (t, i);
00702     i1= i;
00703     for (i=i0; i<i1; i++) u << t[i];
00704     if (i==n) {
00705       // cout << "  " << i0 << ", " << i1 << "\n";
00706       break;
00707     }
00708     i++;
00709     concat_search (t, i, t[i1]);
00710     i2= i;
00711     // cout << "  " << i0 << ", " << i1 << ", " << i2 << "\n";
00712     if ((i2<n) && matching (t[i1], t[i2])) {
00713       u << concat_replace (t, i1, i2);
00714       i= i2+1;
00715     }
00716     else {
00717       i= i1;
00718       if (i == i0) u << t[i++];
00719     }
00720   }
00721   // cout << "out: " << u << "\n";
00722   // cout << "-------------------------------------------------------------\n";
00723   // fflush (stdout);
00724   return u;
00725 }
00726 
00727 static tree
00728 upgrade_set_begin_concat (tree t) {
00729   tree u= t;
00730   do { t= u; u= upgrade_set_begin_concat_once (t); } while (u != t);
00731   u= upgrade_set_begin_default (u);
00732   if (N(u) == 1) return u[0];
00733   return u;
00734 }
00735 
00736 static void
00737 upgrade_verbatim_expand (tree& doc, tree& con, tree ins) {
00738   tree& body= ins[N(ins)-1];
00739   if (is_document (body) && (N(body)>1)) {
00740     int n= N(body);
00741     int start=0, end=n;
00742     if (body[0] == "") start= 1;
00743     if (body[n-1] == "") end= n-1;
00744     body= body (start, end);
00745     if (start != 0) {
00746       doc << con;
00747       con= tree (CONCAT);
00748     }
00749     con << ins;
00750     if (end != n) {
00751       doc << con;
00752       con= tree (CONCAT);
00753     }
00754   }
00755   else con << ins;
00756 }
00757 
00758 static void
00759 upgrade_abstract_expand (tree& doc, tree& con, tree ins) {
00760   (void) doc;
00761   tree& body= ins[N(ins)-1];
00762   if (is_document (body) && (N(body) > 1) && (body[0] == ""))
00763     body= body (1, N(body));
00764   con << ins;
00765 }
00766 
00767 static tree
00768 upgrade_set_begin_document_once (tree doc_t) {
00769   // cout << "in : " << doc_t << "\n";
00770   int doc_i=0, con_i=0;
00771   tree doc (DOCUMENT), con (CONCAT);
00772   while ((doc_i < N(doc_t)) && (con_i < N(doc_t[doc_i]))) {
00773     int doc_0= doc_i, con_0= con_i;
00774     document_search (doc_t, doc_i, con_i);
00775     int doc_1= doc_i, con_1= con_i;
00776     // cout << "  0: " << doc_0 << ", " << con_0 << "\n";
00777     // cout << "  1: " << doc_1 << ", " << con_1 << "\n";
00778     document_merge (doc, con, doc_t, doc_0, con_0, doc_1, con_1);
00779     if (doc_i == N(doc_t)) break;
00780     document_inc (doc_t, doc_i, con_i);
00781     document_search (doc_t, doc_i, con_i, doc_t[doc_1][con_1]);
00782     int doc_2= doc_i, con_2= con_i;
00783     // cout << "  2: " << doc_2 << ", " << con_2 << "\n";
00784     if ((doc_2 < N(doc_t)) &&
00785        matching (doc_t[doc_1][con_1], doc_t[doc_2][con_2]))
00786       {
00787        tree ins= document_replace (doc_t, doc_1, con_1, doc_2, con_2);
00788        if (is_func (ins, EXPAND, 2)) {
00789          if ((ins[0] == "verbatim") || (ins[0] == "code"))
00790            upgrade_verbatim_expand (doc, con, ins);
00791          else if (ins[0] == "abstract")
00792            upgrade_abstract_expand (doc, con, ins);
00793          else con << ins;
00794        }
00795        else con << ins;
00796        document_inc (doc, con, doc_t, doc_i, con_i);
00797       }
00798     else {
00799       doc_i= doc_1; con_i= con_1;
00800       if ((doc_i == doc_0) && (con_i == con_0)) {
00801        con << doc_t[doc_i][con_i];
00802        document_inc (doc, con, doc_t, doc_i, con_i);      
00803       }
00804     }
00805   }
00806   // cout << "out: " << doc << "\n";
00807   // cout << "-------------------------------------------------------------\n";
00808   fflush (stdout);
00809   return doc;
00810 }
00811 
00812 static tree
00813 upgrade_set_begin_document (tree t) {
00814   tree u= t;
00815   do {
00816     t= u;
00817     u= document_explode (u);
00818     u= upgrade_set_begin_document_once (u);
00819     u= document_contract (u);
00820   } while (u != t);
00821   u= upgrade_set_begin_default (u);
00822   return u;
00823 }
00824 
00825 static tree
00826 upgrade_set_begin_surround (tree t, tree search, bool& found) {
00827   if (t == search) {
00828     found= true;
00829     if (upgrade_tex_flag)
00830       return tree (DOCUMENT, copy (t));
00831     return copy (t);
00832   }
00833   if (is_func (t, WITH) || is_func (t, EXPAND)) {
00834     tree u= copy (t);
00835     u[N(u)-1]= upgrade_set_begin_surround (u[N(u)-1], search, found);
00836     return u;
00837   }
00838   if (is_concat (t)) {
00839     int i, n= N(t), searching= !found;
00840     tree left (CONCAT), middle, right (CONCAT);
00841     for (i=0; i<n; i++) {
00842       middle= upgrade_set_begin_surround (t[i], search, found);
00843       if (searching && found) break;
00844       else left << middle;
00845     }
00846     if (i==n) return copy (t);
00847     for (i++; i<n; i++)
00848       right << upgrade_set_begin_surround (t[i], search, found);
00849     if (N(left) == 0) left= "";
00850     else if (N(left) == 1) left= left[0];
00851     if (N(right) == 0) right= "";
00852     else if (N(right) == 1) right= right[0];
00853     return tree (SURROUND, left, right, middle);
00854   }
00855   return copy (t);
00856 }
00857 
00858 static tree
00859 upgrade_env_args (tree t, tree env) {
00860   if (is_atomic (t)) return t;
00861   else if (is_func (t, APPLY, 1)) {
00862     int i, k= N(env);
00863     for (i=0; i<k-2; i++)
00864       if (t[0] == env[i])
00865        return tree (ARG, t[0]);
00866     return t;
00867   }
00868   else {
00869     int i, n= N(t);
00870     tree r (t, n);
00871     for (i=0; i<n; i++)
00872       r[i]= upgrade_env_args (t[i], env);
00873     return r;
00874   }
00875 }
00876 
00877 static tree
00878 upgrade_set_begin_env (tree t) {
00879   //cout << "in  : " << t << "\n";
00880   int i, n= N(t);
00881   tree u (MACRO, n);
00882   for (i=0; i<n-2; i++)
00883     u[i]= upgrade_set_begin (t[i]);
00884   string s= "body";
00885   for (i=0; i<n-2; i++)
00886     if (t[i] == "body") s= "body*";
00887   u[n-2]= copy (s);
00888 
00889   tree begin= t[n-2], end= t[n-1], body (CONCAT);
00890   if (begin == "") begin= tree (CONCAT);
00891   else if (!is_concat (begin)) begin= tree (CONCAT, begin);
00892   if (end == "") end= tree (CONCAT);
00893   else if (!is_concat (end)) end= tree (CONCAT, end);
00894   body << A(begin) << tree (ARG, copy (s)) << A(end);
00895   //cout << "mid1: " << body << "\n";
00896   body= upgrade_set_begin_concat (body);
00897   body= upgrade_env_args (body, t);
00898   //cout << "mid2: " << body << "\n";
00899   bool found= false;
00900   u[n-1]= upgrade_set_begin_surround (body, tree (ARG, s), found);
00901   //cout << "out : " << u << "\n";
00902   //cout << "-------------------------------------------------------------\n";
00903   return u;
00904 }
00905 
00906 static tree
00907 upgrade_set_begin (tree t) {
00908   if (is_atomic (t)) return copy (t);
00909   else {
00910     if (is_concat (t)) return upgrade_set_begin_concat (t);
00911     else if (is_document (t)) return upgrade_set_begin_document (t);
00912     else if (is_func (t, ENV)) return upgrade_set_begin_env (t);
00913     else return upgrade_set_begin_default (t);
00914   }
00915 }
00916 
00917 static tree
00918 eliminate_set_begin (tree t) {
00919   if (is_atomic (t)) return t;
00920   if (is_func (t, SET) || is_func (t, RESET) ||
00921       is_func (t, BEGIN) || is_func (t, END) ||
00922       is_func (t, ENV)) return "";
00923 
00924   int i, n= N(t);
00925   if (is_concat (t)) {
00926     tree r (CONCAT);
00927     for (i=0; i<n; i++) {
00928       tree u= eliminate_set_begin (t[i]);
00929       if (u != "") r << u;
00930     }
00931     if (N(r) == 0) return "";
00932     if (N(r) == 1) return r[0];
00933     return r;
00934   }
00935   else {
00936     tree r (t, n);
00937     for (i=0; i<n; i++)
00938       r[i]= eliminate_set_begin (t[i]);
00939     return r;
00940   }
00941 }
00942 
00943 /******************************************************************************
00944 * Upgrade surround, indentation after and final routine
00945 ******************************************************************************/
00946 
00947 static bool
00948 expand_needs_surrounding (string s) {
00949   return
00950     (s == "maketitle") || (s == "abstract") ||
00951     (s == "theorem") || (s == "proposition") || (s == "lemma") ||
00952     (s == "corollary") || (s == "proof") || (s == "axiom") ||
00953     (s == "definition") || (s == "notation") || (s == "conjecture") ||
00954     (s == "remark") || (s == "note") || (s == "example") ||
00955     (s == "exercise") || (s == "warning") ||
00956     (s == "convention") || (s == "acknowledgments") ||
00957     (s == "code") || (s == "quote") ||
00958     (s == "quotation") || (s == "verse") || (s == "center") ||
00959     (s == "indent") || (s == "body") || (s == "description") ||
00960     starts (s, "itemize") || starts (s, "enumerate");
00961 }
00962 
00963 static bool
00964 with_needs_surrounding (string s) {
00965   return
00966     (s == "paragraph mode") || (s == "paragraph hyphenation") ||
00967     (s == "paragraph width") || (s == "left margin") ||
00968     (s == "right margin") || (s == "first indentation") ||
00969     (s == "last indentation") || (s == "no first indentation") ||
00970     (s == "no last indentation") || (s == "interline space") ||
00971     (s == "horizontal ink separation") || (s == "line stretch") ||
00972     (s == "interparagraph space");
00973 }
00974 
00975 static bool
00976 needs_surrounding (tree t) {
00977   if (is_multi_paragraph (t)) return true;
00978   if ((is_func (t, APPLY) || is_func (t, EXPAND)) && is_atomic (t[0])) {
00979     if (t[0] == "verbatim") return (N(t)==2) && is_multi_paragraph (t[1]);
00980     return expand_needs_surrounding (t[0]->label);
00981   }
00982   if (is_func (t, WITH)) {
00983     int i, n= N(t)-1;
00984     for (i=0; i<n; i+=2)
00985       if (is_atomic (t[i]) && with_needs_surrounding (t[i]->label))
00986        return true;
00987   }
00988   return false;
00989 }
00990 
00991 static bool
00992 needs_transfer (tree t) {
00993   return
00994     is_func (t, EXPAND, 2) &&
00995     ((t[0] == "equation") || (t[0] == "equation*") ||
00996      (t[0] == "eqnarray*") || (t[0] == "leqnarray*"));
00997 }
00998 
00999 static tree
01000 upgrade_surround (tree t) {
01001   if (is_atomic (t)) return t;
01002   int i, n= N(t);
01003   tree r (t, n);
01004   for (i=0; i<n; i++) {
01005     tree u= t[i];
01006     if (is_document (t) && is_concat (u) && (N(u)>1)) {
01007       int j, k= N(u);
01008       for (j=0; j<k; j++)
01009        if (needs_surrounding (u[j])) {
01010          tree before= u (0  , j);
01011          tree after = u (j+1, k);
01012          tree body  = upgrade_surround (u[j]);
01013          if (N(before)==0) before= "";
01014          if (N(before)==1) before= before[0];
01015          if (N(after )==0) after = "";
01016          if (N(after )==1) after = after [0];
01017          before= upgrade_surround (before);
01018          after = upgrade_surround (after );
01019          r[i]= tree (SURROUND, before, after, body);
01020          break;
01021        }
01022        else if (needs_transfer (u[j])) {
01023          tree temp= upgrade_surround (u[j][1]);
01024          if (!is_concat (temp)) temp= tree (CONCAT, temp);
01025          tree body= u (0, j);
01026          body << A (temp) << A (u (j+1, k));
01027          r[i]= tree (EXPAND, u[j][0], body);
01028          break;
01029        }
01030       if (j<k) continue;
01031     }
01032     r[i]= upgrade_surround (u);
01033   }
01034   return r;
01035 }
01036 
01037 static tree
01038 upgrade_indent (tree t) {
01039   if (is_atomic (t)) return t;
01040   else if (t == tree (ASSIGN, "no first indentation", "true"))
01041     return tree (FORMAT, "no indentation after");
01042   else if (t == tree (ASSIGN, "no first indentation", "false"))
01043     return tree (FORMAT, "enable indentation after");
01044   else {
01045     int i, n= N(t);
01046     tree r (t, n);
01047     for (i=0; i<n; i++)
01048       r[i]= upgrade_indent (t[i]);
01049     return r;
01050   }
01051 }
01052 
01053 static tree
01054 upgrade_new_environments (tree t) {
01055   t= upgrade_set_begin (t);
01056   t= eliminate_set_begin (t);
01057   t= upgrade_surround (t);
01058   t= upgrade_indent (t);
01059   return t;
01060 }
01061 
01062 /******************************************************************************
01063 * Upgrade items
01064 ******************************************************************************/
01065 
01066 static tree
01067 upgrade_items (tree t) {
01068   if (is_atomic (t)) return t;
01069   else if ((t == tree (APPLY, "item")) || (t == tree (VALUE, "item")))
01070     return tree (EXPAND, "item");
01071   else {
01072     int i, n= N(t);
01073     tree r (t, n);
01074     for (i=0; i<n; i++)
01075       r[i]= upgrade_items (t[i]);
01076     return r;
01077   }
01078 }
01079 
01080 /******************************************************************************
01081 * Upgrade resize
01082 ******************************************************************************/
01083 
01084 static tree
01085 upgrade_resize_arg (tree t, int type) {
01086   if (!is_atomic (t)) return "";
01087   string s= t->label;
01088   if ((s == "same") || (s == "ink")) return "";
01089   if (type == 1) s= "l[" * s;
01090   if (type == 2) s= "b[" * s;
01091   if (type == 3) s= "r]" * s;
01092   if (type == 4) s= "t]" * s;
01093   return s;
01094 }
01095 
01096 static tree
01097 upgrade_resize (tree t) {
01098   if (is_atomic (t)) return t;
01099   else if (is_func (t, RESIZE, 6)) {
01100     tree r (RESIZE, t[0]);
01101     int extend= (t[1] == "extend"? 1: 0);
01102     r << upgrade_resize_arg (t[2], 1 * extend)
01103       << upgrade_resize_arg (t[3], 2 * extend)
01104       << upgrade_resize_arg (t[4], 3 * extend)
01105       << upgrade_resize_arg (t[5], 4 * extend);
01106     return r;
01107   }
01108   else {
01109     int i, n= N(t);
01110     tree r (t, n);
01111     for (i=0; i<n; i++)
01112       r[i]= upgrade_resize (t[i]);
01113     return r;
01114   }
01115 }
01116 
01117 /******************************************************************************
01118 * Upgrade tables
01119 ******************************************************************************/
01120 
01121 static void
01122 handle_mosaic_format (tree& fm, tree t, int i, int j) {
01123   string align = as_string (t[1]);
01124   string hspan = as_string (t[2]);
01125   string vspan = as_string (t[3]);
01126   string col   = as_string (t[4]);
01127 
01128   string halign= "l";
01129   string valign= "B";
01130   if (N(align)>=2) {
01131     switch (align[0]) {
01132     case 'n': valign= "t"; break;
01133     case 'c': valign= "c"; break;
01134     case '0': valign= "B"; break;
01135     case 's': valign= "s"; break;
01136     }
01137     switch (align[1]) {
01138     case 'w': halign= "l"; break;
01139     case '0': halign= "L"; break;
01140     case 'c': halign= "c"; break;
01141     case 'e': halign= "r"; break;
01142     }
01143   }
01144   if ((col == "none") || (col == "")) col= "";
01145   else col= "foreground";
01146 
01147   tree w (CWITH);
01148   w << as_string (i+1) << as_string (j+1)
01149     << as_string (i+1) << as_string (j+1);
01150 
01151   if (halign != "l") {
01152     tree with= copy (w);
01153     with << "cell halign" << halign;
01154     fm << with;
01155   }
01156   if (valign != "B") {
01157     tree with= copy (w);
01158     with << "cell valign" << valign;
01159     fm << with;
01160   }
01161   if (hspan != "1") {
01162     tree with= copy (w);
01163     with << "cell hspan" << hspan;
01164     fm << with;
01165   }
01166   if (vspan != "1") {
01167     tree with= copy (w);
01168     with << "cell vspan" << vspan;
01169     fm << with;
01170   }
01171   if (col != "") {
01172     tree with= copy (w);
01173     with << "cell background" << col;
01174     fm << with;
01175   }
01176 }
01177 
01178 
01179 static tree
01180 upgrade_table (tree t) {
01181   if (is_atomic (t)) return t;
01182   else if (is_func (t, OLD_MATRIX) ||
01183           is_func (t, OLD_TABLE) ||
01184           is_func (t, OLD_MOSAIC) ||
01185           (is_func (t, TFORMAT) && is_func (t[N(t)-1], OLD_MATRIX)))
01186     {
01187       tree ft (TFORMAT);
01188       if (is_func (t, TFORMAT)) {
01189        ft= t (0, N(t)-1);
01190        t = t [N(t)-1];
01191       }
01192       if (is_func (t, OLD_MOSAIC)) {
01193        tree with (CWITH);
01194        with << "1" << "-1" << "1" << "-1" << "cell mode" << "c";
01195        ft << with;
01196       }
01197 
01198       int i, j;
01199       int nr_rows= as_int (t[N(t)-1]);
01200       int nr_cols= as_int (t[N(t)-2]);
01201       tree tt (TABLE, nr_rows);
01202       for (i=0; i<nr_rows; i++) {
01203        tree rt (ROW, nr_cols);
01204        for (j=0; j<nr_cols; j++) {
01205          tree c= upgrade_table (t[i*nr_cols+j]);
01206          if (is_func (c, OLD_MOSAIC_ITEM)) {
01207            handle_mosaic_format (ft, c, i, j);
01208            c= c[0];
01209          }
01210          rt[j]= tree (CELL, c);
01211        }
01212        tt[i]= rt;
01213       }
01214 
01215       ft << tt;
01216       tree xt (EXPAND, "tabular*", ft);
01217       if (is_func (t, OLD_TABLE)) xt[0]= "block*";
01218       if (is_func (t, OLD_MOSAIC)) xt[0]= "tabular";
01219       return xt;
01220     }
01221   else {
01222     int i, n= N(t);
01223     tree r (t, n);
01224     for (i=0; i<n; i++)
01225       r[i]= upgrade_table (t[i]);
01226     return r;
01227   }
01228 }
01229 
01230 /******************************************************************************
01231 * Upgrade splits
01232 ******************************************************************************/
01233 
01234 static tree
01235 upgrade_split (tree t, bool eq= false) {
01236   int i, n= N(t);
01237   if (is_atomic (t)) return t;
01238   else if (is_func (t, SURROUND, 3) && is_func (t[0], SPLIT)) {
01239     tree u= t[2];
01240     if (!is_concat (u)) u= tree (CONCAT, t[0], u);
01241     else u= tree (CONCAT, t[0]) * u;
01242     return tree (SURROUND, "", upgrade_split (t[1]), upgrade_split (u));
01243   }
01244   else if (is_func (t, SURROUND, 3) && is_concat (t[0])) {
01245     tree r (CONCAT);
01246     tree split ("");
01247     for (i=0; i<N(t[0]); i++)
01248       if (is_func (t[0][i], SPLIT)) split= t[0][i];
01249       else r << t[0][i];
01250     tree u= t[2];
01251     if (split != "") {
01252       if (!is_concat (u)) u= tree (CONCAT, split, u);
01253       else u= tree (CONCAT, split) * u;
01254     }
01255     r= tree (SURROUND, upgrade_split (r),
01256             upgrade_split (t[1]), upgrade_split (u));
01257     return r;
01258   }
01259   else if (is_concat (t)) {
01260     tree r (CONCAT);
01261     tree split ("");
01262     int nr_rows=1, nr_cols=1, sep=1;
01263     for (i=0; i<n; i++)
01264       if (is_func (t[i], SPLIT)) split= t[i];
01265       else {
01266        tree u= upgrade_split (t[i]);
01267        if (u == tree (FORMAT, "line separator")) sep++;
01268        if (u == tree (FORMAT, "next line")) {
01269          nr_cols= max (sep, nr_cols);
01270          sep= 1;
01271          nr_rows++;
01272        }
01273        r << u;
01274       }
01275     nr_cols= max (sep, nr_cols);
01276     if (split == "" && nr_cols == 1 && !eq) return r;
01277     else {
01278       int col=0, row=0;
01279       tree T (TABLE, nr_rows);
01280       for (row=0; row<nr_rows; row++) {
01281        tree R (ROW, nr_cols);
01282        for (col=0; col<nr_cols; col++) R[col]= tree (CELL, "");
01283        T[row]= R;
01284       }
01285 
01286       tree u (CONCAT);
01287       row= col= 0;
01288       for (i=0; i<N(r); i++)
01289        if ((r[i] == tree (FORMAT, "line separator")) ||
01290            (r[i] == tree (FORMAT, "next line")))
01291          {
01292            if (N(u) == 0) u= "";
01293            else if (N(u) == 1) u= u[0];
01294            T[row][col][0]= u;
01295            u= tree (CONCAT);
01296            if (r[i] == tree (FORMAT, "line separator")) col++;
01297            else {
01298              row++;
01299              col= 0;
01300            }
01301          }
01302        else u << r[i];
01303       if (N(u) == 0) u= "";
01304       else if (N(u) == 1) u= u[0];
01305       T[row][col][0]= u;
01306       r= T;
01307     }
01308 
01309     tree tf (TFORMAT);
01310     if (split != "") {
01311       tf << tree (TWITH, "table hyphen", "y")
01312         << tree (TWITH, "table width", "1par")
01313         << tree (TWITH, "table min cols", as_string (N (split)))
01314         << tree (TWITH, "table max cols", as_string (N (split)))
01315         << tree (CWITH, "1", "-1", "1", "1", "cell lsep", "0spc")
01316         << tree (CWITH, "1", "-1", "-1", "-1", "cell rsep", "0spc")
01317         << tree (CWITH, "1", "-1", "1", "-1", "cell bsep", "0sep")
01318         << tree (CWITH, "1", "-1", "1", "-1", "cell tsep", "0sep")
01319         << tree (CWITH, "1", "-1", "1", "1", "cell hyphen", "b")
01320         << tree (CWITH, "1", "-1", "-1", "-1", "cell hyphen", "t");
01321       if (split[0] == "right")
01322        tf << tree (CWITH, "1", "-1", "1", "1", "cell hpart", "1");
01323       if ((split[N(split)-1] == "left") || (split[N(split)-1] == "justify"))
01324        tf << tree (CWITH, "1", "-1", "-1", "-1", "cell hpart", "1");
01325       for (i=0; i<N(split); i++) {
01326        tree with (CWITH);
01327        int j= (i==N(split)-1)? -1: i+1;
01328        with << "1" << "-1" << as_string (j) << as_string (j) << "cell halign";
01329        if (split[i] == "right") with << "r";
01330        else if (split[i] == "center") with << "c";
01331        else with << "l";
01332        tf << with;
01333       }
01334     }
01335     if (r == tree (CONCAT)) r= "";
01336     else if (is_func (r, CONCAT, 1)) r= r[0];
01337     tf << r;
01338     if ((split != "") && is_func (r, TABLE))
01339       return tree (EXPAND, "tabular*", tf);
01340     return tf;
01341   }
01342   else {
01343     tree r (t, n);
01344     if (n == 1 || is_func (t, EXPAND, 2)) {
01345       string s= as_string (L(t));
01346       if (is_func (t, EXPAND, 2) && is_atomic (t[0])) s= t[0]->label;
01347       if (ends (s, "*")) s= s (0, N(s)-1);
01348       if (s == "eqnarray" || s == "align" || s == "multline" ||
01349           s == "gather" || s == "eqsplit") {
01350         tree arg= t[n-1];
01351         if (is_func (arg, DOCUMENT, 1)) arg= arg[0];
01352         if (!is_concat (arg)) arg= tree (CONCAT, arg);
01353         r= copy (t);
01354         r[n-1]= upgrade_split (arg, true);
01355         return r;
01356       }
01357     }
01358     for (i=0; i<n; i++)
01359       r[i]= upgrade_split (t[i]);
01360     return r;
01361   }
01362 }
01363 
01364 /******************************************************************************
01365 * Upgrade projects
01366 ******************************************************************************/
01367 
01368 static tree
01369 upgrade_project (tree t) {
01370   if (is_atomic (t)) return t;
01371   else if (is_expand (t, "include-document", 1))
01372     return tree (INCLUDE, t[1]);
01373   else {
01374     int i, n= N(t);
01375     tree r (t, n);
01376     for (i=0; i<n; i++)
01377       r[i]= upgrade_project (t[i]);
01378     return r;
01379   }
01380 }
01381 
01382 /******************************************************************************
01383 * Upgrade title
01384 ******************************************************************************/
01385 
01386 static tree
01387 upgrade_title (tree t, tree& tit, tree& auth, tree& meta) {
01388   if (is_atomic (t)) return t;
01389   else if (is_func (t, APPLY, 2) ||
01390            is_func (t, EXPAND, 2)) {
01391     if (t[0] == "title") {
01392       tit << tree (EXPAND, "title", t[1]); return ""; }
01393     if (t[0] == "author") {
01394       auth << tree (EXPAND, "author", t[1]); return ""; }
01395     if (t[0] == "address") {
01396       auth << tree (EXPAND, "address", t[1]); return ""; }
01397     if (t[0] == "urladdr") {
01398       auth << tree (EXPAND, "title-web", t[1]); return ""; }
01399     if (t[0] == "title-email") {
01400       auth << tree (EXPAND, "title-email", t[1]); return ""; }
01401     if (t[0] == "title-thanks") {
01402       meta << tree (EXPAND, "title-thanks", t[1]); return ""; }
01403     if (t[0] == "keywords") {
01404       meta << tree (EXPAND, "title-keywords", t[1]); return ""; }
01405     if (t[0] == "subjclass") {
01406       meta << tree (EXPAND, "title-ams-class", t[1]); return ""; }
01407     if (t[0] == "classification") {
01408       meta << tree (EXPAND, "title-ams-class", t[1]); return ""; }
01409   }
01410   else if (is_func (t, APPLY, 3) ||
01411            is_func (t, EXPAND, 3)) {
01412     if (t[0] == "subjclass*") {
01413       meta << tree (EXPAND, "title-ams-class", t[2]); return ""; }
01414   }
01415   else if ((t == tree (APPLY, "maketitle")) ||
01416           (t == tree (EXPAND, "maketitle")))
01417     {
01418       tree doc (DOCUMENT);
01419       doc << A (tit);
01420       doc << A (auth);
01421       doc << A (meta);
01422       doc << tree (EXPAND, "title-date", tree (_DATE, ""));
01423       return tree (EXPAND, "make-title", doc);
01424     }
01425 
01426   int i, n= N(t);
01427   tree r (t, n);
01428   for (i=0; i<n; i++)
01429     r[i]= upgrade_title (t[i], tit, auth, meta);
01430   return r;
01431 }
01432 
01433 static tree
01434 upgrade_title (tree t) {
01435   tree tit (DOCUMENT), auth (DOCUMENT), meta (DOCUMENT);
01436   return simplify_correct (upgrade_title (t, tit, auth, meta));
01437 }
01438 
01439 /******************************************************************************
01440 * Upgrade cas
01441 ******************************************************************************/
01442 
01443 static void
01444 upgrade_cas_search (tree t, tree& style) {
01445   if (is_atomic (t));
01446   else if (is_expand (t, "session", 3)) {
01447     if (!is_atomic (t[1])) return;
01448     string l= copy (t[1]->label);
01449     if (l == "scheme") return;
01450     if (l == "shell") return;
01451     if (l == "gTybalt") l= "gtybalt";
01452     if (l == "Macaulay2") l= "macaulay2";
01453     int i, n= N(style);
01454     for (i=0; i<n; i++)
01455       if (style[i] == l) return;
01456     style << l;
01457   }
01458   else {
01459     int i, n= N(t);
01460     for (i=0; i<n; i++)
01461       upgrade_cas_search (t[i], style);
01462   }
01463 }
01464 
01465 static void
01466 set_document_attribute (tree doc, string attr, tree val) {
01467   int i, n= arity (doc);
01468   for (i=0; i<n; i++)
01469     if ((is_func (doc[i], EXPAND, 2) || is_func (doc[i], APPLY, 2)) &&
01470        (doc[i][0] == attr))
01471       {
01472        doc[i][1]= val;
01473        return;
01474       }
01475   doc << tree (EXPAND, attr, val);
01476 }
01477 
01478 static tree
01479 upgrade_cas (tree doc) {
01480   tree style= copy (extract (doc, "style"));
01481   upgrade_cas_search (doc, style);
01482   doc= copy (doc);
01483   set_document_attribute (doc, "style", style);
01484   return doc;
01485 }
01486 
01487 /******************************************************************************
01488 * Upgrade modified symbols
01489 ******************************************************************************/
01490 
01491 static bool
01492 is_with (tree t, string var, string val) {
01493   return is_func (t, WITH, 3) && (t[0] == var) && (t[1] == val);
01494 }
01495 
01496 static bool
01497 is_alpha (tree t) {
01498   if (is_compound (t)) return false;
01499   string s= t->label;
01500   return (N(s) == 1) && is_alpha (s[0]);
01501 }
01502 
01503 static bool
01504 is_alpha_numeric (tree t) {
01505   if (is_compound (t)) return false;
01506   string s= t->label;
01507   return (N(s) == 1) && (is_alpha (s[0]) || is_numeric (s[0]));
01508 }
01509 
01510 static bool
01511 is_upper (tree t) {
01512   if (is_compound (t)) return false;
01513   string s= t->label;
01514   return (N(s) == 1) && (s[0] >= 'A') && (s[0] <= 'Z');
01515 }
01516 
01517 static bool
01518 is_bold (tree t) {
01519   if (is_compound (t)) return false;
01520   if (is_alpha_numeric (t)) return true;
01521   string s= locase_all (t->label);
01522   return
01523     (s == "<alpha>") || (s == "<beta>") || (s == "<gamma>") ||
01524     (s == "<delta>") || (s == "<epsilon>") || (s == "<zeta>") ||
01525     (s == "<eta>") || (s == "<theta>") || (s == "<iota>") ||
01526     (s == "<kappa>") || (s == "<lambda>") || (s == "<mu>") ||
01527     (s == "<nu>") || (s == "<xi>") || (s == "<omicron>") ||
01528     (s == "<pi>") || (s == "<rho>") || (s == "<sigma>") ||
01529     (s == "<tau>") || (s == "<upsilon>") || (s == "<phi>") ||
01530     (s == "<psi>") || (s == "<chi>") || (s == "<omega>") ||
01531     (s == "<varepsilon>") || (s == "<vartheta>") || (s == "<varkappa>") ||
01532     (s == "<varpi>") || (s == "<varrho>") || (s == "<varsigma>") ||
01533     (s == "<varphi>") || (s == "<backepsilon>") || (s == "<mho>") ||
01534     (s == "<Backepsilon>") || (s == "<Mho>") || (s == "<ell>");
01535 }
01536 
01537 static tree
01538 upgrade_mod_symbol (string prefix, string s) {
01539   if (N(s) == 1) return "<" * prefix * s * ">";
01540   else return "<" * prefix * s (1, N(s)-1) * ">";
01541 }
01542 
01543 static tree
01544 upgrade_mod_symbols (tree t) {
01545   if (is_atomic (t)) return t;
01546   if (is_with (t, "math font series", "bold") && is_bold (t[2]))
01547     return upgrade_mod_symbol ("b-", t[2]->label);
01548   else if (is_with (t, "math font", "cal") && is_upper (t[2]))
01549     return upgrade_mod_symbol ("cal-", t[2]->label);
01550   else if (is_with (t, "math font", "Euler") && is_alpha (t[2]))
01551     return upgrade_mod_symbol ("frak-", t[2]->label);
01552   else if (is_with (t, "math font", "Bbb*") && is_alpha (t[2]))
01553     return upgrade_mod_symbol ("bbb-", t[2]->label);
01554   else if (is_with (t, "math font series", "bold") &&
01555           is_with (t[2], "math font", "cal") && is_upper (t[2][2]))
01556     return upgrade_mod_symbol ("b-cal-", t[2][2]->label);
01557   else if (is_with (t, "math font", "cal") &&
01558           is_with (t[2], "math font series", "bold") && is_upper (t[2][2]))
01559     return upgrade_mod_symbol ("b-cal-", t[2][2]->label);
01560   else if ((is_func (t, VALUE, 1) || is_func (t, EXPAND, 1) ||
01561            is_func (t, APPLY, 1)) && (is_atomic (t[0]))) {
01562     string s= t[0]->label;
01563     if ((N(s) == 2) && ((s[0]=='m') && (s[1]>='a') && s[1]<='z'))
01564       return upgrade_mod_symbol ("frak-", s(1,2));
01565     if ((N(s) == 2) && ((s[0]=='M') && (s[1]>='A') && s[1]<='Z'))
01566       return upgrade_mod_symbol ("frak-", s(1,2));
01567     return t;
01568   }
01569   else {
01570     int i, n= N(t);
01571     tree r (t, n);
01572     for (i=0; i<n; i++)
01573       r[i]= upgrade_mod_symbols (t[i]);
01574     return r;
01575   }
01576 }
01577 
01578 /******************************************************************************
01579 * Upgrading menus in the help
01580 ******************************************************************************/
01581 
01582 static tree
01583 upgrade_menus_in_help (tree t) {
01584   if (is_atomic (t)) return t;
01585   if (is_expand (t, "menu", 1) || is_expand (t, "submenu", 2) ||
01586       is_expand (t, "subsubmenu", 3) || is_expand (t, "subsubsubmenu", 4)) {
01587     int i, n= N(t);
01588     tree r (APPLY, n);
01589     r[0]= "menu";
01590     for (i=1; i<n; i++) r[i]= t[i];
01591     return r;
01592   }
01593   else {
01594     int i, n= N(t);
01595     tree r (t, n);
01596     for (i=0; i<n; i++)
01597       r[i]= upgrade_menus_in_help (t[i]);
01598     return r;
01599   }
01600 }
01601 
01602 static tree
01603 capitalize_sub (tree t) {
01604   if (is_atomic (t)) return upcase_first (t->label);
01605   else return t;
01606 }
01607 
01608 static tree
01609 upgrade_capitalize_menus (tree t) {
01610   if (is_atomic (t)) return t;
01611   if (is_func (t, APPLY) && (t[0] == "menu")) {
01612     int i, n= N(t);
01613     tree r (APPLY, n);
01614     r[0]= "menu";
01615     for (i=1; i<n; i++) r[i]= capitalize_sub (t[i]);
01616     return r;
01617   }
01618   else {
01619     int i, n= N(t);
01620     tree r (t, n);
01621     for (i=0; i<n; i++)
01622       r[i]= upgrade_capitalize_menus (t[i]);
01623     return r;
01624   }
01625 }
01626 
01627 /******************************************************************************
01628 * Upgrade branches
01629 ******************************************************************************/
01630 
01631 static tree
01632 upgrade_traverse_branch (tree t) {
01633   if (is_atomic (t)) return t;
01634   else if (is_expand (t, "branch", 3) ||
01635           (is_func (t, APPLY, 4) && (t[0] == "branch")))
01636     return tree (APPLY, t[0], t[1], t[3]);
01637   else {
01638     int i, n= N(t);
01639     tree r (t, n);
01640     for (i=0; i<n; i++)
01641       r[i]= upgrade_traverse_branch (t[i]);
01642     return r;
01643   }
01644 }
01645 
01646 /******************************************************************************
01647 * Upgrade sessions
01648 ******************************************************************************/
01649 
01650 static tree
01651 upgrade_session (tree t) {
01652   if (is_atomic (t)) return t;
01653   else if (is_expand (t, "session", 3)) {
01654     tree u= tree (EXPAND, "session", t[3]);
01655     tree w= tree (WITH);
01656     w << PROG_LANGUAGE << t[1] << PROG_SESSION << t[2] << u;
01657     return w;
01658   }
01659   else {
01660     int i, n= N(t);
01661     tree r (t, n);
01662     for (i=0; i<n; i++)
01663       r[i]= upgrade_session (t[i]);
01664     return r;
01665   }
01666 }
01667 
01668 /******************************************************************************
01669 * Upgrade sessions
01670 ******************************************************************************/
01671 
01672 static tree
01673 upgrade_formatting (tree t) {
01674   if (is_atomic (t)) return t;
01675   else if (is_func (t, FORMAT, 1)) {
01676     string name= replace (t[0]->label, " ", "-");
01677     if (name == "line-separator") name= "line-sep";
01678     else if (name == "no-line-break") name= "no-break";
01679     else if (name == "no-first-indentation") name= "no-indent";
01680     else if (name == "enable-first-indentation") name= "yes-indent";
01681     else if (name == "no-indentation-after") name= "no-indent*";
01682     else if (name == "enable-indentation-after") name= "yes-indent*";
01683     else if (name == "page-break-before") name= "page-break*";
01684     else if (name == "no-page-break-before") name= "no-page-break*";
01685     else if (name == "no-page-break-after") name= "no-page-break";
01686     else if (name == "new-page-before") name= "new-page*";
01687     else if (name == "new-double-page-before") name= "new-dpage*";
01688     else if (name == "new-double-page") name= "new-dpage";
01689     return tree (as_tree_label (name));
01690   }
01691   else {
01692     int i, n= N(t);
01693     tree r (t, n);
01694     for (i=0; i<n; i++)
01695       r[i]= upgrade_formatting (t[i]);
01696     return r;
01697   }
01698 }
01699 
01700 /******************************************************************************
01701 * Upgrade expand
01702 ******************************************************************************/
01703 
01704 static tree
01705 upgrade_expand (tree t, tree_label WHICH_EXPAND) {
01706   if (is_atomic (t)) return t;
01707   else if (is_func (t, WHICH_EXPAND) && is_atomic (t[0])) {
01708     int i, n= N(t)-1;
01709     string s= t[0]->label;
01710     if (s == "quote") s= s * "-env";
01711     tree_label l= make_tree_label (s);
01712     tree r (l, n);
01713     for (i=0; i<n; i++)
01714       r[i]= upgrade_expand (t[i+1], WHICH_EXPAND);
01715     return r;
01716   }
01717   else if (is_func (t, ASSIGN, 2) &&
01718           (t[0] == "quote") &&
01719           is_func (t[1], MACRO)) {
01720     tree arg= upgrade_expand (t[1], WHICH_EXPAND);
01721     return tree (ASSIGN, t[0]->label * "-env", arg);
01722   }
01723   else {
01724     int i, n= N(t);
01725     tree r (t, n);
01726     for (i=0; i<n; i++)
01727       r[i]= upgrade_expand (t[i], WHICH_EXPAND);
01728     return r;
01729   }
01730 }
01731 
01732 static tree
01733 upgrade_xexpand (tree t) {
01734   if (is_atomic (t)) return t;
01735   else {
01736     int i, n= N(t);
01737     tree r (t, n);
01738     if (is_expand (t))
01739       r= tree (COMPOUND, n);
01740     for (i=0; i<n; i++)
01741       r[i]= upgrade_xexpand (t[i]);
01742     return r;
01743   }
01744 }
01745 
01746 /******************************************************************************
01747 * Upgrade apply
01748 ******************************************************************************/
01749 
01750 static tree
01751 upgrade_apply (tree t) {
01752   if (is_atomic (t)) return t;
01753   /*
01754   if (is_func (t, APPLY))
01755     cout << t[0] << "\n";
01756   */
01757   if (is_func (t, APPLY) && is_atomic (t[0])) {
01758     int i, n= N(t)-1;
01759     string s= t[0]->label;
01760     tree_label l= make_tree_label (s);
01761     tree r (l, n);
01762     for (i=0; i<n; i++)
01763       r[i]= upgrade_apply (t[i+1]);
01764     return r;
01765   }
01766 
01767   int i, n= N(t);
01768   tree r (t, n);
01769   if (is_func (t, APPLY))
01770     r= tree (COMPOUND, n);
01771   for (i=0; i<n; i++)
01772     r[i]= upgrade_apply (t[i]);
01773   return r;
01774 }
01775 
01776 static tree
01777 upgrade_function_arg (tree t, tree var) {
01778   if (is_atomic (t)) return t;
01779   else if ((t == tree (APPLY, var)) || (t == tree (VALUE, var)))
01780     return tree (ARG, var);
01781   else {
01782     int i, n= N(t);
01783     tree r (t, n);
01784     for (i=0; i<n; i++)
01785       r[i]= upgrade_function_arg (t[i], var);
01786     return r;
01787   }
01788 }
01789 
01790 static tree
01791 upgrade_function (tree t) {
01792   if (is_atomic (t)) return t;
01793   if (is_func (t, ASSIGN, 2) && is_func (t[1], FUNC)) {
01794     int i, n= N(t[1])-1;
01795     for (i=0; i<n; i++)
01796       if (ends (as_string (t[1][i]), "*"))
01797        cout << "TeXmacs] Deprecated argument list '" << t[1][i]
01798             << "' in function '" << t[0] << "'\n"
01799             << "TeXmacs] You should use the 'xmacro' primitive now\n";
01800   }
01801   /*
01802   if (is_func (t, ASSIGN, 2) && is_func (t[1], FUNC) && (N(t[1])>1)) {
01803     cout << "Function: " << t[0] << "\n";
01804   }
01805   */
01806   if (is_func (t, FUNC)) {
01807     int i, n= N(t)-1;
01808     tree u= t[n], r (MACRO, n+1);
01809     for (i=0; i<n; i++) {
01810       u= upgrade_function_arg (u, t[i]);
01811       r[i]= copy (t[i]);
01812     }
01813     r[n]= upgrade_function (u);
01814     /*
01815     if (n > 0) {
01816       cout << "t= " << t << "\n";
01817       cout << "r= " << r << "\n";
01818       cout << HRULE;
01819     }
01820     */
01821     return r;
01822   }
01823   else {
01824     int i, n= N(t);
01825     tree r (t, n);
01826     for (i=0; i<n; i++)
01827       r[i]= upgrade_function (t[i]);
01828     return r;
01829   }
01830 }
01831 
01832 /******************************************************************************
01833 * Renaming environment variables
01834 ******************************************************************************/
01835 
01836 static charp var_rename []= {
01837   "shrinking factor", "sfactor",
01838   "info flag", "info-flag",
01839 
01840   "font family", "font-family",
01841   "font series", "font-series",
01842   "font shape", "font-shape",
01843   "font size", "font-size",
01844   "font base size", "font-base-size",
01845   "background color", "bg-color",
01846   "atom decorations", "atom-decorations",
01847   "line decorations", "line-decorations",
01848   "page decorations", "page-decorations",
01849   "xoff decorations", "xoff-decorations",
01850   "yoff decorations", "yoff-decorations",
01851 
01852   "math language", "math-language",
01853   "math font", "math-font",
01854   "math font family", "math-font-family",
01855   "math font series", "math-font-series",
01856   "math font shape", "math-font-shape",
01857   "index level", "math-level",
01858   "formula style", "math-display",
01859   "math condensed", "math-condensed",
01860   "vertical position", "math-vpos",
01861 
01862   "prog language", "prog-language",
01863   "prog font", "prog-font",
01864   "prog font family", "prog-font-family",
01865   "prog font series", "prog-font-series",
01866   "prog font shape", "prog-font-shape",
01867   "this session", "prog-session",
01868 
01869   "paragraph mode", "par-mode",
01870   "paragraph hyphenation", "par-hyphen",
01871   "paragraph width", "par-width",
01872   "left margin", "par-left",
01873   "right margin", "par-right",
01874   "first indentation", "par-first",
01875   "no first indentation", "par-no-first",
01876   "interline space", "par-sep",
01877   "horizontal ink separation", "par-hor-sep",
01878   "line stretch", "par-line-sep",
01879   "interparagraph space", "par-par-sep",
01880   "interfootnote space", "par-fnote-sep",
01881   "nr columns", "par-columns",
01882   "column separation", "par-columns-sep",
01883 
01884   "page medium", "page-medium",
01885   "page type", "page-type",
01886   "page orientation", "page-orientation",
01887   "page breaking", "page-breaking",
01888   "page flexibility", "page-flexibility",
01889   "page number", "page-nr",
01890   "thepage", "page-the-page",
01891   "page width", "page-width",
01892   "page height", "page-height",
01893   "odd page margin", "page-odd",
01894   "even page margin", "page-even",
01895   "page right margin", "page-right",
01896   "page top margin", "page-top",
01897   "page bottom margin", "page-bot",
01898   "page extend", "page-extend",
01899   "page shrink", "page-shrink",
01900   "page header separation", "page-head-sep",
01901   "page footer separation", "page-foot-sep",
01902   "odd page header", "page-odd-header",
01903   "odd page footer", "page-odd-footer",
01904   "even page header", "page-even-header",
01905   "even page footer", "page-even-footer",
01906   "this page header", "page-this-header",
01907   "this page footer", "page-this-footer",
01908   "reduction page left margin", "page-reduce-left",
01909   "reduction page right margin", "page-reduce-right",
01910   "reduction page top margin", "page-reduce-top",
01911   "reduction page bottom margin", "page-reduce-bot",
01912   "show header and footer", "page-show-hf",
01913   "footnote separation", "page-fnote-sep",
01914   "footnote bar length", "page-fnote-barlen",
01915   "float separation", "page-float-sep",
01916   "marginal note separation", "page-mnote-sep",
01917   "marginal note width", "page-mnote-width",
01918 
01919   "table width", "table-width",
01920   "table height", "table-height",
01921   "table hmode", "table-hmode",
01922   "table vmode", "table-vmode",
01923   "table halign", "table-halign",
01924   "table valign", "table-valign",
01925   "table row origin", "table-row-origin",
01926   "table col origin", "table-col-origin",
01927   "table lsep", "table-lsep",
01928   "table rsep", "table-rsep",
01929   "table bsep", "table-bsep",
01930   "table tsep", "table-tsep",
01931   "table lborder", "table-lborder",
01932   "table rborder", "table-rborder",
01933   "table bborder", "table-bborder",
01934   "table tborder", "table-tborder",
01935   "table hyphen", "table-hyphen",
01936   "table min rows", "table-min-rows",
01937   "table min cols", "table-min-cols",
01938   "table max rows", "table-max-rows",
01939   "table max cols", "table-max-cols",
01940 
01941   "cell format", "cell-format",
01942   "cell decoration", "cell-decoration",
01943   "cell background", "cell-background",
01944   "cell orientation", "cell-orientation",
01945   "cell width", "cell-width",
01946   "cell height", "cell-height",
01947   "cell hpart", "cell-hpart",
01948   "cell vpart", "cell-vpart",
01949   "cell hmode", "cell-hmode",
01950   "cell vmode", "cell-vmode",
01951   "cell halign", "cell-halign",
01952   "cell valign", "cell-valign",
01953   "cell lsep", "cell-lsep",
01954   "cell rsep", "cell-rsep",
01955   "cell bsep", "cell-bsep",
01956   "cell tsep", "cell-tsep",
01957   "cell lborder", "cell-lborder",
01958   "cell rborder", "cell-rborder",
01959   "cell bborder", "cell-bborder",
01960   "cell tborder", "cell-tborder",
01961   "cell vcorrect", "cell-vcorrect",
01962   "cell hyphen", "cell-hyphen",
01963   "cell row span", "cell-row-span",
01964   "cell col span", "cell-col-span",
01965   "cell row nr", "cell-row-nr",
01966   "cell col nr", "cell-col-nr",
01967 
01968   "line width", "line-width",
01969   "line style", "line-style",
01970   "line arrows", "line-arrows",
01971   "line caps", "line-join",
01972   "fill mode", "fill-mode",
01973   "fill color", "fill-color",
01974   "fill style", "fill-style",
01975 
01976   "graphical frame", "gr-frame",
01977   "graphical clip", "gr-clip",
01978   "graphical mode", "gr-mode",
01979   "graphical color", "gr-color",
01980   "graphical line width", "gr-line-width",
01981   
01982   ""
01983 };
01984 
01985 static hashmap<string,string> var_rename_table ("?");
01986 
01987 static hashmap<string,string>
01988 cached_renamer (charp* T, hashmap<string,string>& H) {
01989   if (N (H) == 0) {
01990     int i;
01991     for (i=0; T[i][0] != '\0'; i+=2)
01992       H (T[i])= T[i+1];
01993   }
01994   return H;
01995 }
01996 
01997 
01998 static tree
01999 rename_vars (tree t, hashmap<string,string> H, bool flag) {
02000   if (is_atomic (t)) return t;
02001   else {
02002     int i, n= N(t);
02003     tree r (t, n);
02004     static tree_label MARKUP= make_tree_label ("markup");
02005     for (i=0; i<n; i++) {
02006       tree u= rename_vars (t[i], H, flag);
02007       if (is_atomic (u) && H->contains (u->label))
02008        if (((L(t) == WITH) && ((i%2) == 0) && (i < n-1)) ||
02009            ((L(t) == ASSIGN) && (i == 0)) ||
02010            ((L(t) == VALUE) && (i == 0)) ||
02011            ((L(t) == CWITH) && (i == 4)) ||
02012            ((L(t) == TWITH) && (i == 0)) ||
02013            ((L(t) == ASSOCIATE) && (i == 0)) ||
02014            ((L(t) == MARKUP) && (i == 0)))
02015          u= copy (H[u->label]);
02016       r[i]= u;
02017     }
02018     if (flag) {
02019       if (H->contains (as_string (L(t)))) {
02020        tree_label l= make_tree_label (H[as_string (L(t))]);
02021        r= tree (l, A(r));
02022       }
02023     }
02024     else {
02025       if ((n == 0) && H->contains (as_string (L(t)))) {
02026        string v= H[as_string (L(t))];
02027        r= tree (VALUE, copy (v));
02028        if (v == "page-the-page") r= tree (make_tree_label ("page-the-page"));
02029       }
02030     }
02031     return r;
02032   }
02033 }
02034 
02035 tree
02036 upgrade_env_vars (tree t) {
02037   return rename_vars (t, cached_renamer (var_rename, var_rename_table), false);
02038 }
02039 
02040 /******************************************************************************
02041 * Use package primitive for style files
02042 ******************************************************************************/
02043 
02044 static tree
02045 upgrade_use_package (tree t) {
02046   tree style= extract (t, "style");
02047   tree init = extract (t, "initial");
02048   bool preamble= false;
02049   int i, n= N(init);
02050   for (i=0; i<n; i++)
02051     if (init[i] == tree (ASSOCIATE, PREAMBLE, "true"))
02052       preamble= true;
02053 
02054   bool no_style= true;
02055   if (preamble) {
02056     n= N(t);
02057     tree r (L(t));
02058     for (i=0; i<n; i++)
02059       if (is_compound (t[i], "style")) {
02060        r << compound ("style", "source");
02061        no_style= false;
02062       }
02063       else if (is_compound (t[i], "body", 1) && is_document (t[i][0])) {
02064        tree v (USE_PACKAGE);
02065        v << A (style);
02066        tree u (DOCUMENT);
02067        if (N(v) > 0) u << v;
02068        u << A (t[i][0]);
02069        if (no_style) r << compound ("style", "source");
02070        r << compound ("body", u);
02071       }
02072       else r << t[i];
02073     return r;
02074   }
02075   else return t;
02076 }
02077 
02078 /******************************************************************************
02079 * Normalize names of tags in the style files
02080 ******************************************************************************/
02081 
02082 static charp style_rename []= {
02083   "thelabel", "the-label",
02084 
02085   "leftflush", "left-flush",
02086   "rightflush", "right-flush",
02087   "mathord", "math-ord",
02088   "mathopen", "math-open",
02089   "mathclose", "math-close",
02090   "mathpunct", "math-punct",
02091   "mathbin", "math-bin",
02092   "mathrel", "math-rel",
02093   "mathop", "math-op",
02094   "thetoc", "the-toc",
02095   "theidx", "the-idx",
02096   "thegly", "the-gly",
02097   "theitem", "the-item",
02098   "tocnr", "toc-nr",
02099   "idxnr", "idx-nr",
02100   "glynr", "gly-nr",
02101   "itemnr", "item-nr",
02102   "itemname", "item-name",
02103   "newitemize", "new-itemize",
02104   "newenumerate", "new-enumerate",
02105   "newdescription", "new-description",
02106 
02107   "nextnumber", "next-number",
02108   "eqnumber", "eq-number",
02109   "leqnumber", "leq-number",
02110   "reqnumber", "req-number",
02111   "nonumber", "no-number",
02112   "thefootnote", "the-footnote",
02113   "theequation", "the-equation",
02114   "thetheorem", "the-theorem",
02115   "theproposition", "the-proposition",
02116   "thelemma", "the-lemma",
02117   "thecorollary", "the-corollary",
02118   "theaxiom", "the-axiom",
02119   "thedefinition", "the-definition",
02120   "thenotation", "the-notation",
02121   "theconjecture", "the-conjecture",
02122   "theremark", "the-remark",
02123   "theexample", "the-example",
02124   "thenote", "the-note",
02125   "thewarning", "the-warning",
02126   "theconvention", "the-convention",
02127   "theacknowledgments", "the-acknowledgments",
02128   "theexercise", "the-exercise",
02129   "theproblem", "the-problem",
02130   "thefigure", "the-figure",
02131   "thetable", "the-table",
02132   "footnotenr", "footnote-nr",
02133   "equationnr", "equation-nr",
02134   "theoremnr", "theorem-nr",
02135   "propositionnr", "proposition-nr",
02136   "lemmanr", "lemma-nr",
02137   "corollarynr", "corollary-nr",
02138   "axiomnr", "axiom-nr",
02139   "definitionnr", "definition-nr",
02140   "notationnr", "notation-nr",
02141   "conjecturenr", "conjecture-nr",
02142   "remarknr", "remark-nr",
02143   "examplenr", "example-nr",
02144   "notenr", "note-nr",
02145   "warningnr", "warning-nr",
02146   "conventionnr", "convention-nr",
02147   "acknowledgmentsnr", "acknowledgments-nr",
02148   "exercisenr", "exercise-nr",
02149   "problemnr", "problem-nr",
02150   "figurenr", "figure-nr",
02151   "tablenr", "table-nr",
02152   "theoremname", "theorem-name",
02153   "figurename", "figure-name",
02154   "exercisename", "exercise-name",
02155   "theoremsep", "theorem-sep",
02156   "figuresep", "figure-sep",
02157   "exercisesep", "exercise-sep",
02158   "footnotesep", "footnote-sep",
02159   "newtheorem", "new-theorem",
02160   "newremark", "new-remark",
02161   "newexercise", "new-exercise",
02162   "newfigure", "new-figure",
02163 
02164   "theprefix", "the-prefix",
02165   "thechapter", "the-chapter",
02166   "theappendix", "the-appendix",
02167   "thesection", "the-section",
02168   "thesubsection", "the-subsection",
02169   "thesubsubsection", "the-subsubsection",
02170   "theparagraph", "the-paragraph",
02171   "thesubparagraph", "the-subparagraph",
02172   "chapternr", "chapter-nr",
02173   "appendixnr", "appendix-nr",
02174   "sectionnr", "section-nr",
02175   "subsectionnr", "subsection-nr",
02176   "subsubsectionnr", "subsubsection-nr",
02177   "paragraphnr", "paragraph-nr",
02178   "subparagraphnr", "subparagraph-nr",
02179   "sectionsep", "section-sep",
02180   "subsectionsep", "subsection-sep",
02181   "subsubsectionsep", "subsubsection-sep",
02182 
02183   "theorem*", "render-theorem",
02184   "remark*", "render-remark",
02185   "exercise*", "render-exercise",
02186   "proof*", "render-proof",
02187   "small-figure*", "render-small-figure",
02188   "big-figure*", "render-big-figure",
02189 
02190   "theanswer", "the-answer",
02191   "thealgorithm", "the-algorithm",
02192   "answernr", "answer-nr",
02193   "algorithmnr", "algorithm-nr",
02194 
02195   ""
02196 };
02197 
02198 static hashmap<string,string> style_rename_table ("?");
02199 
02200 static tree
02201 upgrade_style_rename_sub (tree t) {
02202   if (is_atomic (t)) return t;
02203   else if (is_func (t, MERGE, 2) && (t[0] == "the"))
02204     return tree (MERGE, "the-", t[1]);
02205   else if (is_func (t, MERGE, 2) && (t[1] == "nr"))
02206     return tree (MERGE, t[0], "-nr");
02207   else {
02208     int i, n= N(t);
02209     tree r (t, n);
02210     for (i=0; i<n; i++)
02211       r[i]= upgrade_style_rename_sub (t[i]);
02212     return r;
02213   }
02214 }
02215 
02216 static tree
02217 upgrade_style_rename (tree t) {
02218   t= upgrade_style_rename_sub (t);
02219   return
02220     rename_vars (t, cached_renamer (style_rename, style_rename_table), true);
02221 }
02222 
02223 /******************************************************************************
02224 * Remove trailing punctuation in item* tags
02225 ******************************************************************************/
02226 
02227 static tree
02228 upgrade_item_punct (tree t) {
02229   if (is_atomic (t)) return t;
02230   else {
02231     int i, n= N(t);
02232     tree r (t, n);
02233     for (i=0; i<n; i++)
02234       r[i]= upgrade_item_punct (t[i]);
02235     if (is_compound (r, "item*", 1)) {
02236       tree& item= r[0];
02237       if (is_atomic (item)) {
02238        string s= item->label;
02239        if (ends (s, ".") || ends (s, ":") || ends (s, " "))
02240          item= s (0, N(s)-1);
02241       }
02242       else if (is_concat (item) && is_atomic (item[N(item)-1])) {
02243        string s= item [N(item)-1] -> label;
02244        if ((s == ".") || (s == ":") || (s == " ")) {
02245          if (N(item) == 2) item= item[0];
02246          else item= item (0, N(item) - 1);
02247        }
02248       }
02249     }
02250     return r;
02251   }
02252 }
02253 
02254 /******************************************************************************
02255 * Forget default page parameters
02256 ******************************************************************************/
02257 
02258 tree
02259 upgrade_page_pars (tree t) {
02260   if (is_atomic (t)) return t;
02261   else if (L(t) == COLLECTION) {
02262     int i, n= N(t);
02263     tree r (COLLECTION);
02264     for (i=0; i<n; i++) {
02265       tree u= t[i];
02266       if (!is_func (u, ASSOCIATE, 2));
02267       else if (u == tree (ASSOCIATE, PAGE_TYPE, "a4"));
02268       else if (u == tree (ASSOCIATE, PAGE_EVEN, "30mm"));
02269       else if (u == tree (ASSOCIATE, PAGE_ODD, "30mm"));
02270       else if (u == tree (ASSOCIATE, PAGE_RIGHT, "30mm"));
02271       else if (u == tree (ASSOCIATE, PAGE_TOP, "30mm"));
02272       else if (u == tree (ASSOCIATE, PAGE_BOT, "30mm"));
02273       else if (u == tree (ASSOCIATE, PAR_WIDTH, "150mm"));
02274       else if (u[0] == "page-reduce-left");
02275       else if (u[0] == "page-reduce-right");
02276       else if (u[0] == "page-reduce-top");
02277       else if (u[0] == "page-reduce-bot");
02278       else if (u[0] == "sfactor");
02279       else r << u;
02280     }
02281     return r;
02282   }
02283   else {
02284     int i, n= N(t);
02285     tree r (t, n);
02286     for (i=0; i<n; i++)
02287       r[i]= upgrade_page_pars (t[i]);
02288     return r;
02289   }
02290 }
02291 
02292 /******************************************************************************
02293 * Substitutions
02294 ******************************************************************************/
02295 
02296 tree
02297 substitute (tree t, tree which, tree by) {
02298   if (t == which) return by;
02299   else if (is_atomic (t)) return t;
02300   else {
02301     int i, n= N(t);
02302     tree r (t, n);
02303     for (i=0; i<n; i++)
02304       r[i]= substitute (t[i], which, by);
02305     return r;
02306   }
02307 }
02308 
02309 /******************************************************************************
02310 * Upgrading title information
02311 ******************************************************************************/
02312 
02313 static tree doc_keywords;
02314 static tree doc_ams_class;
02315 
02316 static void
02317 abstract_add (tree& data, tree what) {
02318   if (is_func (what, DOCUMENT, 1)) what= what[0];
02319   if (is_atomic (what)) {
02320     string s= what->label;
02321     int i, start, n= N(s);
02322     for (i=start=0; i<n; )
02323       if (s[i] == ',') {
02324        int next= i+1;
02325        while ((i>start) && (s[i-1]==' ')) i--;
02326        data << s (start, i);
02327        i= next; if (s[i] == ' ') i++;
02328        start= i;
02329       }
02330       else i++;
02331     while ((i>start) && (s[i-1]==' ')) i--;
02332     data << s (start, i);
02333   }
02334   else data << what;
02335 }
02336 
02337 static tree
02338 upgrade_abstract (tree t) {
02339   if (is_atomic (t)) return t;
02340   else if (is_compound (t, "abstract", 1) && is_document (t[0])) {
02341     int i, n= N(t[0]);
02342     tree r (DOCUMENT);
02343     for (i=0; i<n; i++)
02344       if (is_compound (t[0][i], "keywords", 1))
02345        abstract_add (doc_keywords, t[0][i][0]);
02346       else if (is_compound (t[0][i], "AMS-class"))
02347        abstract_add (doc_ams_class, t[0][i][0]);
02348       else r << t[0][i];
02349     if (N(r) == 0) r << "";
02350     return compound ("abstract", r);
02351   }
02352   else {
02353     int i, n= N(t);
02354     tree r (t, n);
02355     for (i=0; i<n; i++)
02356       r[i]= upgrade_abstract (t[i]);
02357     return r;
02358   }
02359 }
02360 
02361 static tree
02362 search_title_tag (tree t, string tag, bool flag= false) {
02363   if (is_atomic (t)) return tuple ();
02364   else if (is_compound (t, tag, 1)) return tuple (t[0]);
02365   else if (flag && is_compound (t, tag)) return tuple (t);
02366   else {
02367     int i, n= N(t);
02368     tree r (TUPLE);
02369     for (i=0; i<n; i++)
02370       r << A (search_title_tag (t[i], tag, flag));
02371     return r;
02372   }
02373 }
02374 
02375 static void
02376 search_abstract_tag (tree t, tree& data, string tag) {
02377   if (is_atomic (t)) return;
02378   else {
02379     int i, n= N(t);
02380     for (i=0; i<n; i++)
02381       if (is_compound (t[i], tag, 1))
02382         abstract_add (data, t[i][0]);
02383   }
02384 }
02385 
02386 static void
02387 title_add (tree& data, string tag, tree args, bool flag= false) {
02388   int i, n= N(args);
02389   for (i=0; i<n; i++) {
02390     tree t= args[i];
02391     if (flag && (!is_document (t))) t= tree (DOCUMENT, t);
02392     if ((!flag) && is_func (t, DOCUMENT, 1)) t= t[0];
02393     data << compound (tag, t);
02394   }
02395 }
02396 
02397 static void
02398 add_info (tree& data, tree t, string ntag, string otag,
02399           bool flag1= false, bool flag2= false) {
02400   tree u= search_title_tag (t, otag, flag1);
02401   if (N(t) != 0) title_add (data, ntag, u, flag2);
02402 }
02403 
02404 static tree
02405 upgrade_title2 (tree t) {
02406   if (is_atomic (t)) return t;
02407   else if (is_compound (t, "make-title", 1)) {
02408     //cout << "t= " << t << "\n";
02409     tree u= t[0];
02410     if (!is_document (u) && !is_concat (u)) u= tree (DOCUMENT, u);
02411     tree title_data = compound ("doc-data");
02412     tree author_data= compound ("doc-author-data");
02413     tree meta_data  = compound ("doc-data");
02414 
02415     for (int i=0; i<N(u); i++) {
02416       tree v= u[i];
02417       add_info (title_data, v, "doc-title", "title");
02418       add_info (meta_data, v, "doc-date", "title-date");
02419       add_info (meta_data, v, "doc-running-title", "header-title");
02420       add_info (meta_data, v, "doc-running-author", "header-author");
02421       add_info (meta_data, v, "doc-note", "title-thanks", true, true);
02422       if (N (search_title_tag (v, "author")) != 0) {
02423         if (N (author_data) != 0 &&
02424             is_compound (author_data[0], "author-name"))
02425           title_data << author_data;
02426         author_data= compound ("doc-author-data");
02427       }
02428       add_info (author_data, v, "author-name", "author");
02429       add_info (author_data, v, "author-address", "address", false, true);
02430       add_info (author_data, v, "author-email", "title-email");
02431       add_info (author_data, v, "author-homepage", "title-web");
02432     }
02433     if (N (author_data) != 0) title_data << author_data;
02434     if (N (meta_data) != 0) title_data << A (meta_data);
02435 
02436     tree notice= search_title_tag (t, "made-by-TeXmacs", true);
02437     if (N (notice) != 0)
02438       title_data << compound ("doc-note", compound ("with-TeXmacs-text"));    
02439     search_abstract_tag (t[0], doc_keywords, "title-keywords");
02440     search_abstract_tag (t[0], doc_ams_class, "title-ams-class");
02441     if (N (doc_keywords) != 0) title_data << doc_keywords;
02442     if (N (doc_ams_class) != 0) title_data << doc_ams_class;
02443     //cout << "r= " << title_data << "\n";
02444     return title_data;
02445   }
02446   else {
02447     int i, n= N(t);
02448     tree r (t, n);
02449     for (i=0; i<n; i++)
02450       r[i]= upgrade_title2 (t[i]);
02451     return r;
02452   }
02453 }
02454 
02455 static tree
02456 upgrade_doc_info (tree t) {
02457   doc_keywords = compound ("doc-keywords");
02458   doc_ams_class= compound ("doc-AMS-class");
02459   t= upgrade_abstract (t);
02460   t= upgrade_title2 (t);
02461   return t;
02462 }
02463 
02464 /******************************************************************************
02465 * Upgrade bibliographies
02466 ******************************************************************************/
02467 
02468 tree
02469 upgrade_bibliography (tree t) {
02470   if (is_atomic (t)) return t;
02471   else {
02472     int i, n= N(t);
02473     tree r (t, n);
02474     for (i=0; i<n; i++)
02475       r[i]= upgrade_bibliography (t[i]);
02476     if (is_compound (t, "bibliography") || is_compound (t, "bibliography*")) {
02477       int l= N(r)-1;
02478       if (is_func (r[l], DOCUMENT, 1) && is_compound (r[l][0], "bib-list"));
02479       else if (is_compound (r[l], "bib-list"));
02480       else r[l]= tree (DOCUMENT, compound ("bib-list", "[99]", r[l]));
02481     }
02482     return r;
02483   }
02484 }
02485 
02486 /******************************************************************************
02487 * Upgrade switches
02488 ******************************************************************************/
02489 
02490 tree
02491 upgrade_switch (tree t) {
02492   if (is_atomic (t)) return t;
02493   else {
02494     int i, n= N(t);
02495     tree r (t, n);
02496     for (i=0; i<n; i++)
02497       r[i]= upgrade_switch (t[i]);
02498     if (is_compound (r, "switch", 2)) {
02499       int i, n= N(r[1]);
02500       tree u (make_tree_label ("switch"), n);
02501       for (i=0; i<n; i++)
02502        if (is_compound (r[1][i], "tmarker", 0)) u[i]= r[0];
02503        else u[i]= compound ("hidden", r[1][i]);
02504       return u;
02505     }
02506     if (is_compound (r, "fold", 2))
02507       return compound ("folded", r[0], r[1]);
02508     if (is_compound (r, "unfold", 2))
02509       return compound ("unfolded", r[0], r[1]);
02510     if (is_compound (r, "fold-bpr", 2) ||
02511        is_compound (r, "fold-text", 2) ||
02512        is_compound (r, "fold-proof", 2) ||
02513        is_compound (r, "fold-exercise", 2))
02514       return compound ("summarized", r[0], r[1]);
02515     if (is_compound (r, "unfold-bpr", 2) ||
02516        is_compound (r, "unfold-text", 2) ||
02517        is_compound (r, "unfold-proof", 2) ||
02518        is_compound (r, "unfold-exercise", 2))
02519       return compound ("detailed", r[0], r[1]);
02520     if (is_compound (r, "fold-algorithm", 2))
02521       return compound ("summarized-algorithm", r[0], r[1]);
02522     if (is_compound (r, "unfold-algorithm", 2))
02523       return compound ("detailed-algorithm", r[0], r[1]);
02524     if (is_func (r, ASSIGN, 2) && r[0] == "fold-algorithm")
02525       return tree (ASSIGN, "summarized-algorithm", r[1]);
02526     if (is_func (r, ASSIGN, 2) && r[0] == "unfold-algorithm")
02527       return tree (ASSIGN, "detailed-algorithm", r[1]);
02528     return r;
02529   }
02530 }
02531 
02532 /******************************************************************************
02533 * Upgrade graphics
02534 ******************************************************************************/
02535 
02536 static int
02537 find_attr_pos (tree t, string name) {
02538   int i, n= N(t);
02539   for (i=0; i<n; i+=2)
02540     if (t[i] == name && i%2 == 0 && i+1<n) return i;
02541   return -1;
02542 }
02543 
02544 static bool
02545 find_attr (tree t, string name) {
02546   return find_attr_pos (t, name) != -1;
02547 }
02548 
02549 static tree
02550 get_attr (tree t, string name, tree ifnotfound) {
02551   int i= find_attr_pos (t, name);
02552   return i == -1 ? ifnotfound : t[i+1];
02553 }
02554 
02555 static tree
02556 add_attr (tree t, string name, tree value) {
02557   int i, n= N(t);
02558   tree r (t, n+2);
02559   for (i=0; i<n-1; i++)
02560     r[i]= t[i];
02561   r[n-1]= name;
02562   r[n]= value;
02563   r[n+1]= t[n-1];
02564   return r;
02565 }
02566 
02567 static tree
02568 set_attr (tree t, string name, tree value) {
02569   int i= find_attr_pos (t, name);
02570   if (i != -1)
02571     t[i+1]= value;
02572   else
02573     t= add_attr (t, name, value);
02574   return t;
02575 }
02576 
02577 static tree
02578 remove_attr (tree t, string name) {
02579   int i= find_attr_pos (t, name);
02580   if (i == -1)
02581     return t;
02582   else {
02583     int j, n= N(t);
02584     tree r (t, n-2);
02585     for (j=0; j<i; j++)
02586       r[j]= t[j];
02587     for (j=i+2; j<n; j++)
02588       r[j-2]= t[j];
02589     return r;
02590   }
02591 }
02592 
02593 tree
02594 upgrade_fill (tree t) {
02595   int i;
02596   if (is_atomic (t)) return t;
02597   if (is_compound (t, "with")) {
02598     if ((i= find_attr_pos (t, "gr-mode")) != -1
02599      && is_tuple (t[i+1],"edit-prop"))
02600       t[i+1]= tuple ("group-edit","props");
02601 
02602     tree fm= get_attr (t, "fill-mode", tree ("none"));
02603     t= remove_attr (t, "fill-mode");
02604     t= remove_attr (t, "gr-fill-mode");
02605     if (fm == "none")
02606       t= remove_attr (t, "fill-color");
02607     if (fm == "inside")
02608       t= set_attr (t, "color", tree ("none"));
02609   }
02610   int n= N(t);
02611   tree r (t, n);
02612   for (i=0; i<n; i++)
02613     r[i]= upgrade_fill (t[i]);
02614   return r;
02615 }
02616 
02617 static void
02618 length_split (string &num, string &unit, string l) {
02619   int i, n= N(l), nu= 0;
02620   i= n-1;
02621   while (i>=0 && is_alpha (l[i])) i--, nu++;
02622   num= l (0, n-nu);
02623   unit= l (n-nu, n);
02624 }
02625 
02626 static string
02627 length_minus (string l) {
02628   if (l[0] == '+') l[0]= '-';
02629   else
02630   if (l[0] == '-') l[0]= '+';
02631   else
02632     l= "-" * l;
02633   return l;
02634 }
02635 
02636 static string
02637 length_abs (string l) {
02638   if (l[0] == '-') l[0]= '+';
02639   return l;
02640 }
02641 
02642 static int length_add_error;
02643 
02644 static string
02645 length_add (string l1, string l2) {
02646   length_add_error= 0;
02647   string n1, u1, n2, u2;
02648   length_split (n1, u1, l1);
02649   length_split (n2, u2, l2);
02650   double i1= as_double (n1);
02651   double i2= as_double (n2);
02652   if (i1 == 0.0) {
02653     i1= i2;
02654     i2= 0.0;
02655     string u= u1;
02656     u1= u2;
02657     u2= u;
02658   }
02659   if (u1 == "par" && (u2 == "par" || i2 == 0.0))
02660     return as_string (i1 + i2) * "par";
02661   else
02662   if ((u1 == "cm" || u1 == "mm")
02663    && (u2 == "cm" || u2 == "mm" || i2 == 0.0)) {
02664     if (u1 == "cm" && u2 == "mm") i2 /= 10;
02665     if (u1 == "mm" && u2 == "cm") i2 *= 10;
02666     return as_string (i1 + i2) * u1;
02667   }
02668   else {
02669     length_add_error= 1;
02670     return "0cm";
02671   }
02672 }
02673 
02674 tree
02675 upgrade_graphics (tree t) {
02676   int i;
02677   if (is_atomic (t)) return t;
02678   if (is_compound (t, "with") &&
02679       (find_attr (t, "gr-frame") || find_attr (t, "gr-clip"))) {
02680     tree fr= get_attr (t, "gr-frame",
02681                        tuple ("scale", "1cm",
02682                              tree (TUPLE, "0.5par", "0cm")));
02683     tree clip= get_attr (t, "gr-clip",
02684                          tuple ("clip",
02685                                tuple ("0par", "-0.3par"),
02686                                tuple ("1par", "0.3par")));
02687     t= remove_attr (t, "gr-clip");
02688 
02689     string ox= as_string (fr[2][0]), oy= as_string (fr[2][1]);
02690     string cg= as_string (clip[1][0]), cb= as_string (clip[1][1]);
02691     string cd= as_string (clip[2][0]), ch= as_string (clip[2][1]);
02692     string w= length_add (cd, length_minus (cg));
02693     string h= length_add (ch, length_minus (cb));
02694 
02695     fr[2][0]= tree (length_add (length_abs (cg) , ox));
02696     if (length_add_error)
02697       fr[2][0]= tree (PLUS, length_abs (cg) , ox);
02698     fr[2][1]= tree (length_add (length_abs (cb) , oy));
02699     if (length_add_error)
02700       fr[2][1]= tree (PLUS, length_abs (cb) , oy);
02701     tree geom= tuple ("geometry", tree (w), tree (h));
02702     t= add_attr (t, "gr-geometry", geom);
02703     t= set_attr (t, "gr-frame", fr);
02704   }
02705   int n= N(t);
02706   tree r (t, n);
02707   for (i=0; i<n; i++)
02708     r[i]= upgrade_graphics (t[i]);
02709   return r;
02710 }
02711 
02712 tree
02713 upgrade_textat (tree t) {
02714   int i;
02715   if (is_atomic (t)) return t;
02716   if (is_compound (t, "text-at") && N(t) == 4) {
02717     tree t0= t;
02718     t= tree (WITH, tree (TEXT_AT, t[0], t[1]));
02719     t= set_attr (t, "text-at-halign", t0[2]);
02720     t= set_attr (t, "text-at-valign", t0[3]);
02721   }
02722   int n= N(t);
02723   tree r (t, n);
02724   for (i=0; i<n; i++)
02725     r[i]= upgrade_textat (t[i]);
02726   return r;
02727 }
02728 
02729 /******************************************************************************
02730 * Upgrade cell alignment
02731 ******************************************************************************/
02732 
02733 tree
02734 upgrade_cell_alignment (tree t) {
02735   int i;
02736   if (is_atomic (t)) return t;
02737   if (is_func (t, CWITH) && (N(t) >= 2))
02738     if (t[N(t)-2] == CELL_HALIGN)
02739       if (t[N(t)-1] == "." || t[N(t)-1] == ",") {
02740        tree r= copy (t);
02741        r[N(t)-1]= "L" * t[N(t)-1]->label;
02742        return r;
02743       }
02744   int n= N(t);
02745   tree r (t, n);
02746   for (i=0; i<n; i++)
02747     r[i]= upgrade_cell_alignment (t[i]);
02748   return r;
02749 }
02750 
02751 /******************************************************************************
02752 * Renaming primitives
02753 ******************************************************************************/
02754 
02755 tree
02756 rename_primitive (tree t, string which, string by) {
02757   int i;
02758   if (is_atomic (t)) return t;
02759   int n= N(t);
02760   tree r (t, n);
02761   if (is_compound (t, which))
02762     r= tree (make_tree_label (by), n);
02763   for (i=0; i<n; i++)
02764     r[i]= rename_primitive (t[i], which, by);
02765   return r;
02766 }
02767 
02768 /******************************************************************************
02769 * Upgrade label assignment
02770 ******************************************************************************/
02771 
02772 tree
02773 upgrade_label_assignment (tree t) {
02774   int i;
02775   if (is_atomic (t)) return t;
02776   else if (is_func (t, ASSIGN, 2) && t[0] == "the-label")
02777     return tree (SET_BINDING, t[1]);
02778   else {
02779     int n= N(t);
02780     tree r (t, n);
02781     for (i=0; i<n; i++)
02782       r[i]= upgrade_label_assignment (t[i]);
02783     return r;
02784   }
02785 }
02786 
02787 /******************************************************************************
02788 * Upgrade scheme documentation
02789 ******************************************************************************/
02790 
02791 tree
02792 upgrade_scheme_doc (tree t) {
02793   int i;
02794   if (is_atomic (t)) return t;
02795   else if (is_compound (t, "scm-fun", 1) ||
02796           is_compound (t, "scm-macro", 1))
02797     return compound ("scm", t[0]);
02798   else if (is_compound (t, "explain-scm-fun") ||
02799           is_compound (t, "explain-scm-macro"))
02800     {
02801       tree r (CONCAT);
02802       r << "(" << t[0];
02803       for (int i=1; i<N(t); i++)
02804        r << " " << t[i];
02805       r << ")";
02806       return compound ("scm", simplify_concat (r));
02807     }
02808   else {
02809     int n= N(t);
02810     tree r (t, n);
02811     for (i=0; i<n; i++)
02812       r[i]= upgrade_scheme_doc (t[i]);
02813     return r;
02814   }
02815 }
02816 
02817 /******************************************************************************
02818 * Upgrade Mathemagix tag
02819 ******************************************************************************/
02820 
02821 tree
02822 upgrade_mmx (tree t) {
02823   int i;
02824   if (is_atomic (t)) return t;
02825   else if (is_compound (t, "mmx", 0) || t == tree (VALUE, "mmx"))
02826     return compound ("mathemagix");
02827   else if (is_compound (t, "mml", 0) || t == tree (VALUE, "mml"))
02828     return compound ("mmxlib");
02829   else if (is_compound (t, "scheme", 0) || t == tree (VALUE, "scheme"))
02830     return compound ("scheme");
02831   else if (is_compound (t, "cpp", 0) || t == tree (VALUE, "cpp"))
02832     return compound ("c++");
02833   else if (is_compound (t, "scheme-code", 1))
02834     return compound ("scm", upgrade_mmx (t[0]));
02835   else if (is_compound (t, "scheme-fragment", 1))
02836     return compound ("scm-fragment", upgrade_mmx (t[0]));
02837   else if (is_compound (t, "cpp-code", 1))
02838     return compound ("cpp", upgrade_mmx (t[0]));
02839   else {
02840     int n= N(t);
02841     tree r (t, n);
02842     for (i=0; i<n; i++)
02843       r[i]= upgrade_mmx (t[i]);
02844     return r;
02845   }
02846 }
02847 
02848 /******************************************************************************
02849 * Upgrade sessions
02850 ******************************************************************************/
02851 
02852 static tree
02853 upgrade_session (tree t, tree lan, tree ses) {
02854   if (is_atomic (t)) return t;
02855   else if (is_compound (t, "session", 1))
02856     return compound ("session", copy (lan), copy (ses),
02857                    upgrade_session (t[0], lan, ses));
02858   else if (is_func (t, WITH, 5) &&
02859           t[0] == PROG_LANGUAGE &&
02860           t[2] == PROG_SESSION)
02861     return upgrade_session (t[4], t[1], t[3]);
02862   else {
02863     int i, n= N(t);
02864     tree r (L(t));
02865     for (i=0; i<n; i++) {
02866       if (is_document (t) && is_compound (t[i], "input", 2)) {
02867        bool m = is_compound (t[i][1], "math", 1);
02868        tree in= (m? t[i][1][0]: t[i][1]);
02869        if ((i+1)<n && is_compound (t[i+1], "output", 1)) {
02870          const char* op= (m? "unfolded-io-math": "unfolded-io");
02871          r << compound (op, t[i][0], in, t[i+1][0]);
02872          i++;
02873        }
02874        else {
02875          const char* op= (m? "input-math": "input");
02876          r << compound (op, t[i][0], in);
02877        }
02878       }
02879       else r << upgrade_session (t[i], lan, ses);
02880     }
02881     return r;
02882   }
02883 }
02884 
02885 /******************************************************************************
02886 * Upgrade presentation style
02887 ******************************************************************************/
02888 
02889 tree
02890 upgrade_presentation (tree t) {
02891   int i;
02892   if (is_atomic (t)) return t;
02893   else if (is_compound (t, "style") || is_compound (t, "tuple")) {
02894     int n= N(t);
02895     tree r (t, n);
02896     for (i=0; i<n; i++)
02897       if (t[i] == "presentation") r[i]= "presentation-ridged-paper";
02898       else r[i]= upgrade_presentation (t[i]);
02899     return r;
02900   }
02901   else {
02902     int n= N(t);
02903     tree r (t, n);
02904     for (i=0; i<n; i++)
02905       r[i]= upgrade_presentation (t[i]);
02906     return r;
02907   }
02908 }
02909 
02910 /******************************************************************************
02911 * Upgrade mathematical formulas
02912 ******************************************************************************/
02913 
02914 bool
02915 is_non_style_document (tree doc) {
02916   tree style= extract (doc, "style");
02917   if (!is_tuple (style) || N(style) == 0 || !is_atomic (style[0]))
02918     return false;
02919   for (int i=0; i<N(style); i++)
02920     if (style[i] == "source") return false;
02921   string ms= style[0]->label;
02922   return
02923     (starts (ms, "tm")) ||
02924     (starts (ms, "lycee")) ||
02925     (ms == "article") ||
02926     (ms == "beamer") ||
02927     (ms == "book") ||
02928     (ms == "exam") ||
02929     (ms == "generic") ||
02930     (ms == "letter") ||
02931     (ms == "seminar") ||
02932     (ms == "bibliography") ||
02933     (ms == "browser") ||
02934     (ms == "help") ||
02935     (ms == "manual") ||
02936     (ms == "mmxdoc") ||
02937     (ms == "elsart") ||
02938     (ms == "ifac") ||
02939     (ms == "jsc") ||
02940     (ms == "acmconf") ||
02941     (ms == "svjour") ||
02942     (ms == "svmono");
02943 }
02944 
02945 tree
02946 upgrade_math (tree t) {
02947   int i;
02948   if (is_atomic (t)) return t;
02949   else if (is_func (t, WITH, 3) && t[0] == MODE && t[1] == "math")
02950     return compound ("math", upgrade_math (t[2]));
02951   else if (is_func (t, WITH, 3) && t[0] == MODE && t[1] == "text")
02952     return compound ("text", upgrade_math (t[2]));
02953   else if (is_func (t, WITH) && N(t) >= 5 && t[0] == MODE && t[1] == "math")
02954     return compound ("math", upgrade_math (t (2, N(t))));
02955   else if (is_func (t, WITH) && N(t) >= 5 && t[0] == MODE && t[1] == "text")
02956     return compound ("text", upgrade_math (t (2, N(t))));
02957   else {
02958     int n= N(t);
02959     tree r (t, n);
02960     for (i=0; i<n; i++)
02961       r[i]= upgrade_math (t[i]);
02962     return r;
02963   }
02964 }
02965 
02966 /******************************************************************************
02967 * Upgrade resize and clipped
02968 ******************************************************************************/
02969 
02970 tree
02971 upgrade_resize_arg (tree t) {
02972   if (is_func (t, MERGE, 2)) {
02973     if (is_atomic (t[0]) && is_atomic (t[1]))
02974       return upgrade_resize_arg (t[0]->label * t[1]->label);
02975     tree u= upgrade_resize_arg (t[0]);
02976     if (is_func (u, PLUS, 2) || is_func (u, MINUS, 2) ||
02977        is_func (u, MINIMUM, 2) || is_func (u, MAXIMUM, 2))
02978       if (u[1] == "") {
02979        u[1]= upgrade_resize_arg (t[1]);
02980        return u;
02981       }
02982     cout << "TeXmacs] warning, resize argument " << t << " not upgraded\n";
02983     return t;
02984   }
02985   if (is_func (t, ARG, 1) ||
02986       is_func (t, PLUS, 2) || is_func (t, MINUS, 2) ||
02987       is_func (t, MINIMUM, 2) || is_func (t, MAXIMUM, 2))
02988     return t;
02989   if (!is_atomic (t)) {
02990     cout << "TeXmacs] warning, resize argument " << t << " not upgraded\n";
02991     return t;
02992   }
02993   string s= t->label;
02994   if (starts (s, "c")) {
02995     cout << "TeXmacs] warning, resize argument " << t << " not upgraded\n";
02996     return t;
02997   }
02998   if (s == "l") return "1l";
02999   if (s == "r") return "1r";
03000   if (s == "t") return "1t";
03001   if (s == "b") return "1b";
03002   if (N(s) < 2) return t;
03003   if (s[0] != 'l' && s[0] != 'b' && s[0] != 'r' && s[0] != 't') return t;
03004   string s1= "1" * s (0, 1);
03005   string s2= s (2, N(s));
03006   if (s[1] == '+') return tree (PLUS, s1, s2);
03007   if (s[1] == '-') return tree (MINUS, s1, s2);
03008   if (s[1] == '[') return tree (MINIMUM, s1, s2);
03009   if (s[1] == ']') return tree (MAXIMUM, s1, s2);
03010   return t;
03011 }
03012 
03013 tree
03014 upgrade_resize_clipped (tree t) {
03015   if (is_atomic (t)) return t;
03016   else if (N(t) >= 5 && (is_func (t, RESIZE) || is_func (t, CLIPPED))) {
03017     if (is_func (t, CLIPPED))
03018       t= tree (CLIPPED, t[4], t[0], t[1], t[2], t[3]);
03019     int i, n= 5;
03020     tree r (t, n);
03021     r[0]= upgrade_resize_clipped (t[0]);
03022     for (i=1; i<n; i++)
03023       r[i]= upgrade_resize_arg (t[i]);
03024     return r;
03025   }
03026   else {
03027     int i, n= N(t);
03028     tree r (t, n);
03029     for (i=0; i<n; i++)
03030       r[i]= upgrade_resize_clipped (t[i]);
03031     return r;
03032   }
03033 }
03034 
03035 /******************************************************************************
03036 * Upgrade images
03037 ******************************************************************************/
03038 
03039 tree
03040 upgrade_image_length (tree t, string unit) {
03041   if (!is_atomic (t)) return t;
03042   string s= t->label;
03043   if (starts (s, "*") || starts (s, "/")) {
03044     double mag= get_magnification (s);
03045     return as_string (mag) * unit;
03046   }
03047   else return t;
03048 }
03049 
03050 tree
03051 upgrade_image (tree t) {
03052   if (is_atomic (t)) return t;
03053   else if (is_func (t, IMAGE, 7))
03054     return tree (IMAGE, t[0],
03055                upgrade_image_length (t[1], "w"),
03056                upgrade_image_length (t[2], "h"),
03057                "", "");
03058   else {
03059     int i, n= N(t);
03060     tree r (t, n);
03061     for (i=0; i<n; i++)
03062       r[i]= upgrade_image (t[i]);
03063     return r;
03064   }
03065 }
03066 
03067 /******************************************************************************
03068 * Upgrade root switches
03069 ******************************************************************************/
03070 
03071 tree
03072 upgrade_root_switch (tree t, bool top= true) {
03073   if (is_func (t, DOCUMENT) &&
03074       (top || N(t) == 1 ||
03075        (N(t) == 2 && is_compound (t[0], "hide-preamble")))) {
03076     int i, n= N(t);
03077     tree r (DOCUMENT, n);
03078     for (i=0; i<n; i++)
03079       r[i]= upgrade_root_switch (t[i], false);
03080     return r;
03081   }
03082   else if (is_compound (t, "body", 1))
03083     return compound ("body", upgrade_root_switch (t[0], false));
03084   else if (is_compound (t, "switch"))
03085     return compound ("screens", A(t));
03086   else return t;
03087 }
03088 
03089 /******************************************************************************
03090 * Upgrade hyphenation
03091 ******************************************************************************/
03092 
03093 tree
03094 upgrade_hyphenation (tree t) {
03095   tree style= copy (extract (t, "style"));
03096   tree init = extract (t, "initial");
03097   if (is_atomic (style)) style= tuple (style);
03098   if (style == tree (TUPLE)) style= tuple ("generic");
03099   if (!is_tuple (style) || N(style) != 1 || !is_atomic (style[0])) return t;
03100   string ms= style[0]->label;
03101   if (ms == "article" || ms == "beamer" || ms == "book" || ms == "exam" ||
03102       ms == "generic" || ms == "letter" || ms == "seminar")
03103     {
03104       hashmap<string,tree> h (UNINIT, init);
03105       if (!h->contains (PAR_HYPHEN)) h (PAR_HYPHEN)= "normal";
03106       tree new_init= make_collection (h);
03107       return change_doc_attr (t, "initial", new_init);
03108     }
03109   else return t;
03110 }
03111 
03112 /******************************************************************************
03113 * Renaming of symbols
03114 ******************************************************************************/
03115 
03116 tree
03117 rename_symbols (tree t, hashmap<string,string> h) {
03118   if (is_atomic (t)) {
03119     bool same= true;
03120     int pos;
03121     string s= t->label;
03122     for (pos=0; pos<N(s); ) {
03123       int j=pos;
03124       tm_char_forwards (s, pos);
03125       if (j+2 < pos && h->contains (s (j, pos))) {
03126         same= false;
03127         break;
03128       }
03129     }
03130     if (same) return t;
03131     string r;
03132     for (pos=0; pos<N(s); ) {
03133       int j=pos;
03134       tm_char_forwards (s, pos);
03135       if (h->contains (s (j, pos))) r << h [s (j, pos)];
03136       else r << s (j, pos);
03137     }
03138     return r;
03139   }
03140   else if (is_func (t, RAW_DATA)) return t;
03141   else {
03142     int i, n= N(t);
03143     tree r (t, n);
03144     for (i=0; i<n; i++)
03145       r[i]= rename_symbols (t[i], h);
03146     return r;
03147   }
03148 }
03149 
03150 /******************************************************************************
03151 * Rewrite bodies of algorithms
03152 ******************************************************************************/
03153 
03154 tree
03155 upgrade_algorithm (tree t, bool flag= true) {
03156   if (is_atomic (t)) return t;
03157   else if (is_compound (t, "algo", 1))
03158     return compound ("tt", upgrade_algorithm (t[0]));
03159   else if (is_compound (t, "algorithm", 2))
03160     return compound ("named-algorithm-old",
03161                      upgrade_algorithm (t[0]), upgrade_algorithm (t[1]));
03162   else if (flag && is_compound (t, "body", 1))
03163     return compound ("algorithm-body", upgrade_algorithm (t[0]));
03164   else if (is_compound (t, "pile", 1))
03165     return compound ("tabbed", upgrade_algorithm (t[0]));
03166   else if (is_compound (t, "scm-fragment", 1))
03167     return compound ("scm-code", upgrade_algorithm (t[0]));
03168   else if (is_compound (t, "scheme-fragment", 1))
03169     return compound ("scm-code", upgrade_algorithm (t[0]));
03170   else if (is_compound (t, "mmx-fragment", 1))
03171     return compound ("mmx-code", upgrade_algorithm (t[0]));
03172   else if (is_compound (t, "cpp-fragment", 1))
03173     return compound ("cpp-code", upgrade_algorithm (t[0]));
03174   else if (is_compound (t, "shell-fragment", 1))
03175     return compound ("shell-code", upgrade_algorithm (t[0]));
03176   else {
03177     int i, n= N(t);
03178     tree r (t, n);
03179     flag= true;
03180     if (is_document (t))
03181       for (i=0; i<n; i++)
03182         if (is_compound (t[i], "TeXmacs", 1) ||
03183             is_compound (t[i], "style") ||
03184             is_compound (t[i], "initial") ||
03185             is_compound (t[i], "references"))
03186           flag= false;
03187     for (i=0; i<n; i++)
03188       r[i]= upgrade_algorithm (t[i], flag);
03189     return r;
03190   }
03191 }
03192 
03193 /******************************************************************************
03194 * Upgrade mathematical operators
03195 ******************************************************************************/
03196 
03197 tree
03198 upgrade_math_ops (tree t) {
03199   if (is_atomic (t)) return t;
03200   int i, n= N(t);
03201   tree r (t, n);
03202   for (i=0; i<n; i++)
03203     r[i]= upgrade_math_ops (t[i]);
03204   if (is_func (t, WITH, 3) &&
03205       is_atomic (t[2]) &&
03206       is_alpha (t[2]->label) &&
03207       t[0] == "math-font-family")
03208     {
03209       if (t[1] == "trm") return compound ("math-up", t[2]);
03210       if (t[1] == "tss") return compound ("math-ss", t[2]);
03211       if (t[1] == "ttt") return compound ("math-tt", t[2]);
03212       if (t[1] == "rm") return compound ("math-up", t[2]);
03213       if (t[1] == "up") return compound ("math-up", t[2]);
03214       if (t[1] == "bf") return compound ("math-bf", t[2]);
03215       if (t[1] == "sl") return compound ("math-sl", t[2]);
03216       if (t[1] == "it") return compound ("math-it", t[2]);
03217       if (t[1] == "ss") return compound ("math-ss", t[2]);
03218       if (t[1] == "tt") return compound ("math-tt", t[2]);
03219     }
03220   if (n == 1 && starts (as_string (L(t)), "math-")) {
03221     if (is_compound (t, "math-ord")) return compound ("math-ordinary", t[0]);
03222     if (is_compound (t, "math-punct")) return compound ("math-separator", t[0]);
03223     if (is_compound (t, "math-bin")) return compound ("math-plus", t[0]);
03224     if (is_compound (t, "math-rel")) return compound ("math-relation", t[0]);
03225     if (is_compound (t, "math-op")) return compound ("math-big", t[0]);
03226   }
03227   return r;
03228 }
03229 
03230 /******************************************************************************
03231 * Cleaning spurious spaces in the document
03232 ******************************************************************************/
03233 
03234 static bool
03235 only_spaces (string s) {
03236   for (int i=0; i<N(s); i++)
03237     if (s[i] != ' ') return false;
03238   return true;
03239 }
03240 
03241 static bool
03242 eat_spaces (tree t, bool after) {
03243   (void) after;
03244   if (is_atomic (t)) return false;
03245   return
03246     is_compound (t, "hide-preamble") ||
03247     is_compound (t, "doc-data") ||
03248     is_compound (t, "abstract") ||
03249     is_compound (t, "bibliography") ||
03250     is_compound (t, "bibitem") ||
03251     is_compound (t, "bibitem*");
03252 }
03253 
03254 static tree
03255 clean_spaces (tree t) {
03256   if (is_atomic (t)) return t;
03257   int i, n= N(t);
03258   tree r (t, n);
03259   for (i=0; i<n; i++)
03260     r[i]= clean_spaces (t[i]);
03261   if (!is_func (r, CONCAT)) return r;
03262   t= r;
03263   r= tree (CONCAT);
03264   for (i=0; i<n; i++)
03265     if (!is_atomic (t[i])) r << t[i];
03266     else {
03267       string s= t[i]->label;
03268       if (i>0 && eat_spaces (t[i-1], true))
03269         while (starts (s, " ")) s= s (1, N(s));
03270       if (i<N(t)-1 && eat_spaces (t[i+1], false))
03271         while (ends (s, " ")) s= s (0, N(s)-1);
03272       if (s != "") r << tree (s);
03273     }
03274   if (N(r) == 0) return "";
03275   if (N(r) == 1) return r[0];
03276   return r;
03277 }
03278 
03279 /******************************************************************************
03280 * Cleaning the document header
03281 ******************************************************************************/
03282 
03283 static tree
03284 search_header_tag (tree t, string which, tree& h) {
03285   if (is_compound (t, which)) {
03286     h << t;
03287     return "";
03288   }
03289   if (is_func (t, DOCUMENT)) {
03290     tree r (DOCUMENT);
03291     for (int i=0; i<N(t); i++) {
03292       if (is_compound (t[i], which)) h << t[i];
03293       else if (is_func (t[i], SURROUND, 3)) {
03294         tree x= search_header_tag (t[i], which, h);
03295         if (x != "") r << x;
03296       }
03297       else r << t[i];
03298     }
03299     return r;
03300   }
03301   if (is_func (t, SURROUND, 3)) {
03302     tree r (SURROUND, 3);
03303     r[0]= search_header_tag (t[0], which, h);
03304     r[2]= search_header_tag (t[2], which, h);
03305     r[1]= search_header_tag (t[1], which, h);
03306     if (r[0] == "" && r[1] == "") r= r[2];
03307     else if (r[0] == "" && r[2] == "") r= r[1];
03308     else if (r[1] == "" && r[2] == "") r= r[0];
03309     return r;
03310   }
03311   return t;
03312 }
03313 
03314 tree
03315 clean_header (tree t) {
03316   if (!is_func (t, DOCUMENT)) return t;
03317   tree r        (DOCUMENT);
03318   tree preamble (DOCUMENT);
03319   tree title    (DOCUMENT);
03320   tree abstract (DOCUMENT);
03321   t= search_header_tag (t, "hide-preamble", preamble);
03322   t= search_header_tag (t, "doc-data", title);
03323   t= search_header_tag (t, "abstract", abstract);
03324   while (N(t) > 0 && is_atomic (t[0]) && only_spaces (t[0]->label))
03325     t= t (1, N(t));
03326   r << A (preamble);
03327   r << A (title);
03328   r << A (abstract);
03329   r << A (t);
03330   return r;
03331 }
03332 
03333 /******************************************************************************
03334 * Upgrade graphical attributes
03335 ******************************************************************************/
03336 
03337 static void
03338 replace_dash_style (tree& t, string var) {
03339   if (find_attr (t, var)) {
03340     tree val= get_attr (t, var, "default");
03341     if (is_func (val, TUPLE)) {
03342       string nval;
03343       for (int i=0; i<N(val); i++)
03344         if (val[i] == "0") nval << "0";
03345         else nval << "1";
03346       t= set_attr (t, var, tree (nval));
03347     }
03348   }
03349 }
03350 
03351 static tree
03352 encode_arrow (tree t) {
03353   if (is_func (t, WITH, 3) && t[0] == "dash-style") {
03354     if (t[2] == tree (LINE,
03355                       tuple ("10ln", "6ln"),
03356                       tuple ("0ln", "0ln"),
03357                       tuple ("10ln", "-6ln")))
03358       return "<less>";
03359     if (t[2] == tree (LINE,
03360                       tuple ("-10ln", "6ln"),
03361                       tuple ("0ln", "0ln"),
03362                       tuple ("-10ln", "-6ln")))
03363       return "<gtr>";
03364   }
03365   return t;
03366 }
03367 
03368 static void
03369 replace_line_arrows (tree& t, string var, string begin, string end) {
03370   if (find_attr (t, var)) {
03371     tree val= get_attr (t, var, "default");
03372     t= set_attr (t, "arrow-length", "10ln");
03373     t= set_attr (t, "arrow-height", "6ln");
03374     if (is_func (val, TUPLE, 1))
03375       t= set_attr (t, end, encode_arrow (val[0]));
03376     if (is_func (val, TUPLE, 2)) {
03377       t= set_attr (t, begin, encode_arrow (val[0]));
03378       t= set_attr (t, end, encode_arrow (val[1]));
03379     }
03380     t= remove_attr (t, var);
03381   }
03382 }
03383 
03384 static void
03385 replace_magnification (tree& t, string var, string repl) {
03386   tree body= t[N(t)-1];
03387   if (find_attr (t, var))
03388     if (is_func (body, GRAPHICS) ||
03389         is_func (body, GR_GROUP) ||
03390         is_func (body, TEXT_AT) ||
03391         is_func (body, _POINT) ||
03392         is_func (body, LINE) ||
03393         is_func (body, CLINE) ||
03394         is_func (body, SPLINE) ||
03395         is_func (body, CSPLINE) ||
03396         is_func (body, ARC) ||
03397         is_func (body, CARC) ||
03398         is_func (body, VAR_SPLINE))
03399       {
03400         tree val= get_attr (t, var, "1");
03401         if (is_func (val, TIMES, 2) &&
03402             is_func (val[1], VALUE, 1) &&
03403             val[1][0] == var)
03404           val= val[0];
03405         t= set_attr (t, repl, val);
03406         t= remove_attr (t, var);
03407       }
03408 }
03409 
03410 static tree
03411 upgrade_gr_attributes (tree t) {
03412   int i;
03413   if (is_atomic (t)) return t;
03414   if (is_func (t, WITH)) {
03415     replace_dash_style (t, "dash-style");
03416     replace_dash_style (t, "gr-dash-style");
03417     replace_line_arrows (t, "line-arrows", "arrow-begin", "arrow-end");
03418     replace_line_arrows (t, "gr-line-arrows",
03419                             "gr-arrow-begin", "gr-arrow-end");
03420     replace_magnification (t, "magnification", "magnify");
03421   }
03422   int n= N(t);
03423   tree r (t, n);
03424   for (i=0; i<n; i++)
03425     r[i]= upgrade_gr_attributes (t[i]);
03426   return r;
03427 }
03428 
03429 /******************************************************************************
03430 * Upgrade cursor tag
03431 ******************************************************************************/
03432 
03433 static tree
03434 upgrade_cursor (tree t) {
03435   int i;
03436   if (is_atomic (t)) return t;
03437   if (is_func (t, VALUE)) {
03438     if (t == tree (VALUE, "cursor")) return compound ("cursor");
03439     if (t == tree (VALUE, "math-cursor")) return compound ("math-cursor");
03440   }
03441   int n= N(t);
03442   tree r (t, n);
03443   for (i=0; i<n; i++)
03444     r[i]= upgrade_cursor (t[i]);
03445   return r;
03446 }
03447 
03448 /******************************************************************************
03449 * Upgrade from previous versions
03450 ******************************************************************************/
03451 
03452 tree
03453 upgrade_tex (tree t) {
03454   upgrade_tex_flag= true;
03455   t= upgrade_apply_expand_value (t);
03456   t= upgrade_new_environments (t);
03457   t= upgrade_items (t);
03458   t= upgrade_table (t);
03459   t= upgrade_split (t, false);
03460   t= upgrade_title (t);
03461   t= simplify_correct (upgrade_mod_symbols (t));
03462   t= upgrade_menus_in_help (t);
03463   t= upgrade_capitalize_menus (t);
03464   t= upgrade_formatting (t);
03465   t= upgrade_expand (t, EXPAND);
03466   t= upgrade_expand (t, HIDE_EXPAND);
03467   t= upgrade_expand (t, VAR_EXPAND);
03468   t= upgrade_xexpand (t);
03469   t= upgrade_function (t);
03470   t= upgrade_apply (t);
03471   t= upgrade_env_vars (t);
03472   t= upgrade_style_rename (t);
03473   t= upgrade_item_punct (t);
03474   t= substitute (t, tree (VALUE, "hrule"), compound ("hrule"));
03475   t= upgrade_doc_info (t);
03476   t= upgrade_bibliography (t);
03477   t= upgrade_math (t);
03478   t= upgrade_resize_clipped (t);
03479   t= with_correct (t);
03480   t= superfluous_with_correct (t);
03481   t= upgrade_brackets (t);
03482   t= move_brackets (t);
03483   t= upgrade_image (t);
03484   t= upgrade_math_ops (t);
03485   t= clean_spaces (t);
03486   t= clean_header (t);
03487   upgrade_tex_flag= false;
03488   return t;
03489 }
03490 
03491 tree
03492 upgrade_mathml (tree t) {
03493   t= upgrade_brackets (t, "math");
03494   t= downgrade_big (t);
03495   return t;
03496 }
03497 
03498 tree
03499 upgrade (tree t, string version) {
03500   if (version_inf (version, "0.3.1.9")) {
03501     path p;
03502     t= upgrade_textual (t, p);
03503   }
03504   if (version_inf (version, "0.3.3.1"))
03505     t= upgrade_apply_expand_value (t);
03506   if (version_inf (version, "0.3.3.20"))
03507     t= upgrade_new_environments (t);
03508   if (version_inf (version, "0.3.3.24"))
03509     t= upgrade_items (t);
03510   if (version_inf (version, "0.3.4.4"))
03511     t= upgrade_resize (t);
03512   if (version_inf_eq (version, "0.3.4.7"))
03513     t= upgrade_table (t);
03514   if (version_inf_eq (version, "0.3.4.8"))
03515     t= upgrade_split (t, false);
03516   if (version_inf_eq (version, "0.3.5.6"))
03517     t= upgrade_project (t);
03518   if (version_inf_eq (version, "0.3.5.10"))
03519     t= upgrade_title (t);
03520   if (version_inf_eq (version, "1.0.0.1"))
03521     t= upgrade_cas (t);
03522   if (version_inf_eq (version, "1.0.0.8"))
03523     t= simplify_correct (upgrade_mod_symbols (t));
03524   if (version_inf_eq (version, "1.0.0.11"))
03525     t= upgrade_menus_in_help (t);
03526   if (version_inf_eq (version, "1.0.0.13"))
03527     t= upgrade_capitalize_menus (t);
03528   if (version_inf_eq (version, "1.0.0.19"))
03529     t= upgrade_traverse_branch (t);
03530   if (version_inf_eq (version, "1.0.1.20"))
03531     t= upgrade_session (t);
03532   if (version_inf_eq (version, "1.0.2.0"))
03533     t= upgrade_formatting (t);
03534   if (version_inf_eq (version, "1.0.2.3"))
03535     t= upgrade_expand (t, EXPAND);
03536   if (version_inf_eq (version, "1.0.2.4"))
03537     t= upgrade_expand (t, HIDE_EXPAND);
03538   if (version_inf_eq (version, "1.0.2.5")) {
03539     t= upgrade_expand (t, VAR_EXPAND);
03540     t= upgrade_xexpand (t);
03541   }
03542   if (version_inf_eq (version, "1.0.2.6")) {
03543     t= upgrade_function (t);
03544     t= upgrade_apply (t);
03545   }
03546   if (version_inf_eq (version, "1.0.2.8"))
03547     t= upgrade_env_vars (t);
03548   if (version_inf_eq (version, "1.0.3.3"))
03549     t= upgrade_use_package (t);
03550   if (version_inf_eq (version, "1.0.3.4"))
03551     t= upgrade_style_rename (t);
03552   if (version_inf_eq (version, "1.0.3.4"))
03553     t= upgrade_item_punct (t);
03554   if (version_inf_eq (version, "1.0.3.7"))
03555     t= upgrade_page_pars (t);
03556   if (version_inf_eq (version, "1.0.4")) {
03557     t= substitute (t, tree (VALUE, "hrule"), compound ("hrule"));
03558     t= upgrade_doc_info (t);
03559   }
03560   if (version_inf_eq (version, "1.0.4.6"))
03561     t= upgrade_bibliography (t);
03562   if (version_inf_eq (version, "1.0.5.4"))
03563     t= upgrade_switch (t);
03564   if (version_inf_eq (version, "1.0.5.7"))
03565     t= upgrade_fill (t);
03566   if (version_inf_eq (version, "1.0.5.8"))
03567     t= upgrade_graphics (t);
03568   if (version_inf_eq (version, "1.0.5.11"))
03569     t= upgrade_textat (t);
03570   if (version_inf_eq (version, "1.0.6.1"))
03571     t= upgrade_cell_alignment (t);
03572   if (version_inf_eq (version, "1.0.6.2"))
03573     t= rename_primitive (t, "hyper-link", "hlink");
03574   if (version_inf_eq (version, "1.0.6.2"))
03575     t= upgrade_label_assignment (t);
03576   if (version_inf_eq (version, "1.0.6.10"))
03577     t= upgrade_scheme_doc (t);
03578   if (version_inf_eq (version, "1.0.6.14"))
03579     t= upgrade_mmx (t);
03580   if (version_inf_eq (version, "1.0.7.1"))
03581     t= upgrade_session (t, "scheme", "default");
03582   if (version_inf_eq (version, "1.0.7.6"))
03583     t= upgrade_presentation (t);
03584   if (version_inf_eq (version, "1.0.7.6") && is_non_style_document (t))
03585     t= upgrade_math (t);
03586   if (version_inf_eq (version, "1.0.7.7"))
03587     t= upgrade_resize_clipped (t);
03588   if (version_inf_eq (version, "1.0.7.7"))
03589     t= upgrade_image (t);
03590   if (version_inf_eq (version, "1.0.7.7"))
03591     t= upgrade_root_switch (t);
03592   if (version_inf_eq (version, "1.0.7.8"))
03593     t= upgrade_hyphenation (t);
03594   if (DEBUG_CORRECT)
03595     if (is_non_style_document (t))
03596       math_status_cumul (t);
03597   if (version_inf_eq (version, "1.0.7.8") && is_non_style_document (t)) {
03598     t= with_correct (t);
03599     t= superfluous_with_correct (t);
03600     t= upgrade_brackets (t);
03601   }
03602   if (version_inf_eq (version, "1.0.7.9")) {
03603     t= move_brackets (t);
03604     if (is_non_style_document (t))
03605       t= upgrade_algorithm (t, false);
03606     t= upgrade_math_ops (t);
03607   }
03608   if (version_inf_eq (version, "1.0.7.10"))
03609     t= downgrade_big (t);
03610   if (version_inf_eq (version, "1.0.7.13"))
03611     t= upgrade_gr_attributes (t);
03612   if (version_inf_eq (version, "1.0.7.14"))
03613     t= upgrade_cursor (t);
03614 
03615   if (is_non_style_document (t))
03616     t= automatic_correct (t, version);
03617   return t;
03618 }