/*=============================================================== * disp_shrt_format_date -- short form of date for display * This is used for dates in option strings, and in single-line * descriptions of people (ie, in event summaries). * Created: 2001/10/29 (Perry Rapp) *=============================================================*/ static STRING disp_shrt_format_date (STRING date) { INT dfmt=0,mfmt=0,yfmt=0,sfmt=0,efmt=0, cmplx; INT n; STRING fmts, pic; if (!date) return NULL; n = 0; fmts = getlloptstr("ShortDisplayDate", NULL); if (fmts) { /* try to use user-specified format */ n = sscanf(fmts, "%ld,%ld,%ld,%ld,%ld,%ld" , &dfmt, &mfmt, &yfmt, &sfmt, &efmt, &cmplx); } if (n != 6) { dfmt=mfmt=yfmt=sfmt=cmplx=0; sfmt=12; /* old style short form -- year only */ } pic = getlloptstr("ShortDisplayDatePic", NULL); if (pic && pic[0]) set_date_pic(pic); return do_format_date(date, dfmt, mfmt, yfmt, sfmt, efmt, cmplx); }
/*=========================================================== * disp_long_format_date -- Convert date according to options *=========================================================*/ static STRING disp_long_format_date (STRING date) { INT dfmt=0,mfmt=0,yfmt=0,sfmt=0,efmt=0, cmplx; INT n; STRING fmts, pic; if (!date) return NULL; n = 0; fmts = getlloptstr("LongDisplayDate", NULL); if (fmts) { /* try to use user-specified format */ n = sscanf(fmts, "%ld,%ld,%ld,%ld,%ld,%ld" , &dfmt, &mfmt, &yfmt, &sfmt, &efmt, &cmplx); } if (n != 6) { dfmt=mfmt=yfmt=sfmt=efmt=cmplx=0; sfmt=14; /* GEDCOM as is */ } pic = getlloptstr("LongDisplayDatePic", NULL); if (pic && pic[0]) set_date_pic(pic); return do_format_date(date, dfmt, mfmt, yfmt, sfmt, efmt, cmplx); }
/*================================ * save_gedcom -- save gedcom file *==============================*/ BOOLEAN save_gedcom (void) { FILE *fp=NULL; struct tag_export_feedback efeed; STRING srcdir=NULL, fname=0, fullpath=0; srcdir = getlloptstr("LLARCHIVES", "."); fp = ask_for_output_file(LLWRITETEXT, _(qSoutarc), &fname, &fullpath, srcdir, ".ged"); if (!fp) { strfree(&fname); msg_error(_("The database was not saved.")); return FALSE; } prefix_file_for_gedcom(fp); memset(&efeed, 0, sizeof(efeed)); efeed.added_rec_fnc = export_saved_rec; llwprintf(_("Saving database `%s' in file `%s'."), readpath_file, fullpath); /* Display 0 counts */ clear_rec_counts(0); archive_in_file(&efeed, fp); fclose(fp); wpos(7,0); msg_info(_(qSoutfin), readpath_file, fname); strfree(&fname); return TRUE; }
/*========================================================== * transl_load_all_tts -- Load internal list of available translation * tables (based on *.tt files in TTPATH) * Created: 2002/11/28 (Perry Rapp) *========================================================*/ void transl_load_all_tts (void) { CNSTRING ttpath = getlloptstr("TTPATH", "."); if (!inited) local_init(); xl_load_all_dyntts(ttpath); }
/*======================================+ * set_output_file -- Open specified output file * (Closes any previously open output file) * Calls msg_error & returns FALSE, if problem *=====================================*/ static BOOLEAN set_output_file (STRING outfname, BOOLEAN append) { STRING modestr = append ? LLAPPENDTEXT:LLWRITETEXT; STRING rptdir=0; if (Poutfp) { finishrassa(); fclose(Poutfp); Poutfp = NULL; } rptdir = getlloptstr("LLREPORTS", "."); Poutfp = fopenpath(outfname, modestr, rptdir, NULL, uu8, NULL); if (!Poutfp) { /* TODO: need to forward this through rptui */ msg_error(_("Could not open file %s"), outfname); return FALSE; } /* if appending to existing non-empty file, don't add BOM */ if (append) { long offset = 0; fseek(Poutfp, 0, SEEK_END); offset = ftell(Poutfp); if (offset > 0) return TRUE; } prefix_file_for_report(Poutfp); return TRUE; }
/*====================================+ * request_file -- Prompt user for file name * returns open file pointer, or NULL if error * handles error message * Created: 2002/01/18 *===================================*/ static BOOLEAN request_file (BOOLEAN *eflg) { STRING rptdir = getlloptstr("LLREPORTS", "."); STRING fname=0, fullpath=0; Poutfp = rptui_ask_for_output_file(LLWRITETEXT, _(qSwhtout), &fname , &fullpath, rptdir, NULL); if (!Poutfp || !fname || !fname[0]) { if (fname) prog_error(0, _("Report stopping due to error opening output file")); else prog_error(0, _("Report stopping due to lack of output file")); /* set error flag to stop interpreter */ *eflg = TRUE; /* set cancel flag to suppress traceback */ rpt_cancelled = TRUE; strfree(&fname); return FALSE; } if (outfilename) stdfree(outfilename); outfilename = fullpath; strfree(&fname); prefix_file_for_report(Poutfp); return TRUE; }
/*================================ * load_gedcom -- have user select gedcom file & import it *==============================*/ void load_gedcom (BOOLEAN picklist) { FILE *fp=NULL; struct tag_import_feedback ifeed; STRING srcdir=NULL; STRING fullpath=0; time_t begin = time(NULL); time_t beginui = get_uitime(); srcdir = getlloptstr("InputPath", "."); if (!ask_for_gedcom(LLREADTEXT, _(qSwhatgedc), 0, &fullpath, srcdir, ".ged", picklist) || !(fp = fopen(fullpath, LLREADBINARY))) { strfree(&fullpath); return; } /* Note: we read the file in binary mode, so ftell & fseek will work correctly. Microsoft's ftell/fseek do not work correctly if the file has simple unix (\n) line terminations! -- Perry, 2003-02-11 */ memset(&ifeed, 0, sizeof(ifeed)); ifeed.validating_fnc = import_validating; ifeed.validated_rec_fnc = import_validated_rec; ifeed.beginning_import_fnc = import_beginning_import; ifeed.error_invalid_fnc = import_error_invalid; ifeed.error_readonly_fnc = import_readonly; ifeed.adding_unused_keys_fnc = import_adding_unused_keys; ifeed.added_rec_fnc = import_added_rec; ifeed.validation_error_fnc = import_validation_error; ifeed.validation_warning_fnc = import_validation_warning; import_from_gedcom_file(&ifeed, fp); fclose(fp); strfree(&fullpath); if (1) { INT duration = time(NULL) - begin; INT uitime = get_uitime() - beginui; ZSTR zt1=approx_time(duration-uitime), zt2=approx_time(uitime); /* TRANSLATORS: how long Import ran, and how much of that was UI delay */ ZSTR zout = zs_newf(_("Import time %s (ui %s)\n") , zs_str(zt1), zs_str(zt2)); wfield(8,0, zs_str(zout)); zs_free(&zt1); zs_free(&zt2); zs_free(&zout); } /* position cursor further down stdout so check_stdout doesn't overwrite our messages from above */ wpos(15,0); }
/*=============================================+ * vprog_error -- Report a run time program error * node: current parsed node * fmt, args: printf style message * ...: printf style varargs * Prints error to the stdout-style curses window * and to the report log (if one was specified in config file) * Always includes line number of node, if available * Only includes file name if not same as previous error * Returns static buffer with one-line description *============================================*/ static STRING vprog_error (PNODE node, STRING fmt, va_list args) { INT num; STRING rptfile; ZSTR zstr=zs_newn(256); static char msgbuff[100]; if (rpt_cancelled) return _("Report cancelled"); rptfile = getlloptstr("ReportLog", NULL); if (node) { STRING fname = irptinfo(node)->fullpath; INT lineno = iline(node)+1; /* Display filename if not same as last error */ if (!eqstr(vprog_prevfile, fname)) { llstrsets(vprog_prevfile, sizeof(vprog_prevfile), uu8, fname); zs_apps(zstr, _("Report file: ")); zs_apps(zstr, fname); zs_appc(zstr, '\n'); vprog_prevline = -1; /* force line number display */ } /* Display line number if not same as last error */ if (vprog_prevline != lineno) { vprog_prevline = lineno; if (progparsing) zs_appf(zstr, _("Parsing Error at line %d: "), lineno); else zs_appf(zstr, _("Runtime Error at line %d: "), lineno); } } else { zs_apps(zstr, _("Aborting: ")); } zs_appvf(zstr, fmt, args); llwprintf("\n"); llwprintf(zs_str(zstr)); ++progerror; /* if user specified a report error log (in config file) */ if (rptfile && rptfile[0]) { FILE * fp = fopen(rptfile, LLAPPENDTEXT); if (fp) { if (progerror == 1) { LLDATE creation; get_current_lldate(&creation); fprintf(fp, "\n%s\n", creation.datestr); } fprintf(fp, "%s", zs_str(zstr)); fprintf(fp, "\n"); fclose(fp); } } if ((num = getlloptint("PerErrorDelay", 0))) sleep(num); zs_free(&zstr); return msgbuff; }
/*==================================================== * edit_add_other -- Add user record to database by editing *==================================================*/ RECORD edit_add_other (void) { STRING str; if (readonly) { message(_(qSronlya)); return NULL; } str = getlloptstr("OTHR", _(qSdefothr)); return edit_add_record(str, _(qSxredit), _(qSxreditopt), 'X', _(qScfxadd)); }
/*================================================ * edit_add_source -- Add source to database by editing *==============================================*/ RECORD edit_add_source (void) { STRING str; if (readonly) { message(_(qSronlya)); return NULL; } str = getlloptstr("SOURREC", _(qSdefsour)); return edit_add_record(str, _(qSrredit), _(qSrreditopt), 'S', _(qScfradd)); }
/*============================================== * edit_add_event -- Add event to database by editing *============================================*/ RECORD edit_add_event (void) { STRING str; if (readonly) { message(_(qSronlya)); return NULL; } str = getlloptstr("EVENREC", _(qSdefeven)); return edit_add_record(str, _(qSeredit), _(qSereditopt), 'E', _(qScfeadd)); }
/*================================================== * load_configs -- Load global config file(s) * returns FALSE if error, with message in pmsg *================================================*/ static BOOLEAN load_configs (STRING configfile, STRING * pmsg) { INT rtn=0; STRING str=0; char cfg_name[MAXPATHLEN]; /* TODO: Should read a system-wide config file */ if (!configfile) configfile = getenv("LLCONFIGFILE"); *pmsg = NULL; if (configfile && configfile[0]) { rtn = load_global_options(configfile, pmsg); if (rtn == -1) return FALSE; } else { /* No config file specified, so load config_file(s) from the standard places */ /* look for global config file */ llstrncpy(cfg_name, global_conf_path, sizeof(cfg_name), 0); llstrapps(cfg_name, sizeof(cfg_name), 0, "/lifelines.conf"); rtn = load_global_options(cfg_name, pmsg); if (rtn == -1) return FALSE; /* look for one in user's home directory */ /* TODO: Shouldn't Win32 use getenv("USERPROFILE") ? */ llstrncpy(cfg_name, getenv("HOME") , sizeof(cfg_name), 0); /*llstrappc(cfg_name, sizeof(cfg_name), '/');*/ llstrapps(cfg_name, sizeof(cfg_name), 0, "/" LINES_CONFIG_FILE); rtn = load_global_options(cfg_name, pmsg); if (rtn == -1) return FALSE; rtn = load_global_options(LINES_CONFIG_FILE, pmsg); if (rtn == -1) return FALSE; } /* allow chaining to one more config file * if one was defined for the database */ str = getlloptstr("LLCONFIGFILE", NULL); if (str && str[0]) { rtn = load_global_options(str, pmsg); if (rtn == -1) return FALSE; } return TRUE; }
/*================================================== * select_database -- open database (prompting if appropriate) * if fail, return FALSE, and possibly a message to display * perrmsg - [OUT] translated error message *================================================*/ BOOLEAN select_database (STRING dbrequested, INT alteration, STRING * perrmsg) { STRING dbdir = getlloptstr("LLDATABASES", "."); STRING dbused = 0; /* Get Database Name (Prompt or Command-Line) */ if (!dbrequested || !dbrequested[0]) { char dbname[MAXPATHLEN]; /* ask_for_db_filename returns static buffer, we save it below */ if (!ask_for_db_filename(_(qSidldir), _(qSidldrp), dbdir, dbname, sizeof(dbname)) || !dbname[0]) { dbrequested = NULL; *perrmsg = _(qSiddbse); return FALSE; } dbrequested = strsave(dbname); if (eqstr(dbrequested, "?")) { INT n=0; LIST dblist=0, dbdesclist=0; strfree(&dbrequested); if ((n=get_dblist(dbdir, &dblist, &dbdesclist)) > 0) { INT i; i = choose_from_list( _("Choose database to open") , dbdesclist); if (i >= 0) { dbrequested = strsave(get_list_element(dblist, i+1, NULL)); } release_dblist(dblist); release_dblist(dbdesclist); } else { *perrmsg = _("No databases found in database path"); return FALSE; } if (!dbrequested) { *perrmsg = _(qSiddbse); return FALSE; } } } /* search for database */ /* search for file in lifelines path */ dbused = filepath(dbrequested, "r", dbdir, NULL, uu8); /* filepath returns alloc'd string */ if (!dbused) dbused = strsave(dbrequested); if (!open_or_create_database(alteration, &dbused)) { return FALSE; } return TRUE; }
/*================================================== * 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; }
/*============================= * create_table_impl -- Create table * All tables are created in this function * returns addref'd table *===========================*/ static TABLE create_table_impl (enum TB_VALTYPE valtype, DELFUNC delfunc) { TABLE tab = (TABLE) stdalloc(sizeof(*tab)); tab->vtable = &vtable_for_table; tab->refcnt = 1; tab->valtype = valtype; if (getlloptstr("rbtree", 0)) tab->rbtree = RbTreeCreate(tab, rbcompare, rbdestroy); else tab->hashtab = create_hashtab(); tab->destroyfunc = delfunc; return tab; }
/*=================================================== * update_useropts -- Set any global variables * dependent on user options *=================================================*/ void update_useropts (VPTR uparm) { uparm = uparm; /* unused */ if (suppress_reload) return; /* deal with db-specific options */ /* includes setting int_codeset */ if (def_lldb) update_db_options(); /* in case user changed any codesets */ init_codesets(); /* in case user changed locale (need int_codeset already set) */ uilocale(); /* in case user changed codesets */ /* TODO: Isn't this superfluous, as it was called in update_db_options above ? */ transl_load_xlats(); strupdate(&illegal_char, getlloptstr("IllegalChar", 0)); nodechk_enable(!!getlloptint("nodecheck", 0)); }
/*================================================== * create_database -- create (& open) brand new database * dbpath: [IN] path of database about to create *================================================*/ BOOLEAN create_database (STRING dbpath, INT *lldberr) { LLDATABASE lldb = lldb_alloc(); BTREE btree = 0; /* first test that newdb props are legal */ STRING props = getlloptstr("NewDbProps", 0); if (props && props[0]) { TABLE dbopts = create_table_str(); STRING msg=0; if (!init_valtab_from_string(props, dbopts, '=', &msg)) { *lldberr = BTERR_BADPROPS; destroy_table(dbopts); return FALSE; } destroy_table(dbopts); } /* tentatively copy paths into gedlib module versions */ readpath_file=strsave(lastpathname(dbpath)); readpath=strsave(dbpath); if (!(btree = bt_openbtree(dbpath, TRUE, 2, immutable, lldberr))) { /* open failed so clean up, preserve lldberr */ int myerr = *lldberr; lldb_close(&lldb); *lldberr = myerr; return FALSE; } def_lldb = lldb; lldb_set_btree(lldb, btree); initxref(); if (props) store_record("VUOPT", props, strlen(props)); return TRUE; }
/*=========================================== * main -- Main procedure of dbverify command *=========================================*/ int main (int argc, char **argv) { char *flags, *dbname; char *ptr; char * msg; BOOLEAN cflag=FALSE; /* create new db if not found */ INT writ=1; /* request write access to database */ BOOLEAN immut=FALSE; /* immutable access to database */ BOOLEAN allchecks=FALSE; /* if user requested all checks */ INT returnvalue=1; STRING crashlog=NULL; INT lldberrnum=0; int i=0; /* initialize all the low-level library code */ init_stdlib(); validate_errs(); #if HAVE_SETLOCALE /* initialize locales */ setlocale(LC_ALL, ""); #endif /* HAVE_SETLOCALE */ #if ENABLE_NLS ll_bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); #endif save_original_locales(); #ifdef WIN32 /* TO DO - research if this is necessary */ _fmode = O_BINARY; /* default to binary rather than TEXT mode */ #endif /* handle conventional arguments --version and --help */ /* needed for help2man to synthesize manual pages */ for (i=1; i<argc; ++i) { if (!strcmp(argv[i], "--version")) { print_version("dbverify"); return 0; } if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "-?")) { print_usage(); return 0; } } if (argc != 3 || argv[1][0] != '-' || argv[1][1] == '\0') { print_usage(); goto done; } flags = argv[1]; dbname = argv[2]; for (ptr=&flags[1]; *ptr; ++ptr) { switch(*ptr) { case 'l': todo.check_dbstructure=TRUE; break; case 'g': todo.find_ghosts=TRUE; break; case 'G': todo.fix_ghosts=TRUE; break; case 'i': todo.check_indis=TRUE; break; case 'f': todo.check_fams=TRUE; break; case 's': todo.check_sours=TRUE; break; case 'e': todo.check_evens=TRUE; break; case 'x': todo.check_othes=TRUE; break; case 'n': noisy=TRUE; break; case 'a': allchecks=TRUE; break; case 'F': todo.fix_alter_pointers=TRUE; break; case 'm': todo.check_missing_data_records=TRUE; break; case 'M': todo.fix_missing_data_records=TRUE; break; case 'D': todo.fix_deletes=TRUE; break; case 'v': print_version("llexec"); goto done; case 'h': default: print_usage(); goto done; } } /* Turn off Memory Debugging */ /* This is unnecessary -- it is off anyway, Perry, 2001/10/28 */ alloclog = FALSE; /* Enable any checks needed for fixes selected */ if (todo.fix_missing_data_records) todo.check_missing_data_records = 1; /* initialize options & misc. stuff */ llgettext_set_default_localedir(LOCALEDIR); if (!init_lifelines_global(0, &msg, 0)) { printf("%s\n", msg); goto done; } /* setup crashlog in case init_screen fails (eg, bad menu shortcuts) */ crashlog = getlloptstr("CrashLog_dbverify", NULL); if (!crashlog) { crashlog = "Crashlog_dbverify.log"; } crash_setcrashlog(crashlog); /* NB: This assumes btree database */ if (!(BTR = bt_openbtree(dbname, cflag, writ, immut, &lldberrnum))) { char buffer[256]; describe_dberror(lldberrnum, buffer, ARRSIZE(buffer)); puts(buffer); goto done; } /* Do low-level checks before initializing lifelines database layer, because lifelines database init traverses btree for user options and translation tables, and here we check the infrastructure of the btree itself. */ if (todo.check_dbstructure || allchecks) { if (!check_btree(BTR)) goto done; } if (!init_lifelines_postdb()) { printf(_(qSbaddb)); goto done; } printf(_("Checking %s"), dbname); puts(""); /* all checks - if any new ones, have to update this */ if (allchecks) { todo.check_indis=todo.check_fams=todo.check_sours=TRUE; todo.check_evens=todo.check_othes=TRUE; todo.find_ghosts=TRUE; } if (todo.find_ghosts || todo.fix_ghosts) check_ghosts(); if (!(bwrite(BTR))) { todo.fix_alter_pointers = FALSE; todo.fix_ghosts = FALSE; } if (todo.check_indis || todo.check_fams || todo.check_sours || todo.check_evens || todo.check_othes) { check_and_fix_records(); } if (todo.check_missing_data_records) { check_missing_data_records(); } report_results(); closebtree(BTR); /* TODO: probably should call lldb_close, Perry 2005-10-07 */ BTR = 0; returnvalue = 0; done: return returnvalue; }
/*========================================================== * 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; }
/*================================= * init_lifelines_global -- Initialization options & misc. stuff * This is called before first (or later) database opened *===============================*/ BOOLEAN init_lifelines_global (STRING configfile, STRING * pmsg, void (*notify)(STRING db, BOOLEAN opening)) { STRING e; STRING dirvars[] = { "LLPROGRAMS", "LLREPORTS", "LLARCHIVES" , "LLDATABASES", }; INT i; check_installation_path(); /* request notification when options change */ register_notify(&update_useropts); suppress_reload = TRUE; dbnotify_set(notify); if (!load_configs(configfile, pmsg)) { suppress_reload = FALSE; update_useropts(NULL); return FALSE; } pre_codesets_hook(); /* For MS-Windows user config of console codepages */ /* now that codeset variables are set from config file, lets initialize codesets */ /* although int_codeset can't be determined yet, we need GUI codeset for gettext */ init_codesets(); post_codesets_hook(); /* For Windows, link dynamically to gettext & iconv if available */ /* until we have an internal codeset (which is until we open a database) we want output in display codeset */ llgettext_init(PACKAGE, gui_codeset_out); /* read available translation tables */ transl_load_all_tts(); /* set up translations (for first time, will do it again after loading config table, and then again after loading database */ transl_load_xlats(); /* check if any directories not specified, and try environment variables, and default to "." */ for (i=0; i<ARRSIZE(dirvars); ++i) { STRING str = getenv(dirvars[i]); if (!str) str = "."; setoptstr_fallback(dirvars[i], str); } /* also check environment variable for editor */ { STRING str = getenv("LLEDITOR"); if (!str) str = environ_determine_editor(PROGRAM_LIFELINES); setoptstr_fallback("LLEDITOR", str); } /* editor falls back to platform-specific default */ e = getlloptstr("LLEDITOR", NULL); /* configure tempfile & edit command */ editfile = environ_determine_tempfile(); if (!editfile) { *pmsg = strsave("Error creating temp file"); return FALSE; } editfile = strsave(editfile ); editstr = (STRING) stdalloc(strlen(e) + strlen(editfile) + 2); sprintf(editstr, "%s %s", e, editfile); set_usersort(custom_sort); suppress_reload = FALSE; update_useropts(0); /* Finnish always uses custom character sets */ if (opt_finnish ) { opt_mychar = TRUE; mych_set_table(ISO_Latin1); } return TRUE; }
/*================================================== * post_codesets_hook -- code to run just after initializing codesets * For Windows, link dynamically to gettext & iconv if available *================================================*/ static void post_codesets_hook (void) { init_win32_gettext_shim(); init_win32_iconv_shim(getlloptstr("iconv.path","")); }
/*================================== * main -- Main routine of LifeLines *================================*/ int main (int argc, char **argv) { extern char *optarg; extern int optind; char * msg; int c; BOOLEAN ok=FALSE; STRING dbrequested=NULL; /* database (path) requested */ STRING dbused=NULL; /* database (path) found */ BOOLEAN forceopen=FALSE, lockchange=FALSE; char lockarg = 0; /* option passed for database lock */ INT alteration=0; LIST exprogs=NULL; TABLE exargs=NULL; STRING progout=NULL; BOOLEAN graphical=TRUE; STRING configfile=0; STRING crashlog=0; int i=0; /* initialize all the low-level library code */ init_stdlib(); #if HAVE_SETLOCALE /* initialize locales */ setlocale(LC_ALL, ""); #endif /* HAVE_SETLOCALE */ /* capture user's default codeset */ ext_codeset = strsave(ll_langinfo()); /* TODO: We can use this info for default conversions */ #if ENABLE_NLS /* setup gettext translation */ ll_bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); #endif save_original_locales(); load_usage(); /* handle conventional arguments --version and --help */ /* needed for help2man to synthesize manual pages */ for (i=1; i<argc; ++i) { if (!strcmp(argv[i], "--version") || !strcmp(argv[i], "-v")) { print_version("llexec"); return 0; } if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "-h") || !strcmp(argv[i], "-?")) { print_usage(); return 0; } } /* Parse Command-Line Arguments */ opterr = 0; /* turn off getopt's error message */ while ((c = getopt(argc, argv, "adkrwil:fntc:Fu:x:o:zC:I:vh?")) != -1) { switch (c) { case 'c': /* adjust cache sizes */ while(optarg && *optarg) { if(isasciiletter((uchar)*optarg) && isupper((uchar)*optarg)) *optarg = tolower((uchar)*optarg); if(*optarg == 'i') { INT icsz_indi=0; sscanf(optarg+1, "%ld,%ld", &csz_indi, &icsz_indi); } else if(*optarg == 'f') { INT icsz_fam=0; sscanf(optarg+1, "%ld,%ld", &csz_fam, &icsz_fam); } else if(*optarg == 's') { INT icsz_sour=0; sscanf(optarg+1, "%ld,%ld", &csz_sour, &icsz_sour); } else if(*optarg == 'e') { INT icsz_even=0; sscanf(optarg+1, "%ld,%ld", &csz_even, &icsz_even); } else if((*optarg == 'o') || (*optarg == 'x')) { INT icsz_othr=0; sscanf(optarg+1, "%ld,%ld", &csz_othr, &icsz_othr); } optarg++; while(*optarg && isdigit((uchar)*optarg)) optarg++; if(*optarg == ',') optarg++; while(*optarg && isdigit((uchar)*optarg)) optarg++; } break; #ifdef FINNISH # ifdef FINNISHOPTION case 'F': /* Finnish sorting order [toggle] */ opt_finnish = !opt_finnish; /* TO DO - need to mark Finnish databases, as name records are not interoperable, because of different soundex encoding 2001/02/17, Perry Rapp */ break; # endif #endif case 'a': /* debug allocation */ alloclog = TRUE; break; case 'd': /* debug = no signal catchers */ debugmode = TRUE; break; case 'k': /* don't show key values */ keyflag = FALSE; break; case 'r': /* request for read only access */ readonly = TRUE; break; case 'w': /* request for write access */ writeable = TRUE; break; case 'i': /* immutable access */ immutable = TRUE; readonly = TRUE; break; case 'l': /* locking switch */ lockchange = TRUE; lockarg = *optarg; break; case 'f': /* force database open in all cases */ forceopen = TRUE; break; case 'n': /* use non-traditional family rules */ traditional = FALSE; break; case 't': /* show lots of trace statements for debugging */ prog_trace = TRUE; break; case 'x': /* execute program */ if (!exprogs) { exprogs = create_list2(LISTDOFREE); } push_list(exprogs, strdup(optarg ? optarg : "")); break; case 'I': /* program arguments */ { STRING optname=0, optval=0; parse_arg(optarg, &optname, &optval); if (optname && optval) { if (!exargs) { exargs = create_table_str(); } insert_table_str(exargs, optname, optval); } strfree(&optname); strfree(&optval); } break; case 'o': /* output directory */ progout = optarg; break; case 'z': /* nongraphical box */ graphical = FALSE; break; case 'C': /* specify config file */ configfile = optarg; break; case 'v': /* show version */ showversion = TRUE; goto usage; break; case 'h': /* show usage */ case '?': /* show usage */ showversion = TRUE; showusage = TRUE; goto usage; break; } } prompt_for_db: /* catch any fault, so we can close database */ if (debugmode) stdstring_hardfail(); else set_signals(); platform_init(); set_displaykeys(keyflag); /* initialize options & misc. stuff */ llgettext_set_default_localedir(LOCALEDIR); if (!init_lifelines_global(configfile, &msg, &main_db_notify)) { llwprintf("%s", msg); goto finish; } /* setup crashlog in case init_screen fails (eg, bad menu shortcuts) */ crashlog = getlloptstr("CrashLog_llexec", NULL); if (!crashlog) { crashlog = "Crashlog_llexec.log"; } crash_setcrashlog(crashlog); init_interpreter(); /* give interpreter its turn at initialization */ /* Validate Command-Line Arguments */ if ((readonly || immutable) && writeable) { llwprintf(_(qSnorwandro)); goto finish; } if (forceopen && lockchange) { llwprintf(_(qSnofandl)); goto finish; } if (lockchange && lockarg != 'y' && lockarg != 'n') { llwprintf(_(qSbdlkar)); goto finish; } if (forceopen) alteration = 3; else if (lockchange) { if (lockarg == 'y') alteration = 2; else alteration = 1; } c = argc - optind; if (c > 1) { showusage = TRUE; goto usage; } /* Open database, prompting user if necessary */ if (1) { STRING errmsg=0; if (!alldone && c>0) { dbrequested = strsave(argv[optind]); } else { strupdate(&dbrequested, ""); } if (!select_database(dbrequested, alteration, &errmsg)) { if (errmsg) { llwprintf(errmsg); } alldone = 0; goto finish; } } /* Start Program */ if (!init_lifelines_postdb()) { llwprintf(_(qSbaddb)); goto finish; } /* does not use show module */ /* does not use browse module */ if (exargs) { set_cmd_options(exargs); release_table(exargs); exargs = 0; } if (exprogs) { BOOLEAN picklist = FALSE; BOOLEAN timing = FALSE; interp_main(exprogs, progout, picklist, timing); destroy_list(exprogs); } else { /* TODO: prompt for report filename */ } /* does not use show module */ /* does not use browse module */ ok=TRUE; finish: /* we free this not because we care so much about these tiny amounts of memory, but to ensure we have the memory management right */ /* strfree frees memory & nulls pointer */ if (dbused) strfree(&dbused); strfree(&dbrequested); strfree(&readpath_file); shutdown_interpreter(); close_lifelines(); shutdown_ui(!ok); if (alldone == 2) goto prompt_for_db; /* changing databases */ termlocale(); strfree(&ext_codeset); usage: /* Display Version and/or Command-Line Usage Help */ if (showversion) { print_version("llexec"); } if (showusage) puts(usage_summary); /* Exit */ return !ok; }