/*========================================== * free_namerefn -- frees a new NAMEREFN_REC * Created: 2001/01/01, Perry Rapp *========================================*/ static void free_namerefn (NAMEREFN_REC * rec) { stdfree(rec->namerefn); stdfree(rec->key); stdfree(rec); }
/*======================================================= * resolve_node -- Traverse routine for resolve_refn_links (q.v.) * node: Current node in traversal * returns FALSE if bad refn pointer *=====================================================*/ static BOOLEAN resolve_node (NODE node, BOOLEAN annotate_pointers) { STRING val = nval(node); STRING refn=0; if (!val) return TRUE; refn = symbolic_link(val); if (refn) { INT letr = record_letter(ntag(node)); NODE refr = refn_to_record(refn, letr); if (refr) { stdfree(nval(node)); nval(node) = strsave(nxref(refr)); } else { return FALSE; } } if (annotate_pointers) { INT i=0,len=0; if (is_annotated_xref(nval(node), &len)) { char newval[20]; ASSERT(len < (INT)sizeof(newval)); for (i=0; i<len; ++i) { newval[i] = nval(node)[i]; } newval[i] = 0; stdfree(nval(node)); nval(node) = strsave(newval); } } return TRUE; }
/*==================================================== * parserefnrec -- Store refn rec in file buffers *==================================================*/ static void parserefnrec (RKEY rkey, CNSTRING p) { INT i; RRkey = rkey; /* Store refn record in data structures */ memcpy (&RRcount, p, sizeof(INT)); p += sizeof(INT); if (RRcount >= RRmax - 1) { if (RRmax != 0) { stdfree(RRkeys); stdfree(RRoffs); stdfree((STRING)RRrefns); } RRmax = RRcount + 10; RRkeys = (RKEY *) stdalloc((RRmax)*sizeof(RKEY)); RRoffs = (INT *) stdalloc((RRmax)*sizeof(INT)); RRrefns = (CNSTRING *) stdalloc((RRmax)*sizeof(STRING)); } for (i = 0; i < RRcount; i++) { memcpy(&RRkeys[i], p, sizeof(RKEY)); p += sizeof(RKEY); } for (i = 0; i < RRcount; i++) { memcpy(&RRoffs[i], p, sizeof(INT)); p += sizeof(INT); } for (i = 0; i < RRcount; i++) RRrefns[i] = p + RRoffs[i]; }
/*========================== * closebtree -- Close BTREE *========================*/ BOOLEAN closebtree (BTREE btree) { FILE *fk=NULL; KEYFILE1 kfile1; BOOLEAN result=FALSE; if (btree && ((fk = bkfp(btree)) != NULL) && !bimmut(btree)) { kfile1 = btree->b_kfile; if (kfile1.k_ostat <= 0) { /* writer-locked, should be -1 because we don't cater for multiple writers */ kfile1.k_ostat = 0; } else { /* read-only, get current shared status */ rewind(fk); if (fread(&kfile1, sizeof(kfile1), 1, fk) != 1) { /* *lldberr = BTERR_KFILE */ /* closebtree does not report specific errors */ goto exit_closebtree; } if (kfile1.k_ostat <= 0) { /* probably someone has forcibly opened it for write, making this -1, and may also have since closed it, leaving it at 0 */ result=TRUE; goto exit_closebtree; } kfile1.k_ostat--; } rewind(fk); if (fwrite(&kfile1, sizeof(kfile1), 1, fk) != 1) { /* *lldberr = BTERR_KFILE */ /* closebtree does not report specific errors */ goto exit_closebtree; } if (fclose(fk) != 0) { fk = NULL; /* *lldberr = BTERR_KFILE; */ goto exit_closebtree; } fk = NULL; result=TRUE; } else { result=TRUE; } exit_closebtree: if (fk) fclose(fk); if (btree) { freecache(btree); if(bmaster(btree)) { stdfree(bmaster(btree)); } stdfree(btree); } return result; }
/*========================================================= * destroy_array -- Delete array (releasing all elements) *=======================================================*/ void destroy_array (ARRAY array) { int i; for (i=0; i<ASize(array); ++i) { OBJECT obj = (OBJECT)AData(array)[i]; delete_obj(obj); } stdfree(AData(array)); AData(array) = 0; stdfree(array); }
/*=============================================+ * free_dbgsymtab_arrays -- Clear dbgsymtab after use * frees its arrays and dynamic strings * values are assumed to be borrowed, not to free * sdata: [I/O] dbgsymtab to be cleared *============================================*/ static void free_dbgsymtab_arrays (struct dbgsymtab_s * sdata) { free_array_strings(sdata->count, sdata->displays); stdfree(sdata->displays); sdata->displays = 0; /* do not free sdata.values pointers, they're borrowed */ stdfree(sdata->values); sdata->values = 0; sdata->count = 0; memset(sdata, 0, sizeof(*sdata)); }
/*======================================== * free_displaynode -- return displaynode to free-list * (see alloc_displaynode comments) *======================================*/ static void free_displaynode (DISPNODE tn) { tn->firstchild = NULL; tn->nextsib = NULL; tn->keynum = -1; if (tn->str) { stdfree(tn->str); tn->str = NULL; } stdfree(tn); }
/*================================================== * 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; }
/*==================================================== * get_refns -- Find all records who match refn or key *==================================================*/ void get_refns (STRING refn, INT *pnum, STRING **pkeys, INT letr) { INT i, n; *pnum = 0; if (!refn) return; /* Clean up allocated memory from last call */ if (RMcount) { for (i = 0; i < RMcount; i++) stdfree(RMkeys[i]); } RMcount = 0; /* Load static refn buffers; return if no match */ if (!getrefnrec(refn)) return; /* Compare user's refn with all refns in record; the refn record data structures are modified */ n = 0; for (i = 0; i < RRcount; i++) { if (eqstr(refn, RRrefns[i])) { if (letr == 0 || *(rkey2str(RRkeys[i])) == letr) { if (i != n) { RRrefns[n] = RRrefns[i]; RRkeys[n] = RRkeys[i]; } n++; } } } *pnum = RRcount = n; if (RRcount > RMmax) { if (RMmax) stdfree(RMkeys); RMkeys = (STRING *) stdalloc(RRcount*sizeof(STRING)); RMmax = RRcount; } for (i = 0; i < RRcount; i++) RMkeys[i] = strsave(rkey2str(RRkeys[i])); *pkeys = RMkeys; }
/*======================================== * lldb_close -- Close any database contained. * Free LLDATABASE structure. * Safe to call even if not opened *======================================*/ void lldb_close (LLDATABASE *plldb) { LLDATABASE lldb=0; ASSERT(plldb); lldb = *plldb; if (!lldb) return; if (tagtable) destroy_table(tagtable); tagtable = 0; /* TODO: reverse the rest of init_lifelines_postdb -- Perry, 2002.06.05 */ if (placabbvs) { destroy_table(placabbvs); placabbvs = NULL; } free_caches(); check_node_leaks(); check_record_leaks(); closexref(); ASSERT(BTR == lldb->btree); if (lldb->btree) { closebtree(lldb->btree); lldb->btree = 0; BTR = 0; } dbnotify_close(); transl_free_predefined_xlats(); /* clear any active legacy translation tables */ strfree(&readpath_file); strfree(&readpath); stdfree(lldb); *plldb = 0; }
/*====================================+ * 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; }
/*====================== * remove_hashtab -- Remove element from table * return old value if found *====================*/ HVALUE remove_hashtab (HASHTAB tab, CNSTRING key) { HVALUE val=0; INT hval=0; HASHENT preve=0, thise=0; ASSERT(tab); ASSERT(tab->magic == hashtab_magic); hval = hash(tab, key); thise = tab->entries[hval]; while (thise && nestr(key, thise->ekey)) { ASSERT(thise->magic == hashent_magic); preve = thise; thise = thise->enext; } if (!thise) return 0; if (preve) preve->enext = thise->enext; else tab->entries[hval] = thise->enext; val = thise->val; strfree((STRING *)&thise->ekey); thise->val = 0; stdfree(thise); --tab->count; return val; }
/*=============================== * strfree -- Free & clear a STRING by ref * (STRING may be NULL) *=============================*/ void strfree (STRING * str) { if (*str) { stdfree(*str); *str = NULL; } }
/*=============================== * strcfree -- Free & clear a CNSTRING by ref * (STRING may be NULL) *=============================*/ void strcfree (CNSTRING * str) { if (*str) { stdfree(*str); *str = NULL; } }
/*=================================================== * add_dir_files_to_proplist -- Add all files in dir to list of property tables * Created: 2002/10/19, Perry Rapp *=================================================*/ INT add_dir_files_to_proplist (CNSTRING dir, SELECT_FNC selectfnc, LIST list) { struct dirent **programs; INT n = scandir(dir, &programs, selectfnc, alphasort); INT i; for (i=0; i<n; ++i) { TABLE table = create_table_str(); set_prop_dnum(table, 1, "filename", programs[i]->d_name); set_prop_dnum(table, 2, "dir", dir); stdfree(programs[i]); programs[i] = NULL; enqueue_list(list, table); } if (n>0) stdfree(programs); return i; }
/*=================================== * close_lifelines -- Close LifeLines * Close entire lifelines engine - not just * database (see close_lldb below). *=================================*/ void close_lifelines (void) { lldb_close(&def_lldb); /* make sure database closed */ if (editfile) { unlink(editfile); stdfree(editfile); editfile=NULL; } if (editstr) { stdfree(editstr); editstr=NULL; } term_lloptions(); term_date(); term_codesets(); strfree(&int_codeset); xlat_shutdown(); }
/*=================================================== * free_proparray -- free array of property tables * NB: must have NULL marker entry at end * Created: 2002/10/19, Perry Rapp *=================================================*/ void free_proparray (TABLE ** props) { INT i; for (i=0; (*props)[i]; ++i) { TABLE tab = (*props)[i]; destroy_table(tab); } stdfree((*props)); *props = NULL; }
/*================================ * end_hashtab -- Release/destroy hash table iterator *==============================*/ void end_hashtab (HASHTAB_ITER * ptabit) { HASHTAB_ITER tabit = *ptabit; ASSERT(tabit); ASSERT(tabit->magic == hashtab_iter_magic); memset(tabit, 0, sizeof(*tabit)); stdfree(tabit); *ptabit = 0; }
/*================================================= * free_table_iter -- Delete & free table iterator object *===============================================*/ static void free_table_iter (TABLE_ITER tabit) { if (!tabit) return; ASSERT(!tabit->refcnt); if (!tabit->rbit) { end_hashtab(&tabit->hashtab_iter); } memset(tabit, 0, sizeof(*tabit)); stdfree(tabit); }
/*======================================================= * 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); } }
/*============================= * set_cmplx_pic -- Set a custom complex date picture * NULL or empty string will clear any existing custom pic * returns FALSE if invalid argument. * Created: 2001/12/30 (Perry Rapp) *===========================*/ BOOLEAN set_cmplx_pic (INT ecmplx, STRING pic) { if (ecmplx<0 || ecmplx>=ECMPLX_END) return FALSE; if (cmplx_custom[ecmplx]) { stdfree(cmplx_custom[ecmplx]); cmplx_custom[ecmplx] = 0; } if (pic && pic[0]) cmplx_custom[ecmplx] = strsave(pic); return TRUE; }
/*============================================= * remove_refn -- Remove entry from refn record *===========================================*/ BOOLEAN remove_refn (CNSTRING refn, /* record's refn */ CNSTRING key) /* record's GEDCOM key */ { STRING rec, p; INT i, len, off; BOOLEAN found; RKEY rkey; rkey = str2rkey(key); (void) getrefnrec(refn); found = FALSE; for (i = 0; i < RRcount; i++) { if (!ll_strncmp(rkey.r_rkey, RRkeys[i].r_rkey, 8) && eqstr(refn, RRrefns[i])) { found = TRUE; break; } } if (!found) return FALSE; RRcount--; for ( ; i < RRcount; i++) { RRkeys[i] = RRkeys[i+1]; RRrefns[i] = RRrefns[i+1]; } p = rec = (STRING) stdalloc(RRsize); len = 0; memcpy(p, &RRcount, sizeof(INT)); p += sizeof(INT); len += sizeof(INT); for (i = 0; i < RRcount; i++) { memcpy(p, &RRkeys[i], sizeof(RKEY)); p += sizeof(RKEY); len += sizeof(RKEY); } off = 0; for (i = 0; i < RRcount; i++) { memcpy(p, &off, sizeof(INT)); p += sizeof(INT); len += sizeof(INT); off += strlen(RRrefns[i]) + 1; } for (i = 0; i < RRcount; i++) { memcpy(p, RRrefns[i], strlen(RRrefns[i]) + 1); p += strlen(RRrefns[i]) + 1; len += strlen(RRrefns[i]) + 1; } bt_addrecord(BTR, RRkey, rec, len); stdfree(rec); return TRUE; }
/*========================================== * freexref -- Free memory & clear xrefs array * Called when database is closed *========================================*/ static void freexref (DELETESET set) { ASSERT(set); if (set->recs) { stdfree(set->recs); set->recs = 0; set->max = 0; set->n = 0; } else { ASSERT(set->max == 0); ASSERT(set->n == 0); } }
/*================================================= * clear_generic -- free any memory held *===============================================*/ void clear_generic (GENERIC *gen) { switch(gen->selector) { case GENERIC_NULL: break; case GENERIC_INT: break; case GENERIC_FLOAT: stdfree(gen->data.fval); gen->data.fval = 0; case GENERIC_STRING: stdfree(gen->data.sval); gen->data.sval = 0; break; case GENERIC_STRING_SHARED: break; case GENERIC_VPTR: break; case GENERIC_OBJECT: delete_obj(gen->data.oval); break; /* don't need to free any others */ } gen->selector = GENERIC_NULL; gen->data.oval = 0; }
/*================================================= * append_to_text_list - add onto fixed width string list * newline: flag to not append to last element of list * we build each line in current, and add it to list as done * ptr points to the undone part of text * curptr points to the end (insertion point) of current * NB: We also build list from last to first, so client can use * FORLIST traversal (which is backwards) * TO DO: Break at whitespace *=================================================*/ static void append_to_text_list (LIST list, STRING text, INT width, BOOLEAN newline) { STRING ptr = text; STRING temp, current, curptr; INT len, curlen; if (!text || !text[0]) return; /* pull off last line into temp, to append to */ if (newline) { temp = NULL; } else { temp = pop_list(list); if (temp && (INT)strlen(temp) >= width) { enqueue_list(list, temp); temp = NULL; } } current=stdalloc((width+1)*sizeof(char)); current[0] = 0; curptr = current; curlen = width; if (temp) { llstrcatn(&curptr, temp, &curlen); } while (1) { len = strlen(ptr); if (!len) { /* done */ if (current[0]) { enqueue_list(list, strsave(current)); } stdfree(current); return; } if (len > curlen) len = curlen; temp = curptr; llstrcatn(&curptr, ptr, &curlen); ptr += (curptr - temp); if (!curlen) { /* filled up an item */ enqueue_list(list, strsave(current)); current[0] = 0; curptr = current; curlen = width; } } }
/*=========================================== * fopenpath -- Open file using path variable * pfname: [OUT] stdalloc'd copy of full path found *=========================================*/ FILE * fopenpath (STRING name, STRING mode, STRING path, STRING ext, INT utf8 , STRING *pfname) { FILE * fp; STRING str; if(pfname) *pfname = NULL; if (!(str = filepath(name, mode, path, ext, utf8))) return NULL; if(pfname) { *pfname = str; } fp = fopen(str, mode); if (!pfname) stdfree(str); return fp; }
/*================================================================= * 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; }
/*=================================================== * who_is_he_she -- Find who person is from key value *=================================================*/ void who_is_he_she (void) { STRING str, rawrec; NODE indi; INT len; char nkey[100]; char key[20]; if (!ask_for_string(_("Please enter person's internal key value."), _("enter key:"), key, sizeof(key)) || !key[0]) return; nkey[0] = 'I'; if (*key == 'I') strcpy(nkey, key); else strcpy(&nkey[1], key); if (!(rawrec = retrieve_raw_record(nkey, &len))) { msg_error(_("No one in database has key value %s."), key); return; } if (!(indi = string_to_node(rawrec))) { msg_error(_("No one in database has key value %s."), key); stdfree(rawrec); return; } if (!(str = indi_to_name(indi, 60)) || *str == 0) { msg_error(_("No one in database has key value %s."), key); stdfree(rawrec); return; } msg_info("%s - %s", key, str); /* LEAK -- where is stdfree(rawrec) -- Perry 2001/11/18 */ }
/*================================ * destroy_hashtab -- Destroy hash table *==============================*/ void destroy_hashtab (HASHTAB tab, DELFUNC func) { INT i=0; if (!tab) return; ASSERT(tab->magic == hashtab_magic); for (i=0; i<tab->maxhash; ++i) { HASHENT entry = tab->entries[i]; HASHENT next=0; while (entry) { ASSERT(entry->magic == hashent_magic); next = entry->enext; if (func) (*func)(entry->val); entry->val = 0; strfree((STRING *)&entry->ekey); stdfree(entry); entry = next; } } stdfree(tab->entries); tab->entries = 0; stdfree(tab); }
/*========================================== * growxrefs -- Grow memory for xrefs array. * generic for all types *========================================*/ static void growxrefs (DELETESET set) { INT i, m = set->max, *newp; if (set->max == 0) set->max = 64; while (set->max <= set->n) set->max = set->max << 1; newp = (INT *) stdalloc((set->max)*sizeof(INT)); if (m) { for (i = 0; i < set->n; i++) newp[i] = set->recs[i]; stdfree(set->recs); } set->recs = newp; }