[Gnucash-changes] r13745 - gnucash/trunk/lib/libqof/qof - Replace gnc-engine-util with qofutil

Neil Williams codehelp at cvs.gnucash.org
Fri Apr 7 14:49:13 EDT 2006


Author: codehelp
Date: 2006-04-07 14:49:12 -0400 (Fri, 07 Apr 2006)
New Revision: 13745
Trac: http://svn.gnucash.org/trac/changeset/13745

Added:
   gnucash/trunk/lib/libqof/qof/qofutil.c
   gnucash/trunk/lib/libqof/qof/qofutil.h
Removed:
   gnucash/trunk/lib/libqof/qof/gnc-engine-util.c
   gnucash/trunk/lib/libqof/qof/gnc-engine-util.h
Modified:
   gnucash/trunk/lib/libqof/qof/Makefile.am
   gnucash/trunk/lib/libqof/qof/qof.h
Log:
Replace gnc-engine-util with qofutil

Modified: gnucash/trunk/lib/libqof/qof/Makefile.am
===================================================================
--- gnucash/trunk/lib/libqof/qof/Makefile.am	2006-04-07 15:53:52 UTC (rev 13744)
+++ gnucash/trunk/lib/libqof/qof/Makefile.am	2006-04-07 18:49:12 UTC (rev 13745)
@@ -12,7 +12,6 @@
 libqof_la_SOURCES =  \
    deprecated.c      \
    gnc-date.c        \
-   gnc-engine-util.c \
    gnc-numeric.c     \
    guid.c            \
    kvp_frame.c       \
@@ -30,6 +29,7 @@
    qofobject.c       \
    qofquerycore.c    \
    qofreference.c    \
+   qofutil.c         \
    qofsession.c      \
    qofbookmerge.c
 
@@ -38,14 +38,12 @@
 qofinclude_HEADERS = \
    deprecated.h      \
    gnc-date.h        \
-   gnc-engine-util.h \
    gnc-numeric.h     \
    guid.h            \
    kvp_frame.h       \
    kvp-util.h        \
    kvp-util-p.h      \
    qof.h             \
-   qof-be-utils.h    \
    qofbackend.h      \
    qofbackend-p.h    \
    qofclass.h        \
@@ -64,6 +62,7 @@
    qofreference.h    \
    qofsession.h      \
    qofsql.h          \
+   qofutil.h         \
    qofbookmerge.h
 
 nodist_qofinclude_HEADERS = \

Deleted: gnucash/trunk/lib/libqof/qof/gnc-engine-util.c
===================================================================
--- gnucash/trunk/lib/libqof/qof/gnc-engine-util.c	2006-04-07 15:53:52 UTC (rev 13744)
+++ gnucash/trunk/lib/libqof/qof/gnc-engine-util.c	2006-04-07 18:49:12 UTC (rev 13745)
@@ -1,312 +0,0 @@
-/********************************************************************\
- * gnc-engine-util.c -- QOF utility functions                       *
- * Copyright (C) 1997 Robin D. Clark                                *
- * Copyright (C) 1997-2001,2004 Linas Vepstas <linas at linas.org>     *
- *                                                                  *
- * 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, contact:                        *
- *                                                                  *
- * Free Software Foundation           Voice:  +1-617-542-5942       *
- * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
- * Boston, MA  02110-1301,  USA       gnu at gnu.org                   *
- *                                                                  *
- *   Author: Rob Clark (rclark at cs.hmc.edu)                          *
- *   Author: Linas Vepstas (linas at linas.org)                        *
-\********************************************************************/
-
-#include "config.h"
-
-#include <ctype.h>
-#include <glib.h>
-#include <stdlib.h>
-#include <string.h>
-#include "qof.h"
-#include "gnc-engine-util.h"
-
-
-/********************************************************************\
-\********************************************************************/
-
-/* Search for str2 in first nchar chars of str1, ignore case..  Return
- * pointer to first match, or null.  */
-char *
-strncasestr(const unsigned char *str1, const unsigned char *str2, size_t len) 
-{
-  while (*str1 && len--) 
-  {
-    if (toupper(*str1) == toupper(*str2)) 
-    {
-      if (strncasecmp(str1,str2,strlen(str2)) == 0) 
-      {
-        return (char *) str1;
-      }
-    }
-    str1++;
-  }
-  return NULL;
-}
-
-/* Search for str2 in str1, ignore case.  Return pointer to first
- * match, or null.  */
-char *
-strcasestr(const char *str1, const char *str2) 
-{
-   size_t len = strlen (str1);
-   char * retval = strncasestr (str1, str2, len);
-   return retval;
-}
-
-/********************************************************************\
-\********************************************************************/
-
-int 
-safe_strcmp (const char * da, const char * db)
-{
-   SAFE_STRCMP (da, db);
-   return 0;
-}
-
-int 
-safe_strcasecmp (const char * da, const char * db)
-{
-   SAFE_STRCASECMP (da, db);
-   return 0;
-}
-
-int 
-null_strcmp (const char * da, const char * db)
-{
-   if (da && db) return strcmp (da, db);
-   if (!da && db && 0==db[0]) return 0;
-   if (!db && da && 0==da[0]) return 0;
-   if (!da && db) return -1;
-   if (da && !db) return +1;
-   return 0;
-}
-
-/********************************************************************\
-\********************************************************************/
-
-#define MAX_DIGITS 50
-
-/* inverse of strtoul */
-char *
-ultostr (unsigned long val, int base)
-{
-  char buf[MAX_DIGITS];
-  unsigned long broke[MAX_DIGITS];
-  int i;
-  unsigned long places=0, reval;
-  
-  if ((2>base) || (36<base)) return NULL;
-
-  /* count digits */
-  places = 0;
-  for (i=0; i<MAX_DIGITS; i++) {
-     broke[i] = val;
-     places ++;
-     val /= base;
-     if (0 == val) break;
-  }
-
-  /* normalize */
-  reval = 0;
-  for (i=places-2; i>=0; i--) {
-    reval += broke[i+1];
-    reval *= base;
-    broke[i] -= reval;
-  }
-
-  /* print */
-  for (i=0; i<(int)places; i++) {
-    if (10>broke[i]) {
-       buf[places-1-i] = 0x30+broke[i];  /* ascii digit zero */
-    } else {
-       buf[places-1-i] = 0x41-10+broke[i];  /* ascii capital A */
-    }
-  }
-  buf[places] = 0x0;
-
-  return g_strdup (buf);
-}
-
-/********************************************************************\
- * returns TRUE if the string is a number, possibly with whitespace
-\********************************************************************/
-
-gboolean
-gnc_strisnum(const unsigned char *s)
-{
-  if (s == NULL) return FALSE;
-  if (*s == 0) return FALSE;
-
-  while (*s && isspace(*s))
-    s++;
-
-  if (*s == 0) return FALSE;
-  if (!isdigit(*s)) return FALSE;
-
-  while (*s && isdigit(*s))
-    s++;
-
-  if (*s == 0) return TRUE;
-
-  while (*s && isspace(*s))
-    s++;
-
-  if (*s == 0) return TRUE;
-
-  return FALSE;
-}
-
-/********************************************************************\
- * our own version of stpcpy
-\********************************************************************/
-
-char *
-gnc_stpcpy (char *dest, const char *src)
-{
-  strcpy (dest, src);
-  return (dest + strlen (src));
-}
-
-/* =================================================================== */
-/* Return NULL if the field is whitespace (blank, tab, formfeed etc.)  
- * Else return pointer to first non-whitespace character. */
-
-const char *
-qof_util_whitespace_filter (const char * val)
-{
-	size_t len;
-	if (!val) return NULL;
-
-	len = strspn (val, "\a\b\t\n\v\f\r ");
-	if (0 == val[len]) return NULL;
-	return val+len;
-}
-
-/* =================================================================== */
-/* Return integer 1 if the string starts with 't' or 'T' or contains the 
- * word 'true' or 'TRUE'; if string is a number, return that number. */
-
-int
-qof_util_bool_to_int (const char * val)
-{
-	const char * p = qof_util_whitespace_filter (val);
-	if (!p) return 0;
-	if ('t' == p[0]) return 1;
-	if ('T' == p[0]) return 1;
-	if ('y' == p[0]) return 1;
-	if ('Y' == p[0]) return 1;
-	if (strstr (p, "true")) return 1;
-	if (strstr (p, "TRUE")) return 1;
-	if (strstr (p, "yes")) return 1;
-	if (strstr (p, "YES")) return 1;
-	return atoi (val);
-}
-
-/********************************************************************\
- * The engine string cache
-\********************************************************************/
-
-static GCache * gnc_string_cache = NULL;
-
-#ifdef THESE_CAN_BE_USEFUL_FOR_DEGUGGING
-static guint g_str_hash_KEY(gconstpointer v) {
-    return g_str_hash(v);
-}
-static guint g_str_hash_VAL(gconstpointer v) {
-    return g_str_hash(v);
-}
-static gpointer g_strdup_VAL(gpointer v) {
-    return g_strdup(v);
-}
-static gpointer g_strdup_KEY(gpointer v) {
-    return g_strdup(v);
-}
-static void g_free_VAL(gpointer v) {
-    return g_free(v);
-}
-static void g_free_KEY(gpointer v) {
-    return g_free(v);
-}
-static gboolean gnc_str_equal(gconstpointer v, gconstpointer v2)
-{
-    return (v && v2) ? g_str_equal(v, v2) : FALSE;
-}
-#endif
-
-GCache*
-gnc_engine_get_string_cache(void)
-{
-    if(!gnc_string_cache) {
-        gnc_string_cache = g_cache_new(
-            (GCacheNewFunc) g_strdup, /* value_new_func     */
-            g_free,                   /* value_destroy_func */
-            (GCacheDupFunc) g_strdup, /* key_dup_func       */
-            g_free,                   /* key_destroy_func   */
-            g_str_hash,               /* hash_key_func      */
-            g_str_hash,               /* hash_value_func    */
-            g_str_equal);             /* key_equal_func     */
-    }
-    return gnc_string_cache;
-}
-
-void
-gnc_engine_string_cache_destroy (void)
-{
-    if (gnc_string_cache)
-        g_cache_destroy (gnc_string_cache);
-    gnc_string_cache = NULL;
-}
-
-void
-gnc_string_cache_remove(gconstpointer key)
-{
-    if (key) 
-        g_cache_remove(gnc_engine_get_string_cache(), key);
-}
-
-/* TODO: It would be better if this returned gpointerconst.  The
-   returned strings really should be treated as const.  Callers must
-   not modify them. */
-gpointer
-gnc_string_cache_insert(gconstpointer key)
-{
-    if (key) 
-        return g_cache_insert(gnc_engine_get_string_cache(), (gpointer)key);
-    return NULL;
-}
-
-void
-qof_init (void)
-{
-	gnc_engine_get_string_cache ();
-	guid_init ();
-	qof_object_initialize ();
-	qof_query_init ();
-	qof_book_register ();
-}
-
-void
-qof_close(void)
-{
-	qof_query_shutdown ();
-	qof_object_shutdown ();
-	guid_shutdown ();
-	gnc_engine_string_cache_destroy ();
-}
-
-
-/************************* END OF FILE ******************************\
-\********************************************************************/

