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 #include "config.h"
00026 #include <glib.h>
00027 #include "qof.h"
00028
00029 static QofLogModule log_module = QOF_MOD_MERGE;
00030
00031
00032 struct QofBookMergeRuleIterate
00033 {
00034 QofBookMergeRuleForeachCB fcn;
00035 QofBookMergeData *data;
00036 QofBookMergeRule *rule;
00037 GList *ruleList;
00038 guint remainder;
00039 };
00040
00041
00042
00043
00044
00045
00046
00047 #define DEFAULT_MERGE_WEIGHT 1
00048 #define QOF_STRING_WEIGHT 3
00049 #define QOF_DATE_STRING_LENGTH MAX_DATE_LENGTH
00050
00051 static QofBookMergeRule *
00052 qof_book_merge_update_rule (QofBookMergeRule * currentRule, gboolean match,
00053 gint weight)
00054 {
00055 gboolean absolute;
00056
00057 absolute = currentRule->mergeAbsolute;
00058 if (absolute && match && currentRule->mergeResult == MERGE_UNDEF)
00059 currentRule->mergeResult = MERGE_ABSOLUTE;
00060 if (absolute && !match)
00061 currentRule->mergeResult = MERGE_UPDATE;
00062 if (!absolute && match && currentRule->mergeResult == MERGE_UNDEF)
00063 currentRule->mergeResult = MERGE_DUPLICATE;
00064 if (!absolute && !match)
00065 {
00066 currentRule->difference += weight;
00067 if (currentRule->mergeResult == MERGE_DUPLICATE)
00068 currentRule->mergeResult = MERGE_REPORT;
00069 }
00070 return currentRule;
00071 }
00072
00073 struct collect_list_s
00074 {
00075 GSList *linkedEntList;
00076 };
00077
00078 static void
00079 collect_reference_cb (QofEntity * ent, gpointer user_data)
00080 {
00081 struct collect_list_s *s;
00082
00083 s = (struct collect_list_s *) user_data;
00084 if (!ent || !s)
00085 return;
00086 s->linkedEntList = g_slist_prepend (s->linkedEntList, ent);
00087 }
00088
00089 static gint
00090 qof_book_merge_compare (QofBookMergeData * mergeData)
00091 {
00092 QofBookMergeRule *currentRule;
00093 QofCollection *mergeColl, *targetColl;
00094 gchar *stringImport, *stringTarget;
00095 QofEntity *mergeEnt, *targetEnt, *referenceEnt;
00096 const GUID *guidImport, *guidTarget;
00097 QofParam *qtparam;
00098 KvpFrame *kvpImport, *kvpTarget;
00099 QofIdType mergeParamName;
00100 QofType mergeType;
00101 GSList *paramList;
00102 gboolean absolute, mergeError, knowntype, mergeMatch, booleanImport,
00103 booleanTarget, (*boolean_getter) (QofEntity *, QofParam *);
00104 QofNumeric numericImport, numericTarget,
00105 (*numeric_getter) (QofEntity *, QofParam *);
00106 gdouble doubleImport, doubleTarget, (*double_getter) (QofEntity *,
00107 QofParam *);
00108 gint32 i32Import, i32Target, (*int32_getter) (QofEntity *, QofParam *);
00109 gint64 i64Import, i64Target, (*int64_getter) (QofEntity *, QofParam *);
00110 gchar charImport, charTarget, (*char_getter) (QofEntity *, QofParam *);
00111
00112 g_return_val_if_fail ((mergeData != NULL), -1);
00113 currentRule = mergeData->currentRule;
00114 g_return_val_if_fail ((currentRule != NULL), -1);
00115 absolute = currentRule->mergeAbsolute;
00116 mergeEnt = currentRule->importEnt;
00117 targetEnt = currentRule->targetEnt;
00118 paramList = currentRule->mergeParam;
00119 currentRule->difference = 0;
00120 currentRule->mergeResult = MERGE_UNDEF;
00121 currentRule->linkedEntList = NULL;
00122 g_return_val_if_fail ((targetEnt) || (mergeEnt) || (paramList), -1);
00123 kvpImport = kvp_frame_new ();
00124 kvpTarget = kvp_frame_new ();
00125 mergeError = FALSE;
00126 while (paramList != NULL)
00127 {
00128 mergeMatch = FALSE;
00129 knowntype = FALSE;
00130 qtparam = paramList->data;
00131 mergeParamName = qtparam->param_name;
00132 g_return_val_if_fail (mergeParamName != NULL, -1);
00133 mergeType = qtparam->param_type;
00134 if (safe_strcmp (mergeType, QOF_TYPE_STRING) == 0)
00135 {
00136 stringImport = qtparam->param_getfcn (mergeEnt, qtparam);
00137 stringTarget = qtparam->param_getfcn (targetEnt, qtparam);
00138
00139 if (stringImport == NULL)
00140 stringImport = "";
00141 if (stringTarget == NULL)
00142 stringTarget = "";
00143 if (safe_strcmp (stringImport, stringTarget) == 0)
00144 mergeMatch = TRUE;
00145
00146 currentRule = qof_book_merge_update_rule (currentRule,
00147 mergeMatch, QOF_STRING_WEIGHT);
00148 stringImport = stringTarget = NULL;
00149 knowntype = TRUE;
00150 }
00151 if (safe_strcmp (mergeType, QOF_TYPE_TIME) == 0)
00152 {
00153 QofTime *qtImport, *qtTarget;
00154
00155 qtImport = qtparam->param_getfcn (mergeEnt, qtparam);
00156 qtTarget = qtparam->param_getfcn (targetEnt, qtparam);
00157 if (qof_time_cmp (qtImport, qtTarget) == 0)
00158 currentRule = qof_book_merge_update_rule (currentRule,
00159 mergeMatch, DEFAULT_MERGE_WEIGHT);
00160 knowntype = TRUE;
00161 }
00162 #ifndef QOF_DISABLE_DEPRECATED
00163 if (safe_strcmp (mergeType, QOF_TYPE_DATE) == 0)
00164 {
00165 Timespec tsImport, tsTarget, (*date_getter) (QofEntity *, QofParam *);
00166 date_getter =
00167 (Timespec (*)(QofEntity *,
00168 QofParam *)) qtparam->param_getfcn;
00169 tsImport = date_getter (mergeEnt, qtparam);
00170 tsTarget = date_getter (targetEnt, qtparam);
00171 if (timespec_cmp (&tsImport, &tsTarget) == 0)
00172 mergeMatch = TRUE;
00173 currentRule = qof_book_merge_update_rule (currentRule,
00174 mergeMatch, DEFAULT_MERGE_WEIGHT);
00175 knowntype = TRUE;
00176 }
00177 #endif
00178 if ((safe_strcmp (mergeType, QOF_TYPE_NUMERIC) == 0) ||
00179 (safe_strcmp (mergeType, QOF_TYPE_DEBCRED) == 0))
00180 {
00181 numeric_getter =
00182 (QofNumeric (*)(QofEntity *, QofParam *)) qtparam->
00183 param_getfcn;
00184 numericImport = numeric_getter (mergeEnt, qtparam);
00185 numericTarget = numeric_getter (targetEnt, qtparam);
00186 if (qof_numeric_compare (numericImport, numericTarget) == 0)
00187 mergeMatch = TRUE;
00188 currentRule = qof_book_merge_update_rule (currentRule,
00189 mergeMatch, DEFAULT_MERGE_WEIGHT);
00190 knowntype = TRUE;
00191 }
00192 if (safe_strcmp (mergeType, QOF_TYPE_GUID) == 0)
00193 {
00194 guidImport = qtparam->param_getfcn (mergeEnt, qtparam);
00195 guidTarget = qtparam->param_getfcn (targetEnt, qtparam);
00196 if (guid_compare (guidImport, guidTarget) == 0)
00197 mergeMatch = TRUE;
00198 currentRule = qof_book_merge_update_rule (currentRule,
00199 mergeMatch, DEFAULT_MERGE_WEIGHT);
00200 knowntype = TRUE;
00201 }
00202 if (safe_strcmp (mergeType, QOF_TYPE_INT32) == 0)
00203 {
00204 int32_getter =
00205 (gint32 (*)(QofEntity *,
00206 QofParam *)) qtparam->param_getfcn;
00207 i32Import = int32_getter (mergeEnt, qtparam);
00208 i32Target = int32_getter (targetEnt, qtparam);
00209 if (i32Target == i32Import)
00210 mergeMatch = TRUE;
00211 currentRule = qof_book_merge_update_rule (currentRule,
00212 mergeMatch, DEFAULT_MERGE_WEIGHT);
00213 knowntype = TRUE;
00214 }
00215 if (safe_strcmp (mergeType, QOF_TYPE_INT64) == 0)
00216 {
00217 int64_getter =
00218 (gint64 (*)(QofEntity *,
00219 QofParam *)) qtparam->param_getfcn;
00220 i64Import = int64_getter (mergeEnt, qtparam);
00221 i64Target = int64_getter (targetEnt, qtparam);
00222 if (i64Target == i64Import)
00223 mergeMatch = TRUE;
00224 currentRule = qof_book_merge_update_rule (currentRule,
00225 mergeMatch, DEFAULT_MERGE_WEIGHT);
00226 knowntype = TRUE;
00227 }
00228 if (safe_strcmp (mergeType, QOF_TYPE_DOUBLE) == 0)
00229 {
00230 double_getter =
00231 (double (*)(QofEntity *,
00232 QofParam *)) qtparam->param_getfcn;
00233 doubleImport = double_getter (mergeEnt, qtparam);
00234 doubleTarget = double_getter (mergeEnt, qtparam);
00235 if (doubleImport == doubleTarget)
00236 mergeMatch = TRUE;
00237 currentRule = qof_book_merge_update_rule (currentRule,
00238 mergeMatch, DEFAULT_MERGE_WEIGHT);
00239 knowntype = TRUE;
00240 }
00241 if (safe_strcmp (mergeType, QOF_TYPE_BOOLEAN) == 0)
00242 {
00243 boolean_getter =
00244 (gboolean (*)(QofEntity *,
00245 QofParam *)) qtparam->param_getfcn;
00246 booleanImport = boolean_getter (mergeEnt, qtparam);
00247 booleanTarget = boolean_getter (targetEnt, qtparam);
00248 if (booleanImport != FALSE && booleanImport != TRUE)
00249 booleanImport = FALSE;
00250 if (booleanTarget != FALSE && booleanTarget != TRUE)
00251 booleanTarget = FALSE;
00252 if (booleanImport == booleanTarget)
00253 mergeMatch = TRUE;
00254 currentRule = qof_book_merge_update_rule (currentRule,
00255 mergeMatch, DEFAULT_MERGE_WEIGHT);
00256 knowntype = TRUE;
00257 }
00258 if (safe_strcmp (mergeType, QOF_TYPE_KVP) == 0)
00259 {
00260 kvpImport =
00261 kvp_frame_copy (qtparam->param_getfcn (mergeEnt, qtparam));
00262 kvpTarget =
00263 kvp_frame_copy (qtparam->param_getfcn (targetEnt,
00264 qtparam));
00265 if (kvp_frame_compare (kvpImport, kvpTarget) == 0)
00266 mergeMatch = TRUE;
00267 currentRule = qof_book_merge_update_rule (currentRule,
00268 mergeMatch, DEFAULT_MERGE_WEIGHT);
00269 knowntype = TRUE;
00270 }
00271 if (safe_strcmp (mergeType, QOF_TYPE_CHAR) == 0)
00272 {
00273 char_getter =
00274 (gchar (*)(QofEntity *, QofParam *)) qtparam->param_getfcn;
00275 charImport = char_getter (mergeEnt, qtparam);
00276 charTarget = char_getter (targetEnt, qtparam);
00277 if (charImport == charTarget)
00278 mergeMatch = TRUE;
00279 currentRule = qof_book_merge_update_rule (currentRule,
00280 mergeMatch, DEFAULT_MERGE_WEIGHT);
00281 knowntype = TRUE;
00282 }
00283
00284
00285 if (safe_strcmp (mergeType, QOF_ID_BOOK) == 0)
00286 knowntype = TRUE;
00287 if (safe_strcmp (mergeType, QOF_TYPE_COLLECT) == 0)
00288 {
00289 struct collect_list_s s;
00290 s.linkedEntList = NULL;
00291 mergeColl = qtparam->param_getfcn (mergeEnt, qtparam);
00292 targetColl = qtparam->param_getfcn (targetEnt, qtparam);
00293 s.linkedEntList = g_slist_copy (currentRule->linkedEntList);
00294 qof_collection_foreach (mergeColl, collect_reference_cb, &s);
00295 currentRule->linkedEntList = g_slist_copy (s.linkedEntList);
00296 if (0 == qof_collection_compare (mergeColl, targetColl))
00297 mergeMatch = TRUE;
00298 currentRule = qof_book_merge_update_rule (currentRule,
00299 mergeMatch, DEFAULT_MERGE_WEIGHT);
00300 knowntype = TRUE;
00301 }
00302 if (safe_strcmp (mergeType, QOF_TYPE_CHOICE) == 0)
00303 {
00304 referenceEnt = qtparam->param_getfcn (mergeEnt, qtparam);
00305 currentRule->linkedEntList =
00306 g_slist_prepend (currentRule->linkedEntList, referenceEnt);
00307 if (referenceEnt == qtparam->param_getfcn (targetEnt, qtparam))
00308 mergeMatch = TRUE;
00309 knowntype = TRUE;
00310 }
00311 if (knowntype == FALSE)
00312 {
00313 referenceEnt = qtparam->param_getfcn (mergeEnt, qtparam);
00314 if ((referenceEnt != NULL)
00315 && (safe_strcmp (referenceEnt->e_type, mergeType) == 0))
00316 {
00317 currentRule->linkedEntList =
00318 g_slist_prepend (currentRule->linkedEntList,
00319 referenceEnt);
00320 if (referenceEnt ==
00321 qtparam->param_getfcn (targetEnt, qtparam))
00322 mergeMatch = TRUE;
00323 currentRule = qof_book_merge_update_rule (currentRule,
00324 mergeMatch, DEFAULT_MERGE_WEIGHT);
00325 }
00326 }
00327 paramList = g_slist_next (paramList);
00328 }
00329 mergeData->currentRule = currentRule;
00330 g_free (kvpImport);
00331 g_free (kvpTarget);
00332 return 0;
00333 }
00334
00335 static void
00336 qof_book_merge_commit_foreach_cb (gpointer rule, gpointer arg)
00337 {
00338 struct QofBookMergeRuleIterate *qiter;
00339
00340 g_return_if_fail (arg != NULL);
00341 qiter = (struct QofBookMergeRuleIterate *) arg;
00342 g_return_if_fail (qiter->data != NULL);
00343 qiter->fcn (qiter->data, (QofBookMergeRule *) rule,
00344 qiter->remainder);
00345 qiter->remainder--;
00346 }
00347
00348 static void
00349 qof_book_merge_commit_foreach (QofBookMergeRuleForeachCB cb,
00350 QofBookMergeResult mergeResult, QofBookMergeData * mergeData)
00351 {
00352 struct QofBookMergeRuleIterate qiter;
00353 QofBookMergeRule *currentRule;
00354 GList *subList, *node;
00355
00356 g_return_if_fail (cb != NULL);
00357 g_return_if_fail (mergeData != NULL);
00358 currentRule = mergeData->currentRule;
00359 g_return_if_fail (currentRule != NULL);
00360 g_return_if_fail (mergeResult > 0);
00361 g_return_if_fail ((mergeResult != MERGE_INVALID) ||
00362 (mergeResult != MERGE_UNDEF) ||
00363 (mergeResult != MERGE_REPORT));
00364
00365 qiter.fcn = cb;
00366 subList = NULL;
00367 qiter.ruleList = NULL;
00368 for (node = mergeData->mergeList; node != NULL; node = node->next)
00369 {
00370 currentRule = node->data;
00371 if (currentRule->mergeResult == mergeResult)
00372 subList = g_list_prepend (subList, currentRule);
00373 }
00374 qiter.remainder = g_list_length (subList);
00375 qiter.data = mergeData;
00376 g_list_foreach (subList, qof_book_merge_commit_foreach_cb, &qiter);
00377 }
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405 static gboolean
00406 qof_book_merge_rule_cmp (gconstpointer a, gconstpointer b)
00407 {
00408 QofBookMergeRule *ra = (QofBookMergeRule *) a;
00409 QofBookMergeRule *rb = (QofBookMergeRule *) b;
00410 if (ra->difference == rb->difference)
00411 return TRUE;
00412 else
00413 return FALSE;
00414 }
00415
00416 static void
00417 qof_book_merge_orphan_check (double difference,
00418 QofBookMergeRule * mergeRule, QofBookMergeData * mergeData)
00419 {
00420
00421
00422
00423 QofBookMergeRule *rule;
00424
00425 g_return_if_fail (mergeRule != NULL);
00426 g_return_if_fail (mergeData != NULL);
00427 if (g_hash_table_size (mergeData->target_table) == 0)
00428 return;
00429 rule =
00430 (QofBookMergeRule *) g_hash_table_lookup (mergeData->target_table,
00431 mergeRule->targetEnt);
00432
00433 if (rule == NULL)
00434 return;
00435
00436 if (difference >= rule->difference)
00437 return;
00438 rule->targetEnt = NULL;
00439 rule->mergeResult = MERGE_UNDEF;
00440 mergeData->orphan_list = g_slist_append (mergeData->orphan_list, rule);
00441 }
00442
00443 static void
00444 qof_book_merge_match_orphans (QofBookMergeData * mergeData)
00445 {
00446 GSList *orphans, *targets;
00447 QofBookMergeRule *rule, *currentRule;
00448 QofEntity *best_matchEnt;
00449 double difference;
00450
00451 g_return_if_fail (mergeData != NULL);
00452 currentRule = mergeData->currentRule;
00453 g_return_if_fail (currentRule != NULL);
00454
00455
00456 orphans = mergeData->orphan_list;
00457 targets = g_slist_copy (mergeData->targetList);
00458 while (orphans != NULL)
00459 {
00460 rule = orphans->data;
00461 g_return_if_fail (rule != NULL);
00462 difference = g_slist_length (mergeData->mergeObjectParams);
00463 if (rule->targetEnt == NULL)
00464 {
00465 rule->mergeResult = MERGE_NEW;
00466 rule->difference = 0;
00467 mergeData->mergeList =
00468 g_list_prepend (mergeData->mergeList, rule);
00469 orphans = g_slist_next (orphans);
00470 continue;
00471 }
00472 mergeData->currentRule = rule;
00473 g_return_if_fail (qof_book_merge_compare (mergeData) != -1);
00474 if (difference > mergeData->currentRule->difference)
00475 {
00476 best_matchEnt = currentRule->targetEnt;
00477 difference = currentRule->difference;
00478 rule = currentRule;
00479 mergeData->mergeList =
00480 g_list_prepend (mergeData->mergeList, rule);
00481 qof_book_merge_orphan_check (difference, rule, mergeData);
00482 }
00483 orphans = g_slist_next (orphans);
00484 }
00485 g_slist_free (mergeData->orphan_list);
00486 g_slist_free (targets);
00487 }
00488
00489 static void
00490 qof_book_merge_foreach_target (QofEntity * targetEnt, gpointer user_data)
00491 {
00492 QofBookMergeData *mergeData;
00493
00494 g_return_if_fail (user_data != NULL);
00495 mergeData = (QofBookMergeData *) user_data;
00496 g_return_if_fail (targetEnt != NULL);
00497 mergeData->targetList =
00498 g_slist_prepend (mergeData->targetList, targetEnt);
00499 }
00500
00501 static void
00502 qof_book_merge_foreach_type_target (QofObject * merge_obj,
00503 gpointer user_data)
00504 {
00505 QofBookMergeData *mergeData;
00506 QofBookMergeRule *currentRule;
00507
00508 g_return_if_fail (user_data != NULL);
00509 mergeData = (QofBookMergeData *) user_data;
00510 currentRule = mergeData->currentRule;
00511 g_return_if_fail (currentRule != NULL);
00512 g_return_if_fail (merge_obj != NULL);
00513 if (safe_strcmp (merge_obj->e_type,
00514 currentRule->importEnt->e_type) == 0)
00515 {
00516 qof_object_foreach (currentRule->importEnt->e_type,
00517 mergeData->targetBook,
00518 qof_book_merge_foreach_target, user_data);
00519 }
00520 }
00521
00522 static void
00523 qof_book_merge_foreach (QofEntity * mergeEnt, gpointer user_data)
00524 {
00525 QofBookMergeRule *mergeRule, *currentRule;
00526 QofBookMergeData *mergeData;
00527 QofEntity *targetEnt, *best_matchEnt;
00528 GUID *g;
00529 double difference;
00530 GSList *c;
00531
00532 g_return_if_fail (user_data != NULL);
00533 mergeData = (QofBookMergeData *) user_data;
00534 g_return_if_fail (mergeEnt != NULL);
00535 currentRule = mergeData->currentRule;
00536 g_return_if_fail (currentRule != NULL);
00537 g = guid_malloc ();
00538 *g = mergeEnt->guid;
00539 mergeRule = g_new (QofBookMergeRule, 1);
00540 mergeRule->importEnt = mergeEnt;
00541 mergeRule->difference = difference = 0;
00542 mergeRule->mergeAbsolute = FALSE;
00543 mergeRule->mergeResult = MERGE_UNDEF;
00544 mergeRule->updated = FALSE;
00545 mergeRule->mergeType = mergeEnt->e_type;
00546 mergeRule->mergeLabel = qof_object_get_type_label (mergeEnt->e_type);
00547 mergeRule->mergeParam = g_slist_copy (mergeData->mergeObjectParams);
00548 mergeRule->linkedEntList = NULL;
00549 mergeData->currentRule = mergeRule;
00550 targetEnt = best_matchEnt = NULL;
00551 targetEnt =
00552 qof_collection_lookup_entity (qof_book_get_collection
00553 (mergeData->targetBook, mergeEnt->e_type), g);
00554 if (targetEnt != NULL)
00555 {
00556 mergeRule->mergeAbsolute = TRUE;
00557 mergeRule->targetEnt = targetEnt;
00558 g_return_if_fail (qof_book_merge_compare (mergeData) != -1);
00559 mergeRule->linkedEntList =
00560 g_slist_copy (currentRule->linkedEntList);
00561 mergeData->mergeList =
00562 g_list_prepend (mergeData->mergeList, mergeRule);
00563 return;
00564 }
00565
00566 g_slist_free (mergeData->targetList);
00567 mergeData->targetList = NULL;
00568 qof_object_foreach_type (qof_book_merge_foreach_type_target,
00569 mergeData);
00570 if (g_slist_length (mergeData->targetList) == 0)
00571 mergeRule->mergeResult = MERGE_NEW;
00572 difference = g_slist_length (mergeRule->mergeParam);
00573 c = g_slist_copy (mergeData->targetList);
00574 while (c != NULL)
00575 {
00576 mergeRule->targetEnt = c->data;
00577 currentRule = mergeRule;
00578
00579 g_return_if_fail (qof_book_merge_compare (mergeData) != -1);
00580 if (mergeRule->difference == 0)
00581 {
00582
00583 best_matchEnt = mergeRule->targetEnt;
00584 mergeRule->mergeResult = MERGE_DUPLICATE;
00585 difference = 0;
00586 mergeRule->linkedEntList =
00587 g_slist_copy (currentRule->linkedEntList);
00588 g_slist_free (c);
00589 guid_free (g);
00590
00591 return;
00592 }
00593 if (difference > mergeRule->difference)
00594 {
00595
00596
00597 best_matchEnt = mergeRule->targetEnt;
00598 difference = mergeRule->difference;
00599
00600
00601
00602
00603 qof_book_merge_orphan_check (difference, mergeRule, mergeData);
00604 }
00605 c = g_slist_next (c);
00606 }
00607 g_slist_free (c);
00608 if (best_matchEnt != NULL)
00609 {
00610 mergeRule->targetEnt = best_matchEnt;
00611 mergeRule->difference = difference;
00612
00613
00614 g_hash_table_insert (mergeData->target_table, mergeRule->targetEnt,
00615 mergeRule);
00616
00617 g_return_if_fail (qof_book_merge_compare (mergeData) != -1);
00618 mergeRule->linkedEntList =
00619 g_slist_copy (currentRule->linkedEntList);
00620 }
00621 else
00622 {
00623 mergeRule->targetEnt = NULL;
00624 mergeRule->difference = 0;
00625 mergeRule->mergeResult = MERGE_NEW;
00626 mergeRule->linkedEntList =
00627 g_slist_copy (currentRule->linkedEntList);
00628 }
00629 mergeData->mergeList =
00630 g_list_prepend (mergeData->mergeList, mergeRule);
00631 guid_free (g);
00632
00633 }
00634
00635 static void
00636 qof_book_merge_foreach_param (QofParam * param, gpointer user_data)
00637 {
00638 QofBookMergeData *mergeData;
00639
00640 g_return_if_fail (user_data != NULL);
00641 mergeData = (QofBookMergeData *) user_data;
00642 g_return_if_fail (param != NULL);
00643 if ((param->param_getfcn != NULL) && (param->param_setfcn != NULL))
00644 {
00645 mergeData->mergeObjectParams =
00646 g_slist_append (mergeData->mergeObjectParams, param);
00647 }
00648 }
00649
00650 static void
00651 qof_book_merge_foreach_type (QofObject * merge_obj, gpointer user_data)
00652 {
00653 QofBookMergeData *mergeData;
00654
00655 g_return_if_fail (user_data != NULL);
00656 mergeData = (QofBookMergeData *) user_data;
00657 g_return_if_fail ((merge_obj != NULL));
00658
00659 if ((merge_obj->create == NULL) || (merge_obj->foreach == NULL))
00660 {
00661 DEBUG (" merge_obj QOF support failed %s", merge_obj->e_type);
00662 return;
00663 }
00664 if (mergeData->mergeObjectParams != NULL)
00665 g_slist_free (mergeData->mergeObjectParams);
00666 mergeData->mergeObjectParams = NULL;
00667 qof_class_param_foreach (merge_obj->e_type,
00668 qof_book_merge_foreach_param, mergeData);
00669 qof_object_foreach (merge_obj->e_type, mergeData->mergeBook,
00670 qof_book_merge_foreach, mergeData);
00671 }
00672
00673 static void
00674 qof_book_merge_rule_cb (gpointer rule, gpointer arg)
00675 {
00676 struct QofBookMergeRuleIterate *qiter;
00677 QofBookMergeData *mergeData;
00678
00679 g_return_if_fail (arg != NULL);
00680 qiter = (struct QofBookMergeRuleIterate *) arg;
00681 mergeData = qiter->data;
00682 g_return_if_fail (mergeData != NULL);
00683 g_return_if_fail (mergeData->abort == FALSE);
00684 qiter->fcn (mergeData, (QofBookMergeRule *) rule, qiter->remainder);
00685 qiter->data = mergeData;
00686 qiter->remainder--;
00687 }
00688
00689 static void
00690 qof_book_merge_commit_rule_loop (QofBookMergeData * mergeData,
00691 QofBookMergeRule * rule, guint remainder __attribute__ ((unused)))
00692 {
00693 QofInstance *inst;
00694 gboolean registered_type;
00695 QofEntity *referenceEnt;
00696
00697 QofCollection *cm_coll;
00698 QofParam *cm_param;
00699 gchar *cm_string;
00700 const GUID *cm_guid;
00701 KvpFrame *cm_kvp;
00702 QofTime *cm_qt;
00703
00704 QofNumeric cm_numeric, (*numeric_getter) (QofEntity *, QofParam *);
00705 gdouble cm_double, (*double_getter) (QofEntity *, QofParam *);
00706 gboolean cm_boolean, (*boolean_getter) (QofEntity *, QofParam *);
00707 gint32 cm_i32, (*int32_getter) (QofEntity *, QofParam *);
00708 gint64 cm_i64, (*int64_getter) (QofEntity *, QofParam *);
00709 gchar cm_char, (*char_getter) (QofEntity *, QofParam *);
00710
00711 void (*string_setter) (QofEntity *, const gchar *);
00712 void (*time_setter) (QofEntity *, QofTime *);
00713 void (*numeric_setter) (QofEntity *, QofNumeric);
00714 void (*guid_setter) (QofEntity *, const GUID *);
00715 void (*double_setter) (QofEntity *, double);
00716 void (*boolean_setter) (QofEntity *, gboolean);
00717 void (*i32_setter) (QofEntity *, gint32);
00718 void (*i64_setter) (QofEntity *, gint64);
00719 void (*char_setter) (QofEntity *, gchar);
00720 void (*kvp_frame_setter) (QofEntity *, KvpFrame *);
00721 void (*reference_setter) (QofEntity *, QofEntity *);
00722 void (*collection_setter) (QofEntity *, QofCollection *);
00723
00724 g_return_if_fail (rule != NULL);
00725 g_return_if_fail (mergeData != NULL);
00726 g_return_if_fail (mergeData->targetBook != NULL);
00727 g_return_if_fail ((rule->mergeResult != MERGE_NEW)
00728 || (rule->mergeResult != MERGE_UPDATE));
00729
00730
00731 if (rule->mergeResult == MERGE_NEW)
00732 {
00733 inst =
00734 (QofInstance *) qof_object_new_instance (rule->importEnt->
00735 e_type, mergeData->targetBook);
00736 g_return_if_fail (inst != NULL);
00737 rule->targetEnt = &inst->entity;
00738 qof_entity_set_guid (rule->targetEnt,
00739 qof_entity_get_guid (rule->importEnt));
00740 }
00741
00742
00743
00744
00745
00746 while (rule->mergeParam != NULL)
00747 {
00748 registered_type = FALSE;
00749 g_return_if_fail (rule->mergeParam->data);
00750 cm_param = rule->mergeParam->data;
00751 rule->mergeType = cm_param->param_type;
00752 if (safe_strcmp (rule->mergeType, QOF_TYPE_STRING) == 0)
00753 {
00754 cm_string = cm_param->param_getfcn (rule->importEnt, cm_param);
00755 string_setter =
00756 (void (*)(QofEntity *,
00757 const gchar *)) cm_param->param_setfcn;
00758 if (string_setter != NULL)
00759 string_setter (rule->targetEnt, cm_string);
00760 registered_type = TRUE;
00761 }
00762 if (safe_strcmp (rule->mergeType, QOF_TYPE_TIME) == 0)
00763 {
00764 QofTime *(*time_getter) (QofEntity *, QofParam *);
00765
00766 time_getter =
00767 (QofTime* (*)(QofEntity *, QofParam *))cm_param->param_getfcn;
00768 cm_qt = qof_time_copy (
00769 time_getter (rule->importEnt, cm_param));
00770 time_setter =
00771 (void (*)(QofEntity *, QofTime *))
00772 cm_param->param_setfcn;
00773 if ((time_setter != NULL) && (qof_time_is_valid (cm_qt)))
00774 time_setter (rule->targetEnt, cm_qt);
00775 registered_type = TRUE;
00776 }
00777 #ifndef QOF_DISABLE_DEPRECATED
00778 if (safe_strcmp (rule->mergeType, QOF_TYPE_DATE) == 0)
00779 {
00780 Timespec cm_date, (*date_getter) (QofEntity *, QofParam *);
00781 void (*date_setter) (QofEntity *, Timespec);
00782
00783 date_getter =
00784 (Timespec (*)(QofEntity *, QofParam *)) cm_param->
00785 param_getfcn;
00786 cm_date = date_getter (rule->importEnt, cm_param);
00787 date_setter =
00788 (void (*)(QofEntity *, Timespec)) cm_param->param_setfcn;
00789 if (date_setter != NULL)
00790 date_setter (rule->targetEnt, cm_date);
00791 registered_type = TRUE;
00792 }
00793 #endif
00794 if ((safe_strcmp (rule->mergeType, QOF_TYPE_NUMERIC) == 0) ||
00795 (safe_strcmp (rule->mergeType, QOF_TYPE_DEBCRED) == 0))
00796 {
00797 numeric_getter =
00798 (QofNumeric (*)(QofEntity *, QofParam *)) cm_param->
00799 param_getfcn;
00800 cm_numeric = numeric_getter (rule->importEnt, cm_param);
00801 numeric_setter =
00802 (void (*)(QofEntity *,
00803 QofNumeric)) cm_param->param_setfcn;
00804 if (numeric_setter != NULL)
00805 numeric_setter (rule->targetEnt, cm_numeric);
00806 registered_type = TRUE;
00807 }
00808 if (safe_strcmp (rule->mergeType, QOF_TYPE_GUID) == 0)
00809 {
00810 cm_guid = cm_param->param_getfcn (rule->importEnt, cm_param);
00811 guid_setter =
00812 (void (*)(QofEntity *,
00813 const GUID *)) cm_param->param_setfcn;
00814 if (guid_setter != NULL)
00815 guid_setter (rule->targetEnt, cm_guid);
00816 registered_type = TRUE;
00817 }
00818 if (safe_strcmp (rule->mergeType, QOF_TYPE_INT32) == 0)
00819 {
00820 int32_getter =
00821 (gint32 (*)(QofEntity *,
00822 QofParam *)) cm_param->param_getfcn;
00823 cm_i32 = int32_getter (rule->importEnt, cm_param);
00824 i32_setter =
00825 (void (*)(QofEntity *, gint32)) cm_param->param_setfcn;
00826 if (i32_setter != NULL)
00827 i32_setter (rule->targetEnt, cm_i32);
00828 registered_type = TRUE;
00829 }
00830 if (safe_strcmp (rule->mergeType, QOF_TYPE_INT64) == 0)
00831 {
00832 int64_getter =
00833 (gint64 (*)(QofEntity *,
00834 QofParam *)) cm_param->param_getfcn;
00835 cm_i64 = int64_getter (rule->importEnt, cm_param);
00836 i64_setter =
00837 (void (*)(QofEntity *, gint64)) cm_param->param_setfcn;
00838 if (i64_setter != NULL)
00839 i64_setter (rule->targetEnt, cm_i64);
00840 registered_type = TRUE;
00841 }
00842 if (safe_strcmp (rule->mergeType, QOF_TYPE_DOUBLE) == 0)
00843 {
00844 double_getter =
00845 (double (*)(QofEntity *,
00846 QofParam *)) cm_param->param_getfcn;
00847 cm_double = double_getter (rule->importEnt, cm_param);
00848 double_setter =
00849 (void (*)(QofEntity *, double)) cm_param->param_setfcn;
00850 if (double_setter != NULL)
00851 double_setter (rule->targetEnt, cm_double);
00852 registered_type = TRUE;
00853 }
00854 if (safe_strcmp (rule->mergeType, QOF_TYPE_BOOLEAN) == 0)
00855 {
00856 boolean_getter =
00857 (gboolean (*)(QofEntity *, QofParam *)) cm_param->
00858 param_getfcn;
00859 cm_boolean = boolean_getter (rule->importEnt, cm_param);
00860 boolean_setter =
00861 (void (*)(QofEntity *, gboolean)) cm_param->param_setfcn;
00862 if (boolean_setter != NULL)
00863 boolean_setter (rule->targetEnt, cm_boolean);
00864 registered_type = TRUE;
00865 }
00866 if (safe_strcmp (rule->mergeType, QOF_TYPE_KVP) == 0)
00867 {
00868 cm_kvp =
00869 kvp_frame_copy (cm_param->
00870 param_getfcn (rule->importEnt, cm_param));
00871 kvp_frame_setter =
00872 (void (*)(QofEntity *, KvpFrame *)) cm_param->param_setfcn;
00873 if (kvp_frame_setter != NULL)
00874 kvp_frame_setter (rule->targetEnt, cm_kvp);
00875 registered_type = TRUE;
00876 }
00877 if (safe_strcmp (rule->mergeType, QOF_TYPE_CHAR) == 0)
00878 {
00879 char_getter =
00880 (gchar (*)(QofEntity *,
00881 QofParam *)) cm_param->param_getfcn;
00882 cm_char = char_getter (rule->importEnt, cm_param);
00883 char_setter =
00884 (void (*)(QofEntity *, gchar)) cm_param->param_setfcn;
00885 if (char_setter != NULL)
00886 char_setter (rule->targetEnt, cm_char);
00887 registered_type = TRUE;
00888 }
00889 if (safe_strcmp (rule->mergeType, QOF_TYPE_COLLECT) == 0)
00890 {
00891 cm_coll = cm_param->param_getfcn (rule->importEnt, cm_param);
00892 collection_setter =
00893 (void (*)(QofEntity *, QofCollection *)) cm_param->
00894 param_setfcn;
00895 if (collection_setter != NULL)
00896 collection_setter (rule->targetEnt, cm_coll);
00897 registered_type = TRUE;
00898 }
00899 if (safe_strcmp (rule->mergeType, QOF_TYPE_CHOICE) == 0)
00900 {
00901 referenceEnt =
00902 cm_param->param_getfcn (rule->importEnt, cm_param);
00903 reference_setter =
00904 (void (*)(QofEntity *,
00905 QofEntity *)) cm_param->param_setfcn;
00906 if (reference_setter != NULL)
00907 reference_setter (rule->targetEnt, referenceEnt);
00908 registered_type = TRUE;
00909 }
00910 if (registered_type == FALSE)
00911 {
00912 referenceEnt =
00913 cm_param->param_getfcn (rule->importEnt, cm_param);
00914 if (referenceEnt)
00915 {
00916 reference_setter =
00917 (void (*)(QofEntity *, QofEntity *)) cm_param->
00918 param_setfcn;
00919 if (reference_setter != NULL)
00920 {
00921 reference_setter (rule->targetEnt, referenceEnt);
00922 }
00923 }
00924 }
00925 rule->mergeParam = g_slist_next (rule->mergeParam);
00926 }
00927 }
00928
00929
00930
00931
00932 QofBookMergeData *
00933 qof_book_merge_init (QofBook * importBook, QofBook * targetBook)
00934 {
00935 QofBookMergeData *mergeData;
00936 QofBookMergeRule *currentRule;
00937 GList *check;
00938
00939 g_return_val_if_fail ((importBook != NULL)
00940 && (targetBook != NULL), NULL);
00941 mergeData = g_new (QofBookMergeData, 1);
00942 mergeData->abort = FALSE;
00943 mergeData->mergeList = NULL;
00944 mergeData->targetList = NULL;
00945 mergeData->mergeBook = importBook;
00946 mergeData->targetBook = targetBook;
00947 mergeData->mergeObjectParams = NULL;
00948 mergeData->orphan_list = NULL;
00949 mergeData->target_table =
00950 g_hash_table_new (g_direct_hash, qof_book_merge_rule_cmp);
00951 currentRule = g_new (QofBookMergeRule, 1);
00952 mergeData->currentRule = currentRule;
00953 qof_object_foreach_type (qof_book_merge_foreach_type, mergeData);
00954 g_return_val_if_fail (mergeData->mergeObjectParams, NULL);
00955 if (mergeData->orphan_list != NULL)
00956 qof_book_merge_match_orphans (mergeData);
00957 for (check = mergeData->mergeList; check != NULL; check = check->next)
00958 {
00959 currentRule = check->data;
00960 if (currentRule->mergeResult == MERGE_INVALID)
00961 {
00962 mergeData->abort = TRUE;
00963 return (NULL);
00964 }
00965 }
00966 return mergeData;
00967 }
00968
00969 void
00970 qof_book_merge_abort (QofBookMergeData * mergeData)
00971 {
00972 QofBookMergeRule *currentRule;
00973
00974 g_return_if_fail (mergeData != NULL);
00975 while (mergeData->mergeList != NULL)
00976 {
00977 currentRule = mergeData->mergeList->data;
00978 g_slist_free (currentRule->linkedEntList);
00979 g_slist_free (currentRule->mergeParam);
00980 g_free (mergeData->mergeList->data);
00981 if (currentRule)
00982 {
00983 g_slist_free (currentRule->linkedEntList);
00984 g_slist_free (currentRule->mergeParam);
00985 g_free (currentRule);
00986 }
00987 mergeData->mergeList = g_list_next (mergeData->mergeList);
00988 }
00989 g_list_free (mergeData->mergeList);
00990 g_slist_free (mergeData->mergeObjectParams);
00991 g_slist_free (mergeData->targetList);
00992 if (mergeData->orphan_list != NULL)
00993 g_slist_free (mergeData->orphan_list);
00994 g_hash_table_destroy (mergeData->target_table);
00995 g_free (mergeData);
00996 }
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013 gchar *
01014 qof_book_merge_param_as_string (QofParam * qtparam, QofEntity * qtEnt)
01015 {
01016 gchar *param_string;
01017 gchar param_sa[GUID_ENCODING_LENGTH + 1];
01018 QofType paramType;
01019 const GUID *param_guid;
01020 QofTime *param_qt;
01021 QofNumeric param_numeric, (*numeric_getter) (QofEntity *, QofParam *);
01022 gdouble param_double, (*double_getter) (QofEntity *, QofParam *);
01023 gboolean param_boolean, (*boolean_getter) (QofEntity *, QofParam *);
01024 gint32 param_i32, (*int32_getter) (QofEntity *, QofParam *);
01025 gint64 param_i64, (*int64_getter) (QofEntity *, QofParam *);
01026 gchar param_char, (*char_getter) (QofEntity *, QofParam *);
01027
01028 param_string = NULL;
01029 paramType = qtparam->param_type;
01030 if (safe_strcmp (paramType, QOF_TYPE_STRING) == 0)
01031 {
01032 param_string = qtparam->param_getfcn (qtEnt, qtparam);
01033 if (param_string == NULL)
01034 param_string = "";
01035 return param_string;
01036 }
01037 if (safe_strcmp (paramType, QOF_TYPE_TIME) == 0)
01038 {
01039 QofDate *qd;
01040
01041 param_qt = qof_time_copy (
01042 qtparam->param_getfcn (qtEnt, qtparam));
01043 if (!param_qt)
01044 return NULL;
01045 qd = qof_date_from_qtime (param_qt);
01046 param_string = qof_date_print (qd, QOF_DATE_FORMAT_UTC);
01047 qof_date_free (qd);
01048 qof_time_free (param_qt);
01049 return param_string;
01050 }
01051 #ifndef QOF_DISABLE_DEPRECATED
01052 if (safe_strcmp (paramType, QOF_TYPE_DATE) == 0)
01053 {
01054 Timespec param_ts, (*date_getter) (QofEntity *, QofParam *);
01055 time_t param_t;
01056 gchar param_date[QOF_DATE_STRING_LENGTH];
01057
01058 date_getter =
01059 (Timespec (*)(QofEntity *, QofParam *)) qtparam->param_getfcn;
01060 param_ts = date_getter (qtEnt, qtparam);
01061 param_t = timespecToTime_t (param_ts);
01062 strftime (param_date, QOF_DATE_STRING_LENGTH, QOF_UTC_DATE_FORMAT,
01063 gmtime (¶m_t));
01064 param_string = g_strdup (param_date);
01065 return param_string;
01066 }
01067 #endif
01068 if ((safe_strcmp (paramType, QOF_TYPE_NUMERIC) == 0) ||
01069 (safe_strcmp (paramType, QOF_TYPE_DEBCRED) == 0))
01070 {
01071 numeric_getter =
01072 (QofNumeric (*)(QofEntity *,
01073 QofParam *)) qtparam->param_getfcn;
01074 param_numeric = numeric_getter (qtEnt, qtparam);
01075 param_string = g_strdup (qof_numeric_to_string (param_numeric));
01076 return param_string;
01077 }
01078 if (safe_strcmp (paramType, QOF_TYPE_GUID) == 0)
01079 {
01080 param_guid = qtparam->param_getfcn (qtEnt, qtparam);
01081 guid_to_string_buff (param_guid, param_sa);
01082 param_string = g_strdup (param_sa);
01083 return param_string;
01084 }
01085 if (safe_strcmp (paramType, QOF_TYPE_INT32) == 0)
01086 {
01087 int32_getter =
01088 (gint32 (*)(QofEntity *, QofParam *)) qtparam->param_getfcn;
01089 param_i32 = int32_getter (qtEnt, qtparam);
01090 param_string = g_strdup_printf ("%d", param_i32);
01091 return param_string;
01092 }
01093 if (safe_strcmp (paramType, QOF_TYPE_INT64) == 0)
01094 {
01095 int64_getter =
01096 (gint64 (*)(QofEntity *, QofParam *)) qtparam->param_getfcn;
01097 param_i64 = int64_getter (qtEnt, qtparam);
01098 param_string = g_strdup_printf ("%" G_GINT64_FORMAT, param_i64);
01099 return param_string;
01100 }
01101 if (safe_strcmp (paramType, QOF_TYPE_DOUBLE) == 0)
01102 {
01103 double_getter =
01104 (double (*)(QofEntity *, QofParam *)) qtparam->param_getfcn;
01105 param_double = double_getter (qtEnt, qtparam);
01106 param_string = g_strdup_printf ("%f", param_double);
01107 return param_string;
01108 }
01109 if (safe_strcmp (paramType, QOF_TYPE_BOOLEAN) == 0)
01110 {
01111 boolean_getter =
01112 (gboolean (*)(QofEntity *, QofParam *)) qtparam->param_getfcn;
01113 param_boolean = boolean_getter (qtEnt, qtparam);
01114
01115 if (param_boolean == TRUE)
01116 param_string = g_strdup ("true");
01117 else
01118 param_string = g_strdup ("false");
01119 return param_string;
01120 }
01121
01122 if (safe_strcmp (paramType, QOF_TYPE_KVP) == 0)
01123 return param_string;
01124 if (safe_strcmp (paramType, QOF_TYPE_CHAR) == 0)
01125 {
01126 char_getter =
01127 (gchar (*)(QofEntity *, QofParam *)) qtparam->param_getfcn;
01128 param_char = char_getter (qtEnt, qtparam);
01129 param_string = g_strdup_printf ("%c", param_char);
01130 return param_string;
01131 }
01132 return NULL;
01133 }
01134
01135 QofBookMergeData *
01136 qof_book_merge_update_result (QofBookMergeData * mergeData,
01137 QofBookMergeResult tag)
01138 {
01139 QofBookMergeRule *resolved;
01140
01141 g_return_val_if_fail ((mergeData != NULL), NULL);
01142 g_return_val_if_fail ((tag > 0), NULL);
01143 g_return_val_if_fail ((tag != MERGE_REPORT), NULL);
01144 resolved = mergeData->currentRule;
01145 g_return_val_if_fail ((resolved != NULL), NULL);
01146 if ((resolved->mergeAbsolute == TRUE) && (tag == MERGE_DUPLICATE))
01147 tag = MERGE_ABSOLUTE;
01148 if ((resolved->mergeAbsolute == TRUE) && (tag == MERGE_NEW))
01149 tag = MERGE_UPDATE;
01150 if ((resolved->mergeAbsolute == FALSE) && (tag == MERGE_ABSOLUTE))
01151 tag = MERGE_DUPLICATE;
01152 if ((resolved->mergeResult == MERGE_NEW) && (tag == MERGE_UPDATE))
01153 tag = MERGE_NEW;
01154 if (resolved->updated == FALSE)
01155 resolved->mergeResult = tag;
01156 resolved->updated = TRUE;
01157 if (tag >= MERGE_INVALID)
01158 {
01159 mergeData->abort = TRUE;
01160 mergeData->currentRule = resolved;
01161 return NULL;
01162 }
01163 mergeData->currentRule = resolved;
01164 return mergeData;
01165 }
01166
01167 gint
01168 qof_book_merge_commit (QofBookMergeData * mergeData)
01169 {
01170 QofBookMergeRule *currentRule;
01171 GList *check, *node;
01172
01173 g_return_val_if_fail (mergeData != NULL, -1);
01174 g_return_val_if_fail (mergeData->mergeList != NULL, -1);
01175 g_return_val_if_fail (mergeData->targetBook != NULL, -1);
01176 if (mergeData->abort == TRUE)
01177 return -1;
01178 check = g_list_copy (mergeData->mergeList);
01179 g_return_val_if_fail (check != NULL, -1);
01180 for (node = check; node != NULL; node = node->next)
01181 {
01182 currentRule = node->data;
01183 if (currentRule->mergeResult == MERGE_INVALID)
01184 {
01185 qof_book_merge_abort (mergeData);
01186 g_list_free (check);
01187 return (-2);
01188 }
01189 if (currentRule->mergeResult == MERGE_REPORT)
01190 {
01191 g_list_free (check);
01192 return 1;
01193 }
01194 }
01195 g_list_free (check);
01196 qof_book_merge_commit_foreach (qof_book_merge_commit_rule_loop,
01197 MERGE_NEW, mergeData);
01198 qof_book_merge_commit_foreach (qof_book_merge_commit_rule_loop,
01199 MERGE_UPDATE, mergeData);
01200
01201
01202 while (mergeData->mergeList != NULL)
01203 {
01204 currentRule = mergeData->mergeList->data;
01205 g_slist_free (currentRule->mergeParam);
01206 g_slist_free (currentRule->linkedEntList);
01207 mergeData->mergeList = g_list_next (mergeData->mergeList);
01208 }
01209 g_list_free (mergeData->mergeList);
01210 g_slist_free (mergeData->mergeObjectParams);
01211 g_slist_free (mergeData->targetList);
01212 if (mergeData->orphan_list != NULL)
01213 g_slist_free (mergeData->orphan_list);
01214 g_hash_table_destroy (mergeData->target_table);
01215 g_free (mergeData);
01216 return 0;
01217 }
01218
01219 void
01220 qof_book_merge_rule_foreach (QofBookMergeData * mergeData,
01221 QofBookMergeRuleForeachCB cb, QofBookMergeResult mergeResult)
01222 {
01223 struct QofBookMergeRuleIterate qiter;
01224 QofBookMergeRule *currentRule;
01225 GList *matching_rules, *node;
01226
01227 g_return_if_fail (cb != NULL);
01228 g_return_if_fail (mergeData != NULL);
01229 currentRule = mergeData->currentRule;
01230 g_return_if_fail (mergeResult > 0);
01231 g_return_if_fail (mergeResult != MERGE_INVALID);
01232 g_return_if_fail (mergeData->abort == FALSE);
01233 qiter.fcn = cb;
01234 qiter.data = mergeData;
01235 matching_rules = NULL;
01236 for (node = mergeData->mergeList; node != NULL; node = node->next)
01237 {
01238 currentRule = node->data;
01239 if (currentRule->mergeResult == mergeResult)
01240 matching_rules = g_list_prepend (matching_rules,
01241 currentRule);
01242 }
01243 qiter.remainder = g_list_length (matching_rules);
01244 g_list_foreach (matching_rules, qof_book_merge_rule_cb, &qiter);
01245 g_list_free (matching_rules);
01246 }
01247
01248