ECMAScript: added writeonly property window.status
[elinks.git] / src / dom / node.h
blob466bdcbe7a8ac9bc460b24744f4a70ccdfee5f12
2 #ifndef EL_DOM_NODE_H
3 #define EL_DOM_NODE_H
5 #include "dom/string.h"
7 struct dom_node_list;
8 struct dom_document;
10 enum dom_node_type {
11 DOM_NODE_UNKNOWN = 0, /* for internal purpose only */
13 DOM_NODE_ELEMENT = 1,
14 DOM_NODE_ATTRIBUTE = 2,
15 DOM_NODE_TEXT = 3,
16 DOM_NODE_CDATA_SECTION = 4,
17 DOM_NODE_ENTITY_REFERENCE = 5,
18 DOM_NODE_ENTITY = 6,
19 DOM_NODE_PROCESSING_INSTRUCTION = 7,
20 DOM_NODE_COMMENT = 8,
21 DOM_NODE_DOCUMENT = 9,
22 DOM_NODE_DOCUMENT_TYPE = 10,
23 DOM_NODE_DOCUMENT_FRAGMENT = 11,
24 DOM_NODE_NOTATION = 12,
26 DOM_NODES
29 /* Following is the node specific datastructures. They may contain no more
30 * than 4 pointers or something equivalent. */
32 /* The document URI is stored in the string / length members. */
33 struct dom_document_node {
34 /* The document. */
35 struct dom_document *document;
37 /* The child nodes. May be NULL. Ordered like they where inserted. */
38 /* FIXME: Should be just one element (root) node reference. */
39 struct dom_node_list *children;
42 struct dom_id {
43 struct dom_string public_id;
44 struct dom_string system_id;
47 struct dom_doctype_subset_info {
48 struct dom_string internal;
49 struct dom_id external;
52 struct dom_document_type_node {
53 /* These are really maps and should be sorted alphabetically. */
54 struct dom_node_list *entities;
55 struct dom_node_list *notations;
57 /* The string/length members of dom_node hold the name of the document
58 * type "<!DOCTYPE {name} ...>". This holds the ids for the external
59 * subset and the string of the internal subset. */
60 struct dom_doctype_subset_infot *subset;
63 /* Element nodes are indexed nodes stored in node lists of either
64 * other child nodes or the root node. */
65 struct dom_element_node {
66 /* The child nodes. May be NULL. Ordered like they where inserted. */
67 struct dom_node_list *children;
69 /* Only element nodes can have attributes and element nodes can only be
70 * child nodes so the map is put here.
72 * The @map may be NULL if there are none. The @map nodes are sorted
73 * alphabetically according to the attributes name so it has fast
74 * lookup. */
75 struct dom_node_list *map;
77 /* For <xsl:stylesheet ...> elements this holds the offset of
78 * 'stylesheet' */
79 uint16_t namespace_offset;
81 /* Special implementation dependent type specifier for example
82 * containing an enum value representing the element to reduce string
83 * comparing and only do one fast find mapping. */
84 uint16_t type;
87 /* Attribute nodes are named nodes stored in a node map of an element node. */
88 struct dom_attribute_node {
89 /* The string that hold the attribute value. The @string / @length
90 * members of {struct dom_node} holds the name that identifies the node
91 * in the map. */
92 struct dom_string value;
94 /* For xml:lang="en" attributes this holds the offset of 'lang' */
95 uint16_t namespace_offset;
97 /* Special implementation dependent type specifier. For HTML it (will)
98 * contain an enum value representing the attribute HTML_CLASS, HTML_ID etc.
99 * to reduce string comparing and only do one fast find mapping. */
100 uint16_t type;
102 /* The attribute value is delimited by quotes. Can be NUL, ' or ". */
103 unsigned char quoted;
105 /* Was the attribute specified in the DTD as a default attribute or was
106 * it added from the document source. */
107 unsigned int specified:1;
109 /* Has the node->string been converted to internal charset. */
110 unsigned int converted:1;
112 /* Is the attribute a unique identifier meaning the owner (element)
113 * should be added to the document nodes @element_id hash. */
114 unsigned int id:1;
116 /* The attribute value references some other resource */
117 unsigned int reference:1;
120 struct dom_text_node {
121 /* The number of newlines the text string contains */
122 unsigned int newlines;
124 /* We will need to add text nodes even if they contain only whitespace.
125 * In order to quickly identify such nodes this member is used. */
126 unsigned int only_space:1;
128 /* Has the node->string been converted to internal charset. */
129 unsigned int converted:1;
132 enum dom_proc_instruction_type {
133 DOM_PROC_INSTRUCTION,
135 /* Keep this group sorted */
136 DOM_PROC_INSTRUCTION_XML, /* XML header */
137 DOM_PROC_INSTRUCTION_XML_STYLESHEET, /* XML stylesheet link */
139 DOM_PROC_INSTRUCTION_TYPES
142 struct dom_proc_instruction_node {
143 /* The target of the processing instruction (xml for '<?xml ... ?>')
144 * is in the @string / @length members. */
145 /* This holds the value to be processed */
146 struct dom_string instruction;
148 /* For fast checking of the target type */
149 uint16_t type; /* enum dom_proc_instruction_type */
151 /* For some processing instructions like xml the instructions contain
152 * attributes and those attribute can be collected in this @map. */
153 struct dom_node_list *map;
156 union dom_node_data {
157 struct dom_document_node document;
158 struct dom_document_type_node document_type;
159 struct dom_element_node element;
160 struct dom_attribute_node attribute;
161 struct dom_text_node text;
162 struct dom_id notation;
163 /* For entities string/length hold the notation name */
164 struct dom_id entity;
165 struct dom_proc_instruction_node proc_instruction;
167 /* Node types without a union member yet (mostly because it hasn't
168 * been necessary):
170 * DOM_NODE_CDATA_SECTION: Use dom_text_node?
171 * DOM_NODE_DOCUMENT_FRAGMENT: struct dom_node_list children;
172 * DOM_NODE_ENTITY_REFERENCE: unicode_val_T
173 * DOM_NODE_COMMENT
177 /* This structure is size critical so keep ordering to make it easier to pack
178 * and avoid unneeded members. */
179 struct dom_node {
180 /* The type of the node */
181 uint16_t type; /* -> enum dom_node_type */
183 /* Was the node string allocated? */
184 unsigned int allocated:1;
186 /* Can contain either stuff like element name or for attributes the
187 * attribute name. */
188 struct dom_string string;
190 struct dom_node *parent;
192 /* Various info depending on the type of the node. */
193 union dom_node_data data;
196 /* A node list can be used for storing indexed nodes */
197 struct dom_node_list {
198 size_t size;
199 struct dom_node *entries[1];
202 #define foreach_dom_node(list, node, i) \
203 for ((i) = 0; (i) < (list)->size; (i)++) \
204 if (((node) = (list)->entries[(i)]))
206 #define foreachback_dom_node(list, node, i) \
207 for ((i) = (list)->size - 1; (i) > 0; (i)--) \
208 if (((node) = (list)->entries[(i)]))
210 #define is_dom_node_list_member(list, member) \
211 ((list) && 0 <= (member) && (member) < (list)->size)
213 /* Adds @node to the list pointed to by @list_ptr at the given @position. If
214 * @position is -1 the node is added at the end. */
215 struct dom_node_list *
216 add_to_dom_node_list(struct dom_node_list **list_ptr,
217 struct dom_node *node, int position);
219 void done_dom_node_list(struct dom_node_list *list);
221 /* Returns the position or index where the @node has been inserted into the
222 * 'default' list of the @parent node. (Default means use get_dom_node_list()
223 * to acquire the list to search in. Returns -1, if the node is not found. */
224 int get_dom_node_list_index(struct dom_node *parent, struct dom_node *node);
226 /* Returns the position or index where the @node should be inserted into the
227 * node @list in order to the list to be alphabetically sorted. Assumes that
228 * @list is already sorted properly. */
229 int get_dom_node_map_index(struct dom_node_list *list, struct dom_node *node);
231 /* Returns the previous sibling to the node. */
232 struct dom_node *get_dom_node_prev(struct dom_node *node);
234 /* Returns the next sibling to the node. */
235 struct dom_node *get_dom_node_next(struct dom_node *node);
237 /* Returns first text node of the element or NULL. */
238 struct dom_node *
239 get_dom_node_child(struct dom_node *node, enum dom_node_type child_type,
240 int16_t child_subtype);
242 /* Looks up the @node_map for a node matching the requested type and name.
243 * The @subtype maybe be 0 indication unknown subtype and only name should be
244 * tested else it will indicate either the element or attribute private
245 * subtype. */
246 struct dom_node *
247 get_dom_node_map_entry(struct dom_node_list *node_map,
248 enum dom_node_type type, uint16_t subtype,
249 struct dom_string *name);
251 /* Removes the node and all its children and free()s itself */
252 void done_dom_node(struct dom_node *node);
254 /* The allocated argument is used as the value of node->allocated if >= 0.
255 * Use -1 to default node->allocated to the value of parent->allocated. */
256 struct dom_node *
257 init_dom_node_(unsigned char *file, int line,
258 struct dom_node *parent, enum dom_node_type type,
259 struct dom_string *string, int allocated);
261 #define init_dom_node(type, string, allocated) \
262 init_dom_node_(__FILE__, __LINE__, NULL, type, string, allocated)
264 #define add_dom_node(parent, type, string) \
265 init_dom_node_(__FILE__, __LINE__, parent, type, string, -1)
267 #define add_dom_element(parent, string) \
268 add_dom_node(parent, DOM_NODE_ELEMENT, string)
270 static inline struct dom_node *
271 add_dom_attribute(struct dom_node *parent, struct dom_string *name,
272 struct dom_string *value)
274 struct dom_node *node = add_dom_node(parent, DOM_NODE_ATTRIBUTE, name);
276 if (node && value) {
277 struct dom_string *str = &node->data.attribute.value;
279 if (node->allocated) {
280 if (!init_dom_string(str, value->string, value->length)) {
281 done_dom_node(node);
282 return NULL;
284 } else {
285 copy_dom_string(str, value);
289 return node;
292 static inline struct dom_node *
293 add_dom_proc_instruction(struct dom_node *parent, struct dom_string *string,
294 struct dom_string *instruction)
296 struct dom_node *node = add_dom_node(parent, DOM_NODE_PROCESSING_INSTRUCTION, string);
298 if (node && instruction) {
299 struct dom_string *str = &node->data.proc_instruction.instruction;
301 if (node->allocated) {
302 if (!init_dom_string(str, instruction->string, instruction->length)) {
303 done_dom_node(node);
304 return NULL;
306 } else {
307 copy_dom_string(str, instruction);
311 return node;
314 /* Compare two nodes returning non-zero if they differ. */
315 int dom_node_casecmp(struct dom_node *node1, struct dom_node *node2);
317 /* Returns the name of the node in an allocated string. */
318 struct dom_string *get_dom_node_name(struct dom_node *node);
320 /* Returns the value of the node or NULL if no value is defined for the node
321 * type. */
322 struct dom_string *get_dom_node_value(struct dom_node *node);
324 /* Returns the name used for identifying the node type. */
325 struct dom_string *get_dom_node_type_name(enum dom_node_type type);
327 /* Based on the type of the parent and the node type return a proper list
328 * or NULL. This is useful when adding a node to a parent node. */
329 static inline struct dom_node_list **
330 get_dom_node_list_by_type(struct dom_node *parent, enum dom_node_type type)
332 switch (parent->type) {
333 case DOM_NODE_DOCUMENT:
334 return &parent->data.document.children;
336 case DOM_NODE_ELEMENT:
337 switch (type) {
338 case DOM_NODE_ATTRIBUTE:
339 return &parent->data.element.map;
341 default:
342 return &parent->data.element.children;
345 case DOM_NODE_DOCUMENT_TYPE:
346 switch (type) {
347 case DOM_NODE_ENTITY:
348 return &parent->data.document_type.entities;
350 case DOM_NODE_NOTATION:
351 return &parent->data.document_type.notations;
353 default:
354 return NULL;
357 case DOM_NODE_PROCESSING_INSTRUCTION:
358 switch (type) {
359 case DOM_NODE_ATTRIBUTE:
360 return &parent->data.proc_instruction.map;
362 default:
363 return NULL;
366 default:
367 return NULL;
371 #define get_dom_node_list(parent, node) \
372 get_dom_node_list_by_type(parent, (node)->type)
374 #endif