/*=================================================== * show_open_error -- Display database opening error *=================================================*/ static void show_open_error (INT dberr) { char buffer[256]; describe_dberror(dberr, buffer, ARRSIZE(buffer)); llwprintf(buffer); llwprintf("\n"); sleep(5); }
/*=============================================+ * 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; }
/*======================================== * string_to_node -- Read tree from string * (modifies string -- adds 0s between lines) *======================================*/ NODE string_to_node (STRING str) { INT lev; INT lev0; STRING xref; STRING tag; STRING val; INT curlev; NODE root=NULL, node, curnode; STRING msg; flineno = 0; if (!string_to_line(&str, &lev, &xref, &tag, &val, &msg)) goto string_to_node_fail; lev0 = curlev = lev; root = curnode = create_node(xref, tag, val, NULL); while (string_to_line(&str, &lev, &xref, &tag, &val, &msg)) { if (lev == curlev) { node = create_node(xref, tag, val, nparent(curnode)); nsibling(curnode) = node; curnode = node; } else if (lev == curlev + 1) { node = create_node(xref, tag, val, curnode); nchild(curnode) = node; curnode = node; curlev = lev; } else if (lev < curlev) { if (lev < lev0) { llwprintf("Error: line %d: illegal level", flineno); goto string_to_node_fail; } while (lev < curlev) { curnode = nparent(curnode); curlev--; } node = create_node(xref, tag, val, nparent(curnode)); nsibling(curnode) = node; curnode = node; } else { llwprintf("Error: line %d: illegal level", flineno); goto string_to_node_fail; } } if (!msg) { nodechk(root, "string_to_node"); return root; } string_to_node_fail: free_nodes(root); return NULL; }
/*=================================================== * yylex -- High level lexer function (for debugging) * lvalp: [I/O] pointer to bison's data (primarily return value) * yaccparm: [IN] pointer to data passed by interp.c to bison's yyparse *=================================================*/ int yylex (YYSTYPE * lvalp, void * pactx) { INT lex = lowyylex(pactx, lvalp); #ifdef DEBUG if (isascii(lex)) llwprintf("lex<%c> ", lex); else llwprintf("lex<%d> ", lex); #endif return lex; }
/*================================================+ * evaluate_cond -- Evaluate conditional expression *===============================================*/ BOOLEAN evaluate_cond (PNODE node, SYMTAB stab, BOOLEAN *eflg) { PVALUE val; BOOLEAN rc; PNODE var = node, expr = inext(node); if (!expr) { expr = var; var = NULL; } if (var && !iistype(var, IIDENT)) { *eflg = TRUE; prog_error(node, "1st arg in conditional must be variable"); return FALSE; } val = evaluate(expr, stab, eflg); if (*eflg || !val) { *eflg = TRUE; prog_error(node, "error in conditional expression"); return FALSE; } #ifdef DEBUG llwprintf("interp_if: cond = "); show_pvalue(val); wprintf("\n"); #endif if (var) assign_iden(stab, iident(node), copy_pvalue(val)); coerce_pvalue(PBOOL, val, eflg); rc = pvalue_to_bool(val); delete_pvalue(val); return rc; }
/*================================ * 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; }
/*================================================== * 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; }
/*================================================================= * advedit_expand_traverse -- Traverse routine called when expanding record *===============================================================*/ static BOOLEAN advedit_expand_traverse (NODE node, VPTR param) { LIST subs = (LIST)param; STRING key = value_to_xref(nval(node)); if (!key) return TRUE; key = strsave(key); #ifdef DEBUG llwprintf("expand_traverse: %s %s\n", ntag(node), nval(node)); #endif /* DEBUG */ FORLIST(subs, el) #ifdef DEBUG llwprintf("expand_traverse: %s %s\n", key, rmvat(nval((NODE) el))); #endif /* DEBUG */ if (eqstr(key, rmvat(nval((NODE) el)))) { STOPLIST stdfree(key); return TRUE; } ENDLIST enqueue_list(subs, node); stdfree(key); return TRUE; }
/*=============================== * __fatal -- Fatal error routine * handles null or empty details input *=============================*/ void __fatal (STRING file, int line, CNSTRING details) { /* avoid reentrancy */ static BOOLEAN failing=FALSE; if (failing) return; failing=TRUE; /* send to error log if one is specified */ errlog_out(_("Fatal Error"), details, file, line); /* send to screen */ llwprintf("%s\n", _("FATAL ERROR")); if (details && details[0]) { llwprintf(" %s\n", details); } llwprintf(_(" in file <%s> at line %d\n"), file, line); /* offer crash dump before closing database */ ll_optional_abort(_("ASSERT failure")); close_lifelines(); shutdown_ui(TRUE); /* pause */ failing=FALSE; exit(1); }
/*================================================================= * advanced_person_edit -- *===============================================================*/ void advanced_person_edit (NODE root0) { FILE *fp; NODE expd; #ifdef DEBUG llwprintf("advanced_person_edit: %s %s %s\n", nxref(root0), ntag(root0),nval(root0)); #endif expd = expand_tree(root0); ASSERT(fp = fopen(editfile, LLWRITETEXT)); write_nodes(0, fp, NULL, expd, TRUE, TRUE, TRUE); fclose(fp); do_edit(); }
/*============================================ * node_to_file -- Convert tree to GEDCOM file *==========================================*/ BOOLEAN node_to_file (INT levl, /* top level */ NODE node, /* root node */ STRING fname, /* file */ BOOLEAN indent, /* indent? */ TRANTABLE tt) /* char map */ { FILE *fp; if (!(fp = fopen(fname, LLWRITETEXT))) { llwprintf("Could not open file: `%s'\n", fname); return FALSE; } write_nodes(levl, fp, tt, node, indent, TRUE, TRUE); fclose(fp); return TRUE; }
/*=============================== * vcrashlog -- Send crash info to crash log and screen * internal implementation *=============================*/ static void vcrashlog (int newline, const char * fmt, va_list args) { char buffer[2048]; vsnprintf(buffer, sizeof(buffer), fmt, args); buffer[sizeof(buffer)-1] = 0; if (newline) { /* ensure room at end to append \n */ buffer[sizeof(buffer)-2] = 0; strcat(buffer, "\n"); } /* send to error log if one is specified */ errlog_out(NULL, buffer, NULL, -1); /* send to screen */ llwprintf(buffer); }
/*=======================================+ * valueof_iden - Find value of identifier * makes & returns copy *======================================*/ PVALUE valueof_iden (PNODE node, SYMTAB stab, STRING iden, BOOLEAN *eflg) { BOOLEAN there; PVALUE val; #ifdef DEBUG llwprintf("valueof_iden: iden, stab, globtab: %s, %d, %d\n", iden, stab, globtab); #endif *eflg = FALSE; val = symtab_valueofbool(stab, iden, &there); if (there) return copy_pvalue(val); val = symtab_valueofbool(globtab, iden, &there); if (there) return copy_pvalue(val); /* undeclared identifier */ if (explicitvars) { *eflg = TRUE; prog_error(node, "Undeclared identifier: %s", iden); } return create_pvalue_any(); }
static void import_validating (void) { char msg[100]; STRING numstr=0; INT count=0; INT row=0; llwprintf(_("Checking GEDCOM file for errors.\n")); clear_rec_counts(0); numstr = _pl("Error", "Errors", count); row = 6; snprintf(msg, sizeof(msg), "%6ld %s", count, numstr); clear_stdout_hseg(row, 1, 70); wfield(row, 1, msg); numstr = _pl("Warning", "Warnings", count); row = 7; snprintf(msg, sizeof(msg), "%6ld %s", count, numstr); clear_stdout_hseg(row, 1, 70); wfield(row, 1, msg); }
/*================================================================= * expand_tree -- Create copy of node tree with additional link info *===============================================================*/ static NODE expand_tree (NODE root0) { NODE copy, node, sub; STRING key; static NODE root; /* root of record being edited */ LIST subs; /* list of contained records */ NODE expd; /* expanded main record - copy - our retval */ root = root0; expd = copy_nodes(root, TRUE, TRUE); subs = create_list(); traverse_nodes(expd, advedit_expand_traverse, subs); /* expand the list of records into the copied record */ FORLIST(subs, el) node = (NODE) el; #ifdef DEBUG llwprintf("in list: %s %s\n", ntag(node), nval(node)); #endif key = rmvat(nval(node)); if ((sub = nztop(key_possible_to_record(key, *key)))) { copy = copy_node_subtree(sub); nxref(node) = nxref(copy); ntag(node) = ntag(copy); nchild(node) = nchild(copy); nparent(node) = nparent(copy); /*MEMORY LEAK; MEMORY LEAK; MEMORY LEAK: node not removed (because its value and possibly xref [probably not] are still being referred to */ } ENDLIST /* Shouldn't we free subs now ? Perry 2001/06/22 */ #ifdef DEBUG show_node(expd); #endif return expd; }
/*================================================+ * evaluate_ufunc -- Evaluate user defined function * node: [in] parsed node of function definition * stab: [in] function's symbol table * eflg: [out] error flag *===============================================*/ PVALUE evaluate_ufunc (PNODE node, SYMTAB stab, BOOLEAN *eflg) { STRING procname = (STRING) iname(node); PNODE func, arg, parm; SYMTAB newstab = NULL; PVALUE val=NULL; INTERPTYPE irc; INT count=0; *eflg = TRUE; /* find func in local or global table */ func = get_proc_node(procname, irptinfo(node)->functab, gfunctab, &count); if (!func) { if (!count) prog_error(node, _("Undefined func: %s"), procname); else prog_error(node, _("Ambiguous call to func: %s"), procname); goto ufunc_leave; } newstab = create_symtab_proc(procname, stab); arg = (PNODE) iargs(node); parm = (PNODE) iargs(func); while (arg && parm) { BOOLEAN eflg=TRUE; PVALUE value = evaluate(arg, stab, &eflg); if (eflg) { if (getlloptint("FullReportCallStack", 0) > 0) prog_error(node, "In user function %s()", procname); return INTERROR; } insert_symtab(newstab, iident(parm), value); arg = inext(arg); parm = inext(parm); } if (arg || parm) { prog_error(node, "``%s'': mismatched args and params\n", procname); goto ufunc_leave; } irc = interpret((PNODE) ibody(func), newstab, &val); switch (irc) { case INTRETURN: case INTOKAY: #ifdef DEBUG llwprintf("Successful ufunc call -- val returned was "); show_pvalue(val); llwprintf("\n"); #endif *eflg = FALSE; goto ufunc_leave; case INTBREAK: case INTCONTINUE: case INTERROR: break; } if (getlloptint("FullReportCallStack", 0) > 0) prog_error(node, "In user function %s()", procname); *eflg = TRUE; delete_pvalue(val); val=NULL; ufunc_leave: if (newstab) { remove_symtab(newstab); newstab = NULL; } return val; }
/*================================== * 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; }
/*====================================+ * trace_endl -- Finish trace line *===================================*/ void trace_endl (void) { llwprintf("\n"); }