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