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       {
00049         return (gchar *) str1;
00050       }
00051     }
00052     str1++;
00053   }
00054   return NULL;
00055 }
00056 
00057 #ifndef HAVE_STRCASESTR
00058 /* Search for str2 in str1, ignore case.  Return pointer to first
00059  * match, or null.  */
00060 gchar *
00061 strcasestr(const gchar *str1, const gchar *str2) 
00062 {
00063    size_t len = strlen (str1);
00064    gchar * retval = strncasestr (str1, str2, len);
00065    return retval;
00066 }
00067 #endif
00068 
00069 gint 
00070 safe_strcmp (const gchar * da, const gchar * db)
00071 {
00072         if ((da) && (db)) {
00073                 if ((da) != (db)) {
00074                         gint retval = strcmp ((da), (db));
00075                         /* if strings differ, return */
00076                         if (retval) return retval;
00077                 }     
00078         } else
00079         if ((!(da)) && (db)) {
00080                 return -1;
00081         } else
00082         if ((da) && (!(db))) {
00083                 return +1;
00084         }
00085         return 0;
00086 }
00087 
00088 gint 
00089 safe_strcasecmp (const gchar * da, const gchar * db)
00090 {
00091         if ((da) && (db)) {
00092                 if ((da) != (db)) {
00093                         gint retval = strcasecmp ((da), (db));
00094                         /* if strings differ, return */
00095                         if (retval) return retval;
00096                 }     
00097         } else
00098         if ((!(da)) && (db)) {
00099                 return -1;
00100         } else
00101         if ((da) && (!(db))) {
00102                 return +1;
00103     }
00104    return 0;
00105 }
00106 
00107 gint 
00108 null_strcmp (const gchar * da, const gchar * db)
00109 {
00110    if (da && db) return strcmp (da, db);
00111    if (!da && db && 0==db[0]) return 0;
00112    if (!db && da && 0==da[0]) return 0;
00113    if (!da && db) return -1;
00114    if (da && !db) return +1;
00115    return 0;
00116 }
00117 
00118 #define MAX_DIGITS 50
00119 
00120 /* inverse of strtoul */
00121 gchar *
00122 ultostr (gulong val, gint base)
00123 {
00124   gchar buf[MAX_DIGITS];
00125   gulong broke[MAX_DIGITS];
00126   gint i;
00127   gulong places=0, reval;
00128   
00129   if ((2>base) || (36<base)) return NULL;
00130 
00131   /* count digits */
00132   places = 0;
00133   for (i=0; i<MAX_DIGITS; i++) {
00134      broke[i] = val;
00135      places ++;
00136      val /= base;
00137      if (0 == val) break;
00138   }
00139 
00140   /* normalize */
00141   reval = 0;
00142   for (i=places-2; i>=0; i--) {
00143     reval += broke[i+1];
00144     reval *= base;
00145     broke[i] -= reval;
00146   }
00147 
00148   /* print */
00149   for (i=0; i<(gint)places; i++) {
00150     if (10>broke[i]) {
00151        buf[places-1-i] = 0x30+broke[i];  /* ascii digit zero */
00152     } else {
00153        buf[places-1-i] = 0x41-10+broke[i];  /* ascii capital A */
00154     }
00155   }
00156   buf[places] = 0x0;
00157 
00158   return g_strdup (buf);
00159 }
00160 
00161 /* =================================================================== */
00162 /* returns TRUE if the string is a number, possibly with whitespace */
00163 /* =================================================================== */
00164 
00165 gboolean
00166 gnc_strisnum(const guchar *s)
00167 {
00168   if (s == NULL) return FALSE;
00169   if (*s == 0) return FALSE;
00170 
00171   while (*s && isspace(*s))
00172     s++;
00173 
00174   if (*s == 0) return FALSE;
00175   if (!isdigit(*s)) return FALSE;
00176 
00177   while (*s && isdigit(*s))
00178     s++;
00179 
00180   if (*s == 0) return TRUE;
00181 
00182   while (*s && isspace(*s))
00183     s++;
00184 
00185   if (*s == 0) return TRUE;
00186 
00187   return FALSE;
00188 }
00189 
00190 /* =================================================================== */
00191 /* Return NULL if the field is whitespace (blank, tab, formfeed etc.)  
00192  * Else return pointer to first non-whitespace character. */
00193 /* =================================================================== */
00194 
00195 const gchar *
00196 qof_util_whitespace_filter (const gchar * val)
00197 {
00198         size_t len;
00199         if (!val) return NULL;
00200 
00201         len = strspn (val, "\a\b\t\n\v\f\r ");
00202         if (0 == val[len]) return NULL;
00203         return val+len;
00204 }
00205 
00206 /* =================================================================== */
00207 /* Return integer 1 if the string starts with 't' or 'T' or contains the 
00208  * word 'true' or 'TRUE'; if string is a number, return that number. */
00209 /* =================================================================== */
00210 
00211 gint
00212 qof_util_bool_to_int (const gchar * val)
00213 {
00214         const gchar * p = qof_util_whitespace_filter (val);
00215         if (!p) return 0;
00216         if ('t' == p[0]) return 1;
00217         if ('T' == p[0]) return 1;
00218         if ('y' == p[0]) return 1;
00219         if ('Y' == p[0]) return 1;
00220         if (strstr (p, "true")) return 1;
00221         if (strstr (p, "TRUE")) return 1;
00222         if (strstr (p, "yes")) return 1;
00223         if (strstr (p, "YES")) return 1;
00224         return atoi (val);
00225 }
00226 
00227 /* =================================================================== */
00228 /* Entity edit and commit utilities */
00229 /* =================================================================== */
00230 
00231 gboolean
00232 qof_begin_edit(QofInstance *inst)
00233 {
00234   QofBackend * be;
00235 
00236   if (!inst) { return FALSE; }
00237   (inst->editlevel)++;
00238   if (1 < inst->editlevel) { return FALSE; }
00239   if (0 >= inst->editlevel) { inst->editlevel = 1; }
00240   be = qof_book_get_backend (inst->book);
00241     if (be && qof_backend_begin_exists(be)) {
00242      qof_backend_run_begin(be, inst);
00243   } else { inst->dirty = TRUE; }
00244   return TRUE;
00245 }
00246 
00247 gboolean qof_commit_edit(QofInstance *inst)
00248 {
00249   QofBackend * be;
00250 
00251   if (!inst) { return FALSE; }
00252   (inst->editlevel)--;
00253   if (0 < inst->editlevel) { return FALSE; }
00254   if ((-1 == inst->editlevel) && inst->dirty)
00255   {
00256     be = qof_book_get_backend ((inst)->book);
00257     if (be && qof_backend_begin_exists(be)) {
00258      qof_backend_run_begin(be, inst);
00259     }
00260     inst->editlevel = 0;
00261   }
00262   if (0 > inst->editlevel) { inst->editlevel = 0; }
00263   return TRUE;
00264 }
00265 
00266 
00267 gboolean
00268 qof_commit_edit_part2(QofInstance *inst, 
00269                       void (*on_error)(QofInstance *, QofBackendError), 
00270                       void (*on_done)(QofInstance *), 
00271                       void (*on_free)(QofInstance *)) 
00272 {
00273     QofBackend * be;
00274 
00275     /* See if there's a backend.  If there is, invoke it. */
00276     be = qof_book_get_backend(inst->book);
00277     if (be && qof_backend_commit_exists(be)) {
00278         QofBackendError errcode;
00279         
00280         /* clear errors */
00281         do {
00282             errcode = qof_backend_get_error(be);
00283         } while (ERR_BACKEND_NO_ERR != errcode);
00284 
00285         qof_backend_run_commit(be, inst);
00286         errcode = qof_backend_get_error(be);
00287         if (ERR_BACKEND_NO_ERR != errcode) {
00288             /* XXX Should perform a rollback here */
00289             inst->do_free = FALSE;
00290 
00291             /* Push error back onto the stack */
00292             qof_backend_set_error (be, errcode);
00293             if (on_error)
00294                 on_error(inst, errcode);
00295             return FALSE;
00296         }   
00297         /* XXX the backend commit code should clear dirty!! */
00298         inst->dirty = FALSE;
00299     }
00300     if (inst->do_free) {
00301         if (on_free)
00302             on_free(inst);
00303         return TRUE;
00304     }
00305     if (on_done)
00306         on_done(inst);
00307     return TRUE;
00308 }
00309 
00310 /* =================================================================== */
00311 /* The QOF string cache */
00312 /* =================================================================== */
00313 
00314 static GCache * qof_string_cache = NULL;
00315 
00316 #ifdef THESE_CAN_BE_USEFUL_FOR_DEGUGGING
00317 static guint g_str_hash_KEY(gconstpointer v) {
00318     return g_str_hash(v);
00319 }
00320 static guint g_str_hash_VAL(gconstpointer v) {
00321     return g_str_hash(v);
00322 }
00323 static gpointer g_strdup_VAL(gpointer v) {
00324     return g_strdup(v);
00325 }
00326 static gpointer g_strdup_KEY(gpointer v) {
00327     return g_strdup(v);
00328 }
00329 static void g_free_VAL(gpointer v) {
00330     return g_free(v);
00331 }
00332 static void g_free_KEY(gpointer v) {
00333     return g_free(v);
00334 }
00335 static gboolean qof_util_str_equal(gconstpointer v, gconstpointer v2)
00336 {
00337     return (v && v2) ? g_str_equal(v, v2) : FALSE;
00338 }
00339 #endif
00340 #ifdef QOF_DISABLE_DEPRECATED 
00341 static GCache*
00342 qof_util_get_string_cache(void)
00343 #else
00344 GCache*
00345 qof_util_get_string_cache(void)
00346 #endif    
00347 {
00348     if(!qof_string_cache) {
00349         qof_string_cache = g_cache_new(
00350             (GCacheNewFunc) g_strdup, /* value_new_func     */
00351             g_free,                   /* value_destroy_func */
00352             (GCacheDupFunc) g_strdup, /* key_dup_func       */
00353             g_free,                   /* key_destroy_func   */
00354             g_str_hash,               /* hash_key_func      */
00355             g_str_hash,               /* hash_value_func    */
00356             g_str_equal);             /* key_equal_func     */
00357     }
00358     return qof_string_cache;
00359 }
00360 
00361 void
00362 qof_util_string_cache_destroy (void)
00363 {
00364     if (qof_string_cache)
00365         g_cache_destroy (qof_string_cache);
00366     qof_string_cache = NULL;
00367 }
00368 
00369 void
00370 qof_util_string_cache_remove(gconstpointer key)
00371 {
00372     if (key)
00373     g_cache_remove(qof_util_get_string_cache(), key);
00374 }
00375 
00376 gpointer
00377 qof_util_string_cache_insert(gconstpointer key)
00378 {
00379     if (key)
00380         return g_cache_insert(qof_util_get_string_cache(), (gpointer)key);
00381     return NULL;
00382 }
00383 
00384 gchar*
00385 qof_util_param_as_string(QofEntity *ent, QofParam *param)
00386 {
00387         gchar       *param_string, param_date[MAX_DATE_LENGTH];
00388         gchar       param_sa[GUID_ENCODING_LENGTH + 1];
00389     gboolean    known_type;
00390         QofType     paramType;
00391         const GUID *param_guid;
00392         time_t      param_t;
00393         gnc_numeric param_numeric,  (*numeric_getter) (QofEntity*, QofParam*);
00394         Timespec    param_ts,       (*date_getter)    (QofEntity*, QofParam*);
00395         double      param_double,   (*double_getter)  (QofEntity*, QofParam*);
00396         gboolean    param_boolean,  (*boolean_getter) (QofEntity*, QofParam*);
00397         gint32      param_i32,      (*int32_getter)   (QofEntity*, QofParam*);
00398         gint64      param_i64,      (*int64_getter)   (QofEntity*, QofParam*);
00399         gchar       param_char,     (*char_getter)    (QofEntity*, QofParam*);
00400 
00401         param_string = NULL;
00402     known_type = FALSE;
00403         paramType = param->param_type;
00404         if(safe_strcmp(paramType, QOF_TYPE_STRING) == 0)  { 
00405                         param_string = g_strdup(param->param_getfcn(ent, param));
00406                         if(param_string == NULL) { param_string = ""; }
00407             known_type = TRUE;
00408                         return param_string;
00409                 }
00410                 if(safe_strcmp(paramType, QOF_TYPE_DATE) == 0) { 
00411                         date_getter = (Timespec (*)(QofEntity*, QofParam*))param->param_getfcn;
00412                         param_ts = date_getter(ent, param);
00413                         param_t = timespecToTime_t(param_ts);
00414                         strftime(param_date, MAX_DATE_LENGTH, 
00415                 QOF_UTC_DATE_FORMAT, gmtime(&param_t));
00416                         param_string = g_strdup(param_date);
00417             known_type = TRUE;
00418                         return param_string;
00419                 }
00420                 if((safe_strcmp(paramType, QOF_TYPE_NUMERIC) == 0)  ||
00421                 (safe_strcmp(paramType, QOF_TYPE_DEBCRED) == 0)) { 
00422                         numeric_getter = (gnc_numeric (*)(QofEntity*, QofParam*)) param->param_getfcn;
00423                         param_numeric = numeric_getter(ent, param);
00424                         param_string = g_strdup(gnc_numeric_to_string(param_numeric));
00425             known_type = TRUE;
00426                         return param_string;
00427                 }
00428                 if(safe_strcmp(paramType, QOF_TYPE_GUID) == 0) { 
00429                         param_guid = param->param_getfcn(ent, param);
00430                         guid_to_string_buff(param_guid, param_sa);
00431                         param_string = g_strdup(param_sa);
00432             known_type = TRUE;
00433                         return param_string;
00434                 }
00435                 if(safe_strcmp(paramType, QOF_TYPE_INT32) == 0) { 
00436                         int32_getter = (gint32 (*)(QofEntity*, QofParam*)) param->param_getfcn;
00437                         param_i32 = int32_getter(ent, param);
00438                         param_string = g_strdup_printf("%d", param_i32);
00439             known_type = TRUE;
00440                         return param_string;
00441                 }
00442                 if(safe_strcmp(paramType, QOF_TYPE_INT64) == 0) { 
00443                         int64_getter = (gint64 (*)(QofEntity*, QofParam*)) param->param_getfcn;
00444                         param_i64 = int64_getter(ent, param);
00445                         param_string = g_strdup_printf("%"G_GINT64_FORMAT, param_i64);
00446             known_type = TRUE;
00447                         return param_string;
00448                 }
00449                 if(safe_strcmp(paramType, QOF_TYPE_DOUBLE) == 0) { 
00450                         double_getter = (double (*)(QofEntity*, QofParam*)) param->param_getfcn;
00451                         param_double = double_getter(ent, param);
00452                         param_string = g_strdup_printf("%f", param_double);
00453             known_type = TRUE;
00454                         return param_string;
00455                 }
00456                 if(safe_strcmp(paramType, QOF_TYPE_BOOLEAN) == 0){ 
00457                         boolean_getter = (gboolean (*)(QofEntity*, QofParam*)) param->param_getfcn;
00458                         param_boolean = boolean_getter(ent, param);
00459                         /* Boolean values need to be lowercase for QSF validation. */
00460                         if(param_boolean == TRUE) { param_string = g_strdup("true"); }
00461                         else { param_string = g_strdup("false"); }
00462             known_type = TRUE;
00463                         return param_string;
00464                 }
00465                 /* "kvp" contains repeating values, cannot be a single string for the frame. */
00466                 if(safe_strcmp(paramType, QOF_TYPE_KVP) == 0) {
00467             KvpFrame *frame = NULL;
00468             frame = param->param_getfcn(ent, param);
00469             known_type = TRUE;
00470             if(!kvp_frame_is_empty(frame)) 
00471             {
00472                 GHashTable *hash = kvp_frame_get_hash(frame);
00473                 param_string = g_strdup_printf("%s(%d)", QOF_TYPE_KVP,
00474                     g_hash_table_size(hash));
00475             }
00476             return param_string; 
00477         }
00478                 if(safe_strcmp(paramType, QOF_TYPE_CHAR) == 0) { 
00479                         char_getter = (gchar (*)(QofEntity*, QofParam*)) param->param_getfcn;
00480                         param_char = char_getter(ent, param);
00481             known_type = TRUE;
00482                         return g_strdup_printf("%c", param_char);
00483                 }
00484                 /* "collect" contains repeating values, cannot be a single string. */
00485         if(safe_strcmp(paramType, QOF_TYPE_COLLECT) == 0)
00486         {
00487             QofCollection *col = NULL;
00488             col = param->param_getfcn(ent, param);
00489             known_type = TRUE;
00490             return g_strdup_printf("%s(%d)", 
00491                 qof_collection_get_type(col), qof_collection_count(col));
00492         }
00493         if(safe_strcmp(paramType, QOF_TYPE_CHOICE) == 0)
00494         {
00495             QofEntity *child = NULL;
00496             child = param->param_getfcn(ent, param);
00497             if(!child) { return param_string; }
00498             known_type = TRUE;
00499             return g_strdup(qof_object_printable(child->e_type, child));
00500         }
00501         if(safe_strcmp(paramType, QOF_PARAM_BOOK) == 0)
00502         {
00503             QofBackend *be;
00504             QofBook *book;
00505             book = param->param_getfcn(ent, param);
00506             PINFO (" book param %p", book);
00507             be = qof_book_get_backend(book);
00508             known_type = TRUE;
00509             PINFO (" backend=%p", be);
00510             if(!be) { return QOF_PARAM_BOOK; }
00511             param_string = g_strdup(be->fullpath);
00512             PINFO (" fullpath=%s", param_string);
00513             if(param_string) { return param_string; }
00514                         param_guid = qof_book_get_guid(book);
00515                         guid_to_string_buff(param_guid, param_sa);
00516             PINFO (" book GUID=%s", param_sa);
00517                         param_string = g_strdup(param_sa);
00518             return param_string;
00519         }
00520         if(!known_type)
00521         {
00522             QofEntity *child = NULL;
00523             child = param->param_getfcn(ent, param);
00524             if(!child) { return param_string; }
00525             return g_strdup(qof_object_printable(child->e_type, child));
00526         }
00527         return g_strdup("");
00528 }
00529 
00530 void
00531 qof_init (void)
00532 {
00533         qof_util_get_string_cache ();
00534         guid_init ();
00535         qof_object_initialize ();
00536         qof_query_init ();
00537         qof_book_register ();
00538 }
00539 
00540 void
00541 qof_close(void)
00542 {
00543         qof_query_shutdown ();
00544         qof_object_shutdown ();
00545         guid_shutdown ();
00546         qof_util_string_cache_destroy ();
00547 }
00548 
00549 /* ************************ END OF FILE ***************************** */

Generated on Fri May 12 17:57:21 2006 for QOF by  doxygen 1.4.4