1/* -----------------------------------------------------------------------------
2 * See the LICENSE file for information on copyright, usage and redistribution
3 * of SWIG, and the README file for authors - http://www.swig.org/release.html.
4 *
5 * tree.c
6 *
7 * This file provides some general purpose functions for manipulating
8 * parse trees.
9 * ----------------------------------------------------------------------------- */
10
11char cvsroot_tree_c[] = "$Id: tree.c 11080 2009-01-24 13:15:51Z bhy $";
12
13#include "swig.h"
14#include <stdarg.h>
15#include <assert.h>
16
17/* -----------------------------------------------------------------------------
18 * Swig_print_tags()
19 *
20 * Dump the tag structure of a parse tree to standard output
21 * ----------------------------------------------------------------------------- */
22
23void Swig_print_tags(DOH *obj, DOH *root) {
24  DOH *croot, *newroot;
25  DOH *cobj;
26
27  if (!root)
28    croot = NewStringEmpty();
29  else
30    croot = root;
31
32  while (obj) {
33    Printf(stdout, "%s . %s (%s:%d)\n", croot, nodeType(obj), Getfile(obj), Getline(obj));
34    cobj = firstChild(obj);
35    if (cobj) {
36      newroot = NewStringf("%s . %s", croot, nodeType(obj));
37      Swig_print_tags(cobj, newroot);
38      Delete(newroot);
39    }
40    obj = nextSibling(obj);
41  }
42  if (!root)
43    Delete(croot);
44}
45
46static int indent_level = 0;
47
48static void print_indent(int l) {
49  int i;
50  for (i = 0; i < indent_level; i++) {
51    fputc(' ', stdout);
52  }
53  if (l) {
54    fputc('|', stdout);
55    fputc(' ', stdout);
56  }
57}
58
59
60/* -----------------------------------------------------------------------------
61 * Swig_print_node(Node *n)
62 * ----------------------------------------------------------------------------- */
63
64void Swig_print_node(Node *obj) {
65  Iterator ki;
66  Node *cobj;
67
68  print_indent(0);
69  Printf(stdout, "+++ %s ----------------------------------------\n", nodeType(obj));
70  ki = First(obj);
71  while (ki.key) {
72    String *k = ki.key;
73    if ((Cmp(k, "nodeType") == 0) || (Cmp(k, "firstChild") == 0) || (Cmp(k, "lastChild") == 0) ||
74	(Cmp(k, "parentNode") == 0) || (Cmp(k, "nextSibling") == 0) || (Cmp(k, "previousSibling") == 0) || (*(Char(k)) == '$')) {
75      /* Do nothing */
76    } else if (Cmp(k, "parms") == 0) {
77      print_indent(2);
78      Printf(stdout, "%-12s - %s\n", k, ParmList_protostr(Getattr(obj, k)));
79    } else {
80      DOH *o;
81      char *trunc = "";
82      print_indent(2);
83      if (DohIsString(Getattr(obj, k))) {
84	o = Str(Getattr(obj, k));
85	if (Len(o) > 80) {
86	  trunc = "...";
87	}
88	Printf(stdout, "%-12s - \"%(escape)-0.80s%s\"\n", k, o, trunc);
89	Delete(o);
90      } else {
91	Printf(stdout, "%-12s - 0x%x\n", k, Getattr(obj, k));
92      }
93    }
94    ki = Next(ki);
95  }
96  cobj = firstChild(obj);
97  if (cobj) {
98    indent_level += 6;
99    Printf(stdout, "\n");
100    Swig_print_tree(cobj);
101    indent_level -= 6;
102  } else {
103    print_indent(1);
104    Printf(stdout, "\n");
105  }
106}
107
108/* -----------------------------------------------------------------------------
109 * Swig_print_tree()
110 *
111 * Dump the tree structure of a parse tree to standard output
112 * ----------------------------------------------------------------------------- */
113
114void Swig_print_tree(DOH *obj) {
115  while (obj) {
116    Swig_print_node(obj);
117    obj = nextSibling(obj);
118  }
119}
120
121/* -----------------------------------------------------------------------------
122 * appendChild()
123 *
124 * Appends a new child to a node
125 * ----------------------------------------------------------------------------- */
126
127void appendChild(Node *node, Node *chd) {
128  Node *lc;
129
130  if (!chd)
131    return;
132
133  lc = lastChild(node);
134  if (!lc) {
135    set_firstChild(node, chd);
136  } else {
137    set_nextSibling(lc, chd);
138    set_previousSibling(chd, lc);
139  }
140  while (chd) {
141    lc = chd;
142    set_parentNode(chd, node);
143    chd = nextSibling(chd);
144  }
145  set_lastChild(node, lc);
146}
147
148/* -----------------------------------------------------------------------------
149 * prependChild()
150 *
151 * Prepends a new child to a node
152 * ----------------------------------------------------------------------------- */
153
154void prependChild(Node *node, Node *chd) {
155  Node *fc;
156
157  if (!chd)
158    return;
159
160  fc = firstChild(node);
161  if (fc) {
162    set_nextSibling(chd, fc);
163    set_previousSibling(fc, chd);
164  }
165  set_firstChild(node, chd);
166  while (chd) {
167    set_parentNode(chd, node);
168    chd = nextSibling(chd);
169  }
170}
171
172/* -----------------------------------------------------------------------------
173 * removeNode()
174 *
175 * Removes a node from the parse tree.  Detaches it from its parent's child list.
176 * ----------------------------------------------------------------------------- */
177
178void removeNode(Node *n) {
179  Node *parent;
180  Node *prev;
181  Node *next;
182
183  parent = parentNode(n);
184  if (!parent) return;
185
186  prev = previousSibling(n);
187  next = nextSibling(n);
188  if (prev) {
189    set_nextSibling(prev, next);
190  } else {
191    if (parent) {
192      set_firstChild(parent, next);
193    }
194  }
195  if (next) {
196    set_previousSibling(next, prev);
197  } else {
198    if (parent) {
199      set_lastChild(parent, prev);
200    }
201  }
202
203  /* Delete attributes */
204  Delattr(n,"parentNode");
205  Delattr(n,"nextSibling");
206  Delattr(n,"prevSibling");
207}
208
209/* -----------------------------------------------------------------------------
210 * copyNode()
211 *
212 * Copies a node, but only copies simple attributes (no lists, hashes).
213 * ----------------------------------------------------------------------------- */
214
215Node *copyNode(Node *n) {
216  Iterator ki;
217  Node *c = NewHash();
218  for (ki = First(n); ki.key; ki = Next(ki)) {
219    if (DohIsString(ki.item)) {
220      Setattr(c, ki.key, Copy(ki.item));
221    }
222  }
223  Setfile(c, Getfile(n));
224  Setline(c, Getline(n));
225  return c;
226}
227
228/* -----------------------------------------------------------------------------
229 * checkAttribute()
230 * ----------------------------------------------------------------------------- */
231
232int checkAttribute(Node *n, const_String_or_char_ptr name, const_String_or_char_ptr value) {
233  String *v = Getattr(n, name);
234  return v ? Equal(v, value) : 0;
235}
236
237/* -----------------------------------------------------------------------------
238 * Swig_require()
239 * ns   - namespace for the view name for saving any attributes under
240 * n    - node
241 * ...  - list of attribute names of type char*
242 * This method checks that the attribute names exist in the node n and asserts if
243 * not. Assert will only occur unless the attribute is optional. An attribute is
244 * optional if it is prefixed by ?, eg "?value". If the attribute name is prefixed
245 * by * or ?, eg "*value" then a copy of the attribute is saved. The saved
246 * attributes will be restored on a subsequent call to Swig_restore(). All the
247 * saved attributes are saved in the view namespace (prefixed by ns).
248 * This function can be called more than once with different namespaces.
249 * ----------------------------------------------------------------------------- */
250
251void Swig_require(const char *ns, Node *n, ...) {
252  va_list ap;
253  char *name;
254  DOH *obj;
255
256  va_start(ap, n);
257  name = va_arg(ap, char *);
258  while (name) {
259    int newref = 0;
260    int opt = 0;
261    if (*name == '*') {
262      newref = 1;
263      name++;
264    } else if (*name == '?') {
265      newref = 1;
266      opt = 1;
267      name++;
268    }
269    obj = Getattr(n, name);
270    if (!opt && !obj) {
271      Printf(stderr, "%s:%d. Fatal error (Swig_require).  Missing attribute '%s' in node '%s'.\n", Getfile(n), Getline(n), name, nodeType(n));
272      assert(obj);
273    }
274    if (!obj)
275      obj = DohNone;
276    if (newref) {
277      /* Save a copy of the attribute */
278      Setattr(n, NewStringf("%s:%s", ns, name), obj);
279    }
280    name = va_arg(ap, char *);
281  }
282  va_end(ap);
283
284  /* Save the view */
285  {
286    String *view = Getattr(n, "view");
287    if (view) {
288      if (Strcmp(view, ns) != 0) {
289	Setattr(n, NewStringf("%s:view", ns), view);
290	Setattr(n, "view", ns);
291      }
292    } else {
293      Setattr(n, "view", ns);
294    }
295  }
296}
297
298
299/* -----------------------------------------------------------------------------
300 * Swig_save()
301 * Same as Swig_require(), but all attribute names are optional and all attributes
302 * are saved, ie behaves as if all the attribute names were prefixed by ?.
303 * ----------------------------------------------------------------------------- */
304
305void Swig_save(const char *ns, Node *n, ...) {
306  va_list ap;
307  char *name;
308  DOH *obj;
309
310  va_start(ap, n);
311  name = va_arg(ap, char *);
312  while (name) {
313    if (*name == '*') {
314      name++;
315    } else if (*name == '?') {
316      name++;
317    }
318    obj = Getattr(n, name);
319    if (!obj)
320      obj = DohNone;
321
322    /* Save a copy of the attribute */
323    if (Setattr(n, NewStringf("%s:%s", ns, name), obj)) {
324      Printf(stderr, "Swig_save('%s','%s'): Warning, attribute '%s' was already saved.\n", ns, nodeType(n), name);
325    }
326    name = va_arg(ap, char *);
327  }
328  va_end(ap);
329
330  /* Save the view */
331  {
332    String *view = Getattr(n, "view");
333    if (view) {
334      if (Strcmp(view, ns) != 0) {
335	Setattr(n, NewStringf("%s:view", ns), view);
336	Setattr(n, "view", ns);
337      }
338    } else {
339      Setattr(n, "view", ns);
340    }
341  }
342}
343
344/* -----------------------------------------------------------------------------
345 * Swig_restore()
346 * Restores attributes saved by a previous call to Swig_require() or Swig_save().
347 * ----------------------------------------------------------------------------- */
348
349void Swig_restore(Node *n) {
350  String *temp;
351  int len;
352  List *l;
353  String *ns;
354  Iterator ki;
355
356  ns = Getattr(n, "view");
357  assert(ns);
358
359  l = NewList();
360
361  temp = NewStringf("%s:", ns);
362  len = Len(temp);
363
364  for (ki = First(n); ki.key; ki = Next(ki)) {
365    if (Strncmp(temp, ki.key, len) == 0) {
366      Append(l, ki.key);
367    }
368  }
369  for (ki = First(l); ki.item; ki = Next(ki)) {
370    DOH *obj = Getattr(n, ki.item);
371    Setattr(n, Char(ki.item) + len, obj);
372    Delattr(n, ki.item);
373  }
374  Delete(l);
375  Delete(temp);
376}
377