qofutil.c

00001 /********************************************************************\
00002  * qofutil.c -- QOF utility functions                               *
00003  * Copyright (C) 1997 Robin D. Clark                                *
00004  * Copyright (C) 1997-2001,2004 Linas Vepstas <linas@linas.org>     *
00005  * Copyright 2006  Neil Williams  <linux@codehelp.co.uk>            *
00006  *                                                                  *
00007  * This program is free software; you can redistribute it and/or    *
00008  * modify it under the terms of the GNU General Public License as   *
00009  * published by the Free Software Foundation; either version 2 of   *
00010  * the License, or (at your option) any later version.              *
00011  *                                                                  *
00012  * This program is distributed in the hope that it will be useful,  *
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
00015  * GNU General Public License for more details.                     *
00016  *                                                                  *
00017  * You should have received a copy of the GNU General Public License*
00018  * along with this program; if not, contact:                        *
00019  *                                                                  *
00020  * Free Software Foundation           Voice:  +1-617-542-5942       *
00021  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
00022  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
00023  *                                                                  *
00024  *   Author: Rob Clark (rclark@cs.hmc.edu)                          *
00025  *   Author: Linas Vepstas (linas@linas.org)                        *
00026 \********************************************************************/
00027 
00028 #include "config.h"
00029 
00030 #include <ctype.h>
00031 #include <glib.h>
00032 #include <stdlib.h>
00033 #include <string.h>
00034 #include "qof.h"
00035 
00036 static QofLogModule log_module = QOF_MOD_UTIL;
00037 
00038 /* Search for str2 in first nchar chars of str1, ignore case..  Return
00039  * pointer to first match, or null.  */
00040 gchar *
00041 strncasestr (const guchar * str1, const guchar * str2, size_t len)
00042 {
00043     while (*str1 && len--)
00044     {
00045         if (toupper (*str1) == toupper (*str2))
00046         {
00047             if (strncasecmp (str1, str2, strlen (str2)) == 0)
00048                 return (gchar *) str1;
00049         }
00050         str1++;
00051     }
00052     return NULL;
00053 }
00054 
00055 #ifndef HAVE_STRCASESTR
00056 /* Search for str2 in str1, ignore case.  Return pointer to first
00057  * match, or null.  */
00058 gchar *
00059 strcasestr (const gchar * str1, const gchar * str2)
00060 {
00061     size_t len = strlen (str1);
00062     gchar *retval = strncasestr (str1, str2, len);
00063     return retval;
00064 }
00065 #endif
00066 
00067 gint
00068 safe_strcmp (const gchar * da, const gchar * db)
00069 {
00070     if ((da) && (db))
00071     {
00072         if ((da) != (db))
00073         {
00074             gint retval = strcmp ((da), (db));
00075             /* if strings differ, return */
00076             if (retval)
00077                 return retval;
00078         }
00079     }
00080     else if ((!(da)) && (db))
00081         return -1;
00082     else if ((da) && (!(db)))
00083         return +1;
00084     return 0;
00085 }
00086 
00087 gint
00088 safe_strcasecmp (const gchar * da, const gchar * db)
00089 {
00090     if ((da) && (db))
00091     {
00092         if ((da) != (db))
00093         {
00094             gint retval = strcasecmp ((da), (db));
00095             /* if strings differ, return */
00096             if (retval)
00097                 return retval;
00098         }
00099     }
00100     else if ((!(da)) && (db))
00101         return -1;
00102     else if ((da) && (!(db)))
00103         return +1;
00104     return 0;
00105 }
00106 
00107 gint
00108 null_strcmp (const gchar * da, const gchar * db)
00109 {
00110     if (da && db)
00111         return strcmp (da, db);
00112     if (!da && db && 0 == db[0])
00113         return 0;
00114     if (!db && da && 0 == da[0])
00115         return 0;
00116     if (!da && db)
00117         return -1;
00118     if (da && !db)
00119         return +1;
00120     return 0;
00121 }
00122 
00123 #define MAX_DIGITS 50
00124 
00125 /* inverse of strtoul */
00126 gchar *
00127 ultostr (gulong val, gint base)
00128 {
00129     gchar buf[MAX_DIGITS];
00130     gulong broke[MAX_DIGITS];
00131     gint i;
00132     gulong places = 0, reval;
00133 
00134     if ((2 > base) || (36 < base))
00135         return NULL;
00136 
00137     /* count digits */
00138     places = 0;
00139     for (i = 0; i < MAX_DIGITS; i++)
00140     {
00141         broke[i] = val;
00142         places++;
00143         val /= base;
00144         if (0 == val)
00145             break;
00146     }
00147 
00148     /* normalize */
00149     reval = 0;
00150     for (i = places - 2; i >= 0; i--)
00151     {
00152         reval += broke[i + 1];
00153         reval *= base;
00154         broke[i] -= reval;
00155     }
00156 
00157     /* print */
00158     for (i = 0; i < (gint) places; i++)
00159     {
00160         if (10 > broke[i])
00161         {
00162             buf[places - 1 - i] = 0x30 + broke[i];  /* ascii digit zero */
00163         }
00164         else
00165         {
00166             buf[places - 1 - i] = 0x41 - 10 + broke[i]; /* ascii capital A */
00167         }
00168     }
00169     buf[places] = 0x0;
00170 
00171     return g_strdup (buf);
00172 }
00173 
00174 /* =================================================================== */
00175 /* returns TRUE if the string is a number, possibly with whitespace */
00176 /* =================================================================== */
00177 
00178 gboolean
00179 qof_util_string_isnum (const guchar * s)
00180 {
00181     if (s == NULL)
00182         return FALSE;
00183     if (*s == 0)
00184         return FALSE;
00185 
00186     while (*s && isspace (*s))
00187         s++;
00188 
00189     if (*s == 0)
00190         return FALSE;
00191     if (!isdigit (*s))
00192         return FALSE;
00193 
00194     while (*s && isdigit (*s))
00195         s++;
00196 
00197     if (*s == 0)
00198         return TRUE;
00199 
00200     while (*s && isspace (*s))
00201         s++;
00202 
00203     if (*s == 0)
00204         return TRUE;
00205 
00206     return FALSE;
00207 }
00208 
00209 /* =================================================================== */
00210 /* Return NULL if the field is whitespace (blank, tab, formfeed etc.)  
00211  * Else return pointer to first non-whitespace character. */
00212 /* =================================================================== */
00213 
00214 const gchar *
00215 qof_util_whitespace_filter (const gchar * val)
00216 {
00217     size_t len;
00218     if (!val)
00219         return NULL;
00220 
00221     len = strspn (val, "\a\b\t\n\v\f\r ");
00222     if (0 == val[len])
00223         return NULL;
00224     return val + len;
00225 }
00226 
00227 /* =================================================================== */
00228 /* Return integer 1 if the string starts with 't' or 'T' or contains the 
00229  * word 'true' or 'TRUE'; if string is a number, return that number. */
00230 /* =================================================================== */
00231 
00232 gint
00233 qof_util_bool_to_int (const gchar * val)
00234 {
00235     const gchar *p = qof_util_whitespace_filter (val);
00236     if (!p)
00237         return 0;
00238     if ('t' == p[0])
00239         return 1;
00240     if ('T' == p[0])
00241         return 1;
00242     if ('y' == p[0])
00243         return 1;
00244     if ('Y' == p[0])
00245         return 1;
00246     if (strstr (p, "true"))
00247         return 1;
00248     if (strstr (p, "TRUE"))
00249         return 1;
00250     if (strstr (p, "yes"))
00251         return 1;
00252     if (strstr (p, "YES"))
00253         return 1;
00254     return atoi (val);
00255 }
00256 
00257 /* =================================================================== */
00258 /* Entity edit and commit utilities */
00259 /* =================================================================== */
00260 
00261 gboolean
00262 qof_begin_edit (QofInstance * inst)
00263 {
00264     QofBackend *be;
00265 
00266     if (!inst)
00267         return FALSE;
00268     (inst->editlevel)++;
00269     if (1 < inst->editlevel)
00270         return FALSE;
00271     if (0 >= inst->editlevel)
00272         inst->editlevel = 1;
00273     be = qof_book_get_backend (inst->book);
00274     if (be && qof_backend_begin_exists (be))
00275         qof_backend_run_begin (be, inst);
00276     else
00277         inst->dirty = TRUE;
00278     return TRUE;
00279 }
00280 
00281 gboolean
00282 qof_commit_edit (QofInstance * inst)
00283 {
00284     QofBackend *be;
00285 
00286     if (!inst)
00287         return FALSE;
00288     (inst->editlevel)--;
00289     if (0 < inst->editlevel)
00290         return FALSE;
00291     if ((-1 == inst->editlevel) && inst->dirty)
00292     {
00293         be = qof_book_get_backend ((inst)->book);
00294         if (be && qof_backend_begin_exists (be))
00295             qof_backend_run_begin (be, inst);
00296         inst->editlevel = 0;
00297     }
00298     if (0 > inst->editlevel)
00299         inst->editlevel = 0;
00300     return TRUE;
00301 }
00302 
00303 
00304 gboolean
00305 qof_commit_edit_part2 (QofInstance * inst,
00306     void (*on_error) (QofInstance *, QofBackendError),
00307     void (*on_done) (QofInstance *), void (*on_free) (QofInstance *))
00308 {
00309     QofBackend *be;
00310 
00311     /* See if there's a backend.  If there is, invoke it. */
00312     be = qof_book_get_backend (inst->book);
00313     if (be && qof_backend_commit_exists (be))
00314     {
00315         QofBackendError errcode;
00316 
00317         /* clear errors */
00318         do
00319         {
00320             errcode = qof_backend_get_error (be);
00321         }
00322         while (ERR_BACKEND_NO_ERR != errcode);
00323 
00324         qof_backend_run_commit (be, inst);
00325         errcode = qof_backend_get_error (be);
00326         if (ERR_BACKEND_NO_ERR != errcode)
00327         {
00328             /* XXX Should perform a rollback here */
00329             inst->do_free = FALSE;
00330 
00331             /* Push error back onto the stack */
00332             qof_backend_set_error (be, errcode);
00333             if (on_error)
00334                 on_error (inst, errcode);
00335             return FALSE;
00336         }
00337         /* XXX the backend commit code should clear dirty!! */
00338         inst->dirty = FALSE;
00339     }
00340     if (inst->do_free)
00341     {
00342         if (on_free)
00343             on_free (inst);
00344         return TRUE;
00345     }
00346     if (on_done)
00347         on_done (inst);
00348     return TRUE;
00349 }
00350 
00351 /* =================================================================== */
00352 /* The QOF string cache */
00353 /* =================================================================== */
00354 
00355 static GCache *qof_string_cache = NULL;
00356 
00357 #ifdef THESE_CAN_BE_USEFUL_FOR_DEGUGGING
00358 static guint
00359 g_str_hash_KEY (gconstpointer v)
00360 {
00361     return g_str_hash (v);
00362 }
00363 
00364 static guint
00365 g_str_hash_VAL (gconstpointer v)
00366 {
00367     return g_str_hash (v);
00368 }
00369 
00370 static gpointer
00371 g_strdup_VAL (gpointer v)
00372 {
00373     return g_strdup (v);
00374 }
00375 
00376 static gpointer
00377 g_strdup_KEY (gpointer v)
00378 {
00379     return g_strdup (v);
00380 }
00381 static void
00382 g_free_VAL (gpointer v)
00383 {
00384     return g_free (v);
00385 }
00386 static void
00387 g_free_KEY (gpointer v)
00388 {
00389     return g_free (v);
00390 }
00391 
00392 static gboolean
00393 qof_util_str_equal (gconstpointer v, gconstpointer v2)
00394 {
00395     return (v && v2) ? g_str_equal (v, v2) : FALSE;
00396 }
00397 #endif
00398 #ifdef QOF_DISABLE_DEPRECATED
00399 static GCache *
00400 qof_util_get_string_cache (void)
00401 #else
00402 GCache *
00403 qof_util_get_string_cache (void)
00404 #endif
00405 {
00406     if (!qof_string_cache)
00407     {
00408         qof_string_cache = g_cache_new ((GCacheNewFunc) g_strdup,   /* value_new_func     */
00409             g_free,             /* value_destroy_func */
00410             (GCacheDupFunc) g_strdup,   /* key_dup_func       */
00411             g_free,             /* key_destroy_func   */
00412             g_str_hash,         /* hash_key_func      */
00413             g_str_hash,         /* hash_value_func    */
00414             g_str_equal);       /* key_equal_func     */
00415     }
00416     return qof_string_cache;
00417 }
00418 
00419 void
00420 qof_util_string_cache_destroy (void)
00421 {
00422     if (qof_string_cache)
00423         g_cache_destroy (qof_string_cache);
00424     qof_string_cache = NULL;
00425 }
00426 
00427 void
00428 qof_util_string_cache_remove (gconstpointer key)
00429 {
00430     if (key)
00431         g_cache_remove (qof_util_get_string_cache (), key);
00432 }
00433 
00434 gpointer
00435 qof_util_string_cache_insert (gconstpointer key)
00436 {
00437     if (key)
00438         return g_cache_insert (qof_util_get_string_cache (),
00439             (gpointer) key);
00440     return NULL;
00441 }
00442 
00443 gchar *
00444 qof_util_param_as_string (QofEntity * ent, QofParam * param)
00445 {
00446     gchar *param_string;
00447     gchar param_sa[GUID_ENCODING_LENGTH + 1];
00448     gboolean known_type;
00449     QofType paramType;
00450     const GUID *param_guid;
00451     gnc_numeric param_numeric, (*numeric_getter) (QofEntity *, QofParam *);
00452     double param_double, (*double_getter) (QofEntity *, QofParam *);
00453     gboolean param_boolean, (*boolean_getter) (QofEntity *, QofParam *);
00454     gint32 param_i32, (*int32_getter) (QofEntity *, QofParam *);
00455     gint64 param_i64, (*int64_getter) (QofEntity *, QofParam *);
00456     gchar param_char, (*char_getter) (QofEntity *, QofParam *);
00457 
00458     param_string = NULL;
00459     known_type = FALSE;
00460     paramType = param->param_type;
00461     if (safe_strcmp (paramType, QOF_TYPE_STRING) == 0)
00462     {
00463         param_string = g_strdup (param->param_getfcn (ent, param));
00464         if (param_string == NULL)
00465         {
00466             param_string = "";
00467         }
00468         known_type = TRUE;
00469         return param_string;
00470     }
00471     if (safe_strcmp (paramType, QOF_TYPE_TIME) == 0)
00472     {
00473         QofTime *param_qt;
00474         QofDate *qd;
00475         param_qt = param->param_getfcn (ent, param);
00476         qd = qof_date_from_qtime (param_qt);
00477         return qof_date_print (qd, QOF_DATE_FORMAT_UTC);
00478     }
00479 #ifndef QOF_DISABLE_DEPRECATED
00480     if (safe_strcmp (paramType, QOF_TYPE_DATE) == 0)
00481     {
00482         Timespec param_ts, (*date_getter) (QofEntity *, QofParam *);
00483         time_t param_t;
00484         gchar param_date[MAX_DATE_LENGTH];
00485 
00486         date_getter =
00487             (Timespec (*)(QofEntity *, QofParam *)) param->param_getfcn;
00488         param_ts = date_getter (ent, param);
00489         param_t = param_ts.tv_sec;
00490         strftime (param_date, MAX_DATE_LENGTH,
00491             QOF_UTC_DATE_FORMAT, gmtime (&param_t));
00492         param_string = g_strdup (param_date);
00493         known_type = TRUE;
00494         return param_string;
00495     }
00496 #endif
00497     if ((safe_strcmp (paramType, QOF_TYPE_NUMERIC) == 0) ||
00498         (safe_strcmp (paramType, QOF_TYPE_DEBCRED) == 0))
00499     {
00500         numeric_getter =
00501             (gnc_numeric (*)(QofEntity *, QofParam *)) param->param_getfcn;
00502         param_numeric = numeric_getter (ent, param);
00503         param_string = g_strdup (gnc_numeric_to_string (param_numeric));
00504         known_type = TRUE;
00505         return param_string;
00506     }
00507     if (safe_strcmp (paramType, QOF_TYPE_GUID) == 0)
00508     {
00509         param_guid = param->param_getfcn (ent, param);
00510         guid_to_string_buff (param_guid, param_sa);
00511         param_string = g_strdup (param_sa);
00512         known_type = TRUE;
00513         return param_string;
00514     }
00515     if (safe_strcmp (paramType, QOF_TYPE_INT32) == 0)
00516     {
00517         int32_getter =
00518             (gint32 (*)(QofEntity *, QofParam *)) param->param_getfcn;
00519         param_i32 = int32_getter (ent, param);
00520         param_string = g_strdup_printf ("%d", param_i32);
00521         known_type = TRUE;
00522         return param_string;
00523     }
00524     if (safe_strcmp (paramType, QOF_TYPE_INT64) == 0)
00525     {
00526         int64_getter =
00527             (gint64 (*)(QofEntity *, QofParam *)) param->param_getfcn;
00528         param_i64 = int64_getter (ent, param);
00529         param_string = g_strdup_printf ("%" G_GINT64_FORMAT, param_i64);
00530         known_type = TRUE;
00531         return param_string;
00532     }
00533     if (safe_strcmp (paramType, QOF_TYPE_DOUBLE) == 0)
00534     {
00535         double_getter =
00536             (double (*)(QofEntity *, QofParam *)) param->param_getfcn;
00537         param_double = double_getter (ent, param);
00538         param_string = g_strdup_printf ("%f", param_double);
00539         known_type = TRUE;
00540         return param_string;
00541     }
00542     if (safe_strcmp (paramType, QOF_TYPE_BOOLEAN) == 0)
00543     {
00544         boolean_getter =
00545             (gboolean (*)(QofEntity *, QofParam *)) param->param_getfcn;
00546         param_boolean = boolean_getter (ent, param);
00547         /* Boolean values need to be lowercase for QSF validation. */
00548         if (param_boolean == TRUE)
00549         {
00550             param_string = g_strdup ("true");
00551         }
00552         else
00553         {
00554             param_string = g_strdup ("false");
00555         }
00556         known_type = TRUE;
00557         return param_string;
00558     }
00559     /* "kvp" contains repeating values, cannot be a single string for the frame. */
00560     if (safe_strcmp (paramType, QOF_TYPE_KVP) == 0)
00561     {
00562         KvpFrame *frame = NULL;
00563         frame = param->param_getfcn (ent, param);
00564         known_type = TRUE;
00565         if (!kvp_frame_is_empty (frame))
00566         {
00567             GHashTable *hash = kvp_frame_get_hash (frame);
00568             param_string = g_strdup_printf ("%s(%d)", QOF_TYPE_KVP,
00569                 g_hash_table_size (hash));
00570         }
00571         return param_string;
00572     }
00573     if (safe_strcmp (paramType, QOF_TYPE_CHAR) == 0)
00574     {
00575         char_getter =
00576             (gchar (*)(QofEntity *, QofParam *)) param->param_getfcn;
00577         param_char = char_getter (ent, param);
00578         known_type = TRUE;
00579         return g_strdup_printf ("%c", param_char);
00580     }
00581     /* "collect" contains repeating values, cannot be a single string. */
00582     if (safe_strcmp (paramType, QOF_TYPE_COLLECT) == 0)
00583     {
00584         QofCollection *col = NULL;
00585         col = param->param_getfcn (ent, param);
00586         known_type = TRUE;
00587         return g_strdup_printf ("%s(%d)",
00588             qof_collection_get_type (col), qof_collection_count (col));
00589     }
00590     if (safe_strcmp (paramType, QOF_TYPE_CHOICE) == 0)
00591     {
00592         QofEntity *child = NULL;
00593         child = param->param_getfcn (ent, param);
00594         if (!child)
00595         {
00596             return param_string;
00597         }
00598         known_type = TRUE;
00599         return g_strdup (qof_object_printable (child->e_type, child));
00600     }
00601     if (safe_strcmp (paramType, QOF_PARAM_BOOK) == 0)
00602     {
00603         QofBackend *be;
00604         QofBook *book;
00605         book = param->param_getfcn (ent, param);
00606         PINFO (" book param %p", book);
00607         be = qof_book_get_backend (book);
00608         known_type = TRUE;
00609         PINFO (" backend=%p", be);
00610         if (!be)
00611         {
00612             return QOF_PARAM_BOOK;
00613         }
00614         param_string = g_strdup (be->fullpath);
00615         PINFO (" fullpath=%s", param_string);
00616         if (param_string)
00617         {
00618             return param_string;
00619         }
00620         param_guid = qof_entity_get_guid ((QofEntity*)book);
00621         guid_to_string_buff (param_guid, param_sa);
00622         PINFO (" book GUID=%s", param_sa);
00623         param_string = g_strdup (param_sa);
00624         return param_string;
00625     }
00626     if (!known_type)
00627     {
00628         QofEntity *child = NULL;
00629         child = param->param_getfcn (ent, param);
00630         if (!child)
00631         {
00632             return param_string;
00633         }
00634         return g_strdup (qof_object_printable (child->e_type, child));
00635     }
00636     return g_strdup ("");
00637 }
00638 
00639 void
00640 qof_init (void)
00641 {
00642     qof_util_get_string_cache ();
00643     guid_init ();
00644     qof_date_init ();
00645     qof_object_initialize ();
00646     qof_query_init ();
00647     qof_book_register ();
00648 }
00649 
00650 void
00651 qof_close (void)
00652 {
00653     qof_query_shutdown ();
00654     qof_object_shutdown ();
00655     guid_shutdown ();
00656     qof_date_close ();
00657     qof_util_string_cache_destroy ();
00658 }
00659 
00660 /* ************************ END OF FILE ***************************** */

Generated on Fri Sep 1 15:13:11 2006 for QOF by  doxygen 1.4.7