From 7efde30caa7742bef168ff279dc113d974eb9fe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Ates?= Date: Fri, 9 Jan 2015 17:05:53 +0100 Subject: [PATCH] Helper functions, mainly from lasso. --- cv2extractor/utils.c | 163 ++++++++++ cv2extractor/utils.h | 696 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 859 insertions(+) create mode 100644 cv2extractor/utils.c create mode 100644 cv2extractor/utils.h diff --git a/cv2extractor/utils.c b/cv2extractor/utils.c new file mode 100644 index 0000000..2dc020e --- /dev/null +++ b/cv2extractor/utils.c @@ -0,0 +1,163 @@ +/* $Id$ + * + * cv2extractor - A free implementation of a reader of Carte Vitale 2 cards. + * + * Copyright (C) 2015 Entr'ouvert + * https://dev.entrouvert.org/projects/cv2extractor + * + * Authors: See AUTHORS file in top-level directory. + * + * 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 3 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include +#include "./utils.h" + +/** + * SECTION:utilities + * @short_description: Misc functions used internally in Cv2extractor + * @stability: Internal + * @include: utils.h + */ + +/** + * cv2extractor_safe_prefix_string: + * @str: a C string + * @length: the maximum length of an extract of the string + * + * Produce a limite length safe extract of a string, for debugging purpose. Special characters are + * replaced by their C string 'quoting'. + * + * Return value: a C string, of size < @length where newline, carriage returns and tabs are replaced + * by their C quotes. + */ +gchar* +cv2extractor_safe_prefix_string(const gchar *str, gsize length) +{ + GString *output; + gchar *ret; + gsize outputted = 0, i = 0; + + if (str == NULL) { + return strdup("NULL"); + } + output = g_string_sized_new(length); + for (i = 0; i < length && str[i] && outputted < length; i++) { + gchar c = 0; + guint len; + + if ((guchar)str[i] < 128 && (guchar)str[i] > 31) { + g_string_append_c(output, str[i]); + outputted++; + continue; + } + switch (str[i]) { + case '\n': + c = 'n'; + break; + case '\t': + c = 't'; + break; + case '\r': + c = 'r'; + } + if (c) { + if (outputted - length > 1) { + g_string_append_c(output, '\\'); + g_string_append_c(output, c); + outputted += 2; + continue; + } + } + if (c < 8) { + len = 3; + } else if (c < 64) { + len = 4; + } else { + len = 5; + } + if (outputted - length >= len) { + g_string_append_c(output, '\\'); + g_string_append_printf(output, "%o", (guint)str[i]); + } + break; + } + ret = output->str; + cv2extractor_release_gstring(output, FALSE); + return ret; +} + +/** + * cv2extractor_gobject_is_of_type: + * @a: a #GObject object + * @b: a #GType value + * + * Return true if object @a is of type @b. + * + * Return value: whether object @a is of type @b. + */ +int +cv2extractor_gobject_is_of_type(GObject *a, GType b) +{ + GType typeid = (GType)b; + + if (a && G_IS_OBJECT(a)) { + return G_OBJECT_TYPE(G_OBJECT(a)) == typeid ? 0 : 1; + } + return 1; +} + +GObject* +cv2extractor_extract_gtype_from_list(GType type, GList *list) +{ + GList *needle; + + needle = g_list_find_custom(list, (gconstpointer)type, (GCompareFunc)cv2extractor_gobject_is_of_type); + if (needle) { + return needle->data; + } + return NULL; +} + +/** + * cv2extractor_extract_gtype_from_list_or_new: + * @type: a #GType + * @list: a pointer to a #GList pointer variable + * @create: whether to look up an object whose #GType is type, or to just create it. + * + * If create is TRUE, add a new object of type @type to @list and return it. + * Otherwise try to look up an object of type @type, and if none is found add a new one and return + * it. + * + * Return value: a #GObject of type @type. + */ +GObject * +cv2extractor_extract_gtype_from_list_or_new(GType type, GList **list, gboolean create) +{ + GObject *result = NULL; + g_assert (list); + + if (! create) { + result = cv2extractor_extract_gtype_from_list(type, *list); + } + if (result == NULL) { + result = g_object_new(type, NULL); + cv2extractor_list_add_new_gobject(*list, result); + } + return result; +} diff --git a/cv2extractor/utils.h b/cv2extractor/utils.h new file mode 100644 index 0000000..787f90c --- /dev/null +++ b/cv2extractor/utils.h @@ -0,0 +1,696 @@ +/* $Id$ + * + * cv2extractor - A free implementation of a reader of Carte Vitale 2 cards. + * + * Copyright (C) 2015 Entr'ouvert + * https://dev.entrouvert.org/projects/cv2extractor + * + * Authors: See AUTHORS file in top-level directory. + * + * 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 3 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __CV2EXTRACTOR_UTILS_H__ +#define __CV2EXTRACTOR_UTILS_H__ + +#include +#include +#include + +#ifdef CV2EXTRACTOR_DEBUG +#ifdef __GNUC__ +#define cv2extractor_check_type_equality(a,b) \ + { \ + enum { TYPE_MISMATCH = (1 / __builtin_types_compatible_p(typeof(a), typeof(b))) }; \ + } +#else +#define cv2extractor_check_type_equality(a,b) +#endif +#else +#define cv2extractor_check_type_equality(a,b) +#endif + +#ifdef __GNUC__ +#define cv2extractor_check_type_equality2(a,b,c) \ + { \ + enum { TYPE_MISMATCH = (1 / (__builtin_types_compatible_p(typeof(a), typeof(b))+__builtin_types_compatible_p(typeof(a), typeof(c)))) }; \ + } +#else +#define cv2extractor_check_type_equality2(a,b,c) +#endif + +#define cv2extractor_private_data(object) ((object)->private_data) + + +#define cv2extractor_critical(message, args...) \ + g_log("cv2extractor", G_LOG_LEVEL_CRITICAL, message, ## args) + +#define cv2extractor_warning(message, args...) \ + g_log("cv2extractor", G_LOG_LEVEL_WARNING, message, ## args) + +#define cv2extractor_message(message, args...) \ + g_log("cv2extractor", G_LOG_LEVEL_MESSAGE, message, ## args) + +/** + * cv2extractor_ref: + * @object: an object whose reference count must be incremented. + * + * Increment the reference count of an object, do not emit warning if it is NULL. + * + * Return value: the @object. + */ +#define cv2extractor_ref(object) ((object) != NULL ? (g_object_ref(object), object) : NULL) + +/** + * cv2extractor_unref: + * @object: an object whose reference count must be decremented. + * + * Decrement the reference count of an object, do not emit warnings if it is NULL. + * + * Return value: the @object. + */ +#define cv2extractor_unref(object) ((object) != NULL ? (g_object_unref(object), object) : NULL) + +/* Freeing */ + +/* + * cv2extractor_release_xxx are macros which ensure you do not get 'double free' errors, they first check + * that the variable is not NULL before calling the deallocation function, and after deallocation + * they reset the variable to NULL, preventing 'double free'. + */ +#define cv2extractor_release(dest) \ + { \ + if (dest) { \ + g_free(dest); dest = NULL; \ + } \ + } + +#define cv2extractor_release_full(dest, free_function) \ + { \ + if (dest) { \ + free_function(dest); dest = NULL; \ + } \ + } + +#define cv2extractor_release_full2(dest, free_function, type) \ + { \ + cv2extractor_check_type_equality(dest, type); \ + if (dest) { \ + free_function(dest); dest = NULL; \ + } \ + } + +#define cv2extractor_release_gobject(dest) \ + { \ + if (G_IS_OBJECT(dest) || dest == NULL) { \ + cv2extractor_release_full(dest, g_object_unref); \ + } else { \ + g_critical("Trying to unref a non GObject pointer file=%s:%u pointerbybname=%s pointer=%p", __FILE__, __LINE__, #dest, dest); \ + } \ + } + +#define cv2extractor_release_string(dest) \ + cv2extractor_release_full(dest, g_free) + +#define cv2extractor_release_list(dest) \ + cv2extractor_release_full2(dest, g_list_free, GList*) + +#define cv2extractor_release_list_of_full(dest, free_function) \ + { \ + GList **__tmp = &(dest); \ + if (*__tmp) { \ + g_list_foreach(*__tmp, (GFunc)free_function, NULL); \ + cv2extractor_release_list(*__tmp); \ + } \ + } + +#define cv2extractor_release_list_of_strings(dest) \ + cv2extractor_release_list_of_full(dest, g_free) + +#define cv2extractor_release_list_of_gobjects(dest) \ + cv2extractor_release_list_of_full(dest, g_object_unref) + +#define cv2extractor_release_list_of_xml_node(dest) \ + cv2extractor_release_list_of_full(dest, xmlFreeNode) + +#define cv2extractor_release_list_of_xml_node_list(dest) \ + cv2extractor_release_list_of_full(dest, xmlFreeNodeList) + +#define cv2extractor_release_xml_node(node) \ + cv2extractor_release_full2(node, xmlFreeNode, xmlNodePtr) + +#define cv2extractor_release_xml_node_list(node) \ + cv2extractor_release_full2(node, xmlFreeNodeList, xmlNodePtr) + +#define cv2extractor_release_doc(doc) \ + cv2extractor_release_full2(doc, xmlFreeDoc, xmlDocPtr) + +#define cv2extractor_release_xml_string(dest) \ + cv2extractor_release_full2(dest, xmlFree, xmlChar*) + +#define cv2extractor_release_encrypt_context(dest) \ + cv2extractor_release_full2(dest, xmlSecEncCtxDestroy, xmlSecEncCtxPtr) + +#define cv2extractor_release_signature_context(dest) \ + cv2extractor_release_full2(dest, xmlSecDSigCtxDestroy,xmlSecDSigCtxPtr) + +#define cv2extractor_release_key_manager(dest) \ + cv2extractor_release_full2(dest, xmlSecKeysMngrDestroy, xmlSecKeysMngrPtr) + +#define cv2extractor_release_output_buffer(dest) \ + cv2extractor_release_full2(dest, xmlOutputBufferClose, xmlOutputBufferPtr) + +#define cv2extractor_release_xpath_object(dest) \ + cv2extractor_release_full2(dest, xmlXPathFreeObject, xmlXPathObjectPtr) + +#define cv2extractor_release_xpath_context(dest) \ + cv2extractor_release_full2(dest, xmlXPathFreeContext, xmlXPathContextPtr) + +#define cv2extractor_release_xpath_job(xpathObject, xpathContext, xmlDocument) \ + cv2extractor_release_xpath_object(xpathObject); \ + cv2extractor_release_xpath_context(xpathContext); \ + cv2extractor_release_doc(xmlDocument) + +#define cv2extractor_release_sec_key(dest) \ + cv2extractor_release_full2(dest, xmlSecKeyDestroy, xmlSecKeyPtr) + +#define cv2extractor_release_ghashtable(dest) \ + cv2extractor_release_full(dest, g_hash_table_destroy) + +#define cv2extractor_release_gstring(dest, b) \ + { \ + GString **__tmp = &(dest); \ + if (*__tmp) {\ + g_string_free(*__tmp, (b)); \ + *__tmp = NULL; \ + } \ + } + +/* Assignment and list appending */ +/* + * cv2extractor_assign_xxx macros ensure that you dot leak previous value of assigned things, they use + * cv2extractor_release_xxx macros to deallocate, they also ensure proper reference counting on passed by + * references values and proper copying on passed by value values. + */ +#define cv2extractor_assign_string(dest,src) \ + { \ + char *__tmp = g_strdup(src);\ + cv2extractor_release_string(dest); \ + dest = __tmp; \ + } + +#define cv2extractor_assign_xml_string(dest,src) \ + { \ + xmlChar *__tmp = xmlStrdup(src); \ + cv2extractor_release_xml_string(dest); \ + dest = __tmp; \ + } + +#define cv2extractor_assign_new_string(dest,src) \ + { \ + char *__tmp = src; \ + if (dest != __tmp) \ + cv2extractor_release_string(dest); \ + dest = __tmp; \ + } + +#define cv2extractor_assign_gobject(dest,src) \ + { \ + GObject *__tmp = G_OBJECT(src); \ + if (__tmp) \ + g_object_ref(__tmp); \ + cv2extractor_release_gobject(dest); \ + dest = (void*)(__tmp); \ + } + +#define cv2extractor_assign_new_gobject(dest,src) \ + { \ + GObject *__tmp = G_OBJECT(src); \ + if (dest != (void*)__tmp) \ + cv2extractor_release_gobject(dest); \ + dest = (void*)(__tmp); \ + } + +#define cv2extractor_assign_xml_node(dest,src) \ + { \ + xmlNode *__tmp = (src); \ + cv2extractor_check_type_equality(dest, src); \ + if (dest) \ + xmlFreeNode(dest); \ + dest = xmlCopyNode(__tmp, 1); \ + } + +#define cv2extractor_assign_new_xml_node(dest,src) \ + { \ + xmlNode *__tmp = (src); \ + cv2extractor_check_type_equality(dest, src); \ + if (dest) \ + xmlFreeNode(dest); \ + dest = __tmp; \ + } + +#define cv2extractor_assign_xml_node_list(dest,src) \ + { \ + xmlNode *__tmp = (src); \ + cv2extractor_check_type_equality(dest, src); \ + if (dest) \ + xmlFreeNode(dest); \ + dest = xmlCopyNodeList(__tmp); \ + } + +#define cv2extractor_assign_new_xml_node_list(dest,src) \ + cv2extractor_assign_new_xml(dest, src) + +#define cv2extractor_assign_list(dest, src) \ + { \ + GList **__tmp = &(dest); \ + if (*__tmp) \ + g_list_free(*__tmp); \ + *__tmp = g_list_copy((src)); \ + } + +#define cv2extractor_assign_new_list_of_gobjects(dest, src) \ + { \ + GList *__tmp = (src); \ + cv2extractor_release_list_of_gobjects(dest); \ + dest = (GList*)__tmp; \ + } + +#define cv2extractor_assign_new_list_of_strings(dest, src) \ + { \ + GList *__tmp = (src); \ + cv2extractor_release_list_of_strings(dest); \ + dest = (GList*)__tmp; \ + } + +#define cv2extractor_assign_new_list_of_xml_node(dest, src) \ + { \ + GList *__tmp = (src); \ + cv2extractor_release_list_of_xml_node(dest); \ + dest = (GList*)__tmp; \ + } + +#define cv2extractor_assign_list_of_gobjects(dest, src) \ + { \ + GList *__tmp = (src); \ + cv2extractor_release_list_of_gobjects(dest); \ + dest = g_list_copy(__tmp); \ + for (;__tmp != NULL; __tmp = g_list_next(__tmp)) { \ + if (G_IS_OBJECT(__tmp->data)) { \ + g_object_ref(__tmp->data); \ + } \ + } \ + } + +#define cv2extractor_assign_list_of_strings(dest, src) \ + { \ + GList *__tmp = src; \ + GList *__iter_dest; \ + cv2extractor_release_list_of_strings(dest); \ + dest = g_list_copy(__tmp); \ + for (__iter_dest = dest ; __iter_dest != NULL ; __iter_dest = g_list_next(__iter_dest)) { \ + __iter_dest->data = g_strdup(__iter_dest->data); \ + } \ + } + +#define cv2extractor_assign_new_sec_key(dest, src) \ + { \ + xmlSecKey *__tmp = (src); \ + if (dest) \ + cv2extractor_release_sec_key(dest); \ + dest = __tmp; \ + } + +#define cv2extractor_assign_sec_key(dest, src) \ + { \ + xmlSecKey *__tmp = xmlSecKeyDuplicate(src); \ + if (dest) \ + cv2extractor_release_sec_key(dest); \ + dest = __tmp; \ + } + +/* List appending */ + +/* cv2extractor_list_add_xxx macros, simplify code around list manipulation (g_list_append needs to be + * used like this 'l = g_list_appen(l, value)' ) and ensure proper reference count or copying of + * values. + */ +#define cv2extractor_list_add(dest, src) \ + { \ + cv2extractor_check_type_equality((src), void*); \ + dest = g_list_append(dest, (src)); \ + } + +#define cv2extractor_list_add_non_null(dest, src) \ + { \ + void *__tmp_non_null_src = (src); \ + if (__tmp_non_null_src != NULL) { \ + dest = g_list_append(dest, __tmp_non_null_src); \ + } else { \ + g_critical("Adding a NULL value to a non-NULL content list: dest=%s src=%s", #dest, #src); \ + } \ + } + +#define cv2extractor_list_add_string(dest, src) \ + { \ + cv2extractor_list_add_non_null(dest, g_strdup(src));\ + } + +#define cv2extractor_list_add_new_string(dest, src) \ + { \ + gchar *__tmp = src; \ + cv2extractor_list_add_non_null(dest, __tmp); \ + } + +#define cv2extractor_list_add_xml_string(dest, src) \ + {\ + xmlChar *__tmp_src = (src);\ + cv2extractor_list_add_non_null(dest, (void*)g_strdup((char*)__tmp_src));\ + } + +#define cv2extractor_list_add_gobject(dest, src) \ + { \ + void *__tmp_src = (src); \ + if (G_IS_OBJECT(__tmp_src)) { \ + dest = g_list_append(dest, g_object_ref(__tmp_src)); \ + } else { \ + g_critical("Trying to add to a GList* a non GObject pointer dest=%s src=%s", #dest, #src); \ + } \ + } + +#define cv2extractor_list_add_new_gobject(dest, src) \ + { \ + void *__tmp_src = (src); \ + if (G_IS_OBJECT(__tmp_src)) { \ + dest = g_list_append(dest, __tmp_src); \ + } else { \ + g_critical("Trying to add to a GList* a non GObject pointer dest=%s src=%s", #dest, #src); \ + } \ + } + +#define cv2extractor_list_add_xml_node(dest, src) \ + { \ + xmlNode *__tmp_src = xmlCopyNode(src, 1); \ + cv2extractor_list_add_non_null(dest, __tmp_src); \ + } + +#define cv2extractor_list_add_new_xml_node(dest, src) \ + { \ + xmlNode *__tmp_src = src; \ + cv2extractor_list_add_non_null(dest, __tmp_src); \ + } + +#define cv2extractor_list_add_xml_node_list(dest, src) \ + { \ + xmlNode *__tmp_src = xmlCopyNodeList(src); \ + cv2extractor_list_add_non_null(dest, __tmp_src); \ + } + +#define cv2extractor_list_add_new_xml_node_list(dest, src) \ + cv2extractor_list_add_new_xml_node(dest, src) + +#define cv2extractor_list_add_gstrv(dest, src) \ + { \ + GList **__tmp_dest = &(dest); \ + const char **__iter = (const char**)(src); \ + while (__iter && *__iter) { \ + cv2extractor_list_add_string(*__tmp_dest, *__iter); \ + } \ + } + +/* List element removal */ +#define cv2extractor_list_remove_gobject(list, gobject) \ + do { void *__tmp = gobject; GList **__tmp_list = &(list); \ + *__tmp_list = g_list_remove(*__tmp_list, __tmp); \ + cv2extractor_unref(__tmp); } while(0) + +/* Pointer ownership transfer */ + +/* cv2extractor_transfer_xxx macros are like cv2extractor_assign_xxx but they do not increment reference count or + * copy the source value, instead they steal the value (and set the source to NULL, preventing stale + * references). + */ +#define cv2extractor_transfer_full(dest, src, kind) \ + {\ + cv2extractor_release_##kind((dest)); \ + cv2extractor_check_type_equality(dest, src); \ + (dest) = (void*)(src); \ + (src) = NULL; \ + } + +#define cv2extractor_transfer_xpath_object(dest, src) \ + cv2extractor_transfer_full(dest, src, xpath_object) + +#define cv2extractor_transfer_string(dest, src) \ + cv2extractor_transfer_full(dest, src, string) + +#define cv2extractor_transfer_gobject(dest, src) \ + cv2extractor_transfer_full(dest, src, gobject) + +/* Node extraction */ +#define cv2extractor_extract_node_or_fail(to, from, kind, error) \ + {\ + void *__tmp = (from); \ + if (CV2EXTRACTOR_IS_##kind(__tmp)) { \ + to = CV2EXTRACTOR_##kind(__tmp); \ + } else { \ + rc = error; \ + goto cleanup; \ + }\ + } + +/* Bad param handling */ +#define cv2extractor_return_val_if_invalid_param(kind, name, val) \ + g_return_val_if_fail(CV2EXTRACTOR_IS_##kind(name), val) + +#define cv2extractor_bad_param(kind, name) \ + cv2extractor_return_val_if_invalid_param(kind, name, \ + CV2EXTRACTOR_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); + +#define cv2extractor_null_param(name) \ + g_return_val_if_fail(name != NULL, CV2EXTRACTOR_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); + +/** + * cv2extractor_check_non_empty_string: + * @str: a char pointer + * + * Check that @str is non-NULL and not empty, otherwise jump to cleanup and return + * CV2EXTRACTOR_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ. + */ +#define cv2extractor_check_non_empty_string(str) \ + goto_cleanup_if_fail_with_rc(! cv2extractor_strisempty(str), \ + CV2EXTRACTOR_PARAM_ERROR_BAD_TYPE_OR_NULL_OBJ); + +/* + * We extensively use goto operator but in a formalized way, i.e. only for error checking code + * paths. + * + * The next macros goto_cleanup_xxxx encapsulate idioms used in cv2extractor, like checking for a condition + * or setting the return code which must be called 'rc' and be of an 'int' type. + */ + +/* + * The following macros are made to create some formalism for function's cleanup code. + * + * The exit label should be called 'cleanup'. And for functions returning an integer error code, the + * error code should be named 'rc' and 'return rc;' should be the last statement of the function. + */ + +/** + * goto_cleanup_with_rc: + * @rc_value: integer return value + * + * This macro jump to the 'cleanup' label and set the return value to @rc_value. + * + */ +#define goto_cleanup_with_rc(rc_value) \ + do {\ + rc = (rc_value); \ + goto cleanup; \ + } while(0); + +/** + * goto_cleanup_if_fail: + * @condition: a boolean condition + * + * Jump to the 'cleanup' label if the @condition is FALSE. + * + */ +#define goto_cleanup_if_fail(condition) \ + {\ + if (! (condition) ) {\ + goto cleanup; \ + } \ + } + +/** + * goto_cleanup_if_fail_with_rc: + * @condition: a boolean condition + * @rc_value: integer return value + * + * Jump to the 'cleanup' label if the @condition is FALSE and set the return value to + * @rc_value. + * + */ +#define goto_cleanup_if_fail_with_rc(condition, rc_value) \ + {\ + if (! (condition) ) {\ + rc = (rc_value); \ + goto cleanup; \ + } \ + } + +/** + * goto_cleanup_if_fail_with_rc_with_warning: + * @condition: a boolean condition + * @rc_value: integer return value + * + * Jump to the 'cleanup' label if the @condition is FALSE and set the return value to + * @rc_value. Also emit a warning, showing the condition and the return value. + * + */ +#define goto_cleanup_if_fail_with_rc_with_warning(condition, rc_value) \ + {\ + if (! (condition) ) {\ + g_warning("%s failed, returning %s", #condition, #rc_value);\ + rc = (rc_value); \ + goto cleanup; \ + } \ + } + +/** + * goto_cleanup_with_rc_with_critical: + * @message: a critical message + * @rc_value: integer return value + * + * Jump to the 'cleanup' label and set the return value to + * @rc_value. Also emit a critical, showing the message and the return value. + * + */ +#define goto_cleanup_with_rc_with_critical(message, rc_value) \ + {\ + g_critical("%s, returning %s", #message, #rc_value);\ + rc = (rc_value); \ + goto cleanup; \ + } + +/** + * check_good_rc: + * @what: a call to a function returning a cv2extractor error code + * + * Check if return code is 0, if not store it in rc and jump to cleanup label. + */ +#define cv2extractor_check_good_rc(what) \ + { \ + int __rc = (what);\ + goto_cleanup_if_fail_with_rc(__rc == 0, __rc); \ + } + +/*#define cv2extractor_mem_debug(who, what, where) \ + { \ + if (cv2extractor_flag_memory_debug) \ + fprintf(stderr, " freeing %s/%s (at %p)\n", who, what, (void*)where); \ + }*/ + +/** + * cv2extractor_foreach: + * @_iter: a #GList variable, which will server to traverse @_list + * @_list: a #GList value, which we will traverse + * + * Traverse a #GList list using 'for' construct. It must be followed by a block or a statement. + */ +#define cv2extractor_foreach(_iter, _list) \ + for (_iter = (_list); _iter; _iter = g_list_next(_iter)) + +/** + * cv2extractor_foreach_full_begin: + * @_type: the type of the variable @_data + * @_data: the name of the variable to define to store data values + * @_iter: the name of the variable to define to store the iterator + * @_list: the GList* to iterate + * + * Traverse a GList* @_list, using @_iter as iteration variable extract data field to variable + * @_data of type @_type. + */ +#define cv2extractor_foreach_full_begin(_type, _data, _iter, _list) \ + { \ + _type _data = NULL; \ + GList *_iter = NULL; \ + for (_iter = (_list); _iter && ((_data = _iter->data), 1); _iter = g_list_next(_iter)) \ + { + +#define cv2extractor_foreach_full_end() \ + } } + +/** + * cv2extractor_list_get_first_child: + * @list:(allowed-none): a #GList node or NULL. + * + * Return the first child in a list, or NULL. + */ +#define cv2extractor_list_get_first_child(list) \ + ((list) ? (list)->data : NULL) + +/* Get a printable extract for error messages */ +char* cv2extractor_safe_prefix_string(const char *str, gsize length); + +int cv2extractor_gobject_is_of_type(GObject *a, GType b); + +GObject *cv2extractor_extract_gtype_from_list(GType type, GList *list); + +GObject * cv2extractor_extract_gtype_from_list_or_new(GType type, GList **list, gboolean create); + +/* Get first node of this type in a list */ +/* ex: cv2extractor_extract_node (Cv2extractorNode, CV2EXTRACTOR_TYPE_NODE, list) */ +#define cv2extractor_extract_gobject_from_list(type, gobjecttype, list) \ + ((type*) cv2extractor_extract_gtype_from_list(gobjecttype, list)) + +/* + * Simplify simple accessors argument checking. + * + */ +#define cv2extractor_return_val_if_fail(assertion, value) \ + if (!(assertion)) return (value); + +#define cv2extractor_return_null_if_fail(assertion) \ + cv2extractor_return_val_if_fail(assertion, NULL) + +#define cv2extractor_return_if_fail(assertion) \ + if (!(assertion)) return; + +/*#define cv2extractor_trace(args...) \ + if (cv2extractor_flag_memory_debug) { \ + fprintf(stderr, ## args); \ + }*/ + +/* Cv2extractor string data helpers */ +inline static gboolean +cv2extractor_strisequal(const char *a, const char *b) { + return (g_strcmp0(a,b) == 0); +} +inline static gboolean +cv2extractor_strisnotequal(const char *a, const char *b) { + return ! cv2extractor_strisequal(a,b); +} +inline static gboolean +cv2extractor_strisempty(const char *str) { + return ((str) == NULL || (str)[0] == '\0'); +} +/*inline static gboolean +cv2extractor_xmlstrisnotequal(const xmlChar *a, const xmlChar *b) { + return cv2extractor_strisnotequal((char*)a, (char*)b); +}*/ + +#endif /* __CV2EXTRACTOR_UTILS_H__ */