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 
25 struct node *
newelement(const char * name)26 newelement(const char *name)
27 {
28     struct element *element = memalloc(sizeof(struct element));
29     element->n.type = NODE_ELEMENT;
30     element->name = name;
31     return &element->n;
32 }
33 
34 struct node *
newattr(const char * name,const char * val)35 newattr(const char *name, const char *val)
36 {
37     struct attr *attr = memalloc(sizeof(struct attr));
38     attr->n.type = NODE_ATTR;
39     attr->name = name;
40     attr->value = val;
41     return &attr->n;
42 }
43 
44 struct node *
newattrlist(void)45 newattrlist(void)
46 {
47     struct attrlist *attrlist = memalloc(sizeof(struct attrlist));
48     attrlist->n.type = NODE_ATTRLIST;
49     return &attrlist->n;
50 }
51 
52 /***********************************************************************
53  * addnode : add node as child of another node
54  *
55  * Enter:   parent node
56  *          child node
57  *
58  * The children list is constructed backwards. This is fixed later with
59  * a call to reversechildren.
60  *
61  * If child is an attrlist, its children are added to parent and the
62  * attrlist is freed.
63  */
64 void
addnode(struct node * parent,struct node * child)65 addnode(struct node *parent, struct node *child)
66 {
67     if (!child)
68         return;
69     if (child->type == NODE_ATTRLIST) {
70         /* Add the attrs in the attrlist to parent. */
71         struct node *child2;
72         reversechildren(child);
73         child2 = child->children;
74         memfree(child);
75         while (child2) {
76             struct node *next = child2->next;
77             addnode(parent, child2);
78             child2 = next;
79         }
80     } else {
81         child->next = parent->children;
82         parent->children = child;
83         child->parent = parent;
84     }
85 }
86 
87 /***********************************************************************
88  * reversechildren : recursively reverse child lists
89  *
90  * Also sets parent field on each node.
91  */
92 void
reversechildren(struct node * node)93 reversechildren(struct node *node)
94 {
95     struct node *newlist = 0;
96     struct node *child = node->children;
97     while (child) {
98         struct node *next = child->next;
99         child->parent = node;
100         child->next = newlist;
101         newlist = child;
102         reversechildren(child);
103         child = next;
104     }
105     node->children = newlist;
106 }
107 
108 /***********************************************************************
109  * nodeisempty : test if node is empty (has no children)
110  */
111 int
nodeisempty(struct node * node)112 nodeisempty(struct node *node)
113 {
114     return !node->children;
115 }
116 
117 /***********************************************************************
118  * nodewalk : single step of depth last traversal of node tree
119  *
120  * Return:  next node in walk, 0 if finished
121  */
122 struct node *
nodewalk(struct node * node)123 nodewalk(struct node *node)
124 {
125     if (node->children)
126         return node->children;
127     if (node->next)
128         return node->next;
129     do {
130         node = node->parent;
131         if (!node)
132             return 0;
133     } while (!node->next);
134     return node->next;
135 }
136 
137 /***********************************************************************
138  * findchildelement : find child element of a particular name
139  *
140  * Enter:   node = element
141  *          name = name to find
142  *
143  * Return:  0 else child element of that name
144  */
145 static struct node *
findchildelement(struct node * node,const char * name)146 findchildelement(struct node *node, const char *name)
147 {
148     node = node->children;
149     while (node) {
150         if (node->type == NODE_ELEMENT) {
151             struct element *element = (void *)node;
152             if (!strcmp(element->name, name))
153                 break;
154         }
155         node = node->next;
156     }
157     return node;
158 }
159 
160 /***********************************************************************
161  * getattr : get value of attribute
162  *
163  * Enter:   node = element to find attribute in
164  *          name = name of attribute
165  *
166  * Return:  0 if not found, else 0-terminated string value
167  */
168 const char *
getattr(struct node * node,const char * name)169 getattr(struct node *node, const char *name)
170 {
171     node = node->children;
172     while (node) {
173         if (node->type == NODE_ATTR) {
174             struct attr *attr = (void *)node;
175             if (!strcmp(attr->name, name))
176                 return attr->value;
177         }
178         node = node->next;
179     }
180     return 0;
181 }
182 
183 /***********************************************************************
184  * findchildelementwithnameattr : find child element with a name attribute
185  *                                of a particular value
186  *
187  * Enter:   node = element
188  *          name = name to find
189  *
190  * Return:  0 else child element with name attr of that value
191  */
192 static struct node *
findchildelementwithnameattr(struct node * node,const char * name)193 findchildelementwithnameattr(struct node *node, const char *name)
194 {
195     node = node->children;
196     while (node) {
197         if (node->type == NODE_ELEMENT) {
198             const char *s = getattr(node, "name");
199             if (s && !strcmp(s, name))
200                 break;
201         }
202         node = node->next;
203     }
204     return node;
205 }
206 
207 /***********************************************************************
208  * findreturntype : find Type parse node for return type
209  *
210  * Enter:   node = Operation element
211  *
212  * Return:  0 if not found, else Type parse node for return type
213  */
214 struct node *
findreturntype(struct node * node)215 findreturntype(struct node *node)
216 {
217     return findchildelement(node, "Type");
218 }
219 
220 /***********************************************************************
221  * findparamidentifier : find identifier parse node for parameter
222  *
223  * Enter:   node = Operation element
224  *          name = parameter name to find
225  *
226  * Return:  0 if not found, else node struct for parameter identifier
227  */
228 struct node *
findparamidentifier(struct node * node,const char * name)229 findparamidentifier(struct node *node, const char *name)
230 {
231     node = findchildelement(node, "ArgumentList");
232     if (node)
233         node = findchildelementwithnameattr(node, name);
234     return node;
235 }
236 
237 /***********************************************************************
238  * findthrowidentifier : find identifier parse node for exception name
239  *
240  * Enter:   node = Operation element
241  *          name = exception name to find
242  *
243  * Return:  0 if not found, else node for Name element, child of Raises
244  *              or SetRaises
245  */
246 struct node *
findthrowidentifier(struct node * node,const char * name)247 findthrowidentifier(struct node *node, const char *name)
248 {
249     struct node *node2 = findchildelement(node, "Raises");
250     if (node2)
251         node2 = findchildelementwithnameattr(node2, name);
252     if (!node2) {
253         node2 = findchildelement(node, "SetRaises");
254         if (node2)
255             node2 = findchildelementwithnameattr(node2, name);
256     }
257     return node2;
258 }
259 
260 /***********************************************************************
261  * outputid : output the id of a node
262  */
263 static void
outputid(struct node * node)264 outputid(struct node *node)
265 {
266     if (node->parent)
267         outputid(node->parent);
268     if (node->id) {
269         fputs("::", stdout);
270         printtext(node->id, strlen(node->id), 1);
271     }
272 }
273 
274 /***********************************************************************
275  * outputnode : output node and its children
276  *
277  * Enter:   node = node to output, assumed to be an element
278  *          indent
279  */
280 void
outputnode(struct node * node,unsigned int indent)281 outputnode(struct node *node, unsigned int indent)
282 {
283     struct element *element = (void *)node;
284     struct node *child;
285     int empty = 1;
286     printf("%*s<%s", indent, "", element->name);
287     child = element->n.children;
288     while (child) {
289         switch(child->type) {
290         case NODE_ELEMENT:
291             empty = 0;
292             break;
293         case NODE_ATTR:
294             {
295                 struct attr *attr = (void *)child;
296                 printf(" %s=\"", attr->name);
297                 printtext(attr->value, strlen(attr->value), 1);
298                 printf("\"");
299             }
300             break;
301         }
302         child = child->next;
303     }
304     if (node->id) {
305         printf(" id=\"");
306         outputid(node);
307         printf("\"");
308     }
309     if (!empty || node->comments || node->wsstart) {
310         printf(">\n");
311         if (node->wsstart) {
312             printf("%*s  <webidl>", indent, "");
313             outputwidl(node);
314             printf("</webidl>\n");
315         }
316         outputdescriptive(node, indent + 2);
317         child = element->n.children;
318         while (child) {
319             switch(child->type) {
320             case NODE_ELEMENT:
321                 outputnode(child, indent + 2);
322                 break;
323             }
324             child = child->next;
325         }
326         printf("%*s</%s>\n", indent, "", element->name);
327     } else
328         printf("/>\n");
329 }
330 
331 
332