xref: /openbsd/lib/libcurses/tinfo/hashed_db.c (revision c7ef0cfc)
1 /* $OpenBSD: hashed_db.c,v 1.2 2023/10/17 09:52:09 nicm Exp $ */
2 
3 /****************************************************************************
4  * Copyright 2019,2020 Thomas E. Dickey                                     *
5  * Copyright 2006-2011,2013 Free Software Foundation, Inc.                  *
6  *                                                                          *
7  * Permission is hereby granted, free of charge, to any person obtaining a  *
8  * copy of this software and associated documentation files (the            *
9  * "Software"), to deal in the Software without restriction, including      *
10  * without limitation the rights to use, copy, modify, merge, publish,      *
11  * distribute, distribute with modifications, sublicense, and/or sell       *
12  * copies of the Software, and to permit persons to whom the Software is    *
13  * furnished to do so, subject to the following conditions:                 *
14  *                                                                          *
15  * The above copyright notice and this permission notice shall be included  *
16  * in all copies or substantial portions of the Software.                   *
17  *                                                                          *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
21  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
22  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
23  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
24  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
25  *                                                                          *
26  * Except as contained in this notice, the name(s) of the above copyright   *
27  * holders shall not be used in advertising or otherwise to promote the     *
28  * sale, use or other dealings in this Software without prior written       *
29  * authorization.                                                           *
30  ****************************************************************************/
31 
32 /****************************************************************************
33  *  Author: Thomas E. Dickey                        2006-on                 *
34  ****************************************************************************/
35 
36 #include <curses.priv.h>
37 #include <tic.h>
38 #include <hashed_db.h>
39 
40 #if USE_HASHED_DB
41 
42 MODULE_ID("$Id: hashed_db.c,v 1.2 2023/10/17 09:52:09 nicm Exp $")
43 
44 #if HASHED_DB_API >= 2
45 static DBC *cursor;
46 #endif
47 
48 typedef struct _myconn {
49     struct _myconn *next;
50     DB *db;
51     char *path;
52     bool modify;
53 } MYCONN;
54 
55 static MYCONN *connections;
56 
57 static void
cleanup(void)58 cleanup(void)
59 {
60     while (connections != 0) {
61 	_nc_db_close(connections->db);
62     }
63 }
64 
65 static DB *
find_connection(const char * path,bool modify)66 find_connection(const char *path, bool modify)
67 {
68     DB *result = 0;
69     MYCONN *p;
70 
71     for (p = connections; p != 0; p = p->next) {
72 	if (!strcmp(p->path, path) && p->modify == modify) {
73 	    result = p->db;
74 	    break;
75 	}
76     }
77 
78     return result;
79 }
80 
81 static void
drop_connection(DB * db)82 drop_connection(DB * db)
83 {
84     MYCONN *p, *q;
85 
86     for (p = connections, q = 0; p != 0; q = p, p = p->next) {
87 	if (p->db == db) {
88 	    if (q != 0)
89 		q->next = p->next;
90 	    else
91 		connections = p->next;
92 	    free(p->path);
93 	    free(p);
94 	    break;
95 	}
96     }
97 }
98 
99 static void
make_connection(DB * db,const char * path,bool modify)100 make_connection(DB * db, const char *path, bool modify)
101 {
102     MYCONN *p = typeCalloc(MYCONN, 1);
103 
104     if (p != 0) {
105 	p->db = db;
106 	p->path = strdup(path);
107 	p->modify = modify;
108 	if (p->path != 0) {
109 	    p->next = connections;
110 	    connections = p;
111 	} else {
112 	    free(p);
113 	}
114     }
115 }
116 
117 /*
118  * Open the database.
119  */
120 NCURSES_EXPORT(DB *)
_nc_db_open(const char * path,bool modify)121 _nc_db_open(const char *path, bool modify)
122 {
123     DB *result = 0;
124     int code;
125 
126     if (connections == 0)
127 	atexit(cleanup);
128 
129     if ((result = find_connection(path, modify)) == 0) {
130 
131 #if HASHED_DB_API >= 4
132 	db_create(&result, NULL, 0);
133 	if ((code = result->open(result,
134 				 NULL,
135 				 path,
136 				 NULL,
137 				 DB_HASH,
138 				 modify ? DB_CREATE : DB_RDONLY,
139 				 0644)) != 0) {
140 	    result = 0;
141 	}
142 #elif HASHED_DB_API >= 3
143 	db_create(&result, NULL, 0);
144 	if ((code = result->open(result,
145 				 path,
146 				 NULL,
147 				 DB_HASH,
148 				 modify ? DB_CREATE : DB_RDONLY,
149 				 0644)) != 0) {
150 	    result = 0;
151 	}
152 #elif HASHED_DB_API >= 2
153 	if ((code = db_open(path,
154 			    DB_HASH,
155 			    modify ? DB_CREATE : DB_RDONLY,
156 			    0644,
157 			    (DB_ENV *) 0,
158 			    (DB_INFO *) 0,
159 			    &result)) != 0) {
160 	    result = 0;
161 	}
162 #else
163 	if ((result = dbopen(path,
164 			     modify ? (O_CREAT | O_RDWR) : O_RDONLY,
165 			     0644,
166 			     DB_HASH,
167 			     NULL)) == 0) {
168 	    code = errno;
169 	}
170 #endif
171 	if (result != 0) {
172 	    make_connection(result, path, modify);
173 	    T(("opened %s", path));
174 	} else {
175 	    T(("cannot open %s: %s", path, strerror(code)));
176 	}
177     }
178     return result;
179 }
180 
181 /*
182  * Close the database.  Do not attempt to use the 'db' handle after this call.
183  */
184 NCURSES_EXPORT(int)
_nc_db_close(DB * db)185 _nc_db_close(DB * db)
186 {
187     int result;
188 
189     drop_connection(db);
190 #if HASHED_DB_API >= 2
191     result = db->close(db, 0);
192 #else
193     result = db->close(db);
194 #endif
195     return result;
196 }
197 
198 /*
199  * Write a record to the database.
200  *
201  * Returns 0 on success.
202  *
203  * FIXME:  the FreeBSD cap_mkdb program assumes the database could have
204  * duplicates.  There appears to be no good reason for that (review/fix).
205  */
206 NCURSES_EXPORT(int)
_nc_db_put(DB * db,DBT * key,DBT * data)207 _nc_db_put(DB * db, DBT * key, DBT * data)
208 {
209     int result;
210 #if HASHED_DB_API >= 2
211     /* remove any pre-existing value, since we do not want duplicates */
212     (void) db->del(db, NULL, key, 0);
213     result = db->put(db, NULL, key, data, DB_NOOVERWRITE);
214 #else
215     result = db->put(db, key, data, R_NOOVERWRITE);
216 #endif
217     return result;
218 }
219 
220 /*
221  * Read a record from the database.
222  *
223  * Returns 0 on success.
224  */
225 NCURSES_EXPORT(int)
_nc_db_get(DB * db,DBT * key,DBT * data)226 _nc_db_get(DB * db, DBT * key, DBT * data)
227 {
228     int result;
229 
230     memset(data, 0, sizeof(*data));
231 #if HASHED_DB_API >= 2
232     result = db->get(db, NULL, key, data, 0);
233 #else
234     result = db->get(db, key, data, 0);
235 #endif
236     return result;
237 }
238 
239 /*
240  * Read the first record from the database, ignoring order.
241  *
242  * Returns 0 on success.
243  */
244 NCURSES_EXPORT(int)
_nc_db_first(DB * db,DBT * key,DBT * data)245 _nc_db_first(DB * db, DBT * key, DBT * data)
246 {
247     int result;
248 
249     memset(key, 0, sizeof(*key));
250     memset(data, 0, sizeof(*data));
251 #if HASHED_DB_API >= 2
252     if ((result = db->cursor(db, NULL, &cursor, 0)) == 0) {
253 	result = cursor->c_get(cursor, key, data, DB_FIRST);
254     }
255 #else
256     result = db->seq(db, key, data, 0);
257 #endif
258     return result;
259 }
260 
261 /*
262  * Read the next record from the database, ignoring order.
263  *
264  * Returns 0 on success.
265  */
266 NCURSES_EXPORT(int)
_nc_db_next(DB * db,DBT * key,DBT * data)267 _nc_db_next(DB * db, DBT * key, DBT * data)
268 {
269     int result;
270 
271 #if HASHED_DB_API >= 2
272     (void) db;
273     if (cursor != 0) {
274 	result = cursor->c_get(cursor, key, data, DB_NEXT);
275     } else {
276 	result = -1;
277     }
278 #else
279     result = db->seq(db, key, data, R_NEXT);
280 #endif
281     return result;
282 }
283 
284 /*
285  * Check if a record is a terminfo index record.  Index records are those that
286  * contain only an alias pointing to a list of aliases.
287  */
288 NCURSES_EXPORT(bool)
_nc_db_have_index(DBT * key,DBT * data,char ** buffer,int * size)289 _nc_db_have_index(DBT * key, DBT * data, char **buffer, int *size)
290 {
291     bool result = FALSE;
292     int used = (int) data->size - 1;
293     char *have = (char *) data->data;
294 
295     (void) key;
296     if (*have++ == 2) {
297 	result = TRUE;
298     }
299     /*
300      * Update params in any case for consistency with _nc_db_have_data().
301      */
302     *buffer = have;
303     *size = used;
304     return result;
305 }
306 
307 /*
308  * Check if a record is the terminfo data record.  Ignore index records, e.g.,
309  * those that contain only an alias pointing to a list of aliases.
310  */
311 NCURSES_EXPORT(bool)
_nc_db_have_data(DBT * key,DBT * data,char ** buffer,int * size)312 _nc_db_have_data(DBT * key, DBT * data, char **buffer, int *size)
313 {
314     bool result = FALSE;
315     int used = (int) data->size - 1;
316     char *have = (char *) data->data;
317 
318     if (*have++ == 0) {
319 	if (data->size > key->size
320 	    && IS_TIC_MAGIC(have)) {
321 	    result = TRUE;
322 	}
323     }
324     /*
325      * Update params in any case to make it simple to follow a index record
326      * to the data record.
327      */
328     *buffer = have;
329     *size = used;
330     return result;
331 }
332 
333 #else
334 
335 extern
336 NCURSES_EXPORT(void)
337 _nc_hashed_db(void);
338 
339 NCURSES_EXPORT(void)
_nc_hashed_db(void)340 _nc_hashed_db(void)
341 {
342 }
343 
344 #endif /* USE_HASHED_DB */
345