BRL-CAD
db_lookup.c
Go to the documentation of this file.
1 /* D B _ L O O K U P . C
2  * BRL-CAD
3  *
4  * Copyright (c) 1988-2014 United States Government as represented by
5  * the U.S. Army Research Laboratory.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * version 2.1 as published by the Free Software Foundation.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this file; see the file named COPYING for more
18  * information.
19  */
20 /** @addtogroup dbio */
21 /** @{ */
22 /** @file librt/db_lookup.c
23  *
24  * v4/v5 database directory routines
25  *
26  */
27 
28 #include "common.h"
29 
30 #include <string.h>
31 #include "bio.h"
32 
33 #include "vmath.h"
34 #include "db.h"
35 #include "raytrace.h"
36 
37 
38 int
39 db_is_directory_non_empty(const struct db_i *dbip)
40 {
41  int i;
42 
43  RT_CK_DBI(dbip);
44 
45  for (i = 0; i < RT_DBNHASH; i++) {
46  if (dbip->dbi_Head[i] != RT_DIR_NULL)
47  return 1;
48  }
49  return 0;
50 }
51 
52 
53 size_t
54 db_directory_size(const struct db_i *dbip)
55 {
56  struct directory *dp;
57  size_t count = 0;
58  size_t i;
59 
60  RT_CK_DBI(dbip);
61 
62  for (i = 0; i < RT_DBNHASH; i++) {
63  for (dp = dbip->dbi_Head[i]; dp != RT_DIR_NULL; dp = dp->d_forw)
64  count++;
65  }
66  return count;
67 }
68 
69 
70 void
71 db_ck_directory(const struct db_i *dbip)
72 {
73  struct directory *dp;
74  int i;
75 
76  RT_CK_DBI(dbip);
77 
78  for (i = 0; i < RT_DBNHASH; i++) {
79  for (dp = dbip->dbi_Head[i]; dp != RT_DIR_NULL; dp = dp->d_forw)
80  RT_CK_DIR(dp);
81  }
82 }
83 
84 
85 int
86 db_dirhash(const char *str)
87 {
88  const unsigned char *s = (unsigned char *)str;
89  size_t sum = 0;
90  int i = 1;
91 
92  /* sanity */
93  if (!str)
94  return 0;
95 
96  /* BSD name hashing starts i=0, discarding first char. why? */
97  while (*s)
98  sum += (size_t)*s++ * i++;
99 
100  return RT_DBHASH(sum);
101 }
102 
103 
104 int
105 db_dircheck(struct db_i *dbip,
106  struct bu_vls *ret_name,
107  int noisy,
108  struct directory ***headp)
109 {
110  struct directory *dp;
111  char *cp = bu_vls_addr(ret_name);
112  char n0 = cp[0];
113  char n1 = cp[1];
114 
115  /* Compute hash only once (almost always the case) */
116  *headp = &(dbip->dbi_Head[db_dirhash(cp)]);
117 
118  for (dp = **headp; dp != RT_DIR_NULL; dp=dp->d_forw) {
119  char *this_obj;
120  if (n0 == *(this_obj=dp->d_namep) && /* speed */
121  n1 == this_obj[1] && /* speed */
122  BU_STR_EQUAL(cp, this_obj)) {
123  /* Name exists in directory already */
124  int c;
125 
126  bu_vls_strcpy(ret_name, "A_");
127  bu_vls_strcat(ret_name, this_obj);
128 
129  for (c = 'A'; c <= 'Z'; c++) {
130  *cp = c;
131  if (db_lookup(dbip, cp, noisy) == RT_DIR_NULL)
132  break;
133  }
134  if (c > 'Z') {
135  bu_log("db_dircheck: Duplicate of name '%s', ignored\n",
136  cp);
137  return -1; /* fail */
138  }
139  bu_log("db_dircheck: Duplicate of '%s', given temporary name '%s'\n",
140  cp+2, cp);
141 
142  /* no need to recurse, simply recompute the hash and break */
143  *headp = &(dbip->dbi_Head[db_dirhash(cp)]);
144  break;
145  }
146  }
147 
148  return 0; /* success */
149 }
150 
151 
152 struct directory *
153 db_lookup(const struct db_i *dbip, const char *name, int noisy)
154 {
155  struct directory *dp;
156  char n0;
157  char n1;
158 
159  if (!name || name[0] == '\0') {
160  if (noisy || RT_G_DEBUG&DEBUG_DB)
161  bu_log("db_lookup received NULL or empty name\n");
162  return RT_DIR_NULL;
163  }
164 
165  n0 = name[0];
166  n1 = name[1];
167 
168  RT_CK_DBI(dbip);
169 
170  dp = dbip->dbi_Head[db_dirhash(name)];
171  for (; dp != RT_DIR_NULL; dp=dp->d_forw) {
172  char *this_obj;
173 
174  /* first two checks are for speed */
175  if ((n0 == *(this_obj=dp->d_namep)) && (n1 == this_obj[1]) && (BU_STR_EQUAL(name, this_obj))) {
176  if (RT_G_DEBUG&DEBUG_DB)
177  bu_log("db_lookup(%s) %p\n", name, (void *)dp);
178  return dp;
179  }
180  }
181 
182  if (noisy || RT_G_DEBUG&DEBUG_DB)
183  bu_log("db_lookup(%s) failed: %s does not exist\n", name, name);
184 
185  return RT_DIR_NULL;
186 }
187 
188 
189 struct directory *
190 db_diradd(struct db_i *dbip, const char *name, off_t laddr, size_t len, int flags, void *ptr)
191 {
192  struct directory **headp;
193  struct directory *dp;
194  const char *tmp_ptr;
195  struct bu_vls local = BU_VLS_INIT_ZERO;
196 
197  RT_CK_DBI(dbip);
198 
199  if (RT_G_DEBUG&DEBUG_DB) {
200  bu_log("db_diradd(dbip=%p, name='%s', addr=%ld, len=%zu, flags=0x%x, ptr=%p)\n",
201  (void *)dbip, name, laddr, len, flags, ptr);
202  }
203 
204  if ((tmp_ptr = strchr(name, '/')) != NULL) {
205  /* if this is a version 4 database and the offending char is beyond NAMESIZE
206  * then it is not really a problem
207  */
208  if (db_version(dbip) < 5 && (tmp_ptr - name) < NAMESIZE) {
209  bu_log("db_diradd() object named '%s' is illegal, ignored\n", name);
210  return RT_DIR_NULL;
211  }
212  }
213 
214  if (db_version(dbip) < 5) {
215  bu_vls_strncpy(&local, name, NAMESIZE);
216  } else {
217  /* must provide a valid minor type */
218  if (!ptr) {
219  bu_log("WARNING: db_diradd() called with a null minor type pointer for object %s\nIgnoring %s\n", name, name);
220  bu_vls_free(&local);
221  return RT_DIR_NULL;
222  }
223  bu_vls_strcpy(&local, name);
224  }
225  if (db_dircheck(dbip, &local, 0, &headp) < 0) {
226  bu_vls_free(&local);
227  return RT_DIR_NULL;
228  }
229 
230  /* 'name' not found in directory, add it */
232  RT_CK_DIR(dp);
233  RT_DIR_SET_NAMEP(dp, bu_vls_addr(&local)); /* sets d_namep */
234  dp->d_addr = laddr;
235  dp->d_flags = flags & ~(RT_DIR_INMEM);
236  dp->d_len = len;
237  dp->d_forw = *headp;
238  BU_LIST_INIT(&dp->d_use_hd);
239  *headp = dp;
240  dp->d_animate = NULL;
241  dp->d_nref = 0;
242  dp->d_uses = 0;
243 
244  /* v4 geometry databases do not use d_major/minor_type */
245  if (db_version(dbip) > 4) {
246  dp->d_major_type = DB5_MAJORTYPE_BRLCAD;
247  if (ptr)
248  dp->d_minor_type = *(unsigned char *)ptr;
249  else
250  dp->d_minor_type = 0;
251  } else {
252  dp->d_major_type = 0;
253  dp->d_minor_type = 0;
254  }
255 
256  bu_vls_free(&local);
257  return dp;
258 }
259 
260 
261 int
262 db_dirdelete(struct db_i *dbip, struct directory *dp)
263 {
264  struct directory *findp;
265  struct directory **headp;
266 
267  RT_CK_DBI(dbip);
268  RT_CK_DIR(dp);
269 
270  headp = &(dbip->dbi_Head[db_dirhash(dp->d_namep)]);
271 
272  if (dp->d_flags & RT_DIR_INMEM) {
273  if (dp->d_un.ptr != NULL)
274  bu_free(dp->d_un.ptr, "db_dirdelete() inmem ptr");
275  }
276 
277  if (*headp == dp) {
278  RT_DIR_FREE_NAMEP(dp); /* frees d_namep */
279  *headp = dp->d_forw;
280 
281  /* Put 'dp' back on the freelist */
284  return 0;
285  }
286  for (findp = *headp; findp != RT_DIR_NULL; findp = findp->d_forw) {
287  if (findp->d_forw != dp)
288  continue;
289  RT_DIR_FREE_NAMEP(dp); /* frees d_namep */
290  findp->d_forw = dp->d_forw;
291 
292  /* Put 'dp' back on the freelist */
295  return 0;
296  }
297  return -1;
298 }
299 
300 
301 int
302 db_rename(struct db_i *dbip, struct directory *dp, const char *newname)
303 {
304  struct directory *findp;
305  struct directory **headp;
306 
307  RT_CK_DBI(dbip);
308  RT_CK_DIR(dp);
309 
310  /* Remove from linked list */
311  headp = &(dbip->dbi_Head[db_dirhash(dp->d_namep)]);
312  if (*headp == dp) {
313  /* Was first on list, dequeue */
314  *headp = dp->d_forw;
315  } else {
316  for (findp = *headp; findp != RT_DIR_NULL; findp = findp->d_forw) {
317  if (findp->d_forw != dp)
318  continue;
319  /* Dequeue */
320  findp->d_forw = dp->d_forw;
321  goto out;
322  }
323  return -1; /* ERROR: can't find */
324  }
325 
326 out:
327  /* Effect new name */
328  RT_DIR_FREE_NAMEP(dp); /* frees d_namep */
329  RT_DIR_SET_NAMEP(dp, newname); /* sets d_namep */
330 
331  /* Add to new linked list */
332  headp = &(dbip->dbi_Head[db_dirhash(newname)]);
333  dp->d_forw = *headp;
334  *headp = dp;
335  return 0;
336 }
337 
338 
339 void
340 db_pr_dir(const struct db_i *dbip)
341 {
342  const struct directory *dp;
343  char *flags;
344  int i;
345 
346  RT_CK_DBI(dbip);
347 
348  bu_log("db_pr_dir(%p): Dump of directory for file %s [%s]\n",
349  (void *)dbip, dbip->dbi_filename,
350  dbip->dbi_read_only ? "READ-ONLY" : "Read/Write");
351 
352  bu_log("Title = %s\n", dbip->dbi_title);
353  /* units ? */
354 
355  for (i = 0; i < RT_DBNHASH; i++) {
356  for (dp = dbip->dbi_Head[i]; dp != RT_DIR_NULL; dp=dp->d_forw) {
357  if (dp->d_flags & RT_DIR_SOLID)
358  flags = "SOL";
359  else if ((dp->d_flags & (RT_DIR_COMB|RT_DIR_REGION)) ==
361  flags = "REG";
362  else if ((dp->d_flags & (RT_DIR_COMB|RT_DIR_REGION)) ==
363  RT_DIR_COMB)
364  flags = "COM";
365  else
366  flags = "Bad";
367  bu_log("%p %s %s=%ld len=%.5ld use=%.2ld nref=%.2ld %s",
368  (void *)dp,
369  flags,
370  dp->d_flags & RT_DIR_INMEM ? " ptr " : "d_addr",
371  dp->d_addr,
372  dp->d_len,
373  dp->d_uses,
374  dp->d_nref,
375  dp->d_namep);
376  if (dp->d_animate)
377  bu_log(" anim=%p\n", (void *)dp->d_animate);
378  else
379  bu_log("\n");
380  }
381  }
382 }
383 
384 
385 struct bu_ptbl *
386 db_lookup_by_attr(struct db_i *dbip, int dir_flags, struct bu_attribute_value_set *avs, int op)
387 {
388  struct bu_attribute_value_set obj_avs;
389  struct directory *dp;
390  struct bu_ptbl *tbl;
391  int match_count = 0;
392  int attr_count;
393  int i, j;
394  int draw;
395 
396  RT_CK_DBI(dbip);
397 
398  if (avs) {
399  BU_CK_AVS(avs);
400  attr_count = avs->count;
401  } else {
402  attr_count = 0;
403  }
404 
405  BU_ALLOC(tbl, struct bu_ptbl);
406  bu_ptbl_init(tbl, 128, "wdb_get_by_attr ptbl_init");
407 
408  FOR_ALL_DIRECTORY_START(dp, dbip) {
409 
410  if ((dp->d_flags & dir_flags) == 0) continue;
411 
412  /* Skip phony entries */
413  if (dp->d_addr == RT_DIR_PHONY_ADDR) continue;
414 
415  if (attr_count) {
416  bu_avs_init_empty(&obj_avs);
417  if (db5_get_attributes(dbip, &obj_avs, dp) < 0) {
418  bu_log("ERROR: failed to get attributes for %s\n", dp->d_namep);
419  return (struct bu_ptbl *)NULL;
420  }
421 
422  draw = 0;
423  match_count = 0;
424  for (i = 0; (size_t)i < (size_t)avs->count; i++) {
425  for (j = 0; (size_t)j < (size_t)obj_avs.count; j++) {
426  if (BU_STR_EQUAL(avs->avp[i].name, obj_avs.avp[j].name)) {
427  if (BU_STR_EQUAL(avs->avp[i].value, obj_avs.avp[j].value)) {
428  if (op == 2) {
429  draw = 1;
430  break;
431  } else {
432  match_count++;
433  }
434  }
435  }
436  }
437  if (draw) break;
438  }
439 
440  bu_avs_free(&obj_avs);
441  } else {
442  draw = 1;
443  }
444  if (draw || match_count == attr_count) {
445  bu_ptbl_ins(tbl, (long *)dp);
446  }
448 
449  return tbl;
450 }
451 
452 /** @} */
453 /*
454  * Local Variables:
455  * mode: C
456  * tab-width: 8
457  * indent-tabs-mode: t
458  * c-file-style: "stroustrup"
459  * End:
460  * ex: shiftwidth=4 tabstop=8
461  */
char * d_namep
pointer to name string
Definition: raytrace.h:859
Definition: raytrace.h:800
#define FOR_ALL_DIRECTORY_START(_dp, _dbip)
Definition: raytrace.h:895
unsigned char d_major_type
object major type
Definition: raytrace.h:870
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
int db_is_directory_non_empty(const struct db_i *dbip)
Definition: db_lookup.c:39
int db_dircheck(struct db_i *dbip, struct bu_vls *ret_name, int noisy, struct directory ***headp)
Definition: db_lookup.c:105
#define RT_DBNHASH
hash table is an array of linked lists with this many array pointer elements (Memory use for 32-bit: ...
Definition: raytrace.h:755
#define RT_GET_DIRECTORY(_p, _res)
Definition: raytrace.h:924
#define RT_DIR_SET_NAMEP(_dp, _name)
Definition: raytrace.h:901
void bu_avs_init_empty(struct bu_attribute_value_set *avp)
Definition: avs.c:36
#define RT_DIR_FREE_NAMEP(_dp)
Definition: raytrace.h:914
size_t d_len
of db granules used
Definition: raytrace.h:867
#define RT_DIR_INMEM
object is in memory (only)
Definition: raytrace.h:889
long d_nref
times ref'ed by COMBs
Definition: raytrace.h:868
#define RT_DBHASH(sum)
Definition: raytrace.h:778
if lu s
Definition: nmg_mod.c:3860
Definition: clone.c:90
void bu_ptbl_init(struct bu_ptbl *b, size_t len, const char *str)
Definition: ptbl.c:32
void bu_vls_strcat(struct bu_vls *vp, const char *s)
Definition: vls.c:368
long d_uses
uses, from instancing
Definition: raytrace.h:866
int db_version(struct db_i *dbip)
Definition: db5_scan.c:414
size_t db_directory_size(const struct db_i *dbip)
Definition: db_lookup.c:54
void bu_vls_strncpy(struct bu_vls *vp, const char *s, size_t n)
Definition: vls.c:339
#define FOR_ALL_DIRECTORY_END
Definition: raytrace.h:899
Header file for the BRL-CAD common definitions.
const char * value
Definition: avs.h:62
#define RT_DIR_REGION
region
Definition: raytrace.h:885
int bu_ptbl_ins(struct bu_ptbl *b, long *p)
struct directory * d_forw
link to next dir entry
Definition: raytrace.h:864
Definition: ptbl.h:62
char * strchr(const char *sp, int c)
void bu_vls_free(struct bu_vls *vp)
Definition: vls.c:248
unsigned char d_minor_type
object minor type
Definition: raytrace.h:871
struct bu_ptbl * db_lookup_by_attr(struct db_i *dbip, int dir_flags, struct bu_attribute_value_set *avs, int op)
Definition: db_lookup.c:386
struct resource rt_uniresource
default. Defined in librt/globals.c
Definition: globals.c:41
#define RT_G_DEBUG
Definition: raytrace.h:1718
char * dbi_title
title from IDENT rec
Definition: raytrace.h:809
struct bu_attribute_value_pair * avp
Definition: avs.h:89
#define BU_ALLOC(_ptr, _type)
Definition: malloc.h:223
#define RT_CK_DIR(_dp)
Definition: raytrace.h:876
#define RT_DIR_SOLID
this name is a solid
Definition: raytrace.h:883
struct directory * db_lookup(const struct db_i *dbip, const char *name, int noisy)
Definition: db_lookup.c:153
#define RT_DIR_PHONY_ADDR
Special marker for d_addr field.
Definition: raytrace.h:879
goto out
Definition: nmg_mod.c:3846
char * bu_vls_addr(const struct bu_vls *vp)
Definition: vls.c:111
struct bu_list d_use_hd
heads list of uses (struct soltab l2)
Definition: raytrace.h:872
#define RT_CK_DBI(_p)
Definition: raytrace.h:829
int dbi_read_only
!0 => read only file
Definition: raytrace.h:806
union directory::@8 d_un
int db_dirhash(const char *str)
Definition: db_lookup.c:86
void db_ck_directory(const struct db_i *dbip)
Definition: db_lookup.c:71
#define BU_LIST_INIT(_hp)
Definition: list.h:148
#define RT_DIR_COMB
combination
Definition: raytrace.h:884
struct directory * dbi_Head[RT_DBNHASH]
Definition: raytrace.h:814
#define DEBUG_DB
5 Database debugging
Definition: raytrace.h:88
struct directory * re_directory_hd
Definition: raytrace.h:1481
int db_dirdelete(struct db_i *dbip, struct directory *dp)
Definition: db_lookup.c:262
#define RT_DIR_NULL
Definition: raytrace.h:875
void * ptr
ptr to in-memory-only obj
Definition: raytrace.h:862
struct animate * d_animate
link to animation
Definition: raytrace.h:865
void bu_vls_strcpy(struct bu_vls *vp, const char *s)
Definition: vls.c:310
const char * name
Definition: avs.h:61
void bu_free(void *ptr, const char *str)
Definition: malloc.c:328
struct directory * db_diradd(struct db_i *dbip, const char *name, off_t laddr, size_t len, int flags, void *ptr)
Definition: db_lookup.c:190
int db_rename(struct db_i *dbip, struct directory *dp, const char *newname)
Definition: db_lookup.c:302
#define BU_VLS_INIT_ZERO
Definition: vls.h:84
int db5_get_attributes(const struct db_i *dbip, struct bu_attribute_value_set *avs, const struct directory *dp)
Definition: db5_io.c:1027
int d_flags
flags
Definition: raytrace.h:869
Definition: vls.h:56
char * dbi_filename
file name
Definition: raytrace.h:805
#define BU_CK_AVS(_ap)
Definition: avs.h:97
void db_pr_dir(const struct db_i *dbip)
Definition: db_lookup.c:340
void bu_avs_free(struct bu_attribute_value_set *avp)
Definition: avs.c:235
#define BU_STR_EQUAL(s1, s2)
Definition: str.h:126