1 /***********************************************************************
2  * $Id$
3  * Copyright 2009 Aplix Corporation. All rights reserved.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  * Unless required by applicable law or agreed to in writing, software
9  * distributed under the License is distributed on an "AS IS" BASIS,
10  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  * See the License for the specific language governing permissions and
12  * limitations under the License.
13  *
14  * Node-specific functions
15  ***********************************************************************/
16 #include <assert.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include "comment.h"
20 #include "lex.h"
21 #include "misc.h"
22 #include "node.h"
23 #include "process.h"
24 
newelement(const char * name)25 struct node *newelement(const char *name) {
26   struct element *element = memalloc(sizeof(struct element));
27   element->n.type = NODE_ELEMENT;
28   element->name = name;
29   return &element->n;
30 }
31 
newattr(const char * name,const char * val)32 struct node *newattr(const char *name, const char *val) {
33   struct attr *attr = memalloc(sizeof(struct attr));
34   attr->n.type = NODE_ATTR;
35   attr->name = name;
36   attr->value = val;
37   return &attr->n;
38 }
39 
newattrlist(void)40 struct node *newattrlist(void) {
41   struct attrlist *attrlist = memalloc(sizeof(struct attrlist));
42   attrlist->n.type = NODE_ATTRLIST;
43   return &attrlist->n;
44 }
45 
46 /***********************************************************************
47  * addnode : add node as child of another node
48  *
49  * Enter:   parent node
50  *          child node
51  *
52  * The children list is constructed backwards. This is fixed later with
53  * a call to reversechildren.
54  *
55  * If child is an attrlist, its children are added to parent and the
56  * attrlist is freed.
57  */
addnode(struct node * parent,struct node * child)58 void addnode(struct node *parent, struct node *child) {
59   if (!child) return;
60   if (child->type == NODE_ATTRLIST) {
61     /* Add the attrs in the attrlist to parent. */
62     struct node *child2;
63     reversechildren(child);
64     child2 = child->children;
65     memfree(child);
66     while (child2) {
67       struct node *next = child2->next;
68       addnode(parent, child2);
69       child2 = next;
70     }
71   } else {
72     child->next = parent->children;
73     parent->children = child;
74     child->parent = parent;
75   }
76 }
77 
78 /***********************************************************************
79  * reversechildren : recursively reverse child lists
80  *
81  * Also sets parent field on each node.
82  */
reversechildren(struct node * node)83 void reversechildren(struct node *node) {
84   struct node *newlist = 0;
85   struct node *child = node->children;
86   while (child) {
87     struct node *next = child->next;
88     child->parent = node;
89     child->next = newlist;
90     newlist = child;
91     reversechildren(child);
92     child = next;
93   }
94   node->children = newlist;
95 }
96 
97 /***********************************************************************
98  * nodeisempty : test if node is empty (has no children)
99  */
nodeisempty(struct node * node)100 int nodeisempty(struct node *node) { return !node->children; }
101 
102 /***********************************************************************
103  * nodewalk : single step of depth last traversal of node tree
104  *
105  * Return:  next node in walk, 0 if finished
106  */
nodewalk(struct node * node)107 struct node *nodewalk(struct node *node) {
108   if (node->children) return node->children;
109   if (node->next) return node->next;
110   do {
111     node = node->parent;
112     if (!node) return 0;
113   } while (!node->next);
114   return node->next;
115 }
116 
117 /***********************************************************************
118  * findchildelement : find child element of a particular name
119  *
120  * Enter:   node = element
121  *          name = name to find
122  *
123  * Return:  0 else child element of that name
124  */
findchildelement(struct node * node,const char * name)125 static struct node *findchildelement(struct node *node, const char *name) {
126   node = node->children;
127   while (node) {
128     if (node->type == NODE_ELEMENT) {
129       struct element *element = (void *)node;
130       if (!strcmp(element->name, name)) break;
131     }
132     node = node->next;
133   }
134   return node;
135 }
136 
137 /***********************************************************************
138  * getattr : get value of attribute
139  *
140  * Enter:   node = element to find attribute in
141  *          name = name of attribute
142  *
143  * Return:  0 if not found, else 0-terminated string value
144  */
getattr(struct node * node,const char * name)145 const char *getattr(struct node *node, const char *name) {
146   node = node->children;
147   while (node) {
148     if (node->type == NODE_ATTR) {
149       struct attr *attr = (void *)node;
150       if (!strcmp(attr->name, name)) return attr->value;
151     }
152     node = node->next;
153   }
154   return 0;
155 }
156 
157 /***********************************************************************
158  * findchildelementwithnameattr : find child element with a name attribute
159  *                                of a particular value
160  *
161  * Enter:   node = element
162  *          name = name to find
163  *
164  * Return:  0 else child element with name attr of that value
165  */
findchildelementwithnameattr(struct node * node,const char * name)166 static struct node *findchildelementwithnameattr(struct node *node,
167                                                  const char *name) {
168   node = node->children;
169   while (node) {
170     if (node->type == NODE_ELEMENT) {
171       const char *s = getattr(node, "name");
172       if (s && !strcmp(s, name)) break;
173     }
174     node = node->next;
175   }
176   return node;
177 }
178 
179 /***********************************************************************
180  * findreturntype : find Type parse node for return type
181  *
182  * Enter:   node = Operation element
183  *
184  * Return:  0 if not found, else Type parse node for return type
185  */
findreturntype(struct node * node)186 struct node *findreturntype(struct node *node) {
187   return findchildelement(node, "Type");
188 }
189 
190 /***********************************************************************
191  * findparamidentifier : find identifier parse node for parameter
192  *
193  * Enter:   node = Operation element
194  *          name = parameter name to find
195  *
196  * Return:  0 if not found, else node struct for parameter identifier
197  */
findparamidentifier(struct node * node,const char * name)198 struct node *findparamidentifier(struct node *node, const char *name) {
199   node = findchildelement(node, "ArgumentList");
200   if (node) node = findchildelementwithnameattr(node, name);
201   return node;
202 }
203 
204 /***********************************************************************
205  * findthrowidentifier : find identifier parse node for exception name
206  *
207  * Enter:   node = Operation element
208  *          name = exception name to find
209  *
210  * Return:  0 if not found, else node for Name element, child of Raises
211  *              or SetRaises
212  */
findthrowidentifier(struct node * node,const char * name)213 struct node *findthrowidentifier(struct node *node, const char *name) {
214   struct node *node2 = findchildelement(node, "Raises");
215   if (node2) node2 = findchildelementwithnameattr(node2, name);
216   if (!node2) {
217     node2 = findchildelement(node, "SetRaises");
218     if (node2) node2 = findchildelementwithnameattr(node2, name);
219   }
220   return node2;
221 }
222 
223 /***********************************************************************
224  * outputid : output the id of a node
225  */
outputid(struct node * node)226 static void outputid(struct node *node) {
227   if (node->parent) outputid(node->parent);
228   if (node->id) {
229     fputs("::", stdout);
230     printtext(node->id, strlen(node->id), 1);
231   }
232 }
233 
234 /***********************************************************************
235  * outputnode : output node and its children
236  *
237  * Enter:   node = node to output, assumed to be an element
238  *          indent
239  */
outputnode(struct node * node,unsigned int indent)240 void outputnode(struct node *node, unsigned int indent) {
241   struct element *element = (void *)node;
242   struct node *child;
243   int empty = 1;
244   printf("%*s<%s", indent, "", element->name);
245   child = element->n.children;
246   while (child) {
247     switch (child->type) {
248       case NODE_ELEMENT:
249         empty = 0;
250         break;
251       case NODE_ATTR: {
252         struct attr *attr = (void *)child;
253         printf(" %s=\"", attr->name);
254         printtext(attr->value, strlen(attr->value), 1);
255         printf("\"");
256       } break;
257     }
258     child = child->next;
259   }
260   if (node->id) {
261     printf(" id=\"");
262     outputid(node);
263     printf("\"");
264   }
265   if (!empty || node->comments || node->wsstart) {
266     printf(">\n");
267     if (node->wsstart) {
268       printf("%*s  <webidl>", indent, "");
269       outputwidl(node);
270       printf("</webidl>\n");
271     }
272     outputdescriptive(node, indent + 2);
273     child = element->n.children;
274     while (child) {
275       switch (child->type) {
276         case NODE_ELEMENT:
277           outputnode(child, indent + 2);
278           break;
279       }
280       child = child->next;
281     }
282     printf("%*s</%s>\n", indent, "", element->name);
283   } else
284     printf("/>\n");
285 }
286