1/****************************************************************************
2 * Copyright (c) 2006,2007 Free Software Foundation, Inc.                   *
3 *                                                                          *
4 * Permission is hereby granted, free of charge, to any person obtaining a  *
5 * copy of this software and associated documentation files (the            *
6 * "Software"), to deal in the Software without restriction, including      *
7 * without limitation the rights to use, copy, modify, merge, publish,      *
8 * distribute, distribute with modifications, sublicense, and/or sell       *
9 * copies of the Software, and to permit persons to whom the Software is    *
10 * furnished to do so, subject to the following conditions:                 *
11 *                                                                          *
12 * The above copyright notice and this permission notice shall be included  *
13 * in all copies or substantial portions of the Software.                   *
14 *                                                                          *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
22 *                                                                          *
23 * Except as contained in this notice, the name(s) of the above copyright   *
24 * holders shall not be used in advertising or otherwise to promote the     *
25 * sale, use or other dealings in this Software without prior written       *
26 * authorization.                                                           *
27 ****************************************************************************/
28
29/****************************************************************************
30 *  Author: Thomas E. Dickey                                                *
31 ****************************************************************************/
32
33/*
34 * Iterators for terminal databases.
35 */
36
37#include <curses.priv.h>
38
39#include <tic.h>
40
41MODULE_ID("$Id: db_iterator.c,v 1.6 2007/04/22 00:00:26 tom Exp $")
42
43#define HaveTicDirectory _nc_globals.have_tic_directory
44#define KeepTicDirectory _nc_globals.keep_tic_directory
45#define TicDirectory     _nc_globals.tic_directory
46
47/*
48 * Record the "official" location of the terminfo directory, according to
49 * the place where we're writing to, or the normal default, if not.
50 */
51NCURSES_EXPORT(const char *)
52_nc_tic_dir(const char *path)
53{
54    if (!KeepTicDirectory) {
55	if (path != 0) {
56	    TicDirectory = path;
57	    HaveTicDirectory = TRUE;
58	} else if (!HaveTicDirectory && use_terminfo_vars()) {
59	    char *envp;
60	    if ((envp = getenv("TERMINFO")) != 0)
61		return _nc_tic_dir(envp);
62	}
63    }
64    return TicDirectory;
65}
66
67/*
68 * Special fix to prevent the terminfo directory from being moved after tic
69 * has chdir'd to it.  If we let it be changed, then if $TERMINFO has a
70 * relative path, we'll lose track of the actual directory.
71 */
72NCURSES_EXPORT(void)
73_nc_keep_tic_dir(const char *path)
74{
75    _nc_tic_dir(path);
76    KeepTicDirectory = TRUE;
77}
78
79/*
80 * Process the list of :-separated directories, looking for the terminal type.
81 * We don't use strtok because it does not show us empty tokens.
82 */
83#define ThisDbList	_nc_globals.dbi_list
84#define ThisDbSize	_nc_globals.dbi_size
85
86/*
87 * Cleanup.
88 */
89NCURSES_EXPORT(void)
90_nc_last_db(void)
91{
92    if (ThisDbList != 0) {
93	FreeAndNull(ThisDbList);
94    }
95    ThisDbSize = 0;
96}
97
98/* The TERMINFO_DIRS value, if defined by the configure script, begins with a
99 * ":", which will be interpreted as TERMINFO.
100 */
101static const char *
102next_list_item(const char *source, int *offset)
103{
104    if (source != 0) {
105	FreeIfNeeded(ThisDbList);
106	ThisDbList = strdup(source);
107	ThisDbSize = strlen(source);
108    }
109
110    if (ThisDbList != 0 && ThisDbSize && *offset < ThisDbSize) {
111	static char system_db[] = TERMINFO;
112	char *result = ThisDbList + *offset;
113	char *marker = strchr(result, NCURSES_PATHSEP);
114
115	/*
116	 * Put a null on the marker if a separator was found.  Set the offset
117	 * to the next position after the marker so we can call this function
118	 * again, using the data at the offset.
119	 */
120	if (marker == 0) {
121	    *offset += strlen(result) + 1;
122	    marker = result + *offset;
123	} else {
124	    *marker++ = 0;
125	    *offset = marker - ThisDbList;
126	}
127	if (*result == 0 && result != (ThisDbList + ThisDbSize))
128	    result = system_db;
129	return result;
130    }
131    return 0;
132}
133
134#define NEXT_DBD(var, offset) next_list_item((*offset == 0) ? var : 0, offset)
135
136/*
137 * This is a simple iterator which allows the caller to step through the
138 * possible locations for a terminfo directory.  ncurses uses this to find
139 * terminfo files to read.
140 */
141NCURSES_EXPORT(const char *)
142_nc_next_db(DBDIRS * state, int *offset)
143{
144    const char *result;
145    char *envp;
146
147    while (*state < dbdLAST) {
148	DBDIRS next = (DBDIRS) ((int) (*state) + 1);
149
150	result = 0;
151
152	switch (*state) {
153	case dbdTIC:
154	    if (HaveTicDirectory)
155		result = _nc_tic_dir(0);
156	    break;
157#if USE_DATABASE
158	case dbdEnvOnce:
159	    if (use_terminfo_vars()) {
160		if ((envp = getenv("TERMINFO")) != 0)
161		    result = _nc_tic_dir(envp);
162	    }
163	    break;
164	case dbdHome:
165	    if (use_terminfo_vars()) {
166		result = _nc_home_terminfo();
167	    }
168	    break;
169	case dbdEnvList:
170	    if (use_terminfo_vars()) {
171		if ((result = NEXT_DBD(getenv("TERMINFO_DIRS"), offset)) != 0)
172		    next = *state;
173	    }
174	    break;
175	case dbdCfgList:
176#ifdef TERMINFO_DIRS
177	    if ((result = NEXT_DBD(TERMINFO_DIRS, offset)) != 0)
178		next = *state;
179#endif
180	    break;
181	case dbdCfgOnce:
182#ifndef TERMINFO_DIRS
183	    result = TERMINFO;
184#endif
185	    break;
186#endif /* USE_DATABASE */
187#if USE_TERMCAP
188	case dbdEnvOnce2:
189	    if (use_terminfo_vars()) {
190		if ((envp = getenv("TERMCAP")) != 0)
191		    result = _nc_tic_dir(envp);
192	    }
193	    break;
194	case dbdEnvList2:
195	    if (use_terminfo_vars()) {
196		if ((result = NEXT_DBD(getenv("TERMPATH"), offset)) != 0)
197		    next = *state;
198	    }
199	    break;
200	case dbdCfgList2:
201	    if ((result = NEXT_DBD(TERMPATH, offset)) != 0)
202		next = *state;
203	    break;
204#endif /* USE_TERMCAP */
205	case dbdLAST:
206	    break;
207	}
208	if (*state != next) {
209	    *state = next;
210	    *offset = 0;
211	    _nc_last_db();
212	}
213	if (result != 0) {
214	    return result;
215	}
216    }
217    return 0;
218}
219
220NCURSES_EXPORT(void)
221_nc_first_db(DBDIRS * state, int *offset)
222{
223    *state = dbdTIC;
224    *offset = 0;
225}
226