Revision: 66509
          http://sourceforge.net/p/brlcad/code/66509
Author:   starseeker
Date:     2015-10-26 18:59:38 +0000 (Mon, 26 Oct 2015)
Log Message:
-----------
Start of rework of rm command - rather than calling killtree et. al. under the 
hood, use search and implement a consolidated version of all the kill commands. 
 Needs extensive testing and some thought on desired behavior.

Modified Paths:
--------------
    brlcad/trunk/src/libged/remove.c

Modified: brlcad/trunk/src/libged/remove.c
===================================================================
--- brlcad/trunk/src/libged/remove.c    2015-10-26 18:55:31 UTC (rev 66508)
+++ brlcad/trunk/src/libged/remove.c    2015-10-26 18:59:38 UTC (rev 66509)
@@ -26,6 +26,7 @@
 #include "common.h"
 
 #include <string.h>
+#include <limits.h> /* FOR INT_MAX */
 
 #include "bu/cmd.h"
 #include "bu/opt.h"
@@ -39,23 +40,185 @@
 {
     struct bu_vls str = BU_VLS_INIT_ZERO;
     const char *option_help = bu_opt_describe(d, NULL);
-    bu_vls_sprintf(&str, "Usage: %s [options] [comb] object(s)\n", cmd);
-    bu_vls_printf(&str, "By default, if no options are supplied and the first 
object is a comb\n", cmd);
-    bu_vls_printf(&str, "the object(s) are removed from the comb 
definition.\n\n", cmd);
-    bu_vls_printf(&str, "If -f is supplied, the command form becomes:\n", cmd);
-    bu_vls_printf(&str, "       %s [options] object(s)\n", cmd);
-    bu_vls_printf(&str, "and all objects are moved from the .g database.\n", 
cmd);
-    bu_vls_printf(&str, "The -r option implies -f and will recursively walk 
combs\n", cmd);
-    bu_vls_printf(&str, "rather than deleting them.\n", cmd);
+    bu_vls_sprintf(&str, "Usage: %s [options] [comb] [comb/obj] 
object(s)\n\n", cmd);
+    bu_vls_printf(&str, "Any argument of the form comb/obj is interpreted as 
requesting removal of\n");
+    bu_vls_printf(&str, "object \"obj\" from the first level tree of \"comb\" 
(instances of obj\n");
+    bu_vls_printf(&str, "deeper in the tree of \"comb\" are not removed.)  
Note that these paths\n");
+    bu_vls_printf(&str, "are processed first - any other rm operations will 
take place after these\n");
+    bu_vls_printf(&str, "paths are handled.\n\n");
+    bu_vls_printf(&str, "By default, if no options are supplied and the first 
object is a comb\n");
+    bu_vls_printf(&str, "the object(s) are removed from \"comb\" - this is a 
convenient way to\n");
+    bu_vls_printf(&str, "remove multiple objects from a single comb.  Again, 
instances are.\n");
+    bu_vls_printf(&str, "removed only from the immediate child object set of 
\"comb\".\n\n");
+    bu_vls_printf(&str, "If one or more options are supplied or the first 
object specified is not a comb,\n");
+    bu_vls_printf(&str, "the command form becomes:\n\n");
+    bu_vls_printf(&str, "       %s [options] object(s)\n\n", cmd);
+    bu_vls_printf(&str, "and the scope changes from a single comb's tree to 
the .g database.\n");
     if (option_help) {
-       bu_vls_printf(&str, "Options:\n%s\n", option_help);
+       bu_vls_printf(&str, "\nOptions:\n%s\n", option_help);
        bu_free((char *)option_help, "help str");
     }
     bu_vls_printf(gedp->ged_result_str, "%s", bu_vls_addr(&str));
     bu_vls_free(&str);
 }
 
+/* this finds references to 'obj' that are not within any of the the 'topobjs'
+ * combination hierarchies, elsewhere in the database.  this is so we can make
+ * sure we don't kill objects that are referenced elsewhere in the
+ * database, in a hierarchy that is not being deleted.
+ */
 HIDDEN int
+_rm_find_reference(struct db_i *dbip, struct bu_ptbl *topobjs, const char 
*obj, struct bu_vls *rmlog, int verbosity)
+{
+    int i;
+    int ret = 0;
+    struct bu_vls str = BU_VLS_INIT_ZERO;
+
+    if (!dbip || !topobjs || !obj)
+       return 0;
+
+    bu_vls_sprintf(&str, "-depth >0");
+    for (i = 0; i < (int)BU_PTBL_LEN(topobjs); i++) {
+       bu_vls_printf(&str, " -not -below -name %s", (const char 
*)BU_PTBL_GET(topobjs, i));
+    }
+    bu_vls_printf(&str, " -name %s", obj);
+
+    ret = db_search(NULL, DB_SEARCH_TREE, bu_vls_cstr(&str), 0, NULL, dbip);
+
+    if (ret && rmlog && verbosity > 0) {
+       bu_vls_printf(rmlog, "NOTE: %s is referenced by unremoved objects in 
the database - skipping.\n", obj);
+    }
+
+    bu_vls_free(&str);
+
+    return ret;
+}
+
+HIDDEN void
+_rm_ref(struct ged *gedp, struct bu_ptbl *objs, struct bu_vls *rmlog, int 
dry_run)
+{
+    size_t i = 0;
+    struct directory *dp = RT_DIR_NULL;
+    struct rt_db_internal intern;
+    struct rt_comb_internal *comb;
+
+    FOR_ALL_DIRECTORY_START(dp, gedp->ged_wdbp->dbip) {
+       if (!(dp->d_flags & RT_DIR_COMB))
+           continue;
+
+       if (rt_db_get_internal(&intern, dp, gedp->ged_wdbp->dbip, (fastf_t 
*)NULL, &rt_uniresource) < 0) {
+           if (rmlog) {
+               bu_vls_printf(rmlog, "rt_db_get_internal(%s) failure", 
dp->d_namep);
+           }
+           continue;
+       }
+       comb = (struct rt_comb_internal *)intern.idb_ptr;
+       RT_CK_COMB(comb);
+
+       for (i = 0; i < BU_PTBL_LEN(objs); i++) {
+           int code;
+
+           code = db_tree_del_dbleaf(&(comb->tree), (const char 
*)BU_PTBL_GET(objs, i), &rt_uniresource, dry_run);
+           if (code == -1)
+               continue;       /* not found */
+           if (code == -2)
+               continue;       /* empty tree */
+           if (code < 0) {
+               if (rmlog) {
+                   bu_vls_printf(rmlog, "ERROR: Failure deleting %s/%s\n", 
dp->d_namep, (const char *)BU_PTBL_GET(objs, i));
+               }
+           } else {
+               if (rmlog && dry_run) {
+                   bu_vls_printf(rmlog, "Remove reference to object %s from 
%s", (const char *)BU_PTBL_GET(objs, i), dp->d_namep);
+               }
+           }
+       }
+
+       if (!dry_run && rt_db_put_internal(dp, gedp->ged_wdbp->dbip, &intern, 
&rt_uniresource) < 0) {
+           if (rmlog) {
+               bu_vls_printf(rmlog, "ERROR: Unable to write new combination 
into database.\n");
+           }
+           continue;
+       }
+    } FOR_ALL_DIRECTORY_END;
+}
+
+HIDDEN int
+_rm_obj(struct ged *gedp, const char *objname, struct bu_ptbl *topobjs, struct 
bu_vls *rmlog, int verbosity, int force, int dry_run)
+{
+    struct directory *dp = RT_DIR_NULL;
+    if (!gedp || !objname) return -1;
+
+    if (topobjs && !force) {
+       if (_rm_find_reference(gedp->ged_wdbp->dbip, topobjs, objname, rmlog, 
verbosity) > 0) return -1;
+    }
+
+    dp = db_lookup(gedp->ged_wdbp->dbip, objname, LOOKUP_QUIET);
+
+    if (dp != RT_DIR_NULL) {
+       if (!force && dp->d_major_type == DB5_MAJORTYPE_ATTRIBUTE_ONLY && 
dp->d_minor_type == 0) {
+           if (rmlog) {
+               bu_vls_printf(rmlog, "Warning: you attempted to delete the 
_GLOBAL object.\n");
+               bu_vls_printf(rmlog, "\tIf you delete the \"_GLOBAL\" object 
you will be losing some important information\n");
+               bu_vls_printf(rmlog, "\tsuch as your preferred units and the 
title of the database.\n");
+               bu_vls_printf(rmlog, "\tUse the \"-f\" option, if you really 
want to do this.\n");
+           }
+           return -1;
+       }
+
+       /* don't worry about phony objects */
+       if (dp->d_addr == RT_DIR_PHONY_ADDR) return 0;
+
+       /* clear the object from the display */
+       if (!dry_run) {
+           _dl_eraseAllNamesFromDisplay(gedp->ged_gdp->gd_headDisplay, 
gedp->ged_wdbp->dbip, gedp->ged_free_vlist_callback, objname, 0, 
gedp->freesolid);
+
+           /* actually do the deletion */
+           if (db_delete(gedp->ged_wdbp->dbip, dp) != 0 || 
db_dirdelete(gedp->ged_wdbp->dbip, dp) != 0) {
+               /* Abort kill processing on first error */
+               if (rmlog) bu_vls_printf(rmlog, "Error: unable to delete %s", 
objname);
+               return -1;
+           }
+       } else {
+           bu_vls_printf(rmlog, "Delete object %s", objname);
+       }
+    } else {
+       if (rmlog && verbosity >= 2) {
+           bu_vls_printf(rmlog, "Attempted to delete object %s, but it was not 
found in the database\n", objname);
+       }
+       return -1;
+    }
+    return 0;
+}
+
+HIDDEN int
+_valid_rm_objs(struct directory ***dirp, struct bu_ptbl *validobjs, struct ged 
*gedp, struct bu_ptbl *objs, struct bu_vls *rmlog, int verbosity)
+{
+    int i = 0;
+    int dircnt = 0;
+    struct directory *rdp = RT_DIR_NULL;
+    for (i = 0; i < (int)BU_PTBL_LEN(objs); i++) {
+       rdp = db_lookup(gedp->ged_wdbp->dbip, (const char *)BU_PTBL_GET(objs, 
i), LOOKUP_QUIET);
+       if (rdp != RT_DIR_NULL) {
+           bu_ptbl_ins_unique(validobjs, (long *)rdp);
+       } else {
+           if (rmlog && verbosity >= 2) {
+               bu_vls_printf(rmlog, "Attempted to delete object %s, but it was 
not found in the database\n", (const char *)BU_PTBL_GET(objs, i));
+           }
+       }
+    }
+    dircnt = BU_PTBL_LEN(validobjs);
+    /* Got valid objects, build search directory array */
+    if (dircnt > 0) {
+       (*dirp) = (struct directory **)bu_calloc(BU_PTBL_LEN(validobjs), 
sizeof(struct directory *), "dp array");
+       for (i = 0; i < (int)BU_PTBL_LEN(validobjs); i++) {
+           (*dirp)[i] = (struct directory *)BU_PTBL_GET(validobjs, i);
+       }
+    }
+    return dircnt;
+}
+
+HIDDEN int
 _ged_rm_path(struct ged *gedp, const char *in)
 {
     int ret = GED_OK;
@@ -90,7 +253,7 @@
 
     comb = (struct rt_comb_internal *)intern.idb_ptr;
     RT_CK_COMB(comb);
-    
+
     if (db_tree_del_dbleaf(&(comb->tree), bu_vls_addr(&obj), &rt_uniresource, 
0) < 0) {
        bu_vls_printf(gedp->ged_result_str, "ERROR: Failure deleting %s/%s\n", 
dp->d_namep, bu_vls_addr(&obj));
        ret = GED_ERROR;
@@ -115,6 +278,30 @@
     return ret;
 }
 
+
+HIDDEN int
+_rm_verbose(struct bu_vls *msg, int argc, const char **argv, void *set_v)
+{
+    int val = INT_MAX;
+    int *int_set = (int *)set_v;
+    int int_ret;
+    if (!argv || !argv[0] || strlen(argv[0]) == 0 || argc == 0) {
+       /* Have verbosity flag but no valid arg - go with just the flag */
+       if (int_set) (*int_set) = 1;
+       return 0;
+    }
+
+    int_ret = bu_opt_int(msg, argc, argv, (void *)&val);
+    if (int_ret == -1) return -1;
+
+    if (val < 0) return -1;
+    if (val > 4) val = 4;
+
+    if (int_set) (*int_set) = val;
+
+    return 1;
+}
+
 int
 ged_remove(struct ged *gedp, int orig_argc, const char *orig_argv[])
 {
@@ -122,7 +309,9 @@
     int remove_force = 0;
     int remove_from_comb = 1;
     int remove_recursive = 0;
-    int remove_force_refs = 0;
+    int remove_refs = 0;
+    int verbose = 0;
+    int no_op = 0;
     size_t argc = (size_t)orig_argc;
     char **argv = bu_dup_argv(argc, orig_argv);
     size_t free_argc = argc;
@@ -134,9 +323,9 @@
     struct rt_db_internal intern;
     struct rt_comb_internal *comb;
     int ret = GED_OK;
-    static const char *usage = "comb object(s)";
-    struct bu_opt_desc d[6];
+    struct bu_opt_desc d[8];
     struct bu_vls str = BU_VLS_INIT_ZERO;
+    struct bu_vls rmlog = BU_VLS_INIT_ZERO;
     struct bu_ptbl objs = BU_PTBL_INIT_ZERO;
 
     GED_CHECK_DATABASE_OPEN(gedp, GED_ERROR);
@@ -146,10 +335,12 @@
 
     BU_OPT(d[0], "h", "help",  "", NULL, (void *)&print_help, "Print help and 
exit");
     BU_OPT(d[1], "?", "",      "", NULL, (void *)&print_help, "");
-    BU_OPT(d[2], "f", "force",  "", NULL, (void *)&remove_force, "Treat combs 
like any other objects.  If recursive, do not verify objects are unused in 
other trees before deleting.");
-    BU_OPT(d[3], "F", "force-refs",  "", NULL, (void *)&remove_force_refs, 
"Like '-f', but will also remove references to removed objects in other parts 
of the database rather than leaving invalid references. Overrides '-f' if both 
are specified");
-    BU_OPT(d[4], "r", "recursive",  "", NULL, (void *)&remove_recursive, "Walk 
combs and delete all of their sub-objects. Will not delete objects used 
elsewhere in the database.");
-    BU_OPT_NULL(d[5]);
+    BU_OPT(d[2], "f", "force",  "", NULL, (void *)&remove_force, "Treat combs 
like any other objects.  If recursive flag is added, do not verify objects are 
unused in other trees before deleting.");
+    BU_OPT(d[3], "a", "references",  "", NULL, (void *)&remove_refs, "Remove 
references to the removed object elsewhere in the database.  When used without 
the force force flag, will *only* remove references to the specificed object or 
objects and not the objects themselves.  When recursive mode is enabled will 
remove all references to all object identifed by the recursion, not just those 
explicitly listed by the user.");
+    BU_OPT(d[4], "r", "recursive",  "", NULL, (void *)&remove_recursive, 
"Walks combs and deletes all of their sub-objects (or, when used with just -a, 
removes references to objects but not the actual objects.) Will not delete 
objects used elsewhere in the database unless the -f option is also supplied.");
+    BU_OPT(d[5], "v", "verbose",  "[#]", &_rm_verbose, (void *)&verbose, 
"Enable verbose reporting.  Optional integer parameter specifies verbosity 
level - 0 is no output (default when no verbsosity flag is added), 1 reports 
objects skipped due to use elsewhere in the database (the default if no integer 
is supplied to -v), 2 adds reports of attempts to delete objects not present in 
the database, 3 adds reporting of successful deletions, and 4 adds reports of 
all references successfully removed.");
+    BU_OPT(d[6], "n", "no-op",  "", NULL, (void *)&no_op, "Perform a \"dry 
run\" - reports what actions would be taken but does not change the database.");
+    BU_OPT_NULL(d[7]);
 
     /* initialize result */
     bu_vls_trunc(gedp->ged_result_str, 0);
@@ -161,6 +352,7 @@
     ret_ac = bu_opt_parse(&str, argc, (const char **)argv, d);
     if (ret_ac < 0) {
        bu_vls_printf(gedp->ged_result_str, "%s\n", bu_vls_addr(&str));
+       _remove_show_help(gedp, orig_argv[0], d);
        bu_vls_free(&str);
        bu_free_argv(free_argc,free_argv);
        return GED_ERROR;
@@ -168,7 +360,8 @@
 
     /* must be wanting help */
     if (print_help || ret_ac == 0) {
-       bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage);
+       _remove_show_help(gedp, orig_argv[0], d);
+       bu_vls_free(&str);
        bu_free_argv(free_argc,free_argv);
        return GED_HELP;
     }
@@ -176,7 +369,7 @@
     /* Collect paths without slashes - those are full object removals, not
      * removal of an object from a comb.  For paths *with* slashes, those
      * are interpreted as removing the last object in the path from its parent
-     * comb. */
+     * comb - handle them immediately. */
     for (i = 0; i < ret_ac; i++) {
        const char *slash = strrchr(argv[i], '/');
        if (slash == NULL) {
@@ -190,112 +383,123 @@
        }
     }
 
-    if (remove_force || remove_force_refs || remove_recursive) 
remove_from_comb = 0;
+    if (remove_force || remove_refs || remove_recursive) remove_from_comb = 0;
 
-    if (BU_PTBL_LEN(&objs) > 0) {
-       /* Behavior depends on the type of the first object (potentially, based 
on supplied flags) */
-       if ((dp = db_lookup(gedp->ged_wdbp->dbip, (const char 
*)BU_PTBL_GET(&objs, 0), LOOKUP_NOISY)) == RT_DIR_NULL) {
+    /* If we've got nothing else, we're done */
+    if (!BU_PTBL_LEN(&objs) > 0) {
+       goto rcleanup;
+    }
+
+    /* Behavior depends on the type of the first object (potentially, based on 
supplied flags) */
+    if ((dp = db_lookup(gedp->ged_wdbp->dbip, (const char *)BU_PTBL_GET(&objs, 
0), LOOKUP_NOISY)) == RT_DIR_NULL) {
+       ret = GED_ERROR;
+       goto rcleanup;
+    }
+
+    /* If we've got a comb to start with and none of the flags are active, the
+     * interpretation is that the list of objs is removed from the comb child
+     * list of the first comb. */
+    if (remove_from_comb && (dp->d_flags & RT_DIR_COMB) != 0) {
+       if (BU_PTBL_LEN(&objs) == 1) {
+           bu_vls_printf(gedp->ged_result_str, "Error: single comb supplied 
with no flags - not removing %s.  To remove an individual comb from the 
database add the -f flag.", argv[1]);
            ret = GED_ERROR;
            goto rcleanup;
        }
+       if (rt_db_get_internal(&intern, dp, gedp->ged_wdbp->dbip, (fastf_t 
*)NULL, &rt_uniresource) < 0) {
+           bu_vls_printf(gedp->ged_result_str, "Database read error, 
aborting");
+           ret = GED_ERROR;
+           goto rcleanup;
+       }
 
-       /* If we've got a comb to start with, we aren't doing a recursive 
removal, and nothing is
-        * forcing us to remove the comb itself, the interpretation is that the 
list of objs is
-        * removed from the comb child list of the first comb. */
-       if (remove_from_comb && (dp->d_flags & RT_DIR_COMB) != 0) {
-           if (BU_PTBL_LEN(&objs) == 1) {
-               bu_vls_printf(gedp->ged_result_str, "Error: single comb 
supplied without one or more of the '-f' and '-r' flags - not removing %s", 
argv[1]);
+       comb = (struct rt_comb_internal *)intern.idb_ptr;
+       RT_CK_COMB(comb);
+
+       /* Process each argument */
+       for (i = 1; i < (int)BU_PTBL_LEN(&objs); i++) {
+           const char *obj = (const char *)BU_PTBL_GET(&objs, i);
+           if (db_tree_del_dbleaf(&(comb->tree), obj, &rt_uniresource, 0) < 0) 
{
+               bu_vls_printf(gedp->ged_result_str, "ERROR: Failure deleting 
%s/%s\n", dp->d_namep, obj);
                ret = GED_ERROR;
                goto rcleanup;
+           } else {
+               struct bu_vls path = BU_VLS_INIT_ZERO;
+
+               bu_vls_printf(&path, "%s/%s", dp->d_namep, obj);
+               _dl_eraseAllPathsFromDisplay(gedp->ged_gdp->gd_headDisplay, 
gedp->ged_wdbp->dbip, gedp->ged_free_vlist_callback, bu_vls_addr(&path), 0, 
gedp->freesolid);
+               bu_vls_free(&path);
+               bu_vls_printf(gedp->ged_result_str, "deleted %s/%s\n", 
dp->d_namep, obj);
            }
-           if (rt_db_get_internal(&intern, dp, gedp->ged_wdbp->dbip, (fastf_t 
*)NULL, &rt_uniresource) < 0) {
-               bu_vls_printf(gedp->ged_result_str, "Database read error, 
aborting");
-               ret = GED_ERROR;
-               goto rcleanup;
-           }
+       }
 
-           comb = (struct rt_comb_internal *)intern.idb_ptr;
-           RT_CK_COMB(comb);
+       if (rt_db_put_internal(dp, gedp->ged_wdbp->dbip, &intern, 
&rt_uniresource) < 0) {
+           bu_vls_printf(gedp->ged_result_str, "Database write error, 
aborting");
+           ret = GED_ERROR;
+           goto rcleanup;
+       }
+       goto rcleanup;
+    }
 
-           /* Process each argument */
-           for (i = 1; i < (int)BU_PTBL_LEN(&objs); i++) {
-               const char *obj = (const char *)BU_PTBL_GET(&objs, i);
-               if (db_tree_del_dbleaf(&(comb->tree), obj, &rt_uniresource, 0) 
< 0) {
-                   bu_vls_printf(gedp->ged_result_str, "ERROR: Failure 
deleting %s/%s\n", dp->d_namep, obj);
-                   ret = GED_ERROR;
-                   goto rcleanup;
-               } else {
-                   struct bu_vls path = BU_VLS_INIT_ZERO;
-
-                   bu_vls_printf(&path, "%s/%s", dp->d_namep, obj);
-                   _dl_eraseAllPathsFromDisplay(gedp->ged_gdp->gd_headDisplay, 
gedp->ged_wdbp->dbip, gedp->ged_free_vlist_callback, bu_vls_addr(&path), 0, 
gedp->freesolid);
-                   bu_vls_free(&path);
-                   bu_vls_printf(gedp->ged_result_str, "deleted %s/%s\n", 
dp->d_namep, obj);
-               }
+    /* Having handled the removal-from-comb cases, we move on to the more
+     * general database removals.  The various combinations of options need
+     * different logic */
+    if (!remove_refs && !remove_recursive) {
+       for (i = 0; i < (int)BU_PTBL_LEN(&objs) - 1; i++) {
+           (void)_rm_obj(gedp, (const char *)BU_PTBL_GET(&objs, i), NULL, 
&rmlog, verbose, remove_force, no_op);
+       }
+       goto rcleanup;
+    }
+    if (!remove_refs && remove_recursive) {
+       struct bu_ptbl resultobjs = BU_PTBL_INIT_ZERO;
+       struct bu_ptbl validobjs = BU_PTBL_INIT_ZERO;
+       struct directory **dirp = NULL;
+       int v_cnt = _valid_rm_objs(&dirp, &validobjs, gedp, &objs, &rmlog, 
verbose);
+       int r_cnt = db_search(&resultobjs, DB_SEARCH_RETURN_UNIQ_DP, "-name *", 
v_cnt, dirp, gedp->ged_wdbp->dbip);
+       for (i = 0; i < r_cnt; i++) {
+           (void)_rm_obj(gedp, ((struct directory *)BU_PTBL_GET(&resultobjs, 
i))->d_namep, &validobjs, &rmlog, verbose, remove_force, no_op);
+       }
+       if (dirp) bu_free(dirp, "free dirp");
+       bu_ptbl_free(&validobjs);
+       bu_ptbl_free(&resultobjs);
+       goto rcleanup;
+    }
+    if ( remove_refs && !remove_force && !remove_recursive) {
+       _rm_ref(gedp, &objs, &rmlog, no_op);
+       if (remove_force) {
+           for (i = 0; i < (int)BU_PTBL_LEN(&objs) - 1; i++) {
+               (void)_rm_obj(gedp, (const char *)BU_PTBL_GET(&objs, i), NULL, 
&rmlog, verbose, remove_force, no_op);
            }
-
-           if (rt_db_put_internal(dp, gedp->ged_wdbp->dbip, &intern, 
&rt_uniresource) < 0) {
-               bu_vls_printf(gedp->ged_result_str, "Database write error, 
aborting");
-               ret = GED_ERROR;
-               goto rcleanup;
+       }
+       goto rcleanup;
+    }
+    if ( remove_refs && !remove_force && remove_recursive) {
+       struct bu_ptbl resultobjs = BU_PTBL_INIT_ZERO;
+       struct bu_ptbl validobjs = BU_PTBL_INIT_ZERO;
+       struct bu_ptbl resultchars = BU_PTBL_INIT_ZERO;
+       struct directory **dirp = NULL;
+       int v_cnt = _valid_rm_objs(&dirp, &validobjs, gedp, &objs, &rmlog, 
verbose);
+       int r_cnt = db_search(&resultobjs, DB_SEARCH_RETURN_UNIQ_DP, "-name *", 
v_cnt, dirp, gedp->ged_wdbp->dbip);
+       for (i = 0; i < r_cnt; i++) {
+           bu_ptbl_ins(&resultchars, (long *)(((struct directory 
*)BU_PTBL_GET(&resultobjs, i))->d_namep));
+       }
+       _rm_ref(gedp, &resultchars, &rmlog, no_op);
+       for (i = 0; i < r_cnt; i++) {
+           if (remove_force) {
+               (void)_rm_obj(gedp, ((struct directory 
*)BU_PTBL_GET(&resultobjs, i))->d_namep, NULL, &rmlog, verbose, remove_force, 
no_op);
            }
-       } else {
-           /* If we don't have the syntax/options that set up removal of a 
list of objects from a comb, we're
-            * in traditional unix-style rm territory. */
-           if (!remove_recursive) {
-               /* the force flag is a no-op at this stage - without recursive 
removal, it's only role is to override
-                * the remove-from-comb behavior */
-               const char **av = (const char **)bu_calloc(BU_PTBL_LEN(&objs) + 
1, sizeof(char *), "new argv array");
-               av[0] = (const char *)orig_argv[0];
-               for (i = 1; i < (int)BU_PTBL_LEN(&objs) + 1; i++) {
-                   av[i] = (const char *)BU_PTBL_GET(&objs, i - 1);
-               }
-               ret = ged_kill(gedp, BU_PTBL_LEN(&objs)+1, av);
-               bu_free((void *)av, "free tmp argv");
-               return ret;
-           } else {
-               /* This is where the force flag can really impact geometry.  By 
default, killtree checks to
-                * make sure geometry being removed from under one comb isn't 
used elsewhere in the tree.  With
-                * force on, it will wipe out everything. */
-               if (remove_force_refs) {
-                   const char **av = (const char 
**)bu_calloc(BU_PTBL_LEN(&objs) + 2, sizeof(char *), "new argv array");
-                   av[0] = "killtree";
-                   av[1] = "-a";
-                   for (i = 2; i < (int)BU_PTBL_LEN(&objs) + 2; i++) {
-                       av[i] = (const char *)BU_PTBL_GET(&objs, i - 2);
-                   }
-                   ret = ged_killtree(gedp, BU_PTBL_LEN(&objs)+2, av);
-                   bu_free((void *)av, "free tmp argv");
-                   return ret;
-               }
-               if (remove_force) {
-                   const char **av = (const char 
**)bu_calloc(BU_PTBL_LEN(&objs) + 2, sizeof(char *), "new argv array");
-                   av[0] = "killtree";
-                   av[1] = "-f";
-                   for (i = 2; i < (int)BU_PTBL_LEN(&objs) + 2; i++) {
-                       av[i] = (const char *)BU_PTBL_GET(&objs, i - 2);
-                   }
-                   ret = ged_killtree(gedp, BU_PTBL_LEN(&objs)+2, av);
-                   bu_free((void *)av, "free tmp argv");
-                   return ret;
-               }
-               {
-                   const char **av = (const char 
**)bu_calloc(BU_PTBL_LEN(&objs) + 1, sizeof(char *), "new argv array");
-                   av[0] = "killtree";
-                   for (i = 1; i < (int)BU_PTBL_LEN(&objs) + 1; i++) {
-                       av[i] = (const char *)BU_PTBL_GET(&objs, i - 1);
-                   }
-                   ret = ged_killtree(gedp, BU_PTBL_LEN(&objs)+1, av);
-                   bu_free((void *)av, "free tmp argv");
-                   return ret;
-               }
-           }
        }
+       if (dirp) bu_free(dirp, "free dirp");
+       bu_ptbl_free(&resultchars);
+       bu_ptbl_free(&validobjs);
+       bu_ptbl_free(&resultobjs);
+       goto rcleanup;
     }
 
 rcleanup:
     bu_ptbl_free(&objs);
+    bu_vls_free(&str);
     bu_free_argv(free_argc,free_argv);
+    bu_vls_printf(gedp->ged_result_str, "%s", bu_vls_addr(&rmlog));
+    bu_vls_free(&rmlog);
     return ret;
 }
 

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.


------------------------------------------------------------------------------
_______________________________________________
BRL-CAD Source Commits mailing list
brlcad-commits@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/brlcad-commits

Reply via email to