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