blob: ab056bcd0c6f58f5158cb46a9a941d4419a632c1 [file] [log] [blame]
alaffinf5589902000-09-21 21:35:06 +00001/*
2 * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
18 *
19 * You should have received a copy of the GNU General Public License along
Wanlong Gaofed96412012-10-24 10:10:29 +080020 * with this program; if not, write the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
alaffinf5589902000-09-21 21:35:06 +000022 *
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
25 *
26 * http://www.sgi.com
27 *
28 * For further information regarding this notice, see:
29 *
30 * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
31 *
32 */
robbiewf3a83d52002-05-28 16:26:16 +000033/* $Id: symbol.c,v 1.4 2002/05/28 16:26:16 robbiew Exp $ */
alaffinf5589902000-09-21 21:35:06 +000034/*
35 * Generic Symbol Table
36 *
37 * This is intended to look a lot like ndbm, except that all information
38 * is kept in memory, and a multi-key, hierarchical access mode is provided.
39 * This is largely patterned after the Berkeley "DB" package.
40 *
41 * Requirements
42 *
43 * - "key" is ASCII (a C string, in fact)
44 *
45 * Symbol Table Structure
46 *
47 * Two data structures:
48 * Symbol Table Header
49 * Symbol Table Node
50 *
51 * A symbol table header consists of a magic number, a pointer to
52 * the first node in the symbol table, and a cursor that is used
53 * when sequentialy stepping thru the entire list.
54 *
55 * Symbol table nodes contain a pointer to a key, a pointer to this
56 * key's data, and a pointer to the next node in the chain.
57 * Note that to create a hierarchical symbol table, a node is created
58 * whose data points to a symbol table header.
59 */
60
61#include <stdio.h>
62#include <errno.h>
63#include <stdlib.h>
nstrazd5d51ca2001-02-28 17:41:59 +000064#include <string.h>
alaffinf5589902000-09-21 21:35:06 +000065#include <assert.h>
66#include "symbol.h"
67#include "splitstr.h"
68
69#define SYM_MAGIC 0xbadc0de
70
71/*
72 * Some functions can report an error message by assigning it to this
73 * string.
74 */
75
Wanlong Gao354ebb42012-12-07 10:10:04 +080076static char *sym_error = NULL;
alaffinf5589902000-09-21 21:35:06 +000077
78/*
79 * Memory Allocators
80 *
81 * newsym() allocates a new symbol table header node
82 * mknode(...) allocates a new symbol table entry
83 */
84
85SYM newsym()
86{
Wanlong Gao354ebb42012-12-07 10:10:04 +080087 SYM h;
alaffinf5589902000-09-21 21:35:06 +000088
Wanlong Gao354ebb42012-12-07 10:10:04 +080089 if ((h = (SYM) malloc(sizeof(struct symh))) == NULL) {
90 sym_error = "sym header malloc failed!";
91 return (NULL);
92 }
alaffinf5589902000-09-21 21:35:06 +000093
Wanlong Gao354ebb42012-12-07 10:10:04 +080094 h->magic = SYM_MAGIC;
95 h->sym = NULL;
96 h->cursor = NULL;
97 return (h);
alaffinf5589902000-09-21 21:35:06 +000098}
99
Wanlong Gao354ebb42012-12-07 10:10:04 +0800100static struct sym *mknode(struct sym *next, char *key, void *data)
alaffinf5589902000-09-21 21:35:06 +0000101{
Wanlong Gao354ebb42012-12-07 10:10:04 +0800102 struct sym *n;
alaffinf5589902000-09-21 21:35:06 +0000103
Wanlong Gao354ebb42012-12-07 10:10:04 +0800104 if ((n = (struct sym *)malloc(sizeof(struct sym))) == NULL) {
105 sym_error = "sym node malloc failed!";
106 return (NULL);
107 }
alaffinf5589902000-09-21 21:35:06 +0000108
Wanlong Gao354ebb42012-12-07 10:10:04 +0800109 n->next = next;
110 n->key = strdup(key);
111 n->data = data;
alaffinf5589902000-09-21 21:35:06 +0000112
Wanlong Gao354ebb42012-12-07 10:10:04 +0800113 if (n->key == NULL) {
114 sym_error = "sym node strdup(key) failed!";
115 return (NULL);
116 }
117 return (n);
alaffinf5589902000-09-21 21:35:06 +0000118}
119
120/*
121 * Search for a key in a single-level symbol table hierarchy.
122 */
Wanlong Gao354ebb42012-12-07 10:10:04 +0800123static struct sym *find_key1(struct sym *sym, char *key)
alaffinf5589902000-09-21 21:35:06 +0000124{
Wanlong Gao354ebb42012-12-07 10:10:04 +0800125 while (sym != NULL)
126 if (strcmp(sym->key, key) == 0)
127 return (sym);
128 else
129 sym = sym->next;
130 return (NULL);
alaffinf5589902000-09-21 21:35:06 +0000131}
132
133/*
134 * Create a new key node, add it to the *end* of this list
135 */
Wanlong Gao354ebb42012-12-07 10:10:04 +0800136static int add_key(SYM sym, char *key, void *data)
alaffinf5589902000-09-21 21:35:06 +0000137{
Wanlong Gao354ebb42012-12-07 10:10:04 +0800138 register struct sym *sn;
alaffinf5589902000-09-21 21:35:06 +0000139
Wanlong Gao354ebb42012-12-07 10:10:04 +0800140 if (sym->sym == NULL) {
141 sym->sym = mknode(NULL, key, data);
142 if (sym->sym == NULL) {
143 return (-1);
144 }
145 } else {
146 for (sn = sym->sym; sn != NULL && sn->next != NULL;
147 sn = sn->next) ;
148 sn->next = mknode(NULL, key, data);
149 assert(sn->next != NULL);
150 if (sn->next == NULL)
151 return (-1);
152 }
153 return (0);
alaffinf5589902000-09-21 21:35:06 +0000154}
155
156/*
157 * Create a new symbol table
158 */
159SYM sym_open(int flags, int mode, int openinfo)
160{
Wanlong Gao354ebb42012-12-07 10:10:04 +0800161 return (newsym());
alaffinf5589902000-09-21 21:35:06 +0000162}
163
alaffinf5589902000-09-21 21:35:06 +0000164/*
165 * Add (key, data) to an existing symbol table
166 *
167 * If the key does not exist, a new key is added to the end of the list.
168 * If the key exists and the PUT_REPLACE flag is not supplied, return EEXIST.
169 * If a symbol table entry in a multi-part key is not a symbol table (i.e.
170 * element two of a three or more element key), return ENOTDIR.
171 *
172 * "data" is not duplicated and must not point to a static area that could
Garrett Cooper1e6f5a62010-12-19 09:58:10 -0800173 * go away before the element is deleted (such as a local string in a
alaffinf5589902000-09-21 21:35:06 +0000174 * function)
175 *
176 * "key" is duplicated as needed, and is not modified.
177 *
178 * Code:
179 * chop up key on commas
Garrett Cooper1e6f5a62010-12-19 09:58:10 -0800180 *
alaffinf5589902000-09-21 21:35:06 +0000181 * search until a key element isn't found in the key tree, the key list is
182 * exhausted, or a key's data element is not a sub-tree
Garrett Cooper1e6f5a62010-12-19 09:58:10 -0800183 *
alaffinf5589902000-09-21 21:35:06 +0000184 * if the key list is exhausted, return a "duplicate entry" error
Garrett Cooper1e6f5a62010-12-19 09:58:10 -0800185 *
alaffinf5589902000-09-21 21:35:06 +0000186 * if the last found key's data element is not a sub-tree, return
187 * something like "ENOTDIR".
Garrett Cooper1e6f5a62010-12-19 09:58:10 -0800188 *
189 * add new keys for sub-trees until key list is exhausted;
alaffinf5589902000-09-21 21:35:06 +0000190 * last node gets 'data'.
Garrett Cooper1e6f5a62010-12-19 09:58:10 -0800191 *
alaffinf5589902000-09-21 21:35:06 +0000192 */
Wanlong Gao354ebb42012-12-07 10:10:04 +0800193int sym_put(SYM sym, char *key, void *data, int flags)
alaffinf5589902000-09-21 21:35:06 +0000194{
Wanlong Gao354ebb42012-12-07 10:10:04 +0800195 const char **keys; /* key split into a 2d string array */
196 char **kk;
197 char *nkey; /* copy of 'key' -- before split */
198 SYM csym, ncsym; /* search: current symbol table */
199 struct sym *nsym = NULL; /* search: found symbol entry */
alaffinf5589902000-09-21 21:35:06 +0000200
Wanlong Gao354ebb42012-12-07 10:10:04 +0800201 if (sym == NULL)
202 return (EINVAL);
alaffinf5589902000-09-21 21:35:06 +0000203
Wanlong Gao354ebb42012-12-07 10:10:04 +0800204 nkey = strdup(key);
205 keys = splitstr(key, ",", NULL);
alaffinf5589902000-09-21 21:35:06 +0000206
Wanlong Gao354ebb42012-12-07 10:10:04 +0800207 if (keys == NULL)
208 return (EINVAL);
alaffinf5589902000-09-21 21:35:06 +0000209
Wanlong Gao354ebb42012-12-07 10:10:04 +0800210 for (kk = (char **)keys, csym = sym;
211 *kk != NULL && (nsym = find_key1(csym->sym, *kk)) != NULL;
212 csym = nsym->data) {
alaffinf5589902000-09-21 21:35:06 +0000213
Wanlong Gao354ebb42012-12-07 10:10:04 +0800214 if (*++kk == NULL)
215 break;
alaffinf5589902000-09-21 21:35:06 +0000216
Wanlong Gao354ebb42012-12-07 10:10:04 +0800217 if (nsym->data == NULL) { /* fatal error */
218 free(nkey);
219 splitstr_free(keys);
220 return (ENOTDIR);
221 }
222 if (((SYM) (nsym->data))->magic != SYM_MAGIC) {
223 free(nkey);
224 splitstr_free(keys);
225 return (ENOTDIR);
226 }
alaffinf5589902000-09-21 21:35:06 +0000227 }
alaffinf5589902000-09-21 21:35:06 +0000228
Wanlong Gao354ebb42012-12-07 10:10:04 +0800229 if (*kk == NULL) { /* found a complete match */
230 free(nkey);
231 splitstr_free(keys);
232
233 if (flags == PUT_REPLACE) {
234 nsym->data = data;
235 return (0);
236 } else {
237 return (EEXIST);
238 }
239 }
240
241 /* csym is a ptr to a list */
242 for (; *kk != NULL; kk++) {
243 if (*(kk + 1) != NULL) {
244 add_key(csym, *kk, (void *)(ncsym = newsym()));
245 csym = ncsym;
246 } else {
247 add_key(csym, *kk, data); /* last key */
248 }
249 }
250
alaffinf5589902000-09-21 21:35:06 +0000251 free(nkey);
252 splitstr_free(keys);
Wanlong Gao354ebb42012-12-07 10:10:04 +0800253 return (0);
alaffinf5589902000-09-21 21:35:06 +0000254}
255
256/*
257 * Retrieve a Symbol's Contents
258 *
259 * "key" is not modified.
260 * If the key cannot be found, NULL is returned
261 */
Wanlong Gao354ebb42012-12-07 10:10:04 +0800262void *sym_get(SYM sym, char *key)
alaffinf5589902000-09-21 21:35:06 +0000263{
Wanlong Gao354ebb42012-12-07 10:10:04 +0800264 char *nkey;
265 const char **keys; /* key split into a 2d string array */
266 char **kk;
267 SYM csym; /* search: current symbol table */
268 struct sym *nsym = NULL; /* search: found symbol entry */
alaffinf5589902000-09-21 21:35:06 +0000269
Wanlong Gao354ebb42012-12-07 10:10:04 +0800270 if (sym == NULL)
271 return (NULL);
alaffinf5589902000-09-21 21:35:06 +0000272
Wanlong Gao354ebb42012-12-07 10:10:04 +0800273 nkey = strdup(key);
274 keys = splitstr(nkey, ",", NULL);
275 if (keys == NULL)
276 return (NULL);
alaffinf5589902000-09-21 21:35:06 +0000277
Wanlong Gao354ebb42012-12-07 10:10:04 +0800278 for (kk = (char **)keys, csym = sym;
279 *kk != NULL && (nsym = find_key1(csym->sym, *kk)) != NULL;
280 csym = nsym->data) {
alaffinf5589902000-09-21 21:35:06 +0000281
Wanlong Gao354ebb42012-12-07 10:10:04 +0800282 if (*++kk == NULL)
283 break;
alaffinf5589902000-09-21 21:35:06 +0000284
Wanlong Gao354ebb42012-12-07 10:10:04 +0800285 if (nsym->data == NULL) { /* fatal error */
286 free(nkey);
287 splitstr_free(keys);
288 return (NULL);
289 }
290 if (((SYM) (nsym->data))->magic != SYM_MAGIC) {
291 free(nkey);
292 splitstr_free(keys);
293 return (NULL);
294 }
alaffinf5589902000-09-21 21:35:06 +0000295 }
alaffinf5589902000-09-21 21:35:06 +0000296
Wanlong Gao354ebb42012-12-07 10:10:04 +0800297 if (*kk == NULL) { /* found a complete match */
298 splitstr_free(keys);
299 free(nkey);
300 return (nsym->data);
301 } else {
302 splitstr_free(keys);
303 free(nkey);
304 return (NULL);
305 }
Garrett Cooper1e6f5a62010-12-19 09:58:10 -0800306}
alaffinf5589902000-09-21 21:35:06 +0000307
308/*
309 * Step thru a symbol table list
310 *
311 * The cursor must be set by R_CURSOR, R_FIRST before using R_NEXT.
312 * NULL is returned when no more items are available.
313 */
Wanlong Gao354ebb42012-12-07 10:10:04 +0800314int sym_seq(SYM sym, DBT * key, DBT * data, int flags)
alaffinf5589902000-09-21 21:35:06 +0000315{
Wanlong Gao354ebb42012-12-07 10:10:04 +0800316 SYM csym;
alaffinf5589902000-09-21 21:35:06 +0000317
Wanlong Gao354ebb42012-12-07 10:10:04 +0800318 switch (flags) {
319 /*
320 * A number of ways to do this:
321 * specificly: sym_seq( .., "key,key") sets to Nth element of the 2nd
322 * level symbol table
323 * sym_seq(.., "key,key,") sets to the first element of the 3rd
324 * level symbol table
325 *
326 * sym_seq(.., "key,key") where both must be complete keys, sets
327 * cursor to the first element of the 3rd level symbol table;
328 * if there is no 3rd level, return an error.
329 */
330 case R_CURSOR:
331 csym = (SYM) sym_get(sym, (char *)key->data);
332 if (csym == NULL || csym->magic != SYM_MAGIC) {
333 return (2);
334 }
335 sym->cursor = csym->sym;
336 if (sym->cursor == NULL)
337 return (1);
338 key->data = sym->cursor->key;
339 data->data = sym->cursor->data;
340
341 return (0);
342
343 case R_FIRST:
344 sym->cursor = sym->sym;
345 if (sym->cursor == NULL)
346 return (1);
347 key->data = sym->cursor->key;
348 data->data = sym->cursor->data;
349
350 return (0);
351
352 case R_NEXT:
353 if (sym->cursor == NULL)
354 return (1);
355 sym->cursor = sym->cursor->next;
356
357 if (sym->cursor == NULL)
358 return (1);
359
360 key->data = sym->cursor->key;
361 data->data = sym->cursor->data;
362
363 return (0);
364
365 case R_LAST:
366 case R_PREV:
367 default:
368 return (-1);
alaffinf5589902000-09-21 21:35:06 +0000369 }
alaffinf5589902000-09-21 21:35:06 +0000370}
371
372/*
373 * Dump a symbol table's keys.
374 * Handles hierarchies, using a double quote to indicate depth, one
375 * double quote for each level.
376 */
Wanlong Gao354ebb42012-12-07 10:10:04 +0800377int sym_dump(SYM sym, int depth)
alaffinf5589902000-09-21 21:35:06 +0000378{
379
Wanlong Gao354ebb42012-12-07 10:10:04 +0800380 register struct sym *se; /* symbol entry */
381 register int d;
alaffinf5589902000-09-21 21:35:06 +0000382
Wanlong Gao354ebb42012-12-07 10:10:04 +0800383 if (sym == NULL || sym->magic != SYM_MAGIC)
384 return -1;
alaffinf5589902000-09-21 21:35:06 +0000385
Wanlong Gao354ebb42012-12-07 10:10:04 +0800386 for (se = sym->sym; se != NULL; se = se->next) {
387 for (d = 0; d < depth; d++) {
388 putchar('"');
389 putchar(' ');
390 }
391 printf("%s\n", se->key);
392 sym_dump((SYM) se->data, depth + 1);
alaffinf5589902000-09-21 21:35:06 +0000393 }
Wanlong Gao354ebb42012-12-07 10:10:04 +0800394 return 0;
alaffinf5589902000-09-21 21:35:06 +0000395}
396
397/*
398 * sym dump, but data is _always_ a string (print it)
399 */
Wanlong Gao354ebb42012-12-07 10:10:04 +0800400int sym_dump_s(SYM sym, int depth)
alaffinf5589902000-09-21 21:35:06 +0000401{
402
Wanlong Gao354ebb42012-12-07 10:10:04 +0800403 register struct sym *se; /* symbol entry */
404 register int d;
alaffinf5589902000-09-21 21:35:06 +0000405
Wanlong Gao354ebb42012-12-07 10:10:04 +0800406 if (sym == NULL)
407 return 0;
408
409 if (sym->magic != SYM_MAGIC) {
410 for (d = 0; d < depth; d++) {
411 putchar('"');
412 putchar(' ');
413 }
414 printf(" = %s\n", (char *)sym);
415 return 0;
416 }
417
418 for (se = sym->sym; se != NULL; se = se->next) {
419 for (d = 0; d < depth; d++) {
420 putchar('"');
421 putchar(' ');
422 }
423 printf("%s", se->key);
424 if (((SYM) se->data)->magic == SYM_MAGIC) {
425 putchar('\n');
426 sym_dump_s((SYM) se->data, depth + 1);
427 } else {
428 printf("(%p) = %s (%p)\n", se->key, (char *)se->data,
429 se->data);
430 }
431 }
alaffinf5589902000-09-21 21:35:06 +0000432 return 0;
alaffinf5589902000-09-21 21:35:06 +0000433}
434
435/*
436 * Remove an entire symbol table (done bottom up)
437 */
Wanlong Gao354ebb42012-12-07 10:10:04 +0800438int sym_rm(SYM sym, int flags)
alaffinf5589902000-09-21 21:35:06 +0000439{
Wanlong Gao354ebb42012-12-07 10:10:04 +0800440 register struct sym *se, *nse; /* symbol entry */
alaffinf5589902000-09-21 21:35:06 +0000441
Wanlong Gao354ebb42012-12-07 10:10:04 +0800442 if (sym == NULL)
443 return 0;
444
445 if (sym->magic != SYM_MAGIC) {
446 if (!(flags & RM_DATA))
447 free(sym);
448 return 0;
449 }
450
451 for (se = sym->sym; se != NULL;) {
452 sym_rm((SYM) se->data, flags);
453 nse = se->next;
454 if (flags & RM_KEY)
455 free(se->key);
456 if (flags & RM_DATA)
457 free(se->data);
458 free(se);
459 se = nse;
460 }
461 if (!(flags & RM_DATA))
462 free(sym);
alaffinf5589902000-09-21 21:35:06 +0000463 return 0;
Chris Dearmanec6edca2012-10-17 19:54:01 -0700464}