1 
2 /******************************************************************************
3 * MODULE     : totm.cpp
4 * DESCRIPTION: conversion of TeXmacs trees to the TeXmacs file format
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 "drd_std.hpp"
14 
15 /******************************************************************************
16 * Conversion of TeXmacs trees to the present TeXmacs string format
17 ******************************************************************************/
18 
19 struct tm_writer {
20   string  buf;       // the resulting string
21   string  spc;       // "" or " "
22   string  tmp;       // not yet flushed characters
23   int     mode;      // normal: 0, verbatim: 1, mathematics: 2
24 
25   int     tab;       // number of tabs after CR
26   int     xpos;      // current horizontal position in buf
27   bool    spc_flag;  // true if last printed character was a space or CR
28   bool    ret_flag;  // true if last printed character was a CR
29 
tm_writertm_writer30   tm_writer ():
31     buf (""), spc (""), tmp (""), mode (0),
32     tab (0), xpos (0), spc_flag (true), ret_flag (true) {}
33 
34   void cr ();
35   void flush ();
36   void write_space ();
37   void write_return ();
38   void write (string s, bool flag= true, bool encode_space= false);
39   void br (int indent= 0);
40   void tag (string before, string s, string after);
41   void apply (string func, array<tree> args);
42   void write (tree t);
43 };
44 
45 void
cr()46 tm_writer::cr () {
47   int i, n= N(buf);
48   for (i=n-1; i>=0; i--)
49     if ((buf[i] != ' ') || ((i>0) && (buf[i-1] == '\\')))
50       break;
51   if (i<n-1) {
52     buf= buf (0, i+1);
53     n  = n- N(buf);
54     for (i=0; i<n; i++) buf << "\\ ";
55   }
56   buf << '\n';
57   for (i=0; i<min(tab,20); i++) buf << ' ';
58   xpos= min(tab,20);
59 }
60 
61 void
flush()62 tm_writer::flush () {
63   int i, m= N(spc), n= N(tmp);
64   if ((m+n)==0) return;
65   if ((xpos+m+n) < 78) {
66     buf << spc << tmp;
67     xpos += m+n;
68   }
69   else {
70     if (spc == " ") {
71       if (xpos > 40) cr ();
72       else {
73 	buf << " ";
74 	xpos++;
75       }
76     }
77     if ((xpos+n) < 78) {
78       buf << tmp;
79       xpos += n;
80     }
81     else for (i=0; i<n; ) {
82       if (((i+1) < n) && (tmp[i] == '\\') && (tmp[i+1] == ' ')) {
83 	/* not nice when searching text in a .tm file
84 	if (xpos >= 76) {
85 	  buf << "\\";
86 	  cr ();
87 	}
88 	*/
89 	buf << "\\ ";
90 	xpos += 2;
91 	i += 2;
92       }
93       else {
94 	/* not nice when searching text in a .tm file
95 	if (xpos >= 77) {
96 	  buf << "\\";
97 	  cr ();
98 	}
99 	*/
100 	buf << tmp[i];
101 	xpos++;
102 	i++;
103       }
104     }
105   }
106   spc= "";
107   tmp= "";
108 }
109 
110 void
write_space()111 tm_writer::write_space () {
112   if (spc_flag) tmp << "\\ ";
113   else {
114     flush ();
115     spc= " ";
116   }
117   spc_flag= true;
118   ret_flag= false;
119 }
120 
121 void
write_return()122 tm_writer::write_return () {
123   if (ret_flag) {
124     buf << "\\;\n";
125     cr ();
126   }
127   else {
128     if ((spc == " ") && (tmp == "")) {
129       spc= "";
130       tmp= "\\ ";
131     }
132     flush ();
133     buf << "\n";
134     cr ();
135   }
136   spc_flag= true;
137   ret_flag= true;
138 }
139 
140 void
write(string s,bool flag,bool encode_space)141 tm_writer::write (string s, bool flag, bool encode_space) {
142   if (flag) {
143     int i, n=N(s);
144     for (i=0; i<n; i++) {
145       char c= s[i];
146       if ((c == ' ') && (!encode_space)) write_space ();
147       else {
148 	if (c == ' ') tmp << "\\ ";
149 	else if (c == '\n') tmp << "\\n";
150 	else if (c == '\t') tmp << "\\t";
151 	else if (c == '\0') tmp << "\\0";
152 	else if (c == '\\') tmp << "\\\\";
153 	else if (c == '<') tmp << "\\<";
154 	else if (c == '|') tmp << "\\|";
155 	else if (c == '>') tmp << "\\>";
156 	else if (c == '\34') tmp << c;
157 	else if (((unsigned char) c) < ' ') tmp << '\\' << (c+'@');
158 	else tmp << c;
159 	spc_flag= false;
160 	ret_flag= false;
161       }
162     }
163   }
164   else {
165     tmp << s;
166     if (N(s) != 0) {
167       spc_flag= false;
168       ret_flag= false;
169     }
170   }
171 }
172 
173 void
br(int indent)174 tm_writer::br (int indent) {
175   int i;
176   flush ();
177   tab += indent;
178   for (i=N(buf)-1; i>=0; i--) {
179     if (buf[i] == '\n') return;
180     if (buf[i] != ' ') {
181       cr ();
182       spc_flag= true;
183       ret_flag= false;
184       return;
185     }
186   }
187 }
188 
189 void
tag(string before,string s,string after)190 tm_writer::tag (string before, string s, string after) {
191   write (before, false);
192   write (s);
193   write (after, false);
194 }
195 
196 void
apply(string func,array<tree> args)197 tm_writer::apply (string func, array<tree> args) {
198   int i, last, n=N(args);
199   for (i=n-1; i>=0; i--)
200     if (is_document (args[i]) || is_func (args[i], COLLECTION))
201       break;
202   last= i;
203 
204   if (last >= 0) {
205     /*
206     tag ("<\\", func, ">");
207     for (i=0; i<n; i++) {
208       if (is_empty (args[i])) br ();
209       else {
210 	br (2);
211 	write (args[i]);
212 	br (-2);
213       }
214       if (i<(n-1)) tag ("<|", func, ">");
215     }
216     tag ("</", func, ">");
217     */
218 
219     for (i=0; i<=n; i++) {
220       bool flag=
221 	(i<n) && (is_document (args[i]) || is_func (args[i], COLLECTION));
222       if (i==0) { write ("<\\", false); write (func, true, true); }
223       else if (i==last+1) {write ("</", false); write (func, true, true); }
224       else if (is_document (args[i-1]) || is_func (args[i-1], COLLECTION)) {
225 	write ("<|", false); write (func, true, true); }
226       if (i==n) {
227 	write (">", false);
228 	break;
229       }
230 
231       if (flag) {
232 	write (">", false);
233 	br (2);
234 	write (args[i]);
235 	br (-2);
236       }
237       else {
238 	write ("|", false);
239 	write (args[i]);
240       }
241     }
242   }
243   else {
244     write ("<", false);
245     write (func, true, true);
246     for (i=0; i<n; i++) {
247       write ("|", false);
248       write (args[i]);
249     }
250     write (">", false);
251   }
252 }
253 
254 void
write(tree t)255 tm_writer::write (tree t) {
256   if (is_atomic (t)) {
257     write (t->label);
258     return;
259   }
260 
261   int i, n= N(t);
262   switch (L(t)) {
263   case RAW_DATA:
264     {
265       write ("<#", false);
266       string s= as_string (t[0]);
267       for (i=0; i<N(s); i++)
268 	write (as_hexadecimal ((unsigned char) s[i], 2), false);
269       write (">", false);
270       break;
271     }
272   case DOCUMENT:
273     spc_flag= true;
274     ret_flag= true;
275     for (i=0; i<n; i++) {
276       write (t[i]);
277       if (i<(n-1)) write_return ();
278       else if (ret_flag) write ("\\;", false);
279     }
280     break;
281   case CONCAT:
282     for (i=0; i<n; i++) write (t[i]);
283     break;
284   case EXPAND:
285     if ((n>=1) && is_atomic (t[0])) {
286       string s= t[0]->label;
287       if (std_contains (s));
288       else if ((N(s)>0) && (!is_iso_alpha (s)));
289       else {
290 	apply (s, A(t(1,n)));
291 	break;
292       }
293     }
294     apply (as_string (EXPAND), A(t));
295     break;
296   case COLLECTION:
297     tag ("<\\", as_string (COLLECTION), ">");
298     if (n==0) br ();
299     else {
300       br (2);
301       for (i=0; i<n; i++) {
302 	write (t[i]);
303 	if (i<(n-1)) br ();
304       }
305       br (-2);
306     }
307     tag ("</", as_string (COLLECTION), ">");
308     break;
309   default:
310     apply (as_string (L(t)), A(t));
311     break;
312   }
313 }
314 
315 /******************************************************************************
316 * Conversion of TeXmacs trees to TeXmacs strings
317 ******************************************************************************/
318 
319 string
tree_to_texmacs(tree t)320 tree_to_texmacs (tree t) {
321   if (!is_snippet (t)) {
322     int i, n= N(t);
323     tree r (t, n);
324     for (i=0; i<n; i++)
325       if (is_compound (t[i], "style", 1)) {
326 	tree style= t[i][0];
327 	if (is_func (style, TUPLE, 1)) style= style[0];
328 	r[i]= copy (t[i]);
329 	r[i][0]= style;
330       }
331       else r[i]= t[i];
332     t= r;
333   }
334 
335   tm_writer tmw;
336   tmw.write (t);
337   tmw.flush ();
338   return tmw.buf;
339 }
340