ncurses 5.9 - patch 20111022
[ncurses.git] / ncurses / tinfo / hashed_db.c
1 /****************************************************************************
2  * Copyright (c) 2006-2008,2011 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-on                 *
31  ****************************************************************************/
32
33 #include <curses.priv.h>
34 #include <tic.h>
35 #include <hashed_db.h>
36
37 #if USE_HASHED_DB
38
39 MODULE_ID("$Id: hashed_db.c,v 1.15 2011/08/13 21:08:08 tom Exp $")
40
41 #if HASHED_DB_API >= 2
42 static DBC *cursor;
43 #endif
44
45 typedef struct _myconn {
46     struct _myconn *next;
47     DB *db;
48     char *path;
49     bool modify;
50 } MYCONN;
51
52 static MYCONN *connections;
53
54 static void
55 cleanup(void)
56 {
57     while (connections != 0) {
58         _nc_db_close(connections->db);
59     }
60 }
61
62 static DB *
63 find_connection(const char *path, bool modify)
64 {
65     DB *result = 0;
66     MYCONN *p;
67
68     for (p = connections; p != 0; p = p->next) {
69         if (!strcmp(p->path, path) && p->modify == modify) {
70             result = p->db;
71             break;
72         }
73     }
74
75     return result;
76 }
77
78 static void
79 drop_connection(DB * db)
80 {
81     MYCONN *p, *q;
82
83     for (p = connections, q = 0; p != 0; q = p, p = p->next) {
84         if (p->db == db) {
85             if (q != 0)
86                 q->next = p->next;
87             else
88                 connections = p->next;
89             free(p->path);
90             free(p);
91             break;
92         }
93     }
94 }
95
96 static void
97 make_connection(DB * db, const char *path, bool modify)
98 {
99     MYCONN *p = typeCalloc(MYCONN, 1);
100
101     if (p != 0) {
102         p->db = db;
103         p->path = strdup(path);
104         p->modify = modify;
105         if (p->path != 0) {
106             p->next = connections;
107             connections = p;
108         }
109     }
110 }
111
112 /*
113  * Open the database.
114  */
115 NCURSES_EXPORT(DB *)
116 _nc_db_open(const char *path, bool modify)
117 {
118     DB *result = 0;
119     int code;
120
121     if (connections == 0)
122         atexit(cleanup);
123
124     if ((result = find_connection(path, modify)) == 0) {
125
126 #if HASHED_DB_API >= 4
127         db_create(&result, NULL, 0);
128         if ((code = result->open(result,
129                                  NULL,
130                                  path,
131                                  NULL,
132                                  DB_HASH,
133                                  modify ? DB_CREATE : DB_RDONLY,
134                                  0644)) != 0) {
135             result = 0;
136         }
137 #elif HASHED_DB_API >= 3
138         db_create(&result, NULL, 0);
139         if ((code = result->open(result,
140                                  path,
141                                  NULL,
142                                  DB_HASH,
143                                  modify ? DB_CREATE : DB_RDONLY,
144                                  0644)) != 0) {
145             result = 0;
146         }
147 #elif HASHED_DB_API >= 2
148         if ((code = db_open(path,
149                             DB_HASH,
150                             modify ? DB_CREATE : DB_RDONLY,
151                             0644,
152                             (DB_ENV *) 0,
153                             (DB_INFO *) 0,
154                             &result)) != 0) {
155             result = 0;
156         }
157 #else
158         if ((result = dbopen(path,
159                              modify ? (O_CREAT | O_RDWR) : O_RDONLY,
160                              0644,
161                              DB_HASH,
162                              NULL)) == 0) {
163             code = errno;
164         }
165 #endif
166         if (result != 0) {
167             make_connection(result, path, modify);
168             T(("opened %s", path));
169         } else {
170             T(("cannot open %s: %s", path, strerror(code)));
171         }
172     }
173     return result;
174 }
175
176 /*
177  * Close the database.  Do not attempt to use the 'db' handle after this call.
178  */
179 NCURSES_EXPORT(int)
180 _nc_db_close(DB * db)
181 {
182     int result;
183
184     drop_connection(db);
185 #if HASHED_DB_API >= 2
186     result = db->close(db, 0);
187 #else
188     result = db->close(db);
189 #endif
190     return result;
191 }
192
193 /*
194  * Write a record to the database.
195  *
196  * Returns 0 on success.
197  *
198  * FIXME:  the FreeBSD cap_mkdb program assumes the database could have
199  * duplicates.  There appears to be no good reason for that (review/fix).
200  */
201 NCURSES_EXPORT(int)
202 _nc_db_put(DB * db, DBT * key, DBT * data)
203 {
204     int result;
205 #if HASHED_DB_API >= 2
206     /* remove any pre-existing value, since we do not want duplicates */
207     (void) db->del(db, NULL, key, 0);
208     result = db->put(db, NULL, key, data, DB_NOOVERWRITE);
209 #else
210     result = db->put(db, key, data, R_NOOVERWRITE);
211 #endif
212     return result;
213 }
214
215 /*
216  * Read a record from the database.
217  *
218  * Returns 0 on success.
219  */
220 NCURSES_EXPORT(int)
221 _nc_db_get(DB * db, DBT * key, DBT * data)
222 {
223     int result;
224
225     memset(data, 0, sizeof(*data));
226 #if HASHED_DB_API >= 2
227     result = db->get(db, NULL, key, data, 0);
228 #else
229     result = db->get(db, key, data, 0);
230 #endif
231     return result;
232 }
233
234 /*
235  * Read the first record from the database, ignoring order.
236  *
237  * Returns 0 on success.
238  */
239 NCURSES_EXPORT(int)
240 _nc_db_first(DB * db, DBT * key, DBT * data)
241 {
242     int result;
243
244     memset(key, 0, sizeof(*key));
245     memset(data, 0, sizeof(*data));
246 #if HASHED_DB_API >= 2
247     if ((result = db->cursor(db, NULL, &cursor, 0)) == 0) {
248         result = cursor->c_get(cursor, key, data, DB_FIRST);
249     }
250 #else
251     result = db->seq(db, key, data, 0);
252 #endif
253     return result;
254 }
255
256 /*
257  * Read the next record from the database, ignoring order.
258  *
259  * Returns 0 on success.
260  */
261 NCURSES_EXPORT(int)
262 _nc_db_next(DB * db, DBT * key, DBT * data)
263 {
264     int result;
265
266 #if HASHED_DB_API >= 2
267     (void) db;
268     if (cursor != 0) {
269         result = cursor->c_get(cursor, key, data, DB_NEXT);
270     } else {
271         result = -1;
272     }
273 #else
274     result = db->seq(db, key, data, 0);
275 #endif
276     return result;
277 }
278
279 /*
280  * Check if a record is a terminfo index record.  Index records are those that
281  * contain only an alias pointing to a list of aliases.
282  */
283 NCURSES_EXPORT(bool)
284 _nc_db_have_index(DBT * key, DBT * data, char **buffer, int *size)
285 {
286     bool result = FALSE;
287     int used = data->size - 1;
288     char *have = (char *) data->data;
289
290     (void) key;
291     if (*have++ == 2) {
292         result = TRUE;
293     }
294     /*
295      * Update params in any case for consistency with _nc_db_have_data().
296      */
297     *buffer = have;
298     *size = used;
299     return result;
300 }
301
302 /*
303  * Check if a record is the terminfo data record.  Ignore index records, e.g.,
304  * those that contain only an alias pointing to a list of aliases.
305  */
306 NCURSES_EXPORT(bool)
307 _nc_db_have_data(DBT * key, DBT * data, char **buffer, int *size)
308 {
309     bool result = FALSE;
310     int used = data->size - 1;
311     char *have = (char *) data->data;
312
313     if (*have++ == 0) {
314         if (data->size > key->size
315             && IS_TIC_MAGIC(have)) {
316             result = TRUE;
317         }
318     }
319     /*
320      * Update params in any case to make it simple to follow a index record
321      * to the data record.
322      */
323     *buffer = have;
324     *size = used;
325     return result;
326 }
327
328 #else
329
330 extern
331 NCURSES_EXPORT(void)
332 _nc_hashed_db(void);
333
334 NCURSES_EXPORT(void)
335 _nc_hashed_db(void)
336 {
337 }
338
339 #endif /* USE_HASHED_DB */