/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* Pix
*
* Copyright (C) 2003, 2010 Free Software Foundation, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include
#include "albumtheme-private.h"
#define MAX_EXPR_SIZE 100
#define MEM_SIZE 1000
GList *yy_parsed_doc = NULL;
GthMem *
gth_mem_new (int size)
{
GthMem *mem;
mem = g_new0 (GthMem, 1);
mem->data = g_new (int, size);
gth_mem_set_empty (mem);
return mem;
}
void
gth_mem_free (GthMem *mem)
{
g_free (mem->data);
g_free (mem);
}
void
gth_mem_set_empty (GthMem *mem)
{
mem->top = 0;
}
gboolean
gth_mem_is_empty (GthMem *mem)
{
return (mem->top == 0);
}
void
gth_mem_push (GthMem *mem,
int val)
{
mem->data[mem->top++] = val;
}
int
gth_mem_pop (GthMem *mem)
{
if (! gth_mem_is_empty (mem)) {
mem->top--;
return mem->data[mem->top];
}
return 0;
}
int
gth_mem_get_pos (GthMem *mem,
int pos)
{
if ((pos <= 0) || (pos > mem->top))
return 0;
return mem->data[pos - 1];
}
int
gth_mem_get (GthMem *mem)
{
return gth_mem_get_pos (mem, mem->top);
}
int
gth_mem_get_top (GthMem *mem)
{
return mem->top;
}
/* GthCell */
GthCell *
gth_cell_new (void)
{
GthCell *cell;
cell = g_new0 (GthCell, 1);
cell->ref = 1;
return cell;
}
GthCell *
gth_cell_ref (GthCell *cell)
{
cell->ref++;
return cell;
}
void
gth_cell_unref (GthCell *cell)
{
if (cell == NULL)
return;
cell->ref--;
if (cell->ref > 0)
return;
if (cell->type == GTH_CELL_TYPE_VAR)
g_free (cell->value.var);
else if (cell->type == GTH_CELL_TYPE_STRING)
g_string_free (cell->value.string, TRUE);
g_free (cell);
}
/* GthExpr */
static int
default_get_var_value_func (GthExpr *expr,
int *index,
const char *var_name,
gpointer data)
{
return 0;
}
GthExpr *
gth_expr_new (void)
{
GthExpr *e;
e = g_new0 (GthExpr, 1);
e->ref = 1;
e->data = g_new0 (GthCell*, MAX_EXPR_SIZE);
gth_expr_set_get_var_value_func (e, default_get_var_value_func, NULL);
return e;
}
GthExpr *
gth_expr_ref (GthExpr *e)
{
e->ref++;
return e;
}
void
gth_expr_unref (GthExpr *e)
{
if (e == NULL)
return;
e->ref--;
if (e->ref == 0) {
int i;
for (i = 0; i < MAX_EXPR_SIZE; i++)
gth_cell_unref (e->data[i]);
g_free (e->data);
g_free (e);
}
}
void
gth_expr_set_empty (GthExpr *e)
{
e->top = 0;
}
gboolean
gth_expr_is_empty (GthExpr *e)
{
return (e->top == 0);
}
void
gth_expr_push_expr (GthExpr *e,
GthExpr *e2)
{
int i;
for (i = 0; i < e2->top; i++) {
gth_cell_unref (e->data[e->top]);
e->data[e->top] = gth_cell_ref (e2->data[i]);
e->top++;
}
}
void
gth_expr_push_op (GthExpr *e,
GthOp op)
{
GthCell *cell;
gth_cell_unref (e->data[e->top]);
cell = gth_cell_new ();
cell->type = GTH_CELL_TYPE_OP;
cell->value.op = op;
e->data[e->top] = cell;
e->top++;
}
void
gth_expr_push_var (GthExpr *e,
const char *name)
{
GthCell *cell;
gth_cell_unref (e->data[e->top]);
cell = gth_cell_new ();
cell->type = GTH_CELL_TYPE_VAR;
cell->value.var = g_strdup (name);
e->data[e->top] = cell;
e->top++;
}
void
gth_expr_push_string (GthExpr *e,
const char *value)
{
GthCell *cell;
gth_cell_unref (e->data[e->top]);
cell = gth_cell_new ();
cell->type = GTH_CELL_TYPE_STRING;
cell->value.string = g_string_new (value);
e->data[e->top] = cell;
e->top++;
}
void
gth_expr_push_integer (GthExpr *e,
int value)
{
GthCell *cell;
gth_cell_unref (e->data[e->top]);
cell = gth_cell_new ();
cell->type = GTH_CELL_TYPE_INTEGER;
cell->value.integer = value;
e->data[e->top] = cell;
e->top++;
}
void
gth_expr_pop (GthExpr *e)
{
if (! gth_expr_is_empty (e))
e->top--;
}
GthCell *
gth_expr_get_pos (GthExpr *e, int pos)
{
if ((pos <= 0) || (pos > e->top))
return NULL;
return e->data[pos - 1];
}
GthCell *
gth_expr_get (GthExpr *e)
{
return gth_expr_get_pos (e, e->top);
}
int
gth_expr_get_top (GthExpr *e)
{
return e->top;
}
void
gth_expr_set_get_var_value_func (GthExpr *e,
GthGetVarValueFunc f,
gpointer data)
{
e->get_var_value_func = f;
e->get_var_value_data = data;
}
static char *op_name[] = {
"ADD",
"SUB",
"MUL",
"DIV",
"NEG",
"NOT",
"AND",
"OR",
"CMP_EQ",
"CMP_NE",
"CMP_LT",
"CMP_GT",
"CMP_LE",
"CMP_GE"
};
void
gth_expr_print (GthExpr *e)
{
int i;
for (i = 1; i <= gth_expr_get_top (e); i++) {
GthCell *cell = gth_expr_get_pos (e, i);
switch (cell->type) {
case GTH_CELL_TYPE_VAR:
/*g_print ("VAR: %s (%d)\n",
cell->value.var,
e->get_var_value_func (e,
&i,
cell->value.var,
e->get_var_value_data));*/
g_print ("(%d) VAR: %s\n", i, cell->value.var);
break;
case GTH_CELL_TYPE_STRING:
g_print ("(%d) STRING: %s\n", i, cell->value.string->str);
break;
case GTH_CELL_TYPE_INTEGER:
printf ("(%d) NUM: %d\n", i, cell->value.integer);
break;
case GTH_CELL_TYPE_OP:
printf ("(%d) OP: %s\n", i, op_name[cell->value.op]);
break;
}
}
}
int
gth_expr_eval (GthExpr *e)
{
GthMem *mem;
int retval = 0;
int i;
mem = gth_mem_new (MEM_SIZE);
for (i = 1; i <= gth_expr_get_top (e); i++) {
GthCell *cell = gth_expr_get_pos (e, i);
int a, b, c;
switch (cell->type) {
case GTH_CELL_TYPE_VAR:
gth_mem_push (mem,
e->get_var_value_func (e,
&i,
cell->value.var,
e->get_var_value_data));
break;
case GTH_CELL_TYPE_STRING:
/* only used as argument for a function */
break;
case GTH_CELL_TYPE_INTEGER:
gth_mem_push (mem, cell->value.integer);
break;
case GTH_CELL_TYPE_OP:
switch (cell->value.op) {
case GTH_OP_NEG:
a = gth_mem_pop (mem);
gth_mem_push (mem, -a);
break;
case GTH_OP_NOT:
a = gth_mem_pop (mem);
gth_mem_push (mem, (a == 0) ? 1 : 0);
break;
case GTH_OP_ADD:
b = gth_mem_pop (mem);
a = gth_mem_pop (mem);
c = a + b;
gth_mem_push (mem, c);
break;
case GTH_OP_SUB:
b = gth_mem_pop (mem);
a = gth_mem_pop (mem);
c = a - b;
gth_mem_push (mem, c);
break;
case GTH_OP_MUL:
b = gth_mem_pop (mem);
a = gth_mem_pop (mem);
c = a * b;
gth_mem_push (mem, c);
break;
case GTH_OP_DIV:
b = gth_mem_pop (mem);
a = gth_mem_pop (mem);
c = a / b;
gth_mem_push (mem, c);
break;
case GTH_OP_AND:
b = gth_mem_pop (mem);
a = gth_mem_pop (mem);
c = (a != 0) && (b != 0);
gth_mem_push (mem, c);
break;
case GTH_OP_OR:
b = gth_mem_pop (mem);
a = gth_mem_pop (mem);
c = (a != 0) || (b != 0);
gth_mem_push (mem, c);
break;
case GTH_OP_CMP_EQ:
b = gth_mem_pop (mem);
a = gth_mem_pop (mem);
c = (a == b);
gth_mem_push (mem, c);
break;
case GTH_OP_CMP_NE:
b = gth_mem_pop (mem);
a = gth_mem_pop (mem);
c = (a != b);
gth_mem_push (mem, c);
break;
case GTH_OP_CMP_LT:
b = gth_mem_pop (mem);
a = gth_mem_pop (mem);
c = (a < b);
gth_mem_push (mem, c);
break;
case GTH_OP_CMP_GT:
b = gth_mem_pop (mem);
a = gth_mem_pop (mem);
c = (a > b);
gth_mem_push (mem, c);
break;
case GTH_OP_CMP_LE:
b = gth_mem_pop (mem);
a = gth_mem_pop (mem);
c = (a <= b);
gth_mem_push (mem, c);
break;
case GTH_OP_CMP_GE:
b = gth_mem_pop (mem);
a = gth_mem_pop (mem);
c = (a >= b);
gth_mem_push (mem, c);
break;
}
break;
}
}
retval = gth_mem_get (mem);
gth_mem_free (mem);
return retval;
}
void
gth_expr_list_unref (GList *list)
{
GList *scan;
for (scan = list; scan; scan = scan->next)
gth_expr_unref ((GthExpr *) scan->data);
g_list_free (list);
}
/* GthAttribute */
GthAttribute *
gth_attribute_new_expression (const char *name,
GthExpr *expr)
{
GthAttribute *attribute;
g_return_val_if_fail (name != NULL, NULL);
attribute = g_new0 (GthAttribute, 1);
attribute->type = GTH_ATTRIBUTE_EXPR;
attribute->name = g_strdup (name);
attribute->value.expr = gth_expr_ref (expr);
return attribute;
}
GthAttribute*
gth_attribute_new_string (const char *name,
const char *string)
{
GthAttribute *attribute;
g_return_val_if_fail (name != NULL, NULL);
attribute = g_new0 (GthAttribute, 1);
attribute->type = GTH_ATTRIBUTE_STRING;
attribute->name = g_strdup (name);
if (string != NULL)
attribute->value.string = g_strdup (string);
return attribute;
}
void
gth_attribute_free (GthAttribute *attribute)
{
g_free (attribute->name);
switch (attribute->type) {
case GTH_ATTRIBUTE_EXPR:
gth_expr_unref (attribute->value.expr);
break;
case GTH_ATTRIBUTE_STRING:
g_free (attribute->value.string);
break;
}
g_free (attribute);
}
/* GthCondition */
GthCondition *
gth_condition_new (GthExpr *expr)
{
GthCondition *cond;
cond = g_new0 (GthCondition, 1);
cond->expr = gth_expr_ref (expr);
return cond;
}
void
gth_condition_free (GthCondition *cond)
{
if (cond == NULL)
return;
gth_expr_unref (cond->expr);
gth_parsed_doc_free (cond->document);
g_free (cond);
}
void
gth_condition_add_document (GthCondition *cond,
GList *document)
{
if (cond->document != NULL)
gth_parsed_doc_free (cond->document);
cond->document = document;
}
/* GthLoop */
GthLoop *
gth_loop_new (GthTagType loop_type)
{
GthLoop *loop;
loop = g_new0 (GthLoop, 1);
loop->type = loop_type;
return loop;
}
void
gth_loop_free (GthLoop *loop)
{
if (loop == NULL)
return;
gth_parsed_doc_free (loop->document);
g_free (loop);
}
GthTagType
gth_loop_get_type (GthLoop *loop)
{
return loop->type;
}
void
gth_loop_add_document (GthLoop *loop,
GList *document)
{
if (loop->document != NULL)
gth_parsed_doc_free (loop->document);
loop->document = document;
}
/* GthRangeLoop */
GthLoop *
gth_range_loop_new (void)
{
GthLoop *loop;
loop = (GthLoop *) g_new0 (GthRangeLoop, 1);
loop->type = GTH_TAG_FOR_EACH_IN_RANGE;
return loop;
}
void
gth_range_loop_free (GthRangeLoop *loop)
{
g_free (loop->iterator);
gth_expr_unref (loop->first_value);
gth_expr_unref (loop->last_value);
gth_loop_free (GTH_LOOP (loop));
}
void
gth_range_loop_set_range (GthRangeLoop *loop,
const char *iterator,
GthExpr *first_value,
GthExpr *last_value)
{
loop->iterator = g_strdup (iterator);
loop->first_value = gth_expr_ref (first_value);
loop->last_value = gth_expr_ref (last_value);
}
/* GthTag */
GthTag *
gth_tag_new (GthTagType type,
GList *attributes)
{
GthTag *tag;
tag = g_new0 (GthTag, 1);
tag->type = type;
tag->value.attributes = attributes;
return tag;
}
GthTag *
gth_tag_new_html (const char *html)
{
GthTag *tag;
tag = g_new0 (GthTag, 1);
tag->type = GTH_TAG_HTML;
tag->value.html = g_strdup (html);
return tag;
}
GthTag *
gth_tag_new_condition (GList *cond_list)
{
GthTag *tag;
tag = g_new0 (GthTag, 1);
tag->type = GTH_TAG_IF;
tag->value.cond_list = cond_list;
return tag;
}
GthTag *
gth_tag_new_loop (GthLoop *loop)
{
GthTag *tag;
tag = g_new0 (GthTag, 1);
tag->type = loop->type;
if (loop->type == GTH_TAG_FOR_EACH_IN_RANGE)
tag->value.range_loop = (GthRangeLoop *) loop;
else
tag->value.loop = loop;
return tag;
}
void
gth_tag_add_document (GthTag *tag,
GList *document)
{
if (tag->document != NULL)
gth_parsed_doc_free (tag->document);
tag->document = document;
}
void
gth_tag_free (GthTag *tag)
{
if (tag->type == GTH_TAG_HTML) {
g_free (tag->value.html);
}
else if (tag->type == GTH_TAG_IF) {
g_list_foreach (tag->value.cond_list,
(GFunc) gth_condition_free,
NULL);
g_list_free (tag->value.cond_list);
}
else if ((tag->type == GTH_TAG_FOR_EACH_THUMBNAIL_CAPTION)
|| (tag->type == GTH_TAG_FOR_EACH_IMAGE_CAPTION))
{
gth_loop_free (tag->value.loop);
}
else if (tag->type == GTH_TAG_FOR_EACH_IN_RANGE) {
gth_range_loop_free (GTH_RANGE_LOOP (tag->value.range_loop));
}
else {
g_list_foreach (tag->value.attributes,
(GFunc) gth_attribute_free,
NULL);
g_list_free (tag->value.attributes);
}
if (tag->document != NULL)
gth_parsed_doc_free (tag->document);
g_free (tag);
}
GthTagType
gth_tag_get_type_from_name (const char *tag_name)
{
if (tag_name == NULL)
return GTH_TAG_INVALID;
if (g_str_equal (tag_name, "header"))
return GTH_TAG_HEADER;
else if (g_str_equal (tag_name, "footer"))
return GTH_TAG_FOOTER;
else if (g_str_equal (tag_name, "language"))
return GTH_TAG_LANGUAGE;
else if (g_str_equal (tag_name, "theme_link"))
return GTH_TAG_THEME_LINK;
else if (g_str_equal (tag_name, "image"))
return GTH_TAG_IMAGE;
else if (g_str_equal (tag_name, "image_link"))
return GTH_TAG_IMAGE_LINK;
else if (g_str_equal (tag_name, "image_idx"))
return GTH_TAG_IMAGE_IDX;
else if (g_str_equal (tag_name, "image_dim"))
return GTH_TAG_IMAGE_DIM;
else if (g_str_equal (tag_name, "image_attribute"))
return GTH_TAG_IMAGE_ATTRIBUTE;
else if (g_str_equal (tag_name, "images"))
return GTH_TAG_IMAGES;
else if (g_str_equal (tag_name, "file_name"))
return GTH_TAG_FILE_NAME;
else if (g_str_equal (tag_name, "file_path"))
return GTH_TAG_FILE_PATH;
else if (g_str_equal (tag_name, "file_size"))
return GTH_TAG_FILE_SIZE;
else if (g_str_equal (tag_name, "page_link"))
return GTH_TAG_PAGE_LINK;
else if (g_str_equal (tag_name, "page_idx"))
return GTH_TAG_PAGE_IDX;
else if (g_str_equal (tag_name, "page_link"))
return GTH_TAG_PAGE_LINK;
else if (g_str_equal (tag_name, "page_rows"))
return GTH_TAG_PAGE_ROWS;
else if (g_str_equal (tag_name, "page_cols"))
return GTH_TAG_PAGE_COLS;
else if (g_str_equal (tag_name, "pages"))
return GTH_TAG_PAGES;
else if (g_str_equal (tag_name, "thumbnails"))
return GTH_TAG_THUMBNAILS;
else if (g_str_equal (tag_name, "timestamp"))
return GTH_TAG_TIMESTAMP;
else if (g_str_equal (tag_name, "translate"))
return GTH_TAG_TRANSLATE;
else if (g_str_equal (tag_name, "html"))
return GTH_TAG_HTML;
else if (g_str_equal (tag_name, "set_var"))
return GTH_TAG_SET_VAR;
else if (g_str_equal (tag_name, "eval"))
return GTH_TAG_EVAL;
else if (g_str_equal (tag_name, "if"))
return GTH_TAG_IF;
else if (g_str_equal (tag_name, "for_each_thumbnail_caption"))
return GTH_TAG_FOR_EACH_THUMBNAIL_CAPTION;
else if (g_str_equal (tag_name, "for_each_image_caption"))
return GTH_TAG_FOR_EACH_IMAGE_CAPTION;
else if (g_str_equal (tag_name, "for_each_in_range"))
return GTH_TAG_FOR_EACH_IN_RANGE;
else if (g_str_equal (tag_name, "item_attribute"))
return GTH_TAG_ITEM_ATTRIBUTE;
return GTH_TAG_INVALID;
}
const char *
gth_tag_get_name_from_type (GthTagType tag_type)
{
static char *tag_name[] = {
"header",
"footer",
"language",
"theme_link",
"image",
"image_link",
"image_idx",
"image_dim",
"images",
"filename",
"filepath",
"filesize",
"page_link",
"page_idx",
"page_rows",
"page_cols",
"pages",
"thumbnails",
"timestamp",
"text",
"html",
"set_var",
"eval",
"if",
"for_each_thumbnail_caption",
"for_each_image_caption",
"for_each_in_range",
"item_attribute"
};
return tag_name[tag_type];
}
void
gth_parsed_doc_print_tree (GList *document)
{
GList *scan;
for (scan = document; scan; scan = scan->next) {
GthTag *tag = scan->data;
g_print ("<%s>\n", gth_tag_get_name_from_type (tag->type));
if ((tag->type != GTH_TAG_HTML) && (tag->type != GTH_TAG_IF)) {
GList *scan_arg;
for (scan_arg = tag->value.attributes; scan_arg; scan_arg = scan_arg->next) {
GthAttribute *attribute = scan_arg->data;
g_print (" %s = ", attribute->name);
if (attribute->type == GTH_ATTRIBUTE_STRING)
g_print ("%s\n", attribute->value.string);
else
gth_expr_print (attribute->value.expr);
}
}
}
g_print (".\n\n");
}
void
gth_parsed_doc_free (GList *document)
{
if (document != NULL) {
g_list_foreach (document, (GFunc) gth_tag_free, NULL);
g_list_free (document);
}
}