grim/gplate

some more testing migration stuff.

2012-09-04, Gary Kramlich
7f8e0e4f250f
some more testing migration stuff.
Variables aren't done yet
/*
* GPlate - GObject based templating library
* Copyright (C) 2007-2012 Gary Kramlich <grim@reaperworld.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <gplate/gplate-template.h>
#include <gplate/gplate-collection.h>
#include <gplate/gplate-errors.h>
#include <gplate/gplate-library.h>
#include <gplate/gplate-util.h>
#include <gplate/variables/gplate-dictionary-variable.h>
#include <stdio.h>
#include <string.h>
#define GPLATE_TEMPLATE_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE((obj), GPLATE_TYPE_TEMPLATE, GPlateTemplatePrivate))
/******************************************************************************
* Enums
*****************************************************************************/
enum {
PROP_ZERO,
PROP_WD,
PROP_LAST
};
/******************************************************************************
* Structs
*****************************************************************************/
typedef struct {
GPlateVariable *vars;
gchar *wd;
GList *tokens;
GList *current_token;
} GPlateTemplatePrivate;
typedef struct {
GType type;
gchar *contents;
} GPlateTemplateTagData;
/******************************************************************************
* Globals
*****************************************************************************/
static GObjectClass *parent_class = NULL;
/******************************************************************************
* Collection Stuff
*****************************************************************************/
static GPlateVariable *
gplate_template_find_variable(const GPlateCollection *collection,
const gchar *name)
{
GPlateTemplatePrivate *priv = GPLATE_TEMPLATE_GET_PRIVATE(collection);
return gplate_collection_find_variable(GPLATE_COLLECTION(priv->vars),
name);
}
static gboolean
gplate_template_add_variable_with_name(GPlateCollection *collection,
const gchar *name,
GPlateVariable *variable)
{
GPlateTemplatePrivate *priv = GPLATE_TEMPLATE_GET_PRIVATE(collection);
GPlateCollection *c2 = NULL;
c2 = GPLATE_COLLECTION(priv->vars);
return gplate_collection_add_variable_with_name(c2, name, variable);
}
static gboolean
gplate_template_remove_variable(GPlateCollection *collection,
GPlateVariable *variable)
{
GPlateTemplatePrivate *priv = GPLATE_TEMPLATE_GET_PRIVATE(collection);
return gplate_collection_remove_variable(GPLATE_COLLECTION(priv->vars),
variable);
}
static void
gplate_template_collection_init(GPlateCollectionIface *iface) {
iface->find_variable = gplate_template_find_variable;
iface->add_variable_with_name = gplate_template_add_variable_with_name;
iface->remove_variable = gplate_template_remove_variable;
}
/******************************************************************************
* Template Stuff
*****************************************************************************/
static void
gplate_template_update_pattern_helper(GType tag, const gchar *prefix,
const gchar *suffix, gpointer d)
{
GString *str = (GString *)d;
const gchar *sep = "";
/* don't add fall through tags to the regex */
if(!prefix || !suffix)
return;
if(str->len > 1)
sep = "|";
g_string_append_printf(str, "%s%s.*?%s", sep, prefix, suffix);
}
static gchar *
gplate_template_update_pattern(GPlateTemplate *tplate) {
GString *str = g_string_new("(");
gchar *ret = NULL;
gplate_library_tags_foreach(gplate_template_update_pattern_helper, str);
g_string_append_printf(str, "%s", ")");
ret = str->str;
g_string_free(str, FALSE);
return ret;
}
static void
gplate_template_find_tag_helper(GType tag, const gchar *prefix,
const gchar *suffix, gpointer d)
{
GPlateTemplateTagData *data = (GPlateTemplateTagData *)d;
gchar *pattern = NULL;
/* if our tag info doesn't have a prefix or a suffix, we drop out. */
if(!prefix || !suffix)
return;
/* create our pattern string */
pattern = g_strdup_printf("%s.*?%s", prefix, suffix);
/* look for a match:
*
* G_REGEX_DOTALL is REQUIRED so that newlines get counted.
*
* ie: {{\nfoo\n}} would be treated as a fall through if not for it.
*/
if(g_regex_match_simple(pattern, data->contents, G_REGEX_DOTALL, 0))
data->type = tag;
/* cleanup */
g_free(pattern);
}
static GType
gplate_template_find_tag(GPlateTemplate *tplate, gchar *contents) {
GPlateTemplateTagData d;
d.contents = contents;
d.type = G_TYPE_INVALID;
gplate_library_tags_foreach(gplate_template_find_tag_helper, &d);
if(d.type == G_TYPE_INVALID)
d.type = gplate_library_get_default_tag();
return d.type;
}
static GList *
gplate_template_real_tokenize(GPlateTemplate *tplate, const gchar *tplate_string,
GError **error)
{
GList *ret = NULL;
GRegex *regex1 = NULL;
gchar **matches = NULL;
gchar *pattern = NULL;
gint i = 0;
pattern = gplate_template_update_pattern(tplate);
regex1 = g_regex_new(pattern, G_REGEX_OPTIMIZE, 0, error);
if(!regex1) {
g_free(pattern);
return NULL;
}
g_free(pattern);
matches = g_regex_split(regex1, tplate_string, 0);
for(i = 0; matches[i]; i++) {
GPlateTag *tag = NULL;
GType type = G_TYPE_INVALID;
gchar *prefix = NULL, *suffix = NULL;
if(g_utf8_strlen(matches[i], -1) <= 0)
continue;
type = gplate_template_find_tag(tplate, matches[i]);
if(!gplate_library_lookup_tag(type, &prefix, &suffix, error))
continue;
if(!prefix && !suffix) {
/* it's a fall through tag */
tag = g_object_new(type,
"contents", matches[i],
NULL);
} else {
/* it's a normal tag, strip it's prefix and suffix */
GRegex *regex2 = NULL;
GMatchInfo *match = NULL;
gchar *pattern = NULL, *contents = NULL;
pattern = g_strdup_printf("%s(.*?)%s", prefix, suffix);
regex2 = g_regex_new(pattern,
G_REGEX_OPTIMIZE | G_REGEX_DOTALL,
0, error);
g_free(pattern);
if(!regex2) {
GList *l = NULL;
for(l = ret; l; l = l->next)
g_object_unref(G_OBJECT(l->data));
g_list_free(ret);
return NULL;
}
/* get our match info */
if(!g_regex_match(regex2, matches[i], 0, &match)) {
GList *l = NULL;
g_match_info_free(match);
for(l = ret; l; l = l->next)
g_object_unref(G_OBJECT(l->data));
g_list_free(ret);
return NULL;
}
contents = g_match_info_fetch(match, 1);
g_strstrip(contents);
g_match_info_free(match);
tag = g_object_new(type,
"contents", contents,
"template", tplate,
NULL);
g_free(contents);
}
ret = g_list_prepend(ret, tag);
}
g_strfreev(matches);
g_regex_unref(regex1);
ret = g_list_reverse(ret);
return ret;
}
static GPlateTag *
gplate_template_real_first_tag(GPlateTemplate *tplate) {
GPlateTemplatePrivate *priv = GPLATE_TEMPLATE_GET_PRIVATE(tplate);
GPlateTag *tag = NULL;
priv->current_token = priv->tokens;
if(priv->current_token && GPLATE_IS_TAG(priv->current_token->data))
tag = GPLATE_TAG(priv->current_token->data);
return tag;
}
static GPlateTag *
gplate_template_real_last_tag(GPlateTemplate *tplate) {
GPlateTemplatePrivate *priv = GPLATE_TEMPLATE_GET_PRIVATE(tplate);
GPlateTag *tag = NULL;
priv->current_token = g_list_last(priv->tokens);
if(priv->current_token && GPLATE_IS_TAG(priv->current_token->data))
tag = GPLATE_TAG(priv->current_token->data);
return tag;
}
static GPlateTag *
gplate_template_real_current_tag(GPlateTemplate *tplate) {
GPlateTemplatePrivate *priv = GPLATE_TEMPLATE_GET_PRIVATE(tplate);
GPlateTag *tag = NULL;
if(priv->current_token && GPLATE_IS_TAG(priv->current_token->data))
tag = GPLATE_TAG(priv->current_token->data);
return tag;
}
static GPlateTag *
gplate_template_real_next_tag(GPlateTemplate *tplate) {
GPlateTemplatePrivate *priv = GPLATE_TEMPLATE_GET_PRIVATE(tplate);
GPlateTag *tag = NULL;
priv->current_token = g_list_next(priv->current_token);
if(priv->current_token && GPLATE_IS_TAG(priv->current_token->data))
tag = GPLATE_TAG(priv->current_token->data);
return tag;
}
static GPlateTag *
gplate_template_real_previous_tag(GPlateTemplate *tplate) {
GPlateTemplatePrivate *priv = GPLATE_TEMPLATE_GET_PRIVATE(tplate);
GPlateTag *tag = NULL;
priv->current_token = g_list_previous(priv->current_token);
if(priv->current_token && GPLATE_IS_TAG(priv->current_token->data))
tag = GPLATE_TAG(priv->current_token->data);
return tag;
}
static GPlateTag *
gplate_template_real_nth_tag(GPlateTemplate *tplate, guint nth) {
GPlateTemplatePrivate *priv = GPLATE_TEMPLATE_GET_PRIVATE(tplate);
GPlateTag *tag = NULL;
priv->current_token = g_list_nth(priv->current_token, nth);
if(priv->current_token && GPLATE_IS_TAG(priv->current_token->data))
tag = GPLATE_TAG(priv->current_token->data);
return tag;
}
static GPlateTag *
gplate_template_real_nth_previous_tag(GPlateTemplate *tplate, guint nth) {
GPlateTemplatePrivate *priv = GPLATE_TEMPLATE_GET_PRIVATE(tplate);
GPlateTag *tag = NULL;
priv->current_token = g_list_nth_prev(priv->current_token, nth);
if(priv->current_token && GPLATE_IS_TAG(priv->current_token->data))
tag = GPLATE_TAG(priv->current_token->data);
return tag;
}
static void
gplate_template_real_insert_tags(GPlateTemplate *tplate, GList *tags) {
GPlateTemplatePrivate *priv = GPLATE_TEMPLATE_GET_PRIVATE(tplate);
/* check if our current node is valid */
if(!priv->current_token) {
/* check if we have a list of tokens */
if(!priv->tokens) {
/* no existing tokens, set it to tags and exit */
priv->tokens = tags;
} else {
/* we have tokens, but we've read the last one, move back to the
* last one.
*/
priv->tokens = g_list_concat(priv->tokens, tags);
}
} else {
GList *tmp = NULL;
/* we have a valid node selected, save it's next node */
tmp = priv->current_token->next;
/* now mangle current and the first node in tags to shove tags in */
priv->current_token->next = tags;
tags->prev = priv->current_token;
/* if the original next node is valid, we need to put them back into
* place
*/
if(tmp) {
GList *last = g_list_last(tags);
last->next = tmp;
tmp->prev = last;
}
}
}
/******************************************************************************
* Object Stuff
*****************************************************************************/
static void
gplate_template_get_property(GObject *obj, guint param_id, GValue *value,
GParamSpec *pspec)
{
GPlateTemplate *tplate = GPLATE_TEMPLATE(obj);
switch(param_id) {
case PROP_WD:
g_value_set_string(value,
gplate_template_get_working_directory(tplate));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
break;
}
}
static void
gplate_template_set_property(GObject *obj, guint param_id, const GValue *value,
GParamSpec *pspec)
{
GPlateTemplate *tplate = GPLATE_TEMPLATE(obj);
switch(param_id) {
case PROP_WD:
gplate_template_set_working_directory(tplate,
g_value_get_string(value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
break;
}
}
static void
gplate_template_finalize(GObject *obj) {
GPlateTemplatePrivate *priv = GPLATE_TEMPLATE_GET_PRIVATE(obj);
GList *l = NULL;
g_object_unref(priv->vars);
for(l = priv->tokens; l; l = l->next)
g_object_unref(G_OBJECT(l->data));
g_list_free(priv->tokens);
G_OBJECT_CLASS(parent_class)->finalize(obj);
}
static void
gplate_template_class_init(GPlateTemplateClass *klass) {
GObjectClass *obj_class = G_OBJECT_CLASS(klass);
GParamSpec *pspec = NULL;
parent_class = g_type_class_peek_parent(klass);
g_type_class_add_private(klass, sizeof(GPlateTemplatePrivate));
obj_class->get_property = gplate_template_get_property;
obj_class->set_property = gplate_template_set_property;
obj_class->finalize = gplate_template_finalize;
klass->tokenize = gplate_template_real_tokenize;
klass->first_tag = gplate_template_real_first_tag;
klass->last_tag = gplate_template_real_last_tag;
klass->current_tag = gplate_template_real_current_tag;
klass->next_tag = gplate_template_real_next_tag;
klass->previous_tag = gplate_template_real_previous_tag;
klass->nth_tag = gplate_template_real_nth_tag;
klass->nth_previous_tag = gplate_template_real_nth_previous_tag;
klass->insert_tags = gplate_template_real_insert_tags;
pspec = g_param_spec_string("working-directory", "working directory",
"The working directory for the template",
NULL, G_PARAM_READWRITE);
g_object_class_install_property(obj_class, PROP_WD, pspec);
}
static void
gplate_template_init(GTypeInstance *self, gpointer klass) {
GPlateTemplatePrivate *priv = GPLATE_TEMPLATE_GET_PRIVATE(self);
priv->vars = gplate_dictionary_variable_new("dict");
}
/******************************************************************************
* Render helpers
*****************************************************************************/
static inline GPlateFunction *
gplate_template_render_find_function(const gchar *name, GType tag,
gboolean *deffunc, GError **error)
{
GPlateFunction *ret = NULL;
GType function = G_TYPE_INVALID;
gboolean def = FALSE;
function = gplate_library_lookup_function_for_tag(name, tag, NULL);
if(function == G_TYPE_INVALID) {
function = gplate_library_get_default_function_for_tag(tag, NULL);
def = TRUE;
}
if(function != G_TYPE_INVALID) {
ret = g_object_new(function, NULL);
if(deffunc)
*deffunc = def;
}
return ret;
}
/******************************************************************************
* GPlateTemplate API
*****************************************************************************/
GType
gplate_template_get_gtype(void) {
static GType type = 0;
if(type == 0) {
static const GTypeInfo info = {
sizeof(GPlateTemplateClass),
NULL,
NULL,
(GClassInitFunc)gplate_template_class_init,
NULL,
NULL,
sizeof(GPlateTemplate),
0,
gplate_template_init,
};
static const GInterfaceInfo collection_info = {
(GInterfaceInitFunc)gplate_template_collection_init,
NULL,
NULL,
};
type = g_type_register_static(G_TYPE_OBJECT,
"GPlateTemplate",
&info, 0);
g_type_add_interface_static(type, GPLATE_TYPE_COLLECTION,
&collection_info);
}
return type;
}
/**
* gplate_template_new:
*
* Creates a new #GPlateTemplate instance.
*
* Return Value: The new #GPlateTemplate instance.
*/
GPlateTemplate *
gplate_template_new(void) {
return g_object_new(GPLATE_TYPE_TEMPLATE, NULL);
}
/**
* gplate_template_tokenize:
* @tplate: The #GPlateTemplate.
* @tplate_string: The string to be translated.
* @error: The return address for any errors.
*
* Tokenizes @tplate_string into a #GList of #GPlateTag's to be later passed to
* #gplate_template_render.
*
* Normally this is called by #gplate_template_render directly, but there are a
* few corner cases where you may want to call this directly.
*
* Return Value: A #GList of #GPlateTags.
*/
GList *
gplate_template_tokenize(GPlateTemplate *tplate, const gchar *tplate_string,
GError **error)
{
GPlateTemplateClass *klass = NULL;
g_return_val_if_fail(GPLATE_IS_TEMPLATE(tplate), NULL);
g_return_val_if_fail(tplate_string, NULL);
klass = GPLATE_TEMPLATE_GET_CLASS(tplate);
if(klass && klass->tokenize)
return klass->tokenize(tplate, tplate_string, error);
return NULL;
}
/**
* gplate_template_render:
* @tplate: The #GPlateTemplate.
* @tplate_string: The template string to render.
* @error: Return address for errors.
*
* Renders @tplate_string using @tplate.
*
* Return Value: The rendered output.
*/
gchar *
gplate_template_render(GPlateTemplate *tplate, const gchar *tplate_string,
GError **error)
{
GPlateTemplatePrivate *priv = NULL;
GPlateTag *tag = NULL;
GString *str = NULL;
gchar *ret = NULL;
g_return_val_if_fail(GPLATE_IS_TEMPLATE(tplate), NULL);
g_return_val_if_fail(tplate_string, NULL);
priv = GPLATE_TEMPLATE_GET_PRIVATE(tplate);
priv->tokens = gplate_template_tokenize(tplate, tplate_string, error);
if(!priv->tokens)
return g_strdup("");
/* for whatever reason, using g_string_new_len here doesn't work */
str = g_string_new("");
for(tag = gplate_template_first_tag(tplate);
tag;
tag = gplate_template_next_tag(tplate))
{
gchar *output = gplate_template_render_tag(tplate, tag);
g_string_append_printf(str, "%s", output);
g_free(output);
}
ret = str->str;
g_string_free(str, FALSE);
return ret;
}
/**
* gplate_template_render_file:
* @tplate: The #GPlateTemplate.
* @filename: The file name to render.
* @error: Return address for errors.
*
* Renders @filename using #GPlateTemplate @tplate.
*
* Return Value: The rendered output.
*/
gchar *
gplate_template_render_file(GPlateTemplate *tplate, const gchar *filename,
GError **error)
{
gchar *contents = NULL, *ret = NULL;
g_return_val_if_fail(GPLATE_IS_TEMPLATE(tplate), NULL);
g_return_val_if_fail(filename, NULL);
if(!gplate_template_get_working_directory(tplate)) {
gchar *dirname = g_path_get_dirname(filename);
gplate_template_set_working_directory(tplate, dirname);
g_free(dirname);
}
if(!gplate_util_read_file(filename, &contents, NULL, error))
return FALSE;
ret = gplate_template_render(tplate, contents, error);
g_free(contents);
return ret;
}
/**
* gplate_template_render_until:
* @tplate: The #GPlateTemplate
* @ntags: A return address for the number of tags that were rendered
* @Varargs: A NULL terminated list of #GType, content pairs.
*
* Renders the tags in a template from the current point until it a tag is
* found that is the correct type and has the same contents as one of the
* #GType, content pairs.
*
* Returns: The rendered output.
*/
gchar *
gplate_template_render_until(GPlateTemplate *tplate, guint *ntags, ...) {
GPlateTag *tag = NULL;
GList *l = NULL;
GString *str = NULL;
GQueue *queue = NULL;
GType type = G_TYPE_INVALID;
gchar *ret = NULL;
guint count = 0;
gboolean backup = FALSE;
va_list args;
g_return_val_if_fail(GPLATE_IS_TEMPLATE(tplate), NULL);
str = g_string_new("");
queue = g_queue_new();
/* store all of the content/tag pairs */
va_start(args, ntags);
while((type = va_arg(args, gsize)) != G_TYPE_INVALID) {
GPlateTemplateTagData *td = NULL;
gchar *contents = NULL;
td = g_new(GPlateTemplateTagData, 1);
contents = va_arg(args, gchar *);
td->contents = contents ? g_strdup(contents) : NULL;
td->type = type;
g_queue_push_tail(queue, td);
}
va_end(args);
/* now iterate the tags */
while((tag = gplate_template_next_tag(tplate))) {
GPlateTemplateTagData ctd;
gboolean stop = FALSE;
ctd.contents = gplate_tag_get_contents(tag);
ctd.type = G_OBJECT_TYPE(tag);
/* run through our list of TagData's to stop on */
for(l = queue->head; l; l = l->next) {
GPlateTemplateTagData *td = (GPlateTemplateTagData *)l->data;
if(ctd.type == td->type &&
g_utf8_collate(ctd.contents, td->contents) == 0)
{
stop = TRUE;
backup = TRUE;
}
}
g_free(ctd.contents);
if(stop) {
count++;
break;
}
g_string_append_printf(str, "%s",
gplate_template_render_tag(tplate, tag));
count++;
}
/* now clean everything up... */
for(l = queue->head; l; l = l->next) {
GPlateTemplateTagData *td = (GPlateTemplateTagData *)l->data;
g_free(td->contents);
g_free(td);
}
g_queue_free(queue);
ret = str->str;
g_string_free(str, FALSE);
/* if backup is set, we back up to the tag which caused us to stop. In
* other words, the tag stack will currently be at the tag after the one
* we stopped at, but we want to be on the one that we stopped on.
*/
if(backup) {
gplate_template_previous_tag(tplate);
count--;
}
if(ntags)
*ntags = count;
return ret;
}
/**
* gplate_template_jump_to:
* @tplate: The #GPlateTemplate
* @ntags: A return address for the number of tags that were rendered
* @Varargs: A NULL terminated list of #GType, content pairs.
*
* Skips all tags, until one is found that is the correct type and has the same
* contents as one of the #Gtype, content pairs.
*
* The current tag will be the one jumped to.
*/
void
gplate_template_jump_to(GPlateTemplate *tplate, guint *ntags, ...) {
GPlateTag *tag = NULL;
GList *l = NULL;
GQueue *queue = NULL;
GType type = G_TYPE_INVALID;
gboolean backup = FALSE;
guint count = 0;
va_list args;
g_return_if_fail(GPLATE_IS_TEMPLATE(tplate));
queue = g_queue_new();
/* store all of the content/tag pairs */
va_start(args, ntags);
while((type = va_arg(args, gsize)) != G_TYPE_INVALID) {
GPlateTemplateTagData *td = NULL;
const gchar *contents = NULL;
td = g_new(GPlateTemplateTagData, 1);
contents = va_arg(args, gchar *);
td->contents = contents ? g_strdup(contents) : NULL;
td->type = type;
g_queue_push_tail(queue, td);
}
va_end(args);
/* iterate the tags */
while((tag = gplate_template_next_tag(tplate))) {
GPlateTemplateTagData ctd;
gboolean stop = FALSE;
ctd.contents = gplate_tag_get_contents(tag);
ctd.type = G_OBJECT_TYPE(tag);
for(l = queue->head; l; l = l->next) {
GPlateTemplateTagData *td = (GPlateTemplateTagData *)l->data;
if(ctd.type == td->type &&
g_utf8_collate(ctd.contents, td->contents) == 0)
{
stop = TRUE;
backup = TRUE;
}
}
g_free(ctd.contents);
if(stop) {
count++;
break;
}
count++;
}
/* cleanup */
for(l = queue->head; l; l = l->next) {
GPlateTemplateTagData *td = l->data;
g_free(td->contents);
g_free(td);
}
g_queue_free(queue);
if(backup) {
gplate_template_previous_tag(tplate);
count--;
}
if(ntags)
*ntags = count;
}
/**
* gplate_template_first_tag:
* @tplate: The #GPlateTemplate.
*
* Moves the tag stack to the first tag and returns it.
*
* Return Value: The first tag or NULL.
*/
GPlateTag *
gplate_template_first_tag(GPlateTemplate *tplate) {
GPlateTemplateClass *klass = NULL;
g_return_val_if_fail(GPLATE_IS_TEMPLATE(tplate), NULL);
klass = GPLATE_TEMPLATE_GET_CLASS(tplate);
if(klass && klass->first_tag)
return klass->first_tag(tplate);
return NULL;
}
/**
* gplate_template_last_tag:
* @tplate: The #GPlateTemplate.
*
* Moves the tag stack to the last tag and returns it.
*
* Return Value: The last tag or NULL.
*/
GPlateTag *
gplate_template_last_tag(GPlateTemplate *tplate) {
GPlateTemplateClass *klass = NULL;
g_return_val_if_fail(GPLATE_IS_TEMPLATE(tplate), NULL);
klass = GPLATE_TEMPLATE_GET_CLASS(tplate);
if(klass && klass->last_tag)
return klass->last_tag(tplate);
return NULL;
}
/**
* gplate_template_current_tag:
* @tplate: The #GPlateTemplate.
*
* Returns the current tag.
*
* Return Value: The current tag or NULL.
*/
GPlateTag *
gplate_template_current_tag(GPlateTemplate *tplate) {
GPlateTemplateClass *klass = NULL;
g_return_val_if_fail(GPLATE_IS_TEMPLATE(tplate), NULL);
klass = GPLATE_TEMPLATE_GET_CLASS(tplate);
if(klass && klass->current_tag)
return klass->current_tag(tplate);
return NULL;
}
/**
* gplate_template_next_tag:
* @tplate: The #GPlateTemplate.
*
* Moves the tag stack forward one tag and returns it.
*
* Return Value: The next tag or NULL.
*/
GPlateTag *
gplate_template_next_tag(GPlateTemplate *tplate) {
GPlateTemplateClass *klass = NULL;
g_return_val_if_fail(GPLATE_IS_TEMPLATE(tplate), NULL);
klass = GPLATE_TEMPLATE_GET_CLASS(tplate);
if(klass && klass->next_tag)
return klass->next_tag(tplate);
return NULL;
}
/**
* gplate_template_previous_tag:
* @tplate: The #GPlateTemplate.
*
* Moves the tag stack back one tag and returns it.
*
* Return Value: The previous tag or NULL.
*/
GPlateTag *
gplate_template_previous_tag(GPlateTemplate *tplate) {
GPlateTemplateClass *klass = NULL;
g_return_val_if_fail(GPLATE_IS_TEMPLATE(tplate), NULL);
klass = GPLATE_TEMPLATE_GET_CLASS(tplate);
if(klass && klass->previous_tag)
return klass->previous_tag(tplate);
return NULL;
}
/**
* gplate_template_nth_tag:
* @tplate: The #GPlateTemplate.
* @nth: The number of tags to move forwards.
*
* Moves the tag stack forward @nth tags and returns that tag.
*
* Return Value: The @nth tag or NULL.
*/
GPlateTag *
gplate_template_nth_tag(GPlateTemplate *tplate, guint nth) {
GPlateTemplateClass *klass = NULL;
g_return_val_if_fail(GPLATE_IS_TEMPLATE(tplate), NULL);
klass = GPLATE_TEMPLATE_GET_CLASS(tplate);
if(klass && klass->nth_tag)
return klass->nth_tag(tplate, nth);
return NULL;
}
/**
* gplate_template_nth_previous_tag:
* @tplate: The #GPlateTemplate.
* @nth: The number of tags to move backwards.
*
* Moves the tag stack back @nth tags and returns that tag.
*
* Return Value: The @nth previous tag or NULL.
*/
GPlateTag *
gplate_template_nth_previous_tag(GPlateTemplate *tplate, guint nth) {
GPlateTemplateClass *klass = NULL;
g_return_val_if_fail(GPLATE_IS_TEMPLATE(tplate), NULL);
klass = GPLATE_TEMPLATE_GET_CLASS(tplate);
if(klass && klass->nth_previous_tag)
return klass->nth_previous_tag(tplate, nth);
return NULL;
}
/**
* gplate_template_insert_tags:
* @tplate: The #GPlateTemplate.
* @tags: A #GList of #GPlateTag's to insert.
*
* Inserts @tags after the current tag in @tplate's stack.
*/
void
gplate_template_insert_tags(GPlateTemplate *tplate, GList *tags) {
GPlateTemplateClass *klass = NULL;
g_return_if_fail(GPLATE_IS_TEMPLATE(tplate));
g_return_if_fail(tags);
klass = GPLATE_TEMPLATE_GET_CLASS(tplate);
if(klass && klass->insert_tags)
klass->insert_tags(tplate, tags);
}
static gchar *
gplate_template_render_token(GPlateTemplate *tplate, const gchar *contents,
GType tag, GError **error)
{
GPlateFunction *function = NULL;
GType deftag = G_TYPE_INVALID;
gboolean deffunc = FALSE;
gchar *ret = NULL;
deftag = gplate_library_get_default_tag();
if(tag == deftag) {
GType f = gplate_library_get_default_function_for_tag(tag, NULL);
function = g_object_new(f, NULL);
if(!function)
return g_strdup("");
ret = gplate_function_evaluate(function, tplate, contents);
} else {
gchar *name = NULL, *leftovers = NULL;
name = gplate_util_get_first_word(contents, &leftovers);
if(!name)
return g_strdup("");
function =
gplate_template_render_find_function(name, tag, &deffunc, error);
if(function) {
if(deffunc)
ret = gplate_function_evaluate(function, tplate, contents);
else
ret = gplate_function_evaluate(function, tplate, leftovers);
g_object_unref(G_OBJECT(function));
}
g_free(name);
g_free(leftovers);
}
return (ret) ? ret : g_strdup("");
}
/**
* gplate_template_render_tag:
* @tplate: The #GPlateTemplate.
* @tag: The #GPlateTag.
*
* Renders @tag using @tplate as it's context.
*
* Return Value: The rendered output of @tag.
*/
gchar *
gplate_template_render_tag(GPlateTemplate *tplate, const GPlateTag *tag) {
GType ttype = G_TYPE_INVALID;
gchar *contents = NULL, *ret = NULL;
g_return_val_if_fail(GPLATE_IS_TEMPLATE(tplate), NULL);
g_return_val_if_fail(GPLATE_IS_TAG(tag), NULL);
ttype = G_OBJECT_TYPE(tag);
contents = gplate_tag_get_contents(tag);
ret = gplate_template_render_token(tplate, contents, ttype, NULL);
g_free(contents);
return ret;
}
/**
* gplate_template_set_working_directory:
* @tplate: The #GPlateTemplate.
* @wd: The working directory to use for @tplate.
*
* Sets the working directory for @tplate to @wd.
*
* The working directory is used for functions that need paths. For example
* #GPlateIncludeFunction.
*
* If this is not set, and #gplate_template_render_file is called, the working
* directory will be set to that parent directory of the file.
*
* The working directory can be unset by supplying NULL for @wd.
*/
void
gplate_template_set_working_directory(GPlateTemplate *tplate, const gchar *wd) {
GPlateTemplatePrivate *priv = NULL;
g_return_if_fail(GPLATE_IS_TEMPLATE(tplate));
priv = GPLATE_TEMPLATE_GET_PRIVATE(tplate);
g_free(priv->wd);
priv->wd = (wd) ? g_strdup(wd) : NULL;
g_object_notify(G_OBJECT(tplate), "working-directory");
}
/**
* gplate_template_get_working_directory:
* @tplate: The #GPlateTemplate.
*
* Gets the current working directory from @tplate.
*
* See #gplate_template_set_working_directory for more information.
*
* Return Value: The current working directory for @tplate or NULL.
*/
const gchar *
gplate_template_get_working_directory(const GPlateTemplate *tplate) {
GPlateTemplatePrivate *priv = NULL;
g_return_val_if_fail(GPLATE_IS_TEMPLATE(tplate), NULL);
priv = GPLATE_TEMPLATE_GET_PRIVATE(tplate);
return priv->wd;
}