grim/gplate
Clone
Summary
Browse
Changes
Graph
I thought I already added this.. my bad
trying_to_get_includes_working
2008-02-20, grim
545b7214a0de
I thought I already added this.. my bad
/*
* Copyright (C) 2007-2008 Gary Kramlich <grim@reaperworld.com>
*
* 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, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifdef HAVE_CONFIG_H
#
include
<config.h>
#endif
/* HAVE_CONFIG_H */
#include
<gplate/gplate-library.h>
#include
<gplate/gplate-errors.h>
/******************************************************************************
* Structs
*****************************************************************************/
typedef
struct
{
GType
function
;
GType
tag
;
}
GPlateFunctionData
;
typedef
struct
{
GType
tag
;
gchar
*
prefix
;
gchar
*
suffix
;
GType
default_function
;
}
GPlateTagData
;
/******************************************************************************
* Globals
*****************************************************************************/
static
GHashTable
*
functions
=
NULL
;
static
GHashTable
*
tags
=
NULL
;
static
GType
default_tag
=
G_TYPE_INVALID
;
/******************************************************************************
* GPlateFunctionData API
*****************************************************************************/
static
GPlateFunctionData
*
gplate_function_data_new
(
GType
function
,
GType
tag
)
{
GPlateFunctionData
*
data
=
g_new
(
GPlateFunctionData
,
1
);
data
->
function
=
function
;
data
->
tag
=
tag
;
return
data
;
}
static
void
gplate_function_data_free
(
GPlateFunctionData
*
data
)
{
g_free
(
data
);
}
/******************************************************************************
* GPlateTagData API
*****************************************************************************/
static
GPlateTagData
*
gplate_tag_data_new
(
GType
tag
,
GError
**
error
)
{
GPlateTagData
*
data
=
NULL
;
GPlateTagClass
*
klass
=
NULL
;
const
gchar
*
prefix
=
NULL
,
*
suffix
=
NULL
;
klass
=
g_type_class_ref
(
tag
);
prefix
=
gplate_tag_class_get_prefix
(
klass
);
suffix
=
gplate_tag_class_get_suffix
(
klass
);
if
(
!
prefix
&&
suffix
)
{
if
(
error
)
{
*
error
=
g_error_new
(
GPLATE_DOMAIN
,
GPLATE_ERROR_LIBRARY_TAG_NO_PREFIX_HAVE_SUFFIX
,
"tag '%s' does not have a prefix, but has a "
"suffix."
,
g_type_name
(
tag
));
}
return
NULL
;
}
else
if
(
prefix
&&
!
suffix
)
{
if
(
error
)
{
*
error
=
g_error_new
(
GPLATE_DOMAIN
,
GPLATE_ERROR_LIBRARY_TAG_HAVE_PREFIX_NO_SUFFIX
,
"tag '%s' has a prefix, but does not have a "
"suffix."
,
g_type_name
(
tag
));
}
return
NULL
;
}
if
(
!
prefix
&&
!
suffix
)
{
if
(
default_tag
!=
G_TYPE_INVALID
)
{
if
(
error
)
{
*
error
=
g_error_new
(
GPLATE_DOMAIN
,
GPLATE_ERROR_LIBRARY_DEFAULT_TAG_REGISTERED
,
"A default tag named '%s' has already been "
"registered."
,
g_type_name
(
default_tag
));
}
return
NULL
;
}
else
{
default_tag
=
tag
;
}
}
data
=
g_new
(
GPlateTagData
,
1
);
data
->
tag
=
tag
;
data
->
prefix
=
(
prefix
)
?
g_strdup
(
prefix
)
:
NULL
;
data
->
suffix
=
(
suffix
)
?
g_strdup
(
suffix
)
:
NULL
;
data
->
default_function
=
G_TYPE_INVALID
;
g_type_class_unref
(
klass
);
return
data
;
}
static
void
gplate_tag_data_free
(
GPlateTagData
*
data
)
{
g_free
(
data
->
prefix
);
g_free
(
data
->
suffix
);
g_free
(
data
);
}
/******************************************************************************
* Inlines
*****************************************************************************/
static
inline
void
gplate_library_lazy_init
(
void
)
{
if
(
G_UNLIKELY
(
functions
==
NULL
))
{
functions
=
g_hash_table_new_full
(
g_str_hash
,
g_str_equal
,
g_free
,
(
GDestroyNotify
)
gplate_function_data_free
);
}
if
(
G_UNLIKELY
(
tags
==
NULL
))
{
tags
=
g_hash_table_new_full
(
g_direct_hash
,
g_direct_equal
,
NULL
,
(
GDestroyNotify
)
gplate_tag_data_free
);
}
}
static
inline
gboolean
gplate_library_check_type
(
GType
type
,
GType
parent
,
GError
**
error
)
{
if
(
!
g_type_is_a
(
type
,
parent
))
{
if
(
error
)
{
*
error
=
g_error_new
(
GPLATE_DOMAIN
,
GPLATE_ERROR_TYPE_IS_NOT_DESCENDANT
,
"%s is not a subclass of %s."
,
g_type_name
(
type
),
g_type_name
(
parent
));
}
return
FALSE
;
}
if
(
G_TYPE_IS_ABSTRACT
(
type
))
{
if
(
error
)
{
*
error
=
g_error_new
(
GPLATE_DOMAIN
,
GPLATE_ERROR_TYPE_IS_ABSTRACT
,
"%s is abstract."
,
g_type_name
(
type
));
}
return
FALSE
;
}
return
TRUE
;
}
/******************************************************************************
* GPlateLibrary API
*****************************************************************************/
/**
* gplate_library_add_function:
* @name: The name of the function.
* @function: The #GType of the function.
* @error: The return address for errors.
*
* Adds @function to the library.
*
* Return Value: TRUE on success, otherwise FALSE with @error set.
*/
gboolean
gplate_library_add_function
(
const
gchar
*
name
,
GType
function
,
GError
**
error
)
{
GPlateFunctionData
*
data
=
NULL
;
g_return_val_if_fail
(
name
,
FALSE
);
gplate_library_lazy_init
();
if
(
!
gplate_library_check_type
(
function
,
GPLATE_TYPE_FUNCTION
,
error
))
return
FALSE
;
data
=
g_hash_table_lookup
(
functions
,
name
);
if
(
data
)
{
/* if the function is already registered with the same name and
* function, return TRUE and jump out.
*/
if
(
data
->
function
==
function
)
return
TRUE
;
if
(
error
)
{
*
error
=
g_error_new
(
GPLATE_DOMAIN
,
GPLATE_ERROR_LIBRARY_FUNCTION_NAME_EXISTS
,
"Function name '%s' is already registered "
"to '%s'"
,
name
,
g_type_name
(
data
->
function
));
}
return
FALSE
;
}
data
=
gplate_function_data_new
(
function
,
G_TYPE_INVALID
);
g_hash_table_insert
(
functions
,
g_strdup
(
name
),
data
);
return
TRUE
;
}
/**
* gplate_library_remove_function:
* @name: The name of the function to remove.
* @error: Return address for errors.
*
* Removes a function from the library by it's name.
*
* Return Value: TRUE if the function was removed, otherwise FALSE.
*/
gboolean
gplate_library_remove_function
(
const
gchar
*
name
,
GError
**
error
)
{
gboolean
ret
;
g_return_val_if_fail
(
name
,
FALSE
);
ret
=
g_hash_table_remove
(
functions
,
name
);
if
(
!
ret
&&
error
)
{
*
error
=
g_error_new
(
GPLATE_DOMAIN
,
GPLATE_ERROR_LIBRARY_FUNCTION_NAME_NOT_FOUND
,
"Function '%s' was not found."
,
name
);
}
return
ret
;
}
/**
* gplate_library_add_tag:
* @tag: The #GPlateTag's GType to add.
* @error: The return address for any errors.
*
* Adds a tag to the library.
*
* Tags must be added to the library via this function for a template to
* handle them.
*
* Return Value: TRUE on success, FALSE on failure with @error set.
*/
gboolean
gplate_library_add_tag
(
GType
tag
,
GError
**
error
)
{
GPlateTagData
*
data
=
NULL
;
gplate_library_lazy_init
();
if
(
!
gplate_library_check_type
(
tag
,
GPLATE_TYPE_TAG
,
error
))
return
FALSE
;
data
=
g_hash_table_lookup
(
tags
,
GSIZE_TO_POINTER
(
tag
));
if
(
data
)
{
if
(
error
)
{
*
error
=
g_error_new
(
GPLATE_DOMAIN
,
GPLATE_ERROR_LIBRARY_TAG_EXISTS
,
"Tag '%s' is already in the library"
,
g_type_name
(
tag
));
}
return
FALSE
;
}
data
=
gplate_tag_data_new
(
tag
,
error
);
if
(
!
data
)
return
FALSE
;
g_hash_table_insert
(
tags
,
GSIZE_TO_POINTER
(
data
->
tag
),
data
);
return
TRUE
;
}
/**
* gplate_library_remove_tag:
* @tag: The #GType of the tag to remove from the library.
* @error: The return address for any errors.
*
* Unregisters @tag from the library.
*
* Return Value: TRUE on success, FALSE on failure with @error set.
*/
gboolean
gplate_library_remove_tag
(
GType
tag
,
GError
**
error
)
{
gpointer
data
;
gplate_library_lazy_init
();
if
(
!
gplate_library_check_type
(
tag
,
GPLATE_TYPE_TAG
,
error
))
return
FALSE
;
data
=
g_hash_table_lookup
(
tags
,
GSIZE_TO_POINTER
(
tag
));
if
(
!
data
)
{
if
(
error
)
{
*
error
=
g_error_new
(
GPLATE_DOMAIN
,
GPLATE_ERROR_LIBRARY_TAG_NOT_FOUND
,
"Tag '%s' is not in the library."
,
g_type_name
(
tag
));
}
return
FALSE
;
}
g_hash_table_remove
(
tags
,
GSIZE_TO_POINTER
(
tag
));
return
TRUE
;
}
/**
* gplate_library_bind_function:
* @name: The name of the function.
* @tag: The #GType of the tag.
* @error: The return address for errors.
*
* Binds the already registered function @name to @tag.
*
* Return Value: TRUE on success, FALSE on failure with @error set.
*/
gboolean
gplate_library_bind_function
(
const
gchar
*
name
,
GType
tag
,
GError
**
error
)
{
GPlateFunctionData
*
data
=
NULL
;
gplate_library_lazy_init
();
g_return_val_if_fail
(
name
,
FALSE
);
if
(
!
gplate_library_check_type
(
tag
,
GPLATE_TYPE_TAG
,
error
))
return
FALSE
;
data
=
g_hash_table_lookup
(
functions
,
name
);
if
(
!
data
)
{
if
(
error
)
{
*
error
=
g_error_new
(
GPLATE_DOMAIN
,
GPLATE_ERROR_LIBRARY_FUNCTION_NAME_NOT_FOUND
,
"There is no function registered with the "
"name '%s'"
,
name
);
}
return
FALSE
;
}
data
->
tag
=
tag
;
return
TRUE
;
}
/**
* gplate_library_unbind_function:
* @name: The name of the function to unbind.
* @error: The return address for any errors.
*
* Unbinds @name.
*
* If @name is not already bound, this will return FALSE with a
* GPLATE_ERROR_LIBRARY_FUNCTION_NOT_BOUND error.
*
* Return Value: TRUE on success, FALSE on failure with @error set.
*/
gboolean
gplate_library_unbind_function
(
const
gchar
*
name
,
GError
**
error
)
{
GPlateFunctionData
*
data
=
NULL
;
g_return_val_if_fail
(
name
,
FALSE
);
gplate_library_lazy_init
();
data
=
g_hash_table_lookup
(
functions
,
name
);
if
(
!
data
)
{
if
(
error
)
{
*
error
=
g_error_new
(
GPLATE_DOMAIN
,
GPLATE_ERROR_LIBRARY_FUNCTION_NAME_NOT_FOUND
,
"No function named '%s' is registered"
,
name
);
}
return
FALSE
;
}
if
(
data
->
tag
==
G_TYPE_INVALID
)
{
if
(
error
)
{
*
error
=
g_error_new
(
GPLATE_DOMAIN
,
GPLATE_ERROR_LIBRARY_FUNCTION_NOT_BOUND
,
"Function '%s' is not bound to a tag"
,
name
);
}
return
FALSE
;
}
data
->
tag
=
G_TYPE_INVALID
;
return
TRUE
;
}
/**
* gplate_library_add_bound_function:
* @name: The name of the function.
* @function: The #GType of the function.
* @tag: The #GType of the tag.
* @error: The return address for any errors.
*
* Registers @function with @name and then binds it to @tag.
*
* This is just a wrapper around #gplate_library_add_function and
* #gplate_library_bind_function.
*
* Return Value: TRUE on success, otherwise FALSE with @error set.
*/
gboolean
gplate_library_add_bound_function
(
const
gchar
*
name
,
GType
function
,
GType
tag
,
GError
**
error
)
{
gboolean
ret
;
g_return_val_if_fail
(
name
,
FALSE
);
gplate_library_lazy_init
();
ret
=
gplate_library_add_function
(
name
,
function
,
error
);
if
(
!
ret
)
return
FALSE
;
ret
=
gplate_library_bind_function
(
name
,
tag
,
error
);
return
ret
;
}
/**
* gplate_library_lookup_function:
* @name: The name of the function to find.
* @function: Return address for the #GType of the functions.
* @tag: Return address for the #GType of the associated tag.
* @error: Return address for any errors.
*
* Looks for a function in the library.
*
* If the function is found, @function and @type will be set apporiately.
*
* If the function is not found, @function and @type are undefined, and error
* will be set.
*
* Return Value: TRUE if @name is found in the library, otherwise FALSE.
*/
gboolean
gplate_library_lookup_function
(
const
gchar
*
name
,
GType
*
function
,
GType
*
tag
,
GError
**
error
)
{
GPlateFunctionData
*
data
=
NULL
;
g_return_val_if_fail
(
name
,
FALSE
);
data
=
g_hash_table_lookup
(
functions
,
name
);
if
(
!
data
)
{
if
(
error
)
{
*
error
=
g_error_new
(
GPLATE_DOMAIN
,
GPLATE_ERROR_LIBRARY_FUNCTION_NAME_NOT_FOUND
,
"Function '%s' was not found."
,
name
);
}
return
FALSE
;
}
if
(
function
)
*
function
=
data
->
function
;
if
(
tag
)
*
tag
=
data
->
tag
;
return
TRUE
;
}
/**
* gplate_library_lookup_function_for_tag:
* @name: The name of the function to lookup.
* @tag: The #GType of the tag.
* @error: The return address for any error.
*
* Looks up a function named @name that is bound to @tag.
*
* Return Value: The #GType of the function on success, otherwise
* #G_TYPE_INVALID on failure with @error set.
*/
GType
gplate_library_lookup_function_for_tag
(
const
gchar
*
name
,
GType
tag
,
GError
**
error
)
{
GType
type
=
G_TYPE_INVALID
,
function
=
G_TYPE_INVALID
;
gplate_library_lazy_init
();
if
(
!
gplate_library_check_type
(
tag
,
GPLATE_TYPE_TAG
,
error
))
return
G_TYPE_INVALID
;
if
(
!
gplate_library_lookup_function
(
name
,
&
function
,
&
type
,
error
))
return
G_TYPE_INVALID
;
if
(
type
!=
tag
)
{
if
(
error
)
{
*
error
=
g_error_new
(
GPLATE_DOMAIN
,
GPLATE_ERROR_LIBRARY_FUNCTION_NOT_BOUND_TO_TAG
,
"Function '%s' is not bound to '%s'"
,
name
,
g_type_name
(
tag
));
}
return
G_TYPE_INVALID
;
}
return
function
;
}
/**
* gplate_library_lookup_tag:
* @tag: The GType of the tag to lookup.
* @prefix: The return address for the prefix.
* @suffix: The return address for the suffix.
* @error: The return address for any errors.
*
* Looks for @tag in the library. If the tag is found, TRUE is returned and
* @prefix and @suffix will be set. NULL can be passed for @prefix and
* @suffix. If @prefix and @suffix are non-NULL they must be #g_free'd.
*
* If @tag is not found in the library, FALSE will be returned and @error will
* be set.
*
* Return Value: TRUE on success, FALSE otherwise.
*/
gboolean
gplate_library_lookup_tag
(
GType
tag
,
gchar
**
prefix
,
gchar
**
suffix
,
GError
**
error
)
{
GPlateTagData
*
data
=
NULL
;
gplate_library_lazy_init
();
data
=
g_hash_table_lookup
(
tags
,
GSIZE_TO_POINTER
(
tag
));
if
(
!
data
)
{
if
(
error
)
{
*
error
=
g_error_new
(
GPLATE_DOMAIN
,
GPLATE_ERROR_LIBRARY_TAG_NOT_FOUND
,
"Tag '%s' was not found in the library"
,
g_type_name
(
tag
));
}
return
FALSE
;
}
if
(
prefix
)
*
prefix
=
(
data
->
prefix
)
?
g_strdup
(
data
->
prefix
)
:
NULL
;
if
(
suffix
)
*
suffix
=
(
data
->
suffix
)
?
g_strdup
(
data
->
suffix
)
:
NULL
;
return
TRUE
;
}
/**
* gplate_library_get_default_tag:
*
* Gets the default tag if one has been registered.
*
* A default tag is one that does not have a prefix or a suffix. It is used
* when no other tags match.
*
* Return Value: The default tag if one has been registered, otherwise
* #G_TYPE_INVALID.
*/
GType
gplate_library_get_default_tag
(
void
)
{
return
default_tag
;
}
/**
* gplate_library_set_default_function_for_tag:
* @name: The name of the function.
* @tag: The #GType of the tag.
* @error: The return address for any errors.
*
* Sets the default function of @tag to @name.
*
* A default function is used when the contents of a tag do not match any
* functions that are registered to the tag.
*
* For example, the default function of #GPlateCommentTag is
* #GPlateNoopFunction.
*
* Return Value: TRUE on success, otherwise FALSE with @error set.
*/
gboolean
gplate_library_set_default_function_for_tag
(
const
gchar
*
name
,
GType
tag
,
GError
**
error
)
{
GPlateTagData
*
tdata
=
NULL
;
GType
function
=
G_TYPE_INVALID
;
g_return_val_if_fail
(
name
,
FALSE
);
gplate_library_lazy_init
();
tdata
=
g_hash_table_lookup
(
tags
,
GSIZE_TO_POINTER
(
tag
));
if
(
!
tdata
)
{
if
(
error
)
{
*
error
=
g_error_new
(
GPLATE_DOMAIN
,
GPLATE_ERROR_LIBRARY_TAG_NOT_FOUND
,
"tag '%s' is not registered"
,
g_type_name
(
tag
));
}
return
FALSE
;
}
if
(
!
gplate_library_lookup_function
(
name
,
&
function
,
NULL
,
error
))
return
FALSE
;
tdata
->
default_function
=
function
;
return
TRUE
;
}
/**
* gplate_library_get_default_function_for_tag:
* @tag: The #GPlateTag.
* @error: The return address for any errors.
*
* Get's the default function for @tag.
*
* Return Value: On success, the #GType of the function is returned.
* On failure, #G_TYPE_INVALID is returned and @error is set.
*
* However, if a tag does not have a default function,
* #G_TYPE_INVALID will be returned. So it is recommended to
* pass @error and check if it's set before assuming a return
* value of #G_TYPE_INVALID is an error.
*/
GType
gplate_library_get_default_function_for_tag
(
GType
tag
,
GError
**
error
)
{
GPlateTagData
*
tdata
=
NULL
;
gplate_library_lazy_init
();
tdata
=
g_hash_table_lookup
(
tags
,
GSIZE_TO_POINTER
(
tag
));
if
(
!
tdata
)
{
if
(
error
)
{
*
error
=
g_error_new
(
GPLATE_DOMAIN
,
GPLATE_ERROR_LIBRARY_TAG_NOT_FOUND
,
"tag '%s' is not registered"
,
g_type_name
(
tag
));
}
return
G_TYPE_INVALID
;
}
return
tdata
->
default_function
;
}
/******************************************************************************
* For each stuff
*****************************************************************************/
typedef
struct
{
GPlateLibraryTagsForeachFunc
func
;
gpointer
data
;
}
GPlateLibraryTagsForeachData
;
static
void
gplate_library_tags_foreach_helper
(
gpointer
k
,
gpointer
v
,
gpointer
d
)
{
GPlateTagData
*
data
=
(
GPlateTagData
*
)
v
;
GPlateLibraryTagsForeachData
*
fhd
=
(
GPlateLibraryTagsForeachData
*
)
d
;
fhd
->
func
(
data
->
tag
,
data
->
prefix
,
data
->
suffix
,
fhd
->
data
);
}
/**
* gplate_library_tags_foreach:
* @func: The callback function.
* @data: User data to pass to the callback function.
*
* Calls @func with each tag registered in the library.
*/
void
gplate_library_tags_foreach
(
GPlateLibraryTagsForeachFunc
func
,
gpointer
data
)
{
GPlateLibraryTagsForeachData
d
=
{
0
,
};
gplate_library_lazy_init
();
d
.
func
=
func
;
d
.
data
=
data
;
g_hash_table_foreach
(
tags
,
gplate_library_tags_foreach_helper
,
&
d
);
}