xref: /openbsd/lib/libcurses/tinfo/hashed_db.c (revision c7ef0cfc)
1*c7ef0cfcSnicm /* $OpenBSD: hashed_db.c,v 1.2 2023/10/17 09:52:09 nicm Exp $ */
281d8c4e1Snicm 
381d8c4e1Snicm /****************************************************************************
4*c7ef0cfcSnicm  * Copyright 2019,2020 Thomas E. Dickey                                     *
5*c7ef0cfcSnicm  * Copyright 2006-2011,2013 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 /****************************************************************************
33*c7ef0cfcSnicm  *  Author: Thomas E. Dickey                        2006-on                 *
3481d8c4e1Snicm  ****************************************************************************/
3581d8c4e1Snicm 
3681d8c4e1Snicm #include <curses.priv.h>
3781d8c4e1Snicm #include <tic.h>
3881d8c4e1Snicm #include <hashed_db.h>
3981d8c4e1Snicm 
4081d8c4e1Snicm #if USE_HASHED_DB
4181d8c4e1Snicm 
42*c7ef0cfcSnicm MODULE_ID("$Id: hashed_db.c,v 1.2 2023/10/17 09:52:09 nicm Exp $")
4381d8c4e1Snicm 
4481d8c4e1Snicm #if HASHED_DB_API >= 2
4581d8c4e1Snicm static DBC *cursor;
4681d8c4e1Snicm #endif
4781d8c4e1Snicm 
48*c7ef0cfcSnicm typedef struct _myconn {
49*c7ef0cfcSnicm     struct _myconn *next;
50*c7ef0cfcSnicm     DB *db;
51*c7ef0cfcSnicm     char *path;
52*c7ef0cfcSnicm     bool modify;
53*c7ef0cfcSnicm } MYCONN;
54*c7ef0cfcSnicm 
55*c7ef0cfcSnicm static MYCONN *connections;
56*c7ef0cfcSnicm 
57*c7ef0cfcSnicm static void
cleanup(void)58*c7ef0cfcSnicm cleanup(void)
59*c7ef0cfcSnicm {
60*c7ef0cfcSnicm     while (connections != 0) {
61*c7ef0cfcSnicm 	_nc_db_close(connections->db);
62*c7ef0cfcSnicm     }
63*c7ef0cfcSnicm }
64*c7ef0cfcSnicm 
65*c7ef0cfcSnicm static DB *
find_connection(const char * path,bool modify)66*c7ef0cfcSnicm find_connection(const char *path, bool modify)
67*c7ef0cfcSnicm {
68*c7ef0cfcSnicm     DB *result = 0;
69*c7ef0cfcSnicm     MYCONN *p;
70*c7ef0cfcSnicm 
71*c7ef0cfcSnicm     for (p = connections; p != 0; p = p->next) {
72*c7ef0cfcSnicm 	if (!strcmp(p->path, path) && p->modify == modify) {
73*c7ef0cfcSnicm 	    result = p->db;
74*c7ef0cfcSnicm 	    break;
75*c7ef0cfcSnicm 	}
76*c7ef0cfcSnicm     }
77*c7ef0cfcSnicm 
78*c7ef0cfcSnicm     return result;
79*c7ef0cfcSnicm }
80*c7ef0cfcSnicm 
81*c7ef0cfcSnicm static void
drop_connection(DB * db)82*c7ef0cfcSnicm drop_connection(DB * db)
83*c7ef0cfcSnicm {
84*c7ef0cfcSnicm     MYCONN *p, *q;
85*c7ef0cfcSnicm 
86*c7ef0cfcSnicm     for (p = connections, q = 0; p != 0; q = p, p = p->next) {
87*c7ef0cfcSnicm 	if (p->db == db) {
88*c7ef0cfcSnicm 	    if (q != 0)
89*c7ef0cfcSnicm 		q->next = p->next;
90*c7ef0cfcSnicm 	    else
91*c7ef0cfcSnicm 		connections = p->next;
92*c7ef0cfcSnicm 	    free(p->path);
93*c7ef0cfcSnicm 	    free(p);
94*c7ef0cfcSnicm 	    break;
95*c7ef0cfcSnicm 	}
96*c7ef0cfcSnicm     }
97*c7ef0cfcSnicm }
98*c7ef0cfcSnicm 
99*c7ef0cfcSnicm static void
make_connection(DB * db,const char * path,bool modify)100*c7ef0cfcSnicm make_connection(DB * db, const char *path, bool modify)
101*c7ef0cfcSnicm {
102*c7ef0cfcSnicm     MYCONN *p = typeCalloc(MYCONN, 1);
103*c7ef0cfcSnicm 
104*c7ef0cfcSnicm     if (p != 0) {
105*c7ef0cfcSnicm 	p->db = db;
106*c7ef0cfcSnicm 	p->path = strdup(path);
107*c7ef0cfcSnicm 	p->modify = modify;
108*c7ef0cfcSnicm 	if (p->path != 0) {
109*c7ef0cfcSnicm 	    p->next = connections;
110*c7ef0cfcSnicm 	    connections = p;
111*c7ef0cfcSnicm 	} else {
112*c7ef0cfcSnicm 	    free(p);
113*c7ef0cfcSnicm 	}
114*c7ef0cfcSnicm     }
115*c7ef0cfcSnicm }
116*c7ef0cfcSnicm 
11781d8c4e1Snicm /*
11881d8c4e1Snicm  * Open the database.
11981d8c4e1Snicm  */
12081d8c4e1Snicm NCURSES_EXPORT(DB *)
_nc_db_open(const char * path,bool modify)12181d8c4e1Snicm _nc_db_open(const char *path, bool modify)
12281d8c4e1Snicm {
12381d8c4e1Snicm     DB *result = 0;
124*c7ef0cfcSnicm     int code;
125*c7ef0cfcSnicm 
126*c7ef0cfcSnicm     if (connections == 0)
127*c7ef0cfcSnicm 	atexit(cleanup);
128*c7ef0cfcSnicm 
129*c7ef0cfcSnicm     if ((result = find_connection(path, modify)) == 0) {
13081d8c4e1Snicm 
13181d8c4e1Snicm #if HASHED_DB_API >= 4
13281d8c4e1Snicm 	db_create(&result, NULL, 0);
133*c7ef0cfcSnicm 	if ((code = result->open(result,
13481d8c4e1Snicm 				 NULL,
13581d8c4e1Snicm 				 path,
13681d8c4e1Snicm 				 NULL,
13781d8c4e1Snicm 				 DB_HASH,
13881d8c4e1Snicm 				 modify ? DB_CREATE : DB_RDONLY,
139*c7ef0cfcSnicm 				 0644)) != 0) {
140*c7ef0cfcSnicm 	    result = 0;
141*c7ef0cfcSnicm 	}
14281d8c4e1Snicm #elif HASHED_DB_API >= 3
14381d8c4e1Snicm 	db_create(&result, NULL, 0);
144*c7ef0cfcSnicm 	if ((code = result->open(result,
14581d8c4e1Snicm 				 path,
14681d8c4e1Snicm 				 NULL,
14781d8c4e1Snicm 				 DB_HASH,
14881d8c4e1Snicm 				 modify ? DB_CREATE : DB_RDONLY,
149*c7ef0cfcSnicm 				 0644)) != 0) {
150*c7ef0cfcSnicm 	    result = 0;
151*c7ef0cfcSnicm 	}
15281d8c4e1Snicm #elif HASHED_DB_API >= 2
15381d8c4e1Snicm 	if ((code = db_open(path,
15481d8c4e1Snicm 			    DB_HASH,
15581d8c4e1Snicm 			    modify ? DB_CREATE : DB_RDONLY,
15681d8c4e1Snicm 			    0644,
15781d8c4e1Snicm 			    (DB_ENV *) 0,
15881d8c4e1Snicm 			    (DB_INFO *) 0,
15981d8c4e1Snicm 			    &result)) != 0) {
16081d8c4e1Snicm 	    result = 0;
16181d8c4e1Snicm 	}
16281d8c4e1Snicm #else
163*c7ef0cfcSnicm 	if ((result = dbopen(path,
16481d8c4e1Snicm 			     modify ? (O_CREAT | O_RDWR) : O_RDONLY,
16581d8c4e1Snicm 			     0644,
16681d8c4e1Snicm 			     DB_HASH,
167*c7ef0cfcSnicm 			     NULL)) == 0) {
168*c7ef0cfcSnicm 	    code = errno;
16981d8c4e1Snicm 	}
17081d8c4e1Snicm #endif
171*c7ef0cfcSnicm 	if (result != 0) {
172*c7ef0cfcSnicm 	    make_connection(result, path, modify);
173*c7ef0cfcSnicm 	    T(("opened %s", path));
174*c7ef0cfcSnicm 	} else {
175*c7ef0cfcSnicm 	    T(("cannot open %s: %s", path, strerror(code)));
176*c7ef0cfcSnicm 	}
177*c7ef0cfcSnicm     }
17881d8c4e1Snicm     return result;
17981d8c4e1Snicm }
18081d8c4e1Snicm 
18181d8c4e1Snicm /*
18281d8c4e1Snicm  * Close the database.  Do not attempt to use the 'db' handle after this call.
18381d8c4e1Snicm  */
18481d8c4e1Snicm NCURSES_EXPORT(int)
_nc_db_close(DB * db)18581d8c4e1Snicm _nc_db_close(DB * db)
18681d8c4e1Snicm {
18781d8c4e1Snicm     int result;
18881d8c4e1Snicm 
189*c7ef0cfcSnicm     drop_connection(db);
19081d8c4e1Snicm #if HASHED_DB_API >= 2
19181d8c4e1Snicm     result = db->close(db, 0);
19281d8c4e1Snicm #else
19381d8c4e1Snicm     result = db->close(db);
19481d8c4e1Snicm #endif
19581d8c4e1Snicm     return result;
19681d8c4e1Snicm }
19781d8c4e1Snicm 
19881d8c4e1Snicm /*
19981d8c4e1Snicm  * Write a record to the database.
20081d8c4e1Snicm  *
20181d8c4e1Snicm  * Returns 0 on success.
20281d8c4e1Snicm  *
20381d8c4e1Snicm  * FIXME:  the FreeBSD cap_mkdb program assumes the database could have
20481d8c4e1Snicm  * duplicates.  There appears to be no good reason for that (review/fix).
20581d8c4e1Snicm  */
20681d8c4e1Snicm NCURSES_EXPORT(int)
_nc_db_put(DB * db,DBT * key,DBT * data)20781d8c4e1Snicm _nc_db_put(DB * db, DBT * key, DBT * data)
20881d8c4e1Snicm {
20981d8c4e1Snicm     int result;
21081d8c4e1Snicm #if HASHED_DB_API >= 2
21181d8c4e1Snicm     /* remove any pre-existing value, since we do not want duplicates */
21281d8c4e1Snicm     (void) db->del(db, NULL, key, 0);
21381d8c4e1Snicm     result = db->put(db, NULL, key, data, DB_NOOVERWRITE);
21481d8c4e1Snicm #else
21581d8c4e1Snicm     result = db->put(db, key, data, R_NOOVERWRITE);
21681d8c4e1Snicm #endif
21781d8c4e1Snicm     return result;
21881d8c4e1Snicm }
21981d8c4e1Snicm 
22081d8c4e1Snicm /*
22181d8c4e1Snicm  * Read a record from the database.
22281d8c4e1Snicm  *
22381d8c4e1Snicm  * Returns 0 on success.
22481d8c4e1Snicm  */
22581d8c4e1Snicm NCURSES_EXPORT(int)
_nc_db_get(DB * db,DBT * key,DBT * data)22681d8c4e1Snicm _nc_db_get(DB * db, DBT * key, DBT * data)
22781d8c4e1Snicm {
22881d8c4e1Snicm     int result;
22981d8c4e1Snicm 
23081d8c4e1Snicm     memset(data, 0, sizeof(*data));
23181d8c4e1Snicm #if HASHED_DB_API >= 2
23281d8c4e1Snicm     result = db->get(db, NULL, key, data, 0);
23381d8c4e1Snicm #else
23481d8c4e1Snicm     result = db->get(db, key, data, 0);
23581d8c4e1Snicm #endif
23681d8c4e1Snicm     return result;
23781d8c4e1Snicm }
23881d8c4e1Snicm 
23981d8c4e1Snicm /*
24081d8c4e1Snicm  * Read the first record from the database, ignoring order.
24181d8c4e1Snicm  *
24281d8c4e1Snicm  * Returns 0 on success.
24381d8c4e1Snicm  */
24481d8c4e1Snicm NCURSES_EXPORT(int)
_nc_db_first(DB * db,DBT * key,DBT * data)24581d8c4e1Snicm _nc_db_first(DB * db, DBT * key, DBT * data)
24681d8c4e1Snicm {
24781d8c4e1Snicm     int result;
24881d8c4e1Snicm 
24981d8c4e1Snicm     memset(key, 0, sizeof(*key));
25081d8c4e1Snicm     memset(data, 0, sizeof(*data));
25181d8c4e1Snicm #if HASHED_DB_API >= 2
25281d8c4e1Snicm     if ((result = db->cursor(db, NULL, &cursor, 0)) == 0) {
25381d8c4e1Snicm 	result = cursor->c_get(cursor, key, data, DB_FIRST);
25481d8c4e1Snicm     }
25581d8c4e1Snicm #else
25681d8c4e1Snicm     result = db->seq(db, key, data, 0);
25781d8c4e1Snicm #endif
25881d8c4e1Snicm     return result;
25981d8c4e1Snicm }
26081d8c4e1Snicm 
26181d8c4e1Snicm /*
26281d8c4e1Snicm  * Read the next record from the database, ignoring order.
26381d8c4e1Snicm  *
26481d8c4e1Snicm  * Returns 0 on success.
26581d8c4e1Snicm  */
26681d8c4e1Snicm NCURSES_EXPORT(int)
_nc_db_next(DB * db,DBT * key,DBT * data)26781d8c4e1Snicm _nc_db_next(DB * db, DBT * key, DBT * data)
26881d8c4e1Snicm {
26981d8c4e1Snicm     int result;
27081d8c4e1Snicm 
27181d8c4e1Snicm #if HASHED_DB_API >= 2
27281d8c4e1Snicm     (void) db;
27381d8c4e1Snicm     if (cursor != 0) {
27481d8c4e1Snicm 	result = cursor->c_get(cursor, key, data, DB_NEXT);
27581d8c4e1Snicm     } else {
27681d8c4e1Snicm 	result = -1;
27781d8c4e1Snicm     }
27881d8c4e1Snicm #else
279*c7ef0cfcSnicm     result = db->seq(db, key, data, R_NEXT);
28081d8c4e1Snicm #endif
28181d8c4e1Snicm     return result;
28281d8c4e1Snicm }
28381d8c4e1Snicm 
28481d8c4e1Snicm /*
28581d8c4e1Snicm  * Check if a record is a terminfo index record.  Index records are those that
28681d8c4e1Snicm  * contain only an alias pointing to a list of aliases.
28781d8c4e1Snicm  */
28881d8c4e1Snicm NCURSES_EXPORT(bool)
_nc_db_have_index(DBT * key,DBT * data,char ** buffer,int * size)28981d8c4e1Snicm _nc_db_have_index(DBT * key, DBT * data, char **buffer, int *size)
29081d8c4e1Snicm {
29181d8c4e1Snicm     bool result = FALSE;
292*c7ef0cfcSnicm     int used = (int) data->size - 1;
29381d8c4e1Snicm     char *have = (char *) data->data;
29481d8c4e1Snicm 
29581d8c4e1Snicm     (void) key;
29681d8c4e1Snicm     if (*have++ == 2) {
29781d8c4e1Snicm 	result = TRUE;
29881d8c4e1Snicm     }
29981d8c4e1Snicm     /*
30081d8c4e1Snicm      * Update params in any case for consistency with _nc_db_have_data().
30181d8c4e1Snicm      */
30281d8c4e1Snicm     *buffer = have;
30381d8c4e1Snicm     *size = used;
30481d8c4e1Snicm     return result;
30581d8c4e1Snicm }
30681d8c4e1Snicm 
30781d8c4e1Snicm /*
30881d8c4e1Snicm  * Check if a record is the terminfo data record.  Ignore index records, e.g.,
30981d8c4e1Snicm  * those that contain only an alias pointing to a list of aliases.
31081d8c4e1Snicm  */
31181d8c4e1Snicm NCURSES_EXPORT(bool)
_nc_db_have_data(DBT * key,DBT * data,char ** buffer,int * size)31281d8c4e1Snicm _nc_db_have_data(DBT * key, DBT * data, char **buffer, int *size)
31381d8c4e1Snicm {
31481d8c4e1Snicm     bool result = FALSE;
315*c7ef0cfcSnicm     int used = (int) data->size - 1;
31681d8c4e1Snicm     char *have = (char *) data->data;
31781d8c4e1Snicm 
31881d8c4e1Snicm     if (*have++ == 0) {
31981d8c4e1Snicm 	if (data->size > key->size
32081d8c4e1Snicm 	    && IS_TIC_MAGIC(have)) {
32181d8c4e1Snicm 	    result = TRUE;
32281d8c4e1Snicm 	}
32381d8c4e1Snicm     }
32481d8c4e1Snicm     /*
32581d8c4e1Snicm      * Update params in any case to make it simple to follow a index record
32681d8c4e1Snicm      * to the data record.
32781d8c4e1Snicm      */
32881d8c4e1Snicm     *buffer = have;
32981d8c4e1Snicm     *size = used;
33081d8c4e1Snicm     return result;
33181d8c4e1Snicm }
33281d8c4e1Snicm 
33381d8c4e1Snicm #else
33481d8c4e1Snicm 
33581d8c4e1Snicm extern
33681d8c4e1Snicm NCURSES_EXPORT(void)
33781d8c4e1Snicm _nc_hashed_db(void);
33881d8c4e1Snicm 
33981d8c4e1Snicm NCURSES_EXPORT(void)
_nc_hashed_db(void)34081d8c4e1Snicm _nc_hashed_db(void)
34181d8c4e1Snicm {
34281d8c4e1Snicm }
34381d8c4e1Snicm 
34481d8c4e1Snicm #endif /* USE_HASHED_DB */
345