1 
2 /******************************************************************************
3 * MODULE     : upgradetm.cpp
4 * DESCRIPTION: upgrade old TeXmacs formats
5 * COPYRIGHT  : (C) 1999  Joris van der Hoeven
6 *******************************************************************************
7 * This software falls under the GNU general public license version 3 or later.
8 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
9 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
10 ******************************************************************************/
11 
12 #include "convert.hpp"
13 #include "converter.hpp"
14 #include "hashset.hpp"
15 #include "path.hpp"
16 #include "vars.hpp"
17 #include "drd_std.hpp"
18 #include <stdio.h>
19 #include "scheme.hpp"
20 #include "tree_correct.hpp"
21 #include "merge_sort.hpp"
22 
23 static bool upgrade_tex_flag= false;
24 double get_magnification (string s);
25 
26 /******************************************************************************
27 * Retrieve older operator hashmap
28 ******************************************************************************/
29 
30 static void
rename_feature(hashmap<string,int> & H,string old_name,string new_name)31 rename_feature (hashmap<string,int>& H, string old_name, string new_name) {
32   H (old_name)= H [new_name];
33   H->reset (new_name);
34 }
35 
36 static void
new_feature(hashmap<string,int> & H,string new_name)37 new_feature (hashmap<string,int>& H, string new_name) {
38   H->reset (new_name);
39 }
40 
41 /*static*/ hashmap<string,int>
get_codes(string version)42 get_codes (string version) {
43   hashmap<string,int> H (UNKNOWN);
44   H->join (STD_CODE);
45 
46   if (version_inf ("1.0.7.6", version)) return H;
47 
48   rename_feature (H, "group", "rigid");
49   rename_feature (H, "postscript", "image");
50 
51   if (version_inf ("1.0.6.9", version)) return H;
52 
53   rename_feature (H, "frozen", "freeze");
54 
55   if (version_inf ("1.0.6.2", version)) return H;
56 
57   new_feature (H, "expand-as");
58   new_feature (H, "locus");
59   new_feature (H, "id");
60   new_feature (H, "hard-id");
61   new_feature (H, "link");
62   new_feature (H, "url");
63   new_feature (H, "script");
64 
65   if (version_inf ("1.0.4.1", version)) return H;
66 
67   new_feature (H, "copy");
68   new_feature (H, "cm-length");
69   new_feature (H, "mm-length");
70   new_feature (H, "in-length");
71   new_feature (H, "pt-length");
72   new_feature (H, "bp-length");
73   new_feature (H, "dd-length");
74   new_feature (H, "pc-length");
75   new_feature (H, "cc-length");
76   new_feature (H, "fs-length");
77   new_feature (H, "fbs-length");
78   new_feature (H, "em-length");
79   new_feature (H, "ln-length");
80   new_feature (H, "sep-length");
81   new_feature (H, "yfrac-length");
82   new_feature (H, "ex-length");
83   new_feature (H, "fn-length");
84   new_feature (H, "fns-length");
85   new_feature (H, "bls-length");
86   new_feature (H, "spc-length");
87   new_feature (H, "xspc-length");
88   new_feature (H, "par-length");
89   new_feature (H, "pag-length");
90   new_feature (H, "tmpt-length");
91   new_feature (H, "px-length");
92   new_feature (H, "tmlen");
93 
94   if (version_inf ("1.0.3.12", version)) return H;
95 
96   new_feature (H, "unquote*");
97 
98   if (version_inf ("1.0.3.4", version)) return H;
99 
100   new_feature (H, "for-each");
101   new_feature (H, "quasi");
102   rename_feature (H, "hold", "quasiquote");
103   rename_feature (H, "release", "unquote");
104 
105   if (version_inf ("1.0.3.3", version)) return H;
106 
107   new_feature (H, "quote-value");
108   new_feature (H, "quote-arg");
109   new_feature (H, "mark");
110   new_feature (H, "use-package");
111   new_feature (H, "style-only");
112   new_feature (H, "style-only*");
113   new_feature (H, "rewrite-inactive");
114   new_feature (H, "inline-tag");
115   new_feature (H, "open-tag");
116   new_feature (H, "middle-tag");
117   new_feature (H, "close-tag");
118 
119   if (version_inf ("1.0.2.8", version)) return H;
120 
121   rename_feature (H, "raw_data", "raw-data");
122   rename_feature (H, "sub_table", "subtable");
123   rename_feature (H, "drd_props", "drd-props");
124   rename_feature (H, "get_label", "get-label");
125   rename_feature (H, "get_arity", "get-arity");
126   rename_feature (H, "map_args", "map-args");
127   rename_feature (H, "eval_args", "eval-args");
128   rename_feature (H, "find_file", "find-file");
129   rename_feature (H, "is_tuple", "is-tuple");
130   rename_feature (H, "look_up", "look-up");
131   rename_feature (H, "var_if", "if*");
132   rename_feature (H, "var_inactive", "inactive*");
133   rename_feature (H, "var_active", "active*");
134   rename_feature (H, "text_at", "text-at");
135   rename_feature (H, "var_spline", "spline*");
136   rename_feature (H, "old_matrix", "old-matrix");
137   rename_feature (H, "old_table", "old-table");
138   rename_feature (H, "old_mosaic", "old-mosaic");
139   rename_feature (H, "old_mosaic_item", "old-mosaic-item");
140   rename_feature (H, "var_expand", "expand*");
141   rename_feature (H, "hide_expand", "hide-expand");
142 
143   rename_feature (H, "with_limits", "with-limits");
144   rename_feature (H, "line_break", "line-break");
145   rename_feature (H, "new_line", "new-line");
146   rename_feature (H, "line_separator", "line-sep");
147   rename_feature (H, "next_line", "next-line");
148   rename_feature (H, "no_line_break", "no-break");
149   rename_feature (H, "no_first_indentation", "no-indent");
150   rename_feature (H, "enable_first_indentation", "yes-indent");
151   rename_feature (H, "no_indentation_after", "no-indent*");
152   rename_feature (H, "enable_indentation_after", "yes-indent*");
153   rename_feature (H, "page_break_before", "page-break*");
154   rename_feature (H, "page_break", "page-break");
155   rename_feature (H, "no_page_break_before", "no-page-break*");
156   rename_feature (H, "no_page_break_after", "no-page-break");
157   rename_feature (H, "new_page_before", "new-page*");
158   rename_feature (H, "new_page", "new-page");
159   rename_feature (H, "new_double_page_before", "new-dpage*");
160   rename_feature (H, "new_double_page", "new-dpage");
161 
162   if (version_inf ("1.0.2.5", version)) return H;
163 
164   new_feature (H, "compound");
165   new_feature (H, "xmacro");
166   new_feature (H, "get_label");
167   new_feature (H, "get_arity");
168   new_feature (H, "map_args");
169   new_feature (H, "eval_args");
170   new_feature (H, "drd_props");
171 
172   if (version_inf ("1.0.2.0", version)) return H;
173 
174   new_feature (H, "with_limits");
175   new_feature (H, "line_break");
176   new_feature (H, "new_line");
177   new_feature (H, "line_separator");
178   new_feature (H, "next_line");
179   new_feature (H, "no_line_break");
180   new_feature (H, "no_first_indentation");
181   new_feature (H, "enable_first_indentation");
182   new_feature (H, "no_indentation_after");
183   new_feature (H, "enable_indentation_after");
184   new_feature (H, "page_break_before");
185   new_feature (H, "page_break");
186   new_feature (H, "no_page_break_before");
187   new_feature (H, "no_page_break_after");
188   new_feature (H, "new_page_before");
189   new_feature (H, "new_page");
190   new_feature (H, "new_double_page_before");
191   new_feature (H, "new_double_page");
192 
193   if (version_inf ("1.0.1.25", version)) return H;
194 
195   new_feature (H, "active");
196   new_feature (H, "var_inactive");
197   new_feature (H, "var_active");
198   new_feature (H, "attr");
199 
200   if (version_inf ("1.0.0.20", version)) return H;
201 
202   new_feature (H, "text_at");
203 
204   if (version_inf ("1.0.0.19", version)) return H;
205 
206   new_feature (H, "find_file");
207 
208   if (version_inf ("1.0.0.14", version)) return H;
209 
210   rename_feature (H, "paragraph", "para");
211 
212   if (version_inf ("1.0.0.5", version)) return H;
213 
214   new_feature (H, "var_if");
215   new_feature (H, "hide_expand");
216 
217   if (version_inf ("1.0.0.2", version)) return H;
218 
219   new_feature (H, "superpose");
220   new_feature (H, "spline");
221   new_feature (H, "var_spline");
222   new_feature (H, "cspline");
223   new_feature (H, "fill");
224 
225   if (version_inf ("0.3.5.2", version)) return H;
226 
227   new_feature (H, "raw_data");
228   new_feature (H, "include");
229 
230   if (version_inf ("0.3.5.1", version)) return H;
231 
232   new_feature (H, "var_expand");
233 
234   if (version_inf ("0.3.4.12", version)) return H;
235 
236   new_feature (H, "range");
237   new_feature (H, "is_tuple");
238   new_feature (H, "look_up");
239 
240   if (version_inf ("0.3.4.11", version)) return H;
241 
242   new_feature (H, "float");
243   new_feature (H, "datoms");
244   new_feature (H, "dlines");
245   new_feature (H, "dpages");
246   new_feature (H, "pageref");
247 
248   if (version_inf ("0.3.4.7", version)) return H;
249 
250   rename_feature (H, "matrix", "old_matrix");
251   rename_feature (H, "table", "old_table");
252   rename_feature (H, "mosaic", "old_mosaic");
253   rename_feature (H, "mosaic_item", "old_mosaic_item");
254 
255   if (version_inf ("0.3.4.6", version)) return H;
256 
257   new_feature (H, "tformat");
258   new_feature (H, "twith");
259   new_feature (H, "cwith");
260   new_feature (H, "tmarker");
261   new_feature (H, "row");
262   new_feature (H, "cell");
263   new_feature (H, "sub_table");
264 
265   if (version_inf ("0.3.4.0", version)) return H;
266 
267   new_feature (H, "tag");
268   new_feature (H, "syntax");
269 
270   if (version_inf_eq ("0.3.3.15", version)) return H;
271 
272   new_feature (H, "uninit");
273   new_feature (H, "error");
274   new_feature (H, "surround");
275   new_feature (H, "hold");
276   new_feature (H, "release");
277   new_feature (H, "arg");
278 
279   if (version_inf_eq ("0.3.3.0", version)) return H;
280 
281   new_feature (H, "with");
282   new_feature (H, "macro");
283   new_feature (H, "eval");
284   new_feature (H, "value");
285   new_feature (H, "or");
286   new_feature (H, "xor");
287   new_feature (H, "and");
288   new_feature (H, "not");
289   new_feature (H, "over");
290   new_feature (H, "divide");
291   new_feature (H, "modulo");
292   new_feature (H, "length");
293   new_feature (H, "date");
294   new_feature (H, "equal");
295   new_feature (H, "unequal");
296   new_feature (H, "less");
297   new_feature (H, "lesseq");
298   new_feature (H, "greater");
299   new_feature (H, "greatereq");
300   new_feature (H, "if");
301   new_feature (H, "case");
302   new_feature (H, "for");
303   new_feature (H, "while");
304   new_feature (H, "extern");
305   new_feature (H, "authorize");
306 
307   if (version_inf_eq ("0.3.1.8", version)) return H;
308 
309   rename_feature (H, "mosaic item", "mosaic_item");
310   rename_feature (H, "<>", "symbol");
311   rename_feature (H, ";", "backup");
312   rename_feature (H, "'", "quote");
313   rename_feature (H, ":=", "assign");
314   rename_feature (H, "\\", "apply");
315   rename_feature (H, "()", "tuple");
316   rename_feature (H, "{,}", "collection");
317   rename_feature (H, "->", "associate");
318   rename_feature (H, "+", "plus");
319   rename_feature (H, "-", "minus");
320   rename_feature (H, "x", "times");
321   rename_feature (H, "*", "merge");
322   rename_feature (H, "nr", "number");
323   H ("style")= H ["()"];
324 
325   return H;
326 }
327 
328 /******************************************************************************
329 * Old style is_expand predicates
330 ******************************************************************************/
331 
332 static bool
is_expand(tree t)333 is_expand (tree t) {
334   return ((L(t) == EXPAND) || (L(t) == VAR_EXPAND) || (L(t) == HIDE_EXPAND));
335 }
336 
337 static bool
is_expand(tree t,string s,int n)338 is_expand (tree t, string s, int n) {
339   return is_expand (t) && (N(t) == n+1) && (t[0] == s);
340 }
341 
342 /******************************************************************************
343 * Old style conversion from TeXmacs strings to TeXmacs trees
344 ******************************************************************************/
345 
346 static tree
string_to_tree(string s,int & pos,hashmap<string,int> codes)347 string_to_tree (string s, int& pos, hashmap<string,int> codes) {
348   string l ("");
349   while ((pos<N(s)) && (s[pos]!='(') && (s[pos]!=',') && (s[pos]!=')')) {
350     if ((s[pos]=='\\') && (pos<N(s)-1)) pos++;
351     l << s[pos++];
352   }
353   tree t (l);
354   tree_label code= (tree_label) codes [l];
355   if ((l == "style") || (code == COLLECTION)) t= tree (code);
356   if ((pos<N(s)) && (s[pos]=='(')) {
357     if (code != UNKNOWN) t= tree (code);
358     else t= tuple (l);
359     do {
360       pos++;
361       t << string_to_tree (s, pos, codes);
362     } while ((pos<N(s)) && (s[pos]==','));
363     if ((pos<N(s)) && (s[pos]==')')) pos++;
364   }
365   return t;
366 }
367 
368 static tree
un_paragraph(tree t)369 un_paragraph (tree t) {
370   if (is_atomic (t)) return t;
371   if (is_func (t, PARA, 1)) return t[0];
372   else {
373     int i, n= N(t);
374     tree r (t, n);
375     for (i=0; i<n; i++) r[i]= un_paragraph (t[i]);
376     return r;
377   }
378 }
379 
380 /*static*/ tree
string_to_tree(string s,string version)381 string_to_tree (string s, string version) {
382   int pos=0;
383   return un_paragraph (string_to_tree (s, pos, get_codes (version)));
384 }
385 
386 /******************************************************************************
387 * Upgrade large delimiters, big operators and primes
388 ******************************************************************************/
389 
390 tree
upgrade_textual(tree t,path & mode_stack)391 upgrade_textual (tree t, path& mode_stack) {
392   if (t == "") return t;
393   if (is_atomic (t)) {
394     int i, n= N(t->label);
395     string s;
396     tree r (CONCAT);
397     for (i=0; i<n; ) {
398       if (t->label[i] == '<') {
399 	int start= i;
400 	for (i++; i<n; i++)
401 	  if (t->label[i-1] == '>') break;
402 	string ss= t->label (start, i);
403 	if (t->label[i-1] != '>') ss << '>';
404 	if (starts (ss, "<left-")) {
405 	  if (s != "") r << s; s= "";
406 	  r << tree (LEFT, ss (6, N(ss)-1));
407 	}
408 	else if (starts (ss, "<mid-")) {
409 	  if (s != "") r << s; s= "";
410 	  r << tree (MID, ss (5, N(ss)-1));
411 	}
412 	else if (starts (ss, "<right-")) {
413 	  if (s != "") r << s; s= "";
414 	  r << tree (RIGHT, ss (7, N(ss)-1));
415 	}
416 	else if (starts (ss, "<big-")) {
417 	  if (s != "") r << s; s= "";
418 	  r << tree (BIG, ss (5, N(ss)-1));
419 	}
420 	else s << ss;
421       }
422       else if (((t->label[i] == '\'') || (t->label[i] == '`')) &&
423 	       (!is_nil (mode_stack)) && (mode_stack->item == 1))
424 	{
425 	  int start= i++;
426 	  while ((i<n) && (t->label[i] == t->label[i-1])) i++;
427 	  if (s != "") r << s; s= "";
428 	  tree_label op= t->label[start] == '`'? LPRIME: RPRIME;
429 	  r << tree (op, t->label (start, i));
430 	}
431       else s << t->label[i++];
432     }
433     if (s != "") r << s;
434     if (N(r) == 1) return r[0];
435     return r;
436   }
437   else {
438     int i, n= arity (t);
439     tree r (t, 0);
440     for (i=0; i<n; i++) {
441       tree u= upgrade_textual (t[i], mode_stack);
442       if (is_func (u, SET)) {
443 	if (u == tree (SET, "mode", "text")) mode_stack= path (0, mode_stack);
444 	if (u == tree (SET, "mode", "math")) mode_stack= path (1, mode_stack);
445 	if (u == tree (SET, "mode", "prog")) mode_stack= path (2, mode_stack);
446       }
447       else if (is_func (u, RESET)) {
448 	if (u == tree (RESET, "mode"))
449 	  if (!is_nil (mode_stack))
450 	    mode_stack= mode_stack->next;
451       }
452       else if (is_func (u, BEGIN, 1)) {
453 	if ((u[0] == "equation") ||
454 	    (u[0] == "equation*") ||
455 	    (u[0] == "eqnarray*") ||
456 	    (u[0] == "leqnarray*"))
457 	  mode_stack= path (1, mode_stack);
458       }
459       else if (is_func (u, END, 1)) {
460 	if ((u[0] == "equation") ||
461 	    (u[0] == "equation*") ||
462 	    (u[0] == "eqnarray*") ||
463 	    (u[0] == "leqnarray*"))
464 	  if (!is_nil (mode_stack))
465 	    mode_stack= mode_stack->next;
466       }
467       if (is_concat (t) && is_concat (u)) r << A(u);
468       else r << u;
469     }
470     return r;
471   }
472 }
473 
474 /******************************************************************************
475 * Upgrade lambda application -> macro expansion and value keyword
476 ******************************************************************************/
477 
478 tree
upgrade_apply_expand_value(tree t,hashset<string> H)479 upgrade_apply_expand_value (tree t, hashset<string> H) {
480   if (is_atomic (t)) return t;
481   else {
482     int i, n= arity (t);
483     tree r (t, n);
484     if (is_func (t, APPLY))
485       if ((n >= 1) && is_atomic (t[0]) && H->contains (t[0]->label)) {
486 	if (n == 1) r= tree (VALUE, n);
487 	else r= tree (EXPAND, n);
488       }
489     for (i=0; i<n; i++)
490       r[i]= upgrade_apply_expand_value (t[i], H);
491     return r;
492   }
493 }
494 
495 typedef const char* charp;
496 static charp apply_expand_value_strings[]= {
497   "part", "part*", "chapter", "chapter*", "appendix",
498   "section", "section*", "subsection", "subsection*",
499   "subsubsection", "subsubsection*",
500   "paragraph", "paragraph*", "subparagraph", "subparagraph*",
501   "footnote", "item*", "overline", "underline",
502   "mathord", "mathbin", "mathopen", "mathpunct",
503   "mathop", "mathrel", "mathclose", "mathalpha",
504   "op", "strong", "em", "tt", "name", "samp", "abbr",
505   "dfn", "kbd", "var", "acronym", "person",
506   "menu", "submenu", "subsubmenu", "tmdef", "tmref",
507   "key", "skey", "ckey", "akey", "mkey", "hkey",
508   "include-document", "include-project", "globalize-variable",
509   "localize-variable", "assign-variable",
510   "gb", "cgb", "gbt", "cgbt", "head", "tail", "hm", "tm", "binom",
511   //"ma", "mb", "md", "me", "mf", "mg", "mh", "mi", "mj", "mk",
512   //"mm", "mn", "mu", "mv", "mw", "my", "mz",
513   //"MA", "MB", "MD", "ME", "MF", "MG", "MH", "MI", "MJ", "MK",
514   //"MM", "MN", "MU", "MV", "MW", "MY", "MZ",
515   ""
516 };
517 
518 tree
upgrade_apply_expand_value(tree t)519 upgrade_apply_expand_value (tree t) {
520   int i;
521   hashset<string> H;
522   for (i=0; apply_expand_value_strings[i][0] != '\0'; i++)
523     H->insert (apply_expand_value_strings[i]);
524   return upgrade_apply_expand_value (t, H);
525 }
526 
527 /******************************************************************************
528 * Subroutines for upgrading set/reset -> with, begin/end -> apply
529 ******************************************************************************/
530 
531 static bool
matching(tree open,tree close)532 matching (tree open, tree close) {
533   if (is_func (open, SET, 2))
534     return is_func (close, RESET, 1) && (open[0] == close[0]);
535   if (is_func (open, BEGIN))
536     return is_func (close, END, 1) && (open[0] == close[0]);
537   return false;
538 }
539 
540 static tree
with_replace(tree var,tree val,tree body)541 with_replace (tree var, tree val, tree body) {
542   if (is_func (body, WITH)) {
543     int i, n= N(body);
544     tree t= tree (WITH, n+2);
545     t[0]= var;
546     t[1]= val;
547     for (i=0; i<n; i++) t[i+2]= body[i];
548     return t;
549   }
550   else return tree (WITH, var, val, body);
551 }
552 
553 static tree
expand_replace(tree begin,tree body)554 expand_replace (tree begin, tree body) {
555   int i, k= N(begin);
556   tree expand (EXPAND, k+1);
557   for (i=0; i<k; i++) expand[i]= begin[i];
558   expand[i]= body;
559   return expand;
560 }
561 
562 static void
concat_search(tree t,int & i,tree open="")563 concat_search (tree t, int& i, tree open= "") {
564   bool set_reset= (open == "") || is_func (open, SET) || is_func (open, RESET);
565   bool begin_end= (open == "") || is_func (open, BEGIN) || is_func (open, END);
566   int n= N(t);
567   while (i<n) {
568     if (set_reset && is_func (t[i], SET, 2)) return;
569     if (set_reset && is_func (t[i], RESET, 1)) return;
570     if (begin_end && is_func (t[i], BEGIN)) return;
571     if (begin_end && is_func (t[i], END, 1)) return;
572     i++;
573   }
574 }
575 
576 static tree
concat_replace(tree t,int i1,int i2)577 concat_replace (tree t, int i1, int i2) {
578   int i;
579   tree v (CONCAT);
580   for (i=i1+1; i<i2; i++) v << t[i];
581   if (N(v)==0) v= "";
582   else if (N(v)==1) v= v[0];
583   if (is_func (t[i1], SET))
584     return with_replace (t[i1][0], t[i1][1], v);
585   else return expand_replace (t[i1], v);
586 }
587 
588 static tree
document_explode(tree t)589 document_explode (tree t) {
590   int i, n= N(t);
591   tree u (t, n);
592   for (i=0; i<n; i++)
593     if (is_concat (t[i])) u[i]= t[i];
594     else u[i]= tree (CONCAT, t[i]);
595   return u;
596 }
597 
598 static tree
document_contract(tree t)599 document_contract (tree t) {
600   int i, n= N(t);
601   tree u (t, n);
602   for (i=0; i<n; i++)
603     if (N(t[i]) == 0) u[i]= "";
604     else if (N(t[i]) == 1) u[i]= t[i][0];
605     else u[i]= t[i];
606   return u;
607 }
608 
609 static void
document_search(tree t,int & i,int & j,tree open="")610 document_search (tree t, int& i, int& j, tree open= "") {
611   bool set_reset= (open == "") || is_func (open, SET) || is_func (open, RESET);
612   bool begin_end= (open == "") || is_func (open, BEGIN) || is_func (open, END);
613   int n= N(t);
614   while (i<n) {
615     int k= N(t[i]);
616     while (j<k) {
617       if (set_reset && is_func (t[i][j], SET, 2)) return;
618       if (set_reset && is_func (t[i][j], RESET, 1)) return;
619       if (begin_end && is_func (t[i][j], BEGIN)) return;
620       if (begin_end && is_func (t[i][j], END, 1)) return;
621       j++;
622     }
623     i++;
624     j=0;
625   }
626 }
627 
628 static void
document_inc(tree doc_t,int & doc_i,int & con_i)629 document_inc (tree doc_t, int& doc_i, int& con_i) {
630   con_i++;
631   if (con_i == N(doc_t[doc_i])) {
632     doc_i++;
633     con_i= 0;
634   }
635 }
636 
637 static void
document_inc(tree & doc,tree & con,tree doc_t,int & doc_i,int & con_i)638 document_inc (tree& doc, tree& con, tree doc_t, int& doc_i, int& con_i) {
639   con_i++;
640   if (con_i == N(doc_t[doc_i])) {
641     doc << con;
642     con= tree (CONCAT);
643     doc_i++;
644     con_i= 0;
645   }
646 }
647 
648 static void
document_merge(tree & doc,tree & con,tree doc_t,int doc_1,int con_1,int doc_2,int con_2)649 document_merge (tree& doc, tree& con, tree doc_t,
650 		int doc_1, int con_1, int doc_2, int con_2)
651 {
652   int doc_i= doc_1, con_i= con_1;
653   while ((doc_i<doc_2) || ((doc_i==doc_2) && (con_i<con_2))) {
654     con << doc_t[doc_i][con_i];
655     document_inc (doc, con, doc_t, doc_i, con_i);
656   }
657 }
658 
659 static tree
document_replace(tree doc_t,int doc_1,int con_1,int doc_2,int con_2)660 document_replace (tree doc_t, int doc_1, int con_1, int doc_2, int con_2) {
661   tree doc_b (DOCUMENT), con_b (CONCAT);
662   int doc_i= doc_1, con_i= con_1;
663   document_inc (doc_b, con_b, doc_t, doc_i, con_i);
664   document_merge (doc_b, con_b, doc_t, doc_i, con_i, doc_2, con_2);
665   doc_b << con_b;
666   doc_b= document_contract (doc_b);
667   bool flag= (doc_1!=doc_2) || ((con_1==0) && (con_2==N(doc_t[doc_2])-1));
668   /*
669   if (N(doc_b) != (doc_2-doc_1+1))
670     cout << (doc_2-doc_1+1) << ", " << doc_b << "\n";
671   */
672   if ((!flag) && (N(doc_b)==1)) doc_b= doc_b[0];
673   if (is_func (doc_t[doc_1][con_1], SET))
674     return with_replace (doc_t[doc_1][con_1][0],
675 			 doc_t[doc_1][con_1][1],
676 			 doc_b);
677   else return expand_replace (doc_t[doc_1][con_1], doc_b);
678 }
679 
680 /******************************************************************************
681 * Upgrade set/reset -> with, begin/end -> apply
682 ******************************************************************************/
683 
684 static tree upgrade_set_begin (tree t);
685 
686 static tree
upgrade_set_begin_default(tree t)687 upgrade_set_begin_default (tree t) {
688   int i, n= N(t);
689   tree u (t, n);
690   for (i=0; i<n; i++)
691     u[i]= upgrade_set_begin (t[i]);
692   return u;
693 }
694 
695 static tree
upgrade_set_begin_concat_once(tree t)696 upgrade_set_begin_concat_once (tree t) {
697   // cout << "in : " << t << "\n";
698   int i=0, n= N(t);
699   tree u (CONCAT);
700   while (i<n) {
701     int i0=i, i1, i2;
702     concat_search (t, i);
703     i1= i;
704     for (i=i0; i<i1; i++) u << t[i];
705     if (i==n) {
706       // cout << "  " << i0 << ", " << i1 << "\n";
707       break;
708     }
709     i++;
710     concat_search (t, i, t[i1]);
711     i2= i;
712     // cout << "  " << i0 << ", " << i1 << ", " << i2 << "\n";
713     if ((i2<n) && matching (t[i1], t[i2])) {
714       u << concat_replace (t, i1, i2);
715       i= i2+1;
716     }
717     else {
718       i= i1;
719       if (i == i0) u << t[i++];
720     }
721   }
722   // cout << "out: " << u << "\n";
723   // cout << "-------------------------------------------------------------\n";
724   // fflush (stdout);
725   return u;
726 }
727 
728 static tree
upgrade_set_begin_concat(tree t)729 upgrade_set_begin_concat (tree t) {
730   tree u= t;
731   do { t= u; u= upgrade_set_begin_concat_once (t); } while (u != t);
732   u= upgrade_set_begin_default (u);
733   if (N(u) == 1) return u[0];
734   return u;
735 }
736 
737 static void
upgrade_verbatim_expand(tree & doc,tree & con,tree ins)738 upgrade_verbatim_expand (tree& doc, tree& con, tree ins) {
739   tree& body= ins[N(ins)-1];
740   if (is_document (body) && (N(body)>1)) {
741     int n= N(body);
742     int start=0, end=n;
743     if (body[0] == "") start= 1;
744     if (body[n-1] == "") end= n-1;
745     body= body (start, end);
746     if (start != 0) {
747       doc << con;
748       con= tree (CONCAT);
749     }
750     con << ins;
751     if (end != n) {
752       doc << con;
753       con= tree (CONCAT);
754     }
755   }
756   else con << ins;
757 }
758 
759 static void
upgrade_abstract_expand(tree & doc,tree & con,tree ins)760 upgrade_abstract_expand (tree& doc, tree& con, tree ins) {
761   (void) doc;
762   tree& body= ins[N(ins)-1];
763   if (is_document (body) && (N(body) > 1) && (body[0] == ""))
764     body= body (1, N(body));
765   con << ins;
766 }
767 
768 static tree
upgrade_set_begin_document_once(tree doc_t)769 upgrade_set_begin_document_once (tree doc_t) {
770   // cout << "in : " << doc_t << "\n";
771   int doc_i=0, con_i=0;
772   tree doc (DOCUMENT), con (CONCAT);
773   while ((doc_i < N(doc_t)) && (con_i < N(doc_t[doc_i]))) {
774     int doc_0= doc_i, con_0= con_i;
775     document_search (doc_t, doc_i, con_i);
776     int doc_1= doc_i, con_1= con_i;
777     // cout << "  0: " << doc_0 << ", " << con_0 << "\n";
778     // cout << "  1: " << doc_1 << ", " << con_1 << "\n";
779     document_merge (doc, con, doc_t, doc_0, con_0, doc_1, con_1);
780     if (doc_i == N(doc_t)) break;
781     document_inc (doc_t, doc_i, con_i);
782     document_search (doc_t, doc_i, con_i, doc_t[doc_1][con_1]);
783     int doc_2= doc_i, con_2= con_i;
784     // cout << "  2: " << doc_2 << ", " << con_2 << "\n";
785     if ((doc_2 < N(doc_t)) &&
786 	matching (doc_t[doc_1][con_1], doc_t[doc_2][con_2]))
787       {
788 	tree ins= document_replace (doc_t, doc_1, con_1, doc_2, con_2);
789         // cout << "ins: " << ins << "\n";
790 	if (is_func (ins, EXPAND, 2)) {
791           if ((ins[0] == "verbatim") || (ins[0] == "code") ||
792               (upgrade_tex_flag && is_verbatim (compound (as_string(ins[0])))))
793 	    upgrade_verbatim_expand (doc, con, ins);
794 	  else if (ins[0] == "abstract")
795 	    upgrade_abstract_expand (doc, con, ins);
796 	  else con << ins;
797 	}
798         else if (is_func (ins, WITH) &&
799                  is_func (ins[N(ins)-1], DOCUMENT, 1)) {
800           ins[N(ins)-1]= ins[N(ins)-1][0];
801           con << ins;
802         }
803 	else con << ins;
804 	document_inc (doc, con, doc_t, doc_i, con_i);
805       }
806     else {
807       doc_i= doc_1; con_i= con_1;
808       if ((doc_i == doc_0) && (con_i == con_0)) {
809 	con << doc_t[doc_i][con_i];
810 	document_inc (doc, con, doc_t, doc_i, con_i);
811       }
812     }
813   }
814   // cout << "out: " << doc << "\n";
815   // cout << "-------------------------------------------------------------\n";
816   fflush (stdout);
817   return doc;
818 }
819 
820 static tree
upgrade_set_begin_document(tree t)821 upgrade_set_begin_document (tree t) {
822   tree u= t;
823   do {
824     t= u;
825     u= document_explode (u);
826     u= upgrade_set_begin_document_once (u);
827     u= document_contract (u);
828   } while (u != t);
829   u= upgrade_set_begin_default (u);
830   return u;
831 }
832 
833 static tree
upgrade_set_begin_surround(tree t,tree search,bool & found)834 upgrade_set_begin_surround (tree t, tree search, bool& found) {
835   if (t == search) {
836     found= true;
837     if (upgrade_tex_flag)
838       return tree (DOCUMENT, copy (t));
839     return copy (t);
840   }
841   if (is_func (t, WITH) || is_func (t, EXPAND)) {
842     tree u= copy (t);
843     u[N(u)-1]= upgrade_set_begin_surround (u[N(u)-1], search, found);
844     return u;
845   }
846   if (is_concat (t)) {
847     int i, n= N(t), searching= !found;
848     tree left (CONCAT), middle, right (CONCAT);
849     for (i=0; i<n; i++) {
850       middle= upgrade_set_begin_surround (t[i], search, found);
851       if (searching && found) break;
852       else left << middle;
853     }
854     if (i==n) return copy (t);
855     for (i++; i<n; i++)
856       right << upgrade_set_begin_surround (t[i], search, found);
857     if (N(left) == 0) left= "";
858     else if (N(left) == 1) left= left[0];
859     if (N(right) == 0) right= "";
860     else if (N(right) == 1) right= right[0];
861     return tree (SURROUND, left, right, middle);
862   }
863   return copy (t);
864 }
865 
866 static tree
upgrade_env_args(tree t,tree env)867 upgrade_env_args (tree t, tree env) {
868   if (is_atomic (t)) return t;
869   else if (is_func (t, APPLY, 1)) {
870     int i, k= N(env);
871     for (i=0; i<k-2; i++)
872       if (t[0] == env[i])
873 	return tree (ARG, t[0]);
874     return t;
875   }
876   else {
877     int i, n= N(t);
878     tree r (t, n);
879     for (i=0; i<n; i++)
880       r[i]= upgrade_env_args (t[i], env);
881     return r;
882   }
883 }
884 
885 static tree
upgrade_set_begin_env(tree t)886 upgrade_set_begin_env (tree t) {
887   //cout << "in  : " << t << "\n";
888   int i, n= N(t);
889   tree u (MACRO, n);
890   for (i=0; i<n-2; i++)
891     u[i]= upgrade_set_begin (t[i]);
892   string s= "body";
893   for (i=0; i<n-2; i++)
894     if (t[i] == "body") s= "body*";
895   u[n-2]= copy (s);
896 
897   tree begin= t[n-2], end= t[n-1], body (CONCAT);
898   if (begin == "") begin= tree (CONCAT);
899   else if (!is_concat (begin)) begin= tree (CONCAT, begin);
900   if (end == "") end= tree (CONCAT);
901   else if (!is_concat (end)) end= tree (CONCAT, end);
902   body << A(begin) << tree (ARG, copy (s)) << A(end);
903   //cout << "mid1: " << body << "\n";
904   body= upgrade_set_begin_concat (body);
905   body= upgrade_env_args (body, t);
906   //cout << "mid2: " << body << "\n";
907   bool found= false;
908   u[n-1]= upgrade_set_begin_surround (body, tree (ARG, s), found);
909   //cout << "out : " << u << "\n";
910   //cout << "-------------------------------------------------------------\n";
911   return u;
912 }
913 
914 static tree
upgrade_set_begin(tree t)915 upgrade_set_begin (tree t) {
916   if (is_atomic (t)) return copy (t);
917   else {
918     if (is_concat (t)) return upgrade_set_begin_concat (t);
919     else if (is_document (t)) return upgrade_set_begin_document (t);
920     else if (is_func (t, ENV)) return upgrade_set_begin_env (t);
921     else return upgrade_set_begin_default (t);
922   }
923 }
924 
925 static tree
eliminate_set_begin(tree t)926 eliminate_set_begin (tree t) {
927   if (is_atomic (t)) return t;
928   if (is_func (t, SET) || is_func (t, RESET) ||
929       is_func (t, BEGIN) || is_func (t, END) ||
930       is_func (t, ENV)) return "";
931 
932   int i, n= N(t);
933   if (is_concat (t)) {
934     tree r (CONCAT);
935     for (i=0; i<n; i++) {
936       tree u= eliminate_set_begin (t[i]);
937       if (u != "") r << u;
938     }
939     if (N(r) == 0) return "";
940     if (N(r) == 1) return r[0];
941     return r;
942   }
943   else {
944     tree r (t, n);
945     for (i=0; i<n; i++)
946       r[i]= eliminate_set_begin (t[i]);
947     return r;
948   }
949 }
950 
951 /******************************************************************************
952 * Upgrade surround, indentation after and final routine
953 ******************************************************************************/
954 
955 bool
expand_needs_surrounding(string s)956 expand_needs_surrounding (string s) {
957   return
958     (s == "maketitle") || (s == "abstract") ||
959     (s == "theorem") || (s == "proposition") || (s == "lemma") ||
960     (s == "corollary") || (s == "proof") || (s == "axiom") ||
961     (s == "definition") || (s == "notation") || (s == "conjecture") ||
962     (s == "remark") || (s == "note") || (s == "example") ||
963     (s == "exercise") || (s == "warning") ||
964     (s == "convention") || (s == "acknowledgments") ||
965     (s == "code") || (s == "quote") ||
966     (s == "quotation") || (s == "verse") || (s == "center") ||
967     (s == "indent") || (s == "body") || (s == "description") ||
968     starts (s, "itemize") || starts (s, "enumerate");
969 }
970 
971 static bool
with_needs_surrounding(string s)972 with_needs_surrounding (string s) {
973   return
974     (s == "paragraph mode") || (s == "paragraph hyphenation") ||
975     (s == "paragraph width") || (s == "left margin") ||
976     (s == "right margin") || (s == "first indentation") ||
977     (s == "last indentation") || (s == "no first indentation") ||
978     (s == "no last indentation") || (s == "interline space") ||
979     (s == "horizontal ink separation") || (s == "line stretch") ||
980     (s == "interparagraph space");
981 }
982 
983 static bool
needs_surrounding(tree t)984 needs_surrounding (tree t) {
985   if (is_multi_paragraph (t)) return true;
986   if ((is_func (t, APPLY) || is_func (t, EXPAND)) && is_atomic (t[0])) {
987     if (t[0] == "verbatim") return (N(t)==2) && is_multi_paragraph (t[1]);
988     return expand_needs_surrounding (t[0]->label);
989   }
990   if (is_func (t, WITH)) {
991     int i, n= N(t)-1;
992     for (i=0; i<n; i+=2)
993       if (is_atomic (t[i]) && with_needs_surrounding (t[i]->label))
994 	return true;
995   }
996   return false;
997 }
998 
999 static bool
needs_transfer(tree t)1000 needs_transfer (tree t) {
1001   return
1002     is_func (t, EXPAND, 2) &&
1003     ((t[0] == "equation") || (t[0] == "equation*") ||
1004      (t[0] == "eqnarray*") || (t[0] == "leqnarray*"));
1005 }
1006 
1007 static tree
upgrade_surround(tree t)1008 upgrade_surround (tree t) {
1009   if (upgrade_tex_flag || is_atomic (t)) return t;
1010   int i, n= N(t);
1011   tree r (t, n);
1012   for (i=0; i<n; i++) {
1013     tree u= t[i];
1014     if (is_document (t) && is_concat (u) && (N(u)>1)) {
1015       int j, k= N(u);
1016       for (j=0; j<k; j++)
1017 	if (needs_surrounding (u[j])) {
1018 	  tree before= u (0  , j);
1019 	  tree after = u (j+1, k);
1020 	  tree body  = upgrade_surround (u[j]);
1021 	  if (N(before)==0) before= "";
1022 	  if (N(before)==1) before= before[0];
1023 	  if (N(after )==0) after = "";
1024 	  if (N(after )==1) after = after [0];
1025 	  before= upgrade_surround (before);
1026 	  after = upgrade_surround (after );
1027 	  r[i]= tree (SURROUND, before, after, body);
1028 	  break;
1029 	}
1030 	else if (needs_transfer (u[j])) {
1031 	  tree temp= upgrade_surround (u[j][1]);
1032 	  if (!is_concat (temp)) temp= tree (CONCAT, temp);
1033 	  tree body= u (0, j);
1034 	  body << A (temp) << A (u (j+1, k));
1035 	  r[i]= tree (EXPAND, u[j][0], body);
1036 	  break;
1037 	}
1038       if (j<k) continue;
1039     }
1040     r[i]= upgrade_surround (u);
1041   }
1042   return r;
1043 }
1044 
1045 static tree
upgrade_indent(tree t)1046 upgrade_indent (tree t) {
1047   if (is_atomic (t)) return t;
1048   else if (t == tree (ASSIGN, "no first indentation", "true"))
1049     return tree (FORMAT, "no indentation after");
1050   else if (t == tree (ASSIGN, "no first indentation", "false"))
1051     return tree (FORMAT, "enable indentation after");
1052   else {
1053     int i, n= N(t);
1054     tree r (t, n);
1055     for (i=0; i<n; i++)
1056       r[i]= upgrade_indent (t[i]);
1057     return r;
1058   }
1059 }
1060 
1061 static tree
upgrade_equations(tree t)1062 upgrade_equations (tree t) {
1063   if (!upgrade_tex_flag || is_atomic (t)) return t;
1064   else if (needs_transfer (t) && !is_document (t[1])) {
1065     t[1]= document (upgrade_equations (t[1]));
1066     return t;
1067   }
1068   else {
1069     int i, n= N(t);
1070     tree r (t, n);
1071     for (i=0; i<n; i++)
1072       r[i]= upgrade_equations (t[i]);
1073     return r;
1074   }
1075 }
1076 
1077 static tree
upgrade_new_environments(tree t)1078 upgrade_new_environments (tree t) {
1079   t= upgrade_set_begin (t);
1080   t= eliminate_set_begin (t);
1081   t= upgrade_surround (t);
1082   t= upgrade_indent (t);
1083   t= upgrade_equations (t);
1084   return t;
1085 }
1086 
1087 /******************************************************************************
1088 * Upgrade items
1089 ******************************************************************************/
1090 
1091 static tree
upgrade_items(tree t)1092 upgrade_items (tree t) {
1093   if (is_atomic (t)) return t;
1094   else if ((t == tree (APPLY, "item")) || (t == tree (VALUE, "item")))
1095     return tree (EXPAND, "item");
1096   else {
1097     int i, n= N(t);
1098     tree r (t, n);
1099     for (i=0; i<n; i++)
1100       r[i]= upgrade_items (t[i]);
1101     return r;
1102   }
1103 }
1104 
1105 /******************************************************************************
1106 * Upgrade resize
1107 ******************************************************************************/
1108 
1109 static tree
upgrade_resize_arg(tree t,int type)1110 upgrade_resize_arg (tree t, int type) {
1111   if (!is_atomic (t)) return "";
1112   string s= t->label;
1113   if ((s == "same") || (s == "ink")) return "";
1114   if (type == 1) s= "l[" * s;
1115   if (type == 2) s= "b[" * s;
1116   if (type == 3) s= "r]" * s;
1117   if (type == 4) s= "t]" * s;
1118   return s;
1119 }
1120 
1121 static tree
upgrade_resize(tree t)1122 upgrade_resize (tree t) {
1123   if (is_atomic (t)) return t;
1124   else if (is_func (t, RESIZE, 6)) {
1125     tree r (RESIZE, t[0]);
1126     int extend= (t[1] == "extend"? 1: 0);
1127     r << upgrade_resize_arg (t[2], 1 * extend)
1128       << upgrade_resize_arg (t[3], 2 * extend)
1129       << upgrade_resize_arg (t[4], 3 * extend)
1130       << upgrade_resize_arg (t[5], 4 * extend);
1131     return r;
1132   }
1133   else {
1134     int i, n= N(t);
1135     tree r (t, n);
1136     for (i=0; i<n; i++)
1137       r[i]= upgrade_resize (t[i]);
1138     return r;
1139   }
1140 }
1141 
1142 /******************************************************************************
1143 * Upgrade tables
1144 ******************************************************************************/
1145 
1146 static void
handle_mosaic_format(tree & fm,tree t,int i,int j)1147 handle_mosaic_format (tree& fm, tree t, int i, int j) {
1148   string align = as_string (t[1]);
1149   string hspan = as_string (t[2]);
1150   string vspan = as_string (t[3]);
1151   string col   = as_string (t[4]);
1152 
1153   string halign= "l";
1154   string valign= "B";
1155   if (N(align)>=2) {
1156     switch (align[0]) {
1157     case 'n': valign= "t"; break;
1158     case 'c': valign= "c"; break;
1159     case '0': valign= "B"; break;
1160     case 's': valign= "s"; break;
1161     }
1162     switch (align[1]) {
1163     case 'w': halign= "l"; break;
1164     case '0': halign= "L"; break;
1165     case 'c': halign= "c"; break;
1166     case 'e': halign= "r"; break;
1167     }
1168   }
1169   if ((col == "none") || (col == "")) col= "";
1170   else col= "foreground";
1171 
1172   tree w (CWITH);
1173   w << as_string (i+1) << as_string (j+1)
1174     << as_string (i+1) << as_string (j+1);
1175 
1176   if (halign != "l") {
1177     tree with= copy (w);
1178     with << "cell halign" << halign;
1179     fm << with;
1180   }
1181   if (valign != "B") {
1182     tree with= copy (w);
1183     with << "cell valign" << valign;
1184     fm << with;
1185   }
1186   if (hspan != "1") {
1187     tree with= copy (w);
1188     with << "cell hspan" << hspan;
1189     fm << with;
1190   }
1191   if (vspan != "1") {
1192     tree with= copy (w);
1193     with << "cell vspan" << vspan;
1194     fm << with;
1195   }
1196   if (col != "") {
1197     tree with= copy (w);
1198     with << "cell background" << col;
1199     fm << with;
1200   }
1201 }
1202 
1203 
1204 static tree
upgrade_table(tree t)1205 upgrade_table (tree t) {
1206   if (is_atomic (t)) return t;
1207   else if (is_func (t, OLD_MATRIX) ||
1208 	   is_func (t, OLD_TABLE) ||
1209 	   is_func (t, OLD_MOSAIC) ||
1210 	   (is_func (t, TFORMAT) && is_func (t[N(t)-1], OLD_MATRIX)))
1211     {
1212       tree ft (TFORMAT);
1213       if (is_func (t, TFORMAT)) {
1214 	ft= t (0, N(t)-1);
1215 	t = t [N(t)-1];
1216       }
1217       if (is_func (t, OLD_MOSAIC)) {
1218 	tree with (CWITH);
1219 	with << "1" << "-1" << "1" << "-1" << "cell mode" << "c";
1220 	ft << with;
1221       }
1222 
1223       int i, j;
1224       int nr_rows= as_int (t[N(t)-1]);
1225       int nr_cols= as_int (t[N(t)-2]);
1226       tree tt (TABLE, nr_rows);
1227       for (i=0; i<nr_rows; i++) {
1228 	tree rt (ROW, nr_cols);
1229 	for (j=0; j<nr_cols; j++) {
1230 	  tree c= upgrade_table (t[i*nr_cols+j]);
1231 	  if (is_func (c, OLD_MOSAIC_ITEM)) {
1232 	    handle_mosaic_format (ft, c, i, j);
1233 	    c= c[0];
1234 	  }
1235 	  rt[j]= tree (CELL, c);
1236 	}
1237 	tt[i]= rt;
1238       }
1239 
1240       ft << tt;
1241       tree xt (EXPAND, "tabular*", ft);
1242       if (is_func (t, OLD_TABLE)) xt[0]= "block*";
1243       if (is_func (t, OLD_MOSAIC)) xt[0]= "tabular";
1244       return xt;
1245     }
1246   else {
1247     int i, n= N(t);
1248     tree r (t, n);
1249     for (i=0; i<n; i++)
1250       r[i]= upgrade_table (t[i]);
1251     return r;
1252   }
1253 }
1254 
1255 /******************************************************************************
1256 * Upgrade splits
1257 ******************************************************************************/
1258 
1259 static tree
upgrade_split(tree t,bool eq=false)1260 upgrade_split (tree t, bool eq= false) {
1261   int i, n= N(t);
1262   if (is_atomic (t)) return t;
1263   else if (is_func (t, SURROUND, 3) && is_func (t[0], SPLIT)) {
1264     tree u= t[2];
1265     if (!is_concat (u)) u= tree (CONCAT, t[0], u);
1266     else u= tree (CONCAT, t[0]) * u;
1267     return tree (SURROUND, "", upgrade_split (t[1]), upgrade_split (u));
1268   }
1269   else if (is_func (t, SURROUND, 3) && is_concat (t[0])) {
1270     tree r (CONCAT);
1271     tree split ("");
1272     for (i=0; i<N(t[0]); i++)
1273       if (is_func (t[0][i], SPLIT)) split= t[0][i];
1274       else r << t[0][i];
1275     tree u= t[2];
1276     if (split != "") {
1277       if (!is_concat (u)) u= tree (CONCAT, split, u);
1278       else u= tree (CONCAT, split) * u;
1279     }
1280     r= tree (SURROUND, upgrade_split (r),
1281 	     upgrade_split (t[1]), upgrade_split (u));
1282     return r;
1283   }
1284   else if (is_concat (t)) {
1285     tree r (CONCAT);
1286     tree split ("");
1287     int nr_rows=1, nr_cols=1, sep=1;
1288     for (i=0; i<n; i++)
1289       if (is_func (t[i], SPLIT)) split= t[i];
1290       else {
1291 	tree u= upgrade_split (t[i]);
1292 	if (u == tree (FORMAT, "line separator")) sep++;
1293 	if (u == tree (FORMAT, "next line")) {
1294 	  nr_cols= max (sep, nr_cols);
1295 	  sep= 1;
1296 	  nr_rows++;
1297 	}
1298 	r << u;
1299       }
1300     nr_cols= max (sep, nr_cols);
1301     if (split == "" && nr_cols == 1 && !eq) return r;
1302     else {
1303       int col=0, row=0;
1304       tree T (TABLE, nr_rows);
1305       for (row=0; row<nr_rows; row++) {
1306 	tree R (ROW, nr_cols);
1307 	for (col=0; col<nr_cols; col++) R[col]= tree (CELL, "");
1308 	T[row]= R;
1309       }
1310 
1311       tree u (CONCAT);
1312       row= col= 0;
1313       for (i=0; i<N(r); i++)
1314 	if ((r[i] == tree (FORMAT, "line separator")) ||
1315 	    (r[i] == tree (FORMAT, "next line")))
1316 	  {
1317 	    if (N(u) == 0) u= "";
1318 	    else if (N(u) == 1) u= u[0];
1319 	    T[row][col][0]= u;
1320 	    u= tree (CONCAT);
1321 	    if (r[i] == tree (FORMAT, "line separator")) col++;
1322 	    else {
1323 	      row++;
1324 	      col= 0;
1325 	    }
1326 	  }
1327 	else u << r[i];
1328       if (N(u) == 0) u= "";
1329       else if (N(u) == 1) u= u[0];
1330       T[row][col][0]= u;
1331       r= T;
1332     }
1333 
1334     tree tf (TFORMAT);
1335     if (split != "") {
1336       tf << tree (TWITH, "table hyphen", "y")
1337 	 << tree (TWITH, "table width", "1par")
1338 	 << tree (TWITH, "table min cols", as_string (N (split)))
1339 	 << tree (TWITH, "table max cols", as_string (N (split)))
1340 	 << tree (CWITH, "1", "-1", "1", "1", "cell lsep", "0spc")
1341 	 << tree (CWITH, "1", "-1", "-1", "-1", "cell rsep", "0spc")
1342 	 << tree (CWITH, "1", "-1", "1", "-1", "cell bsep", "0sep")
1343 	 << tree (CWITH, "1", "-1", "1", "-1", "cell tsep", "0sep")
1344 	 << tree (CWITH, "1", "-1", "1", "1", "cell hyphen", "b")
1345 	 << tree (CWITH, "1", "-1", "-1", "-1", "cell hyphen", "t");
1346       if (split[0] == "right")
1347 	tf << tree (CWITH, "1", "-1", "1", "1", "cell hpart", "1");
1348       if ((split[N(split)-1] == "left") || (split[N(split)-1] == "justify"))
1349 	tf << tree (CWITH, "1", "-1", "-1", "-1", "cell hpart", "1");
1350       for (i=0; i<N(split); i++) {
1351 	tree with (CWITH);
1352 	int j= (i==N(split)-1)? -1: i+1;
1353 	with << "1" << "-1" << as_string (j) << as_string (j) << "cell halign";
1354 	if (split[i] == "right") with << "r";
1355 	else if (split[i] == "center") with << "c";
1356 	else with << "l";
1357 	tf << with;
1358       }
1359     }
1360     if (r == tree (CONCAT)) r= "";
1361     else if (is_func (r, CONCAT, 1)) r= r[0];
1362     tf << r;
1363     if ((split != "") && is_func (r, TABLE))
1364       return tree (EXPAND, "tabular*", tf);
1365     return tf;
1366   }
1367   else {
1368     tree r (t, n);
1369     if (n == 1 || is_func (t, EXPAND, 2)) {
1370       string s= as_string (L(t));
1371       if (is_func (t, EXPAND, 2) && is_atomic (t[0])) s= t[0]->label;
1372       if (ends (s, "*")) s= s (0, N(s)-1);
1373       if (s == "eqnarray" || s == "align" || s == "multline" ||
1374           s == "gather" || s == "eqsplit") {
1375         tree arg= t[n-1];
1376         if (is_func (arg, DOCUMENT, 1)) arg= arg[0];
1377         if (!is_concat (arg)) arg= tree (CONCAT, arg);
1378         r= copy (t);
1379         r[n-1]= upgrade_split (arg, true);
1380         return r;
1381       }
1382     }
1383     else if (upgrade_tex_flag && (n == 2 || is_func (t, EXPAND, 3))) {
1384       string s= as_string (L(t));
1385       if (is_func (t, EXPAND, 3) && is_atomic (t[0])) s= t[0]->label;
1386       if (ends (s, "*")) s= s (0, N(s)-1);
1387       if (s == "alignat") {
1388         tree arg= t[n-1];
1389         if (is_func (arg, DOCUMENT, 1)) arg= arg[0];
1390         if (!is_concat (arg)) arg= tree (CONCAT, arg);
1391         r= copy (t);
1392         r[n-1]= upgrade_split (arg, true);
1393         return r;
1394       }
1395     }
1396     for (i=0; i<n; i++)
1397       r[i]= upgrade_split (t[i]);
1398     return r;
1399   }
1400 }
1401 
1402 /******************************************************************************
1403 * Upgrade projects
1404 ******************************************************************************/
1405 
1406 static tree
upgrade_project(tree t)1407 upgrade_project (tree t) {
1408   if (is_atomic (t)) return t;
1409   else if (is_expand (t, "include-document", 1))
1410     return tree (VAR_INCLUDE, t[1]);
1411   else {
1412     int i, n= N(t);
1413     tree r (t, n);
1414     for (i=0; i<n; i++)
1415       r[i]= upgrade_project (t[i]);
1416     return r;
1417   }
1418 }
1419 
1420 /******************************************************************************
1421 * Upgrade title
1422 ******************************************************************************/
1423 
1424 static tree
upgrade_title(tree t,tree & tit,tree & auth,tree & meta)1425 upgrade_title (tree t, tree& tit, tree& auth, tree& meta) {
1426   if (is_atomic (t)) return t;
1427   else if (is_func (t, APPLY, 2) ||
1428            is_func (t, EXPAND, 2)) {
1429     if (t[0] == "title") {
1430       tit << tree (EXPAND, "title", t[1]); return ""; }
1431     if (t[0] == "author") {
1432       auth << tree (EXPAND, "author", t[1]); return ""; }
1433     if (t[0] == "address") {
1434       auth << tree (EXPAND, "address", t[1]); return ""; }
1435     if (t[0] == "urladdr") {
1436       auth << tree (EXPAND, "title-web", t[1]); return ""; }
1437     if (t[0] == "title-email") {
1438       auth << tree (EXPAND, "title-email", t[1]); return ""; }
1439     if (t[0] == "title-thanks") {
1440       meta << tree (EXPAND, "title-thanks", t[1]); return ""; }
1441     if (t[0] == "keywords") {
1442       meta << tree (EXPAND, "title-keywords", t[1]); return ""; }
1443     if (t[0] == "subjclass") {
1444       meta << tree (EXPAND, "title-ams-class", t[1]); return ""; }
1445     if (t[0] == "classification") {
1446       meta << tree (EXPAND, "title-ams-class", t[1]); return ""; }
1447   }
1448   else if (is_func (t, APPLY, 3) ||
1449            is_func (t, EXPAND, 3)) {
1450     if (t[0] == "subjclass*") {
1451       meta << tree (EXPAND, "title-ams-class", t[2]); return ""; }
1452   }
1453   else if ((t == tree (APPLY, "maketitle")) ||
1454 	   (t == tree (EXPAND, "maketitle")))
1455     {
1456       tree doc (DOCUMENT);
1457       doc << A (tit);
1458       doc << A (auth);
1459       doc << A (meta);
1460       doc << tree (EXPAND, "title-date", tree (_DATE, ""));
1461       return tree (EXPAND, "make-title", doc);
1462     }
1463 
1464   int i, n= N(t);
1465   tree r (t, n);
1466   for (i=0; i<n; i++)
1467     r[i]= upgrade_title (t[i], tit, auth, meta);
1468   return r;
1469 }
1470 
1471 static tree
upgrade_title(tree t)1472 upgrade_title (tree t) {
1473   tree tit (DOCUMENT), auth (DOCUMENT), meta (DOCUMENT);
1474   return simplify_correct (upgrade_title (t, tit, auth, meta));
1475 }
1476 
1477 /******************************************************************************
1478 * Upgrade cas
1479 ******************************************************************************/
1480 
1481 static void
upgrade_cas_search(tree t,tree & style)1482 upgrade_cas_search (tree t, tree& style) {
1483   if (is_atomic (t));
1484   else if (is_expand (t, "session", 3)) {
1485     if (!is_atomic (t[1])) return;
1486     string l= copy (t[1]->label);
1487     if (l == "scheme") return;
1488     if (l == "shell") return;
1489     if (l == "gTybalt") l= "gtybalt";
1490     if (l == "Macaulay2") l= "macaulay2";
1491     int i, n= N(style);
1492     for (i=0; i<n; i++)
1493       if (style[i] == l) return;
1494     style << l;
1495   }
1496   else {
1497     int i, n= N(t);
1498     for (i=0; i<n; i++)
1499       upgrade_cas_search (t[i], style);
1500   }
1501 }
1502 
1503 static void
set_document_attribute(tree doc,string attr,tree val)1504 set_document_attribute (tree doc, string attr, tree val) {
1505   int i, n= arity (doc);
1506   for (i=0; i<n; i++)
1507     if ((is_func (doc[i], EXPAND, 2) || is_func (doc[i], APPLY, 2)) &&
1508 	(doc[i][0] == attr))
1509       {
1510 	doc[i][1]= val;
1511 	return;
1512       }
1513   doc << tree (EXPAND, attr, val);
1514 }
1515 
1516 static tree
upgrade_cas(tree doc)1517 upgrade_cas (tree doc) {
1518   tree style= copy (extract (doc, "style"));
1519   upgrade_cas_search (doc, style);
1520   doc= copy (doc);
1521   set_document_attribute (doc, "style", style);
1522   return doc;
1523 }
1524 
1525 /******************************************************************************
1526 * Upgrade modified symbols
1527 ******************************************************************************/
1528 
1529 static bool
is_with(tree t,string var,string val)1530 is_with (tree t, string var, string val) {
1531   return is_func (t, WITH, 3) && (t[0] == var) && (t[1] == val);
1532 }
1533 
1534 static bool
is_alpha(tree t)1535 is_alpha (tree t) {
1536   if (is_compound (t)) return false;
1537   string s= t->label;
1538   return (N(s) == 1) && is_alpha (s[0]);
1539 }
1540 
1541 static bool
is_alpha_numeric(tree t)1542 is_alpha_numeric (tree t) {
1543   if (is_compound (t)) return false;
1544   string s= t->label;
1545   return (N(s) == 1) && (is_alpha (s[0]) || is_numeric (s[0]));
1546 }
1547 
1548 static bool
is_upper(tree t)1549 is_upper (tree t) {
1550   if (is_compound (t)) return false;
1551   string s= t->label;
1552   return (N(s) == 1) && (s[0] >= 'A') && (s[0] <= 'Z');
1553 }
1554 
1555 static bool
is_bold(tree t)1556 is_bold (tree t) {
1557   if (is_compound (t)) return false;
1558   if (is_alpha_numeric (t)) return true;
1559   string s= locase_all (t->label);
1560   return
1561     (s == "<alpha>") || (s == "<beta>") || (s == "<gamma>") ||
1562     (s == "<delta>") || (s == "<epsilon>") || (s == "<zeta>") ||
1563     (s == "<eta>") || (s == "<theta>") || (s == "<iota>") ||
1564     (s == "<kappa>") || (s == "<lambda>") || (s == "<mu>") ||
1565     (s == "<nu>") || (s == "<xi>") || (s == "<omicron>") ||
1566     (s == "<pi>") || (s == "<rho>") || (s == "<sigma>") ||
1567     (s == "<tau>") || (s == "<upsilon>") || (s == "<phi>") ||
1568     (s == "<psi>") || (s == "<chi>") || (s == "<omega>") ||
1569     (s == "<varepsilon>") || (s == "<vartheta>") || (s == "<varkappa>") ||
1570     (s == "<varpi>") || (s == "<varrho>") || (s == "<varsigma>") ||
1571     (s == "<varphi>") || (s == "<backepsilon>") || (s == "<mho>") ||
1572     (s == "<Backepsilon>") || (s == "<Mho>") || (s == "<ell>");
1573 }
1574 
1575 static tree
upgrade_mod_symbol(string prefix,string s)1576 upgrade_mod_symbol (string prefix, string s) {
1577   if (N(s) == 1) return "<" * prefix * s * ">";
1578   else return "<" * prefix * s (1, N(s)-1) * ">";
1579 }
1580 
1581 static tree
upgrade_mod_symbols(tree t)1582 upgrade_mod_symbols (tree t) {
1583   if (is_atomic (t)) return t;
1584   if (is_with (t, "math font series", "bold") && is_bold (t[2]))
1585     return upgrade_mod_symbol ("b-", t[2]->label);
1586   else if (is_with (t, "math font", "cal") && is_upper (t[2]))
1587     return upgrade_mod_symbol ("cal-", t[2]->label);
1588   else if (is_with (t, "math font", "Euler") && is_alpha (t[2]))
1589     return upgrade_mod_symbol ("frak-", t[2]->label);
1590   else if (is_with (t, "math font", "Bbb*") && is_alpha (t[2]))
1591     return upgrade_mod_symbol ("bbb-", t[2]->label);
1592   else if (is_with (t, "math font series", "bold") &&
1593 	   is_with (t[2], "math font", "cal") && is_upper (t[2][2]))
1594     return upgrade_mod_symbol ("b-cal-", t[2][2]->label);
1595   else if (is_with (t, "math font", "cal") &&
1596 	   is_with (t[2], "math font series", "bold") && is_upper (t[2][2]))
1597     return upgrade_mod_symbol ("b-cal-", t[2][2]->label);
1598   //else if ((is_func (t, VALUE, 1) || is_func (t, EXPAND, 1) ||
1599   //         is_func (t, APPLY, 1)) && (is_atomic (t[0]))) {
1600   //  string s= t[0]->label;
1601   //  if ((N(s) == 2) && ((s[0]=='m') && (s[1]>='a') && s[1]<='z'))
1602   //    return upgrade_mod_symbol ("frak-", s(1,2));
1603   //  if ((N(s) == 2) && ((s[0]=='M') && (s[1]>='A') && s[1]<='Z'))
1604   //    return upgrade_mod_symbol ("frak-", s(1,2));
1605   //  return t;
1606   //}
1607   else {
1608     int i, n= N(t);
1609     tree r (t, n);
1610     for (i=0; i<n; i++)
1611       r[i]= upgrade_mod_symbols (t[i]);
1612     return r;
1613   }
1614 }
1615 
1616 /******************************************************************************
1617 * Upgrading menus in the help
1618 ******************************************************************************/
1619 
1620 static tree
upgrade_menus_in_help(tree t)1621 upgrade_menus_in_help (tree t) {
1622   if (is_atomic (t)) return t;
1623   if (is_expand (t, "menu", 1) || is_expand (t, "submenu", 2) ||
1624       is_expand (t, "subsubmenu", 3) || is_expand (t, "subsubsubmenu", 4)) {
1625     int i, n= N(t);
1626     tree r (APPLY, n);
1627     r[0]= "menu";
1628     for (i=1; i<n; i++) r[i]= t[i];
1629     return r;
1630   }
1631   else {
1632     int i, n= N(t);
1633     tree r (t, n);
1634     for (i=0; i<n; i++)
1635       r[i]= upgrade_menus_in_help (t[i]);
1636     return r;
1637   }
1638 }
1639 
1640 static tree
capitalize_sub(tree t)1641 capitalize_sub (tree t) {
1642   if (is_atomic (t)) return upcase_first (t->label);
1643   else return t;
1644 }
1645 
1646 static tree
upgrade_capitalize_menus(tree t)1647 upgrade_capitalize_menus (tree t) {
1648   if (is_atomic (t)) return t;
1649   if (is_func (t, APPLY) && (t[0] == "menu")) {
1650     int i, n= N(t);
1651     tree r (APPLY, n);
1652     r[0]= "menu";
1653     for (i=1; i<n; i++) r[i]= capitalize_sub (t[i]);
1654     return r;
1655   }
1656   else {
1657     int i, n= N(t);
1658     tree r (t, n);
1659     for (i=0; i<n; i++)
1660       r[i]= upgrade_capitalize_menus (t[i]);
1661     return r;
1662   }
1663 }
1664 
1665 /******************************************************************************
1666 * Upgrade branches
1667 ******************************************************************************/
1668 
1669 static tree
upgrade_traverse_branch(tree t)1670 upgrade_traverse_branch (tree t) {
1671   if (is_atomic (t)) return t;
1672   else if (is_expand (t, "branch", 3) ||
1673 	   (is_func (t, APPLY, 4) && (t[0] == "branch")))
1674     return tree (APPLY, t[0], t[1], t[3]);
1675   else {
1676     int i, n= N(t);
1677     tree r (t, n);
1678     for (i=0; i<n; i++)
1679       r[i]= upgrade_traverse_branch (t[i]);
1680     return r;
1681   }
1682 }
1683 
1684 /******************************************************************************
1685 * Upgrade sessions
1686 ******************************************************************************/
1687 
1688 static tree
upgrade_session(tree t)1689 upgrade_session (tree t) {
1690   if (is_atomic (t)) return t;
1691   else if (is_expand (t, "session", 3)) {
1692     tree u= tree (EXPAND, "session", t[3]);
1693     tree w= tree (WITH);
1694     w << PROG_LANGUAGE << t[1] << PROG_SESSION << t[2] << u;
1695     return w;
1696   }
1697   else {
1698     int i, n= N(t);
1699     tree r (t, n);
1700     for (i=0; i<n; i++)
1701       r[i]= upgrade_session (t[i]);
1702     return r;
1703   }
1704 }
1705 
1706 /******************************************************************************
1707 * Upgrade sessions
1708 ******************************************************************************/
1709 
1710 static tree
upgrade_formatting(tree t)1711 upgrade_formatting (tree t) {
1712   if (is_atomic (t)) return t;
1713   else if (is_func (t, FORMAT, 1)) {
1714     string name= replace (t[0]->label, " ", "-");
1715     if (name == "line-separator") name= "line-sep";
1716     else if (name == "no-line-break") name= "no-break";
1717     else if (name == "no-first-indentation") name= "no-indent";
1718     else if (name == "enable-first-indentation") name= "yes-indent";
1719     else if (name == "no-indentation-after") name= "no-indent*";
1720     else if (name == "enable-indentation-after") name= "yes-indent*";
1721     else if (name == "page-break-before") name= "page-break*";
1722     else if (name == "no-page-break-before") name= "no-page-break*";
1723     else if (name == "no-page-break-after") name= "no-page-break";
1724     else if (name == "new-page-before") name= "new-page*";
1725     else if (name == "new-double-page-before") name= "new-dpage*";
1726     else if (name == "new-double-page") name= "new-dpage";
1727     return tree (as_tree_label (name));
1728   }
1729   else {
1730     int i, n= N(t);
1731     tree r (t, n);
1732     for (i=0; i<n; i++)
1733       r[i]= upgrade_formatting (t[i]);
1734     return r;
1735   }
1736 }
1737 
1738 /******************************************************************************
1739 * Upgrade expand
1740 ******************************************************************************/
1741 
1742 static tree
upgrade_expand(tree t,tree_label WHICH_EXPAND)1743 upgrade_expand (tree t, tree_label WHICH_EXPAND) {
1744   if (is_atomic (t)) return t;
1745   else if (is_func (t, WHICH_EXPAND) && is_atomic (t[0])) {
1746     int i, n= N(t)-1;
1747     string s= t[0]->label;
1748     if (s == "quote") s= s * "-env";
1749     tree_label l= make_tree_label (s);
1750     tree r (l, n);
1751     for (i=0; i<n; i++)
1752       r[i]= upgrade_expand (t[i+1], WHICH_EXPAND);
1753     return r;
1754   }
1755   else if (is_func (t, ASSIGN, 2) &&
1756 	   (t[0] == "quote") &&
1757 	   is_func (t[1], MACRO)) {
1758     tree arg= upgrade_expand (t[1], WHICH_EXPAND);
1759     return tree (ASSIGN, t[0]->label * "-env", arg);
1760   }
1761   else {
1762     int i, n= N(t);
1763     tree r (t, n);
1764     for (i=0; i<n; i++)
1765       r[i]= upgrade_expand (t[i], WHICH_EXPAND);
1766     return r;
1767   }
1768 }
1769 
1770 static tree
upgrade_xexpand(tree t)1771 upgrade_xexpand (tree t) {
1772   if (is_atomic (t)) return t;
1773   else {
1774     int i, n= N(t);
1775     tree r (t, n);
1776     if (is_expand (t))
1777       r= tree (COMPOUND, n);
1778     for (i=0; i<n; i++)
1779       r[i]= upgrade_xexpand (t[i]);
1780     return r;
1781   }
1782 }
1783 
1784 /******************************************************************************
1785 * Upgrade apply
1786 ******************************************************************************/
1787 
1788 static tree
upgrade_apply(tree t)1789 upgrade_apply (tree t) {
1790   if (is_atomic (t)) return t;
1791   /*
1792   if (is_func (t, APPLY))
1793     cout << t[0] << "\n";
1794   */
1795   if (is_func (t, APPLY) && is_atomic (t[0])) {
1796     int i, n= N(t)-1;
1797     string s= t[0]->label;
1798     tree_label l= make_tree_label (s);
1799     tree r (l, n);
1800     for (i=0; i<n; i++)
1801       r[i]= upgrade_apply (t[i+1]);
1802     return r;
1803   }
1804 
1805   int i, n= N(t);
1806   tree r (t, n);
1807   if (is_func (t, APPLY))
1808     r= tree (COMPOUND, n);
1809   for (i=0; i<n; i++)
1810     r[i]= upgrade_apply (t[i]);
1811   return r;
1812 }
1813 
1814 static tree
upgrade_function_arg(tree t,tree var)1815 upgrade_function_arg (tree t, tree var) {
1816   if (is_atomic (t)) return t;
1817   else if ((t == tree (APPLY, var)) || (t == tree (VALUE, var)))
1818     return tree (ARG, var);
1819   else {
1820     int i, n= N(t);
1821     tree r (t, n);
1822     for (i=0; i<n; i++)
1823       r[i]= upgrade_function_arg (t[i], var);
1824     return r;
1825   }
1826 }
1827 
1828 static tree
upgrade_function(tree t)1829 upgrade_function (tree t) {
1830   if (is_atomic (t)) return t;
1831   if (is_func (t, ASSIGN, 2) && is_func (t[1], FUNC)) {
1832     int i, n= N(t[1])-1;
1833     for (i=0; i<n; i++)
1834       if (ends (as_string (t[1][i]), "*"))
1835 	cout << "TeXmacs] Deprecated argument list '" << t[1][i]
1836 	     << "' in function '" << t[0] << "'\n"
1837 	     << "TeXmacs] You should use the 'xmacro' primitive now\n";
1838   }
1839   /*
1840   if (is_func (t, ASSIGN, 2) && is_func (t[1], FUNC) && (N(t[1])>1)) {
1841     cout << "Function: " << t[0] << "\n";
1842   }
1843   */
1844   if (is_func (t, FUNC)) {
1845     int i, n= N(t)-1;
1846     tree u= t[n], r (MACRO, n+1);
1847     for (i=0; i<n; i++) {
1848       u= upgrade_function_arg (u, t[i]);
1849       r[i]= copy (t[i]);
1850     }
1851     r[n]= upgrade_function (u);
1852     /*
1853     if (n > 0) {
1854       cout << "t= " << t << "\n";
1855       cout << "r= " << r << "\n";
1856       cout << HRULE;
1857     }
1858     */
1859     return r;
1860   }
1861   else {
1862     int i, n= N(t);
1863     tree r (t, n);
1864     for (i=0; i<n; i++)
1865       r[i]= upgrade_function (t[i]);
1866     return r;
1867   }
1868 }
1869 
1870 /******************************************************************************
1871 * Renaming environment variables
1872 ******************************************************************************/
1873 
1874 static charp var_rename []= {
1875   "shrinking factor", "sfactor",
1876   "info flag", "info-flag",
1877 
1878   "font family", "font-family",
1879   "font series", "font-series",
1880   "font shape", "font-shape",
1881   "font size", "font-size",
1882   "font base size", "font-base-size",
1883   "background color", "bg-color",
1884   "atom decorations", "atom-decorations",
1885   "line decorations", "line-decorations",
1886   "page decorations", "page-decorations",
1887   "xoff decorations", "xoff-decorations",
1888   "yoff decorations", "yoff-decorations",
1889 
1890   "math language", "math-language",
1891   "math font", "math-font",
1892   "math font family", "math-font-family",
1893   "math font series", "math-font-series",
1894   "math font shape", "math-font-shape",
1895   "index level", "math-level",
1896   "formula style", "math-display",
1897   "math condensed", "math-condensed",
1898   "vertical position", "math-vpos",
1899 
1900   "prog language", "prog-language",
1901   "prog font", "prog-font",
1902   "prog font family", "prog-font-family",
1903   "prog font series", "prog-font-series",
1904   "prog font shape", "prog-font-shape",
1905   "this session", "prog-session",
1906 
1907   "paragraph mode", "par-mode",
1908   "paragraph hyphenation", "par-hyphen",
1909   "paragraph width", "par-width",
1910   "left margin", "par-left",
1911   "right margin", "par-right",
1912   "first indentation", "par-first",
1913   "no first indentation", "par-no-first",
1914   "interline space", "par-sep",
1915   "horizontal ink separation", "par-hor-sep",
1916   "line stretch", "par-line-sep",
1917   "interparagraph space", "par-par-sep",
1918   "interfootnote space", "par-fnote-sep",
1919   "nr columns", "par-columns",
1920   "column separation", "par-columns-sep",
1921 
1922   "page medium", "page-medium",
1923   "page type", "page-type",
1924   "page orientation", "page-orientation",
1925   "page breaking", "page-breaking",
1926   "page flexibility", "page-flexibility",
1927   "page number", "page-nr",
1928   "thepage", "page-the-page",
1929   "page width", "page-width",
1930   "page height", "page-height",
1931   "odd page margin", "page-odd",
1932   "even page margin", "page-even",
1933   "page right margin", "page-right",
1934   "page top margin", "page-top",
1935   "page bottom margin", "page-bot",
1936   "page extend", "page-extend",
1937   "page shrink", "page-shrink",
1938   "page header separation", "page-head-sep",
1939   "page footer separation", "page-foot-sep",
1940   "odd page header", "page-odd-header",
1941   "odd page footer", "page-odd-footer",
1942   "even page header", "page-even-header",
1943   "even page footer", "page-even-footer",
1944   "this page header", "page-this-header",
1945   "this page footer", "page-this-footer",
1946   "reduction page left margin", "page-reduce-left",
1947   "reduction page right margin", "page-reduce-right",
1948   "reduction page top margin", "page-reduce-top",
1949   "reduction page bottom margin", "page-reduce-bot",
1950   "show header and footer", "page-show-hf",
1951   "footnote separation", "page-fnote-sep",
1952   "footnote bar length", "page-fnote-barlen",
1953   "float separation", "page-float-sep",
1954   "marginal note separation", "page-mnote-sep",
1955   "marginal note width", "page-mnote-width",
1956 
1957   "table width", "table-width",
1958   "table height", "table-height",
1959   "table hmode", "table-hmode",
1960   "table vmode", "table-vmode",
1961   "table halign", "table-halign",
1962   "table valign", "table-valign",
1963   "table row origin", "table-row-origin",
1964   "table col origin", "table-col-origin",
1965   "table lsep", "table-lsep",
1966   "table rsep", "table-rsep",
1967   "table bsep", "table-bsep",
1968   "table tsep", "table-tsep",
1969   "table lborder", "table-lborder",
1970   "table rborder", "table-rborder",
1971   "table bborder", "table-bborder",
1972   "table tborder", "table-tborder",
1973   "table hyphen", "table-hyphen",
1974   "table min rows", "table-min-rows",
1975   "table min cols", "table-min-cols",
1976   "table max rows", "table-max-rows",
1977   "table max cols", "table-max-cols",
1978 
1979   "cell format", "cell-format",
1980   "cell decoration", "cell-decoration",
1981   "cell background", "cell-background",
1982   "cell orientation", "cell-orientation",
1983   "cell width", "cell-width",
1984   "cell height", "cell-height",
1985   "cell hpart", "cell-hpart",
1986   "cell vpart", "cell-vpart",
1987   "cell hmode", "cell-hmode",
1988   "cell vmode", "cell-vmode",
1989   "cell halign", "cell-halign",
1990   "cell valign", "cell-valign",
1991   "cell lsep", "cell-lsep",
1992   "cell rsep", "cell-rsep",
1993   "cell bsep", "cell-bsep",
1994   "cell tsep", "cell-tsep",
1995   "cell lborder", "cell-lborder",
1996   "cell rborder", "cell-rborder",
1997   "cell bborder", "cell-bborder",
1998   "cell tborder", "cell-tborder",
1999   "cell vcorrect", "cell-vcorrect",
2000   "cell hyphen", "cell-hyphen",
2001   "cell row span", "cell-row-span",
2002   "cell col span", "cell-col-span",
2003   "cell row nr", "cell-row-nr",
2004   "cell col nr", "cell-col-nr",
2005 
2006   "line width", "line-width",
2007   "line style", "line-style",
2008   "line arrows", "line-arrows",
2009   "line caps", "line-join",
2010   "fill mode", "fill-mode",
2011   "fill color", "fill-color",
2012   "fill style", "fill-style",
2013 
2014   "graphical frame", "gr-frame",
2015   "graphical clip", "gr-clip",
2016   "graphical mode", "gr-mode",
2017   "graphical color", "gr-color",
2018   "graphical line width", "gr-line-width",
2019 
2020   ""
2021 };
2022 
2023 static hashmap<string,string> var_rename_table ("?");
2024 
2025 static hashmap<string,string>
cached_renamer(charp * T,hashmap<string,string> & H)2026 cached_renamer (charp* T, hashmap<string,string>& H) {
2027   if (N (H) == 0) {
2028     int i;
2029     for (i=0; T[i][0] != '\0'; i+=2)
2030       H (T[i])= T[i+1];
2031   }
2032   return H;
2033 }
2034 
2035 
2036 static tree
rename_vars(tree t,hashmap<string,string> H,bool flag)2037 rename_vars (tree t, hashmap<string,string> H, bool flag) {
2038   if (is_atomic (t)) return t;
2039   else {
2040     int i, n= N(t);
2041     tree r (t, n);
2042     static tree_label MARKUP= make_tree_label ("markup");
2043     for (i=0; i<n; i++) {
2044       tree u= rename_vars (t[i], H, flag);
2045       if (is_atomic (u) && H->contains (u->label))
2046 	if (((L(t) == WITH) && ((i%2) == 0) && (i < n-1)) ||
2047 	    ((L(t) == ASSIGN) && (i == 0)) ||
2048 	    ((L(t) == VALUE) && (i == 0)) ||
2049 	    ((L(t) == CWITH) && (i == 4)) ||
2050 	    ((L(t) == TWITH) && (i == 0)) ||
2051 	    ((L(t) == ASSOCIATE) && (i == 0)) ||
2052 	    ((L(t) == MARKUP) && (i == 0)))
2053 	  u= copy (H[u->label]);
2054       r[i]= u;
2055     }
2056     if (flag) {
2057       if (H->contains (as_string (L(t)))) {
2058 	tree_label l= make_tree_label (H[as_string (L(t))]);
2059 	r= tree (l, A(r));
2060       }
2061     }
2062     else {
2063       if ((n == 0) && H->contains (as_string (L(t)))) {
2064 	string v= H[as_string (L(t))];
2065 	r= tree (VALUE, copy (v));
2066 	if (v == "page-the-page") r= tree (make_tree_label ("page-the-page"));
2067       }
2068     }
2069     return r;
2070   }
2071 }
2072 
2073 tree
upgrade_env_vars(tree t)2074 upgrade_env_vars (tree t) {
2075   return rename_vars (t, cached_renamer (var_rename, var_rename_table), false);
2076 }
2077 
2078 /******************************************************************************
2079 * Use package primitive for style files
2080 ******************************************************************************/
2081 
2082 static tree
upgrade_use_package(tree t)2083 upgrade_use_package (tree t) {
2084   tree style= extract (t, "style");
2085   tree init = extract (t, "initial");
2086   bool preamble= false;
2087   int i, n= N(init);
2088   for (i=0; i<n; i++)
2089     if (init[i] == tree (ASSOCIATE, PREAMBLE, "true"))
2090       preamble= true;
2091 
2092   bool no_style= true;
2093   if (preamble) {
2094     n= N(t);
2095     tree r (L(t));
2096     for (i=0; i<n; i++)
2097       if (is_compound (t[i], "style")) {
2098 	r << compound ("style", "source");
2099 	no_style= false;
2100       }
2101       else if (is_compound (t[i], "body", 1) && is_document (t[i][0])) {
2102 	tree v (USE_PACKAGE);
2103 	v << A (style);
2104 	tree u (DOCUMENT);
2105 	if (N(v) > 0) u << v;
2106 	u << A (t[i][0]);
2107 	if (no_style) r << compound ("style", "source");
2108 	r << compound ("body", u);
2109       }
2110       else r << t[i];
2111     return r;
2112   }
2113   else return t;
2114 }
2115 
2116 /******************************************************************************
2117 * Normalize names of tags in the style files
2118 ******************************************************************************/
2119 
2120 static charp style_rename []= {
2121   "thelabel", "the-label",
2122 
2123   "leftflush", "left-flush",
2124   "rightflush", "right-flush",
2125   "mathord", "math-ord",
2126   "mathopen", "math-open",
2127   "mathclose", "math-close",
2128   "mathpunct", "math-punct",
2129   "mathbin", "math-bin",
2130   "mathrel", "math-rel",
2131   "mathop", "math-op",
2132   "thetoc", "the-toc",
2133   "theidx", "the-idx",
2134   "thegly", "the-gly",
2135   "theitem", "the-item",
2136   "tocnr", "toc-nr",
2137   "idxnr", "idx-nr",
2138   "glynr", "gly-nr",
2139   "itemnr", "item-nr",
2140   "itemname", "item-name",
2141   "newitemize", "new-itemize",
2142   "newenumerate", "new-enumerate",
2143   "newdescription", "new-description",
2144 
2145   "nextnumber", "next-number",
2146   "eqnumber", "eq-number",
2147   "leqnumber", "leq-number",
2148   "reqnumber", "req-number",
2149   "nonumber", "no-number",
2150   "thefootnote", "the-footnote",
2151   "theequation", "the-equation",
2152   "thetheorem", "the-theorem",
2153   "theproposition", "the-proposition",
2154   "thelemma", "the-lemma",
2155   "thecorollary", "the-corollary",
2156   "theaxiom", "the-axiom",
2157   "thedefinition", "the-definition",
2158   "thenotation", "the-notation",
2159   "theconjecture", "the-conjecture",
2160   "theremark", "the-remark",
2161   "theexample", "the-example",
2162   "thenote", "the-note",
2163   "thewarning", "the-warning",
2164   "theconvention", "the-convention",
2165   "theacknowledgments", "the-acknowledgments",
2166   "theexercise", "the-exercise",
2167   "theproblem", "the-problem",
2168   "thefigure", "the-figure",
2169   "thetable", "the-table",
2170   "footnotenr", "footnote-nr",
2171   "equationnr", "equation-nr",
2172   "theoremnr", "theorem-nr",
2173   "propositionnr", "proposition-nr",
2174   "lemmanr", "lemma-nr",
2175   "corollarynr", "corollary-nr",
2176   "axiomnr", "axiom-nr",
2177   "definitionnr", "definition-nr",
2178   "notationnr", "notation-nr",
2179   "conjecturenr", "conjecture-nr",
2180   "remarknr", "remark-nr",
2181   "examplenr", "example-nr",
2182   "notenr", "note-nr",
2183   "warningnr", "warning-nr",
2184   "conventionnr", "convention-nr",
2185   "acknowledgmentsnr", "acknowledgments-nr",
2186   "exercisenr", "exercise-nr",
2187   "problemnr", "problem-nr",
2188   "figurenr", "figure-nr",
2189   "tablenr", "table-nr",
2190   "theoremname", "theorem-name",
2191   "figurename", "figure-name",
2192   "exercisename", "exercise-name",
2193   "theoremsep", "theorem-sep",
2194   "figuresep", "figure-sep",
2195   "exercisesep", "exercise-sep",
2196   "footnotesep", "footnote-sep",
2197   "newtheorem", "new-theorem",
2198   "newremark", "new-remark",
2199   "newexercise", "new-exercise",
2200   "newfigure", "new-figure",
2201 
2202   "theprefix", "the-prefix",
2203   "thechapter", "the-chapter",
2204   "theappendix", "the-appendix",
2205   "thesection", "the-section",
2206   "thesubsection", "the-subsection",
2207   "thesubsubsection", "the-subsubsection",
2208   "theparagraph", "the-paragraph",
2209   "thesubparagraph", "the-subparagraph",
2210   "chapternr", "chapter-nr",
2211   "appendixnr", "appendix-nr",
2212   "sectionnr", "section-nr",
2213   "subsectionnr", "subsection-nr",
2214   "subsubsectionnr", "subsubsection-nr",
2215   "paragraphnr", "paragraph-nr",
2216   "subparagraphnr", "subparagraph-nr",
2217   "sectionsep", "section-sep",
2218   "subsectionsep", "subsection-sep",
2219   "subsubsectionsep", "subsubsection-sep",
2220 
2221   "theorem*", "render-theorem",
2222   "remark*", "render-remark",
2223   "exercise*", "render-exercise",
2224   "proof*", "render-proof",
2225   "small-figure*", "render-small-figure",
2226   "big-figure*", "render-big-figure",
2227 
2228   "theanswer", "the-answer",
2229   "thealgorithm", "the-algorithm",
2230   "answernr", "answer-nr",
2231   "algorithmnr", "algorithm-nr",
2232 
2233   ""
2234 };
2235 
2236 static hashmap<string,string> style_rename_table ("?");
2237 
2238 static tree
upgrade_style_rename_sub(tree t)2239 upgrade_style_rename_sub (tree t) {
2240   if (is_atomic (t)) return t;
2241   else if (is_func (t, MERGE, 2) && (t[0] == "the"))
2242     return tree (MERGE, "the-", t[1]);
2243   else if (is_func (t, MERGE, 2) && (t[1] == "nr"))
2244     return tree (MERGE, t[0], "-nr");
2245   else {
2246     int i, n= N(t);
2247     tree r (t, n);
2248     for (i=0; i<n; i++)
2249       r[i]= upgrade_style_rename_sub (t[i]);
2250     return r;
2251   }
2252 }
2253 
2254 static tree
upgrade_style_rename(tree t)2255 upgrade_style_rename (tree t) {
2256   t= upgrade_style_rename_sub (t);
2257   return
2258     rename_vars (t, cached_renamer (style_rename, style_rename_table), true);
2259 }
2260 
2261 /******************************************************************************
2262 * Remove trailing punctuation in item* tags
2263 ******************************************************************************/
2264 
2265 static tree
upgrade_item_punct(tree t)2266 upgrade_item_punct (tree t) {
2267   if (is_atomic (t)) return t;
2268   else {
2269     int i, n= N(t);
2270     tree r (t, n);
2271     for (i=0; i<n; i++)
2272       r[i]= upgrade_item_punct (t[i]);
2273     if (is_compound (r, "item*", 1)) {
2274       tree& item= r[0];
2275       if (is_atomic (item)) {
2276 	string s= item->label;
2277 	if (ends (s, ".") || ends (s, ":") || ends (s, " "))
2278 	  item= s (0, N(s)-1);
2279       }
2280       else if (is_concat (item) && is_atomic (item[N(item)-1])) {
2281 	string s= item [N(item)-1] -> label;
2282 	if ((s == ".") || (s == ":") || (s == " ")) {
2283 	  if (N(item) == 2) item= item[0];
2284 	  else item= item (0, N(item) - 1);
2285 	}
2286       }
2287     }
2288     return r;
2289   }
2290 }
2291 
2292 /******************************************************************************
2293 * Forget default page parameters
2294 ******************************************************************************/
2295 
2296 tree
upgrade_page_pars(tree t)2297 upgrade_page_pars (tree t) {
2298   if (is_atomic (t)) return t;
2299   else if (L(t) == COLLECTION) {
2300     int i, n= N(t);
2301     tree r (COLLECTION);
2302     for (i=0; i<n; i++) {
2303       tree u= t[i];
2304       if (!is_func (u, ASSOCIATE, 2));
2305       else if (u == tree (ASSOCIATE, PAGE_TYPE, "a4"));
2306       else if (u == tree (ASSOCIATE, PAGE_EVEN, "30mm"));
2307       else if (u == tree (ASSOCIATE, PAGE_ODD, "30mm"));
2308       else if (u == tree (ASSOCIATE, PAGE_RIGHT, "30mm"));
2309       else if (u == tree (ASSOCIATE, PAGE_TOP, "30mm"));
2310       else if (u == tree (ASSOCIATE, PAGE_BOT, "30mm"));
2311       else if (u == tree (ASSOCIATE, PAR_WIDTH, "150mm"));
2312       else if (u[0] == "page-reduce-left");
2313       else if (u[0] == "page-reduce-right");
2314       else if (u[0] == "page-reduce-top");
2315       else if (u[0] == "page-reduce-bot");
2316       else if (u[0] == "sfactor");
2317       else r << u;
2318     }
2319     return r;
2320   }
2321   else {
2322     int i, n= N(t);
2323     tree r (t, n);
2324     for (i=0; i<n; i++)
2325       r[i]= upgrade_page_pars (t[i]);
2326     return r;
2327   }
2328 }
2329 
2330 /******************************************************************************
2331 * Substitutions
2332 ******************************************************************************/
2333 
2334 tree
substitute(tree t,tree which,tree by)2335 substitute (tree t, tree which, tree by) {
2336   if (t == which) return by;
2337   else if (is_atomic (t)) return t;
2338   else {
2339     int i, n= N(t);
2340     tree r (t, n);
2341     for (i=0; i<n; i++)
2342       r[i]= substitute (t[i], which, by);
2343     return r;
2344   }
2345 }
2346 
2347 /******************************************************************************
2348 * Upgrading title information
2349 ******************************************************************************/
2350 
2351 static tree doc_keywords;
2352 static tree doc_ams_class;
2353 
2354 static void
abstract_add(tree & data,tree what)2355 abstract_add (tree& data, tree what) {
2356   if (is_func (what, DOCUMENT, 1)) what= what[0];
2357   if (is_atomic (what)) {
2358     string s= what->label;
2359     int i, start, n= N(s);
2360     for (i=start=0; i<n; )
2361       if (s[i] == ',') {
2362 	int next= i+1;
2363 	while ((i>start) && (s[i-1]==' ')) i--;
2364 	data << s (start, i);
2365 	i= next; if (s[i] == ' ') i++;
2366 	start= i;
2367       }
2368       else i++;
2369     while ((i>start) && (s[i-1]==' ')) i--;
2370     data << s (start, i);
2371   }
2372   else data << what;
2373 }
2374 
2375 static tree
upgrade_abstract(tree t)2376 upgrade_abstract (tree t) {
2377   if (is_atomic (t)) return t;
2378   else if (is_compound (t, "abstract", 1) && is_document (t[0])) {
2379     int i, n= N(t[0]);
2380     tree r (DOCUMENT);
2381     for (i=0; i<n; i++)
2382       if (is_compound (t[0][i], "keywords", 1))
2383 	abstract_add (doc_keywords, t[0][i][0]);
2384       else if (is_compound (t[0][i], "AMS-class"))
2385 	abstract_add (doc_ams_class, t[0][i][0]);
2386       else r << t[0][i];
2387     if (N(r) == 0) r << "";
2388     return compound ("abstract", r);
2389   }
2390   else {
2391     int i, n= N(t);
2392     tree r (t, n);
2393     for (i=0; i<n; i++)
2394       r[i]= upgrade_abstract (t[i]);
2395     return r;
2396   }
2397 }
2398 
2399 static tree
search_title_tag(tree t,string tag,bool flag=false)2400 search_title_tag (tree t, string tag, bool flag= false) {
2401   if (is_atomic (t)) return tuple ();
2402   else if (is_compound (t, tag, 1)) return tuple (t[0]);
2403   else if (flag && is_compound (t, tag)) return tuple (t);
2404   else {
2405     int i, n= N(t);
2406     tree r (TUPLE);
2407     for (i=0; i<n; i++)
2408       r << A (search_title_tag (t[i], tag, flag));
2409     return r;
2410   }
2411 }
2412 
2413 static void
search_abstract_tag(tree t,tree & data,string tag)2414 search_abstract_tag (tree t, tree& data, string tag) {
2415   if (is_atomic (t)) return;
2416   else {
2417     int i, n= N(t);
2418     for (i=0; i<n; i++)
2419       if (is_compound (t[i], tag, 1))
2420         abstract_add (data, t[i][0]);
2421   }
2422 }
2423 
2424 static void
title_add(tree & data,string tag,tree args,bool flag=false)2425 title_add (tree& data, string tag, tree args, bool flag= false) {
2426   int i, n= N(args);
2427   for (i=0; i<n; i++) {
2428     tree t= args[i];
2429     if (flag && (!is_document (t))) t= tree (DOCUMENT, t);
2430     if ((!flag) && is_func (t, DOCUMENT, 1)) t= t[0];
2431     data << compound (tag, t);
2432   }
2433 }
2434 
2435 static void
add_info(tree & data,tree t,string ntag,string otag,bool flag1=false,bool flag2=false)2436 add_info (tree& data, tree t, string ntag, string otag,
2437           bool flag1= false, bool flag2= false) {
2438   tree u= search_title_tag (t, otag, flag1);
2439   if (N(t) != 0) title_add (data, ntag, u, flag2);
2440 }
2441 
2442 static tree
upgrade_title2(tree t)2443 upgrade_title2 (tree t) {
2444   if (is_atomic (t)) return t;
2445   else if (is_compound (t, "make-title", 1)) {
2446     //cout << "t= " << t << "\n";
2447     tree u= t[0];
2448     if (!is_document (u) && !is_concat (u)) u= tree (DOCUMENT, u);
2449     tree title_data = compound ("doc-data");
2450     tree author_data= compound ("doc-author-data");
2451     tree meta_data  = compound ("doc-data");
2452 
2453     for (int i=0; i<N(u); i++) {
2454       tree v= u[i];
2455       add_info (title_data, v, "doc-title", "title");
2456       add_info (meta_data, v, "doc-date", "title-date");
2457       add_info (meta_data, v, "doc-running-title", "header-title");
2458       add_info (meta_data, v, "doc-running-author", "header-author");
2459       add_info (meta_data, v, "doc-note", "title-thanks", true, true);
2460       if (N (search_title_tag (v, "author")) != 0) {
2461         if (N (author_data) != 0 &&
2462             is_compound (author_data[0], "author-name"))
2463           title_data << author_data;
2464         author_data= compound ("doc-author-data");
2465       }
2466       add_info (author_data, v, "author-name", "author");
2467       add_info (author_data, v, "author-address", "address", false, true);
2468       add_info (author_data, v, "author-email", "title-email");
2469       add_info (author_data, v, "author-homepage", "title-web");
2470     }
2471     if (N (author_data) != 0) title_data << author_data;
2472     if (N (meta_data) != 0) title_data << A (meta_data);
2473 
2474     tree notice= search_title_tag (t, "made-by-TeXmacs", true);
2475     if (N (notice) != 0)
2476       title_data << compound ("doc-note", compound ("with-TeXmacs-text"));
2477     search_abstract_tag (t[0], doc_keywords, "title-keywords");
2478     search_abstract_tag (t[0], doc_ams_class, "title-ams-class");
2479     if (N (doc_keywords) != 0) title_data << doc_keywords;
2480     if (N (doc_ams_class) != 0) title_data << doc_ams_class;
2481     //cout << "r= " << title_data << "\n";
2482     return title_data;
2483   }
2484   else {
2485     int i, n= N(t);
2486     tree r (t, n);
2487     for (i=0; i<n; i++)
2488       r[i]= upgrade_title2 (t[i]);
2489     return r;
2490   }
2491 }
2492 
2493 static tree
upgrade_doc_info(tree t)2494 upgrade_doc_info (tree t) {
2495   doc_keywords = compound ("doc-keywords");
2496   doc_ams_class= compound ("doc-AMS-class");
2497   t= upgrade_abstract (t);
2498   t= upgrade_title2 (t);
2499   return t;
2500 }
2501 
2502 /******************************************************************************
2503 * Upgrade bibliographies
2504 ******************************************************************************/
2505 
2506 tree
upgrade_bibliography(tree t)2507 upgrade_bibliography (tree t) {
2508   if (is_atomic (t)) return t;
2509   else {
2510     int i, n= N(t);
2511     tree r (t, n);
2512     for (i=0; i<n; i++)
2513       r[i]= upgrade_bibliography (t[i]);
2514     if (is_compound (t, "bibliography") || is_compound (t, "bibliography*")) {
2515       int l= N(r)-1;
2516       if (is_func (r[l], DOCUMENT, 1) && is_compound (r[l][0], "bib-list"));
2517       else if (is_compound (r[l], "bib-list"));
2518       else r[l]= tree (DOCUMENT, compound ("bib-list", "[99]", r[l]));
2519     }
2520     return r;
2521   }
2522 }
2523 
2524 /******************************************************************************
2525 * Upgrade switches
2526 ******************************************************************************/
2527 
2528 tree
upgrade_switch(tree t)2529 upgrade_switch (tree t) {
2530   if (is_atomic (t)) return t;
2531   else {
2532     int i, n= N(t);
2533     tree r (t, n);
2534     for (i=0; i<n; i++)
2535       r[i]= upgrade_switch (t[i]);
2536     if (is_compound (r, "switch", 2)) {
2537       int i, n= N(r[1]);
2538       tree u (make_tree_label ("switch"), n);
2539       for (i=0; i<n; i++)
2540 	if (is_compound (r[1][i], "tmarker", 0)) u[i]= r[0];
2541 	else u[i]= compound ("hidden", r[1][i]);
2542       return u;
2543     }
2544     if (is_compound (r, "fold", 2))
2545       return compound ("folded", r[0], r[1]);
2546     if (is_compound (r, "unfold", 2))
2547       return compound ("unfolded", r[0], r[1]);
2548     if (is_compound (r, "fold-bpr", 2) ||
2549 	is_compound (r, "fold-text", 2) ||
2550 	is_compound (r, "fold-proof", 2) ||
2551 	is_compound (r, "fold-exercise", 2))
2552       return compound ("summarized", r[0], r[1]);
2553     if (is_compound (r, "unfold-bpr", 2) ||
2554 	is_compound (r, "unfold-text", 2) ||
2555 	is_compound (r, "unfold-proof", 2) ||
2556 	is_compound (r, "unfold-exercise", 2))
2557       return compound ("detailed", r[0], r[1]);
2558     if (is_compound (r, "fold-algorithm", 2))
2559       return compound ("summarized-algorithm", r[0], r[1]);
2560     if (is_compound (r, "unfold-algorithm", 2))
2561       return compound ("detailed-algorithm", r[0], r[1]);
2562     if (is_func (r, ASSIGN, 2) && r[0] == "fold-algorithm")
2563       return tree (ASSIGN, "summarized-algorithm", r[1]);
2564     if (is_func (r, ASSIGN, 2) && r[0] == "unfold-algorithm")
2565       return tree (ASSIGN, "detailed-algorithm", r[1]);
2566     return r;
2567   }
2568 }
2569 
2570 /******************************************************************************
2571 * Upgrade graphics
2572 ******************************************************************************/
2573 
2574 static int
find_attr_pos(tree t,string name)2575 find_attr_pos (tree t, string name) {
2576   int i, n= N(t);
2577   for (i=0; i<n; i+=2)
2578     if (t[i] == name && i%2 == 0 && i+1<n) return i;
2579   return -1;
2580 }
2581 
2582 static bool
find_attr(tree t,string name)2583 find_attr (tree t, string name) {
2584   return find_attr_pos (t, name) != -1;
2585 }
2586 
2587 static tree
get_attr(tree t,string name,tree ifnotfound)2588 get_attr (tree t, string name, tree ifnotfound) {
2589   int i= find_attr_pos (t, name);
2590   return i == -1 ? ifnotfound : t[i+1];
2591 }
2592 
2593 static tree
add_attr(tree t,string name,tree value)2594 add_attr (tree t, string name, tree value) {
2595   int i, n= N(t);
2596   tree r (t, n+2);
2597   for (i=0; i<n-1; i++)
2598     r[i]= t[i];
2599   r[n-1]= name;
2600   r[n]= value;
2601   r[n+1]= t[n-1];
2602   return r;
2603 }
2604 
2605 static tree
set_attr(tree t,string name,tree value)2606 set_attr (tree t, string name, tree value) {
2607   int i= find_attr_pos (t, name);
2608   if (i != -1)
2609     t[i+1]= value;
2610   else
2611     t= add_attr (t, name, value);
2612   return t;
2613 }
2614 
2615 static tree
remove_attr(tree t,string name)2616 remove_attr (tree t, string name) {
2617   int i= find_attr_pos (t, name);
2618   if (i == -1)
2619     return t;
2620   else {
2621     int j, n= N(t);
2622     tree r (t, n-2);
2623     for (j=0; j<i; j++)
2624       r[j]= t[j];
2625     for (j=i+2; j<n; j++)
2626       r[j-2]= t[j];
2627     return r;
2628   }
2629 }
2630 
2631 tree
upgrade_fill(tree t)2632 upgrade_fill (tree t) {
2633   int i;
2634   if (is_atomic (t)) return t;
2635   if (is_compound (t, "with")) {
2636     if ((i= find_attr_pos (t, "gr-mode")) != -1
2637      && is_tuple (t[i+1],"edit-prop"))
2638       t[i+1]= tuple ("group-edit","props");
2639 
2640     tree fm= get_attr (t, "fill-mode", tree ("none"));
2641     t= remove_attr (t, "fill-mode");
2642     t= remove_attr (t, "gr-fill-mode");
2643     if (fm == "none")
2644       t= remove_attr (t, "fill-color");
2645     if (fm == "inside")
2646       t= set_attr (t, "color", tree ("none"));
2647   }
2648   int n= N(t);
2649   tree r (t, n);
2650   for (i=0; i<n; i++)
2651     r[i]= upgrade_fill (t[i]);
2652   return r;
2653 }
2654 
2655 static void
length_split(string & num,string & unit,string l)2656 length_split (string &num, string &unit, string l) {
2657   int i, n= N(l), nu= 0;
2658   i= n-1;
2659   while (i>=0 && is_alpha (l[i])) i--, nu++;
2660   num= l (0, n-nu);
2661   unit= l (n-nu, n);
2662 }
2663 
2664 static string
length_minus(string l)2665 length_minus (string l) {
2666   if (l[0] == '+') l[0]= '-';
2667   else
2668   if (l[0] == '-') l[0]= '+';
2669   else
2670     l= "-" * l;
2671   return l;
2672 }
2673 
2674 static string
length_abs(string l)2675 length_abs (string l) {
2676   if (l[0] == '-') l[0]= '+';
2677   return l;
2678 }
2679 
2680 static int length_add_error;
2681 
2682 static string
length_add(string l1,string l2)2683 length_add (string l1, string l2) {
2684   length_add_error= 0;
2685   string n1, u1, n2, u2;
2686   length_split (n1, u1, l1);
2687   length_split (n2, u2, l2);
2688   double i1= as_double (n1);
2689   double i2= as_double (n2);
2690   if (i1 == 0.0) {
2691     i1= i2;
2692     i2= 0.0;
2693     string u= u1;
2694     u1= u2;
2695     u2= u;
2696   }
2697   if (u1 == "par" && (u2 == "par" || i2 == 0.0))
2698     return as_string (i1 + i2) * "par";
2699   else
2700   if ((u1 == "cm" || u1 == "mm")
2701    && (u2 == "cm" || u2 == "mm" || i2 == 0.0)) {
2702     if (u1 == "cm" && u2 == "mm") i2 /= 10;
2703     if (u1 == "mm" && u2 == "cm") i2 *= 10;
2704     return as_string (i1 + i2) * u1;
2705   }
2706   else {
2707     length_add_error= 1;
2708     return "0cm";
2709   }
2710 }
2711 
2712 tree
upgrade_graphics(tree t)2713 upgrade_graphics (tree t) {
2714   int i;
2715   if (is_atomic (t)) return t;
2716   if (is_compound (t, "with") &&
2717       (find_attr (t, "gr-frame") || find_attr (t, "gr-clip"))) {
2718     tree fr= get_attr (t, "gr-frame",
2719 			  tuple ("scale", "1cm",
2720 				 tree (TUPLE, "0.5par", "0cm")));
2721     tree clip= get_attr (t, "gr-clip",
2722 			    tuple ("clip",
2723 				   tuple ("0par", "-0.3par"),
2724 				   tuple ("1par", "0.3par")));
2725     t= remove_attr (t, "gr-clip");
2726 
2727     string ox= as_string (fr[2][0]), oy= as_string (fr[2][1]);
2728     string cg= as_string (clip[1][0]), cb= as_string (clip[1][1]);
2729     string cd= as_string (clip[2][0]), ch= as_string (clip[2][1]);
2730     string w= length_add (cd, length_minus (cg));
2731     string h= length_add (ch, length_minus (cb));
2732 
2733     fr[2][0]= tree (length_add (length_abs (cg) , ox));
2734     if (length_add_error)
2735       fr[2][0]= tree (PLUS, length_abs (cg) , ox);
2736     fr[2][1]= tree (length_add (length_abs (cb) , oy));
2737     if (length_add_error)
2738       fr[2][1]= tree (PLUS, length_abs (cb) , oy);
2739     tree geom= tuple ("geometry", tree (w), tree (h));
2740     t= add_attr (t, "gr-geometry", geom);
2741     t= set_attr (t, "gr-frame", fr);
2742   }
2743   int n= N(t);
2744   tree r (t, n);
2745   for (i=0; i<n; i++)
2746     r[i]= upgrade_graphics (t[i]);
2747   return r;
2748 }
2749 
2750 tree
upgrade_textat(tree t)2751 upgrade_textat (tree t) {
2752   int i;
2753   if (is_atomic (t)) return t;
2754   if (is_compound (t, "text-at") && N(t) == 4) {
2755     tree t0= t;
2756     t= tree (WITH, tree (TEXT_AT, t[0], t[1]));
2757     t= set_attr (t, "text-at-halign", t0[2]);
2758     t= set_attr (t, "text-at-valign", t0[3]);
2759   }
2760   int n= N(t);
2761   tree r (t, n);
2762   for (i=0; i<n; i++)
2763     r[i]= upgrade_textat (t[i]);
2764   return r;
2765 }
2766 
2767 /******************************************************************************
2768 * Upgrade cell alignment
2769 ******************************************************************************/
2770 
2771 tree
upgrade_cell_alignment(tree t)2772 upgrade_cell_alignment (tree t) {
2773   int i;
2774   if (is_atomic (t)) return t;
2775   if (is_func (t, CWITH) && (N(t) >= 2))
2776     if (t[N(t)-2] == CELL_HALIGN)
2777       if (t[N(t)-1] == "." || t[N(t)-1] == ",") {
2778 	tree r= copy (t);
2779 	r[N(t)-1]= "L" * t[N(t)-1]->label;
2780 	return r;
2781       }
2782   int n= N(t);
2783   tree r (t, n);
2784   for (i=0; i<n; i++)
2785     r[i]= upgrade_cell_alignment (t[i]);
2786   return r;
2787 }
2788 
2789 /******************************************************************************
2790 * Renaming primitives
2791 ******************************************************************************/
2792 
2793 tree
rename_primitive(tree t,string which,string by)2794 rename_primitive (tree t, string which, string by) {
2795   int i;
2796   if (is_atomic (t)) return t;
2797   int n= N(t);
2798   tree r (t, n);
2799   if (is_compound (t, which))
2800     r= tree (make_tree_label (by), n);
2801   for (i=0; i<n; i++)
2802     r[i]= rename_primitive (t[i], which, by);
2803   return r;
2804 }
2805 
2806 /******************************************************************************
2807 * Upgrade label assignment
2808 ******************************************************************************/
2809 
2810 tree
upgrade_label_assignment(tree t)2811 upgrade_label_assignment (tree t) {
2812   int i;
2813   if (is_atomic (t)) return t;
2814   else if (is_func (t, ASSIGN, 2) && t[0] == "the-label")
2815     return tree (SET_BINDING, t[1]);
2816   else {
2817     int n= N(t);
2818     tree r (t, n);
2819     for (i=0; i<n; i++)
2820       r[i]= upgrade_label_assignment (t[i]);
2821     return r;
2822   }
2823 }
2824 
2825 /******************************************************************************
2826 * Upgrade scheme documentation
2827 ******************************************************************************/
2828 
2829 tree
upgrade_scheme_doc(tree t)2830 upgrade_scheme_doc (tree t) {
2831   int i;
2832   if (is_atomic (t)) return t;
2833   else if (is_compound (t, "scm-fun", 1) ||
2834 	   is_compound (t, "scm-macro", 1))
2835     return compound ("scm", t[0]);
2836   else if (is_compound (t, "explain-scm-fun") ||
2837 	   is_compound (t, "explain-scm-macro"))
2838     {
2839       tree r (CONCAT);
2840       r << "(" << t[0];
2841       for (int i=1; i<N(t); i++)
2842 	r << " " << t[i];
2843       r << ")";
2844       return compound ("scm", simplify_concat (r));
2845     }
2846   else {
2847     int n= N(t);
2848     tree r (t, n);
2849     for (i=0; i<n; i++)
2850       r[i]= upgrade_scheme_doc (t[i]);
2851     return r;
2852   }
2853 }
2854 
2855 /******************************************************************************
2856 * Upgrade Mathemagix tag
2857 ******************************************************************************/
2858 
2859 tree
upgrade_mmx(tree t)2860 upgrade_mmx (tree t) {
2861   int i;
2862   if (is_atomic (t)) return t;
2863   else if (is_compound (t, "mmx", 0) || t == tree (VALUE, "mmx"))
2864     return compound ("mathemagix");
2865   else if (is_compound (t, "mml", 0) || t == tree (VALUE, "mml"))
2866     return compound ("mmxlib");
2867   else if (is_compound (t, "scheme", 0) || t == tree (VALUE, "scheme"))
2868     return compound ("scheme");
2869   else if (is_compound (t, "cpp", 0) || t == tree (VALUE, "cpp"))
2870     return compound ("c++");
2871   else if (is_compound (t, "scheme-code", 1))
2872     return compound ("scm", upgrade_mmx (t[0]));
2873   else if (is_compound (t, "scheme-fragment", 1))
2874     return compound ("scm-fragment", upgrade_mmx (t[0]));
2875   else if (is_compound (t, "cpp-code", 1))
2876     return compound ("cpp", upgrade_mmx (t[0]));
2877   else {
2878     int n= N(t);
2879     tree r (t, n);
2880     for (i=0; i<n; i++)
2881       r[i]= upgrade_mmx (t[i]);
2882     return r;
2883   }
2884 }
2885 
2886 /******************************************************************************
2887 * Upgrade sessions
2888 ******************************************************************************/
2889 
2890 static tree
upgrade_session(tree t,tree lan,tree ses)2891 upgrade_session (tree t, tree lan, tree ses) {
2892   if (is_atomic (t)) return t;
2893   else if (is_compound (t, "session", 1))
2894     return compound ("session", copy (lan), copy (ses),
2895 		     upgrade_session (t[0], lan, ses));
2896   else if (is_func (t, WITH, 5) &&
2897 	   t[0] == PROG_LANGUAGE &&
2898 	   t[2] == PROG_SESSION)
2899     return upgrade_session (t[4], t[1], t[3]);
2900   else {
2901     int i, n= N(t);
2902     tree r (L(t));
2903     for (i=0; i<n; i++) {
2904       if (is_document (t) && is_compound (t[i], "input", 2)) {
2905 	bool m = is_compound (t[i][1], "math", 1);
2906 	tree in= (m? t[i][1][0]: t[i][1]);
2907 	if ((i+1)<n && is_compound (t[i+1], "output", 1)) {
2908 	  const char* op= (m? "unfolded-io-math": "unfolded-io");
2909 	  r << compound (op, t[i][0], in, t[i+1][0]);
2910 	  i++;
2911 	}
2912 	else {
2913 	  const char* op= (m? "input-math": "input");
2914 	  r << compound (op, t[i][0], in);
2915 	}
2916       }
2917       else r << upgrade_session (t[i], lan, ses);
2918     }
2919     return r;
2920   }
2921 }
2922 
2923 /******************************************************************************
2924 * Upgrade presentation style
2925 ******************************************************************************/
2926 
2927 tree
upgrade_presentation(tree t)2928 upgrade_presentation (tree t) {
2929   int i;
2930   if (is_atomic (t)) return t;
2931   else if (is_compound (t, "style") || is_compound (t, "tuple")) {
2932     int n= N(t);
2933     tree r (t, n);
2934     for (i=0; i<n; i++)
2935       if (t[i] == "presentation") r[i]= "presentation-ridged-paper";
2936       else r[i]= upgrade_presentation (t[i]);
2937     return r;
2938   }
2939   else {
2940     int n= N(t);
2941     tree r (t, n);
2942     for (i=0; i<n; i++)
2943       r[i]= upgrade_presentation (t[i]);
2944     return r;
2945   }
2946 }
2947 
2948 /******************************************************************************
2949 * Upgrade mathematical formulas
2950 ******************************************************************************/
2951 
2952 bool
is_non_style_document(tree doc)2953 is_non_style_document (tree doc) {
2954   tree style= extract (doc, "style");
2955   if (!is_tuple (style) || N(style) == 0 || !is_atomic (style[0]))
2956     return false;
2957   for (int i=0; i<N(style); i++)
2958     if (style[i] == "source") return false;
2959   string ms= style[0]->label;
2960   return
2961     (starts (ms, "tm")) ||
2962     (starts (ms, "lycee")) ||
2963     (ms == "article") ||
2964     (ms == "beamer") ||
2965     (ms == "book") ||
2966     (ms == "exam") ||
2967     (ms == "generic") ||
2968     (ms == "letter") ||
2969     (ms == "seminar") ||
2970     (ms == "bibliography") ||
2971     (ms == "browser") ||
2972     (ms == "help") ||
2973     (ms == "manual") ||
2974     (ms == "mmxdoc") ||
2975     (ms == "elsart") ||
2976     (ms == "ifac") ||
2977     (ms == "jsc") ||
2978     (ms == "acmconf") ||
2979     (ms == "svjour") ||
2980     (ms == "svmono");
2981 }
2982 
2983 tree
upgrade_math(tree t)2984 upgrade_math (tree t) {
2985   int i;
2986   if (is_atomic (t)) return t;
2987   else if (is_func (t, WITH, 3) && t[0] == MODE && t[1] == "math")
2988     return compound ("math", upgrade_math (t[2]));
2989   else if (is_func (t, WITH, 3) && t[0] == MODE && t[1] == "text")
2990     return compound ("text", upgrade_math (t[2]));
2991   else if (is_func (t, WITH) && N(t) >= 5 && t[0] == MODE && t[1] == "math")
2992     return compound ("math", upgrade_math (t (2, N(t))));
2993   else if (is_func (t, WITH) && N(t) >= 5 && t[0] == MODE && t[1] == "text")
2994     return compound ("text", upgrade_math (t (2, N(t))));
2995   else {
2996     int n= N(t);
2997     tree r (t, n);
2998     for (i=0; i<n; i++)
2999       r[i]= upgrade_math (t[i]);
3000     return r;
3001   }
3002 }
3003 
3004 /******************************************************************************
3005 * Upgrade resize and clipped
3006 ******************************************************************************/
3007 
3008 tree
upgrade_resize_arg(tree t)3009 upgrade_resize_arg (tree t) {
3010   if (is_func (t, MERGE, 2)) {
3011     if (is_atomic (t[0]) && is_atomic (t[1]))
3012       return upgrade_resize_arg (t[0]->label * t[1]->label);
3013     tree u= upgrade_resize_arg (t[0]);
3014     if (is_func (u, PLUS, 2) || is_func (u, MINUS, 2) ||
3015 	is_func (u, MINIMUM, 2) || is_func (u, MAXIMUM, 2))
3016       if (u[1] == "") {
3017 	u[1]= upgrade_resize_arg (t[1]);
3018 	return u;
3019       }
3020     cout << "TeXmacs] warning, resize argument " << t << " not upgraded\n";
3021     return t;
3022   }
3023   if (is_func (t, ARG, 1) ||
3024       is_func (t, PLUS, 2) || is_func (t, MINUS, 2) ||
3025       is_func (t, MINIMUM, 2) || is_func (t, MAXIMUM, 2))
3026     return t;
3027   if (!is_atomic (t)) {
3028     cout << "TeXmacs] warning, resize argument " << t << " not upgraded\n";
3029     return t;
3030   }
3031   string s= t->label;
3032   if (starts (s, "c")) {
3033     cout << "TeXmacs] warning, resize argument " << t << " not upgraded\n";
3034     return t;
3035   }
3036   if (s == "l") return "1l";
3037   if (s == "r") return "1r";
3038   if (s == "t") return "1t";
3039   if (s == "b") return "1b";
3040   if (N(s) < 2) return t;
3041   if (s[0] != 'l' && s[0] != 'b' && s[0] != 'r' && s[0] != 't') return t;
3042   string s1= "1" * s (0, 1);
3043   string s2= s (2, N(s));
3044   if (s[1] == '+') return tree (PLUS, s1, s2);
3045   if (s[1] == '-') return tree (MINUS, s1, s2);
3046   if (s[1] == '[') return tree (MINIMUM, s1, s2);
3047   if (s[1] == ']') return tree (MAXIMUM, s1, s2);
3048   return t;
3049 }
3050 
3051 tree
upgrade_resize_clipped(tree t)3052 upgrade_resize_clipped (tree t) {
3053   if (is_atomic (t)) return t;
3054   else if (N(t) >= 5 && (is_func (t, RESIZE) || is_func (t, CLIPPED))) {
3055     if (is_func (t, CLIPPED))
3056       t= tree (CLIPPED, t[4], t[0], t[1], t[2], t[3]);
3057     int i, n= 5;
3058     tree r (t, n);
3059     r[0]= upgrade_resize_clipped (t[0]);
3060     for (i=1; i<n; i++)
3061       r[i]= upgrade_resize_arg (t[i]);
3062     return r;
3063   }
3064   else {
3065     int i, n= N(t);
3066     tree r (t, n);
3067     for (i=0; i<n; i++)
3068       r[i]= upgrade_resize_clipped (t[i]);
3069     return r;
3070   }
3071 }
3072 
3073 /******************************************************************************
3074 * Upgrade images
3075 ******************************************************************************/
3076 
3077 tree
upgrade_image_length(tree t,string unit)3078 upgrade_image_length (tree t, string unit) {
3079   if (!is_atomic (t)) return t;
3080   string s= t->label;
3081   if (starts (s, "*") || starts (s, "/")) {
3082     double mag= get_magnification (s);
3083     return as_string (mag) * unit;
3084   }
3085   else return t;
3086 }
3087 
3088 tree
upgrade_image(tree t)3089 upgrade_image (tree t) {
3090   if (is_atomic (t)) return t;
3091   else if (is_func (t, IMAGE, 7))
3092     return tree (IMAGE, t[0],
3093 		 upgrade_image_length (t[1], "w"),
3094 		 upgrade_image_length (t[2], "h"),
3095 		 "", "");
3096   else {
3097     int i, n= N(t);
3098     tree r (t, n);
3099     for (i=0; i<n; i++)
3100       r[i]= upgrade_image (t[i]);
3101     return r;
3102   }
3103 }
3104 
3105 /******************************************************************************
3106 * Upgrade root switches
3107 ******************************************************************************/
3108 
3109 tree
upgrade_root_switch(tree t,bool top=true)3110 upgrade_root_switch (tree t, bool top= true) {
3111   if (is_func (t, DOCUMENT) &&
3112       (top || N(t) == 1 ||
3113        (N(t) == 2 && is_compound (t[0], "hide-preamble")))) {
3114     int i, n= N(t);
3115     tree r (DOCUMENT, n);
3116     for (i=0; i<n; i++)
3117       r[i]= upgrade_root_switch (t[i], false);
3118     return r;
3119   }
3120   else if (is_compound (t, "body", 1))
3121     return compound ("body", upgrade_root_switch (t[0], false));
3122   else if (is_compound (t, "switch"))
3123     return compound ("screens", A(t));
3124   else return t;
3125 }
3126 
3127 /******************************************************************************
3128 * Upgrade hyphenation
3129 ******************************************************************************/
3130 
3131 tree
upgrade_hyphenation(tree t)3132 upgrade_hyphenation (tree t) {
3133   tree style= copy (extract (t, "style"));
3134   tree init = extract (t, "initial");
3135   if (is_atomic (style)) style= tuple (style);
3136   if (style == tree (TUPLE)) style= tuple ("generic");
3137   if (!is_tuple (style) || N(style) != 1 || !is_atomic (style[0])) return t;
3138   string ms= style[0]->label;
3139   if (ms == "article" || ms == "beamer" || ms == "book" || ms == "exam" ||
3140       ms == "generic" || ms == "letter" || ms == "seminar")
3141     {
3142       hashmap<string,tree> h (UNINIT, init);
3143       if (!h->contains (PAR_HYPHEN)) h (PAR_HYPHEN)= "normal";
3144       tree new_init= make_collection (h);
3145       return change_doc_attr (t, "initial", new_init);
3146     }
3147   else return t;
3148 }
3149 
3150 /******************************************************************************
3151 * Renaming of symbols
3152 ******************************************************************************/
3153 
3154 tree
rename_symbols(tree t,hashmap<string,string> h)3155 rename_symbols (tree t, hashmap<string,string> h) {
3156   if (is_atomic (t)) {
3157     bool same= true;
3158     int pos;
3159     string s= t->label;
3160     for (pos=0; pos<N(s); ) {
3161       int j=pos;
3162       tm_char_forwards (s, pos);
3163       if (j+2 < pos && h->contains (s (j, pos))) {
3164         same= false;
3165         break;
3166       }
3167     }
3168     if (same) return t;
3169     string r;
3170     for (pos=0; pos<N(s); ) {
3171       int j=pos;
3172       tm_char_forwards (s, pos);
3173       if (h->contains (s (j, pos))) r << h [s (j, pos)];
3174       else r << s (j, pos);
3175     }
3176     return r;
3177   }
3178   else if (is_func (t, RAW_DATA)) return t;
3179   else {
3180     int i, n= N(t);
3181     tree r (t, n);
3182     for (i=0; i<n; i++)
3183       r[i]= rename_symbols (t[i], h);
3184     return r;
3185   }
3186 }
3187 
3188 /******************************************************************************
3189 * Rewrite bodies of algorithms
3190 ******************************************************************************/
3191 
3192 tree
upgrade_algorithm(tree t,bool flag=true)3193 upgrade_algorithm (tree t, bool flag= true) {
3194   if (is_atomic (t)) return t;
3195   else if (is_compound (t, "algo", 1))
3196     return compound ("tt", upgrade_algorithm (t[0]));
3197   else if (is_compound (t, "algorithm", 2))
3198     return compound ("named-algorithm-old",
3199                      upgrade_algorithm (t[0]), upgrade_algorithm (t[1]));
3200   else if (flag && is_compound (t, "body", 1))
3201     return compound ("algorithm-body", upgrade_algorithm (t[0]));
3202   else if (is_compound (t, "pile", 1))
3203     return compound ("tabbed", upgrade_algorithm (t[0]));
3204   else if (is_compound (t, "scm-fragment", 1))
3205     return compound ("scm-code", upgrade_algorithm (t[0]));
3206   else if (is_compound (t, "scheme-fragment", 1))
3207     return compound ("scm-code", upgrade_algorithm (t[0]));
3208   else if (is_compound (t, "mmx-fragment", 1))
3209     return compound ("mmx-code", upgrade_algorithm (t[0]));
3210   else if (is_compound (t, "cpp-fragment", 1))
3211     return compound ("cpp-code", upgrade_algorithm (t[0]));
3212   else if (is_compound (t, "shell-fragment", 1))
3213     return compound ("shell-code", upgrade_algorithm (t[0]));
3214   else {
3215     int i, n= N(t);
3216     tree r (t, n);
3217     flag= true;
3218     if (is_document (t))
3219       for (i=0; i<n; i++)
3220         if (is_compound (t[i], "TeXmacs", 1) ||
3221             is_compound (t[i], "style") ||
3222             is_compound (t[i], "initial") ||
3223             is_compound (t[i], "references"))
3224           flag= false;
3225     for (i=0; i<n; i++)
3226       r[i]= upgrade_algorithm (t[i], flag);
3227     return r;
3228   }
3229 }
3230 
3231 /******************************************************************************
3232 * Upgrade mathematical operators
3233 ******************************************************************************/
3234 
3235 tree
upgrade_math_ops(tree t)3236 upgrade_math_ops (tree t) {
3237   if (is_atomic (t)) return t;
3238   int i, n= N(t);
3239   tree r (t, n);
3240   for (i=0; i<n; i++)
3241     r[i]= upgrade_math_ops (t[i]);
3242   if (is_func (t, WITH, 3) &&
3243       is_atomic (t[2]) &&
3244       is_alpha (t[2]->label) &&
3245       t[0] == "math-font-family")
3246     {
3247       if (t[1] == "trm") return compound ("math-up", t[2]);
3248       if (t[1] == "tss") return compound ("math-ss", t[2]);
3249       if (t[1] == "ttt") return compound ("math-tt", t[2]);
3250       if (t[1] == "rm") return compound ("math-up", t[2]);
3251       if (t[1] == "up") return compound ("math-up", t[2]);
3252       if (t[1] == "bf") return compound ("math-bf", t[2]);
3253       if (t[1] == "sl") return compound ("math-sl", t[2]);
3254       if (t[1] == "it") return compound ("math-it", t[2]);
3255       if (t[1] == "ss") return compound ("math-ss", t[2]);
3256       if (t[1] == "tt") return compound ("math-tt", t[2]);
3257     }
3258   if (n == 1 && starts (as_string (L(t)), "math-")) {
3259     if (is_compound (t, "math-ord")) return compound ("math-ordinary", t[0]);
3260     if (is_compound (t, "math-punct")) return compound ("math-separator", t[0]);
3261     if (is_compound (t, "math-bin")) return compound ("math-plus", t[0]);
3262     if (is_compound (t, "math-rel")) return compound ("math-relation", t[0]);
3263     if (is_compound (t, "math-op")) return compound ("math-big", t[0]);
3264   }
3265   return r;
3266 }
3267 
3268 /******************************************************************************
3269 * Cleaning spurious spaces in the document
3270 ******************************************************************************/
3271 
3272 static bool
only_spaces(string s)3273 only_spaces (string s) {
3274   for (int i=0; i<N(s); i++)
3275     if (s[i] != ' ') return false;
3276   return true;
3277 }
3278 
3279 static bool
eat_spaces(tree t,bool after)3280 eat_spaces (tree t, bool after) {
3281   (void) after;
3282   if (is_atomic (t)) return false;
3283   return
3284     is_compound (t, "hide-preamble") ||
3285     is_compound (t, "doc-data") ||
3286     is_compound (t, "abstract") ||
3287     is_compound (t, "bibliography") ||
3288     is_compound (t, "bibitem") ||
3289     is_compound (t, "bibitem*");
3290 }
3291 
3292 static tree
clean_spaces(tree t)3293 clean_spaces (tree t) {
3294   if (is_atomic (t)) return t;
3295   int i, n= N(t);
3296   tree r (t, n);
3297   for (i=0; i<n; i++)
3298     r[i]= clean_spaces (t[i]);
3299   if (!is_func (r, CONCAT)) return r;
3300   t= r;
3301   r= tree (CONCAT);
3302   for (i=0; i<n; i++)
3303     if (!is_atomic (t[i])) r << t[i];
3304     else {
3305       string s= t[i]->label;
3306       if (i>0 && eat_spaces (t[i-1], true))
3307         while (starts (s, " ")) s= s (1, N(s));
3308       if (i<N(t)-1 && eat_spaces (t[i+1], false))
3309         while (ends (s, " ")) s= s (0, N(s)-1);
3310       if (s != "") r << tree (s);
3311     }
3312   if (N(r) == 0) return "";
3313   if (N(r) == 1) return r[0];
3314   return r;
3315 }
3316 
3317 /******************************************************************************
3318 * Cleaning the document header
3319 ******************************************************************************/
3320 
3321 static tree
search_header_tag(tree t,string which,tree & h)3322 search_header_tag (tree t, string which, tree& h) {
3323   if (is_compound (t, which)) {
3324     h << t;
3325     return "";
3326   }
3327   if (is_func (t, DOCUMENT)) {
3328     tree r (DOCUMENT);
3329     for (int i=0; i<N(t); i++) {
3330       if (is_compound (t[i], which)) h << t[i];
3331       else if (is_func (t[i], SURROUND, 3)) {
3332         tree x= search_header_tag (t[i], which, h);
3333         if (x != "") r << x;
3334       }
3335       else r << t[i];
3336     }
3337     return r;
3338   }
3339   if (is_func (t, SURROUND, 3)) {
3340     tree r (SURROUND, 3);
3341     r[0]= search_header_tag (t[0], which, h);
3342     r[2]= search_header_tag (t[2], which, h);
3343     r[1]= search_header_tag (t[1], which, h);
3344     if (r[0] == "" && r[1] == "") r= r[2];
3345     else if (r[0] == "" && r[2] == "") r= r[1];
3346     else if (r[1] == "" && r[2] == "") r= r[0];
3347     return r;
3348   }
3349   return t;
3350 }
3351 
3352 tree
clean_header(tree t)3353 clean_header (tree t) {
3354   if (!is_func (t, DOCUMENT)) return t;
3355   tree r        (DOCUMENT);
3356   tree preamble (DOCUMENT);
3357   tree title    (DOCUMENT);
3358   tree abstract (DOCUMENT);
3359   t= search_header_tag (t, "hide-preamble", preamble);
3360   t= search_header_tag (t, "doc-data", title);
3361   t= search_header_tag (t, "abstract", abstract);
3362   while (N(t) > 0 && is_atomic (t[0]) && only_spaces (t[0]->label))
3363     t= t (1, N(t));
3364   r << A (preamble);
3365   r << A (title);
3366   r << A (abstract);
3367   r << A (t);
3368   return r;
3369 }
3370 
3371 /******************************************************************************
3372 * Upgrade graphical attributes
3373 ******************************************************************************/
3374 
3375 static void
replace_dash_style(tree & t,string var)3376 replace_dash_style (tree& t, string var) {
3377   if (find_attr (t, var)) {
3378     tree val= get_attr (t, var, "default");
3379     if (is_func (val, TUPLE)) {
3380       string nval;
3381       for (int i=0; i<N(val); i++)
3382         if (val[i] == "0") nval << "0";
3383         else nval << "1";
3384       t= set_attr (t, var, tree (nval));
3385     }
3386   }
3387 }
3388 
3389 static tree
encode_arrow(tree t)3390 encode_arrow (tree t) {
3391   if (is_func (t, WITH, 3) && t[0] == "dash-style") {
3392     if (t[2] == tree (LINE,
3393                       tuple ("10ln", "6ln"),
3394                       tuple ("0ln", "0ln"),
3395                       tuple ("10ln", "-6ln")))
3396       return "<less>";
3397     if (t[2] == tree (LINE,
3398                       tuple ("-10ln", "6ln"),
3399                       tuple ("0ln", "0ln"),
3400                       tuple ("-10ln", "-6ln")))
3401       return "<gtr>";
3402   }
3403   return t;
3404 }
3405 
3406 static void
replace_line_arrows(tree & t,string var,string begin,string end)3407 replace_line_arrows (tree& t, string var, string begin, string end) {
3408   if (find_attr (t, var)) {
3409     tree val= get_attr (t, var, "default");
3410     t= set_attr (t, "arrow-length", "10ln");
3411     t= set_attr (t, "arrow-height", "6ln");
3412     if (is_func (val, TUPLE, 1))
3413       t= set_attr (t, end, encode_arrow (val[0]));
3414     if (is_func (val, TUPLE, 2)) {
3415       t= set_attr (t, begin, encode_arrow (val[0]));
3416       t= set_attr (t, end, encode_arrow (val[1]));
3417     }
3418     t= remove_attr (t, var);
3419   }
3420 }
3421 
3422 static void
replace_magnification(tree & t,string var,string repl)3423 replace_magnification (tree& t, string var, string repl) {
3424   tree body= t[N(t)-1];
3425   if (find_attr (t, var))
3426     if (is_func (body, GRAPHICS) ||
3427         is_func (body, GR_GROUP) ||
3428         is_func (body, TEXT_AT) ||
3429         is_func (body, _POINT) ||
3430         is_func (body, LINE) ||
3431         is_func (body, CLINE) ||
3432         is_func (body, SPLINE) ||
3433         is_func (body, CSPLINE) ||
3434         is_func (body, ARC) ||
3435         is_func (body, CARC) ||
3436         is_func (body, VAR_SPLINE))
3437       {
3438         tree val= get_attr (t, var, "1");
3439         if (is_func (val, TIMES, 2) &&
3440             is_func (val[1], VALUE, 1) &&
3441             val[1][0] == var)
3442           val= val[0];
3443         t= set_attr (t, repl, val);
3444         t= remove_attr (t, var);
3445       }
3446 }
3447 
3448 static tree
upgrade_gr_attributes(tree t)3449 upgrade_gr_attributes (tree t) {
3450   int i;
3451   if (is_atomic (t)) return t;
3452   if (is_func (t, WITH)) {
3453     replace_dash_style (t, "dash-style");
3454     replace_dash_style (t, "gr-dash-style");
3455     replace_line_arrows (t, "line-arrows", "arrow-begin", "arrow-end");
3456     replace_line_arrows (t, "gr-line-arrows",
3457                             "gr-arrow-begin", "gr-arrow-end");
3458     replace_magnification (t, "magnification", "magnify");
3459   }
3460   int n= N(t);
3461   tree r (t, n);
3462   for (i=0; i<n; i++)
3463     r[i]= upgrade_gr_attributes (t[i]);
3464   return r;
3465 }
3466 
3467 /******************************************************************************
3468 * Upgrade cursor tag
3469 ******************************************************************************/
3470 
3471 static tree
upgrade_cursor(tree t)3472 upgrade_cursor (tree t) {
3473   int i;
3474   if (is_atomic (t)) return t;
3475   if (is_func (t, VALUE)) {
3476     if (t == tree (VALUE, "cursor")) return compound ("cursor");
3477     if (t == tree (VALUE, "math-cursor")) return compound ("math-cursor");
3478   }
3479   int n= N(t);
3480   tree r (t, n);
3481   for (i=0; i<n; i++)
3482     r[i]= upgrade_cursor (t[i]);
3483   return r;
3484 }
3485 
3486 /******************************************************************************
3487 * Upgrade encoding to unicode whenever cyrillic font is used
3488 ******************************************************************************/
3489 
3490 bool
become_cyrillic(string s1,string s2)3491 become_cyrillic (string s1, string s2) {
3492   return (s1 == "font" && s2 == "cyrillic");}
3493 
3494 bool
become_other(string s1,string s2)3495 become_other (string s1, string s2) {
3496   return (s1 == "font" && s2 != "cyrillic");
3497 }
3498 
3499 tree
upgrade_cyrillic_encoding(tree t,bool cyrillic)3500 upgrade_cyrillic_encoding (tree t, bool cyrillic) {
3501   if (is_atomic (t)) {
3502     if (cyrillic) return cyrillic_subset_in_t2a_to_code_point (as_string(t));
3503     else          return t;
3504   }
3505   else {
3506     int i = 0;
3507     if (is_func(t, WITH)) {
3508       for (i = 0 ; i < N(t) - 1 ; i+=2) {
3509         if (!cyrillic
3510             && become_cyrillic (as_string (t[i]), as_string (t[i+1])))
3511           cyrillic = true;
3512         else if (cyrillic
3513             && become_other (as_string (t[i]), as_string (t[i+1])))
3514           cyrillic = false;
3515       }
3516       t[N(t)-1] = upgrade_cyrillic_encoding (t[N(t)-1], cyrillic);
3517     }
3518     else {
3519       for (i = 0 ; i < N(t) ; i++)
3520         t[i] = upgrade_cyrillic_encoding (t[i], cyrillic);
3521     }
3522     return t;
3523   }
3524 }
3525 
3526 array<tree>
get_childs_by_name(tree t,string s)3527 get_childs_by_name (tree t, string s) {
3528   array<tree> r = array<tree>();
3529   if (!is_atomic (t))
3530     for (int i = 0 ; i < N(t) ; i++) {
3531       if (as_string (L(t[i])) == s) r << t[i];
3532     }
3533   return r;
3534 }
3535 
3536 static tree
upgrade_cyrillic(tree t)3537 upgrade_cyrillic (tree t) {
3538   bool cyrillic = false;
3539   array<tree> initial, collection, associate;
3540   initial = get_childs_by_name (t, "initial");
3541   for (int i = 0 ; i < N(initial) ; i++){
3542     collection = get_childs_by_name (initial[i], "collection");
3543     for (int j = 0 ; j < N(collection) ; j++){
3544       associate = get_childs_by_name (collection[j], "associate");
3545       for (int k = 0 ; k < N(associate) ; k++) {
3546         if (is_func(associate[k], ASSOCIATE, 2) && associate[k][0] == "font")
3547           cyrillic = (associate[k][1] == "cyrillic");
3548       }
3549     }
3550   }
3551   return upgrade_cyrillic_encoding(t, cyrillic);
3552 }
3553 
3554 /******************************************************************************
3555 * Upgrade metadata storage format
3556 ******************************************************************************/
3557 
3558 static tree
correct_metadata(tree t)3559 correct_metadata (tree t) {
3560   if (is_atomic (t)) return t;
3561   tree r;
3562 
3563   if (is_compound (t, "author-misc"))
3564     r= compound ("author-note");
3565   else
3566     r= compound (as_string (L(t)));
3567 
3568   for (int i=0; i<N(t); i++)
3569     r << correct_metadata (t[i]);
3570   return r;
3571 }
3572 
3573 static tree
upgrade_metadata(tree t)3574 upgrade_metadata (tree t) {
3575   if (is_atomic (t)) return t;
3576   tree r;
3577   string l;
3578   if (is_compound (t, "doc-abstract"))   l= "abstract";
3579   if (is_compound (t, "author-address")) l= "author-affiliation";
3580   if (is_compound (t, "doc-AMS-class"))  l= "abstract-msc";
3581   if (is_compound (t, "doc-msc"))        l= "abstract-msc";
3582   if (is_compound (t, "doc-keywords"))   l= "abstract-keywords";
3583 
3584   if (is_compound (t, "doc-author-data")) {
3585     tree r= compound ("author-data");
3586     for (int i=0; i<N(t); i++)
3587       r << upgrade_metadata (t[i]);
3588     return compound ("doc-author", r);
3589   }
3590 
3591   if (l == "") r= compound (as_string (L(t)));
3592   else         r= compound (l);
3593   for (int i=0; i<N(t); i++)
3594     r << upgrade_metadata (t[i]);
3595   return r;
3596 }
3597 
3598 static tree
remove_abstract_data(tree t,array<tree> & abstract_data)3599 remove_abstract_data (tree t, array<tree> &abstract_data) {
3600   // Remove all abstract-msc and abstract-keywords found in a doc-data
3601   // structure, and store them in abstract_data.
3602   tree r(L(t));
3603   if (is_compound (t, "doc-data")) {
3604     for (int i=0; i<N(t); i++) {
3605       if (is_compound (t[i], "abstract-msc") ||
3606           is_compound (t[i], "abstract-keywords"))
3607         abstract_data << t[i];
3608       else r << t[i];
3609     }
3610   }
3611   else if (is_atomic (t))
3612     return t;
3613   else {
3614     r= tree (t, N(t));
3615     for (int i=0; i<N(t); i++)
3616       r[i]= remove_abstract_data (t[i], abstract_data);
3617   }
3618   return r;
3619 }
3620 
3621 static array<tree>
sort_abstract_data(array<tree> abstract_data)3622 sort_abstract_data (array<tree> abstract_data) {
3623   // Sort and merge abstract-msc and abstract-keywords compounds
3624   bool has_doc_msc= false, has_doc_keywords= false;
3625   tree doc_msc (make_tree_label ("abstract-msc"));
3626   tree doc_keywords (make_tree_label ("abstract-keywords"));
3627   array<tree> r;
3628 
3629   for (int i=0; i<N(abstract_data); i++) {
3630     if (is_compound (abstract_data[i], "abstract-msc")) {
3631       has_doc_msc= true;
3632       for (int j=0; j<N(abstract_data[i]); j++)
3633         doc_msc << abstract_data[i][j];
3634     }
3635     if (is_compound (abstract_data[i], "abstract-keywords")) {
3636       has_doc_keywords= true;
3637       for (int j=0; j<N(abstract_data[i]); j++)
3638         doc_keywords << abstract_data[i][j];
3639     }
3640   }
3641   if (has_doc_msc) r << doc_msc;
3642   if (has_doc_keywords) r << doc_keywords;
3643 
3644   return r;
3645 }
3646 
3647 static tree
merge_abstract_data(tree t,array<tree> abstract_data,bool & stop)3648 merge_abstract_data (tree t, array<tree> abstract_data, bool &stop) {
3649   // Merge abstract_data with the first abstract found.
3650   tree r;
3651   if (stop || is_atomic (t)) return t;
3652   else if (is_compound (t, "abstract", 1)) {
3653     stop= true;
3654     r= tree (make_tree_label ("abstract-data"));
3655     r << t;
3656     for (int i=0; i<N(abstract_data); i++)
3657       r << abstract_data[i];
3658   }
3659   else {
3660     r= tree (t, N(t));
3661     for (int i=0; i<N(t); i++)
3662       r[i]= merge_abstract_data (t[i], abstract_data, stop);
3663   }
3664   return r;
3665 }
3666 
3667 static tree
add_abstract_data(tree t,array<tree> abstract_data,bool & stop)3668 add_abstract_data (tree t, array<tree> abstract_data, bool &stop) {
3669   // Add abstract_data after the first doc-data found.
3670   if (stop || is_atomic (t)) return t;
3671   tree r= tree (L(t));
3672   for (int i=0; i<N(t); i++) {
3673     if (is_compound (t[i], "doc-data")) {
3674       stop= true;
3675       r << t[i];
3676       r << tree (make_tree_label ("abstract-data"));
3677       for (int j=0; j<N(abstract_data); j++)
3678         r[N(r)-1] << abstract_data[j];
3679     }
3680     else
3681       r << add_abstract_data (t[i], abstract_data, stop);
3682   }
3683   return r;
3684 }
3685 
3686 static tree
upgrade_abstract_data(tree t)3687 upgrade_abstract_data (tree t) {
3688   // Remove all abstract-msc and abstract-keywords found in a doc-data
3689   // structure, and merge them with the first abstract found.
3690   array<tree> abstract_data;
3691   tree r= remove_abstract_data (t, abstract_data);
3692   bool stop= false;
3693   if (N(abstract_data) > 0) {
3694     abstract_data= sort_abstract_data (abstract_data);
3695     r= merge_abstract_data (r, abstract_data, stop);
3696     if (stop) return r;
3697     else return add_abstract_data (r, abstract_data, stop);
3698   }
3699   return t;
3700 }
3701 
3702 /******************************************************************************
3703 * Upgrade unroll
3704 ******************************************************************************/
3705 
3706 tree
upgrade_unroll(tree t)3707 upgrade_unroll (tree t) {
3708   if (is_atomic (t)) return t;
3709   int i, n= N(t);
3710   tree r (t, n);
3711   for (i=0; i<n; i++) {
3712     r[i]= upgrade_unroll (t[i]);
3713     if (is_compound (t, "unroll") && is_func (r[i], HIDDEN, 1))
3714       r[i]= compound ("hidden*", r[i][0]);
3715   }
3716   return r;
3717 }
3718 
3719 /******************************************************************************
3720 * Upgrade style files
3721 ******************************************************************************/
3722 
3723 tree
upgrade_style(tree t,bool flag)3724 upgrade_style (tree t, bool flag) {
3725   int i;
3726   if (is_atomic (t)) return t;
3727   else if (is_compound (t, "style") || is_func (t, TUPLE)) {
3728     int n= N(t);
3729     tree r (t, 0);
3730     bool doc= false;
3731     for (i=0; i<n; i++)
3732       if (!flag) r << upgrade_style (t[i], is_compound (t, "style"));
3733       else if (t[i] == "beamer") r << "old-beamer";
3734       else if (t[i] == "generic") r << "old-generic";
3735       else if (t[i] == "help") r << "old-help";
3736       else if (t[i] == "letter") r << "old-letter";
3737       else if (t[i] == "seminar") r << "old-seminar";
3738       else if (t[i] == "tmdoc-keyboard") { if (!doc) r << "doc"; doc= true; }
3739       else if (t[i] == "tmdoc-markup") { if (!doc) r << "doc"; doc= true; }
3740       else if (t[i] == "tmdoc-traversal") { if (!doc) r << "doc"; doc= true; }
3741       else r << upgrade_style (t[i], flag);
3742     return r;
3743   }
3744   else {
3745     int n= N(t);
3746     tree r (t, n);
3747     for (i=0; i<n; i++)
3748       r[i]= upgrade_style (t[i], flag);
3749     return r;
3750   }
3751 }
3752 
3753 /******************************************************************************
3754 * Upgrade document language
3755 ******************************************************************************/
3756 
3757 tree
upgrade_doc_language(tree t)3758 upgrade_doc_language (tree t) {
3759   tree style= extract (t, "style");
3760   tree init = extract (t, "initial");
3761   if (init == "" || N(init) == 0) return t;
3762 
3763   string lan= "";
3764   for (int i=0; i<N(init); i++)
3765     if (is_func (init[i], ASSOCIATE, 2) && init[i][0] == LANGUAGE)
3766       lan= as_string (init[i][1]);
3767 
3768   tree new_style= copy (style);
3769   tree new_init = tree (COLLECTION);
3770   for (int i=0; i<N(init); i++)
3771     if (is_func (init[i], ASSOCIATE, 2) && init[i][0] == LANGUAGE)
3772       new_style << init[i][1];
3773     else if (is_func (init[i], ASSOCIATE, 2) && init[i][0] == FONT) {
3774       if (init[i][1] == "cyrillic" &&
3775           (lan == "bulgarian" || lan == "russian" || lan == "ukrainian"));
3776       else if ((init[i][1] == "sys-chinese" || init[i][1] == "fireflysung") &&
3777                (lan == "chinese" || lan == "taiwanese"));
3778       else if ((init[i][1] == "sys-japanese" || init[i][1] == "ipa") &&
3779                lan == "japanese");
3780       else if ((init[i][1] == "sys-korean" || init[i][1] == "unbatang") &&
3781                lan == "korean");
3782       else new_init << init[i];
3783     }
3784     else new_init << init[i];
3785 
3786   if (new_style != style)
3787     t= change_doc_attr (t, "style", new_style);
3788   if (new_init != init)
3789     t= change_doc_attr (t, "initial", new_init);
3790   return t;
3791 }
3792 
3793 /******************************************************************************
3794 * Rename varsession package
3795 ******************************************************************************/
3796 
3797 tree
upgrade_varsession(tree t)3798 upgrade_varsession (tree t) {
3799   int i;
3800   if (is_atomic (t)) return t;
3801   else if (is_compound (t, "style") || is_func (t, TUPLE)) {
3802     int n= N(t);
3803     tree r (t, n);
3804     for (i=0; i<n; i++) {
3805       if (t[i] == "varsession") r[i]= "framed-session";
3806       else r[i]= upgrade_varsession (t[i]);
3807     }
3808     return r;
3809   }
3810   else if (is_func (t, DOCUMENT)) {
3811     int n= N(t);
3812     tree r (t, n);
3813     for (i=0; i<n; i++)
3814       r[i]= upgrade_varsession (t[i]);
3815     return r;
3816   }
3817   else return t;
3818 }
3819 
3820 /******************************************************************************
3821 * Upgrade subsessions
3822 ******************************************************************************/
3823 
3824 tree
upgrade_subsession(tree t,bool in_session=false)3825 upgrade_subsession (tree t, bool in_session= false) {
3826   int i;
3827   if (is_atomic (t)) return t;
3828   else if (in_session && is_compound (t, "folded", 2))
3829     return compound ("folded-subsession", upgrade_subsession (t[0]),
3830                      upgrade_subsession (t[1], true));
3831   else if (in_session && is_compound (t, "unfolded", 2))
3832     return compound ("unfolded-subsession", upgrade_subsession (t[0]),
3833                      upgrade_subsession (t[1], true));
3834   else {
3835     bool flag=
3836       (is_func (t, DOCUMENT) && in_session) ||
3837       is_compound (t, "session");
3838     int n= N(t);
3839     tree r (t, n);
3840     for (i=0; i<n; i++)
3841       r[i]= upgrade_subsession (t[i], flag);
3842     return r;
3843   }
3844 }
3845 
3846 /******************************************************************************
3847 * Upgrade quotes
3848 ******************************************************************************/
3849 
3850 static hashset<string> std_textual_envs;
3851 
3852 static array<string>&
operator <<(array<string> & a,const char * s)3853 operator << (array<string>& a, const char* s) {
3854   return a << string (s);
3855 }
3856 
3857 static bool
is_std_textual_env(string s)3858 is_std_textual_env (string s) {
3859   if (N(std_textual_envs) == 0) {
3860     array<string> a;
3861     a << "part" << "chapter" << "section" << "subsection"
3862       << "subsubsection" << "paragraph" << "subparagraph" << "appendix"
3863       << "part*" << "chapter*" << "section*" << "subsection*"
3864       << "subsubsection*" << "paragraph*" << "subparagraph*" << "appendix*"
3865       << "abstract" << "theorem" << "proposition" << "lemma"
3866       << "corollary" << "proof" << "axiom" << "definition"
3867       << "notation" << "conjecture" << "remark" << "note"
3868       << "example" << "exercise" << "warning" << "convention"
3869       << "theorem*" << "proposition*" << "lemma*"
3870       << "corollary*" << "proof*" << "axiom*" << "definition*"
3871       << "notation*" << "conjecture*" << "remark*" << "note*"
3872       << "example*" << "exercise*" << "warning*" << "convention*"
3873       << "acknowledgments" << "quote" << "quotation" << "verse"
3874       << "indent" << "compact" << "jump-in"
3875       << "algorithm" << "body" << "render-code"
3876       << "center" << "left-aligned" << "right-aligned"
3877       << "small-table" << "big-table" << "small-figure" << "big-figure"
3878       << "tabular" << "tabular*" << "block" << "block*" << "descriptive-table"
3879       << "description" << "itemize" << "enumerate"
3880       << "bibliography" << "bib-list" << "thebibliography"
3881       << "bib-field" << "bib-entry" << "db-field" << "db-entry"
3882       << "itemize-minus" << "enumerate-roman" << "enumerate-alpha"
3883       << "strong" << "em" << "dfn" << "sample"
3884       << "name" << "person" << "cite*" << "abbr" << "acronym"
3885       << "really-tiny" << "tiny" << "very-small" << "small" << "flat-size"
3886       << "normal-size" << "large" << "very-large" << "huge" << "really-huge"
3887       << "underline" << "overline" << "pastel" << "greyed" << "light"
3888       << "british" << "bulgarian" << "chinese" << "croatian"
3889       << "czech" << "danish" << "dutch" << "english" << "finnish"
3890       << "french" << "german" << "greek" << "hungarian" << "italian"
3891       << "japanese" << "korean" << "polish" << "portuguese" << "romanian"
3892       << "russian" << "slovene" << "spanish" << "swedish"
3893       << "taiwanese" << "ukrainian"
3894       << "switch" << "screens" << "tiny-switch"
3895       << "shown" << "hidden" << "shown*" << "hidden*"
3896       << "unroll" << "unroll-compressed" << "unroll-phantoms" << "unroll-greyed"
3897       << "folded" << "unfolded";
3898     for (int i=0; i<N(a); i++) std_textual_envs->insert (a[i]);
3899   }
3900   return std_textual_envs->contains (s);
3901 }
3902 
3903 static string
upgrade_quotes(string s)3904 upgrade_quotes (string s) {
3905   string r;
3906   int i, n= N(s);
3907   for (i=0; i<n; )
3908     if (s[i] == '<') {
3909       int start= i;
3910       tm_char_forwards (s, i);
3911       r << s (start, i);
3912     }
3913     else if (s[i] == '-' && i+1 < n && s[i+1] == '-') { r << "\25"; i += 2; }
3914     else if (s[i] == '\'' && i+1 < n && s[i+1] == '\'') { r << "\21"; i += 2; }
3915     else if (s[i] == '`' && i+1 < n && s[i+1] == '`') { r << "\20"; i += 2; }
3916     else { r << s[i]; i++; }
3917   return r;
3918 }
3919 
3920 tree
upgrade_quotes(tree t)3921 upgrade_quotes (tree t) {
3922   if (is_atomic (t))
3923     return upgrade_quotes (t->label);
3924   else if (is_concat (t)) {
3925     int i, n= N(t);
3926     tree r (t, n);
3927     bool adjust= false;
3928     for (i=0; i<n; i++) {
3929       adjust= adjust || is_compound (t[i], "emdash", 0);
3930       r[i]= upgrade_quotes (t[i]);
3931     }
3932     if (adjust) r= simplify_correct (r);
3933     return r;
3934   }
3935   else if (is_compound (t, "emdash", 0))
3936     return "\26";
3937   else if (is_compound (t, "body", 1))
3938     return compound ("body", upgrade_quotes (t[0]));
3939   else {
3940     int i, n= N(t);
3941     tree r (t, n);
3942     for (i=0; i<n; i++) {
3943       if (is_std_textual_env (as_string (L(t))))
3944         r[i]= upgrade_quotes (t[i]);
3945       else if (std_drd->get_type_child (t, i) != TYPE_REGULAR ||
3946                std_drd->get_env_child (t, i, MODE, "text") != "text")
3947         r[i]= t[i];
3948       else r[i]= upgrade_quotes (t[i]);
3949     }
3950     return r;
3951   }
3952 }
3953 
3954 /******************************************************************************
3955 * Upgrade ancient
3956 ******************************************************************************/
3957 
3958 static charp equation_tags[]= {
3959   "equation", "equation*", "eqnarray", "eqnarray*",
3960   "leqnarray", "leqnarray*", "align", "align*",
3961   "falign", "falign*", "aligned", "aligned*",
3962   "multline", "multline*", "gather", "gather*",
3963   "eqsplit", "eqsplit*",
3964   ""
3965 };
3966 
3967 bool
is_equation_env(tree t)3968 is_equation_env (tree t) {
3969   if (is_atomic (t) || N(t) != 1) return false;
3970   static hashset<tree_label> H;
3971   if (N(H) == 0)
3972     for (int i=0; equation_tags[i][0] != '\0'; i++)
3973       H->insert (as_tree_label (equation_tags[i]));
3974   return H->contains (L(t));
3975 }
3976 
3977 tree
upgrade_ancient(tree t)3978 upgrade_ancient (tree t) {
3979   // Miscellaneous upgradings for old documents
3980   if (is_atomic (t)) return t;
3981   else if (is_func (t, INACTIVE, 1) && is_func (t[0], RIGID))
3982     return upgrade_ancient (t[0]);
3983   else if (is_equation_env (t) && !is_func (t[0], DOCUMENT))
3984     return tree (L(t), tree (DOCUMENT, upgrade_ancient (t[0])));
3985   else {
3986     int i, n= N(t);
3987     tree r (t, n);
3988     for (i=0; i<n; i++)
3989       r[i]= upgrade_ancient (t[i]);
3990     if (is_func (r, WITH)) {
3991       bool font_series= false;
3992       for (i=0; i+1<n; i+=2)
3993         if (r[i] == FONT_SERIES) font_series= true;
3994       for (i=0; i+1<n; i+=2)
3995         if (r[i] == MATH_FONT_SERIES && !font_series) {
3996           tree ins= tree (WITH, FONT_SERIES, copy (r[i+1]));
3997           return r (0, i) * ins * r (i, N(r));
3998         }
3999     }
4000     return r;
4001   }
4002 }
4003 
4004 /******************************************************************************
4005 * Upgrade from previous versions
4006 ******************************************************************************/
4007 
4008 tree
upgrade_tex(tree t)4009 upgrade_tex (tree t) {
4010   upgrade_tex_flag= true;
4011   t= upgrade_apply_expand_value (t);
4012   t= upgrade_new_environments (t);
4013   t= upgrade_items (t);
4014   t= upgrade_table (t);
4015   t= upgrade_split (t, false);
4016   t= simplify_correct (upgrade_mod_symbols (t));
4017   t= upgrade_menus_in_help (t);
4018   t= upgrade_capitalize_menus (t);
4019   t= upgrade_formatting (t);
4020   t= upgrade_expand (t, EXPAND);
4021   t= upgrade_expand (t, HIDE_EXPAND);
4022   t= upgrade_expand (t, VAR_EXPAND);
4023   t= upgrade_xexpand (t);
4024   t= upgrade_function (t);
4025   t= upgrade_apply (t);
4026   t= upgrade_env_vars (t);
4027   t= upgrade_style_rename (t);
4028   t= upgrade_item_punct (t);
4029   t= substitute (t, tree (VALUE, "hrule"), compound ("hrule"));
4030   t= upgrade_math (t);
4031   t= upgrade_resize_clipped (t);
4032   t= with_correct (t);
4033   t= superfluous_with_correct (t);
4034   t= upgrade_brackets (t);
4035   t= move_brackets (t);
4036   t= upgrade_image (t);
4037   t= upgrade_math_ops (t);
4038   t= clean_spaces (t);
4039   t= clean_header (t);
4040   t= upgrade_doc_language (t);
4041   t= upgrade_quotes (t);
4042   upgrade_tex_flag= false;
4043   return t;
4044 }
4045 
4046 tree
upgrade_mathml(tree t)4047 upgrade_mathml (tree t) {
4048   t= upgrade_brackets (t, "math");
4049   t= downgrade_big (t);
4050   return t;
4051 }
4052 
4053 tree
upgrade(tree t,string version)4054 upgrade (tree t, string version) {
4055   if (version_inf (version, "0.3.1.9")) {
4056     path p;
4057     t= upgrade_textual (t, p);
4058   }
4059   if (version_inf (version, "0.3.3.1"))
4060     t= upgrade_apply_expand_value (t);
4061   if (version_inf (version, "0.3.3.20"))
4062     t= upgrade_new_environments (t);
4063   if (version_inf (version, "0.3.3.24"))
4064     t= upgrade_items (t);
4065   if (version_inf (version, "0.3.4.4"))
4066     t= upgrade_resize (t);
4067   if (version_inf_eq (version, "0.3.4.7"))
4068     t= upgrade_table (t);
4069   if (version_inf_eq (version, "0.3.4.8"))
4070     t= upgrade_split (t, false);
4071   if (version_inf_eq (version, "0.3.5.6"))
4072     t= upgrade_project (t);
4073   if (version_inf_eq (version, "0.3.5.10"))
4074     t= upgrade_title (t);
4075   if (version_inf_eq (version, "1.0.0.1"))
4076     t= upgrade_cas (t);
4077   if (version_inf_eq (version, "1.0.0.8"))
4078     t= simplify_correct (upgrade_mod_symbols (t));
4079   if (version_inf_eq (version, "1.0.0.11"))
4080     t= upgrade_menus_in_help (t);
4081   if (version_inf_eq (version, "1.0.0.13"))
4082     t= upgrade_capitalize_menus (t);
4083   if (version_inf_eq (version, "1.0.0.19"))
4084     t= upgrade_traverse_branch (t);
4085   if (version_inf_eq (version, "1.0.1.20"))
4086     t= upgrade_session (t);
4087   if (version_inf_eq (version, "1.0.2.0"))
4088     t= upgrade_formatting (t);
4089   if (version_inf_eq (version, "1.0.2.3"))
4090     t= upgrade_expand (t, EXPAND);
4091   if (version_inf_eq (version, "1.0.2.4"))
4092     t= upgrade_expand (t, HIDE_EXPAND);
4093   if (version_inf_eq (version, "1.0.2.5")) {
4094     t= upgrade_expand (t, VAR_EXPAND);
4095     t= upgrade_xexpand (t);
4096   }
4097   if (version_inf_eq (version, "1.0.2.6")) {
4098     t= upgrade_function (t);
4099     t= upgrade_apply (t);
4100   }
4101   if (version_inf_eq (version, "1.0.2.8"))
4102     t= upgrade_env_vars (t);
4103   if (version_inf_eq (version, "1.0.3.3"))
4104     t= upgrade_use_package (t);
4105   if (version_inf_eq (version, "1.0.3.4"))
4106     t= upgrade_style_rename (t);
4107   if (version_inf_eq (version, "1.0.3.4"))
4108     t= upgrade_item_punct (t);
4109   if (version_inf_eq (version, "1.0.3.7"))
4110     t= upgrade_page_pars (t);
4111   if (version_inf_eq (version, "1.0.4")) {
4112     t= substitute (t, tree (VALUE, "hrule"), compound ("hrule"));
4113     t= upgrade_doc_info (t);
4114   }
4115   if (version_inf_eq (version, "1.0.4.6"))
4116     t= upgrade_bibliography (t);
4117   if (version_inf_eq (version, "1.0.5.4"))
4118     t= upgrade_switch (t);
4119   if (version_inf_eq (version, "1.0.5.7"))
4120     t= upgrade_fill (t);
4121   if (version_inf_eq (version, "1.0.5.8"))
4122     t= upgrade_graphics (t);
4123   if (version_inf_eq (version, "1.0.5.11"))
4124     t= upgrade_textat (t);
4125   if (version_inf_eq (version, "1.0.6.1"))
4126     t= upgrade_cell_alignment (t);
4127   if (version_inf_eq (version, "1.0.6.2"))
4128     t= rename_primitive (t, "hyper-link", "hlink");
4129   if (version_inf_eq (version, "1.0.6.2"))
4130     t= upgrade_label_assignment (t);
4131   if (version_inf_eq (version, "1.0.6.10"))
4132     t= upgrade_scheme_doc (t);
4133   if (version_inf_eq (version, "1.0.6.14"))
4134     t= upgrade_mmx (t);
4135   if (version_inf_eq (version, "1.0.7.1"))
4136     t= upgrade_session (t, "scheme", "default");
4137   if (version_inf_eq (version, "1.0.7.6"))
4138     t= upgrade_presentation (t);
4139   if (version_inf_eq (version, "1.0.7.6") && is_non_style_document (t))
4140     t= upgrade_math (t);
4141   if (version_inf_eq (version, "1.0.7.7"))
4142     t= upgrade_resize_clipped (t);
4143   if (version_inf_eq (version, "1.0.7.7"))
4144     t= upgrade_image (t);
4145   if (version_inf_eq (version, "1.0.7.7"))
4146     t= upgrade_root_switch (t);
4147   if (version_inf_eq (version, "1.0.7.8"))
4148     t= upgrade_hyphenation (t);
4149   if (DEBUG_CORRECT)
4150     if (is_non_style_document (t))
4151       math_status_cumul (t);
4152   if (version_inf_eq (version, "1.0.7.8") && is_non_style_document (t)) {
4153     t= with_correct (t);
4154     t= superfluous_with_correct (t);
4155     t= upgrade_brackets (t);
4156   }
4157   if (version_inf_eq (version, "1.0.7.9")) {
4158     t= move_brackets (t);
4159     if (is_non_style_document (t))
4160       t= upgrade_algorithm (t, false);
4161     t= upgrade_math_ops (t);
4162   }
4163   if (version_inf_eq (version, "1.0.7.10"))
4164     t= downgrade_big (t);
4165   if (version_inf_eq (version, "1.0.7.13"))
4166     t= upgrade_gr_attributes (t);
4167   if (version_inf_eq (version, "1.0.7.14"))
4168     t= upgrade_cursor (t);
4169   if (version_inf_eq (version, "1.0.7.15"))
4170     t= upgrade_cyrillic (t);
4171   if (version_inf_eq (version, "1.0.7.17")) {
4172     t= upgrade_metadata (t);
4173     t= upgrade_abstract_data (t);
4174     t= correct_metadata (t);
4175   }
4176   if (version_inf_eq (version, "1.0.7.20")) {
4177     t= upgrade_unroll (t);
4178     t= upgrade_style (t, false);
4179     t= upgrade_doc_language (t);
4180   }
4181   if (version_inf_eq (version, "1.0.7.21")) {
4182     t= upgrade_varsession (t);
4183     t= upgrade_subsession (t);
4184   }
4185   if (version_inf_eq (version, "1.99.2")) {
4186     t= upgrade_quotes (t);
4187     t= upgrade_ancient (t);
4188   }
4189 
4190   if (is_non_style_document (t))
4191     t= automatic_correct (t, version);
4192   return t;
4193 }
4194