1 
2 /******************************************************************************
3 * MODULE     : concat_macro.cpp
4 * DESCRIPTION: Typesetting markup around macro expansion mechanisms
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 "concater.hpp"
13 
14 /******************************************************************************
15 * Typesetting environment changes
16 ******************************************************************************/
17 
18 void
typeset_assign(tree t,path ip)19 concater_rep::typeset_assign (tree t, path ip) {
20   if (N(t) != 2) { typeset_error (t, ip); return; }
21   tree r= env->exec (t[0]);
22   if (!is_atomic (r)) return;
23   string var= r->label;
24   env->assign (var, copy (t[1]));
25   if (env->var_type [var] == Env_Paragraph)
26     control (tuple ("env_par", var, env->read (var)), ip);
27   else if (env->var_type [var] == Env_Page)
28     control (tuple ("env_page", var, env->read (var)), ip);
29   else control (t, ip);
30 }
31 
32 void
typeset_with(tree t,path ip)33 concater_rep::typeset_with (tree t, path ip) {
34   int i, n= N(t), k= (n-1)>>1; // is k=0 allowed ?
35   if ((n&1) != 1) { typeset_error (t, ip); return; }
36 
37   STACK_NEW_ARRAY(vars,string,k);
38   STACK_NEW_ARRAY(oldv,tree,k);
39   STACK_NEW_ARRAY(newv,tree,k);
40   for (i=0; i<k; i++) {
41     tree var_t= env->exec (t[i<<1]);
42     if (is_atomic (var_t)) {
43       string var= var_t->label;
44       vars[i]= var;
45       oldv[i]= env->read (var);
46       newv[i]= env->exec (t[(i<<1)+1]);
47     }
48     else {
49       STACK_DELETE_ARRAY(vars);
50       STACK_DELETE_ARRAY(oldv);
51       STACK_DELETE_ARRAY(newv);
52       return;
53     }
54   }
55 
56   marker (descend (ip, 0));
57   // for (i=0; i<k; i++) env->monitored_write_update (vars[i], newv[i]);
58   for (i=0; i<k; i++) env->write_update (vars[i], newv[i]);
59   typeset (t[n-1], descend (ip, n-1));
60   for (i=k-1; i>=0; i--) env->write_update (vars[i], oldv[i]);
61   marker (descend (ip, 1));
62   STACK_DELETE_ARRAY(vars);
63   STACK_DELETE_ARRAY(oldv);
64   STACK_DELETE_ARRAY(newv);
65 }
66 
67 void
typeset_compound(tree t,path ip)68 concater_rep::typeset_compound (tree t, path ip) {
69   int d; tree f;
70   if (L(t) == COMPOUND) {
71     if (N(t) == 0) { typeset_error (t, ip); return; }
72     d= 1;
73     f= t[0];
74     if (is_compound (f)) f= env->exec (f);
75     if (is_atomic (f)) {
76       string var= f->label;
77       if (!env->provides (var)) {
78 	typeset_error (t, ip);
79 	return;
80       }
81       f= env->read (var);
82     }
83   }
84   else {
85     string var= as_string (L(t));
86     if (!env->provides (var)) {
87       typeset_error (t, ip);
88       return;
89     }
90     d= 0;
91     f= env->read (var);
92   }
93 
94   if (is_applicable (f)) {
95     int i, n=N(f)-1, m=N(t)-d;
96     env->macro_arg= list<hashmap<string,tree> > (
97       hashmap<string,tree> (UNINIT), env->macro_arg);
98     env->macro_src= list<hashmap<string,path> > (
99       hashmap<string,path> (path (DECORATION)), env->macro_src);
100     if (L(f) == XMACRO) {
101       if (is_atomic (f[0])) {
102 	string var= f[0]->label;
103 	env->macro_arg->item (var)= t;
104 	env->macro_src->item (var)= ip;
105       }
106     }
107     else for (i=0; i<n; i++)
108       if (is_atomic (f[i])) {
109 	string var= f[i]->label;
110 	env->macro_arg->item (var)=
111 	  i<m? t[i+d]: attach_dip (tree (UNINIT), decorate_right(ip));
112 	env->macro_src->item (var)= i<m? descend (ip,i+d): decorate_right(ip);
113       }
114     if (is_decoration (ip))
115       typeset (attach_here (f[n], ip));
116     else {
117       /*IF_NON_CHILD_ENFORCING(t)*/ marker (descend (ip, 0));
118       typeset (attach_right (f[n], ip));
119       /*IF_NON_CHILD_ENFORCING(t)*/ marker (descend (ip, 1));
120     }
121     env->macro_arg= env->macro_arg->next;
122     env->macro_src= env->macro_src->next;
123   }
124   else {
125     if (is_decoration (ip)) typeset (attach_here (f, ip));
126     else {
127       /*IF_NON_CHILD_ENFORCING(t)*/ marker (descend (ip, 0));
128       typeset (attach_right (f, ip));
129       /*IF_NON_CHILD_ENFORCING(t)*/ marker (descend (ip, 1));
130     }
131   }
132 }
133 
134 void
typeset_auto(tree t,path ip,tree f)135 concater_rep::typeset_auto (tree t, path ip, tree f) {
136   env->macro_arg= list<hashmap<string,tree> > (
137     hashmap<string,tree> (UNINIT), env->macro_arg);
138   env->macro_src= list<hashmap<string,path> > (
139     hashmap<string,path> (path (DECORATION)), env->macro_src);
140   string var= f[0]->label;
141   env->macro_arg->item (var)= t;
142   env->macro_src->item (var)= ip;
143   typeset (attach_right (f[1], ip));
144   env->macro_arg= env->macro_arg->next;
145   env->macro_src= env->macro_src->next;
146 }
147 
148 void
typeset_include(tree t,path ip)149 concater_rep::typeset_include (tree t, path ip) {
150   if (N(t) != 1) { typeset_error (t, ip); return; }
151   url file_name= url_unix (env->exec_string (t[0]));
152   url incl_file= relative (env->base_file_name, file_name);
153   tree incl= load_inclusion (incl_file);
154   url save_name= env->cur_file_name;
155   env->cur_file_name= incl_file;
156   env->secure= is_secure (env->cur_file_name);
157   typeset_dynamic (incl, ip);
158   env->cur_file_name= save_name;
159   env->secure= is_secure (env->cur_file_name);
160 }
161 
162 void
typeset_drd_props(tree t,path ip)163 concater_rep::typeset_drd_props (tree t, path ip) {
164   (void) env->exec (t);
165   flag ("drd-properties", ip, brown);
166   control (t, ip);
167 }
168 
169 void
typeset_eval(tree t,path ip)170 concater_rep::typeset_eval (tree t, path ip) {
171   if (N(t) != 1) { typeset_error (t, ip); return; }
172   tree r= env->exec (t[0]);
173   typeset_dynamic (r, ip);
174 }
175 
176 void
typeset_value(tree t,path ip)177 concater_rep::typeset_value (tree t, path ip) {
178   // cout << "Value " << t << ", " << ip << "\n";
179   if (N(t) != 1) { typeset_error (t, ip); return; }
180   tree r= env->exec (t[0]);
181   if (is_compound (r)) {
182     typeset_error (t, ip);
183     return;
184   }
185   string name= r->label;
186   if (!env->provides (name)) {
187     typeset_error (t, ip);
188     return;
189   }
190   typeset_dynamic (env->read (name), ip);
191 }
192 
193 void
typeset_argument(tree t,path ip)194 concater_rep::typeset_argument (tree t, path ip) {
195   // cout << "Argument " << t << ", " << ip << "\n";
196   if (N(t) == 0) { typeset_error (t, ip); return; }
197   tree r= t[0];
198   if (is_compound (r) ||
199       is_nil (env->macro_arg) ||
200       (!env->macro_arg->item->contains (r->label)))
201     {
202       typeset_error (t, ip);
203       return;
204     }
205 
206   string name = r->label;
207   tree   value= env->macro_arg->item [name];
208   path   valip= decorate_right (ip);
209   if (!is_func (value, BACKUP)) {
210     path new_valip= env->macro_src->item [name];
211     if (is_accessible (new_valip)) valip= new_valip;
212   }
213   // cout << "Src   " << name << "=\t " << valip << "\n";
214 
215   marker (descend (ip, 0));
216   list<hashmap<string,tree> > old_var= env->macro_arg;
217   list<hashmap<string,path> > old_src= env->macro_src;
218   if (!is_nil (env->macro_arg)) env->macro_arg= env->macro_arg->next;
219   if (!is_nil (env->macro_src)) env->macro_src= env->macro_src->next;
220 
221   if (N(t) > 1) {
222     int i, n= N(t);
223     for (i=1; i<n; i++) {
224       tree r= env->exec (t[i]);
225       if (!is_int (r)) {
226         value= tree (ERROR, "arg " * name);
227         valip= decorate_right (ip);
228         break;
229       }
230       int nr= as_int (r);
231       if ((!is_compound (value)) || (nr<0) || (nr>=N(value))) {
232         value= tree (ERROR, "arg " * name);
233         valip= decorate_right (ip);
234         break;
235       }
236       value= value[nr];
237       valip= descend (valip, nr);
238     }
239   }
240   typeset (attach_here (value, valip));
241 
242   env->macro_arg= old_var;
243   env->macro_src= old_src;
244   marker (descend (ip, 1));
245 }
246 
247 void
typeset_eval_args(tree t,path ip)248 concater_rep::typeset_eval_args (tree t, path ip) {
249   if (N(t) != 1) { typeset_error (t, ip); return; }
250   marker (descend (ip, 0));
251   typeset_inactive (attach_right (env->exec (t), ip));
252   marker (descend (ip, 1));
253 }
254 
255 void
typeset_mark(tree t,path ip)256 concater_rep::typeset_mark (tree t, path ip) {
257   // cout << "Mark: " << t << ", " << ip << "\n\n";
258   if (N(t) != 2) { typeset_error (t, ip); return; }
259   if (is_func (t[0], ARG) &&
260       is_atomic (t[0][0]) &&
261       (!is_nil (env->macro_arg)) &&
262       env->macro_arg->item->contains (t[0][0]->label))
263     {
264       string name = t[0][0]->label;
265       tree   value= env->macro_arg->item [name];
266       path   valip= decorate_right (ip);
267       if (!is_func (value, BACKUP)) {
268 	path new_valip= env->macro_src->item [name];
269 	if (is_accessible (new_valip)) valip= new_valip;
270       }
271       // cout << "Src   " << name << "=\t " << valip << "\n";
272 
273       if (N(t[0]) > 1) {
274 	int i, n= N(t[0]);
275 	for (i=1; i<n; i++) {
276 	  tree r= env->exec (t[0][i]);
277 	  if (!is_int (r)) break;
278 	  int nr= as_int (r);
279 	  if ((!is_compound (value)) || (nr<0) || (nr>=N(value))) break;
280 	  value= value[nr];
281 	  valip= descend (valip, nr);
282 	}
283       }
284 
285       marker (descend (valip, 0));
286       typeset (t[1], descend (ip, 1));
287       marker (descend (valip, right_index (value)));
288     }
289   else typeset (t[1], descend (ip, 1));
290 }
291 
292 void
typeset_expand_as(tree t,path ip)293 concater_rep::typeset_expand_as (tree t, path ip) {
294   // cout << "Mark: " << t << ", " << ip << "\n\n";
295   if (N(t) != 2) { typeset_error (t, ip); return; }
296   marker (descend (ip, 0));
297   typeset (t[1], descend (ip, 1));
298   marker (descend (ip, 1));
299 }
300 
301 void
typeset_executable(tree t,path ip)302 concater_rep::typeset_executable (tree t, path ip) {
303   tree r= env->exec (t);
304   typeset_dynamic (r, ip);
305 }
306 
307 void
typeset_rewrite(tree t,path ip)308 concater_rep::typeset_rewrite (tree t, path ip) {
309   tree r= env->rewrite (t);
310   typeset_dynamic (r, ip);
311 }
312 
313 void
typeset_dynamic(tree t,path ip)314 concater_rep::typeset_dynamic (tree t, path ip) {
315   // ATTENTION: in the future, the ip should still be passed to
316   // this routine, since the typesetting depends on whether ip
317   // is a decoration or not
318 
319   // cout << "Dynamic " << t << ", " << ip << "\n";
320   if (is_decoration (ip)) {
321     typeset (attach_here (t, ip));
322     return;
323   }
324 
325   marker (descend (ip, 0));
326   // int start= N(a);
327   typeset (attach_right (t, ip));
328   // int end= N(a), i;
329 
330   /* Old style unaccessible text, using left and middle decorations
331   SI total= 0, half= 0, mid;
332   for (i=start; i<end; i++)
333     total += a[i]->b->w();
334   for (mid=start; mid<end; mid++) {
335     half += a[mid]->b->w();
336     if (half >= (total>>1)) break;
337   }
338   for (i=start; i<mid; i++)
339     a[i]->b->relocate (decorate_left (ip));
340   if (i<end) {
341     if (a[i]->b->decoration ())
342       if ((a[i]->type==STD_ITEM) ||
343           (a[i]->type == MARKER_ITEM) ||
344 	  (a[i]->type==STRING_ITEM))
345 	a[i]->b= macro_box (decorate_right (ip), a[i]->b);
346     a[i]->b->relocate (decorate_middle (ip));
347     i++;
348   }
349   */
350 
351   marker (descend (ip, 1));
352 
353   /*
354   for (i=start-1; i<end+1; i++)
355     cout << i << ": " << a[i]->b
356 	 << ", " << a[i]->b->find_lip ()
357 	 << ", " << a[i]->b->find_rip () << "\n";
358   */
359 
360   /*
361   for (i=start; i<end; i++)
362     cout << i << ": " << a[i]->b << ", " << a[i]->b->ip << "\n";
363   */
364 }
365 
366 void
typeset_range(tree t,path ip)367 concater_rep::typeset_range (tree t, path ip) {
368   if (N(t) != 3) { typeset_error (t, ip); return; }
369   tree t1= env->exec (t[0]);
370   tree t2= env->exec (t[1]);
371   tree t3= env->exec (t[2]);
372   if (!(is_int (t2) && is_int (t3)))
373     typeset_dynamic (tree (ERROR, "bad range"), ip);
374   else if (is_compound (t1)) {
375     if (is_tuple (t1)) {
376       int i1= max (0, as_int (t2));
377       int i2= min (N (t1), as_int (t3));
378       i2 = max (i1, i2);
379       typeset_dynamic (t1 (i1, i2), ip);
380     }
381     else typeset_dynamic (tree (ERROR, "bad range"), ip);
382   }
383   else {
384     int i1= max (0, as_int (t2));
385     int i2= min (N(t1->label), as_int (t3));
386     i2 = max (i1, i2);
387     path ip1= obtain_ip (t1);
388     if (is_decoration (ip1))
389       typeset_dynamic (t1->label (i1, i2), ip);
390     else {
391       marker (descend (ip, 0));
392       if (env->mode == 1)
393         typeset_text_string (t1->label, ip1, i1, i2);
394       else if (env->mode == 2)
395         typeset_math_string (t1->label, ip1, i1, i2);
396       else if (env->mode == 3)
397         typeset_prog_string (t1       , ip1, i1, i2);
398       else
399         typeset_text_string (t1->label, ip1, i1, i2);
400       marker (descend (ip, 1));
401     }
402   }
403 }
404