ncurses 5.6
[ncurses.git] / ncurses / tinfo / db_iterator.c
1 /****************************************************************************
2  * Copyright (c) 2006 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                     2006                       *
31  ****************************************************************************/
32
33 /*
34  * Iterators for terminal databases.
35  */
36
37 #include <curses.priv.h>
38
39 #include <tic.h>
40
41 MODULE_ID("$Id: db_iterator.c,v 1.5 2006/12/16 19:06:42 tom Exp $")
42
43 static bool have_tic_directory = FALSE;
44 static bool keep_tic_directory = FALSE;
45
46 /*
47  * Record the "official" location of the terminfo directory, according to
48  * the place where we're writing to, or the normal default, if not.
49  */
50 NCURSES_EXPORT(const char *)
51 _nc_tic_dir(const char *path)
52 {
53     static const char *result = TERMINFO;
54
55     if (!keep_tic_directory) {
56         if (path != 0) {
57             result = path;
58             have_tic_directory = TRUE;
59         } else if (!have_tic_directory && use_terminfo_vars()) {
60             char *envp;
61             if ((envp = getenv("TERMINFO")) != 0)
62                 return _nc_tic_dir(envp);
63         }
64     }
65     return result;
66 }
67
68 /*
69  * Special fix to prevent the terminfo directory from being moved after tic
70  * has chdir'd to it.  If we let it be changed, then if $TERMINFO has a
71  * relative path, we'll lose track of the actual directory.
72  */
73 NCURSES_EXPORT(void)
74 _nc_keep_tic_dir(const char *path)
75 {
76     _nc_tic_dir(path);
77     keep_tic_directory = TRUE;
78 }
79
80 /*
81  * Process the list of :-separated directories, looking for the terminal type.
82  * We don't use strtok because it does not show us empty tokens.
83  */
84
85 static char *this_db_list = 0;
86 static int size_db_list;
87
88 /*
89  * Cleanup.
90  */
91 NCURSES_EXPORT(void)
92 _nc_last_db(void)
93 {
94     if (this_db_list != 0) {
95         FreeAndNull(this_db_list);
96     }
97     size_db_list = 0;
98 }
99
100 /* The TERMINFO_DIRS value, if defined by the configure script, begins with a
101  * ":", which will be interpreted as TERMINFO.
102  */
103 static const char *
104 next_list_item(const char *source, int *offset)
105 {
106     if (source != 0) {
107         FreeIfNeeded(this_db_list);
108         this_db_list = strdup(source);
109         size_db_list = strlen(source);
110     }
111
112     if (this_db_list != 0 && size_db_list && *offset < size_db_list) {
113         static char system_db[] = TERMINFO;
114         char *result = this_db_list + *offset;
115         char *marker = strchr(result, NCURSES_PATHSEP);
116
117         /*
118          * Put a null on the marker if a separator was found.  Set the offset
119          * to the next position after the marker so we can call this function
120          * again, using the data at the offset.
121          */
122         if (marker == 0) {
123             *offset += strlen(result) + 1;
124             marker = result + *offset;
125         } else {
126             *marker++ = 0;
127             *offset = marker - this_db_list;
128         }
129         if (*result == 0 && result != (this_db_list + size_db_list))
130             result = system_db;
131         return result;
132     }
133     return 0;
134 }
135
136 #define NEXT_DBD(var, offset) next_list_item((*offset == 0) ? var : 0, offset)
137
138 /*
139  * This is a simple iterator which allows the caller to step through the
140  * possible locations for a terminfo directory.  ncurses uses this to find
141  * terminfo files to read.
142  */
143 NCURSES_EXPORT(const char *)
144 _nc_next_db(DBDIRS * state, int *offset)
145 {
146     const char *result;
147     char *envp;
148
149     while (*state < dbdLAST) {
150         DBDIRS next = (DBDIRS) ((int) (*state) + 1);
151
152         result = 0;
153
154         switch (*state) {
155         case dbdTIC:
156             if (have_tic_directory)
157                 result = _nc_tic_dir(0);
158             break;
159 #if USE_DATABASE
160         case dbdEnvOnce:
161             if (use_terminfo_vars()) {
162                 if ((envp = getenv("TERMINFO")) != 0)
163                     result = _nc_tic_dir(envp);
164             }
165             break;
166         case dbdHome:
167             if (use_terminfo_vars()) {
168                 result = _nc_home_terminfo();
169             }
170             break;
171         case dbdEnvList:
172             if (use_terminfo_vars()) {
173                 if ((result = NEXT_DBD(getenv("TERMINFO_DIRS"), offset)) != 0)
174                     next = *state;
175             }
176             break;
177         case dbdCfgList:
178 #ifdef TERMINFO_DIRS
179             if ((result = NEXT_DBD(TERMINFO_DIRS, offset)) != 0)
180                 next = *state;
181 #endif
182             break;
183         case dbdCfgOnce:
184 #ifndef TERMINFO_DIRS
185             result = TERMINFO;
186 #endif
187             break;
188 #endif /* USE_DATABASE */
189 #if USE_TERMCAP
190         case dbdEnvOnce2:
191             if (use_terminfo_vars()) {
192                 if ((envp = getenv("TERMCAP")) != 0)
193                     result = _nc_tic_dir(envp);
194             }
195             break;
196         case dbdEnvList2:
197             if (use_terminfo_vars()) {
198                 if ((result = NEXT_DBD(getenv("TERMPATH"), offset)) != 0)
199                     next = *state;
200             }
201             break;
202         case dbdCfgList2:
203             if ((result = NEXT_DBD(TERMPATH, offset)) != 0)
204                 next = *state;
205             break;
206 #endif /* USE_TERMCAP */
207         case dbdLAST:
208             break;
209         }
210         if (*state != next) {
211             *state = next;
212             *offset = 0;
213             _nc_last_db();
214         }
215         if (result != 0) {
216             return result;
217         }
218     }
219     return 0;
220 }
221
222 NCURSES_EXPORT(void)
223 _nc_first_db(DBDIRS * state, int *offset)
224 {
225     *state = dbdTIC;
226     *offset = 0;
227 }