1*c7ef0cfcSnicm /* $OpenBSD: db_iterator.c,v 1.2 2023/10/17 09:52:09 nicm Exp $ */
281d8c4e1Snicm
381d8c4e1Snicm /****************************************************************************
4*c7ef0cfcSnicm * Copyright 2018-2022,2023 Thomas E. Dickey *
5*c7ef0cfcSnicm * Copyright 2006-2016,2017 Free Software Foundation, Inc. *
681d8c4e1Snicm * *
781d8c4e1Snicm * Permission is hereby granted, free of charge, to any person obtaining a *
881d8c4e1Snicm * copy of this software and associated documentation files (the *
981d8c4e1Snicm * "Software"), to deal in the Software without restriction, including *
1081d8c4e1Snicm * without limitation the rights to use, copy, modify, merge, publish, *
1181d8c4e1Snicm * distribute, distribute with modifications, sublicense, and/or sell *
1281d8c4e1Snicm * copies of the Software, and to permit persons to whom the Software is *
1381d8c4e1Snicm * furnished to do so, subject to the following conditions: *
1481d8c4e1Snicm * *
1581d8c4e1Snicm * The above copyright notice and this permission notice shall be included *
1681d8c4e1Snicm * in all copies or substantial portions of the Software. *
1781d8c4e1Snicm * *
1881d8c4e1Snicm * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
1981d8c4e1Snicm * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
2081d8c4e1Snicm * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
2181d8c4e1Snicm * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
2281d8c4e1Snicm * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
2381d8c4e1Snicm * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
2481d8c4e1Snicm * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
2581d8c4e1Snicm * *
2681d8c4e1Snicm * Except as contained in this notice, the name(s) of the above copyright *
2781d8c4e1Snicm * holders shall not be used in advertising or otherwise to promote the *
2881d8c4e1Snicm * sale, use or other dealings in this Software without prior written *
2981d8c4e1Snicm * authorization. *
3081d8c4e1Snicm ****************************************************************************/
3181d8c4e1Snicm
3281d8c4e1Snicm /****************************************************************************
3381d8c4e1Snicm * Author: Thomas E. Dickey *
3481d8c4e1Snicm ****************************************************************************/
3581d8c4e1Snicm
3681d8c4e1Snicm /*
3781d8c4e1Snicm * Iterators for terminal databases.
3881d8c4e1Snicm */
3981d8c4e1Snicm
4081d8c4e1Snicm #include <curses.priv.h>
4181d8c4e1Snicm
42*c7ef0cfcSnicm #include <time.h>
4381d8c4e1Snicm #include <tic.h>
4481d8c4e1Snicm
45*c7ef0cfcSnicm #if USE_HASHED_DB
46*c7ef0cfcSnicm #include <hashed_db.h>
47*c7ef0cfcSnicm #endif
48*c7ef0cfcSnicm
49*c7ef0cfcSnicm MODULE_ID("$Id: db_iterator.c,v 1.2 2023/10/17 09:52:09 nicm Exp $")
5081d8c4e1Snicm
5181d8c4e1Snicm #define HaveTicDirectory _nc_globals.have_tic_directory
5281d8c4e1Snicm #define KeepTicDirectory _nc_globals.keep_tic_directory
5381d8c4e1Snicm #define TicDirectory _nc_globals.tic_directory
54*c7ef0cfcSnicm #define my_blob _nc_globals.dbd_blob
55*c7ef0cfcSnicm #define my_list _nc_globals.dbd_list
56*c7ef0cfcSnicm #define my_size _nc_globals.dbd_size
57*c7ef0cfcSnicm #define my_time _nc_globals.dbd_time
58*c7ef0cfcSnicm #define my_vars _nc_globals.dbd_vars
59*c7ef0cfcSnicm
60*c7ef0cfcSnicm static void
add_to_blob(const char * text,size_t limit)61*c7ef0cfcSnicm add_to_blob(const char *text, size_t limit)
62*c7ef0cfcSnicm {
63*c7ef0cfcSnicm (void) limit;
64*c7ef0cfcSnicm
65*c7ef0cfcSnicm if (*text != '\0') {
66*c7ef0cfcSnicm char *last = my_blob + strlen(my_blob);
67*c7ef0cfcSnicm if (last != my_blob)
68*c7ef0cfcSnicm *last++ = NCURSES_PATHSEP;
69*c7ef0cfcSnicm _nc_STRCPY(last, text, limit);
70*c7ef0cfcSnicm }
71*c7ef0cfcSnicm }
72*c7ef0cfcSnicm
73*c7ef0cfcSnicm static bool
check_existence(const char * name,struct stat * sb)74*c7ef0cfcSnicm check_existence(const char *name, struct stat *sb)
75*c7ef0cfcSnicm {
76*c7ef0cfcSnicm bool result = FALSE;
77*c7ef0cfcSnicm
78*c7ef0cfcSnicm if (quick_prefix(name)) {
79*c7ef0cfcSnicm result = TRUE;
80*c7ef0cfcSnicm } else if (stat(name, sb) == 0
81*c7ef0cfcSnicm && (S_ISDIR(sb->st_mode)
82*c7ef0cfcSnicm || (S_ISREG(sb->st_mode) && sb->st_size))) {
83*c7ef0cfcSnicm result = TRUE;
84*c7ef0cfcSnicm }
85*c7ef0cfcSnicm #if USE_HASHED_DB
86*c7ef0cfcSnicm else if (strlen(name) < PATH_MAX - sizeof(DBM_SUFFIX)) {
87*c7ef0cfcSnicm char temp[PATH_MAX];
88*c7ef0cfcSnicm _nc_SPRINTF(temp, _nc_SLIMIT(sizeof(temp)) "%s%s", name, DBM_SUFFIX);
89*c7ef0cfcSnicm if (stat(temp, sb) == 0 && S_ISREG(sb->st_mode) && sb->st_size) {
90*c7ef0cfcSnicm result = TRUE;
91*c7ef0cfcSnicm }
92*c7ef0cfcSnicm }
93*c7ef0cfcSnicm #endif
94*c7ef0cfcSnicm return result;
95*c7ef0cfcSnicm }
96*c7ef0cfcSnicm
97*c7ef0cfcSnicm /*
98*c7ef0cfcSnicm * Trim newlines (and backslashes preceding those) and tab characters to
99*c7ef0cfcSnicm * help simplify scripting of the quick-dump feature. Leave spaces and
100*c7ef0cfcSnicm * other backslashes alone.
101*c7ef0cfcSnicm */
102*c7ef0cfcSnicm static void
trim_formatting(char * source)103*c7ef0cfcSnicm trim_formatting(char *source)
104*c7ef0cfcSnicm {
105*c7ef0cfcSnicm char *target = source;
106*c7ef0cfcSnicm char ch;
107*c7ef0cfcSnicm
108*c7ef0cfcSnicm while ((ch = *source++) != '\0') {
109*c7ef0cfcSnicm if (ch == '\\' && *source == '\n')
110*c7ef0cfcSnicm continue;
111*c7ef0cfcSnicm if (ch == '\n' || ch == '\t')
112*c7ef0cfcSnicm continue;
113*c7ef0cfcSnicm *target++ = ch;
114*c7ef0cfcSnicm }
115*c7ef0cfcSnicm *target = '\0';
116*c7ef0cfcSnicm }
117*c7ef0cfcSnicm
118*c7ef0cfcSnicm /*
119*c7ef0cfcSnicm * Store the latest value of an environment variable in my_vars[] so we can
120*c7ef0cfcSnicm * detect if one changes, invalidating the cached search-list.
121*c7ef0cfcSnicm */
122*c7ef0cfcSnicm static bool
update_getenv(const char * name,DBDIRS which)123*c7ef0cfcSnicm update_getenv(const char *name, DBDIRS which)
124*c7ef0cfcSnicm {
125*c7ef0cfcSnicm bool result = FALSE;
126*c7ef0cfcSnicm
127*c7ef0cfcSnicm if (which < dbdLAST) {
128*c7ef0cfcSnicm char *value;
129*c7ef0cfcSnicm char *cached_value = my_vars[which].value;
130*c7ef0cfcSnicm bool same_value;
131*c7ef0cfcSnicm
132*c7ef0cfcSnicm if ((value = getenv(name)) != 0) {
133*c7ef0cfcSnicm value = strdup(value);
134*c7ef0cfcSnicm }
135*c7ef0cfcSnicm same_value = ((value == 0 && cached_value == 0) ||
136*c7ef0cfcSnicm (value != 0 &&
137*c7ef0cfcSnicm cached_value != 0 &&
138*c7ef0cfcSnicm strcmp(value, cached_value) == 0));
139*c7ef0cfcSnicm
140*c7ef0cfcSnicm /* Set variable name to enable checks in cache_expired(). */
141*c7ef0cfcSnicm my_vars[which].name = name;
142*c7ef0cfcSnicm
143*c7ef0cfcSnicm if (!same_value) {
144*c7ef0cfcSnicm FreeIfNeeded(my_vars[which].value);
145*c7ef0cfcSnicm my_vars[which].value = value;
146*c7ef0cfcSnicm result = TRUE;
147*c7ef0cfcSnicm } else {
148*c7ef0cfcSnicm free(value);
149*c7ef0cfcSnicm }
150*c7ef0cfcSnicm }
151*c7ef0cfcSnicm return result;
152*c7ef0cfcSnicm }
153*c7ef0cfcSnicm
154*c7ef0cfcSnicm #if NCURSES_USE_DATABASE || NCURSES_USE_TERMCAP
155*c7ef0cfcSnicm static char *
cache_getenv(const char * name,DBDIRS which)156*c7ef0cfcSnicm cache_getenv(const char *name, DBDIRS which)
157*c7ef0cfcSnicm {
158*c7ef0cfcSnicm char *result = 0;
159*c7ef0cfcSnicm
160*c7ef0cfcSnicm (void) update_getenv(name, which);
161*c7ef0cfcSnicm if (which < dbdLAST) {
162*c7ef0cfcSnicm result = my_vars[which].value;
163*c7ef0cfcSnicm }
164*c7ef0cfcSnicm return result;
165*c7ef0cfcSnicm }
166*c7ef0cfcSnicm #endif
167*c7ef0cfcSnicm
168*c7ef0cfcSnicm /*
169*c7ef0cfcSnicm * The cache expires if at least a second has passed since the initial lookup,
170*c7ef0cfcSnicm * or if one of the environment variables changed.
171*c7ef0cfcSnicm *
172*c7ef0cfcSnicm * Only a few applications use multiple lookups of terminal entries, seems that
173*c7ef0cfcSnicm * aside from bulk I/O such as tic and toe, that leaves interactive programs
174*c7ef0cfcSnicm * which should not be modifying the terminal databases in a way that would
175*c7ef0cfcSnicm * invalidate the search-list.
176*c7ef0cfcSnicm *
177*c7ef0cfcSnicm * The "1-second" is to allow for user-directed changes outside the program.
178*c7ef0cfcSnicm */
179*c7ef0cfcSnicm static bool
cache_expired(void)180*c7ef0cfcSnicm cache_expired(void)
181*c7ef0cfcSnicm {
182*c7ef0cfcSnicm bool result = FALSE;
183*c7ef0cfcSnicm time_t now = time((time_t *) 0);
184*c7ef0cfcSnicm
185*c7ef0cfcSnicm if (now > my_time) {
186*c7ef0cfcSnicm result = TRUE;
187*c7ef0cfcSnicm } else {
188*c7ef0cfcSnicm DBDIRS n;
189*c7ef0cfcSnicm for (n = (DBDIRS) 0; n < dbdLAST; ++n) {
190*c7ef0cfcSnicm if (my_vars[n].name != 0
191*c7ef0cfcSnicm && update_getenv(my_vars[n].name, n)) {
192*c7ef0cfcSnicm result = TRUE;
193*c7ef0cfcSnicm break;
194*c7ef0cfcSnicm }
195*c7ef0cfcSnicm }
196*c7ef0cfcSnicm }
197*c7ef0cfcSnicm return result;
198*c7ef0cfcSnicm }
199*c7ef0cfcSnicm
200*c7ef0cfcSnicm static void
free_cache(void)201*c7ef0cfcSnicm free_cache(void)
202*c7ef0cfcSnicm {
203*c7ef0cfcSnicm FreeAndNull(my_blob);
204*c7ef0cfcSnicm FreeAndNull(my_list);
205*c7ef0cfcSnicm }
206*c7ef0cfcSnicm
207*c7ef0cfcSnicm static void
update_tic_dir(const char * update)208*c7ef0cfcSnicm update_tic_dir(const char *update)
209*c7ef0cfcSnicm {
210*c7ef0cfcSnicm free((char *) TicDirectory);
211*c7ef0cfcSnicm TicDirectory = update;
212*c7ef0cfcSnicm }
21381d8c4e1Snicm
21481d8c4e1Snicm /*
21581d8c4e1Snicm * Record the "official" location of the terminfo directory, according to
21681d8c4e1Snicm * the place where we're writing to, or the normal default, if not.
21781d8c4e1Snicm */
21881d8c4e1Snicm NCURSES_EXPORT(const char *)
_nc_tic_dir(const char * path)21981d8c4e1Snicm _nc_tic_dir(const char *path)
22081d8c4e1Snicm {
221*c7ef0cfcSnicm T(("_nc_tic_dir %s", NonNull(path)));
22281d8c4e1Snicm if (!KeepTicDirectory) {
223*c7ef0cfcSnicm if (path != NULL) {
224*c7ef0cfcSnicm if (path != TicDirectory)
225*c7ef0cfcSnicm update_tic_dir(strdup(path));
22681d8c4e1Snicm HaveTicDirectory = TRUE;
227*c7ef0cfcSnicm } else if (HaveTicDirectory == 0) {
228*c7ef0cfcSnicm if (use_terminfo_vars()) {
229*c7ef0cfcSnicm const char *envp;
23081d8c4e1Snicm if ((envp = getenv("TERMINFO")) != 0)
23181d8c4e1Snicm return _nc_tic_dir(envp);
23281d8c4e1Snicm }
23381d8c4e1Snicm }
234*c7ef0cfcSnicm }
235*c7ef0cfcSnicm return TicDirectory ? TicDirectory : TERMINFO;
23681d8c4e1Snicm }
23781d8c4e1Snicm
23881d8c4e1Snicm /*
23981d8c4e1Snicm * Special fix to prevent the terminfo directory from being moved after tic
24081d8c4e1Snicm * has chdir'd to it. If we let it be changed, then if $TERMINFO has a
24181d8c4e1Snicm * relative path, we'll lose track of the actual directory.
24281d8c4e1Snicm */
24381d8c4e1Snicm NCURSES_EXPORT(void)
_nc_keep_tic_dir(const char * path)24481d8c4e1Snicm _nc_keep_tic_dir(const char *path)
24581d8c4e1Snicm {
24681d8c4e1Snicm _nc_tic_dir(path);
24781d8c4e1Snicm KeepTicDirectory = TRUE;
24881d8c4e1Snicm }
24981d8c4e1Snicm
25081d8c4e1Snicm /*
25181d8c4e1Snicm * Cleanup.
25281d8c4e1Snicm */
25381d8c4e1Snicm NCURSES_EXPORT(void)
_nc_last_db(void)25481d8c4e1Snicm _nc_last_db(void)
25581d8c4e1Snicm {
256*c7ef0cfcSnicm if (my_blob != 0 && cache_expired()) {
257*c7ef0cfcSnicm free_cache();
25881d8c4e1Snicm }
25981d8c4e1Snicm }
26081d8c4e1Snicm
26181d8c4e1Snicm /*
26281d8c4e1Snicm * This is a simple iterator which allows the caller to step through the
26381d8c4e1Snicm * possible locations for a terminfo directory. ncurses uses this to find
26481d8c4e1Snicm * terminfo files to read.
26581d8c4e1Snicm */
26681d8c4e1Snicm NCURSES_EXPORT(const char *)
_nc_next_db(DBDIRS * state,int * offset)26781d8c4e1Snicm _nc_next_db(DBDIRS * state, int *offset)
26881d8c4e1Snicm {
26981d8c4e1Snicm const char *result;
27081d8c4e1Snicm
271*c7ef0cfcSnicm (void) offset;
272*c7ef0cfcSnicm if ((int) *state < my_size
273*c7ef0cfcSnicm && my_list != 0
274*c7ef0cfcSnicm && my_list[*state] != 0) {
275*c7ef0cfcSnicm result = my_list[*state];
276*c7ef0cfcSnicm (*state)++;
277*c7ef0cfcSnicm } else {
27881d8c4e1Snicm result = 0;
27981d8c4e1Snicm }
28081d8c4e1Snicm if (result != 0) {
281*c7ef0cfcSnicm T(("_nc_next_db %d %s", *state, result));
282*c7ef0cfcSnicm }
28381d8c4e1Snicm return result;
28481d8c4e1Snicm }
28581d8c4e1Snicm
28681d8c4e1Snicm NCURSES_EXPORT(void)
_nc_first_db(DBDIRS * state,int * offset)28781d8c4e1Snicm _nc_first_db(DBDIRS * state, int *offset)
28881d8c4e1Snicm {
289*c7ef0cfcSnicm bool cache_has_expired = FALSE;
29081d8c4e1Snicm *state = dbdTIC;
29181d8c4e1Snicm *offset = 0;
292*c7ef0cfcSnicm
293*c7ef0cfcSnicm T((T_CALLED("_nc_first_db")));
294*c7ef0cfcSnicm
295*c7ef0cfcSnicm /* build a blob containing all of the strings we will use for a lookup
296*c7ef0cfcSnicm * table.
297*c7ef0cfcSnicm */
298*c7ef0cfcSnicm if (my_blob == 0 || (cache_has_expired = cache_expired())) {
299*c7ef0cfcSnicm size_t blobsize = 0;
300*c7ef0cfcSnicm const char *values[dbdLAST];
301*c7ef0cfcSnicm struct stat *my_stat;
302*c7ef0cfcSnicm int j;
303*c7ef0cfcSnicm
304*c7ef0cfcSnicm if (cache_has_expired)
305*c7ef0cfcSnicm free_cache();
306*c7ef0cfcSnicm
307*c7ef0cfcSnicm for (j = 0; j < dbdLAST; ++j)
308*c7ef0cfcSnicm values[j] = 0;
309*c7ef0cfcSnicm
310*c7ef0cfcSnicm /*
311*c7ef0cfcSnicm * This is the first item in the list, and is used only when tic is
312*c7ef0cfcSnicm * writing to the database, as a performance improvement.
313*c7ef0cfcSnicm */
314*c7ef0cfcSnicm values[dbdTIC] = TicDirectory;
315*c7ef0cfcSnicm
316*c7ef0cfcSnicm #if NCURSES_USE_DATABASE
317*c7ef0cfcSnicm #ifdef TERMINFO_DIRS
318*c7ef0cfcSnicm values[dbdCfgList] = TERMINFO_DIRS;
319*c7ef0cfcSnicm #endif
320*c7ef0cfcSnicm #ifdef TERMINFO
321*c7ef0cfcSnicm values[dbdCfgOnce] = TERMINFO;
322*c7ef0cfcSnicm #endif
323*c7ef0cfcSnicm #endif
324*c7ef0cfcSnicm
325*c7ef0cfcSnicm #if NCURSES_USE_TERMCAP
326*c7ef0cfcSnicm values[dbdCfgList2] = TERMPATH;
327*c7ef0cfcSnicm #endif
328*c7ef0cfcSnicm
329*c7ef0cfcSnicm if (use_terminfo_vars()) {
330*c7ef0cfcSnicm #if NCURSES_USE_DATABASE
331*c7ef0cfcSnicm values[dbdEnvOnce] = cache_getenv("TERMINFO", dbdEnvOnce);
332*c7ef0cfcSnicm values[dbdHome] = _nc_home_terminfo();
333*c7ef0cfcSnicm (void) cache_getenv("HOME", dbdHome);
334*c7ef0cfcSnicm values[dbdEnvList] = cache_getenv("TERMINFO_DIRS", dbdEnvList);
335*c7ef0cfcSnicm
336*c7ef0cfcSnicm #endif
337*c7ef0cfcSnicm #if NCURSES_USE_TERMCAP
338*c7ef0cfcSnicm values[dbdEnvOnce2] = cache_getenv("TERMCAP", dbdEnvOnce2);
339*c7ef0cfcSnicm /* only use $TERMCAP if it is an absolute path */
340*c7ef0cfcSnicm if (values[dbdEnvOnce2] != 0
341*c7ef0cfcSnicm && *values[dbdEnvOnce2] != '/') {
342*c7ef0cfcSnicm values[dbdEnvOnce2] = 0;
34381d8c4e1Snicm }
344*c7ef0cfcSnicm values[dbdEnvList2] = cache_getenv("TERMPATH", dbdEnvList2);
345*c7ef0cfcSnicm #endif /* NCURSES_USE_TERMCAP */
346*c7ef0cfcSnicm }
347*c7ef0cfcSnicm
348*c7ef0cfcSnicm for (j = 0; j < dbdLAST; ++j) {
349*c7ef0cfcSnicm if (values[j] == 0)
350*c7ef0cfcSnicm values[j] = "";
351*c7ef0cfcSnicm blobsize += 2 + strlen(values[j]);
352*c7ef0cfcSnicm }
353*c7ef0cfcSnicm
354*c7ef0cfcSnicm my_blob = malloc(blobsize);
355*c7ef0cfcSnicm if (my_blob != 0) {
356*c7ef0cfcSnicm *my_blob = '\0';
357*c7ef0cfcSnicm for (j = 0; j < dbdLAST; ++j) {
358*c7ef0cfcSnicm add_to_blob(values[j], blobsize);
359*c7ef0cfcSnicm }
360*c7ef0cfcSnicm
361*c7ef0cfcSnicm /* Now, build an array which will be pointers to the distinct
362*c7ef0cfcSnicm * strings in the blob.
363*c7ef0cfcSnicm */
364*c7ef0cfcSnicm blobsize = 2;
365*c7ef0cfcSnicm for (j = 0; my_blob[j] != '\0'; ++j) {
366*c7ef0cfcSnicm if (my_blob[j] == NCURSES_PATHSEP)
367*c7ef0cfcSnicm ++blobsize;
368*c7ef0cfcSnicm }
369*c7ef0cfcSnicm my_list = typeCalloc(char *, blobsize);
370*c7ef0cfcSnicm my_stat = typeCalloc(struct stat, blobsize);
371*c7ef0cfcSnicm if (my_list != 0 && my_stat != 0) {
372*c7ef0cfcSnicm int k = 0;
373*c7ef0cfcSnicm my_list[k++] = my_blob;
374*c7ef0cfcSnicm for (j = 0; my_blob[j] != '\0'; ++j) {
375*c7ef0cfcSnicm if (my_blob[j] == NCURSES_PATHSEP
376*c7ef0cfcSnicm && ((&my_blob[j] - my_list[k - 1]) != 3
377*c7ef0cfcSnicm || !quick_prefix(my_list[k - 1]))) {
378*c7ef0cfcSnicm my_blob[j] = '\0';
379*c7ef0cfcSnicm my_list[k++] = &my_blob[j + 1];
380*c7ef0cfcSnicm }
381*c7ef0cfcSnicm }
382*c7ef0cfcSnicm
383*c7ef0cfcSnicm /*
384*c7ef0cfcSnicm * Eliminate duplicates from the list.
385*c7ef0cfcSnicm */
386*c7ef0cfcSnicm for (j = 0; my_list[j] != 0; ++j) {
387*c7ef0cfcSnicm #ifdef TERMINFO
388*c7ef0cfcSnicm if (*my_list[j] == '\0') {
389*c7ef0cfcSnicm char *my_copy = strdup(TERMINFO);
390*c7ef0cfcSnicm if (my_copy != 0)
391*c7ef0cfcSnicm my_list[j] = my_copy;
392*c7ef0cfcSnicm }
393*c7ef0cfcSnicm #endif
394*c7ef0cfcSnicm trim_formatting(my_list[j]);
395*c7ef0cfcSnicm for (k = 0; k < j; ++k) {
396*c7ef0cfcSnicm if (!strcmp(my_list[j], my_list[k])) {
397*c7ef0cfcSnicm T(("duplicate %s", my_list[j]));
398*c7ef0cfcSnicm k = j - 1;
399*c7ef0cfcSnicm while ((my_list[j] = my_list[j + 1]) != 0) {
400*c7ef0cfcSnicm ++j;
401*c7ef0cfcSnicm }
402*c7ef0cfcSnicm j = k;
403*c7ef0cfcSnicm break;
404*c7ef0cfcSnicm }
405*c7ef0cfcSnicm }
406*c7ef0cfcSnicm }
407*c7ef0cfcSnicm
408*c7ef0cfcSnicm /*
409*c7ef0cfcSnicm * Eliminate non-existent databases, and those that happen to
410*c7ef0cfcSnicm * be symlinked to another location.
411*c7ef0cfcSnicm */
412*c7ef0cfcSnicm for (j = 0; my_list[j] != 0; ++j) {
413*c7ef0cfcSnicm bool found = check_existence(my_list[j], &my_stat[j]);
414*c7ef0cfcSnicm #if HAVE_LINK
415*c7ef0cfcSnicm if (found) {
416*c7ef0cfcSnicm for (k = 0; k < j; ++k) {
417*c7ef0cfcSnicm if (my_stat[j].st_dev == my_stat[k].st_dev
418*c7ef0cfcSnicm && my_stat[j].st_ino == my_stat[k].st_ino) {
419*c7ef0cfcSnicm found = FALSE;
420*c7ef0cfcSnicm break;
421*c7ef0cfcSnicm }
422*c7ef0cfcSnicm }
423*c7ef0cfcSnicm }
424*c7ef0cfcSnicm #endif
425*c7ef0cfcSnicm if (!found) {
426*c7ef0cfcSnicm T(("not found %s", my_list[j]));
427*c7ef0cfcSnicm k = j;
428*c7ef0cfcSnicm while ((my_list[k] = my_list[k + 1]) != 0) {
429*c7ef0cfcSnicm ++k;
430*c7ef0cfcSnicm }
431*c7ef0cfcSnicm --j;
432*c7ef0cfcSnicm }
433*c7ef0cfcSnicm }
434*c7ef0cfcSnicm my_size = j;
435*c7ef0cfcSnicm my_time = time((time_t *) 0);
436*c7ef0cfcSnicm } else {
437*c7ef0cfcSnicm FreeAndNull(my_blob);
438*c7ef0cfcSnicm }
439*c7ef0cfcSnicm free(my_stat);
440*c7ef0cfcSnicm }
441*c7ef0cfcSnicm }
442*c7ef0cfcSnicm returnVoid;
443*c7ef0cfcSnicm }
444*c7ef0cfcSnicm
445*c7ef0cfcSnicm #if NO_LEAKS
446*c7ef0cfcSnicm void
_nc_db_iterator_leaks(void)447*c7ef0cfcSnicm _nc_db_iterator_leaks(void)
448*c7ef0cfcSnicm {
449*c7ef0cfcSnicm DBDIRS which;
450*c7ef0cfcSnicm
451*c7ef0cfcSnicm if (my_blob != 0)
452*c7ef0cfcSnicm FreeAndNull(my_blob);
453*c7ef0cfcSnicm if (my_list != 0)
454*c7ef0cfcSnicm FreeAndNull(my_list);
455*c7ef0cfcSnicm for (which = 0; (int) which < dbdLAST; ++which) {
456*c7ef0cfcSnicm my_vars[which].name = 0;
457*c7ef0cfcSnicm FreeIfNeeded(my_vars[which].value);
458*c7ef0cfcSnicm my_vars[which].value = 0;
459*c7ef0cfcSnicm }
460*c7ef0cfcSnicm update_tic_dir(NULL);
461*c7ef0cfcSnicm }
462*c7ef0cfcSnicm #endif
463