1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 
3 /*
4  *  GThumb
5  *
6  *  Copyright (C) 2003, 2010 Free Software Foundation, Inc.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <stdio.h>
23 #include "albumtheme-private.h"
24 
25 #define MAX_EXPR_SIZE 100
26 #define MEM_SIZE 1000
27 
28 
29 GList *yy_parsed_doc = NULL;
30 
31 
32 GthMem *
gth_mem_new(int size)33 gth_mem_new (int size)
34 {
35 	GthMem *mem;
36 
37 	mem = g_new0 (GthMem, 1);
38 
39 	mem->data = g_new (int, size);
40 	gth_mem_set_empty (mem);
41 
42 	return mem;
43 }
44 
45 
46 void
gth_mem_free(GthMem * mem)47 gth_mem_free (GthMem *mem)
48 {
49 	g_free (mem->data);
50 	g_free (mem);
51 }
52 
53 
54 void
gth_mem_set_empty(GthMem * mem)55 gth_mem_set_empty (GthMem *mem)
56 {
57 	mem->top = 0;
58 }
59 
60 
61 gboolean
gth_mem_is_empty(GthMem * mem)62 gth_mem_is_empty (GthMem *mem)
63 {
64 	return (mem->top == 0);
65 }
66 
67 
68 void
gth_mem_push(GthMem * mem,int val)69 gth_mem_push (GthMem *mem,
70 	      int     val)
71 {
72 	mem->data[mem->top++] = val;
73 }
74 
75 
76 int
gth_mem_pop(GthMem * mem)77 gth_mem_pop (GthMem *mem)
78 {
79 	if (! gth_mem_is_empty (mem)) {
80 		mem->top--;
81 		return mem->data[mem->top];
82 	}
83 
84 	return 0;
85 }
86 
87 
88 int
gth_mem_get_pos(GthMem * mem,int pos)89 gth_mem_get_pos (GthMem *mem,
90 		 int     pos)
91 {
92 	if ((pos <= 0) || (pos > mem->top))
93 		return 0;
94 	return mem->data[pos - 1];
95 }
96 
97 
98 int
gth_mem_get(GthMem * mem)99 gth_mem_get (GthMem *mem)
100 {
101 	return gth_mem_get_pos (mem, mem->top);
102 }
103 
104 
105 int
gth_mem_get_top(GthMem * mem)106 gth_mem_get_top (GthMem *mem)
107 {
108 	return mem->top;
109 }
110 
111 
112 /* GthCell */
113 
114 
115 GthCell *
gth_cell_new(void)116 gth_cell_new (void)
117 {
118 	GthCell *cell;
119 
120 	cell = g_new0 (GthCell, 1);
121 	cell->ref = 1;
122 
123 	return cell;
124 }
125 
126 
127 GthCell *
gth_cell_ref(GthCell * cell)128 gth_cell_ref (GthCell *cell)
129 {
130 	cell->ref++;
131 	return cell;
132 }
133 
134 
135 void
gth_cell_unref(GthCell * cell)136 gth_cell_unref (GthCell *cell)
137 {
138 	if (cell == NULL)
139 		return;
140 
141 	cell->ref--;
142 	if (cell->ref > 0)
143 		return;
144 
145 	if (cell->type == GTH_CELL_TYPE_VAR)
146 		g_free (cell->value.var);
147 	else if (cell->type == GTH_CELL_TYPE_STRING)
148 		g_string_free (cell->value.string, TRUE);
149 	g_free (cell);
150 }
151 
152 
153 /* GthExpr */
154 
155 
156 static int
default_get_var_value_func(GthExpr * expr,int * index,const char * var_name,gpointer data)157 default_get_var_value_func (GthExpr    *expr,
158 		   	    int        *index,
159 		   	    const char *var_name,
160 			    gpointer    data)
161 {
162 	return 0;
163 }
164 
165 
166 GthExpr *
gth_expr_new(void)167 gth_expr_new (void)
168 {
169 	GthExpr *e;
170 
171 	e = g_new0 (GthExpr, 1);
172 	e->ref = 1;
173 	e->data = g_new0 (GthCell*, MAX_EXPR_SIZE);
174 	gth_expr_set_get_var_value_func (e, default_get_var_value_func, NULL);
175 
176 	return e;
177 }
178 
179 
180 GthExpr *
gth_expr_ref(GthExpr * e)181 gth_expr_ref (GthExpr *e)
182 {
183 	e->ref++;
184 	return e;
185 }
186 
187 
188 void
gth_expr_unref(GthExpr * e)189 gth_expr_unref (GthExpr *e)
190 {
191 	if (e == NULL)
192 		return;
193 
194 	e->ref--;
195 
196 	if (e->ref == 0) {
197 		int i;
198 
199 		for (i = 0; i < MAX_EXPR_SIZE; i++)
200 			gth_cell_unref (e->data[i]);
201 		g_free (e->data);
202 		g_free (e);
203 	}
204 }
205 
206 
207 void
gth_expr_set_empty(GthExpr * e)208 gth_expr_set_empty (GthExpr *e)
209 {
210 	e->top = 0;
211 }
212 
213 
214 gboolean
gth_expr_is_empty(GthExpr * e)215 gth_expr_is_empty (GthExpr *e)
216 {
217 	return (e->top == 0);
218 }
219 
220 
221 void
gth_expr_push_expr(GthExpr * e,GthExpr * e2)222 gth_expr_push_expr (GthExpr *e,
223 		    GthExpr *e2)
224 {
225 	int i;
226 
227 	for (i = 0; i < e2->top; i++) {
228 		gth_cell_unref (e->data[e->top]);
229 		e->data[e->top] = gth_cell_ref (e2->data[i]);
230 		e->top++;
231 	}
232 }
233 
234 
235 void
gth_expr_push_op(GthExpr * e,GthOp op)236 gth_expr_push_op (GthExpr *e,
237 		  GthOp    op)
238 {
239 	GthCell *cell;
240 
241 	gth_cell_unref (e->data[e->top]);
242 
243 	cell = gth_cell_new ();
244 	cell->type = GTH_CELL_TYPE_OP;
245 	cell->value.op = op;
246 	e->data[e->top] = cell;
247 
248 	e->top++;
249 }
250 
251 
252 void
gth_expr_push_var(GthExpr * e,const char * name)253 gth_expr_push_var (GthExpr    *e,
254 		   const char *name)
255 {
256 	GthCell *cell;
257 
258 	gth_cell_unref (e->data[e->top]);
259 
260 	cell = gth_cell_new ();
261 	cell->type = GTH_CELL_TYPE_VAR;
262 	cell->value.var = g_strdup (name);
263 	e->data[e->top] = cell;
264 
265 	e->top++;
266 }
267 
268 
269 void
gth_expr_push_string(GthExpr * e,const char * value)270 gth_expr_push_string (GthExpr    *e,
271 		      const char *value)
272 {
273 	GthCell *cell;
274 
275 	gth_cell_unref (e->data[e->top]);
276 
277 	cell = gth_cell_new ();
278 	cell->type = GTH_CELL_TYPE_STRING;
279 	cell->value.string = g_string_new (value);
280 	e->data[e->top] = cell;
281 
282 	e->top++;
283 }
284 
285 
286 void
gth_expr_push_integer(GthExpr * e,int value)287 gth_expr_push_integer (GthExpr *e,
288 		       int      value)
289 {
290 	GthCell *cell;
291 
292 	gth_cell_unref (e->data[e->top]);
293 
294 	cell = gth_cell_new ();
295 	cell->type = GTH_CELL_TYPE_INTEGER;
296 	cell->value.integer = value;
297 	e->data[e->top] = cell;
298 
299 	e->top++;
300 }
301 
302 
303 void
gth_expr_pop(GthExpr * e)304 gth_expr_pop (GthExpr *e)
305 {
306 	if (! gth_expr_is_empty (e))
307 		e->top--;
308 }
309 
310 
311 GthCell *
gth_expr_get_pos(GthExpr * e,int pos)312 gth_expr_get_pos (GthExpr *e, int pos)
313 {
314 	if ((pos <= 0) || (pos > e->top))
315 		return NULL;
316 	return e->data[pos - 1];
317 }
318 
319 
320 GthCell *
gth_expr_get(GthExpr * e)321 gth_expr_get (GthExpr *e)
322 {
323 	return gth_expr_get_pos (e, e->top);
324 }
325 
326 
327 int
gth_expr_get_top(GthExpr * e)328 gth_expr_get_top (GthExpr *e)
329 {
330 	return e->top;
331 }
332 
333 
334 void
gth_expr_set_get_var_value_func(GthExpr * e,GthGetVarValueFunc f,gpointer data)335 gth_expr_set_get_var_value_func (GthExpr            *e,
336 				 GthGetVarValueFunc  f,
337 				 gpointer            data)
338 {
339 	e->get_var_value_func = f;
340 	e->get_var_value_data = data;
341 }
342 
343 
344 static char *op_name[] = {
345 	"ADD",
346 	"SUB",
347 	"MUL",
348 	"DIV",
349 	"NEG",
350 	"NOT",
351 	"AND",
352 	"OR",
353 	"CMP_EQ",
354 	"CMP_NE",
355 	"CMP_LT",
356 	"CMP_GT",
357 	"CMP_LE",
358 	"CMP_GE"
359 };
360 
361 
362 void
gth_expr_print(GthExpr * e)363 gth_expr_print (GthExpr *e)
364 {
365 	int i;
366 
367 	for (i = 1; i <= gth_expr_get_top (e); i++) {
368 		GthCell *cell = gth_expr_get_pos (e, i);
369 
370 		switch (cell->type) {
371 		case GTH_CELL_TYPE_VAR:
372 			/*g_print ("VAR: %s (%d)\n",
373 				 cell->value.var,
374 				 e->get_var_value_func (e,
375 						        &i,
376 						        cell->value.var,
377 						        e->get_var_value_data));*/
378 			g_print ("(%d) VAR: %s\n", i, cell->value.var);
379 			break;
380 
381 		case GTH_CELL_TYPE_STRING:
382 			g_print ("(%d) STRING: %s\n", i, cell->value.string->str);
383 			break;
384 
385 		case GTH_CELL_TYPE_INTEGER:
386 			printf ("(%d) NUM: %d\n", i, cell->value.integer);
387 			break;
388 
389 		case GTH_CELL_TYPE_OP:
390 			printf ("(%d) OP: %s\n", i, op_name[cell->value.op]);
391 			break;
392 		}
393 	}
394 }
395 
396 
397 int
gth_expr_eval(GthExpr * e)398 gth_expr_eval (GthExpr *e)
399 {
400 	GthMem *mem;
401 	int     retval = 0;
402 	int     i;
403 
404 	mem = gth_mem_new (MEM_SIZE);
405 
406 	for (i = 1; i <= gth_expr_get_top (e); i++) {
407 		GthCell *cell = gth_expr_get_pos (e, i);
408 		int      a, b, c;
409 
410 		switch (cell->type) {
411 		case GTH_CELL_TYPE_VAR:
412 			gth_mem_push (mem,
413 				      e->get_var_value_func (e,
414 						      	     &i,
415 						      	     cell->value.var,
416 							     e->get_var_value_data));
417 			break;
418 
419 		case GTH_CELL_TYPE_STRING:
420 			/* only used as argument for a function */
421 			break;
422 
423 		case GTH_CELL_TYPE_INTEGER:
424 			gth_mem_push (mem, cell->value.integer);
425 			break;
426 
427 		case GTH_CELL_TYPE_OP:
428 			switch (cell->value.op) {
429 			case GTH_OP_NEG:
430 				a = gth_mem_pop (mem);
431 				gth_mem_push (mem, -a);
432 				break;
433 
434 			case GTH_OP_NOT:
435 				a = gth_mem_pop (mem);
436 				gth_mem_push (mem, (a == 0) ? 1 : 0);
437 				break;
438 
439 			case GTH_OP_ADD:
440 				b = gth_mem_pop (mem);
441 				a = gth_mem_pop (mem);
442 				c = a + b;
443 				gth_mem_push (mem, c);
444 				break;
445 
446 			case GTH_OP_SUB:
447 				b = gth_mem_pop (mem);
448 				a = gth_mem_pop (mem);
449 				c = a - b;
450 				gth_mem_push (mem, c);
451 				break;
452 
453 			case GTH_OP_MUL:
454 				b = gth_mem_pop (mem);
455 				a = gth_mem_pop (mem);
456 				c = a * b;
457 				gth_mem_push (mem, c);
458 				break;
459 
460 			case GTH_OP_DIV:
461 				b = gth_mem_pop (mem);
462 				a = gth_mem_pop (mem);
463 				c = a / b;
464 				gth_mem_push (mem, c);
465 				break;
466 
467 			case GTH_OP_AND:
468 				b = gth_mem_pop (mem);
469 				a = gth_mem_pop (mem);
470 				c = (a != 0) && (b != 0);
471 				gth_mem_push (mem, c);
472 				break;
473 
474 			case GTH_OP_OR:
475 				b = gth_mem_pop (mem);
476 				a = gth_mem_pop (mem);
477 				c = (a != 0) || (b != 0);
478 				gth_mem_push (mem, c);
479 				break;
480 
481 			case GTH_OP_CMP_EQ:
482 				b = gth_mem_pop (mem);
483 				a = gth_mem_pop (mem);
484 				c = (a == b);
485 				gth_mem_push (mem, c);
486 				break;
487 
488 			case GTH_OP_CMP_NE:
489 				b = gth_mem_pop (mem);
490 				a = gth_mem_pop (mem);
491 				c = (a != b);
492 				gth_mem_push (mem, c);
493 				break;
494 
495 			case GTH_OP_CMP_LT:
496 				b = gth_mem_pop (mem);
497 				a = gth_mem_pop (mem);
498 				c = (a < b);
499 				gth_mem_push (mem, c);
500 				break;
501 
502 			case GTH_OP_CMP_GT:
503 				b = gth_mem_pop (mem);
504 				a = gth_mem_pop (mem);
505 				c = (a > b);
506 				gth_mem_push (mem, c);
507 				break;
508 
509 			case GTH_OP_CMP_LE:
510 				b = gth_mem_pop (mem);
511 				a = gth_mem_pop (mem);
512 				c = (a <= b);
513 				gth_mem_push (mem, c);
514 				break;
515 
516 			case GTH_OP_CMP_GE:
517 				b = gth_mem_pop (mem);
518 				a = gth_mem_pop (mem);
519 				c = (a >= b);
520 				gth_mem_push (mem, c);
521 				break;
522 			}
523 			break;
524 		}
525 	}
526 
527 	retval = gth_mem_get (mem);
528 
529 	gth_mem_free (mem);
530 
531 	return retval;
532 }
533 
534 
535 void
gth_expr_list_unref(GList * list)536 gth_expr_list_unref (GList *list)
537 {
538 	GList *scan;
539 
540 	for (scan = list; scan; scan = scan->next)
541 		gth_expr_unref ((GthExpr *) scan->data);
542 	g_list_free (list);
543 }
544 
545 
546 /* GthAttribute */
547 
548 
549 GthAttribute *
gth_attribute_new_expression(const char * name,GthExpr * expr)550 gth_attribute_new_expression (const char *name,
551 			      GthExpr    *expr)
552 {
553 	GthAttribute *attribute;
554 
555 	g_return_val_if_fail (name != NULL, NULL);
556 
557 	attribute = g_new0 (GthAttribute, 1);
558 	attribute->type = GTH_ATTRIBUTE_EXPR;
559 	attribute->name = g_strdup (name);
560 	attribute->value.expr = gth_expr_ref (expr);
561 
562 	return attribute;
563 }
564 
565 
566 GthAttribute*
gth_attribute_new_string(const char * name,const char * string)567 gth_attribute_new_string (const char *name,
568 			  const char *string)
569 {
570 	GthAttribute *attribute;
571 
572 	g_return_val_if_fail (name != NULL, NULL);
573 
574 	attribute = g_new0 (GthAttribute, 1);
575 	attribute->type = GTH_ATTRIBUTE_STRING;
576 	attribute->name = g_strdup (name);
577 	if (string != NULL)
578 		attribute->value.string = g_strdup (string);
579 
580 	return attribute;
581 }
582 
583 
584 void
gth_attribute_free(GthAttribute * attribute)585 gth_attribute_free (GthAttribute *attribute)
586 {
587 	g_free (attribute->name);
588 	switch (attribute->type) {
589 	case GTH_ATTRIBUTE_EXPR:
590 		gth_expr_unref (attribute->value.expr);
591 		break;
592 	case GTH_ATTRIBUTE_STRING:
593 		g_free (attribute->value.string);
594 		break;
595 	}
596 	g_free (attribute);
597 }
598 
599 
600 /* GthCondition */
601 
602 
603 GthCondition *
gth_condition_new(GthExpr * expr)604 gth_condition_new (GthExpr *expr)
605 {
606 	GthCondition *cond;
607 
608 	cond = g_new0 (GthCondition, 1);
609 	cond->expr = gth_expr_ref (expr);
610 
611 	return cond;
612 }
613 
614 
615 void
gth_condition_free(GthCondition * cond)616 gth_condition_free (GthCondition *cond)
617 {
618 	if (cond == NULL)
619 		return;
620 	gth_expr_unref (cond->expr);
621 	gth_parsed_doc_free (cond->document);
622 	g_free (cond);
623 }
624 
625 
626 void
gth_condition_add_document(GthCondition * cond,GList * document)627 gth_condition_add_document (GthCondition *cond,
628 			    GList        *document)
629 {
630 	if (cond->document != NULL)
631 		gth_parsed_doc_free (cond->document);
632 	cond->document = document;
633 }
634 
635 
636 /* GthLoop */
637 
638 
639 GthLoop *
gth_loop_new(GthTagType loop_type)640 gth_loop_new (GthTagType  loop_type)
641 {
642 	GthLoop *loop;
643 
644 	loop = g_new0 (GthLoop, 1);
645 	loop->type = loop_type;
646 
647 	return loop;
648 }
649 
650 
651 void
gth_loop_free(GthLoop * loop)652 gth_loop_free (GthLoop *loop)
653 {
654 	if (loop == NULL)
655 		return;
656 	gth_parsed_doc_free (loop->document);
657 	g_free (loop);
658 }
659 
660 
661 GthTagType
gth_loop_get_type(GthLoop * loop)662 gth_loop_get_type (GthLoop *loop)
663 {
664 	return loop->type;
665 }
666 
667 
668 void
gth_loop_add_document(GthLoop * loop,GList * document)669 gth_loop_add_document (GthLoop *loop,
670 		       GList   *document)
671 {
672 	if (loop->document != NULL)
673 		gth_parsed_doc_free (loop->document);
674 	loop->document = document;
675 }
676 
677 
678 /* GthRangeLoop */
679 
680 
681 GthLoop *
gth_range_loop_new(void)682 gth_range_loop_new (void)
683 {
684 	GthLoop *loop;
685 
686 	loop = (GthLoop *) g_new0 (GthRangeLoop, 1);
687 	loop->type = GTH_TAG_FOR_EACH_IN_RANGE;
688 
689 	return loop;
690 }
691 
692 
693 void
gth_range_loop_free(GthRangeLoop * loop)694 gth_range_loop_free (GthRangeLoop *loop)
695 {
696 	g_free (loop->iterator);
697 	gth_expr_unref (loop->first_value);
698 	gth_expr_unref (loop->last_value);
699 	gth_loop_free (GTH_LOOP (loop));
700 }
701 
702 
703 void
gth_range_loop_set_range(GthRangeLoop * loop,const char * iterator,GthExpr * first_value,GthExpr * last_value)704 gth_range_loop_set_range (GthRangeLoop *loop,
705 			  const char   *iterator,
706 			  GthExpr      *first_value,
707 			  GthExpr      *last_value)
708 {
709 	loop->iterator = g_strdup (iterator);
710 	loop->first_value = gth_expr_ref (first_value);
711 	loop->last_value = gth_expr_ref (last_value);
712 }
713 
714 
715 /* GthTag */
716 
717 
718 GthTag *
gth_tag_new(GthTagType type,GList * attributes)719 gth_tag_new (GthTagType  type,
720 	     GList      *attributes)
721 {
722 	GthTag *tag;
723 
724 	tag = g_new0 (GthTag, 1);
725 	tag->type = type;
726 	tag->value.attributes = attributes;
727 
728 	return tag;
729 }
730 
731 
732 GthTag *
gth_tag_new_html(const char * html)733 gth_tag_new_html (const char *html)
734 {
735 	GthTag *tag;
736 
737 	tag = g_new0 (GthTag, 1);
738 	tag->type = GTH_TAG_HTML;
739 	tag->value.html = g_strdup (html);
740 
741 	return tag;
742 }
743 
744 
745 GthTag *
gth_tag_new_condition(GList * cond_list)746 gth_tag_new_condition (GList *cond_list)
747 {
748 	GthTag *tag;
749 
750 	tag = g_new0 (GthTag, 1);
751 	tag->type = GTH_TAG_IF;
752 	tag->value.cond_list = cond_list;
753 
754 	return tag;
755 }
756 
757 
758 GthTag *
gth_tag_new_loop(GthLoop * loop)759 gth_tag_new_loop (GthLoop *loop)
760 {
761 	GthTag *tag;
762 
763 	tag = g_new0 (GthTag, 1);
764 	tag->type = loop->type;
765 	if (loop->type == GTH_TAG_FOR_EACH_IN_RANGE)
766 		tag->value.range_loop = (GthRangeLoop *) loop;
767 	else
768 		tag->value.loop = loop;
769 
770 	return tag;
771 }
772 
773 
774 void
gth_tag_add_document(GthTag * tag,GList * document)775 gth_tag_add_document (GthTag *tag,
776 		      GList  *document)
777 {
778 	if (tag->document != NULL)
779 		gth_parsed_doc_free (tag->document);
780 	tag->document = document;
781 }
782 
783 
784 void
gth_tag_free(GthTag * tag)785 gth_tag_free (GthTag *tag)
786 {
787 	if (tag->type == GTH_TAG_HTML) {
788 		g_free (tag->value.html);
789 	}
790 	else if (tag->type == GTH_TAG_IF) {
791 		g_list_foreach (tag->value.cond_list,
792 				(GFunc) gth_condition_free,
793 				NULL);
794 		g_list_free (tag->value.cond_list);
795 	}
796 	else if ((tag->type == GTH_TAG_FOR_EACH_THUMBNAIL_CAPTION)
797 		 || (tag->type == GTH_TAG_FOR_EACH_IMAGE_CAPTION))
798 	{
799 		gth_loop_free (tag->value.loop);
800 	}
801 	else if (tag->type == GTH_TAG_FOR_EACH_IN_RANGE) {
802 		gth_range_loop_free (GTH_RANGE_LOOP (tag->value.range_loop));
803 	}
804 	else {
805 		g_list_foreach (tag->value.attributes,
806 				(GFunc) gth_attribute_free,
807 				NULL);
808 		g_list_free (tag->value.attributes);
809 	}
810 
811 	if (tag->document != NULL)
812 		gth_parsed_doc_free (tag->document);
813 
814 	g_free (tag);
815 }
816 
817 
818 GthTagType
gth_tag_get_type_from_name(const char * tag_name)819 gth_tag_get_type_from_name (const char *tag_name)
820 {
821 	if (tag_name == NULL)
822 		return GTH_TAG_INVALID;
823 
824 	if (g_str_equal (tag_name, "header"))
825 		return GTH_TAG_HEADER;
826 	else if (g_str_equal (tag_name, "footer"))
827 		return GTH_TAG_FOOTER;
828 	else if (g_str_equal (tag_name, "language"))
829 		return GTH_TAG_LANGUAGE;
830 	else if (g_str_equal (tag_name, "theme_link"))
831 		return GTH_TAG_THEME_LINK;
832 	else if (g_str_equal (tag_name, "image"))
833 		return GTH_TAG_IMAGE;
834 	else if (g_str_equal (tag_name, "image_link"))
835 		return GTH_TAG_IMAGE_LINK;
836 	else if (g_str_equal (tag_name, "image_idx"))
837 		return GTH_TAG_IMAGE_IDX;
838 	else if (g_str_equal (tag_name, "image_dim"))
839 		return GTH_TAG_IMAGE_DIM;
840 	else if (g_str_equal (tag_name, "image_attribute"))
841 		return GTH_TAG_IMAGE_ATTRIBUTE;
842 	else if (g_str_equal (tag_name, "images"))
843 		return GTH_TAG_IMAGES;
844 	else if (g_str_equal (tag_name, "file_name"))
845 		return GTH_TAG_FILE_NAME;
846 	else if (g_str_equal (tag_name, "file_path"))
847 		return GTH_TAG_FILE_PATH;
848 	else if (g_str_equal (tag_name, "file_size"))
849 		return GTH_TAG_FILE_SIZE;
850 	else if (g_str_equal (tag_name, "page_link"))
851 		return GTH_TAG_PAGE_LINK;
852 	else if (g_str_equal (tag_name, "page_idx"))
853 		return GTH_TAG_PAGE_IDX;
854 	else if (g_str_equal (tag_name, "page_link"))
855 		return GTH_TAG_PAGE_LINK;
856 	else if (g_str_equal (tag_name, "page_rows"))
857 		return GTH_TAG_PAGE_ROWS;
858 	else if (g_str_equal (tag_name, "page_cols"))
859 		return GTH_TAG_PAGE_COLS;
860 	else if (g_str_equal (tag_name, "pages"))
861 		return GTH_TAG_PAGES;
862 	else if (g_str_equal (tag_name, "thumbnails"))
863 		return GTH_TAG_THUMBNAILS;
864 	else if (g_str_equal (tag_name, "timestamp"))
865 		return GTH_TAG_TIMESTAMP;
866 	else if (g_str_equal (tag_name, "translate"))
867 		return GTH_TAG_TRANSLATE;
868 	else if (g_str_equal (tag_name, "html"))
869 		return GTH_TAG_HTML;
870 	else if (g_str_equal (tag_name, "set_var"))
871 		return GTH_TAG_SET_VAR;
872 	else if (g_str_equal (tag_name, "eval"))
873 		return GTH_TAG_EVAL;
874 	else if (g_str_equal (tag_name, "if"))
875 		return GTH_TAG_IF;
876 	else if (g_str_equal (tag_name, "for_each_thumbnail_caption"))
877 		return GTH_TAG_FOR_EACH_THUMBNAIL_CAPTION;
878 	else if (g_str_equal (tag_name, "for_each_image_caption"))
879 		return GTH_TAG_FOR_EACH_IMAGE_CAPTION;
880 	else if (g_str_equal (tag_name, "for_each_in_range"))
881 		return GTH_TAG_FOR_EACH_IN_RANGE;
882 	else if (g_str_equal (tag_name, "item_attribute"))
883 		return GTH_TAG_ITEM_ATTRIBUTE;
884 
885 	return GTH_TAG_INVALID;
886 }
887 
888 
889 const char *
gth_tag_get_name_from_type(GthTagType tag_type)890 gth_tag_get_name_from_type (GthTagType tag_type)
891 {
892 	static char *tag_name[] = {
893 		"header",
894 		"footer",
895 		"language",
896 		"theme_link",
897 		"image",
898 		"image_link",
899 		"image_idx",
900 		"image_dim",
901 		"images",
902 		"filename",
903 		"filepath",
904 		"filesize",
905 		"page_link",
906 		"page_idx",
907 		"page_rows",
908 		"page_cols",
909 		"pages",
910 		"thumbnails",
911 		"timestamp",
912 		"text",
913 		"html",
914 		"set_var",
915 		"eval",
916 		"if",
917 		"for_each_thumbnail_caption",
918 		"for_each_image_caption",
919 		"for_each_in_range",
920 		"item_attribute"
921 	};
922 
923 	return tag_name[tag_type];
924 }
925 
926 
927 void
gth_parsed_doc_print_tree(GList * document)928 gth_parsed_doc_print_tree (GList *document)
929 {
930 	GList *scan;
931 
932 	for (scan = document; scan; scan = scan->next) {
933 		GthTag *tag = scan->data;
934 
935 		g_print ("<%s>\n", gth_tag_get_name_from_type (tag->type));
936 
937 		if ((tag->type != GTH_TAG_HTML) && (tag->type != GTH_TAG_IF)) {
938 			GList *scan_arg;
939 
940 			for (scan_arg = tag->value.attributes; scan_arg; scan_arg = scan_arg->next) {
941 				GthAttribute *attribute = scan_arg->data;
942 
943 				g_print ("  %s = ", attribute->name);
944 				if (attribute->type == GTH_ATTRIBUTE_STRING)
945 					g_print ("%s\n", attribute->value.string);
946 				else
947 					gth_expr_print (attribute->value.expr);
948 			}
949 		}
950 	}
951 	g_print (".\n\n");
952 }
953 
954 
955 void
gth_parsed_doc_free(GList * document)956 gth_parsed_doc_free (GList *document)
957 {
958 	if (document != NULL) {
959 		g_list_foreach (document, (GFunc) gth_tag_free, NULL);
960 		g_list_free (document);
961 	}
962 }
963