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