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