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_new0 (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_new0 (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_new0 (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
01009 gchar *
01010 qof_book_merge_param_as_string (QofParam * qtparam, QofEntity * qtEnt)
01011 {
01012 gchar *param_string;
01013 gchar param_sa[GUID_ENCODING_LENGTH + 1];
01014 QofType paramType;
01015 const GUID *param_guid;
01016 QofTime *param_qt;
01017 QofNumeric param_numeric, (*numeric_getter) (QofEntity *, QofParam *);
01018 gdouble param_double, (*double_getter) (QofEntity *, QofParam *);
01019 gboolean param_boolean, (*boolean_getter) (QofEntity *, QofParam *);
01020 gint32 param_i32, (*int32_getter) (QofEntity *, QofParam *);
01021 gint64 param_i64, (*int64_getter) (QofEntity *, QofParam *);
01022 gchar param_char, (*char_getter) (QofEntity *, QofParam *);
01023
01024 param_string = NULL;
01025 paramType = qtparam->param_type;
01026 if (safe_strcmp (paramType, QOF_TYPE_STRING) == 0)
01027 {
01028 param_string = qtparam->param_getfcn (qtEnt, qtparam);
01029 if (param_string == NULL)
01030 param_string = "";
01031 return param_string;
01032 }
01033 if (safe_strcmp (paramType, QOF_TYPE_TIME) == 0)
01034 {
01035 QofDate *qd;
01036
01037 param_qt = qof_time_copy (
01038 qtparam->param_getfcn (qtEnt, qtparam));
01039 if (!param_qt)
01040 return NULL;
01041 qd = qof_date_from_qtime (param_qt);
01042 param_string = qof_date_print (qd, QOF_DATE_FORMAT_UTC);
01043 qof_date_free (qd);
01044 qof_time_free (param_qt);
01045 return param_string;
01046 }
01047 #ifndef QOF_DISABLE_DEPRECATED
01048 if (safe_strcmp (paramType, QOF_TYPE_DATE) == 0)
01049 {
01050 Timespec param_ts, (*date_getter) (QofEntity *, QofParam *);
01051 time_t param_t;
01052 gchar param_date[QOF_DATE_STRING_LENGTH];
01053
01054 date_getter =
01055 (Timespec (*)(QofEntity *, QofParam *)) qtparam->param_getfcn;
01056 param_ts = date_getter (qtEnt, qtparam);
01057 param_t = timespecToTime_t (param_ts);
01058 strftime (param_date, QOF_DATE_STRING_LENGTH, QOF_UTC_DATE_FORMAT,
01059 gmtime (¶m_t));
01060 param_string = g_strdup (param_date);
01061 return param_string;
01062 }
01063 #endif
01064 if ((safe_strcmp (paramType, QOF_TYPE_NUMERIC) == 0) ||
01065 (safe_strcmp (paramType, QOF_TYPE_DEBCRED) == 0))
01066 {
01067 numeric_getter =
01068 (QofNumeric (*)(QofEntity *,
01069 QofParam *)) qtparam->param_getfcn;
01070 param_numeric = numeric_getter (qtEnt, qtparam);
01071 param_string = g_strdup (qof_numeric_to_string (param_numeric));
01072 return param_string;
01073 }
01074 if (safe_strcmp (paramType, QOF_TYPE_GUID) == 0)
01075 {
01076 param_guid = qtparam->param_getfcn (qtEnt, qtparam);
01077 guid_to_string_buff (param_guid, param_sa);
01078 param_string = g_strdup (param_sa);
01079 return param_string;
01080 }
01081 if (safe_strcmp (paramType, QOF_TYPE_INT32) == 0)
01082 {
01083 int32_getter =
01084 (gint32 (*)(QofEntity *, QofParam *)) qtparam->param_getfcn;
01085 param_i32 = int32_getter (qtEnt, qtparam);
01086 param_string = g_strdup_printf ("%d", param_i32);
01087 return param_string;
01088 }
01089 if (safe_strcmp (paramType, QOF_TYPE_INT64) == 0)
01090 {
01091 int64_getter =
01092 (gint64 (*)(QofEntity *, QofParam *)) qtparam->param_getfcn;
01093 param_i64 = int64_getter (qtEnt, qtparam);
01094 param_string = g_strdup_printf ("%" G_GINT64_FORMAT, param_i64);
01095 return param_string;
01096 }
01097 if (safe_strcmp (paramType, QOF_TYPE_DOUBLE) == 0)
01098 {
01099 double_getter =
01100 (double (*)(QofEntity *, QofParam *)) qtparam->param_getfcn;
01101 param_double = double_getter (qtEnt, qtparam);
01102 param_string = g_strdup_printf ("%f", param_double);
01103 return param_string;
01104 }
01105 if (safe_strcmp (paramType, QOF_TYPE_BOOLEAN) == 0)
01106 {
01107 boolean_getter =
01108 (gboolean (*)(QofEntity *, QofParam *)) qtparam->param_getfcn;
01109 param_boolean = boolean_getter (qtEnt, qtparam);
01110
01111 if (param_boolean == TRUE)
01112 param_string = g_strdup ("true");
01113 else
01114 param_string = g_strdup ("false");
01115 return param_string;
01116 }
01117
01118 if (safe_strcmp (paramType, QOF_TYPE_KVP) == 0)
01119 return param_string;
01120 if (safe_strcmp (paramType, QOF_TYPE_CHAR) == 0)
01121 {
01122 char_getter =
01123 (gchar (*)(QofEntity *, QofParam *)) qtparam->param_getfcn;
01124 param_char = char_getter (qtEnt, qtparam);
01125 param_string = g_strdup_printf ("%c", param_char);
01126 return param_string;
01127 }
01128 return NULL;
01129 }
01130
01131 QofBookMergeData *
01132 qof_book_merge_update_result (QofBookMergeData * mergeData,
01133 QofBookMergeResult tag)
01134 {
01135 QofBookMergeRule *resolved;
01136
01137 g_return_val_if_fail ((mergeData != NULL), NULL);
01138 g_return_val_if_fail ((tag > 0), NULL);
01139 g_return_val_if_fail ((tag != MERGE_REPORT), NULL);
01140 resolved = mergeData->currentRule;
01141 g_return_val_if_fail ((resolved != NULL), NULL);
01142 if ((resolved->mergeAbsolute == TRUE) && (tag == MERGE_DUPLICATE))
01143 tag = MERGE_ABSOLUTE;
01144 if ((resolved->mergeAbsolute == TRUE) && (tag == MERGE_NEW))
01145 tag = MERGE_UPDATE;
01146 if ((resolved->mergeAbsolute == FALSE) && (tag == MERGE_ABSOLUTE))
01147 tag = MERGE_DUPLICATE;
01148 if ((resolved->mergeResult == MERGE_NEW) && (tag == MERGE_UPDATE))
01149 tag = MERGE_NEW;
01150 if (resolved->updated == FALSE)
01151 resolved->mergeResult = tag;
01152 resolved->updated = TRUE;
01153 if (tag >= MERGE_INVALID)
01154 {
01155 mergeData->abort = TRUE;
01156 mergeData->currentRule = resolved;
01157 return NULL;
01158 }
01159 mergeData->currentRule = resolved;
01160 return mergeData;
01161 }
01162
01163 gint
01164 qof_book_merge_commit (QofBookMergeData * mergeData)
01165 {
01166 QofBookMergeRule *currentRule;
01167 GList *check, *node;
01168
01169 g_return_val_if_fail (mergeData != NULL, -1);
01170 g_return_val_if_fail (mergeData->mergeList != NULL, -1);
01171 g_return_val_if_fail (mergeData->targetBook != NULL, -1);
01172 if (mergeData->abort == TRUE)
01173 return -1;
01174 check = g_list_copy (mergeData->mergeList);
01175 g_return_val_if_fail (check != NULL, -1);
01176 for (node = check; node != NULL; node = node->next)
01177 {
01178 currentRule = node->data;
01179 if (currentRule->mergeResult == MERGE_INVALID)
01180 {
01181 qof_book_merge_abort (mergeData);
01182 g_list_free (check);
01183 return (-2);
01184 }
01185 if (currentRule->mergeResult == MERGE_REPORT)
01186 {
01187 g_list_free (check);
01188 return 1;
01189 }
01190 }
01191 g_list_free (check);
01192 qof_book_merge_commit_foreach (qof_book_merge_commit_rule_loop,
01193 MERGE_NEW, mergeData);
01194 qof_book_merge_commit_foreach (qof_book_merge_commit_rule_loop,
01195 MERGE_UPDATE, mergeData);
01196
01197
01198 while (mergeData->mergeList != NULL)
01199 {
01200 currentRule = mergeData->mergeList->data;
01201 g_slist_free (currentRule->mergeParam);
01202 g_slist_free (currentRule->linkedEntList);
01203 mergeData->mergeList = g_list_next (mergeData->mergeList);
01204 }
01205 g_list_free (mergeData->mergeList);
01206 g_slist_free (mergeData->mergeObjectParams);
01207 g_slist_free (mergeData->targetList);
01208 if (mergeData->orphan_list != NULL)
01209 g_slist_free (mergeData->orphan_list);
01210 g_hash_table_destroy (mergeData->target_table);
01211 g_free (mergeData);
01212 return 0;
01213 }
01214
01215 void
01216 qof_book_merge_rule_foreach (QofBookMergeData * mergeData,
01217 QofBookMergeRuleForeachCB cb, QofBookMergeResult mergeResult)
01218 {
01219 struct QofBookMergeRuleIterate qiter;
01220 QofBookMergeRule *currentRule;
01221 GList *matching_rules, *node;
01222
01223 g_return_if_fail (cb != NULL);
01224 g_return_if_fail (mergeData != NULL);
01225 currentRule = mergeData->currentRule;
01226 g_return_if_fail (mergeResult > 0);
01227 g_return_if_fail (mergeResult != MERGE_INVALID);
01228 g_return_if_fail (mergeData->abort == FALSE);
01229 qiter.fcn = cb;
01230 qiter.data = mergeData;
01231 matching_rules = NULL;
01232 for (node = mergeData->mergeList; node != NULL; node = node->next)
01233 {
01234 currentRule = node->data;
01235 if (currentRule->mergeResult == mergeResult)
01236 matching_rules = g_list_prepend (matching_rules,
01237 currentRule);
01238 }
01239 qiter.remainder = g_list_length (matching_rules);
01240 g_list_foreach (matching_rules, qof_book_merge_rule_cb, &qiter);
01241 g_list_free (matching_rules);
01242 }
01243
01244