1166124Srafan/****************************************************************************
2174993Srafan * Copyright (c) 2006,2007 Free Software Foundation, Inc.                   *
3166124Srafan *                                                                          *
4166124Srafan * Permission is hereby granted, free of charge, to any person obtaining a  *
5166124Srafan * copy of this software and associated documentation files (the            *
6166124Srafan * "Software"), to deal in the Software without restriction, including      *
7166124Srafan * without limitation the rights to use, copy, modify, merge, publish,      *
8166124Srafan * distribute, distribute with modifications, sublicense, and/or sell       *
9166124Srafan * copies of the Software, and to permit persons to whom the Software is    *
10166124Srafan * furnished to do so, subject to the following conditions:                 *
11166124Srafan *                                                                          *
12166124Srafan * The above copyright notice and this permission notice shall be included  *
13166124Srafan * in all copies or substantial portions of the Software.                   *
14166124Srafan *                                                                          *
15166124Srafan * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
16166124Srafan * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
17166124Srafan * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
18166124Srafan * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
19166124Srafan * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
20166124Srafan * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
21166124Srafan * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
22166124Srafan *                                                                          *
23166124Srafan * Except as contained in this notice, the name(s) of the above copyright   *
24166124Srafan * holders shall not be used in advertising or otherwise to promote the     *
25166124Srafan * sale, use or other dealings in this Software without prior written       *
26166124Srafan * authorization.                                                           *
27166124Srafan ****************************************************************************/
28166124Srafan
29166124Srafan/****************************************************************************
30174993Srafan *  Author: Thomas E. Dickey                                                *
31166124Srafan ****************************************************************************/
32166124Srafan
33166124Srafan/*
34166124Srafan * Iterators for terminal databases.
35166124Srafan */
36166124Srafan
37166124Srafan#include <curses.priv.h>
38166124Srafan
39166124Srafan#include <tic.h>
40166124Srafan
41174993SrafanMODULE_ID("$Id: db_iterator.c,v 1.6 2007/04/22 00:00:26 tom Exp $")
42166124Srafan
43174993Srafan#define HaveTicDirectory _nc_globals.have_tic_directory
44174993Srafan#define KeepTicDirectory _nc_globals.keep_tic_directory
45174993Srafan#define TicDirectory     _nc_globals.tic_directory
46166124Srafan
47166124Srafan/*
48166124Srafan * Record the "official" location of the terminfo directory, according to
49166124Srafan * the place where we're writing to, or the normal default, if not.
50166124Srafan */
51166124SrafanNCURSES_EXPORT(const char *)
52166124Srafan_nc_tic_dir(const char *path)
53166124Srafan{
54174993Srafan    if (!KeepTicDirectory) {
55166124Srafan	if (path != 0) {
56174993Srafan	    TicDirectory = path;
57174993Srafan	    HaveTicDirectory = TRUE;
58174993Srafan	} else if (!HaveTicDirectory && use_terminfo_vars()) {
59166124Srafan	    char *envp;
60166124Srafan	    if ((envp = getenv("TERMINFO")) != 0)
61166124Srafan		return _nc_tic_dir(envp);
62166124Srafan	}
63166124Srafan    }
64174993Srafan    return TicDirectory;
65166124Srafan}
66166124Srafan
67166124Srafan/*
68166124Srafan * Special fix to prevent the terminfo directory from being moved after tic
69166124Srafan * has chdir'd to it.  If we let it be changed, then if $TERMINFO has a
70166124Srafan * relative path, we'll lose track of the actual directory.
71166124Srafan */
72166124SrafanNCURSES_EXPORT(void)
73166124Srafan_nc_keep_tic_dir(const char *path)
74166124Srafan{
75166124Srafan    _nc_tic_dir(path);
76174993Srafan    KeepTicDirectory = TRUE;
77166124Srafan}
78166124Srafan
79166124Srafan/*
80166124Srafan * Process the list of :-separated directories, looking for the terminal type.
81166124Srafan * We don't use strtok because it does not show us empty tokens.
82166124Srafan */
83174993Srafan#define ThisDbList	_nc_globals.dbi_list
84174993Srafan#define ThisDbSize	_nc_globals.dbi_size
85166124Srafan
86166124Srafan/*
87166124Srafan * Cleanup.
88166124Srafan */
89166124SrafanNCURSES_EXPORT(void)
90166124Srafan_nc_last_db(void)
91166124Srafan{
92174993Srafan    if (ThisDbList != 0) {
93174993Srafan	FreeAndNull(ThisDbList);
94166124Srafan    }
95174993Srafan    ThisDbSize = 0;
96166124Srafan}
97166124Srafan
98166124Srafan/* The TERMINFO_DIRS value, if defined by the configure script, begins with a
99166124Srafan * ":", which will be interpreted as TERMINFO.
100166124Srafan */
101166124Srafanstatic const char *
102166124Srafannext_list_item(const char *source, int *offset)
103166124Srafan{
104166124Srafan    if (source != 0) {
105174993Srafan	FreeIfNeeded(ThisDbList);
106174993Srafan	ThisDbList = strdup(source);
107174993Srafan	ThisDbSize = strlen(source);
108166124Srafan    }
109166124Srafan
110174993Srafan    if (ThisDbList != 0 && ThisDbSize && *offset < ThisDbSize) {
111166124Srafan	static char system_db[] = TERMINFO;
112174993Srafan	char *result = ThisDbList + *offset;
113166124Srafan	char *marker = strchr(result, NCURSES_PATHSEP);
114166124Srafan
115166124Srafan	/*
116166124Srafan	 * Put a null on the marker if a separator was found.  Set the offset
117166124Srafan	 * to the next position after the marker so we can call this function
118166124Srafan	 * again, using the data at the offset.
119166124Srafan	 */
120166124Srafan	if (marker == 0) {
121166124Srafan	    *offset += strlen(result) + 1;
122166124Srafan	    marker = result + *offset;
123166124Srafan	} else {
124166124Srafan	    *marker++ = 0;
125174993Srafan	    *offset = marker - ThisDbList;
126166124Srafan	}
127174993Srafan	if (*result == 0 && result != (ThisDbList + ThisDbSize))
128166124Srafan	    result = system_db;
129166124Srafan	return result;
130166124Srafan    }
131166124Srafan    return 0;
132166124Srafan}
133166124Srafan
134166124Srafan#define NEXT_DBD(var, offset) next_list_item((*offset == 0) ? var : 0, offset)
135166124Srafan
136166124Srafan/*
137166124Srafan * This is a simple iterator which allows the caller to step through the
138166124Srafan * possible locations for a terminfo directory.  ncurses uses this to find
139166124Srafan * terminfo files to read.
140166124Srafan */
141166124SrafanNCURSES_EXPORT(const char *)
142166124Srafan_nc_next_db(DBDIRS * state, int *offset)
143166124Srafan{
144166124Srafan    const char *result;
145166124Srafan    char *envp;
146166124Srafan
147166124Srafan    while (*state < dbdLAST) {
148166124Srafan	DBDIRS next = (DBDIRS) ((int) (*state) + 1);
149166124Srafan
150166124Srafan	result = 0;
151166124Srafan
152166124Srafan	switch (*state) {
153166124Srafan	case dbdTIC:
154174993Srafan	    if (HaveTicDirectory)
155166124Srafan		result = _nc_tic_dir(0);
156166124Srafan	    break;
157166124Srafan#if USE_DATABASE
158166124Srafan	case dbdEnvOnce:
159166124Srafan	    if (use_terminfo_vars()) {
160166124Srafan		if ((envp = getenv("TERMINFO")) != 0)
161166124Srafan		    result = _nc_tic_dir(envp);
162166124Srafan	    }
163166124Srafan	    break;
164166124Srafan	case dbdHome:
165166124Srafan	    if (use_terminfo_vars()) {
166166124Srafan		result = _nc_home_terminfo();
167166124Srafan	    }
168166124Srafan	    break;
169166124Srafan	case dbdEnvList:
170166124Srafan	    if (use_terminfo_vars()) {
171166124Srafan		if ((result = NEXT_DBD(getenv("TERMINFO_DIRS"), offset)) != 0)
172166124Srafan		    next = *state;
173166124Srafan	    }
174166124Srafan	    break;
175166124Srafan	case dbdCfgList:
176166124Srafan#ifdef TERMINFO_DIRS
177166124Srafan	    if ((result = NEXT_DBD(TERMINFO_DIRS, offset)) != 0)
178166124Srafan		next = *state;
179166124Srafan#endif
180166124Srafan	    break;
181166124Srafan	case dbdCfgOnce:
182166124Srafan#ifndef TERMINFO_DIRS
183166124Srafan	    result = TERMINFO;
184166124Srafan#endif
185166124Srafan	    break;
186166124Srafan#endif /* USE_DATABASE */
187166124Srafan#if USE_TERMCAP
188166124Srafan	case dbdEnvOnce2:
189166124Srafan	    if (use_terminfo_vars()) {
190166124Srafan		if ((envp = getenv("TERMCAP")) != 0)
191166124Srafan		    result = _nc_tic_dir(envp);
192166124Srafan	    }
193166124Srafan	    break;
194166124Srafan	case dbdEnvList2:
195166124Srafan	    if (use_terminfo_vars()) {
196166124Srafan		if ((result = NEXT_DBD(getenv("TERMPATH"), offset)) != 0)
197166124Srafan		    next = *state;
198166124Srafan	    }
199166124Srafan	    break;
200166124Srafan	case dbdCfgList2:
201166124Srafan	    if ((result = NEXT_DBD(TERMPATH, offset)) != 0)
202166124Srafan		next = *state;
203166124Srafan	    break;
204166124Srafan#endif /* USE_TERMCAP */
205166124Srafan	case dbdLAST:
206166124Srafan	    break;
207166124Srafan	}
208166124Srafan	if (*state != next) {
209166124Srafan	    *state = next;
210166124Srafan	    *offset = 0;
211166124Srafan	    _nc_last_db();
212166124Srafan	}
213166124Srafan	if (result != 0) {
214166124Srafan	    return result;
215166124Srafan	}
216166124Srafan    }
217166124Srafan    return 0;
218166124Srafan}
219166124Srafan
220166124SrafanNCURSES_EXPORT(void)
221166124Srafan_nc_first_db(DBDIRS * state, int *offset)
222166124Srafan{
223166124Srafan    *state = dbdTIC;
224166124Srafan    *offset = 0;
225166124Srafan}
226