/*=============================================+ * 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; }
/*======================================================= * annotate_node -- Alter a node by * expanding refns (eg, "@S25@" to "<1850.Census>") * annotating pointers (eg, "@I1@" to "@I1@ {{ John/SMITH }}") * Used during editing *=====================================================*/ static void annotate_node (NODE node, BOOLEAN expand_refns, BOOLEAN annotate_pointers, RFMT rfmt) { STRING key=0; RECORD rec=0; key = value_to_xref(nval(node)); if (!key) return; rec = key_possible_to_record(key, *key); if (!rec) return; if (expand_refns) { NODE refn = REFN(nztop(rec)); char buffer[60]; /* if there is a REFN, and it fits in our buffer, and it doesn't have any (confusing) > in it */ if (refn && nval(refn) && !strchr(nval(refn), '>') && strlen(nval(refn))<=sizeof(buffer)-3) { /* then replace, eg, @S25@, with, eg, <1850.Census> */ buffer[0]=0; strcpy(buffer, "<"); strcat(buffer, nval(refn)); strcat(buffer, ">"); stdfree(nval(node)); nval(node) = strsave(buffer); } } if (annotate_pointers) { STRING str = generic_to_list_string(nztop(rec), key, 60, ", ", rfmt, FALSE); ZSTR zstr = zs_news(nval(node)); zs_apps(zstr, " {{"); zs_apps(zstr, str); zs_apps(zstr, " }}"); stdfree(nval(node)); nval(node) = strsave(zs_str(zstr)); zs_free(&zstr); } }
/*=================================================== * format_eratime -- Add AD/BC info to date * pdate: [IN] actual date information * zstr: [I/O] date string consisting of yr, mo, da portion * efmt: [IN] eratime format code * 0 - no AD/BC marker * 1 - trailing B.C. if appropriate * 2 - trailing A.D. or B.C. * 11 - trailing BC if appropriate * 12 - trailng AD or BC * 21 - trailing B.C.E. if appropriate * 22 - trailing C.E. or B.C.E. * 31 - trailing BCE if appropriate * 32 - trailing CE or BCE * Created: 2001/12/28 (Perry Rapp) *=================================================*/ static void format_eratime (ZSTR zstr, INT eratime, INT efmt) { /* TODO: calendar-specific handling */ if (eratime == GDV_BC) { if (efmt > 0) { STRING tag = 0; switch (efmt/10) { case 1: tag = _(qSdatetrl_bcB); break; case 2: tag = _(qSdatetrl_bcC); break; case 3: tag = _(qSdatetrl_bcD); break; } /* this way we handle if one is blank */ if (!tag || !tag[0]) tag = _(qSdatetrl_bcA); zs_apps(zstr, " "); zs_apps(zstr, tag); return; } } else { if (efmt > 1) { STRING tag = 0; switch (efmt/10) { case 1: tag = _(qSdatetrl_adB); break; case 2: tag = _(qSdatetrl_adC); break; case 3: tag = _(qSdatetrl_adD); break; } /* this way we handle if one is blank */ if (!tag || !tag[0]) tag = _(qSdatetrl_adA); zs_apps(zstr, " "); zs_apps(zstr, tag); return; } } /* no trailing tag at all */ }
/*=============================================+ * prog_var_error_zstr -- Report a run time program error * node: [IN] current parse node * stab: [IN] current symbol table (lexical scope) * arg: [IN] if non-null, parse node of troublesome argument * val: [IN] if non-null, PVALUE of troublesome argument * zstr: [IN] message * * Inline debugger is implemented here * See vprog_error * Created: 2002/02/17, Perry Rapp *============================================*/ static void prog_var_error_zstr (PNODE node, SYMTAB stab, PNODE arg, PVALUE val, ZSTR zstr) { STRING choices[5]; INT rtn=0; SYMTAB curstab = stab; /* currently displayed symbol table */ INT nlevels=0; /* number frames on callstack */ INT curlevel=0; /* 0 is lowest */ ASSERT(zstr); if (val) { ZSTR zval = describe_pvalue(val); zs_appf(zstr, " (value: %s)", zs_str(zval)); } else if (arg) { INT max=40 + zs_len(zstr); /* not too much argument description */ /* arg isn't evaluated, but describe will at least give its type */ zs_apps(zstr, " (arg: "); describe_pnode(arg, zstr, max); zs_apps(zstr, ")"); } prog_error(node, zs_str(zstr)); zs_free(&zstr); if (dbg_mode != -99 && dbg_mode != 3) { INT ch = 0; while (!(ch=='d' || ch=='q')) ch = rptui_prompt_stdout(_("Enter d for debugger, q to quit")); if (ch == 'q') dbg_mode = -99; } /* call stack size & location */ nlevels = count_symtab_ancestors(stab) + 1; curlevel = 0; /* report debugger loop */ while (dbg_mode != -99) { ZSTR zstr=zs_new(); INT n=0; /* 0: display local variable(s) */ n = (curstab->tab ? get_table_count(curstab->tab) : 0); zs_setf(zstr, _pl("Display local (%d var)", "Display locals (%d vars)", n), n); zs_appf(zstr, " [%s]", curstab->title); choices[0] = strsave(zs_str(zstr)); /* 1: display global variables */ n = (globtab->tab ? get_table_count(globtab->tab) : 0); zs_setf(zstr, _pl("Display global (%d var)", "Display globals (%d vars)", n), n); choices[1] = strsave(zs_str(zstr)); /* 2: up call stack */ n = nlevels - curlevel - 1; zs_setf(zstr, _pl("Call stack has %d higher level", "Call stack has %d higher levels", n), n); zs_apps(zstr, ". "); if (n > 0) { zs_apps(zstr, _(" Go up one level")); zs_appf(zstr, "(%s)", curstab->parent->title); } choices[2] = strsave(zs_str(zstr)); /* 3: down call stack */ n = curlevel; zs_setf(zstr, _pl("Call stack has %d lower level", "Call stack has %d lower levels", n), n); zs_apps(zstr, ". "); if (n > 0) { CNSTRING title = get_symtab_ancestor(stab, n-1)->title; zs_apps(zstr, _(" Go down one level")); zs_appf(zstr, "(%s)", title); } choices[3] = strsave(zs_str(zstr)); /* quit */ choices[4] = strsave(_("Quit debugger")); dbgloop: rtn = rptui_choose_from_array(_("Report debugger"), ARRSIZE(choices), choices); if (rtn == 4 || rtn == -1) { dbg_mode = -99; } else if (rtn == 0) { disp_symtab(_("Local variables"), curstab); goto dbgloop; } else if (rtn == 1) { disp_symtab(_("Global variables"), globtab); goto dbgloop; } else if (rtn == 2) { if (curlevel+1 < nlevels) { curstab = curstab->parent; ++curlevel; ASSERT(curstab); } } else if (rtn == 3) { if (curlevel > 0) { curstab = get_symtab_ancestor(stab, curlevel-1); --curlevel; ASSERT(curstab); } } zs_free(&zstr); free_array_strings(ARRSIZE(choices), choices); } }
/*=================================================== * format_ymd -- Assembles date according to dateformat * zstr: [I/O] resultant formatted zstring * syr: [IN] year string * smo: [IN] month string * sda: [IN] day string * sfmt: [IN] format code * 0 - da mo yr * 1 - mo da, yr * 2 - mo/da/yr * 3 - da/mo/yr * 4 - mo-da-yr * 5 - da-mo-yr * 6 - modayr * 7 - damoyr * 8 - yr mo da * 9 - yr/mo/da * 10- yr-mo-da * 11- yrmoda * 12- yr (year only, old short form) * 13- dd/mo yr * 14- as in GEDCOM * This routine applies the custom date pic if present (date_pic) *=================================================*/ static void format_ymd (ZSTR zstr, STRING syr, STRING smo, STRING sda, INT sfmt) { zs_clear(zstr); if (date_pic) { ZSTR zs2 = zprintpic3(date_pic, syr, smo, sda); zs_move(zstr, &zs2); return; } switch (sfmt) { case 0: /* da mo yr */ if (sda) { zs_apps(zstr, sda); zs_appc(zstr, ' '); } if (smo) { zs_apps(zstr, smo); zs_appc(zstr, ' '); } if (syr) { zs_apps(zstr, syr); } break; case 1: /* mo da, yr */ if (smo) { zs_apps(zstr, smo); zs_appc(zstr, ' '); } if (sda) { zs_apps(zstr, sda); zs_apps(zstr, ", "); } if (syr) zs_apps(zstr, syr); break; case 2: /* mo/da/yr */ if (smo) zs_apps(zstr, smo); zs_appc(zstr, '/'); if (sda) zs_apps(zstr, sda); zs_appc(zstr, '/'); if (syr) zs_apps(zstr, syr); break; case 3: /* da/mo/yr */ if (sda) zs_apps(zstr, sda); zs_appc(zstr, '/'); if (smo) zs_apps(zstr, smo); zs_appc(zstr, '/'); if (syr) zs_apps(zstr, syr); break; case 4: /* mo-da-yr */ if (smo) zs_apps(zstr, smo); zs_appc(zstr, '-'); if (sda) zs_apps(zstr, sda); zs_appc(zstr, '-'); if (syr) zs_apps(zstr, syr); break; case 5: /* da-mo-yr */ if (sda) zs_apps(zstr, sda); zs_appc(zstr, '-'); if (smo) zs_apps(zstr, smo); zs_appc(zstr, '-'); if (syr) zs_apps(zstr, syr); break; case 6: /* modayr */ if (smo) zs_apps(zstr, smo); if (sda) zs_apps(zstr, sda); if (syr) zs_apps(zstr, syr); break; case 7: /* damoyr */ if (sda) zs_apps(zstr, sda); if (smo) zs_apps(zstr, smo); if (syr) zs_apps(zstr, syr); break; case 8: /* yr mo da */ if (syr) zs_apps(zstr, syr); if (smo) { zs_appc(zstr, ' '); zs_apps(zstr, smo); } if (sda) { zs_appc(zstr, ' '); zs_apps(zstr, sda); } break; case 9: /* yr/mo/da */ if (syr) zs_apps(zstr, syr); zs_appc(zstr, '/'); if (smo) zs_apps(zstr, smo); zs_appc(zstr, '/'); if (sda) zs_apps(zstr, sda); break; case 10: /* yr-mo-da */ if (syr) zs_apps(zstr, syr); zs_appc(zstr, '-'); if (smo) zs_apps(zstr, smo); zs_appc(zstr, '-'); if (sda) zs_apps(zstr, sda); break; case 11: /* yrmoda */ if (syr) zs_apps(zstr, syr); if (smo) zs_apps(zstr, smo); if (sda) zs_apps(zstr, sda); break; /* 12 (year only) was handled directly in do_format_date */ case 13: /* da/mo yr */ if (sda) zs_apps(zstr, sda); zs_appc(zstr, '/'); if (smo) zs_apps(zstr, smo); zs_appc(zstr, ' '); if (syr) zs_apps(zstr, syr); break; /* 14 (as GEDCOM) was handled directly in do_format_date */ } }