Allow elements out of context in GOM.
[gedcom-parse.git] / gom / event.c
index e19fd379ba2e11f2ab77ac2d41d96be113a6ecd0..b585a688abca91f686c7e5ac5d840e85ff0ff8fa 100644 (file)
 Gedcom_ctxt sub_evt_start(_ELT_PARAMS_)
 {
   Gom_ctxt ctxt = (Gom_ctxt)parent;
-  struct event *evt = NULL;
-
-  if (ctxt) {
-    evt = (struct event *)malloc(sizeof(struct event));
-    memset (evt, 0, sizeof(struct event));
-    evt->event = parsed_tag;
-    evt->event_name = strdup(tag);
-    if (GEDCOM_IS_STRING(parsed_value))
-      evt->val = strdup(GEDCOM_STRING(parsed_value));
-
-    switch (ctxt->ctxt_type) {
-      case REC_FAM:
-       family_add_event(ctxt, evt); break;
-      case REC_INDI:
-       individual_add_event(ctxt, evt); break;
-      default:
-       UNEXPECTED_CONTEXT(ctxt->ctxt_type);
+  Gom_ctxt result = NULL;
+
+  if (! ctxt)
+    NO_CONTEXT;
+  else {
+    struct event *evt = SUB_MAKEFUNC(event)();
+    if (evt) {
+      evt->event = parsed_tag;
+      evt->event_name = strdup(tag);
+      if (! evt->event_name) {
+       MEMORY_ERROR;
+       free(evt);
+      }
+      else {
+       int err = 0;
+       if (GEDCOM_IS_STRING(parsed_value)) {
+         evt->val = strdup(GEDCOM_STRING(parsed_value));
+         if (! evt->val) {
+           MEMORY_ERROR;
+           free(evt->event_name);
+           free(evt);
+           err = 1;
+         }
+       }
+
+       if (! err) {
+         int type = ctxt_type(ctxt);
+         switch (type) {
+           case REC_FAM:
+             ADDFUNC2(family,event)(ctxt, evt); break;
+           case REC_INDI:
+             ADDFUNC2(individual,event)(ctxt, evt); break;
+           default:
+             UNEXPECTED_CONTEXT(type);
+         }
+         result = MAKE_GOM_CTXT(elt, event, evt);
+       }
+      }
     }
   }
 
-  return (Gedcom_ctxt) MAKE_GOM_CTXT(elt, event, evt);
+  return (Gedcom_ctxt)result;
 }
 
 Gedcom_ctxt sub_attr_start(_ELT_PARAMS_)
 {
   Gom_ctxt ctxt = (Gom_ctxt)parent;
-  struct event *evt = NULL;
-
-  if (ctxt) {
-    evt = (struct event *)malloc(sizeof(struct event));
-    memset (evt, 0, sizeof(struct event));
-    evt->event = parsed_tag;
-    evt->event_name = strdup(tag);
-    if (GEDCOM_IS_STRING(parsed_value))
-      evt->val = strdup(GEDCOM_STRING(parsed_value));
-    switch (ctxt->ctxt_type) {
-      case REC_INDI:
-       individual_add_attribute(ctxt, evt); break;
-      default:
-       UNEXPECTED_CONTEXT(ctxt->ctxt_type);
+  Gom_ctxt result = NULL;
+
+  if (! ctxt)
+    NO_CONTEXT;
+  else {
+    struct event *evt = SUB_MAKEFUNC(event)();
+    if (evt) {
+      evt->event = parsed_tag;
+      evt->event_name = strdup(tag);
+      if (! evt->event_name) {
+       MEMORY_ERROR;
+       free(evt);
+      }
+      else {
+       int err = 0;
+       if (GEDCOM_IS_STRING(parsed_value)) {
+         evt->val = strdup(GEDCOM_STRING(parsed_value));
+         if (! evt->val) {
+           MEMORY_ERROR;
+           free(evt->event_name);
+           free(evt);
+           err = 1;
+         }
+       }
+
+       if (! err) {
+         int type = ctxt_type(ctxt);
+         switch (type) {
+           case REC_INDI:
+             ADDFUNC2_TOVAR(individual,event,attribute)(ctxt, evt); break;
+           default:
+             UNEXPECTED_CONTEXT(type);
+         }
+         result = MAKE_GOM_CTXT(elt, event, evt);
+       }
+      }
     }
   }
-  return (Gedcom_ctxt) MAKE_GOM_CTXT(elt, event, evt);
+  return (Gedcom_ctxt)result;
 }
 
-STRING_CB(event, sub_evt_type_start, type)
-DATE_CB(event, sub_evt_date_start, date)
-AGE_CB(event, sub_evt_age_start, age)
-STRING_CB(event, sub_evt_agnc_start, agency)
-STRING_CB(event, sub_evt_caus_start, cause)
-NULL_CB(event, sub_fam_evt_husb_wife_start)
-XREF_CB(event, sub_evt_famc_start, family, make_family_record)
-STRING_CB(event, sub_evt_famc_adop_start, adoption_parent)
+DEFINE_SUB_MAKEFUNC(event)
+DEFINE_SUB_ADDFUNC(event)
+DEFINE_SUB_FINDFUNC(event)
+DEFINE_SUB_REMOVEFUNC(event)
+DEFINE_SUB_MOVEFUNC(event)
      
+DEFINE_STRING_CB(event, sub_evt_type_start, type)
+DEFINE_DATE_CB(event, sub_evt_date_start, date)
+DEFINE_AGE_CB(event, sub_evt_age_start, age)
+DEFINE_STRING_CB(event, sub_evt_agnc_start, agency)
+DEFINE_STRING_CB(event, sub_evt_caus_start, cause)
+DEFINE_NULL_CB(event, sub_fam_evt_husb_wife_start)
+DEFINE_XREF_CB(event, sub_evt_famc_start, family, family)
+DEFINE_STRING_CB(event, sub_evt_famc_adop_start, adoption_parent)
+     
+DEFINE_ADDFUNC2(event, source_citation, citation)
+DEFINE_ADDFUNC2(event, multimedia_link, mm_link)
+DEFINE_ADDFUNC2(event, note_sub, note)
+DEFINE_ADDFUNC2(event, user_data, extra)
+DEFINE_ADDFUNC2_NOLIST(event, place, place)
+DEFINE_ADDFUNC2_NOLIST(event, address, address)
+DEFINE_ADDFUNC2_STRN(event, phone, 3)
+
 Gedcom_ctxt sub_fam_evt_age_start(_ELT_PARAMS_)
 {
-  struct age_value age = GEDCOM_AGE(parsed_value);
   Gom_ctxt ctxt = (Gom_ctxt)parent;
-  struct event *evt = NULL;
-  if (ctxt) {
-    evt = SAFE_CTXT_CAST(event, ctxt);
-    switch (ctxt->ctxt_type) {
-      case ELT_SUB_FAM_EVT_HUSB:
-       evt->husband_age = dup_age(age); break;
-      case ELT_SUB_FAM_EVT_WIFE:
-       evt->wife_age = dup_age(age); break;
-      default:
-       UNEXPECTED_CONTEXT(ctxt->ctxt_type);
+  Gom_ctxt result = NULL;
+  
+  if (! ctxt)
+    NO_CONTEXT;
+  else {
+    struct event *evt = SAFE_CTXT_CAST(event, ctxt);
+    if (evt) {
+      int err = 0;
+      struct age_value age = GEDCOM_AGE(parsed_value);
+      int type = ctxt_type(ctxt);
+      switch (type) {
+       case ELT_SUB_FAM_EVT_HUSB:
+         evt->husband_age = gedcom_new_age_value(&age);
+         if (! evt->husband_age) {
+           MEMORY_ERROR;
+           err = 1;
+         }
+         break;
+       case ELT_SUB_FAM_EVT_WIFE:
+         evt->wife_age = gedcom_new_age_value(&age);
+         if (! evt->wife_age) {
+           MEMORY_ERROR;
+           err = 1;
+         }
+         break;
+       default:
+         UNEXPECTED_CONTEXT(type);
+      }
+      if (! err)
+       result = MAKE_GOM_CTXT(elt, event, evt);
     }
   }
-  return (Gedcom_ctxt) MAKE_GOM_CTXT(elt, event, evt);
-}
-
-void event_add_place(Gom_ctxt ctxt, struct place* place)
-{
-  struct event *evt = SAFE_CTXT_CAST(event, ctxt);
-  evt->place = place;
-}
-
-void event_add_address(Gom_ctxt ctxt, struct address* address)
-{
-  struct event *evt = SAFE_CTXT_CAST(event, ctxt);
-  evt->address = address;
-}
-
-void event_add_phone(Gom_ctxt ctxt, char *phone)
-{
-  struct event *evt = SAFE_CTXT_CAST(event, ctxt);
-  if (! evt->phone[0])
-    evt->phone[0] = strdup(phone);
-  else if (! evt->phone[1])
-    evt->phone[1] = strdup(phone);
-  else if (! evt->phone[2])
-    evt->phone[2] = strdup(phone);
-}
-
-void event_add_citation(Gom_ctxt ctxt, struct source_citation* cit)
-{
-  struct event *evt = SAFE_CTXT_CAST(event, ctxt);
-  LINK_CHAIN_ELT(source_citation, evt->citation, cit)    
-}
-
-void event_add_mm_link(Gom_ctxt ctxt, struct multimedia_link* mm)
-{
-  struct event *evt = SAFE_CTXT_CAST(event, ctxt);
-  LINK_CHAIN_ELT(multimedia_link, evt->mm_link, mm)    
-}
-
-void event_add_note(Gom_ctxt ctxt, struct note_sub* note)
-{
-  struct event *evt = SAFE_CTXT_CAST(event, ctxt);
-  LINK_CHAIN_ELT(note_sub, evt->note, note)    
-}
-
-void event_add_user_data(Gom_ctxt ctxt, struct user_data* data)
-{
-  struct event *obj = SAFE_CTXT_CAST(event, ctxt);
-  LINK_CHAIN_ELT(user_data, obj->extra, data)
+  return (Gedcom_ctxt)result;
 }
 
 void event_subscribe()
@@ -200,27 +229,168 @@ void event_subscribe()
                              sub_evt_caus_start, def_elt_end);
 }
 
-void event_cleanup(struct event* evt)
+void UNREFALLFUNC(event)(struct event* obj)
+{
+  if (obj) {
+    struct event* runner;
+    for (runner = obj; runner; runner = runner->next) {
+      UNREFALLFUNC(place)(runner->place);
+      UNREFALLFUNC(address)(runner->address);
+      UNREFALLFUNC(source_citation)(runner->citation);
+      UNREFALLFUNC(multimedia_link)(runner->mm_link);
+      UNREFALLFUNC(note_sub)(runner->note);
+      unref_xref_value(runner->family);
+      UNREFALLFUNC(user_data)(runner->extra);
+    }
+  }
+}
+
+void CLEANFUNC(event)(struct event* evt)
 {
   if (evt) {
     SAFE_FREE(evt->event_name);
     SAFE_FREE(evt->val);
     SAFE_FREE(evt->type);
     SAFE_FREE(evt->date);
-    place_cleanup(evt->place);
-    address_cleanup(evt->address);
+    CLEANFUNC(place)(evt->place);
+    CLEANFUNC(address)(evt->address);
     SAFE_FREE(evt->phone[0]);
     SAFE_FREE(evt->phone[1]);
     SAFE_FREE(evt->phone[2]);
     SAFE_FREE(evt->age);
     SAFE_FREE(evt->agency);
     SAFE_FREE(evt->cause);
-    DESTROY_CHAIN_ELTS(source_citation, evt->citation, citation_cleanup)
-    DESTROY_CHAIN_ELTS(multimedia_link, evt->mm_link, multimedia_link_cleanup)
-    DESTROY_CHAIN_ELTS(note_sub, evt->note, note_sub_cleanup)
+    DESTROY_CHAIN_ELTS(source_citation, evt->citation);
+    DESTROY_CHAIN_ELTS(multimedia_link, evt->mm_link);
+    DESTROY_CHAIN_ELTS(note_sub, evt->note);
     SAFE_FREE(evt->husband_age);
     SAFE_FREE(evt->wife_age);
     SAFE_FREE(evt->adoption_parent);
-    DESTROY_CHAIN_ELTS(user_data, evt->extra, user_data_cleanup)
+    DESTROY_CHAIN_ELTS(user_data, evt->extra);
+  }
+}
+
+static int get_gedcom_elt(EventType evt_type, int parsed_tag)
+{
+  int obj_elt = 0;
+  switch (evt_type) {
+    case EVT_TYPE_FAMILY:
+      obj_elt = (parsed_tag == TAG_EVEN ? ELT_SUB_FAM_EVT_EVEN :
+                ELT_SUB_FAM_EVT);
+      break;
+    case EVT_TYPE_INDIV_ATTR:
+      obj_elt = (parsed_tag == TAG_RESI ? ELT_SUB_INDIV_RESI :
+                ELT_SUB_INDIV_ATTR);
+      break;
+    case EVT_TYPE_INDIV_EVT:
+      switch (parsed_tag) {
+       case TAG_BIRT: case TAG_CHR:
+         obj_elt = ELT_SUB_INDIV_BIRT; break;
+       case TAG_DEAT: case TAG_BURI: case TAG_CREM: case TAG_BAPM:
+       case TAG_BARM: case TAG_BASM: case TAG_BLES: case TAG_CHRA:
+       case TAG_CONF: case TAG_FCOM: case TAG_ORDN: case TAG_NATU:
+       case TAG_EMIG: case TAG_IMMI: case TAG_CENS: case TAG_PROB:
+       case TAG_WILL: case TAG_GRAD: case TAG_RETI:
+         obj_elt = ELT_SUB_INDIV_GEN; break;
+       case TAG_ADOP:
+         obj_elt = ELT_SUB_INDIV_ADOP; break;
+       case TAG_EVEN:
+         obj_elt = ELT_SUB_INDIV_EVEN; break;
+       default:
+         gedcom_warning(_("Internal error: unknown evt tag %d"), parsed_tag);
+      }
+      break;
+    default:
+      gedcom_warning(_("Internal error: unknown evt type %d"), evt_type);
+  }
+  return obj_elt;
+}
+
+int get_gedcom_fam_elt(int elt)
+{
+  int fam_obj_elt = 0;
+  switch (elt) {
+    case ELT_SUB_INDIV_BIRT:
+      fam_obj_elt = ELT_SUB_INDIV_BIRT_FAMC;
+      break;
+    case ELT_SUB_INDIV_ADOP:
+      fam_obj_elt = ELT_SUB_INDIV_ADOP_FAMC;
+      break;
+    default:
+      gedcom_warning(_("Internal error: wrong parent for evt->family"));
+  }
+  return fam_obj_elt;
+}
+
+int write_events(Gedcom_write_hndl hndl, int parent, EventType evt_type,
+                struct event* evt)
+{
+  int result = 0;
+  int i;
+  struct event* obj;
+
+  if (!evt) return 1;
+
+  for (obj = evt; obj; obj = obj->next) {
+    int obj_elt = get_gedcom_elt(evt_type, obj->event);
+    result |= gedcom_write_element_str(hndl, obj_elt, obj->event,
+                                      parent, obj->val);
+    if (obj->type)
+      result |= gedcom_write_element_str(hndl, ELT_SUB_EVT_TYPE, 0,
+                                        obj_elt, obj->type);
+    if (obj->date)
+      result |= gedcom_write_element_date(hndl, ELT_SUB_EVT_DATE, 0,
+                                         obj_elt, obj->date);
+    if (obj->place)
+      result |= write_place(hndl, obj_elt, obj->place);
+    if (obj->address)
+      result |= write_address(hndl, obj_elt, obj->address);
+    for (i = 0; i < 3 && obj->phone[i]; i++)
+      result |= gedcom_write_element_str(hndl, ELT_SUB_PHON, 0, obj_elt,
+                                        obj->phone[i]);
+    if (obj->age)
+      result |= gedcom_write_element_age(hndl, ELT_SUB_EVT_AGE, 0,
+                                        obj_elt, obj->age);
+    if (obj->agency)
+      result |= gedcom_write_element_str(hndl, ELT_SUB_EVT_AGNC, 0,
+                                        obj_elt, obj->agency);
+    if (obj->cause)
+      result |= gedcom_write_element_str(hndl, ELT_SUB_EVT_CAUS, 0,
+                                        obj_elt, obj->cause);
+    if (obj->citation)
+      result |= write_citations(hndl, obj_elt, obj->citation);
+    if (obj->mm_link)
+      result |= write_multimedia_links(hndl, obj_elt, obj->mm_link);
+    if (obj->note)
+      result |= write_note_subs(hndl, obj_elt, obj->note);
+    if (obj->husband_age) {
+      result |= gedcom_write_element_str(hndl, ELT_SUB_FAM_EVT_HUSB, 0,
+                                        obj_elt, NULL);
+      result |= gedcom_write_element_age(hndl, ELT_SUB_FAM_EVT_AGE, 0,
+                                        ELT_SUB_FAM_EVT_HUSB,
+                                        obj->husband_age);
+    }
+    if (obj->wife_age) {
+      result |= gedcom_write_element_str(hndl, ELT_SUB_FAM_EVT_WIFE, 0,
+                                        obj_elt, NULL);
+      result |= gedcom_write_element_age(hndl, ELT_SUB_FAM_EVT_AGE, 0,
+                                        ELT_SUB_FAM_EVT_WIFE,
+                                        obj->wife_age);
+    }
+    if (obj->family) {
+      int fam_obj_elt = get_gedcom_fam_elt(obj_elt);
+      result |= gedcom_write_element_xref(hndl, fam_obj_elt, 0,
+                                         obj_elt, obj->family);
+      if (obj->adoption_parent) {
+       result |= gedcom_write_element_str(hndl, ELT_SUB_INDIV_ADOP_FAMC_ADOP,
+                                          0, fam_obj_elt,
+                                          obj->adoption_parent);
+      }
+    }
+    if (obj->extra)
+      result |= write_user_data(hndl, obj->extra);
   }
+  
+  return result;
 }
+