/*================================================== * open_or_create_database -- open database, prompt for * creating new one if it doesn't exist * if fails, displays error (show_open_error) and returns * FALSE * alteration: [IN] flags for locking, forcing open... * dbused: [I/O] actual database path (may be relative) * If this routine creates new database, it will alter dbused * Created: 2001/04/29, Perry Rapp *================================================*/ BOOLEAN open_or_create_database (INT alteration, STRING *dbused) { INT lldberrnum=0; /* Open Database */ if (open_database(alteration, *dbused, &lldberrnum)) return TRUE; /* filter out real errors */ if (lldberrnum != BTERR_NODB && lldberrnum != BTERR_NOKEY) { show_open_error(lldberrnum); return FALSE; } if (readonly || immutable || alteration) { llwprintf(_("Cannot create new database with -r, -i, -l, or -f flags.")); return FALSE; } /* error was only that db doesn't exist, so lets try making a new one If no database directory specified, add prefix llnewdbdir */ if (is_unadorned_directory(*dbused)) { STRING dbpath = getlloptstr("LLDATABASES", "."); CNSTRING newdbdir = get_first_path_entry(dbpath); STRING temp = *dbused; if (newdbdir) { char tempth[MAXPATHLEN]; newdbdir = strdup(newdbdir); concat_path(newdbdir, *dbused, uu8, tempth, sizeof(tempth)); *dbused = strsave(tempth); stdfree(temp); stdfree((STRING)newdbdir); } } /* Is user willing to make a new db ? */ if (!ask_yes_or_no_msg(_(qSnodbse), _(qScrdbse))) return FALSE; /* try to make a new db */ if (create_database(*dbused, &lldberrnum)) return TRUE; show_open_error(lldberrnum); return FALSE; }
/*========================================================== * add_indi_by_edit -- Add new person to database by editing * (with user interaction) * returns addref'd record *========================================================*/ RECORD add_indi_by_edit (RFMT rfmt) { FILE *fp; RECORD indi0=0; NODE indi=0; STRING str, msg; BOOLEAN emp; XLAT ttmi = transl_get_predefined_xlat(MEDIN); if (readonly) { message(_(qSronlya)); return NULL; } /* Create person template for user to edit */ if (!(fp = fopen(editfile, LLWRITETEXT))) return NULL; prefix_file_for_edit(fp); /* prefer useroption in this db */ if ((str = getlloptstr("INDIREC", NULL))) fprintf(fp, "%s\n", str); else { /* default */ fprintf(fp, "0 INDI\n1 NAME Fname/Surname\n1 SEX MF\n"); fprintf(fp, "1 BIRT\n 2 DATE\n 2 PLAC\n"); fprintf(fp, "1 DEAT\n 2 DATE\n 2 PLAC\n1 SOUR\n"); } /* Have user edit new person record */ fclose(fp); do_edit(); while (TRUE) { INT cnt; if (indi0) { release_record(indi0); indi0=0; } indi0 = file_to_record(editfile, ttmi, &msg, &emp); if (!indi0) { if (ask_yes_or_no_msg(msg, _(qSiredit))) { do_edit(); continue; } break; } indi = nztop(indi0); cnt = resolve_refn_links(indi); /* check validation & allow user to reedit if invalid */ /* this is a showstopper, so alternative is to abort */ if (!valid_indi_tree(indi, &msg, NULL)) { if (ask_yes_or_no_msg(msg, _(qSiredit))) { do_edit(); continue; } release_record(indi0); indi0 = NULL; break; } /* Allow user to reedit if desired if any refn links unresolved */ /* this is not a showstopper, so alternative is to continue */ if (cnt > 0) { char msgb[120]; llstrncpyf(msgb, sizeof(msgb), uu8 , get_unresolved_ref_error_string(cnt), cnt); if (ask_yes_or_no_msg(msgb, _(qSireditopt))) { write_indi_to_file_for_edit(indi, editfile, rfmt); do_edit(); continue; } } break; } if (!indi0 || !ask_yes_or_no(_(qScfpadd))) { if (indi0) release_record(indi0); return NULL; } /* add the new record to the database */ add_new_indi_to_db(indi0); msg_status(_(qSgdpadd), indi_to_name(nztop(indi0), 35)); return indi0; }
/*================================================ * edit_add_record -- Add record to database by editing * recstr: [IN] default record * redt: [IN] re-edit message * ntype, [IN] S, E, or X * cfrm: [IN] confirm message *==============================================*/ static RECORD edit_add_record (STRING recstr, STRING redt, STRING redtopt, char ntype, STRING cfrm) { FILE *fp; NODE node=0, refn; STRING msg, key; BOOLEAN emp; XLAT ttmi = transl_get_predefined_xlat(MEDIN); STRING (*getreffnc)(void) = NULL; /* get next internal key */ void (*todbasefnc)(NODE) = NULL; /* write record to dbase */ void (*tocachefnc)(NODE) = NULL; /* write record to cache */ /* set up functions according to type */ if (ntype == 'S') { getreffnc = getsxref; todbasefnc = sour_to_dbase; tocachefnc = sour_to_cache; } else if (ntype == 'E') { getreffnc = getexref; todbasefnc = even_to_dbase; tocachefnc = even_to_cache; } else { /* X */ getreffnc = getxxref; todbasefnc = othr_to_dbase; tocachefnc = othr_to_cache; } /* Create template for user to edit */ if (!(fp = fopen(editfile, LLWRITETEXT))) { msg_error(_(qSnofopn), editfile); return FALSE; } prefix_file_for_edit(fp); fprintf(fp, "%s\n", recstr); /* Have user edit new record */ fclose(fp); do_edit(); while (TRUE) { INT cnt; node = file_to_node(editfile, ttmi, &msg, &emp); if (!node) { if (ask_yes_or_no_msg(msg, redt)) { /* yes, edit again */ do_edit(); continue; } break; } cnt = resolve_refn_links(node); /* check validation & allow user to reedit if invalid */ /* this is a showstopper, so alternative is to abort */ if (!valid_node_type(node, ntype, &msg, NULL)) { if (ask_yes_or_no_msg(msg, redt)) { do_edit(); continue; } free_nodes(node); node = NULL; /* fail out */ break; } /* Allow user to reedit if desired if any refn links unresolved */ /* this is not a showstopper, so alternative is to continue */ if (cnt > 0) { char msgb[120]; snprintf(msgb, sizeof(msgb) , get_unresolved_ref_error_string(cnt), cnt); if (ask_yes_or_no_msg(msgb, redtopt)) { write_node_to_editfile(node); do_edit(); continue; } } break; } if (!node || !ask_yes_or_no(cfrm)) { if (node) free_nodes(node); return NULL; } nxref(node) = strsave((STRING)(*getreffnc)()); key = rmvat(nxref(node)); for (refn = nchild(node); refn; refn = nsibling(refn)) { if (eqstr("REFN", ntag(refn)) && nval(refn)) add_refn(nval(refn), key); } (*todbasefnc)(node); (*tocachefnc)(node); return key_to_record(key); }
/*======================================= * edit_record -- Edit record in database * root1: [IN] record to edit (may be NULL) * idedt: [IN] user id prompt * letr: [IN] record type (E, S, or X) * redt: [IN] reedit prompt displayed if hard error after editing * redtopt: [IN] reedit prompt displayed if soft error (unresolved links) * val: [IN] callback to validate routine * cfrm: [IN] confirmation msg string * tag: [IN] tag (SOUR, EVEN, or NULL) * todbase: [IN] callback to write record to dbase * gdmsg: [IN] success message * rfmt: [IN] display reformatter *=====================================*/ static BOOLEAN edit_record (RECORD rec1, STRING idedt, INT letr, STRING redt, STRING redtopt , BOOLEAN (*val)(NODE, STRING *, NODE) , STRING cfrm, void (*todbase)(NODE), STRING gdmsg , RFMT rfmt) { XLAT ttmi = transl_get_predefined_xlat(MEDIN); STRING msg, key; BOOLEAN emp; NODE root0=0, root1=0, root2=0; NODE refn1=0, refn2=0, refnn=0, refn1n=0; NODE body=0, node=0; /* Identify record if need be */ if (!rec1) { rec1 = ask_for_record(idedt, letr); } root1 = nztop(rec1); if (!root1) { message(_(qSnosuchrec)); return FALSE; } /* Have user edit record */ annotate_with_supplemental(root1, rfmt); write_node_to_editfile(root1); resolve_refn_links(root1); do_edit(); if (readonly) { root2 = file_to_node(editfile, ttmi, &msg, &emp); if (!equal_tree(root1, root2)) message(_(qSronlye)); free_nodes(root2); return FALSE; } while (TRUE) { INT cnt; root2 = file_to_node(editfile, ttmi, &msg, &emp); if (!root2) { if (ask_yes_or_no_msg(msg, redt)) { do_edit(); continue; } break; } cnt = resolve_refn_links(root2); /* check validation & allow user to reedit if invalid */ /* this is a showstopper, so alternative is to abort */ if (!(*val)(root2, &msg, root1)) { if (ask_yes_or_no_msg(msg, redt)) { do_edit(); continue; } free_nodes(root2); root2 = NULL; break; } /* Allow user to reedit if desired if any refn links unresolved */ /* this is not a showstopper, so alternative is to continue */ if (cnt > 0) { char msgb[120]; snprintf(msgb, sizeof(msgb) , get_unresolved_ref_error_string(cnt), cnt); if (ask_yes_or_no_msg(msgb, redtopt)) { write_node_to_editfile(root2); do_edit(); continue; } } break; } /* If error or no change or user backs out return */ if (!root2) return FALSE; if (equal_tree(root1, root2) || !ask_yes_or_no(cfrm)) { free_nodes(root2); return FALSE; } /* Prepare to change database */ /* Move root1 data into root0 & save refns */ split_othr(root1, &refn1, &body); root0 = copy_node(root1); join_othr(root0, NULL, body); /* delete root0 tree & root1 node (root1 is solitary node) */ free_nodes(root0); root0 = 0; free_nodes(root1); root1 = 0; /* now copy root2 node into root1, then root2 tree under it */ root1 = copy_node(root2); split_othr(root2, &refn2, &body); refnn = copy_nodes(refn2, TRUE, TRUE); join_othr(root1, refn2, body); /* now root2 is solitary node, delete it */ free_node(root2); root2 = 0; /* Change the database */ (*todbase)(root1); key = rmvat(nxref(root1)); /* remove deleted refns & add new ones */ classify_nodes(&refn1, &refnn, &refn1n); for (node = refn1; node; node = nsibling(node)) if (nval(node)) remove_refn(nval(node), key); for (node = refnn; node; node = nsibling(node)) if (nval(node)) add_refn(nval(node), key); free_nodes(refn1); free_nodes(refnn); free_nodes(refn1n); msg_info(gdmsg); return TRUE; }
/*================================================= * do_import -- Read GEDCOM file to database * ifeed: [IN] output methods * fp: [I/O] GEDCOM file whence to load data *===============================================*/ static BOOLEAN do_import (IMPORT_FEEDBACK ifeed, FILE *fp) { NODE node, conv; XLAT ttm = 0; STRING msg; BOOLEAN emp; INT nindi = 0, nfam = 0, neven = 0; INT nsour = 0, nothr = 0, type, num = 0; INT totkeys = 0, totused = 0; char msgbuf[80]; BOOLEAN succeeded=FALSE; STRING str,unistr=0; ZSTR zerr=0; TABLE metadatatab = create_table_str(); STRING gdcodeset=0; INT warnings=0; /* start by assuming default */ strupdate(&gdcodeset, gedcom_codeset_in); /* rptui_init(); *//* clear ui time counter */ /* Open and validate GEDCOM file */ if ((unistr=check_file_for_unicode(fp)) && !eqstr(unistr, "UTF-8")) { msg_error(_(qSunsupuniv), unistr); goto end_import; } if (eqstr_ex(unistr, "UTF-8")) { strupdate(&gdcodeset, "UTF-8"); } if (!scan_header(fp, metadatatab, &zerr)) { msg_error(zs_str(zerr)); goto end_import; } if ((str = valueof_str(metadatatab, "GEDC.FORM"))!= NULL) { if (!eqstr(str, "LINEAGE-LINKED")) { if (!ask_yes_or_no_msg( _("This is not a lineage linked GEDCOM file.") , _("Proceed anyway?") )) goto end_import; } } if (!unistr && (str = valueof_str(metadatatab, "CHAR"))!= NULL) { /* if no BOM, use file's declared encoding if present */ strupdate(&gdcodeset, str); } /* TODO: Push this codeset question down to after the validation, where we can know if the incoming file happened to really be all ASCII */ if (!int_codeset[0]) { /* TODO: ask if user would like to adopt codeset of incoming file, if we found it */ if (!ask_yes_or_no_msg( _("No current internal codeset, so no codeset conversion can be done") , _("Proceed without codeset conversion?") )) goto end_import; } /* Warn if lossy code conversion likely */ if (gdcodeset[0] && int_codeset[0]) { if (is_lossy_conversion(gdcodeset, int_codeset)) { ZSTR zstr=zs_new(); zs_setf(zstr, _("Lossy codeset conversion (from <%s> to <%s>) likely") , gdcodeset, int_codeset); if (!ask_yes_or_no_msg( zs_str(zstr) , _("Proceed anyway?") )) goto end_import; } } /* validate */ if (ifeed && ifeed->validating_fnc) (*ifeed->validating_fnc)(); if (!validate_gedcom(ifeed, fp)) { if (ifeed && ifeed->error_invalid_fnc) (*ifeed->error_invalid_fnc)(_(qSgdnadd)); goto end_import; } warnings = validate_get_warning_count(); if (warnings) { ZSTR zstr=zs_new(); zs_setf(zstr, _pl("%d warning during import", "%d warnings during import", warnings), warnings); if (!ask_yes_or_no_msg(zs_str(zstr), _(qSproceed))) { goto end_import; } } if (gdcodeset[0] && int_codeset[0]) { retry_input_codeset: ttm = transl_get_xlat(gdcodeset, int_codeset); if (!transl_is_xlat_valid(ttm)) { ZSTR zstr=zs_new(); char csname[64]; BOOLEAN b; transl_release_xlat(ttm); ttm = 0; zs_setf(zstr, _("Cannot convert codeset (from <%s> to <%s>)") , gdcodeset, int_codeset); b = ask_for_string(zs_str(zstr) , _("Enter codeset to assume (* for none)") , csname, sizeof(csname)) && csname[0]; zs_free(&zstr); if (!b) goto end_import; if (!eqstr(csname, "*")) { strupdate(&gdcodeset, csname); goto retry_input_codeset; } } } if((num_indis() > 0) || (num_fams() > 0) || (num_sours() > 0) || (num_evens() > 0) || (num_othrs() > 0)) gd_reuse = FALSE; else if((gd_reuse = check_stdkeys())) { totused = gd_itot + gd_ftot + gd_stot + gd_etot + gd_xtot; totkeys = gd_imax + gd_fmax + gd_smax + gd_emax + gd_xmax; if((totkeys-totused) > 0) { INT delkeys = totkeys-totused; snprintf(msgbuf, sizeof(msgbuf) , _pl("Using original keys, %d deleted record will be in the database." , "Using original keys, %d deleted records will be in the database." , delkeys) , delkeys ); } else strcpy(msgbuf, " "); gd_reuse = ask_yes_or_no_msg(msgbuf, _(qScfoldk)); /* TODO: why were these here ? touchwin(uiw_win(stdout_win)); wrefresh(uiw_win(stdout_win)); */ } /* start loading the file */ rewind(fp); /* test for read-only database here */ if(readonly) { if (ifeed && ifeed->error_readonly_fnc) (*ifeed->error_readonly_fnc)(); goto end_import; } /* tell user we are beginning real part of import */ if (ifeed && ifeed->beginning_import_fnc) { if(gd_reuse) (*ifeed->beginning_import_fnc)(_(qSdboldk)); else (*ifeed->beginning_import_fnc)(_(qSdbnewk)); } /* Add records to database */ node = convert_first_fp_to_node(fp, FALSE, ttm, &msg, &emp); while (node) { if (!(conv = node_to_node(node, &type))) { free_nodes(node); node = next_fp_to_node(fp, FALSE, ttm, &msg, &emp); continue; } switch (type) { case INDI_REC: num = ++nindi; break; case FAM_REC: num = ++nfam; break; case EVEN_REC: num = ++neven; break; case SOUR_REC: num = ++nsour; break; case OTHR_REC: num = ++nothr; break; default: FATAL(); } restore_record(conv, type, num); if (ifeed && ifeed->added_rec_fnc) ifeed->added_rec_fnc(nxref(conv)[1], ntag(conv), num); free_nodes(node); node = next_fp_to_node(fp, FALSE, ttm, &msg, &emp); } if (msg) { msg_error(msg); } if(gd_reuse && ((totkeys - totused) > 0)) { if (ifeed && ifeed->adding_unused_keys_fnc) (*ifeed->adding_unused_keys_fnc)(); addmissingkeys(INDI_REC); addmissingkeys(FAM_REC); addmissingkeys(EVEN_REC); addmissingkeys(SOUR_REC); addmissingkeys(OTHR_REC); } succeeded = TRUE; end_import: validate_end_import(); zs_free(&zerr); destroy_table(metadatatab); strfree(&gdcodeset); return succeeded; }