00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "config.h"
00029
00030 #include <errno.h>
00031 #include <ctype.h>
00032 #include <glib.h>
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include <math.h>
00036 #include "qof.h"
00037 #include "qofundo-p.h"
00038 #include "qofbook-p.h"
00039
00040 static QofLogModule log_module = QOF_MOD_UTIL;
00041
00042
00043
00044 gchar *
00045 strncasestr (const guchar * str1, const guchar * str2, size_t len)
00046 {
00047 while (*str1 && len--)
00048 {
00049 if (toupper (*str1) == toupper (*str2))
00050 {
00051 if (strncasecmp (str1, str2, strlen (str2)) == 0)
00052 return (gchar *) str1;
00053 }
00054 str1++;
00055 }
00056 return NULL;
00057 }
00058
00059 #ifndef HAVE_STRCASESTR
00060
00061
00062 gchar *
00063 strcasestr (const gchar * str1, const gchar * str2)
00064 {
00065 size_t len = strlen (str1);
00066 gchar *retval = strncasestr (str1, str2, len);
00067 return retval;
00068 }
00069 #endif
00070
00071 gint
00072 safe_strcmp (const gchar * da, const gchar * db)
00073 {
00074 if ((da) && (db))
00075 {
00076 if ((da) != (db))
00077 {
00078 gint retval = strcmp ((da), (db));
00079
00080 if (retval)
00081 return retval;
00082 }
00083 }
00084 else if ((!(da)) && (db))
00085 return -1;
00086 else if ((da) && (!(db)))
00087 return +1;
00088 return 0;
00089 }
00090
00091 gint
00092 safe_strcasecmp (const gchar * da, const gchar * db)
00093 {
00094 if ((da) && (db))
00095 {
00096 if ((da) != (db))
00097 {
00098 gint retval = strcasecmp ((da), (db));
00099
00100 if (retval)
00101 return retval;
00102 }
00103 }
00104 else if ((!(da)) && (db))
00105 return -1;
00106 else if ((da) && (!(db)))
00107 return +1;
00108 return 0;
00109 }
00110
00111 inline gint
00112 null_strcmp (const gchar * da, const gchar * db)
00113 {
00114 if (da && db)
00115 return strcmp (da, db);
00116 if (!da && db && 0 == db[0])
00117 return 0;
00118 if (!db && da && 0 == da[0])
00119 return 0;
00120 if (!da && db)
00121 return -1;
00122 if (da && !db)
00123 return +1;
00124 return 0;
00125 }
00126
00127 #define MAX_DIGITS 50
00128
00129
00130 gchar *
00131 ultostr (gulong val, gint base)
00132 {
00133 gchar buf[MAX_DIGITS];
00134 gulong broke[MAX_DIGITS];
00135 gint i;
00136 gulong places = 0, reval;
00137
00138 if ((2 > base) || (36 < base))
00139 return NULL;
00140
00141
00142 places = 0;
00143 for (i = 0; i < MAX_DIGITS; i++)
00144 {
00145 broke[i] = val;
00146 places++;
00147 val /= base;
00148 if (0 == val)
00149 break;
00150 }
00151
00152
00153 reval = 0;
00154 for (i = places - 2; i >= 0; i--)
00155 {
00156 reval += broke[i + 1];
00157 reval *= base;
00158 broke[i] -= reval;
00159 }
00160
00161
00162 for (i = 0; i < (gint) places; i++)
00163 {
00164 if (10 > broke[i])
00165 {
00166 buf[places - 1 - i] = 0x30 + broke[i];
00167 }
00168 else
00169 {
00170 buf[places - 1 - i] = 0x41 - 10 + broke[i];
00171 }
00172 }
00173 buf[places] = 0x0;
00174
00175 return g_strdup (buf);
00176 }
00177
00178 inline gint
00179 qof_util_double_compare (gdouble d1, gdouble d2)
00180 {
00181 if (isnan (d1) && isnan (d2))
00182 return 0;
00183 if (d1 < d2)
00184 return -1;
00185 if (d1 > d2)
00186 return 1;
00187 return 0;
00188 }
00189
00190
00191
00192
00193
00194 gboolean
00195 qof_util_string_isnum (const guchar * s)
00196 {
00197 if (s == NULL)
00198 return FALSE;
00199 if (*s == 0)
00200 return FALSE;
00201
00202 while (*s && isspace (*s))
00203 s++;
00204
00205 if (*s == 0)
00206 return FALSE;
00207 if (!isdigit (*s))
00208 return FALSE;
00209
00210 while (*s && isdigit (*s))
00211 s++;
00212
00213 if (*s == 0)
00214 return TRUE;
00215
00216 while (*s && isspace (*s))
00217 s++;
00218
00219 if (*s == 0)
00220 return TRUE;
00221
00222 return FALSE;
00223 }
00224
00225
00226
00227
00228
00229
00230 const gchar *
00231 qof_util_whitespace_filter (const gchar * val)
00232 {
00233 size_t len;
00234 if (!val)
00235 return NULL;
00236
00237 len = strspn (val, "\a\b\t\n\v\f\r ");
00238 if (0 == val[len])
00239 return NULL;
00240 return val + len;
00241 }
00242
00243
00244
00245
00246
00247
00248 gint
00249 qof_util_bool_to_int (const gchar * val)
00250 {
00251 const gchar *p = qof_util_whitespace_filter (val);
00252 if (!p)
00253 return 0;
00254 if ('t' == p[0])
00255 return 1;
00256 if ('T' == p[0])
00257 return 1;
00258 if ('y' == p[0])
00259 return 1;
00260 if ('Y' == p[0])
00261 return 1;
00262 if (strstr (p, "true"))
00263 return 1;
00264 if (strstr (p, "TRUE"))
00265 return 1;
00266 if (strstr (p, "yes"))
00267 return 1;
00268 if (strstr (p, "YES"))
00269 return 1;
00270 return atoi (val);
00271 }
00272
00273
00274
00275
00276
00277 gboolean
00278 qof_util_param_edit (QofInstance * inst, const QofParam *param)
00279 {
00280 QofBackend *be;
00281 QofUndo *undo_data;
00282
00283 if (!inst)
00284 return FALSE;
00285 (inst->editlevel)++;
00286 if (1 < inst->editlevel)
00287 return FALSE;
00288 if (0 >= inst->editlevel)
00289 inst->editlevel = 1;
00290 be = qof_book_get_backend (inst->book);
00291 if (param != NULL)
00292 {
00293 undo_data = inst->book->undo_data;
00294 inst->param = param;
00295 if (undo_data->undo_operation_open)
00296 qof_undo_modify (inst, param);
00297 }
00298 if (be && qof_backend_begin_exists (be))
00299 qof_backend_run_begin (be, inst);
00300 else
00301 inst->dirty = TRUE;
00302 return TRUE;
00303 }
00304
00305 gboolean
00306 qof_util_param_commit (QofInstance * inst, const QofParam * param)
00307 {
00308 QofUndo *undo_data;
00309 QofBackend * be;
00310
00311 if (!inst)
00312 return FALSE;
00313 (inst->editlevel)--;
00314 if (0 < inst->editlevel)
00315 return FALSE;
00316 be = qof_book_get_backend (inst->book);
00317 inst->param = param;
00318 if (be && qof_backend_commit_exists (be))
00319 qof_backend_run_commit (be, inst);
00320 if (param != NULL)
00321 {
00322 undo_data = inst->book->undo_data;
00323 if (undo_data->undo_operation_open)
00324 qof_undo_commit (inst, param);
00325 }
00326 return TRUE;
00327 }
00328
00329
00330
00331
00332
00333 static GCache *qof_string_cache = NULL;
00334
00335 #ifdef THESE_CAN_BE_USEFUL_FOR_DEGUGGING
00336 static guint
00337 g_str_hash_KEY (gconstpointer v)
00338 {
00339 return g_str_hash (v);
00340 }
00341
00342 static guint
00343 g_str_hash_VAL (gconstpointer v)
00344 {
00345 return g_str_hash (v);
00346 }
00347
00348 static gpointer
00349 g_strdup_VAL (gpointer v)
00350 {
00351 return g_strdup (v);
00352 }
00353
00354 static gpointer
00355 g_strdup_KEY (gpointer v)
00356 {
00357 return g_strdup (v);
00358 }
00359 static void
00360 g_free_VAL (gpointer v)
00361 {
00362 return g_free (v);
00363 }
00364 static void
00365 g_free_KEY (gpointer v)
00366 {
00367 return g_free (v);
00368 }
00369
00370 static gboolean
00371 qof_util_str_equal (gconstpointer v, gconstpointer v2)
00372 {
00373 return (v && v2) ? g_str_equal (v, v2) : FALSE;
00374 }
00375 #endif
00376 #ifdef QOF_DISABLE_DEPRECATED
00377 static GCache *
00378 qof_util_get_string_cache (void)
00379 #else
00380 GCache *
00381 qof_util_get_string_cache (void)
00382 #endif
00383 {
00384 if (!qof_string_cache)
00385 {
00386 qof_string_cache = g_cache_new ((GCacheNewFunc) g_strdup,
00387 g_free,
00388 (GCacheDupFunc) g_strdup,
00389 g_free,
00390 g_str_hash,
00391 g_str_hash,
00392 g_str_equal);
00393 }
00394 return qof_string_cache;
00395 }
00396
00397 void
00398 qof_util_string_cache_destroy (void)
00399 {
00400 if (qof_string_cache)
00401 g_cache_destroy (qof_string_cache);
00402 qof_string_cache = NULL;
00403 }
00404
00405 void
00406 qof_util_string_cache_remove (gconstpointer key)
00407 {
00408 if (key)
00409 g_cache_remove (qof_util_get_string_cache (), key);
00410 }
00411
00412 gpointer
00413 qof_util_string_cache_insert (gconstpointer key)
00414 {
00415 if (key)
00416 return g_cache_insert(qof_util_get_string_cache(), (gpointer)key);
00417 return NULL;
00418 }
00419
00420 gchar *
00421 qof_util_param_to_string (QofEntity * ent, const QofParam * param)
00422 {
00423 gchar *param_string;
00424 gchar param_sa[GUID_ENCODING_LENGTH + 1];
00425 gboolean known_type;
00426 QofType paramType;
00427 const GUID *param_guid;
00428 QofNumeric param_numeric, (*numeric_getter) (QofEntity *, const QofParam *);
00429 gdouble param_double, (*double_getter) (QofEntity *, const QofParam *);
00430 gboolean param_boolean, (*boolean_getter) (QofEntity *, const QofParam *);
00431 gint32 param_i32, (*int32_getter) (QofEntity *, const QofParam *);
00432 gint64 param_i64, (*int64_getter) (QofEntity *, const QofParam *);
00433 gchar param_char, (*char_getter) (QofEntity *, const QofParam *);
00434
00435 param_string = NULL;
00436 known_type = FALSE;
00437 paramType = param->param_type;
00438 if (safe_strcmp (paramType, QOF_TYPE_STRING) == 0)
00439 {
00440 param_string = g_strdup (param->param_getfcn (ent, param));
00441 if (param_string == NULL)
00442 {
00443 param_string = "";
00444 }
00445 known_type = TRUE;
00446 return param_string;
00447 }
00448 if (safe_strcmp (paramType, QOF_TYPE_TIME) == 0)
00449 {
00450 QofTime *param_qt;
00451 QofDate *qd;
00452 param_qt = param->param_getfcn (ent, param);
00453 qd = qof_date_from_qtime (param_qt);
00454 return qof_date_print (qd, QOF_DATE_FORMAT_UTC);
00455 }
00456 #ifndef QOF_DISABLE_DEPRECATED
00457 if (safe_strcmp (paramType, QOF_TYPE_DATE) == 0)
00458 {
00459 Timespec param_ts, (*date_getter) (QofEntity *, const QofParam *);
00460 time_t param_t;
00461 gchar param_date[MAX_DATE_LENGTH];
00462
00463 date_getter =
00464 (Timespec (*)(QofEntity *, const QofParam *)) param->param_getfcn;
00465 param_ts = date_getter (ent, param);
00466 param_t = param_ts.tv_sec;
00467 strftime (param_date, MAX_DATE_LENGTH,
00468 QOF_UTC_DATE_FORMAT, gmtime (¶m_t));
00469 param_string = g_strdup (param_date);
00470 known_type = TRUE;
00471 return param_string;
00472 }
00473 #endif
00474 if ((safe_strcmp (paramType, QOF_TYPE_NUMERIC) == 0) ||
00475 (safe_strcmp (paramType, QOF_TYPE_DEBCRED) == 0))
00476 {
00477 numeric_getter =
00478 (QofNumeric (*)(QofEntity *, const QofParam *)) param->param_getfcn;
00479 param_numeric = numeric_getter (ent, param);
00480 param_string = g_strdup (qof_numeric_to_string (param_numeric));
00481 known_type = TRUE;
00482 return param_string;
00483 }
00484 if (safe_strcmp (paramType, QOF_TYPE_GUID) == 0)
00485 {
00486 param_guid = param->param_getfcn (ent, param);
00487 guid_to_string_buff (param_guid, param_sa);
00488 param_string = g_strdup (param_sa);
00489 known_type = TRUE;
00490 return param_string;
00491 }
00492 if (safe_strcmp (paramType, QOF_TYPE_INT32) == 0)
00493 {
00494 int32_getter =
00495 (gint32 (*)(QofEntity *, const QofParam *)) param->param_getfcn;
00496 param_i32 = int32_getter (ent, param);
00497 param_string = g_strdup_printf ("%d", param_i32);
00498 known_type = TRUE;
00499 return param_string;
00500 }
00501 if (safe_strcmp (paramType, QOF_TYPE_INT64) == 0)
00502 {
00503 int64_getter =
00504 (gint64 (*)(QofEntity *, const QofParam *)) param->param_getfcn;
00505 param_i64 = int64_getter (ent, param);
00506 param_string = g_strdup_printf ("%" G_GINT64_FORMAT, param_i64);
00507 known_type = TRUE;
00508 return param_string;
00509 }
00510 if (safe_strcmp (paramType, QOF_TYPE_DOUBLE) == 0)
00511 {
00512 double_getter =
00513 (double (*)(QofEntity *, const QofParam *)) param->param_getfcn;
00514 param_double = double_getter (ent, param);
00515 param_string = g_strdup_printf ("%f", param_double);
00516 known_type = TRUE;
00517 return param_string;
00518 }
00519 if (safe_strcmp (paramType, QOF_TYPE_BOOLEAN) == 0)
00520 {
00521 boolean_getter =
00522 (gboolean (*)(QofEntity *, const QofParam *)) param->param_getfcn;
00523 param_boolean = boolean_getter (ent, param);
00524
00525 if (param_boolean == TRUE)
00526 {
00527 param_string = g_strdup ("true");
00528 }
00529 else
00530 {
00531 param_string = g_strdup ("false");
00532 }
00533 known_type = TRUE;
00534 return param_string;
00535 }
00536
00537 if (safe_strcmp (paramType, QOF_TYPE_KVP) == 0)
00538 {
00539 KvpFrame *frame = NULL;
00540 frame = param->param_getfcn (ent, param);
00541 known_type = TRUE;
00542 if (!kvp_frame_is_empty (frame))
00543 {
00544 GHashTable *hash = kvp_frame_get_hash (frame);
00545 param_string = g_strdup_printf ("%s(%d)", QOF_TYPE_KVP,
00546 g_hash_table_size (hash));
00547 }
00548 return param_string;
00549 }
00550 if (safe_strcmp (paramType, QOF_TYPE_CHAR) == 0)
00551 {
00552 char_getter =
00553 (gchar (*)(QofEntity *, const QofParam *)) param->param_getfcn;
00554 param_char = char_getter (ent, param);
00555 known_type = TRUE;
00556 return g_strdup_printf ("%c", param_char);
00557 }
00558
00559 if (safe_strcmp (paramType, QOF_TYPE_COLLECT) == 0)
00560 {
00561 QofCollection *col = NULL;
00562 col = param->param_getfcn (ent, param);
00563 known_type = TRUE;
00564 return g_strdup_printf ("%s(%d)",
00565 qof_collection_get_type (col), qof_collection_count (col));
00566 }
00567 if (safe_strcmp (paramType, QOF_TYPE_CHOICE) == 0)
00568 {
00569 QofEntity *child = NULL;
00570 child = param->param_getfcn (ent, param);
00571 if (!child)
00572 {
00573 return param_string;
00574 }
00575 known_type = TRUE;
00576 return g_strdup (qof_object_printable (child->e_type, child));
00577 }
00578 if (safe_strcmp (paramType, QOF_PARAM_BOOK) == 0)
00579 {
00580 QofBackend *be;
00581 QofBook *book;
00582 book = param->param_getfcn (ent, param);
00583 PINFO (" book param %p", book);
00584 be = qof_book_get_backend (book);
00585 known_type = TRUE;
00586 PINFO (" backend=%p", be);
00587 if (!be)
00588 {
00589 return QOF_PARAM_BOOK;
00590 }
00591 param_string = g_strdup (be->fullpath);
00592 PINFO (" fullpath=%s", param_string);
00593 if (param_string)
00594 {
00595 return param_string;
00596 }
00597 param_guid = qof_entity_get_guid ((QofEntity*)book);
00598 guid_to_string_buff (param_guid, param_sa);
00599 PINFO (" book GUID=%s", param_sa);
00600 param_string = g_strdup (param_sa);
00601 return param_string;
00602 }
00603 if (!known_type)
00604 {
00605 QofEntity *child = NULL;
00606 child = param->param_getfcn (ent, param);
00607 if (!child)
00608 {
00609 return param_string;
00610 }
00611 return g_strdup (qof_object_printable (child->e_type, child));
00612 }
00613 return g_strdup ("");
00614 }
00615
00616 gboolean
00617 qof_util_param_set_string (QofEntity * ent, const QofParam * param,
00618 const gchar * value_string)
00619 {
00620 void (*string_setter) (QofEntity *, const gchar *);
00621 void (*time_setter) (QofEntity *, QofTime *);
00622 void (*numeric_setter) (QofEntity *, QofNumeric);
00623 void (*guid_setter) (QofEntity *, const GUID *);
00624 void (*double_setter) (QofEntity *, gdouble);
00625 void (*boolean_setter) (QofEntity *, gboolean);
00626 void (*i32_setter) (QofEntity *, gint32);
00627 void (*i64_setter) (QofEntity *, gint64);
00628 void (*char_setter) (QofEntity *, gchar);
00629
00630
00631
00632
00633 g_return_val_if_fail (ent, FALSE);
00634 g_return_val_if_fail (param, FALSE);
00635 g_return_val_if_fail (value_string, FALSE);
00636
00637 if (safe_strcmp (param->param_type, QOF_TYPE_STRING) == 0)
00638 {
00639 string_setter =
00640 (void (*)(QofEntity *,
00641 const gchar *)) param->param_setfcn;
00642 if (string_setter != NULL)
00643 string_setter (ent, value_string);
00644
00645 }
00646 if (safe_strcmp (param->param_type, QOF_TYPE_TIME) == 0)
00647 {
00648 QofTime *qt;
00649 QofDate *qd;
00650
00651 qd = qof_date_parse (value_string, QOF_DATE_FORMAT_UTC);
00652 if (!qd)
00653 return FALSE;
00654 qt = qof_date_to_qtime (qd);
00655 time_setter =
00656 (void (*)(QofEntity *, QofTime *))
00657 param->param_setfcn;
00658 if ((time_setter != NULL) && (qof_time_is_valid (qt)))
00659 time_setter (ent, qt);
00660 qof_date_free (qd);
00661
00662 }
00663 #ifndef QOF_DISABLE_DEPRECATED
00664 if (safe_strcmp (param->param_type, QOF_TYPE_DATE) == 0)
00665 {
00666 return FALSE;
00667
00668 }
00669 #endif
00670 if ((safe_strcmp (param->param_type, QOF_TYPE_NUMERIC) == 0) ||
00671 (safe_strcmp (param->param_type, QOF_TYPE_DEBCRED) == 0))
00672 {
00673 QofNumeric num;
00674 numeric_setter =
00675 (void (*)(QofEntity *,
00676 QofNumeric)) param->param_setfcn;
00677 if (!qof_numeric_from_string (value_string, &num) ||
00678 (qof_numeric_check (num) != QOF_ERROR_OK))
00679 return FALSE;
00680 if (numeric_setter != NULL)
00681 numeric_setter (ent, num);
00682
00683 }
00684 if (safe_strcmp (param->param_type, QOF_TYPE_GUID) == 0)
00685 {
00686 GUID * guid;
00687
00688 guid = guid_malloc();
00689 guid_new (guid);
00690 guid_setter =
00691 (void (*)(QofEntity *,
00692 const GUID *)) param->param_setfcn;
00693 if (!string_to_guid(value_string, guid))
00694 return FALSE;
00695 if (guid_setter != NULL)
00696 guid_setter (ent, guid);
00697
00698 }
00699 if (safe_strcmp (param->param_type, QOF_TYPE_INT32) == 0)
00700 {
00701 gint32 i32;
00702 gchar *tail;
00703
00704 errno = 0;
00705 i32_setter =
00706 (void (*)(QofEntity *, gint32)) param->param_setfcn;
00707 i32 =
00708 (gint32) strtol (value_string, &tail, 0);
00709 if ((i32_setter != NULL) && (errno == 0))
00710
00711 i32_setter (ent, i32);
00712
00713 }
00714 if (safe_strcmp (param->param_type, QOF_TYPE_INT64) == 0)
00715 {
00716 gint64 i64;
00717 gchar *tail;
00718
00719 errno = 0;
00720 i64 = strtoll (value_string, &tail, 0);
00721 i64_setter =
00722 (void (*)(QofEntity *, gint64)) param->param_setfcn;
00723 if ((i64_setter != NULL) && (errno == 0))
00724 i64_setter (ent, i64);
00725
00726 }
00727 if (safe_strcmp (param->param_type, QOF_TYPE_DOUBLE) == 0)
00728 {
00729 gdouble db;
00730 gchar *tail;
00731
00732 errno = 0;
00733 db = strtod (value_string, &tail);
00734 double_setter =
00735 (void (*)(QofEntity *, gdouble)) param->param_setfcn;
00736 if ((double_setter != NULL) && (errno == 0))
00737 double_setter (ent, db);
00738
00739 }
00740 if (safe_strcmp (param->param_type, QOF_TYPE_BOOLEAN) == 0)
00741 {
00742 gint val;
00743 gboolean b;
00744
00745 boolean_setter =
00746 (void (*)(QofEntity *, gboolean)) param->param_setfcn;
00747 val = qof_util_bool_to_int(value_string);
00748 if ((val > 1) || (val < 0))
00749 return FALSE;
00750 b = (val == 1) ? TRUE : FALSE;
00751 if (boolean_setter != NULL)
00752 boolean_setter (ent, val);
00753
00754 }
00755 if (safe_strcmp (param->param_type, QOF_TYPE_KVP) == 0)
00756 {
00757
00758 return FALSE;
00759
00760
00761
00762
00763
00764
00765
00766
00767 }
00768 if (safe_strcmp (param->param_type, QOF_TYPE_CHAR) == 0)
00769 {
00770 char_setter =
00771 (void (*)(QofEntity *, gchar)) param->param_setfcn;
00772 if (char_setter != NULL)
00773 char_setter (ent, value_string[0]);
00774
00775 }
00776 if (safe_strcmp (param->param_type, QOF_TYPE_COLLECT) == 0)
00777 {
00778
00779 return FALSE;
00780 }
00781 if (safe_strcmp (param->param_type, QOF_TYPE_CHOICE) == 0)
00782 {
00783
00784 return FALSE;
00785 }
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801 return TRUE;
00802 }
00803
00804
00805 void
00806 qof_init (void)
00807 {
00808 qof_util_get_string_cache ();
00809 guid_init ();
00810 qof_date_init ();
00811 qof_object_initialize ();
00812 qof_query_init ();
00813 qof_book_register ();
00814 }
00815
00816 void
00817 qof_close (void)
00818 {
00819 qof_query_shutdown ();
00820 qof_object_shutdown ();
00821 guid_shutdown ();
00822 qof_date_close ();
00823 qof_util_string_cache_destroy ();
00824 }
00825
00826