BRL-CAD
killtree.c
Go to the documentation of this file.
1 /* K I L L T R E E . C
2  * BRL-CAD
3  *
4  * Copyright (c) 2008-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 /** @file libged/killtree.c
21  *
22  * The killtree command.
23  *
24  */
25 
26 #include "common.h"
27 
28 #include <string.h>
29 
30 #include "bu/cmd.h"
31 #include "bu/getopt.h"
32 
33 #include "./ged_private.h"
34 
35 
36 #define AV_STEP 4096
37 
38 
39 struct killtree_data {
40  struct ged *gedp;
41  int killrefs;
42  int print;
43  int force;
44  const char *top;
45  int ac;
46  char **av;
47  size_t av_capacity;
48 };
49 
50 
51 /* this finds references to 'obj' that are not within the 'topobj'
52  * combination hierarchy, elsewhere in the database. this is so we
53  * can make sure we don't kill objects that are referenced somewhere
54  * else in the database.
55  */
56 HIDDEN int
57 find_reference(struct db_i *dbip, const char *topobj, const char *obj)
58 {
59  int ret;
60  struct bu_vls str = BU_VLS_INIT_ZERO;
61 
62  if (!dbip || !topobj || !obj)
63  return 0;
64 
65  /* FIXME: these should be wrapped in quotes, but need to dewrap
66  * after bu_argv_from_string().
67  */
68  bu_vls_printf(&str, "-not -below -name %s -name %s", topobj, obj);
69 
70  ret = db_search(NULL, DB_SEARCH_TREE, bu_vls_cstr(&str), 0, NULL, dbip);
71 
72  bu_vls_free(&str);
73 
74  return ret;
75 }
76 
77 
78 HIDDEN void
79 killtree_callback(struct db_i *dbip, struct directory *dp, void *ptr)
80 {
81  struct killtree_data *gktdp = (struct killtree_data *)ptr;
82  int ref_exists = 0;
83 
84  if (dbip == DBI_NULL)
85  return;
86 
87  /* don't bother checking for references if the -f or -a flags are
88  * presented to force a full kill and all references respectively.
89  */
90  if (!gktdp->force && !gktdp->killrefs)
91  ref_exists = find_reference(dbip, gktdp->top, dp->d_namep);
92 
93  /* if a reference exists outside of the subtree we're killing, we
94  * don't kill this object or it'll create invalid reference
95  * elsewhere in the database. do nothing.
96  */
97  if (ref_exists)
98  return;
99 
100  if (gktdp->print) {
101  if (!gktdp->killrefs)
102  bu_vls_printf(gktdp->gedp->ged_result_str, "%s ", dp->d_namep);
103  else {
104  if ((size_t)(gktdp->ac + 2) >= gktdp->av_capacity) {
105  gktdp->av = (char **)bu_realloc(gktdp->av, sizeof(char *) * (gktdp->av_capacity + AV_STEP), "realloc av");
106  gktdp->av_capacity += AV_STEP;
107  }
108  gktdp->av[gktdp->ac++] = bu_strdup(dp->d_namep);
109  gktdp->av[gktdp->ac] = (char *)0;
110 
111  bu_vls_printf(gktdp->gedp->ged_result_str, "%s ", dp->d_namep);
112  }
113  } else {
115 
116  bu_vls_printf(gktdp->gedp->ged_result_str, "KILL %s: %s\n",
117  (dp->d_flags & RT_DIR_COMB) ? "COMB" : "Solid",
118  dp->d_namep);
119 
120  if (!gktdp->killrefs) {
121  if (db_delete(dbip, dp) != 0 || db_dirdelete(dbip, dp) != 0) {
122  bu_vls_printf(gktdp->gedp->ged_result_str, "an error occurred while deleting %s\n", dp->d_namep);
123  }
124  } else {
125  if ((size_t)(gktdp->ac + 2) >= gktdp->av_capacity) {
126  gktdp->av = (char **)bu_realloc(gktdp->av, sizeof(char *) * (gktdp->av_capacity + AV_STEP), "realloc av");
127  gktdp->av_capacity += AV_STEP;
128  }
129  gktdp->av[gktdp->ac++] = bu_strdup(dp->d_namep);
130  gktdp->av[gktdp->ac] = (char *)0;
131 
132  if (db_delete(dbip, dp) != 0 || db_dirdelete(dbip, dp) != 0) {
133  bu_vls_printf(gktdp->gedp->ged_result_str, "an error occurred while deleting %s\n", dp->d_namep);
134 
135  /* Remove from list */
136  bu_free((void *)gktdp->av[--gktdp->ac], "killtree_callback");
137  gktdp->av[gktdp->ac] = (char *)0;
138  }
139  }
140  }
141 }
142 
143 
144 int
145 ged_killtree(struct ged *gedp, int argc, const char *argv[])
146 {
147  struct directory *dp;
148  int i;
149  int c;
150  struct killtree_data gktd;
151  static const char *usage = "[-a|-f|-n] object(s)";
152 
155  GED_CHECK_ARGC_GT_0(gedp, argc, GED_ERROR);
156 
157  /* initialize result */
158  bu_vls_trunc(gedp->ged_result_str, 0);
159 
160  /* must be wanting help */
161  if (argc == 1) {
162  bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage);
163  return GED_HELP;
164  }
165 
166  gktd.gedp = gedp;
167  gktd.killrefs = 0;
168  gktd.print = 0;
169  gktd.force = 0;
170  gktd.ac = 1;
171  gktd.top = NULL;
172 
173  gktd.av = (char **)bu_calloc(1, sizeof(char *) * AV_STEP, "alloc av");
174  gktd.av_capacity = AV_STEP;
175  BU_ASSERT(gktd.ac + argc + 2 < AV_STEP); /* potential -n opts */
176  gktd.av[0] = "killrefs";
177  gktd.av[1] = (char *)0;
178 
179  bu_optind = 1;
180  while ((c = bu_getopt(argc, (char * const *)argv, "afn")) != -1) {
181  switch (c) {
182  case 'a':
183  gktd.killrefs = 1;
184  break;
185  case 'n':
186  gktd.print = 1;
187  gktd.av[gktd.ac++] = bu_strdup("-n");
188  gktd.av[gktd.ac] = (char *)0;
189  break;
190  case 'f':
191  gktd.force = 1;
192  break;
193  default:
194  bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage);
195  bu_free(gktd.av, "free av (error)");
196  gktd.av = NULL;
197  return GED_ERROR;
198  }
199  }
200 
201  argc -= (bu_optind - 1);
202  argv += (bu_optind - 1);
203 
204  /* Objects that would be killed are in the first sublist */
205  if (gktd.print)
206  bu_vls_printf(gedp->ged_result_str, "{");
207 
208  for (i = 1; i < argc; i++) {
209  if ((dp = db_lookup(gedp->ged_wdbp->dbip, argv[i], LOOKUP_NOISY)) == RT_DIR_NULL)
210  continue;
211 
212  /* ignore phony objects */
213  if (dp->d_addr == RT_DIR_PHONY_ADDR)
214  continue;
215 
216  /* stash the what's killed so we can find refs elsewhere */
217  gktd.top = argv[i];
218 
219  db_functree(gedp->ged_wdbp->dbip, dp,
221  gedp->ged_wdbp->wdb_resp, (void *)&gktd);
222  }
223 
224  /* Close the sublist of would-be killed objects. Also open the
225  * sublist of objects that reference the would-be killed objects.
226  */
227  if (gktd.print)
228  bu_vls_printf(gedp->ged_result_str, "} {");
229 
230  if (gktd.killrefs && gktd.ac > 1) {
231  gedp->ged_internal_call = 1;
232  (void)ged_killrefs(gedp, gktd.ac, (const char **)gktd.av);
233  gedp->ged_internal_call = 0;
234 
235  for (i = 1; i < gktd.ac; i++) {
236  if (!gktd.print)
237  bu_vls_printf(gedp->ged_result_str, "Freeing %s\n", gktd.av[i]);
238  bu_free((void *)gktd.av[i], "killtree_data");
239  gktd.av[i] = NULL;
240  }
241  }
242 
243  if (gktd.print)
244  bu_vls_printf(gedp->ged_result_str, "}");
245 
246  bu_free(gktd.av, "free av");
247  gktd.av = NULL;
248 
249  return GED_OK;
250 }
251 
252 
253 /*
254  * Local Variables:
255  * tab-width: 8
256  * mode: C
257  * indent-tabs-mode: t
258  * c-file-style: "stroustrup"
259  * End:
260  * ex: shiftwidth=4 tabstop=8
261  */
void usage(struct ged *gedp)
Definition: coil.c:315
#define GED_OK
Definition: ged.h:55
char * d_namep
pointer to name string
Definition: raytrace.h:859
Definition: raytrace.h:800
int db_dirdelete(struct db_i *, struct directory *dp)
Definition: db_lookup.c:262
Definition: ged.h:338
int killrefs
Definition: killtree.c:41
struct db_i * dbip
Definition: raytrace.h:1266
int ged_internal_call
Definition: ged.h:374
void bu_vls_trunc(struct bu_vls *vp, int len)
Definition: vls.c:198
#define GED_CHECK_ARGC_GT_0(_gedp, _argc, _flags)
Definition: ged.h:202
struct directory * db_lookup(const struct db_i *, const char *name, int noisy)
Definition: db_lookup.c:153
int ged_killtree(struct ged *gedp, int argc, const char *argv[])
Definition: killtree.c:145
size_t av_capacity
Definition: killtree.c:47
struct rt_wdb * ged_wdbp
Definition: ged.h:340
Header file for the BRL-CAD common definitions.
int bu_optind
Definition: globals.c:89
void(* ged_free_vlist_callback)(unsigned int, int)
function to call after freeing a vlist
Definition: ged.h:371
#define BU_ASSERT(_equation)
Definition: defines.h:216
int bu_getopt(int nargc, char *const nargv[], const char *ostr)
Definition: getopt.c:43
struct bu_list * gd_headDisplay
head of display list
Definition: ged.h:307
#define GED_ERROR
Definition: ged.h:61
#define HIDDEN
Definition: common.h:86
#define DB_SEARCH_TREE
Do a hierarchy-aware search. This is the default.
Definition: search.h:110
struct solid * freesolid
Definition: ged.h:345
void bu_vls_free(struct bu_vls *vp)
Definition: vls.c:248
#define GED_CHECK_DATABASE_OPEN(_gedp, _flags)
Definition: ged.h:114
void _dl_eraseAllNamesFromDisplay(struct bu_list *hdlp, struct db_i *dbip, void(*callback)(unsigned int, int), const char *name, const int skip_first, struct solid *freesolid)
Definition: display_list.c:332
void * bu_calloc(size_t nelem, size_t elsize, const char *str)
Definition: malloc.c:321
#define AV_STEP
Definition: killtree.c:36
struct ged * gedp
Definition: killtree.c:40
#define RT_DIR_PHONY_ADDR
Special marker for d_addr field.
Definition: raytrace.h:879
void * bu_realloc(void *ptr, size_t siz, const char *str)
const char * bu_vls_cstr(const struct bu_vls *vp)
Definition: vls.c:103
struct bu_vls * ged_result_str
Definition: ged.h:357
struct ged_drawable * ged_gdp
Definition: ged.h:360
char ** av
Definition: killtree.c:46
HIDDEN void killtree_callback(struct db_i *dbip, struct directory *dp, void *ptr)
Definition: killtree.c:79
#define RT_DIR_COMB
combination
Definition: raytrace.h:884
const char * top
Definition: killtree.c:44
#define DBI_NULL
Definition: raytrace.h:827
void bu_vls_printf(struct bu_vls *vls, const char *fmt,...) _BU_ATTR_PRINTF23
Definition: vls.c:694
#define RT_DIR_NULL
Definition: raytrace.h:875
#define LOOKUP_NOISY
Definition: raytrace.h:892
int ged_killrefs(struct ged *gedp, int argc, const char *argv[])
Definition: killrefs.c:36
#define GED_HELP
Definition: ged.h:62
void db_functree(struct db_i *dbip, struct directory *dp, void(*comb_func)(struct db_i *, struct directory *, void *), void(*leaf_func)(struct db_i *, struct directory *, void *), struct resource *resp, void *client_data)
Definition: db_walk.c:199
struct resource * wdb_resp
Definition: raytrace.h:1270
void bu_free(void *ptr, const char *str)
Definition: malloc.c:328
#define BU_VLS_INIT_ZERO
Definition: vls.h:84
#define GED_CHECK_READ_ONLY(_gedp, _flags)
Definition: ged.h:181
int d_flags
flags
Definition: raytrace.h:869
Definition: vls.h:56
int db_delete(struct db_i *, struct directory *dp)
Definition: db_alloc.c:132
HIDDEN int find_reference(struct db_i *dbip, const char *topobj, const char *obj)
Definition: killtree.c:57
#define bu_strdup(s)
Definition: str.h:71
int db_search(struct bu_ptbl *results, int flags, const char *filter, int path_c, struct directory **path_v, struct db_i *dbip)
Search for objects in a geometry database using filters.
Definition: search.c:2232