Deleted: gnucash/trunk/lib/libqof/qof/gnc-engine-util.h
===================================================================
--- gnucash/trunk/lib/libqof/qof/gnc-engine-util.h	2006-04-07 15:53:52 UTC (rev 13744)
+++ gnucash/trunk/lib/libqof/qof/gnc-engine-util.h	2006-04-07 18:49:12 UTC (rev 13745)
@@ -1,326 +0,0 @@
-/********************************************************************\
- * gnc-engine-util.h -- QOF utility functions                       *
- *                                                                  *
- * 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, contact:                        *
- *                                                                  *
- * Free Software Foundation           Voice:  +1-617-542-5942       *
- * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
- * Boston, MA  02110-1301,  USA       gnu at gnu.org                   *
-\********************************************************************/
-
-/** @addtogroup Utilities
-    @{ */
-/** @file gnc-engine-util.h 
-    @brief QOF utility functions
-	(This file is due to be renamed qofutil.h in libqof2.
-	It will remain as a placeholder during libqof1.)
-    @author Copyright (C) 1997 Robin D. Clark <rclark at cs.hmc.edu>
-    @author Copyright (C) 2000 Bill Gribble <grib at billgribble.com>
-    @author Copyright (C) 1997-2002,2004 Linas Vepstas <linas at linas.org>
-*/
-
-#ifndef QOF_UTIL_H
-#define QOF_UTIL_H
-
-#include <glib.h>
-#include <stddef.h>
-#include "qof.h"
-
-/* Macros *****************************************************/
-
-/** \deprecated Use the function versions, safe_strcmp() and
-safe_strcasecmp(). These macros will be made private in libqof2.
-
-If the pointer arguments are equal, the macro does nothing and
-safe_strcmp / safe_strcasecmp return 0.
-
-These macros change program control flow and are not good 
-substitutes for the function equivalents.
-*/
-#define SAFE_STRCMP_REAL(fcn,da,db) {    \
-  if ((da) && (db)) {                    \
-    if ((da) != (db)) {                  \
-      int retval = fcn ((da), (db));     \
-      /* if strings differ, return */    \
-      if (retval) return retval;         \
-    }                                    \
-  } else                                 \
-  if ((!(da)) && (db)) {                 \
-    return -1;                           \
-  } else                                 \
-  if ((da) && (!(db))) {                 \
-    return +1;                           \
-  }                                      \
-}
-
-/** \deprecated use safe_strcmp() */
-#define SAFE_STRCMP(da,db) SAFE_STRCMP_REAL(strcmp,(da),(db))
-/** \deprecated use safe_strcasecmp() */
-#define SAFE_STRCASECMP(da,db) SAFE_STRCMP_REAL(strcasecmp,(da),(db))
-
-/** \name typedef enum as string macros
-@{
-*/
-#define ENUM_BODY(name, value)           \
-    name value,
-
-#define AS_STRING_CASE(name, value)      \
-    case name: { return #name; }
-
-#define FROM_STRING_CASE(name, value)    \
-    if (strcmp(str, #name) == 0) {       \
-        return name;  }
-
-#define DEFINE_ENUM(name, list)          \
-    typedef enum {                       \
-        list(ENUM_BODY)                  \
-    }name;
-
-#define AS_STRING_DEC(name, list)        \
-    const char* name##asString(name n);
-
-#define AS_STRING_FUNC(name, list)       \
-    const char* name##asString(name n) { \
-        switch (n) {                     \
-            list(AS_STRING_CASE)         \
-            default: return "";  } }
-
-#define FROM_STRING_DEC(name, list)      \
-    name name##fromString                \
-    (const char* str);
-
-#define FROM_STRING_FUNC(name, list)     \
-    name name##fromString                \
-    (const char* str) {                  \
-    if(str == NULL) { return 0; }        \
-        list(FROM_STRING_CASE)           \
-        return 0;  }
-
-/** @} */
-
-/** \name enum as string with no typedef
-@{
-
-  Similar but used when the enum is NOT a typedef
-  Make sure you use the DEFINE_ENUM_NON_TYPEDEF macro.
-
- You can precede the FROM_STRING_FUNC_NON_TYPEDEF 
- and AS_STRING_FUNC_NON_TYPEDEF macros with the 
- keyword static if appropriate.
-  
- ENUM_BODY is used in both types.
- */
-
-#define DEFINE_ENUM_NON_TYPEDEF(name, list)   \
-    enum name {                               \
-        list(ENUM_BODY)                       \
-    };
-
-#define FROM_STRING_DEC_NON_TYPEDEF(name, list)   \
-   void name##fromString                          \
-   (const char* str, enum name *type);
-
-#define FROM_STRING_CASE_NON_TYPEDEF(name, value) \
-   if (strcmp(str, #name) == 0) { *type = name; }
-
-#define FROM_STRING_FUNC_NON_TYPEDEF(name, list)  \
-   void name##fromString                          \
-   (const char* str, enum name *type) {           \
-   if(str == NULL) { return; }                    \
-    list(FROM_STRING_CASE_NON_TYPEDEF) }
-
-#define AS_STRING_DEC_NON_TYPEDEF(name, list)     \
-   const char* name##asString(enum name n);
-
-#define AS_STRING_FUNC_NON_TYPEDEF(name, list)    \
-   const char* name##asString(enum name n) {      \
-       switch (n) {                               \
-           list(AS_STRING_CASE_NON_TYPEDEF)       \
-           default: return ""; } }
-
-#define AS_STRING_CASE_NON_TYPEDEF(name, value)   \
-   case name: { return #name; }
-
-/** @} */
-
-/** \deprecated Define the long long int conversion for scanf 
- * HAVE_SCANF_LLD will be removed from libqof2
- * */
-#if HAVE_SCANF_LLD
-# define GNC_SCANF_LLD "%lld" /**< \deprecated 
-	use G_GINT64_FORMAT instead. */
-#else
-# define GNC_SCANF_LLD "%qd"  /**< \deprecated */
-#endif
-
-/** @name Convenience wrappers
-   @{
-*/
-   
-/** \brief Initialise the Query Object Framework 
-
-Use in place of separate init functions (like guid_init()
-and qof_query_init() etc.) to protect against future changes.
-*/
-void qof_init (void);
-
-/** \brief Safely close down the Query Object Framework 
-
-Use in place of separate close / shutdown functions 
-(like guid_shutdown(), qof_query_shutdown() etc.) to protect
-against future changes.
-*/
-void qof_close (void);
-
-/** @} */
-
-/* **** Prototypes *********************************************/
-
-/** The safe_strcmp compares strings da and db the same way that strcmp()
- does, except that either may be null.  This routine assumes that
- a non-null string is always greater than a null string.
- 
- @param da string 1.
- @param db string 2.
- 
- @return If da == NULL && db != NULL, returns -1.
-         If da != NULL && db == NULL, returns +1.
-         If da != NULL && db != NULL, returns the result of 
-                   strcmp(da, db).
-         If da == NULL && db == NULL, returns 0. 
-*/
-int safe_strcmp (const char * da, const char * db);
-
-/** case sensitive comparison of strings da and db - either
-may be NULL. A non-NULL string is greater than a NULL string.
- 
- @param da string 1.
- @param db string 2.
- 
- @return If da == NULL && db != NULL, returns -1.
-         If da != NULL && db == NULL, returns +1.
-         If da != NULL && db != NULL, returns the result of 
-                   strcmp(da, db).
-         If da == NULL && db == NULL, returns 0. 
-*/
-int safe_strcasecmp (const char * da, const char * db);
-
-/** The null_strcmp compares strings a and b the same way that strcmp()
- * does, except that either may be null.  This routine assumes that
- * a null string is equal to the empty string.
- */
-int null_strcmp (const char * da, const char * db);
-
-/** Search for str2 in first nchar chars of str1, ignore case. Return
- * pointer to first match, or null. These are just like that strnstr
- * and the strstr functions, except that they ignore the case. */
-extern char *strncasestr(const unsigned char *str1, const unsigned char *str2, 
-	size_t len);
-extern char *strcasestr(const char *str1, const char *str2);
-
-/** The ultostr() subroutine is the inverse of strtoul(). It accepts a
- * number and prints it in the indicated base.  The returned string
- * should be g_freed when done.  */
-char * ultostr (unsigned long val, int base);
-
-/** Returns true if string s is a number, possibly surrounded by
- * whitespace. */
-gboolean gnc_strisnum(const unsigned char *s);
-
-/** Local copy of stpcpy, used wtih libc's that don't have one. */
-char * gnc_stpcpy (char *dest, const char *src);
-
-#ifndef HAVE_STPCPY
-#define stpcpy gnc_stpcpy
-#endif
-
-/** Return NULL if the field is whitespace (blank, tab, formfeed etc.)  
- *  Else return pointer to first non-whitespace character. 
- */
-const char * qof_util_whitespace_filter (const char * val);
-
-/** Return integer 1 if the string starts with 't' or 'T' or 
- *  contains the word 'true' or 'TRUE'; if string is a number, 
- *  return that number. (Leading whitespace is ignored). */
-int qof_util_bool_to_int (const char * val);
-
-
-/** The QOF String Cache:
- *
- * Many strings used throughout QOF and QOF applications are likely to
- * be duplicated.
- *
- * QOF provides a reference counted cache system for the strings, which
- * shares strings whenever possible.
- *
- * Use gnc_string_cache_insert to insert a string into the cache (it
- * will return a pointer to the cached string).  Basically you should
- * use this instead of g_strdup.
- *
- * Use gnc_string_cache_remove (giving it a pointer to a cached
- * string) if the string is unused.  If this is the last reference to
- * the string it will be removed from the cache, otherwise it will
- * just decrement the reference count.  Basically you should use this
- * instead of g_free.
- *
- * Just in case it's not clear: The remove function must NOT be called
- * for the string you passed INTO the insert function.  It must be
- * called for the _cached_ string that is _returned_ by the insert
- * function.
- *
- * Note that all the work is done when inserting or removing.  Once
- * cached the strings are just plain C strings.
- *
- * The string cache is demand-created on first use.
- *
- **/
-
-/** \deprecated use qof_init instead.
-
-Get the gnc_string_cache.  Create it if it doesn't exist already.
-*/
-GCache* gnc_engine_get_string_cache(void);
-
-/** Destroy the gnc_string_cache */
-void gnc_engine_string_cache_destroy (void);
-
-/** You can use this function as a destroy notifier for a GHashTable
-   that uses common strings as keys (or values, for that matter.)
-*/
-void gnc_string_cache_remove(gconstpointer key);
-
-/** You can use this function with g_hash_table_insert(), for the key
-   (or value), as long as you use the destroy notifier above.
-*/
-gpointer gnc_string_cache_insert(gconstpointer key);
-
-#define CACHE_INSERT(str) gnc_string_cache_insert((gconstpointer)(str))
-#define CACHE_REMOVE(str) gnc_string_cache_remove((str))
-
-/* Replace cached string currently in 'dst' with string in 'src'.
- * Typical usage:
- *     void foo_set_name(Foo *f, const char *str) {
- *        CACHE_REPLACE(f->name, str);
- *     }
- * It avoids unnecessary ejection by doing INSERT before REMOVE.
-*/
-#define CACHE_REPLACE(dst, src) do {               \
-        gpointer tmp = CACHE_INSERT((src));        \
-        CACHE_REMOVE((dst));                       \
-        (dst) = tmp;                               \
-    } while (0)
-
-
-#endif /* QOF_UTIL_H */
-/** @} */

Modified: gnucash/trunk/lib/libqof/qof/qof.h
===================================================================
--- gnucash/trunk/lib/libqof/qof/qof.h	2006-04-07 15:53:52 UTC (rev 13744)
+++ gnucash/trunk/lib/libqof/qof/qof.h	2006-04-07 18:49:12 UTC (rev 13745)
@@ -80,7 +80,7 @@
 #include "qoflog.h"
 #include "gnc-date.h"
 #include "gnc-numeric.h"
-#include "gnc-engine-util.h"
+#include "qofutil.h"
 #include "guid.h"
 #include "kvp_frame.h"
 #include "kvp-util.h"
@@ -98,7 +98,6 @@
 #include "qofsql.h"
 #include "qofchoice.h"
 #include "qofbookmerge.h"
-#include "qof-be-utils.h"
 #include "qofreference.h"
 #include "qofla-dir.h"
 #include "deprecated.h"

Copied: gnucash/trunk/lib/libqof/qof/qofutil.c (from rev 13729, gnucash/trunk/lib/libqof/qof/gnc-engine-util.c)
===================================================================
--- gnucash/trunk/lib/libqof/qof/gnc-engine-util.c	2006-04-03 18:34:45 UTC (rev 13729)
+++ gnucash/trunk/lib/libqof/qof/qofutil.c	2006-04-07 18:49:12 UTC (rev 13745)
@@ -0,0 +1,547 @@
+/********************************************************************\
+ * qofutil.c -- QOF utility functions                               *
+ * Copyright (C) 1997 Robin D. Clark                                *
+ * Copyright (C) 1997-2001,2004 Linas Vepstas <linas at linas.org>     *
+ * Copyright 2006  Neil Williams  <linux at codehelp.co.uk>            *
+ *                                                                  *
+ * 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, contact:                        *
+ *                                                                  *
+ * Free Software Foundation           Voice:  +1-617-542-5942       *
+ * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
+ * Boston, MA  02110-1301,  USA       gnu at gnu.org                   *
+ *                                                                  *
+ *   Author: Rob Clark (rclark at cs.hmc.edu)                          *
+ *   Author: Linas Vepstas (linas at linas.org)                        *
+\********************************************************************/
+
+#include "config.h"
+
+#include <ctype.h>
+#include <glib.h>
+#include <stdlib.h>
+#include <string.h>
+#include "qof.h"
+
+static QofLogModule log_module = QOF_MOD_UTIL;
+
+/* Search for str2 in first nchar chars of str1, ignore case..  Return
+ * pointer to first match, or null.  */
+gchar *
+strncasestr(const guchar *str1, const guchar *str2, size_t len) 
+{
+  while (*str1 && len--) 
+  {
+    if (toupper(*str1) == toupper(*str2)) 
+    {
+      if (strncasecmp(str1,str2,strlen(str2)) == 0) 
+      {
+        return (gchar *) str1;
+      }
+    }
+    str1++;
+  }
+  return NULL;
+}
+
+/* Search for str2 in str1, ignore case.  Return pointer to first
+ * match, or null.  */
+gchar *
+strcasestr(const gchar *str1, const gchar *str2) 
+{
+   size_t len = strlen (str1);
+   gchar * retval = strncasestr (str1, str2, len);
+   return retval;
+}
+
+gint 
+safe_strcmp (const gchar * da, const gchar * db)
+{
+	if ((da) && (db)) {
+		if ((da) != (db)) {
+			gint retval = strcmp ((da), (db));
+			/* if strings differ, return */
+			if (retval) return retval;
+		}     
+	} else
+	if ((!(da)) && (db)) {
+		return -1;
+	} else
+	if ((da) && (!(db))) {
+		return +1;
+	}
+	return 0;
+}
+
+gint 
+safe_strcasecmp (const gchar * da, const gchar * db)
+{
+	if ((da) && (db)) {
+		if ((da) != (db)) {
+			gint retval = strcasecmp ((da), (db));
+			/* if strings differ, return */
+			if (retval) return retval;
+		}     
+	} else
+	if ((!(da)) && (db)) {
+		return -1;
+	} else
+	if ((da) && (!(db))) {
+		return +1;
+    }
+   return 0;
+}
+
+gint 
+null_strcmp (const gchar * da, const gchar * db)
+{
+   if (da && db) return strcmp (da, db);
+   if (!da && db && 0==db[0]) return 0;
+   if (!db && da && 0==da[0]) return 0;
+   if (!da && db) return -1;
+   if (da && !db) return +1;
+   return 0;
+}
+
+#define MAX_DIGITS 50
+
+/* inverse of strtoul */
+gchar *
+ultostr (gulong val, gint base)
+{
+  gchar buf[MAX_DIGITS];
+  gulong broke[MAX_DIGITS];
+  gint i;
+  gulong places=0, reval;
+  
+  if ((2>base) || (36<base)) return NULL;
+
+  /* count digits */
+  places = 0;
+  for (i=0; i<MAX_DIGITS; i++) {
+     broke[i] = val;
+     places ++;
+     val /= base;
+     if (0 == val) break;
+  }
+
+  /* normalize */
+  reval = 0;
+  for (i=places-2; i>=0; i--) {
+    reval += broke[i+1];
+    reval *= base;
+    broke[i] -= reval;
+  }
+
+  /* print */
+  for (i=0; i<(gint)places; i++) {
+    if (10>broke[i]) {
+       buf[places-1-i] = 0x30+broke[i];  /* ascii digit zero */
+    } else {
+       buf[places-1-i] = 0x41-10+broke[i];  /* ascii capital A */
+    }
+  }
+  buf[places] = 0x0;
+
+  return g_strdup (buf);
+}
+
+/* =================================================================== */
+/* returns TRUE if the string is a number, possibly with whitespace */
+/* =================================================================== */
+
+gboolean
+gnc_strisnum(const guchar *s)
+{
+  if (s == NULL) return FALSE;
+  if (*s == 0) return FALSE;
+
+  while (*s && isspace(*s))
+    s++;
+
+  if (*s == 0) return FALSE;
+  if (!isdigit(*s)) return FALSE;
+
+  while (*s && isdigit(*s))
+    s++;
+
+  if (*s == 0) return TRUE;
+
+  while (*s && isspace(*s))
+    s++;
+
+  if (*s == 0) return TRUE;
+
+  return FALSE;
+}
+
+/* =================================================================== */
+/* Return NULL if the field is whitespace (blank, tab, formfeed etc.)  
+ * Else return pointer to first non-whitespace character. */
+/* =================================================================== */
+
+const gchar *
+qof_util_whitespace_filter (const gchar * val)
+{
+	size_t len;
+	if (!val) return NULL;
+
+	len = strspn (val, "\a\b\t\n\v\f\r ");
+	if (0 == val[len]) return NULL;
+	return val+len;
+}
+
+/* =================================================================== */
+/* Return integer 1 if the string starts with 't' or 'T' or contains the 
+ * word 'true' or 'TRUE'; if string is a number, return that number. */
+/* =================================================================== */
+
+gint
+qof_util_bool_to_int (const gchar * val)
+{
+	const gchar * p = qof_util_whitespace_filter (val);
+	if (!p) return 0;
+	if ('t' == p[0]) return 1;
+	if ('T' == p[0]) return 1;
+	if ('y' == p[0]) return 1;
+	if ('Y' == p[0]) return 1;
+	if (strstr (p, "true")) return 1;
+	if (strstr (p, "TRUE")) return 1;
+	if (strstr (p, "yes")) return 1;
+	if (strstr (p, "YES")) return 1;
+	return atoi (val);
+}
+
+/* =================================================================== */
+/* Entity edit and commit utilities */
+/* =================================================================== */
+
+gboolean
+qof_begin_edit(QofInstance *inst)
+{
+  QofBackend * be;
+
+  if (!inst) { return FALSE; }
+  (inst->editlevel)++;
+  if (1 < inst->editlevel) { return FALSE; }
+  if (0 >= inst->editlevel) { inst->editlevel = 1; }
+  be = qof_book_get_backend (inst->book);
+    if (be && qof_backend_begin_exists(be)) {
+     qof_backend_run_begin(be, inst);
+  } else { inst->dirty = TRUE; }
+  return TRUE;
+}
+
+gboolean qof_commit_edit(QofInstance *inst)
+{
+  QofBackend * be;
+
+  if (!inst) { return FALSE; }
+  (inst->editlevel)--;
+  if (0 < inst->editlevel) { return FALSE; }
+  if ((-1 == inst->editlevel) && inst->dirty)
+  {
+    be = qof_book_get_backend ((inst)->book);
+    if (be && qof_backend_begin_exists(be)) {
+     qof_backend_run_begin(be, inst);
+    }
+    inst->editlevel = 0;
+  }
+  if (0 > inst->editlevel) { inst->editlevel = 0; }
+  return TRUE;
+}
+
+
+gboolean
+qof_commit_edit_part2(QofInstance *inst, 
+                      void (*on_error)(QofInstance *, QofBackendError), 
+                      void (*on_done)(QofInstance *), 
+                      void (*on_free)(QofInstance *)) 
+{
+    QofBackend * be;
+
+    /* See if there's a backend.  If there is, invoke it. */
+    be = qof_book_get_backend(inst->book);
+    if (be && qof_backend_commit_exists(be)) {
+        QofBackendError errcode;
+        
+        /* clear errors */
+        do {
+            errcode = qof_backend_get_error(be);
+        } while (ERR_BACKEND_NO_ERR != errcode);
+
+        qof_backend_run_commit(be, inst);
+        errcode = qof_backend_get_error(be);
+        if (ERR_BACKEND_NO_ERR != errcode) {
+            /* XXX Should perform a rollback here */
+            inst->do_free = FALSE;
+
+            /* Push error back onto the stack */
+            qof_backend_set_error (be, errcode);
+            if (on_error)
+                on_error(inst, errcode);
+            return FALSE;
+        }   
+        /* XXX the backend commit code should clear dirty!! */
+        inst->dirty = FALSE;
+    }
+    if (inst->do_free) {
+        if (on_free)
+            on_free(inst);
+        return TRUE;
+    }
+    if (on_done)
+        on_done(inst);
+    return TRUE;
+}
+
+/* =================================================================== */
+/* The QOF string cache */
+/* =================================================================== */
+
+static GCache * qof_string_cache = NULL;
+
+#ifdef THESE_CAN_BE_USEFUL_FOR_DEGUGGING
+static guint g_str_hash_KEY(gconstpointer v) {
+    return g_str_hash(v);
+}
+static guint g_str_hash_VAL(gconstpointer v) {
+    return g_str_hash(v);
+}
+static gpointer g_strdup_VAL(gpointer v) {
+    return g_strdup(v);
+}
+static gpointer g_strdup_KEY(gpointer v) {
+    return g_strdup(v);
+}
+static void g_free_VAL(gpointer v) {
+    return g_free(v);
+}
+static void g_free_KEY(gpointer v) {
+    return g_free(v);
+}
+static gboolean qof_util_str_equal(gconstpointer v, gconstpointer v2)
+{
+    return (v && v2) ? g_str_equal(v, v2) : FALSE;
+}
+#endif
+#ifdef QOF_DISABLE_DEPRECATED 
+static GCache*
+qof_util_get_string_cache(void)
+#else
+GCache*
+qof_util_get_string_cache(void)
+#endif    
+{
+    if(!qof_string_cache) {
+        qof_string_cache = g_cache_new(
+            (GCacheNewFunc) g_strdup, /* value_new_func     */
+            g_free,                   /* value_destroy_func */
+            (GCacheDupFunc) g_strdup, /* key_dup_func       */
+            g_free,                   /* key_destroy_func   */
+            g_str_hash,               /* hash_key_func      */
+            g_str_hash,               /* hash_value_func    */
+            g_str_equal);             /* key_equal_func     */
+    }
+    return qof_string_cache;
+}
+
+void
+qof_util_string_cache_destroy (void)
+{
+    if (qof_string_cache)
+        g_cache_destroy (qof_string_cache);
+    qof_string_cache = NULL;
+}
+
+void
+qof_util_string_cache_remove(gconstpointer key)
+{
+    if (key)
+    g_cache_remove(qof_util_get_string_cache(), key);
+}
+
+gpointer
+qof_util_string_cache_insert(gconstpointer key)
+{
+    if (key)
+        return g_cache_insert(qof_util_get_string_cache(), (gpointer)key);
+    return NULL;
+}
+
+gchar*
+qof_util_param_as_string(QofEntity *ent, QofParam *param)
+{
+	gchar       *param_string, param_date[MAX_DATE_LENGTH];
+	gchar       param_sa[GUID_ENCODING_LENGTH + 1];
+    gboolean    known_type;
+	QofType     paramType;
+	const GUID *param_guid;
+	time_t      param_t;
+	gnc_numeric param_numeric,  (*numeric_getter) (QofEntity*, QofParam*);
+	Timespec    param_ts,       (*date_getter)    (QofEntity*, QofParam*);
+	double      param_double,   (*double_getter)  (QofEntity*, QofParam*);
+	gboolean    param_boolean,  (*boolean_getter) (QofEntity*, QofParam*);
+	gint32      param_i32,      (*int32_getter)   (QofEntity*, QofParam*);
+	gint64      param_i64,      (*int64_getter)   (QofEntity*, QofParam*);
+	gchar       param_char,     (*char_getter)    (QofEntity*, QofParam*);
+
+	param_string = NULL;
+    known_type = FALSE;
+	paramType = param->param_type;
+	if(safe_strcmp(paramType, QOF_TYPE_STRING) == 0)  { 
+			param_string = g_strdup(param->param_getfcn(ent, param));
+			if(param_string == NULL) { param_string = ""; }
+            known_type = TRUE;
+			return param_string;
+		}
+		if(safe_strcmp(paramType, QOF_TYPE_DATE) == 0) { 
+			date_getter = (Timespec (*)(QofEntity*, QofParam*))param->param_getfcn;
+			param_ts = date_getter(ent, param);
+			param_t = timespecToTime_t(param_ts);
+			strftime(param_date, MAX_DATE_LENGTH, 
+                QOF_UTC_DATE_FORMAT, gmtime(&param_t));
+			param_string = g_strdup(param_date);
+            known_type = TRUE;
+			return param_string;
+		}
+		if((safe_strcmp(paramType, QOF_TYPE_NUMERIC) == 0)  ||
+		(safe_strcmp(paramType, QOF_TYPE_DEBCRED) == 0)) { 
+			numeric_getter = (gnc_numeric (*)(QofEntity*, QofParam*)) param->param_getfcn;
+			param_numeric = numeric_getter(ent, param);
+			param_string = g_strdup(gnc_numeric_to_string(param_numeric));
+            known_type = TRUE;
+			return param_string;
+		}
+		if(safe_strcmp(paramType, QOF_TYPE_GUID) == 0) { 
+			param_guid = param->param_getfcn(ent, param);
+			guid_to_string_buff(param_guid, param_sa);
+			param_string = g_strdup(param_sa);
+            known_type = TRUE;
+			return param_string;
+		}
+		if(safe_strcmp(paramType, QOF_TYPE_INT32) == 0) { 
+			int32_getter = (gint32 (*)(QofEntity*, QofParam*)) param->param_getfcn;
+			param_i32 = int32_getter(ent, param);
+			param_string = g_strdup_printf("%d", param_i32);
+            known_type = TRUE;
+			return param_string;
+		}
+		if(safe_strcmp(paramType, QOF_TYPE_INT64) == 0) { 
+			int64_getter = (gint64 (*)(QofEntity*, QofParam*)) param->param_getfcn;
+			param_i64 = int64_getter(ent, param);
+			param_string = g_strdup_printf("%"G_GINT64_FORMAT, param_i64);
+            known_type = TRUE;
+			return param_string;
+		}
+		if(safe_strcmp(paramType, QOF_TYPE_DOUBLE) == 0) { 
+			double_getter = (double (*)(QofEntity*, QofParam*)) param->param_getfcn;
+			param_double = double_getter(ent, param);
+			param_string = g_strdup_printf("%f", param_double);
+            known_type = TRUE;
+			return param_string;
+		}
+		if(safe_strcmp(paramType, QOF_TYPE_BOOLEAN) == 0){ 
+			boolean_getter = (gboolean (*)(QofEntity*, QofParam*)) param->param_getfcn;
+			param_boolean = boolean_getter(ent, param);
+			/* Boolean values need to be lowercase for QSF validation. */
+			if(param_boolean == TRUE) { param_string = g_strdup("true"); }
+			else { param_string = g_strdup("false"); }
+            known_type = TRUE;
+			return param_string;
+		}
+		/* "kvp" contains repeating values, cannot be a single string for the frame. */
+		if(safe_strcmp(paramType, QOF_TYPE_KVP) == 0) {
+            KvpFrame *frame = NULL;
+            frame = param->param_getfcn(ent, param);
+            known_type = TRUE;
+            if(!kvp_frame_is_empty(frame)) 
+            {
+                GHashTable *hash = kvp_frame_get_hash(frame);
+                param_string = g_strdup_printf("%s(%d)", QOF_TYPE_KVP,
+                    g_hash_table_size(hash));
+            }
+            return param_string; 
+        }
+		if(safe_strcmp(paramType, QOF_TYPE_CHAR) == 0) { 
+			char_getter = (gchar (*)(QofEntity*, QofParam*)) param->param_getfcn;
+			param_char = char_getter(ent, param);
+            known_type = TRUE;
+			return g_strdup_printf("%c", param_char);
+		}
+		/* "collect" contains repeating values, cannot be a single string. */
+        if(safe_strcmp(paramType, QOF_TYPE_COLLECT) == 0)
+        {
+            QofCollection *col = NULL;
+            col = param->param_getfcn(ent, param);
+            known_type = TRUE;
+            return g_strdup_printf("%s(%d)", 
+                qof_collection_get_type(col), qof_collection_count(col));
+        }
+        if(safe_strcmp(paramType, QOF_TYPE_CHOICE) == 0)
+        {
+            QofEntity *child = NULL;
+            child = param->param_getfcn(ent, param);
+            if(!child) { return param_string; }
+            known_type = TRUE;
+            return g_strdup(qof_object_printable(child->e_type, child));
+        }
+        if(safe_strcmp(paramType, QOF_PARAM_BOOK) == 0)
+        {
+            QofBackend *be;
+            QofBook *book;
+            book = param->param_getfcn(ent, param);
+            PINFO (" book param %p", book);
+            be = qof_book_get_backend(book);
+            known_type = TRUE;
+            PINFO (" backend=%p", be);
+            if(!be) { return QOF_PARAM_BOOK; }
+            param_string = g_strdup(be->fullpath);
+            PINFO (" fullpath=%s", param_string);
+            if(param_string) { return param_string; }
+			param_guid = qof_book_get_guid(book);
+			guid_to_string_buff(param_guid, param_sa);
+            PINFO (" book GUID=%s", param_sa);
+			param_string = g_strdup(param_sa);
+            return param_string;
+        }
+        if(!known_type)
+        {
+            QofEntity *child = NULL;
+            child = param->param_getfcn(ent, param);
+            if(!child) { return param_string; }
+            return g_strdup(qof_object_printable(child->e_type, child));
+        }
+	return g_strdup("");
+}
+
+void
+qof_init (void)
+{
+	qof_util_get_string_cache ();
+	guid_init ();
+	qof_object_initialize ();
+	qof_query_init ();
+	qof_book_register ();
+}
+
+void
+qof_close(void)
+{
+	qof_query_shutdown ();
+	qof_object_shutdown ();
+	guid_shutdown ();
+	qof_util_string_cache_destroy ();
+}
+
+/* ************************ END OF FILE ***************************** */

Copied: gnucash/trunk/lib/libqof/qof/qofutil.h (from rev 13729, gnucash/trunk/lib/libqof/qof/gnc-engine-util.h)
===================================================================
--- gnucash/trunk/lib/libqof/qof/gnc-engine-util.h	2006-04-03 18:34:45 UTC (rev 13729)
+++ gnucash/trunk/lib/libqof/qof/qofutil.h	2006-04-07 18:49:12 UTC (rev 13745)
@@ -0,0 +1,443 @@
+/********************************************************************\
+ * qof-util.h -- QOF utility functions                              *
+ *                                                                  *
+ * 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, contact:                        *
+ *                                                                  *
+ * Free Software Foundation           Voice:  +1-617-542-5942       *
+ * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
+ * Boston, MA  02110-1301,  USA       gnu at gnu.org                   *
+\********************************************************************/
+
+/** @addtogroup Utilities
+    @{ */
+/** @file qof-util.h 
+    @brief QOF utility functions
+    @author Copyright (C) 1997 Robin D. Clark <rclark at cs.hmc.edu>
+    @author Copyright (C) 2000 Bill Gribble <grib at billgribble.com>
+    @author Copyright (C) 1997-2002,2004 Linas Vepstas <linas at linas.org>
+    @author Copyright 2006  Neil Williams  <linux at codehelp.co.uk>
+*/
+
+#ifndef QOF_UTIL_H
+#define QOF_UTIL_H
+
+#include <stddef.h>
+#include "qof.h"
+#include "qoflog.h"
+#include "qofutil.h"
+#include "qofbackend-p.h"
+#include "qofbook.h"
+#include "qofinstance.h"
+
+#define QOF_MOD_UTIL "qof-utilities"
+
+/** \name typedef enum as string macros
+@{
+*/
+#define ENUM_BODY(name, value)           \
+    name value,
+
+#define AS_STRING_CASE(name, value)      \
+    case name: { return #name; }
+
+#define FROM_STRING_CASE(name, value)    \
+    if (strcmp(str, #name) == 0) {       \
+        return name;  }
+
+#define DEFINE_ENUM(name, list)          \
+    typedef enum {                       \
+        list(ENUM_BODY)                  \
+    }name;
+
+#define AS_STRING_DEC(name, list)        \
+    const gchar* name##asString(name n);
+
+#define AS_STRING_FUNC(name, list)        \
+    const gchar* name##asString(name n) { \
+        switch (n) {                      \
+            list(AS_STRING_CASE)          \
+            default: return "";  } }
+
+#define FROM_STRING_DEC(name, list)      \
+    name name##fromString                \
+    (const gchar* str);
+
+#define FROM_STRING_FUNC(name, list)     \
+    name name##fromString                \
+    (const gchar* str) {                 \
+    if(str == NULL) { return 0; }        \
+        list(FROM_STRING_CASE)           \
+        return 0;  }
+
+/** @} */
+
+/** \name enum as string with no typedef
+@{
+
+  Similar but used when the enum is NOT a typedef
+  Make sure you use the DEFINE_ENUM_NON_TYPEDEF macro.
+
+ You can precede the FROM_STRING_FUNC_NON_TYPEDEF 
+ and AS_STRING_FUNC_NON_TYPEDEF macros with the 
+ keyword static if appropriate.
+  
+ ENUM_BODY is used in both types.
+ */
+
+#define DEFINE_ENUM_NON_TYPEDEF(name, list)   \
+    enum name {                               \
+        list(ENUM_BODY)                       \
+    };
+
+#define FROM_STRING_DEC_NON_TYPEDEF(name, list)   \
+   void name##fromString                          \
+   (const gchar* str, enum name *type);
+
+#define FROM_STRING_CASE_NON_TYPEDEF(name, value) \
+   if (strcmp(str, #name) == 0) { *type = name; }
+
+#define FROM_STRING_FUNC_NON_TYPEDEF(name, list)  \
+   void name##fromString                          \
+   (const gchar* str, enum name *type) {          \
+   if(str == NULL) { return; }                    \
+    list(FROM_STRING_CASE_NON_TYPEDEF) }
+
+#define AS_STRING_DEC_NON_TYPEDEF(name, list)     \
+   const gchar* name##asString(enum name n);
+
+#define AS_STRING_FUNC_NON_TYPEDEF(name, list)    \
+   const gchar* name##asString(enum name n) {     \
+       switch (n) {                               \
+           list(AS_STRING_CASE_NON_TYPEDEF)       \
+           default: return ""; } }
+
+#define AS_STRING_CASE_NON_TYPEDEF(name, value)   \
+   case name: { return #name; }
+
+/** @} */
+
+/** @name Convenience wrappers
+   @{
+*/
+   
+/** \brief Initialise the Query Object Framework 
+
+Use in place of separate init functions (like guid_init()
+and qof_query_init() etc.) to protect against future changes.
+*/
+void qof_init (void);
+
+/** \brief Safely close down the Query Object Framework 
+
+Use in place of separate close / shutdown functions 
+(like guid_shutdown(), qof_query_shutdown() etc.) to protect
+against future changes.
+*/
+void qof_close (void);
+
+/** @} */
+
+/* **** Prototypes *********************************************/
+
+/** The safe_strcmp compares strings da and db the same way that strcmp()
+ does, except that either may be null.  This routine assumes that
+ a non-null string is always greater than a null string.
+ 
+ @param da string 1.
+ @param db string 2.
+ 
+ @return If da == NULL && db != NULL, returns -1.
+         If da != NULL && db == NULL, returns +1.
+         If da != NULL && db != NULL, returns the result of 
+                   strcmp(da, db).
+         If da == NULL && db == NULL, returns 0. 
+*/
+gint safe_strcmp (const gchar * da, const gchar * db);
+
+/** case sensitive comparison of strings da and db - either
+may be NULL. A non-NULL string is greater than a NULL string.
+ 
+ @param da string 1.
+ @param db string 2.
+ 
+ @return If da == NULL && db != NULL, returns -1.
+         If da != NULL && db == NULL, returns +1.
+         If da != NULL && db != NULL, returns the result of 
+                   strcmp(da, db).
+         If da == NULL && db == NULL, returns 0. 
+*/
+gint safe_strcasecmp (const gchar * da, const gchar * db);
+
+/** The null_strcmp compares strings a and b the same way that strcmp()
+ * does, except that either may be null.  This routine assumes that
+ * a null string is equal to the empty string.
+ */
+gint null_strcmp (const gchar * da, const gchar * db);
+
+/** Search for str2 in first nchar chars of str1, ignore case. Return
+ * pointer to first match, or null. These are just like that strnstr
+ * and the strstr functions, except that they ignore the case. */
+extern gchar *strncasestr(const guchar *str1, const guchar *str2, 
+	size_t len);
+extern gchar *strcasestr(const gchar *str1, const gchar *str2);
+
+/** The ultostr() subroutine is the inverse of strtoul(). It accepts a
+ * number and prints it in the indicated base.  The returned string
+ * should be g_freed when done.  */
+gchar * ultostr (gulong val, gint base);
+
+/** Returns true if string s is a number, possibly surrounded by
+ * whitespace. */
+gboolean gnc_strisnum(const guchar *s);
+
+#ifndef HAVE_STPCPY
+#define stpcpy g_stpcpy
+#endif
+
+/** Return NULL if the field is whitespace (blank, tab, formfeed etc.)  
+ *  Else return pointer to first non-whitespace character. 
+ */
+const gchar * qof_util_whitespace_filter (const gchar * val);
+
+/** Return integer 1 if the string starts with 't' or 'T' or 
+ *  contains the word 'true' or 'TRUE'; if string is a number, 
+ *  return that number. (Leading whitespace is ignored). */
+gint qof_util_bool_to_int (const gchar * val);
+
+/** \brief Converts a parameter to a printable string.
+
+The returned string must be freed by the caller.
+*/
+gchar* qof_util_param_as_string(QofEntity *ent, QofParam *param);
+
+/** The QOF String Cache:
+ *
+ * Many strings used throughout QOF and QOF applications are likely to
+ * be duplicated.
+ *
+ * QOF provides a reference counted cache system for the strings, which
+ * shares strings whenever possible.
+ *
+ * Use qof_util_string_cache_insert to insert a string into the cache (it
+ * will return a pointer to the cached string).  Basically you should
+ * use this instead of g_strdup.
+ *
+ * Use qof_util_string_cache_remove (giving it a pointer to a cached
+ * string) if the string is unused.  If this is the last reference to
+ * the string it will be removed from the cache, otherwise it will
+ * just decrement the reference count.  Basically you should use this
+ * instead of g_free.
+ *
+ * Just in case it's not clear: The remove function must NOT be called
+ * for the string you passed INTO the insert function.  It must be
+ * called for the _cached_ string that is _returned_ by the insert
+ * function.
+ *
+ * Note that all the work is done when inserting or removing.  Once
+ * cached the strings are just plain C strings.
+ *
+ * The string cache is demand-created on first use.
+ *
+ **/
+/** Destroy the qof_util_string_cache */
+void qof_util_string_cache_destroy (void);
+
+/** You can use this function as a destroy notifier for a GHashTable
+   that uses common strings as keys (or values, for that matter.)
+*/
+void qof_util_string_cache_remove(gconstpointer key);
+
+/** You can use this function with g_hash_table_insert(), for the key
+   (or value), as long as you use the destroy notifier above.
+*/
+gpointer qof_util_string_cache_insert(gconstpointer key);
+
+#define CACHE_INSERT(str) qof_util_string_cache_insert((gconstpointer)(str))
+#define CACHE_REMOVE(str) qof_util_string_cache_remove((str))
+
+/* Replace cached string currently in 'dst' with string in 'src'.
+ * Typical usage:
+ *     void foo_set_name(Foo *f, const char *str) {
+ *        CACHE_REPLACE(f->name, str);
+ *     }
+ * It avoids unnecessary ejection by doing INSERT before REMOVE.
+*/
+#define CACHE_REPLACE(dst, src) do {          \
+        gpointer tmp = CACHE_INSERT((src));   \
+        CACHE_REMOVE((dst));                  \
+        (dst) = tmp;                          \
+    } while (0)
+
+#define QOF_CACHE_NEW(void) qof_util_string_cache_insert("")
+
+/** begin_edit helper
+ *
+ * @param  inst: an instance of QofInstance
+ *
+ * The caller should use this macro first and then perform any other operations.
+ 
+ Uses newly created functions to allow the macro to be used
+ when QOF is linked as a library. qofbackend-p.h is a private header.
+ */
+
+#define QOF_BEGIN_EDIT(inst)                                        \
+  if (!(inst)) return;                                              \
+                                                                    \
+  (inst)->editlevel++;                                              \
+  if (1 < (inst)->editlevel) return;                                \
+                                                                    \
+  if (0 >= (inst)->editlevel)                                       \
+  {                                                                 \
+    PERR ("unbalanced call - resetting (was %d)", (inst)->editlevel); \
+    (inst)->editlevel = 1;                                          \
+  }                                                                 \
+  ENTER ("(inst=%p)", (inst));                                      \
+                                                                    \
+  /* See if there's a backend.  If there is, invoke it. */          \
+  {                                                                 \
+    QofBackend * be;                                                \
+    be = qof_book_get_backend ((inst)->book);                       \
+      if (be && qof_backend_begin_exists(be)) {                     \
+         qof_backend_run_begin(be, (inst));                         \
+    } else {                                                        \
+      /* We tried and failed to start transaction! */               \
+      (inst)->dirty = TRUE;                                         \
+    }                                                               \
+  }                                                                 \
+  LEAVE (" ");
+
+/** \brief function version of QOF_BEGIN_EDIT
+
+The macro cannot be used in a function that returns a value,
+this function can be used instead.
+*/
+gboolean qof_begin_edit(QofInstance *inst);
+
+/**
+ * commit_edit helpers
+ *
+ * The caller should call PART1 as the first thing, then 
+ * perform any local operations prior to calling the backend.
+ * Then call PART2.  
+ */
+
+/**
+ * part1 -- deal with the editlevel
+ * 
+ * @param inst: an instance of QofInstance
+ */
+
+#define QOF_COMMIT_EDIT_PART1(inst) {                            \
+  if (!(inst)) return;                                           \
+                                                                 \
+  (inst)->editlevel--;                                           \
+  if (0 < (inst)->editlevel) return;                             \
+                                                                 \
+  /* The pricedb suffers from delayed update...     */          \
+  /* This may be setting a bad precedent for other types, I fear. */ \
+  /* Other types probably really should handle begin like this. */ \
+  if ((-1 == (inst)->editlevel) && (inst)->dirty)                \
+  {                                                              \
+    QofBackend * be;                                             \
+    be = qof_book_get_backend ((inst)->book);                    \
+    if (be && qof_backend_begin_exists(be)) {                    \
+      qof_backend_run_begin(be, (inst));                         \
+    }                                                            \
+    (inst)->editlevel = 0;                                       \
+  }                                                              \
+  if (0 > (inst)->editlevel)                                     \
+  {                                                              \
+    PERR ("unbalanced call - resetting (was %d)", (inst)->editlevel); \
+    (inst)->editlevel = 0;                                       \
+  }                                                              \
+  ENTER ("(inst=%p) dirty=%d do-free=%d",                        \
+            (inst), (inst)->dirty, (inst)->do_free);             \
+}
+
+/** \brief function version of QOF_COMMIT_EDIT_PART1
+
+The macro cannot be used in a function that returns a value,
+this function can be used instead. Only Part1 is implemented.
+*/
+gboolean qof_commit_edit(QofInstance *inst);
+
+/**
+ * part2 -- deal with the backend
+ * 
+ * @param inst: an instance of QofInstance
+ * @param on_error: a function called if there is a backend error.
+ *                void (*on_error)(inst, QofBackendError)
+ * @param on_done: a function called after the commit is completed 
+ *                successfully for an object which remained valid.
+ *                void (*on_done)(inst)
+ * @param on_free: a function called if the commit succeeded and the instance
+ *                 is to be freed. 
+ *                void (*on_free)(inst)
+ * 
+ * Note that only *one* callback will be called (or zero, if that
+ * callback is NULL).  In particular, 'on_done' will not be called for
+ * an object which is to be freed.
+ *
+ * Returns TRUE, if the commit succeeded, FALSE otherwise.
+ */
+gboolean
+qof_commit_edit_part2(QofInstance *inst, 
+                      void (*on_error)(QofInstance *, QofBackendError), 
+                      void (*on_done)(QofInstance *), 
+                      void (*on_free)(QofInstance *));
+
+/** \brief Macro version of ::qof_commit_edit_part2
+
+\note This macro changes programme flow if the instance is freed.
+*/
+#define QOF_COMMIT_EDIT_PART2(inst,on_error,on_done,on_free) {   \
+  QofBackend * be;                                               \
+                                                                 \
+  /* See if there's a backend.  If there is, invoke it. */       \
+  be = qof_book_get_backend ((inst)->book);                      \
+  if (be && qof_backend_commit_exists(be))                       \
+  {                                                              \
+    QofBackendError errcode;                                     \
+                                                                 \
+    /* clear errors */                                           \
+    do {                                                         \
+      errcode = qof_backend_get_error (be);                      \
+    } while (ERR_BACKEND_NO_ERR != errcode);                     \
+                                                                 \
+    qof_backend_run_commit(be, (inst));                          \
+    errcode = qof_backend_get_error (be);                        \
+    if (ERR_BACKEND_NO_ERR != errcode)                           \
+    {                                                            \
+      /* XXX Should perform a rollback here */                   \
+      (inst)->do_free = FALSE;                                   \
+                                                                 \
+      /* Push error back onto the stack */                       \
+      qof_backend_set_error (be, errcode);                       \
+      (on_error)((inst), errcode);                               \
+    }                                                            \
+    /* XXX the backend commit code should clear dirty!! */       \
+    (inst)->dirty = FALSE;                                       \
+  }                                                              \
+  (on_done)(inst);                                               \
+                                                                 \
+  LEAVE ("inst=%p, dirty=%d do-free=%d",                         \
+            (inst), (inst)->dirty, (inst)->do_free);             \
+  if ((inst)->do_free) {                                         \
+     (on_free)(inst);                                            \
+     return;                                                     \
+  }                                                              \
+}
+    
+#endif /* QOF_UTIL_H */
+/** @} */



More information about the gnucash-changes mailing list