1 /* iksemel (XML parser for Jabber)
2 ** Copyright (C) 2000-2007 Gurer Ozen <madcat@e-kolay.net>
3 ** This code is free software; you can redistribute it and/or
4 ** modify it under the terms of GNU Lesser General Public License.
5 */
6 
7 #include "common.h"
8 #include "iksemel.h"
9 
10 #define IKS_COMMON \
11 	struct iks_struct *next, *prev; \
12 	struct iks_struct *parent; \
13 	enum ikstype type; \
14 	ikstack *s
15 
16 struct iks_struct {
17 	IKS_COMMON;
18 };
19 
20 struct iks_tag {
21 	IKS_COMMON;
22 	struct iks_struct *children, *last_child;
23 	struct iks_struct *attribs, *last_attrib;
24 	char *name;
25 };
26 
27 #define IKS_TAG_NAME(x) ((struct iks_tag *) (x) )->name
28 #define IKS_TAG_CHILDREN(x) ((struct iks_tag *) (x) )->children
29 #define IKS_TAG_LAST_CHILD(x) ((struct iks_tag *) (x) )->last_child
30 #define IKS_TAG_ATTRIBS(x) ((struct iks_tag *) (x) )->attribs
31 #define IKS_TAG_LAST_ATTRIB(x) ((struct iks_tag *) (x) )->last_attrib
32 
33 struct iks_cdata {
34 	IKS_COMMON;
35 	char *cdata;
36 	size_t len;
37 };
38 
39 #define IKS_CDATA_CDATA(x) ((struct iks_cdata *) (x) )->cdata
40 #define IKS_CDATA_LEN(x) ((struct iks_cdata *) (x) )->len
41 
42 struct iks_attrib {
43 	IKS_COMMON;
44 	char *name;
45 	char *value;
46 };
47 
48 #define IKS_ATTRIB_NAME(x) ((struct iks_attrib *) (x) )->name
49 #define IKS_ATTRIB_VALUE(x) ((struct iks_attrib *) (x) )->value
50 
51 /*****  Node Creating & Deleting  *****/
52 
53 iks *
iks_new(const char * name)54 iks_new (const char *name)
55 {
56 	ikstack *s;
57 	iks *x;
58 
59 	s = iks_stack_new (sizeof (struct iks_tag) * 6, 256);
60 	if (!s) return NULL;
61 	x = iks_new_within (name, s);
62 	if (!x) {
63 		iks_stack_delete (&s);
64 		return NULL;
65 	}
66 	return x;
67 }
68 
69 iks *
iks_new_within(const char * name,ikstack * s)70 iks_new_within (const char *name, ikstack *s)
71 {
72 	iks *x;
73 	size_t len;
74 
75 	if (name) len = sizeof (struct iks_tag); else len = sizeof (struct iks_cdata);
76 	x = iks_stack_alloc (s, len);
77 	if (!x) return NULL;
78 	memset (x, 0, len);
79 	x->s = s;
80 	x->type = IKS_TAG;
81 	if (name) {
82 		IKS_TAG_NAME (x) = iks_stack_strdup (s, name, 0);
83 		if (!IKS_TAG_NAME (x)) return NULL;
84 	}
85 	return x;
86 }
87 
88 iks *
iks_insert(iks * x,const char * name)89 iks_insert (iks *x, const char *name)
90 {
91 	iks *y;
92 
93 	if (!x) return NULL;
94 
95 	y = iks_new_within (name, x->s);
96 	if (!y) return NULL;
97 	y->parent = x;
98 	if (!IKS_TAG_CHILDREN (x)) IKS_TAG_CHILDREN (x) = y;
99 	if (IKS_TAG_LAST_CHILD (x)) {
100 		IKS_TAG_LAST_CHILD (x)->next = y;
101 		y->prev = IKS_TAG_LAST_CHILD (x);
102 	}
103 	IKS_TAG_LAST_CHILD (x) = y;
104 	return y;
105 }
106 
107 iks *
iks_insert_cdata(iks * x,const char * data,size_t len)108 iks_insert_cdata (iks *x, const char *data, size_t len)
109 {
110 	iks *y;
111 
112 	if(!x || !data) return NULL;
113 	if(len == 0) len = strlen (data);
114 
115 	y = IKS_TAG_LAST_CHILD (x);
116 	if (y && y->type == IKS_CDATA) {
117 		IKS_CDATA_CDATA (y) = iks_stack_strcat (x->s, IKS_CDATA_CDATA (y), IKS_CDATA_LEN (y), data, len);
118 		IKS_CDATA_LEN (y) += len;
119 	} else {
120 		y = iks_insert (x, NULL);
121 		if (!y) return NULL;
122 		y->type = IKS_CDATA;
123 		IKS_CDATA_CDATA (y) = iks_stack_strdup (x->s, data, len);
124 		if (!IKS_CDATA_CDATA (y)) return NULL;
125 		IKS_CDATA_LEN (y) = len;
126 	}
127 	return y;
128 }
129 
130 iks *
iks_insert_attrib(iks * x,const char * name,const char * value)131 iks_insert_attrib (iks *x, const char *name, const char *value)
132 {
133 	iks *y;
134 
135 	if (!x) return NULL;
136 
137 	y = IKS_TAG_ATTRIBS (x);
138 	while (y) {
139 		if (strcmp (name, IKS_ATTRIB_NAME (y)) == 0) break;
140 		y = y->next;
141 	}
142 	if (NULL == y) {
143 		if (!value) return NULL;
144 		y = iks_stack_alloc (x->s, sizeof (struct iks_attrib));
145 		if (!y) return NULL;
146 		memset (y, 0, sizeof (struct iks_attrib));
147 		y->type = IKS_ATTRIBUTE;
148 		y->s = x->s;
149 		IKS_ATTRIB_NAME (y) = iks_stack_strdup (x->s, name, 0);
150 		if (!IKS_ATTRIB_NAME (y)) return NULL;
151 		y->parent = x;
152 		if (!IKS_TAG_ATTRIBS (x)) IKS_TAG_ATTRIBS (x) = y;
153 		if (IKS_TAG_LAST_ATTRIB (x)) {
154 			IKS_TAG_LAST_ATTRIB (x)->next = y;
155 			y->prev = IKS_TAG_LAST_ATTRIB (x);
156 		}
157 		IKS_TAG_LAST_ATTRIB (x) = y;
158 	}
159 
160 	if (value) {
161 		IKS_ATTRIB_VALUE (y) = iks_stack_strdup (x->s, value, 0);
162 		if (!IKS_ATTRIB_VALUE (y)) return NULL;
163 	} else {
164 		if (y->next) y->next->prev = y->prev;
165 		if (y->prev) y->prev->next = y->next;
166 		if (IKS_TAG_ATTRIBS (x) == y) IKS_TAG_ATTRIBS (x) = y->next;
167 		if (IKS_TAG_LAST_ATTRIB (x) == y) IKS_TAG_LAST_ATTRIB (x) = y->prev;
168 	}
169 
170 	return y;
171 }
172 
173 iks *
iks_insert_node(iks * x,iks * y)174 iks_insert_node (iks *x, iks *y)
175 {
176 	y->parent = x;
177 	if (!IKS_TAG_CHILDREN (x)) IKS_TAG_CHILDREN (x) = y;
178 	if (IKS_TAG_LAST_CHILD (x)) {
179 		IKS_TAG_LAST_CHILD (x)->next = y;
180 		y->prev = IKS_TAG_LAST_CHILD (x);
181 	}
182 	IKS_TAG_LAST_CHILD (x) = y;
183 	return y;
184 }
185 
186 iks *
iks_append(iks * x,const char * name)187 iks_append (iks *x, const char *name)
188 {
189 	iks *y;
190 
191 	if (!x) return NULL;
192 	y = iks_new_within (name, x->s);
193 	if (!y) return NULL;
194 
195 	if (x->next) {
196 		x->next->prev = y;
197 	} else {
198 		IKS_TAG_LAST_CHILD (x->parent) = y;
199 	}
200 	y->next = x->next;
201 	x->next = y;
202 	y->parent = x->parent;
203 	y->prev = x;
204 
205 	return y;
206 }
207 
208 iks *
iks_prepend(iks * x,const char * name)209 iks_prepend (iks *x, const char *name)
210 {
211 	iks *y;
212 
213 	if (!x) return NULL;
214 	y = iks_new_within (name, x->s);
215 	if (!y) return NULL;
216 
217 	if (x->prev) {
218 		x->prev->next = y;
219 	} else {
220 		IKS_TAG_CHILDREN (x->parent) = y;
221 	}
222 	y->prev = x->prev;
223 	x->prev = y;
224 	y->parent = x->parent;
225 	y->next = x;
226 
227 	return y;
228 }
229 
230 iks *
iks_append_cdata(iks * x,const char * data,size_t len)231 iks_append_cdata (iks *x, const char *data, size_t len)
232 {
233 	iks *y;
234 
235 	if (!x || !data) return NULL;
236 	if (len == 0) len = strlen (data);
237 
238 	y = iks_new_within (NULL, x->s);
239 	if (!y) return NULL;
240 	y->type = IKS_CDATA;
241 	IKS_CDATA_CDATA (y) = iks_stack_strdup (x->s, data, len);
242 	if (!IKS_CDATA_CDATA (y)) return NULL;
243 	IKS_CDATA_LEN (y) = len;
244 
245 	if (x->next) {
246 		x->next->prev = y;
247 	} else {
248 		IKS_TAG_LAST_CHILD (x->parent) = y;
249 	}
250 	y->next = x->next;
251 	x->next = y;
252 	y->parent = x->parent;
253 	y->prev = x;
254 
255 	return y;
256 }
257 
258 iks *
iks_prepend_cdata(iks * x,const char * data,size_t len)259 iks_prepend_cdata (iks *x, const char *data, size_t len)
260 {
261 	iks *y;
262 
263 	if (!x || !data) return NULL;
264 	if (len == 0) len = strlen (data);
265 
266 	y = iks_new_within (NULL, x->s);
267 	if (!y) return NULL;
268 	y->type = IKS_CDATA;
269 	IKS_CDATA_CDATA(y) = iks_stack_strdup (x->s, data, len);
270 	if (!IKS_CDATA_CDATA (y)) return NULL;
271 	IKS_CDATA_LEN (y) = len;
272 
273 	if (x->prev) {
274 		x->prev->next = y;
275 	} else {
276 		IKS_TAG_CHILDREN (x->parent) = y;
277 	}
278 	y->prev = x->prev;
279 	x->prev = y;
280 	y->parent = x->parent;
281 	y->next = x;
282 
283 	return y;
284 }
285 
286 void
iks_hide(iks * x)287 iks_hide (iks *x)
288 {
289 	iks *y;
290 
291 	if (!x) return;
292 
293 	if (x->prev) x->prev->next = x->next;
294 	if (x->next) x->next->prev = x->prev;
295 	y = x->parent;
296 	if (y) {
297 		if (IKS_TAG_CHILDREN (y) == x) IKS_TAG_CHILDREN (y) = x->next;
298 		if (IKS_TAG_LAST_CHILD (y) == x) IKS_TAG_LAST_CHILD (y) = x->prev;
299 	}
300 }
301 
302 void
iks_delete(iks * x)303 iks_delete (iks *x)
304 {
305 	if (x) iks_stack_delete (&x->s);
306 }
307 
308 /*****  Node Traversing  *****/
309 
310 iks *
iks_next(iks * x)311 iks_next (iks *x)
312 {
313 	if (x) return x->next;
314 	return NULL;
315 }
316 
317 iks *
iks_next_tag(iks * x)318 iks_next_tag (iks *x)
319 {
320 	if (x) {
321 		while (1) {
322 			x = x->next;
323 			if (NULL == x) break;
324 			if (IKS_TAG == x->type) return x;
325 		}
326 	}
327 	return NULL;
328 }
329 
330 iks *
iks_prev(iks * x)331 iks_prev (iks *x)
332 {
333 	if (x) return x->prev;
334 	return NULL;
335 }
336 
337 iks *
iks_prev_tag(iks * x)338 iks_prev_tag (iks *x)
339 {
340 	if (x) {
341 		while (1) {
342 			x = x->prev;
343 			if (NULL == x) break;
344 			if (IKS_TAG == x->type) return x;
345 		}
346 	}
347 	return NULL;
348 }
349 
350 iks *
iks_parent(iks * x)351 iks_parent (iks *x)
352 {
353 	if (x) return x->parent;
354 	return NULL;
355 }
356 
357 iks *
iks_root(iks * x)358 iks_root (iks *x)
359 {
360 	if (x) {
361 		while (x->parent)
362 			x = x->parent;
363 	}
364 	return x;
365 }
366 
367 iks *
iks_child(iks * x)368 iks_child (iks *x)
369 {
370 	if (x && IKS_TAG == x->type) return IKS_TAG_CHILDREN (x);
371 	return NULL;
372 }
373 
374 iks *
iks_first_tag(iks * x)375 iks_first_tag (iks *x)
376 {
377 	if (x) {
378 		x = IKS_TAG_CHILDREN (x);
379 		while (x) {
380 			if (IKS_TAG == x->type) return x;
381 			x = x->next;
382 		}
383 	}
384 	return NULL;
385 }
386 
387 iks *
iks_attrib(iks * x)388 iks_attrib (iks *x)
389 {
390 	if (x) return IKS_TAG_ATTRIBS (x);
391 	return NULL;
392 }
393 
394 iks *
iks_find(iks * x,const char * name)395 iks_find (iks *x, const char *name)
396 {
397 	iks *y;
398 
399 	if (!x) return NULL;
400 	y = IKS_TAG_CHILDREN (x);
401 	while (y) {
402 		if (IKS_TAG == y->type && IKS_TAG_NAME (y) && strcmp (IKS_TAG_NAME (y), name) == 0) return y;
403 		y = y->next;
404 	}
405 	return NULL;
406 }
407 
408 char *
iks_find_cdata(iks * x,const char * name)409 iks_find_cdata (iks *x, const char *name)
410 {
411 	iks *y;
412 
413 	y = iks_find (x, name);
414 	if (!y) return NULL;
415 	y = IKS_TAG_CHILDREN (y);
416 	if (!y || IKS_CDATA != y->type) return NULL;
417 	return IKS_CDATA_CDATA (y);
418 }
419 
420 char *
iks_find_attrib(iks * x,const char * name)421 iks_find_attrib (iks *x, const char *name)
422 {
423 	iks *y;
424 
425 	if (!x) return NULL;
426 
427 	y = IKS_TAG_ATTRIBS (x);
428 	while (y) {
429 		if (IKS_ATTRIB_NAME (y) && strcmp (IKS_ATTRIB_NAME (y), name) == 0)
430 			return IKS_ATTRIB_VALUE (y);
431 		y = y->next;
432 	}
433 	return NULL;
434 }
435 
436 iks *
iks_find_with_attrib(iks * x,const char * tagname,const char * attrname,const char * value)437 iks_find_with_attrib (iks *x, const char *tagname, const char *attrname, const char *value)
438 {
439 	iks *y;
440 
441 	if (NULL == x) return NULL;
442 
443 	if (tagname) {
444 		for (y = IKS_TAG_CHILDREN (x); y; y = y->next) {
445 			if (IKS_TAG == y->type
446 				&& strcmp (IKS_TAG_NAME (y), tagname) == 0
447 				&& iks_strcmp (iks_find_attrib (y, attrname), value) == 0) {
448 					return y;
449 			}
450 		}
451 	} else {
452 		for (y = IKS_TAG_CHILDREN (x); y; y = y->next) {
453 			if (IKS_TAG == y->type
454 				&& iks_strcmp (iks_find_attrib (y, attrname), value) == 0) {
455 					return y;
456 			}
457 		}
458 	}
459 	return NULL;
460 }
461 
462 /*****  Node Information  *****/
463 
464 ikstack *
iks_stack(iks * x)465 iks_stack (iks *x)
466 {
467 	if (x) return x->s;
468 	return NULL;
469 }
470 
471 enum ikstype
iks_type(iks * x)472 iks_type (iks *x)
473 {
474 	if (x) return x->type;
475 	return IKS_NONE;
476 }
477 
478 char *
iks_name(iks * x)479 iks_name (iks *x)
480 {
481 	if (x) {
482 		if (IKS_TAG == x->type)
483 			return IKS_TAG_NAME (x);
484 		else
485 			return IKS_ATTRIB_NAME (x);
486 	}
487 	return NULL;
488 }
489 
490 char *
iks_cdata(iks * x)491 iks_cdata (iks *x)
492 {
493 	if (x) {
494 		if (IKS_CDATA == x->type)
495 			return IKS_CDATA_CDATA (x);
496 		else
497 			return IKS_ATTRIB_VALUE (x);
498 	}
499 	return NULL;
500 }
501 
502 size_t
iks_cdata_size(iks * x)503 iks_cdata_size (iks *x)
504 {
505 	if (x) return IKS_CDATA_LEN (x);
506 	return 0;
507 }
508 
509 int
iks_has_children(iks * x)510 iks_has_children (iks *x)
511 {
512 	if (x && IKS_TAG == x->type && IKS_TAG_CHILDREN (x)) return 1;
513 	return 0;
514 }
515 
516 int
iks_has_attribs(iks * x)517 iks_has_attribs (iks *x)
518 {
519 	if (x && IKS_TAG == x->type && IKS_TAG_ATTRIBS (x)) return 1;
520 	return 0;
521 }
522 
523 /*****  Serializing  *****/
524 
525 static size_t
escape_size(char * src,size_t len)526 escape_size (char *src, size_t len)
527 {
528 	size_t sz;
529 	char c;
530 	int i;
531 
532 	sz = 0;
533 	for (i = 0; i < len; i++) {
534 		c = src[i];
535 		switch (c) {
536 			case '&': sz += 5; break;
537 			case '\'': sz += 6; break;
538 			case '"': sz += 6; break;
539 			case '<': sz += 4; break;
540 			case '>': sz += 4; break;
541 			default: sz++; break;
542 		}
543 	}
544 	return sz;
545 }
546 
547 static char *
my_strcat(char * dest,char * src,size_t len)548 my_strcat (char *dest, char *src, size_t len)
549 {
550 	if (0 == len) len = strlen (src);
551 	memcpy (dest, src, len);
552 	return dest + len;
553 }
554 
555 static char *
escape(char * dest,char * src,size_t len)556 escape (char *dest, char *src, size_t len)
557 {
558 	char c;
559 	int i;
560 	int j = 0;
561 
562 	for (i = 0; i < len; i++) {
563 		c = src[i];
564 		if ('&' == c || '<' == c || '>' == c || '\'' == c || '"' == c) {
565 			if (i - j > 0) dest = my_strcat (dest, src + j, i - j);
566 			j = i + 1;
567 			switch (c) {
568 			case '&': dest = my_strcat (dest, "&amp;", 5); break;
569 			case '\'': dest = my_strcat (dest, "&apos;", 6); break;
570 			case '"': dest = my_strcat (dest, "&quot;", 6); break;
571 			case '<': dest = my_strcat (dest, "&lt;", 4); break;
572 			case '>': dest = my_strcat (dest, "&gt;", 4); break;
573 			}
574 		}
575 	}
576 	if (i - j > 0) dest = my_strcat (dest, src + j, i - j);
577 	return dest;
578 }
579 
580 char *
iks_string(ikstack * s,iks * x)581 iks_string (ikstack *s, iks *x)
582 {
583 	size_t size;
584 	int level, dir;
585 	iks *y, *z;
586 	char *ret, *t;
587 
588 	if (!x) return NULL;
589 
590 	if (x->type == IKS_CDATA) {
591 		if (s) {
592 			return iks_stack_strdup (s, IKS_CDATA_CDATA (x), IKS_CDATA_LEN (x));
593 		} else {
594 			ret = iks_malloc (IKS_CDATA_LEN (x));
595 			memcpy (ret, IKS_CDATA_CDATA (x), IKS_CDATA_LEN (x));
596 			return ret;
597 		}
598 	}
599 
600 	size = 0;
601 	level = 0;
602 	dir = 0;
603 	y = x;
604 	while (1) {
605 		if (dir==0) {
606 			if (y->type == IKS_TAG) {
607 				size++;
608 				size += strlen (IKS_TAG_NAME (y));
609 				for (z = IKS_TAG_ATTRIBS (y); z; z = z->next) {
610 					if (z->type == IKS_NONE) {
611 						continue;
612 					}
613 					size += 4 + strlen (IKS_ATTRIB_NAME (z))
614 						+ escape_size (IKS_ATTRIB_VALUE (z), strlen (IKS_ATTRIB_VALUE (z)));
615 				}
616 				if (IKS_TAG_CHILDREN (y)) {
617 					size++;
618 					y = IKS_TAG_CHILDREN (y);
619 					level++;
620 					continue;
621 				} else {
622 					size += 2;
623 				}
624 			} else {
625 				size += escape_size (IKS_CDATA_CDATA (y), IKS_CDATA_LEN (y));
626 			}
627 		}
628 		z = y->next;
629 		if (z) {
630 			if (0 == level) {
631 				if (IKS_TAG_CHILDREN (y)) size += 3 + strlen (IKS_TAG_NAME (y));
632 				break;
633 			}
634 			y = z;
635 			dir = 0;
636 		} else {
637 			y = y->parent;
638 			level--;
639 			if (level >= 0) size += 3 + strlen (IKS_TAG_NAME (y));
640 			if (level < 1) break;
641 			dir = 1;
642 		}
643 	}
644 
645 	if (s) ret = iks_stack_alloc (s, size + 1);
646 	else ret = iks_malloc (size + 1);
647 
648 	if (!ret) return NULL;
649 
650 	t = ret;
651 	level = 0;
652 	dir = 0;
653 	while (1) {
654 		if (dir==0) {
655 			if (x->type == IKS_TAG) {
656 				*t++ = '<';
657 				t = my_strcat (t, IKS_TAG_NAME (x), 0);
658 				y = IKS_TAG_ATTRIBS (x);
659 				while (y) {
660 					*t++ = ' ';
661 					t = my_strcat (t, IKS_ATTRIB_NAME (y), 0);
662 					*t++ = '=';
663 					*t++ = '\'';
664 					t = escape (t, IKS_ATTRIB_VALUE (y), strlen (IKS_ATTRIB_VALUE (y)));
665 					*t++ = '\'';
666 					y = y->next;
667 				}
668 				if (IKS_TAG_CHILDREN (x)) {
669 					*t++ = '>';
670 					x = IKS_TAG_CHILDREN (x);
671 					level++;
672 					continue;
673 				} else {
674 					*t++ = '/';
675 					*t++ = '>';
676 				}
677 			} else {
678 				t = escape (t, IKS_CDATA_CDATA (x), IKS_CDATA_LEN (x));
679 			}
680 		}
681 		y = x->next;
682 		if (y) {
683 			if (0 == level) {
684 				if (IKS_TAG_CHILDREN (x)) {
685 					*t++ = '<';
686 					*t++ = '/';
687 					t = my_strcat (t, IKS_TAG_NAME (x), 0);
688 					*t++ = '>';
689 				}
690 				break;
691 			}
692 			x = y;
693 			dir = 0;
694 		} else {
695 			x = x->parent;
696 			level--;
697 			if (level >= 0) {
698 					*t++ = '<';
699 					*t++ = '/';
700 					t = my_strcat (t, IKS_TAG_NAME (x), 0);
701 					*t++ = '>';
702 				}
703 			if (level < 1) break;
704 			dir = 1;
705 		}
706 	}
707 	*t = '\0';
708 
709 	return ret;
710 }
711 
712 /*****  Copying  *****/
713 
714 iks *
iks_copy_within(iks * x,ikstack * s)715 iks_copy_within (iks *x, ikstack *s)
716 {
717 	int level=0, dir=0;
718 	iks *copy = NULL;
719 	iks *cur = NULL;
720 	iks *y;
721 
722 	while (1) {
723 		if (dir == 0) {
724 			if (x->type == IKS_TAG) {
725 				if (copy == NULL) {
726 					copy = iks_new_within (IKS_TAG_NAME (x), s);
727 					cur = copy;
728 				} else {
729 					cur = iks_insert (cur, IKS_TAG_NAME (x));
730 				}
731 				for (y = IKS_TAG_ATTRIBS (x); y; y = y->next) {
732 					iks_insert_attrib (cur, IKS_ATTRIB_NAME (y), IKS_ATTRIB_VALUE (y));
733 				}
734 				if (IKS_TAG_CHILDREN (x)) {
735 					x = IKS_TAG_CHILDREN (x);
736 					level++;
737 					continue;
738 				} else {
739 					cur = cur->parent;
740 				}
741 			} else {
742 				iks_insert_cdata (cur, IKS_CDATA_CDATA (x), IKS_CDATA_LEN (x));
743 			}
744 		}
745 		y = x->next;
746 		if (y) {
747 			if (0 == level) break;
748 			x = y;
749 			dir = 0;
750 		} else {
751 			if (level < 2) break;
752 			level--;
753 			x = x->parent;
754 			cur = cur->parent;
755 			dir = 1;
756 		}
757 	}
758 	return copy;
759 }
760 
761 iks *
iks_copy(iks * x)762 iks_copy (iks *x)
763 {
764 	return iks_copy_within (x, iks_stack_new (sizeof (struct iks_tag) * 6, 256));
765 }
766