Revision: 74167
          http://sourceforge.net/p/brlcad/code/74167
Author:   starseeker
Date:     2019-10-17 21:14:16 +0000 (Thu, 17 Oct 2019)
Log Message:
-----------
Rename attr.c as a C++ file.

Modified Paths:
--------------
    brlcad/trunk/src/libged/CMakeLists.txt

Added Paths:
-----------
    brlcad/trunk/src/libged/attr.cpp

Removed Paths:
-------------
    brlcad/trunk/src/libged/attr.c

Modified: brlcad/trunk/src/libged/CMakeLists.txt
===================================================================
--- brlcad/trunk/src/libged/CMakeLists.txt      2019-10-17 16:27:59 UTC (rev 
74166)
+++ brlcad/trunk/src/libged/CMakeLists.txt      2019-10-17 21:14:16 UTC (rev 
74167)
@@ -45,7 +45,7 @@
   arb.c
   arced.c
   arot.c
-  attr.c
+  attr.cpp
   autoview.c
   bb.c
   bev.c

Deleted: brlcad/trunk/src/libged/attr.c
===================================================================
--- brlcad/trunk/src/libged/attr.c      2019-10-17 16:27:59 UTC (rev 74166)
+++ brlcad/trunk/src/libged/attr.c      2019-10-17 21:14:16 UTC (rev 74167)
@@ -1,683 +0,0 @@
-/*                         A T T R . C
- * BRL-CAD
- *
- * Copyright (c) 2008-2019 United States Government as represented by
- * the U.S. Army Research Laboratory.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * version 2.1 as published by the Free Software Foundation.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this file; see the file named COPYING for more
- * information.
- */
-/** @file libged/attr.c
- *
- * The attr command.
- *
- */
-
-#include "common.h"
-
-#include <string.h>
-
-#include "bu/getopt.h"
-#include "bu/sort.h"
-#include "./ged_private.h"
-
-
-typedef enum {
-    ATTR_APPEND,
-    ATTR_COPY,
-    ATTR_GET,
-    ATTR_RM,
-    ATTR_SET,
-    ATTR_SHOW,
-    ATTR_SORT,
-    ATTR_LIST,
-    ATTR_UNKNOWN
-} attr_cmd_t;
-
-
-/*
- * avs attribute comparison function, e.g. for bu_sort
- */
-HIDDEN int
-attr_cmp(const void *p1, const void *p2, void *UNUSED(arg))
-{
-    return bu_strcmp(((struct bu_attribute_value_pair *)p1)->name,
-                    ((struct bu_attribute_value_pair *)p2)->name);
-}
-
-
-HIDDEN int
-attr_cmp_nocase(const void *p1, const void *p2, void *UNUSED(arg))
-{
-    return bu_strcasecmp(((struct bu_attribute_value_pair *)p1)->name,
-                        ((struct bu_attribute_value_pair *)p2)->name);
-}
-
-
-HIDDEN int
-attr_cmp_value(const void *p1, const void *p2, void *UNUSED(arg))
-{
-    return bu_strcmp(((struct bu_attribute_value_pair *)p1)->value,
-                    ((struct bu_attribute_value_pair *)p2)->value);
-}
-
-
-HIDDEN int
-attr_cmp_value_nocase(const void *p1, const void *p2, void *UNUSED(arg))
-{
-    return bu_strcasecmp(((struct bu_attribute_value_pair *)p1)->value,
-                        ((struct bu_attribute_value_pair *)p2)->value);
-}
-
-
-HIDDEN int
-attr_pretty_print(struct ged *gedp, struct directory *dp, const char *name)
-{
-    if (dp->d_flags & RT_DIR_COMB) {
-       if (dp->d_flags & RT_DIR_REGION) {
-           bu_vls_printf(gedp->ged_result_str, "%s region:\n", name);
-       } else {
-           bu_vls_printf(gedp->ged_result_str, "%s combination:\n", name);
-       }
-    } else if (dp->d_flags & RT_DIR_SOLID) {
-       struct rt_db_internal intern;
-       GED_DB_GET_INTERNAL(gedp, &intern, dp, (fastf_t *)NULL, 
&rt_uniresource, GED_ERROR);
-       bu_vls_printf(gedp->ged_result_str, "%s %s:\n", name, 
intern.idb_meth->ft_label);
-       rt_db_free_internal(&intern);
-    } else {
-       switch (dp->d_major_type) {
-           case DB5_MAJORTYPE_ATTRIBUTE_ONLY:
-               bu_vls_printf(gedp->ged_result_str, "%s global:\n", name);
-               break;
-           case DB5_MAJORTYPE_BINARY_MIME:
-               bu_vls_printf(gedp->ged_result_str, "%s binary(mime):\n", name);
-               break;
-           case DB5_MAJORTYPE_BINARY_UNIF:
-               bu_vls_printf(gedp->ged_result_str, "%s %s:\n", name,
-                             binu_types[dp->d_minor_type]);
-               break;
-       }
-    }
-
-    return GED_OK;
-}
-
-
-HIDDEN attr_cmd_t
-attr_cmd(const char* arg)
-{
-    /* sub-commands */
-    const char APPEND[] = "append";
-    const char COPY[]   = "copy";
-    const char GET[]    = "get";
-    const char LIST[]   = "list";
-    const char RM[]     = "rm";
-    const char SET[]    = "set";
-    const char SHOW[]   = "show";
-    const char SORT[]   = "sort";
-
-    /* in one user's predicted order of frequency: */
-    if (BU_STR_EQUIV(SHOW, arg))
-       return ATTR_SHOW;
-    else if (BU_STR_EQUIV(SET, arg))
-       return ATTR_SET;
-    else if (BU_STR_EQUIV(SORT, arg))
-       return ATTR_SORT;
-    else if (BU_STR_EQUIV(RM, arg))
-       return ATTR_RM;
-    else if (BU_STR_EQUIV(APPEND, arg))
-       return ATTR_APPEND;
-    else if (BU_STR_EQUIV(GET, arg))
-       return ATTR_GET;
-    else if (BU_STR_EQUIV(LIST, arg))
-       return ATTR_LIST;
-    else if (BU_STR_EQUIV(COPY, arg))
-       return ATTR_COPY;
-    else
-       return ATTR_UNKNOWN;
-}
-
-HIDDEN void
-attr_print(struct ged *gedp, struct bu_attribute_value_set *avs, int argc, 
const char **argv)
-{
-    size_t max_attr_name_len  = 0;
-    struct bu_attribute_value_pair *avpp;
-    size_t i, j;
-    /* If we don't have a specified set, do everything */
-    /* find the max_attr_name_len  */
-    if (argc == 0 || !argv) {
-       for (j = 0, avpp = avs->avp; j < avs->count; j++, avpp++) {
-           size_t len = strlen(avpp->name);
-           if (len > max_attr_name_len) max_attr_name_len = len;
-       }
-       for (i = 0, avpp = avs->avp; i < avs->count; i++, avpp++) {
-           size_t len_diff = 0;
-           size_t count = 0;
-           bu_vls_printf(gedp->ged_result_str, "\t%s", avpp->name);
-           len_diff = max_attr_name_len - strlen(avpp->name);
-           while (count < (len_diff) + 1) {
-               bu_vls_printf(gedp->ged_result_str, " ");
-               count++;
-           }
-           bu_vls_printf(gedp->ged_result_str, "%s\n", avpp->value);
-       }
-    } else {
-       for (i = 0; i < (size_t)argc; i++) {
-           size_t len = strlen(argv[i]);
-           if (len > max_attr_name_len) max_attr_name_len = len;
-       }
-       for (i = 0; i < (size_t)argc; i++) {
-           const char *aval = bu_avs_get(avs, argv[i]);
-           size_t len_diff = 0;
-           size_t count = 0;
-           if (!aval) {
-               bu_vls_sprintf(gedp->ged_result_str, "ERROR: attribute %s not 
found\n", argv[i]);
-               return;
-           }
-           bu_vls_printf(gedp->ged_result_str, "\t%s", argv[i]);
-           len_diff = max_attr_name_len - strlen(argv[i]);
-           while (count < (len_diff) + 1) {
-               bu_vls_printf(gedp->ged_result_str, " ");
-               count++;
-           }
-           bu_vls_printf(gedp->ged_result_str, "%s\n", aval);
-       }
-    }
-}
-
-
-int
-ged_attr(struct ged *gedp, int argc, const char *argv[])
-{
-    int ret = GED_OK;
-    size_t i;
-    struct directory *dp;
-    struct bu_attribute_value_pair *avpp;
-    static const char *usage = "{[-c sep_char] 
set|get|show|rm|append|sort|list|copy} object [key [value] ... ]";
-    attr_cmd_t scmd;
-    struct directory **paths = NULL;
-    size_t path_cnt = 0;
-    int opt;
-    int c_sep = -1;
-    const char *cmd_name = argv[0];
-
-    /* sort types */
-    const char CASE[]         = "case";
-    const char NOCASE[]       = "nocase";
-    const char VALUE[]        = "value";
-    const char VALUE_NOCASE[] = "value-nocase";
-
-    GED_CHECK_ARGC_GT_0(gedp, argc, GED_ERROR);
-
-    /* initialize result */
-    bu_vls_trunc(gedp->ged_result_str, 0);
-
-    /* must be wanting help */
-    if (argc == 1) {
-       bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", cmd_name, usage);
-       return GED_HELP;
-    }
-
-    bu_optind = 1;      /* re-init bu_getopt() */
-    while ((opt = bu_getopt(argc, (char * const *)argv, "c:")) != -1) {
-       switch (opt) {
-           case 'c':
-               c_sep = (int)bu_optarg[0];
-               break;
-           default:
-               bu_vls_printf(gedp->ged_result_str, "Unrecognized option - %c", 
opt);
-               return GED_ERROR;
-       }
-    }
-
-    argc -= bu_optind - 1;
-    argv += bu_optind - 1;
-
-    if (argc < 3) {
-       bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", cmd_name, usage);
-       return GED_ERROR;
-    }
-
-    /* Verify that this wdb supports lookup operations
-       (non-null dbip) */
-    GED_CHECK_DATABASE_OPEN(gedp, GED_ERROR);
-
-    /* this is only valid for v5 databases */
-    if (db_version(gedp->ged_wdbp->dbip) < 5) {
-       bu_vls_printf(gedp->ged_result_str, "Attributes are not available for 
this database format.\nPlease upgrade your database format using \"dbupgrade\" 
to enable attributes.");
-       return GED_ERROR;
-    }
-
-    scmd = attr_cmd(argv[1]);
-
-    path_cnt = db_ls(gedp->ged_wdbp->dbip, DB_LS_HIDDEN, argv[2], &paths);
-
-    if (path_cnt == 0) {
-       bu_vls_printf(gedp->ged_result_str, "Cannot locate objects matching 
%s\n", argv[2]);
-       ret = GED_ERROR;
-       goto ged_attr_memfree;
-    }
-
-    if (scmd == ATTR_SORT) {
-       for (i = 0; i < path_cnt; i++) {
-           /* for pretty printing */
-           size_t j = 0;
-           size_t max_attr_value_len = 0;
-
-           struct bu_attribute_value_set avs;
-           bu_avs_init_empty(&avs);
-
-           dp = paths[i];
-
-           if (db5_get_attributes(gedp->ged_wdbp->dbip, &avs, dp)) {
-               bu_vls_printf(gedp->ged_result_str, "Cannot get attributes for 
object %s\n", dp->d_namep);
-               ret = GED_ERROR;
-               goto ged_attr_memfree;
-           }
-           bu_sort(&avs.avp[0], avs.count, sizeof(struct 
bu_attribute_value_pair), attr_cmp, NULL);
-           /* get a jump on calculating name and value lengths */
-           for (j = 0, avpp = avs.avp; j < avs.count; j++, avpp++) {
-               if (avpp->value) {
-                   size_t len = strlen(avpp->value);
-                   if (len > max_attr_value_len)
-                       max_attr_value_len = len;
-               }
-           }
-
-           /* pretty print */
-           if ((attr_pretty_print(gedp, dp, argv[2])) != GED_OK) {
-               ret = GED_ERROR;
-               goto ged_attr_memfree;
-           }
-           if (argc == 3) {
-               /* just list the already sorted attribute-value pairs */
-               attr_print(gedp, &avs, 0, NULL);
-           } else {
-               /* argv[3] is the sort type: 'case', 'nocase', 'value', 
'value-nocase' */
-               if (BU_STR_EQUIV(argv[3], NOCASE)) {
-                   bu_sort(&avs.avp[0], avs.count, sizeof(struct 
bu_attribute_value_pair), attr_cmp_nocase, NULL);
-               } else if (BU_STR_EQUIV(argv[3], VALUE)) {
-                   bu_sort(&avs.avp[0], avs.count, sizeof(struct 
bu_attribute_value_pair), attr_cmp_value, NULL);
-               } else if (BU_STR_EQUIV(argv[3], VALUE_NOCASE)) {
-                   bu_sort(&avs.avp[0], avs.count, sizeof(struct 
bu_attribute_value_pair), attr_cmp_value_nocase, NULL);
-               } else if (BU_STR_EQUIV(argv[3], CASE)) {
-                   ; /* don't need to do anything since this is the existing 
(default) sort */
-               }
-               /* just list the already sorted attribute-value pairs */
-               attr_print(gedp, &avs, 0, NULL);
-           }
-           bu_avs_free(&avs);
-       }
-    } else if (scmd == ATTR_GET) {
-       if (path_cnt == 1) {
-           struct bu_attribute_value_set avs;
-           bu_avs_init_empty(&avs);
-
-           dp = paths[0];
-
-           if (db5_get_attributes(gedp->ged_wdbp->dbip, &avs, dp)) {
-               bu_vls_printf(gedp->ged_result_str, "Cannot get attributes for 
object %s\n", dp->d_namep);
-               ret = GED_ERROR;
-               goto ged_attr_memfree;
-           }
-           bu_sort(&avs.avp[0], avs.count, sizeof(struct 
bu_attribute_value_pair), attr_cmp, NULL);
-
-           if (argc == 3) {
-               /* just list all the attributes */
-               for (i = 0, avpp = avs.avp; i < avs.count; i++, avpp++) {
-                   if (c_sep == -1)
-                       bu_vls_printf(gedp->ged_result_str, "%s {%s} ", 
avpp->name, avpp->value);
-                   else {
-                       if (i == 0)
-                           bu_vls_printf(gedp->ged_result_str, "%s%c%s", 
avpp->name, (char)c_sep, avpp->value);
-                       else
-                           bu_vls_printf(gedp->ged_result_str, "%c%s%c%s", 
(char)c_sep, avpp->name, (char)c_sep, avpp->value);
-                   }
-               }
-           } else {
-               const char *val;
-               int do_separators=argc-4; /* if more than one attribute */
-
-               for (i = 3; i < (size_t)argc; i++) {
-                   val = bu_avs_get(&avs, argv[i]);
-                   if (!val) {
-                       bu_vls_printf(gedp->ged_result_str,
-                               "Object %s does not have a %s attribute\n",
-                               dp->d_namep,
-                               argv[i]);
-                       bu_avs_free(&avs);
-                       ret = GED_ERROR;
-                       goto ged_attr_memfree;
-                   }
-                   if (do_separators) {
-                       if (c_sep == -1)
-                           bu_vls_printf(gedp->ged_result_str, "{%s} ", val);
-                       else {
-                           if (i == 3)
-                               bu_vls_printf(gedp->ged_result_str, "%s", val);
-                           else
-                               bu_vls_printf(gedp->ged_result_str, "%c%s", 
(char)c_sep, val);
-                       }
-                   } else {
-                       bu_vls_printf(gedp->ged_result_str, "%s", val);
-                   }
-               }
-           }
-           bu_avs_free(&avs);
-       } else {
-           for (i = 0; i < path_cnt; i++) {
-               size_t j = 0;
-               struct bu_vls obj_vals = BU_VLS_INIT_ZERO;
-               struct bu_attribute_value_set avs;
-               bu_avs_init_empty(&avs);
-               dp = paths[i];
-
-               if (db5_get_attributes(gedp->ged_wdbp->dbip, &avs, dp)) {
-                   bu_vls_printf(gedp->ged_result_str, "Cannot get attributes 
for object %s\n", dp->d_namep);
-                   ret = GED_ERROR;
-                   goto ged_attr_memfree;
-               }
-               bu_sort(&avs.avp[0], avs.count, sizeof(struct 
bu_attribute_value_pair), attr_cmp, NULL);
-
-               if (argc == 3) {
-                   /* just list all the attributes */
-                   for (j = 0, avpp = avs.avp; j < avs.count; j++, avpp++) {
-                       if (c_sep == -1)
-                           bu_vls_printf(&obj_vals, "%s {%s} ", avpp->name, 
avpp->value);
-                       else {
-                           if (j == 0)
-                               bu_vls_printf(&obj_vals, "%s%c%s", avpp->name, 
(char)c_sep, avpp->value);
-                           else
-                               bu_vls_printf(&obj_vals, "%c%s%c%s", 
(char)c_sep, avpp->name, (char)c_sep, avpp->value);
-                       }
-                   }
-               } else {
-                   const char *val;
-                   int do_separators=argc-4; /* if more than one attribute */
-
-                   for (j = 3; j < (size_t)argc; j++) {
-                       val = bu_avs_get(&avs, argv[j]);
-                       if (val) {
-                           if (do_separators) {
-                               if (c_sep == -1)
-                                   bu_vls_printf(&obj_vals, "{%s} ", val);
-                               else {
-                                   if (j == 0)
-                                       bu_vls_printf(&obj_vals, "%s", val);
-                                   else
-                                       bu_vls_printf(&obj_vals, "%c%s", 
(char)c_sep, val);
-                               }
-                           } else {
-                               bu_vls_printf(&obj_vals, "%s", val);
-                           }
-                       }
-                   }
-               }
-               if (strlen(bu_vls_addr(&obj_vals)) > 0) {
-                   bu_vls_printf(gedp->ged_result_str, "%s: ", dp->d_namep);
-                   bu_vls_printf(gedp->ged_result_str, "%s", 
bu_vls_addr(&obj_vals));
-
-                   if (i < path_cnt-1) {
-                       bu_vls_printf(gedp->ged_result_str, "\n");
-                   }
-               }
-
-               bu_vls_free(&obj_vals);
-               bu_avs_free(&avs);
-           }
-       }
-    } else if (scmd == ATTR_LIST) {
-       struct bu_attribute_value_set avs;
-       bu_avs_init_empty(&avs);
-
-       for (i = 0; i < path_cnt; i++) {
-           struct bu_attribute_value_set lavs;
-           bu_avs_init_empty(&lavs);
-           dp = paths[i];
-           if (db5_get_attributes(gedp->ged_wdbp->dbip, &lavs, dp)) {
-               bu_vls_printf(gedp->ged_result_str, "Cannot get attributes for 
object %s\n", dp->d_namep);
-               ret = GED_ERROR;
-               goto ged_attr_memfree;
-           }
-           bu_avs_merge(&avs, &lavs);
-           bu_avs_free(&lavs);
-       }
-       /* Now that we have them all, sort */
-       bu_sort(&avs.avp[0], avs.count, sizeof(struct bu_attribute_value_pair), 
attr_cmp, NULL);
-       /* list all the attributes */
-       for (i = 0, avpp = avs.avp; i < avs.count; i++, avpp++) {
-           bu_vls_printf(gedp->ged_result_str, "%s\n", avpp->name);
-       }
-       bu_avs_free(&avs);
-    } else if (scmd == ATTR_COPY) {
-       const char *oattr, *nattr;
-
-       if (argc != 5) {
-           bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", cmd_name, 
usage);
-           return GED_ERROR;
-       }
-       oattr = argv[3];
-       nattr = argv[4];
-
-       for (i = 0; i < path_cnt; i++) {
-           const char *val;
-           struct bu_attribute_value_set lavs;
-           bu_avs_init_empty(&lavs);
-           dp = paths[i];
-           if (db5_get_attributes(gedp->ged_wdbp->dbip, &lavs, dp)) {
-               bu_vls_printf(gedp->ged_result_str, "Cannot get attributes for 
object %s\n", dp->d_namep);
-               ret = GED_ERROR;
-               goto ged_attr_memfree;
-           }
-           val = bu_avs_get(&lavs, oattr);
-           if (val) {
-               (void)bu_avs_add(&lavs, nattr, val);
-               db5_standardize_avs(&lavs);
-               if (db5_update_attributes(dp, &lavs, gedp->ged_wdbp->dbip)) {
-                   bu_vls_printf(gedp->ged_result_str,
-                           "Error: failed to update attributes\n");
-                   bu_avs_free(&lavs);
-                   ret = GED_ERROR;
-                   goto ged_attr_memfree;
-               }
-               /* lavs is freed by db5_update_attributes() */
-           } else {
-               bu_avs_free(&lavs);
-           }
-       }
-
-    } else if (scmd == ATTR_SET) {
-       GED_CHECK_READ_ONLY(gedp, GED_ERROR);
-       /* setting attribute/value pairs */
-       if ((argc - 3) % 2) {
-           bu_vls_printf(gedp->ged_result_str,
-                   "Error: attribute names and values must be in pairs!!!\n");
-           ret = GED_ERROR;
-           goto ged_attr_memfree;
-       }
-       for (i = 0; i < path_cnt; i++) {
-           size_t j = 3;
-           struct bu_attribute_value_set avs;
-           bu_avs_init_empty(&avs);
-           dp = paths[i];
-
-           if (db5_get_attributes(gedp->ged_wdbp->dbip, &avs, dp)) {
-               bu_vls_printf(gedp->ged_result_str, "Cannot get attributes for 
object %s\n", dp->d_namep);
-               ret = GED_ERROR;
-               goto ged_attr_memfree;
-           }
-           bu_sort(&avs.avp[0], avs.count, sizeof(struct 
bu_attribute_value_pair), attr_cmp, NULL);
-           while (j < (size_t)argc) {
-               if (BU_STR_EQUAL(argv[j], "region") && BU_STR_EQUAL(argv[j+1], 
"R")) {
-                   dp->d_flags |= RT_DIR_REGION;
-               }
-               (void)bu_avs_add(&avs, argv[j], argv[j+1]);
-               j += 2;
-           }
-           db5_standardize_avs(&avs);
-           if (db5_update_attributes(dp, &avs, gedp->ged_wdbp->dbip)) {
-               bu_vls_printf(gedp->ged_result_str,
-                       "Error: failed to update attributes\n");
-               bu_avs_free(&avs);
-               ret = GED_ERROR;
-               goto ged_attr_memfree;
-           }
-           /* avs is freed by db5_update_attributes() */
-       }
-
-    } else if (scmd == ATTR_RM) {
-       GED_CHECK_READ_ONLY(gedp, GED_ERROR);
-       for (i = 0; i < path_cnt; i++) {
-           size_t j = 3;
-           struct bu_attribute_value_set avs;
-           bu_avs_init_empty(&avs);
-           dp = paths[i];
-
-           if (db5_get_attributes(gedp->ged_wdbp->dbip, &avs, dp)) {
-               bu_vls_printf(gedp->ged_result_str, "Cannot get attributes for 
object %s\n", dp->d_namep);
-               ret = GED_ERROR;
-               goto ged_attr_memfree;
-           }
-           bu_sort(&avs.avp[0], avs.count, sizeof(struct 
bu_attribute_value_pair), attr_cmp, NULL);
-
-           while (j < (size_t)argc) {
-               if (BU_STR_EQUAL(argv[j], "region")) {
-                   dp->d_flags = dp->d_flags & ~(RT_DIR_REGION);
-               }
-               (void)bu_avs_remove(&avs, argv[j]);
-               j++;
-           }
-           if (db5_replace_attributes(dp, &avs, gedp->ged_wdbp->dbip)) {
-               bu_vls_printf(gedp->ged_result_str,
-                       "Error: failed to update attributes\n");
-               bu_avs_free(&avs);
-               ret = GED_ERROR;
-               goto ged_attr_memfree;
-           }
-           /* avs is freed by db5_replace_attributes() */
-       }
-
-    } else if (scmd == ATTR_APPEND) {
-       GED_CHECK_READ_ONLY(gedp, GED_ERROR);
-       if ((argc-3) % 2) {
-           bu_vls_printf(gedp->ged_result_str,
-                         "Error: attribute names and values must be in 
pairs!!!\n");
-           ret = GED_ERROR;
-           goto ged_attr_memfree;
-       }
-       for (i = 0; i < path_cnt; i++) {
-           size_t j = 3;
-           struct bu_attribute_value_set avs;
-           bu_avs_init_empty(&avs);
-           dp = paths[i];
-
-           if (db5_get_attributes(gedp->ged_wdbp->dbip, &avs, dp)) {
-               bu_vls_printf(gedp->ged_result_str, "Cannot get attributes for 
object %s\n", dp->d_namep);
-               ret = GED_ERROR;
-               goto ged_attr_memfree;
-           }
-           bu_sort(&avs.avp[0], avs.count, sizeof(struct 
bu_attribute_value_pair), attr_cmp, NULL);
-
-           while (j < (size_t)argc) {
-               const char *old_val;
-               if (BU_STR_EQUAL(argv[j], "region") && BU_STR_EQUAL(argv[j+1], 
"R")) {
-                   dp->d_flags |= RT_DIR_REGION;
-               }
-               old_val = bu_avs_get(&avs, argv[j]);
-               if (!old_val) {
-                   (void)bu_avs_add(&avs, argv[j], argv[j+1]);
-               } else {
-                   struct bu_vls vls = BU_VLS_INIT_ZERO;
-
-                   bu_vls_strcat(&vls, old_val);
-                   bu_vls_strcat(&vls, argv[j+1]);
-                   bu_avs_add_vls(&avs, argv[j], &vls);
-                   bu_vls_free(&vls);
-               }
-
-               j += 2;
-           }
-           if (db5_replace_attributes(dp, &avs, gedp->ged_wdbp->dbip)) {
-               bu_vls_printf(gedp->ged_result_str,
-                       "Error: failed to update attributes\n");
-               bu_avs_free(&avs);
-               ret = GED_ERROR;
-               goto ged_attr_memfree;
-           }
-
-           /* avs is freed by db5_replace_attributes() */
-       }
-    } else if (scmd == ATTR_SHOW) {
-       for (i = 0; i < path_cnt; i++) {
-           /* for pretty printing */
-           size_t max_attr_value_len = 0;
-
-           size_t j = 0;
-           struct bu_attribute_value_set avs;
-           bu_avs_init_empty(&avs);
-           dp = paths[i];
-
-           if (db5_get_attributes(gedp->ged_wdbp->dbip, &avs, dp)) {
-               bu_vls_printf(gedp->ged_result_str, "Cannot get attributes for 
object %s\n", dp->d_namep);
-               ret = GED_ERROR;
-               goto ged_attr_memfree;
-           }
-
-           /* get a jump on calculating name and value lengths */
-           for (j = 0, avpp = avs.avp; j < avs.count; j++, avpp++) {
-               if (avpp->value) {
-                   size_t len = strlen(avpp->value);
-                   if (len > max_attr_value_len)
-                       max_attr_value_len = len;
-               }
-           }
-
-           /* pretty print */
-           if ((attr_pretty_print(gedp, dp, dp->d_namep)) != GED_OK) {
-               ret = GED_ERROR;
-               goto ged_attr_memfree;
-           }
-
-           if (argc == 3) {
-               /* just display all attributes */
-               attr_print(gedp, &avs, 0, NULL);
-           } else {
-               /* show just the specified attributes */
-               attr_print(gedp, &avs, argc - 3, argv + 3);
-           }
-       }
-    } else {
-       bu_vls_printf(gedp->ged_result_str, "ERROR: unrecognized attr 
subcommand %s\n", argv[1]);
-       bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", cmd_name, usage);
-
-       ret = GED_ERROR;
-       goto ged_attr_memfree;
-    }
-
-ged_attr_memfree:
-
-    bu_free(paths, "db_ls paths");
-
-    return ret;
-}
-
-
-/*
- * Local Variables:
- * tab-width: 8
- * mode: C
- * indent-tabs-mode: t
- * c-file-style: "stroustrup"
- * End:
- * ex: shiftwidth=4 tabstop=8
- */

Copied: brlcad/trunk/src/libged/attr.cpp (from rev 74166, 
brlcad/trunk/src/libged/attr.c)
===================================================================
--- brlcad/trunk/src/libged/attr.cpp                            (rev 0)
+++ brlcad/trunk/src/libged/attr.cpp    2019-10-17 21:14:16 UTC (rev 74167)
@@ -0,0 +1,683 @@
+/*                         A T T R . C
+ * BRL-CAD
+ *
+ * Copyright (c) 2008-2019 United States Government as represented by
+ * the U.S. Army Research Laboratory.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this file; see the file named COPYING for more
+ * information.
+ */
+/** @file libged/attr.c
+ *
+ * The attr command.
+ *
+ */
+
+#include "common.h"
+
+#include <string.h>
+
+#include "bu/getopt.h"
+#include "bu/sort.h"
+#include "./ged_private.h"
+
+
+typedef enum {
+    ATTR_APPEND,
+    ATTR_COPY,
+    ATTR_GET,
+    ATTR_RM,
+    ATTR_SET,
+    ATTR_SHOW,
+    ATTR_SORT,
+    ATTR_LIST,
+    ATTR_UNKNOWN
+} attr_cmd_t;
+
+
+/*
+ * avs attribute comparison function, e.g. for bu_sort
+ */
+HIDDEN int
+attr_cmp(const void *p1, const void *p2, void *UNUSED(arg))
+{
+    return bu_strcmp(((struct bu_attribute_value_pair *)p1)->name,
+                    ((struct bu_attribute_value_pair *)p2)->name);
+}
+
+
+HIDDEN int
+attr_cmp_nocase(const void *p1, const void *p2, void *UNUSED(arg))
+{
+    return bu_strcasecmp(((struct bu_attribute_value_pair *)p1)->name,
+                        ((struct bu_attribute_value_pair *)p2)->name);
+}
+
+
+HIDDEN int
+attr_cmp_value(const void *p1, const void *p2, void *UNUSED(arg))
+{
+    return bu_strcmp(((struct bu_attribute_value_pair *)p1)->value,
+                    ((struct bu_attribute_value_pair *)p2)->value);
+}
+
+
+HIDDEN int
+attr_cmp_value_nocase(const void *p1, const void *p2, void *UNUSED(arg))
+{
+    return bu_strcasecmp(((struct bu_attribute_value_pair *)p1)->value,
+                        ((struct bu_attribute_value_pair *)p2)->value);
+}
+
+
+HIDDEN int
+attr_pretty_print(struct ged *gedp, struct directory *dp, const char *name)
+{
+    if (dp->d_flags & RT_DIR_COMB) {
+       if (dp->d_flags & RT_DIR_REGION) {
+           bu_vls_printf(gedp->ged_result_str, "%s region:\n", name);
+       } else {
+           bu_vls_printf(gedp->ged_result_str, "%s combination:\n", name);
+       }
+    } else if (dp->d_flags & RT_DIR_SOLID) {
+       struct rt_db_internal intern;
+       GED_DB_GET_INTERNAL(gedp, &intern, dp, (fastf_t *)NULL, 
&rt_uniresource, GED_ERROR);
+       bu_vls_printf(gedp->ged_result_str, "%s %s:\n", name, 
intern.idb_meth->ft_label);
+       rt_db_free_internal(&intern);
+    } else {
+       switch (dp->d_major_type) {
+           case DB5_MAJORTYPE_ATTRIBUTE_ONLY:
+               bu_vls_printf(gedp->ged_result_str, "%s global:\n", name);
+               break;
+           case DB5_MAJORTYPE_BINARY_MIME:
+               bu_vls_printf(gedp->ged_result_str, "%s binary(mime):\n", name);
+               break;
+           case DB5_MAJORTYPE_BINARY_UNIF:
+               bu_vls_printf(gedp->ged_result_str, "%s %s:\n", name,
+                             binu_types[dp->d_minor_type]);
+               break;
+       }
+    }
+
+    return GED_OK;
+}
+
+
+HIDDEN attr_cmd_t
+attr_cmd(const char* arg)
+{
+    /* sub-commands */
+    const char APPEND[] = "append";
+    const char COPY[]   = "copy";
+    const char GET[]    = "get";
+    const char LIST[]   = "list";
+    const char RM[]     = "rm";
+    const char SET[]    = "set";
+    const char SHOW[]   = "show";
+    const char SORT[]   = "sort";
+
+    /* in one user's predicted order of frequency: */
+    if (BU_STR_EQUIV(SHOW, arg))
+       return ATTR_SHOW;
+    else if (BU_STR_EQUIV(SET, arg))
+       return ATTR_SET;
+    else if (BU_STR_EQUIV(SORT, arg))
+       return ATTR_SORT;
+    else if (BU_STR_EQUIV(RM, arg))
+       return ATTR_RM;
+    else if (BU_STR_EQUIV(APPEND, arg))
+       return ATTR_APPEND;
+    else if (BU_STR_EQUIV(GET, arg))
+       return ATTR_GET;
+    else if (BU_STR_EQUIV(LIST, arg))
+       return ATTR_LIST;
+    else if (BU_STR_EQUIV(COPY, arg))
+       return ATTR_COPY;
+    else
+       return ATTR_UNKNOWN;
+}
+
+HIDDEN void
+attr_print(struct ged *gedp, struct bu_attribute_value_set *avs, int argc, 
const char **argv)
+{
+    size_t max_attr_name_len  = 0;
+    struct bu_attribute_value_pair *avpp;
+    size_t i, j;
+    /* If we don't have a specified set, do everything */
+    /* find the max_attr_name_len  */
+    if (argc == 0 || !argv) {
+       for (j = 0, avpp = avs->avp; j < avs->count; j++, avpp++) {
+           size_t len = strlen(avpp->name);
+           if (len > max_attr_name_len) max_attr_name_len = len;
+       }
+       for (i = 0, avpp = avs->avp; i < avs->count; i++, avpp++) {
+           size_t len_diff = 0;
+           size_t count = 0;
+           bu_vls_printf(gedp->ged_result_str, "\t%s", avpp->name);
+           len_diff = max_attr_name_len - strlen(avpp->name);
+           while (count < (len_diff) + 1) {
+               bu_vls_printf(gedp->ged_result_str, " ");
+               count++;
+           }
+           bu_vls_printf(gedp->ged_result_str, "%s\n", avpp->value);
+       }
+    } else {
+       for (i = 0; i < (size_t)argc; i++) {
+           size_t len = strlen(argv[i]);
+           if (len > max_attr_name_len) max_attr_name_len = len;
+       }
+       for (i = 0; i < (size_t)argc; i++) {
+           const char *aval = bu_avs_get(avs, argv[i]);
+           size_t len_diff = 0;
+           size_t count = 0;
+           if (!aval) {
+               bu_vls_sprintf(gedp->ged_result_str, "ERROR: attribute %s not 
found\n", argv[i]);
+               return;
+           }
+           bu_vls_printf(gedp->ged_result_str, "\t%s", argv[i]);
+           len_diff = max_attr_name_len - strlen(argv[i]);
+           while (count < (len_diff) + 1) {
+               bu_vls_printf(gedp->ged_result_str, " ");
+               count++;
+           }
+           bu_vls_printf(gedp->ged_result_str, "%s\n", aval);
+       }
+    }
+}
+
+
+int
+ged_attr(struct ged *gedp, int argc, const char *argv[])
+{
+    int ret = GED_OK;
+    size_t i;
+    struct directory *dp;
+    struct bu_attribute_value_pair *avpp;
+    static const char *usage = "{[-c sep_char] 
set|get|show|rm|append|sort|list|copy} object [key [value] ... ]";
+    attr_cmd_t scmd;
+    struct directory **paths = NULL;
+    size_t path_cnt = 0;
+    int opt;
+    int c_sep = -1;
+    const char *cmd_name = argv[0];
+
+    /* sort types */
+    const char CASE[]         = "case";
+    const char NOCASE[]       = "nocase";
+    const char VALUE[]        = "value";
+    const char VALUE_NOCASE[] = "value-nocase";
+
+    GED_CHECK_ARGC_GT_0(gedp, argc, GED_ERROR);
+
+    /* initialize result */
+    bu_vls_trunc(gedp->ged_result_str, 0);
+
+    /* must be wanting help */
+    if (argc == 1) {
+       bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", cmd_name, usage);
+       return GED_HELP;
+    }
+
+    bu_optind = 1;      /* re-init bu_getopt() */
+    while ((opt = bu_getopt(argc, (char * const *)argv, "c:")) != -1) {
+       switch (opt) {
+           case 'c':
+               c_sep = (int)bu_optarg[0];
+               break;
+           default:
+               bu_vls_printf(gedp->ged_result_str, "Unrecognized option - %c", 
opt);
+               return GED_ERROR;
+       }
+    }
+
+    argc -= bu_optind - 1;
+    argv += bu_optind - 1;
+
+    if (argc < 3) {
+       bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", cmd_name, usage);
+       return GED_ERROR;
+    }
+
+    /* Verify that this wdb supports lookup operations
+       (non-null dbip) */
+    GED_CHECK_DATABASE_OPEN(gedp, GED_ERROR);
+
+    /* this is only valid for v5 databases */
+    if (db_version(gedp->ged_wdbp->dbip) < 5) {
+       bu_vls_printf(gedp->ged_result_str, "Attributes are not available for 
this database format.\nPlease upgrade your database format using \"dbupgrade\" 
to enable attributes.");
+       return GED_ERROR;
+    }
+
+    scmd = attr_cmd(argv[1]);
+
+    path_cnt = db_ls(gedp->ged_wdbp->dbip, DB_LS_HIDDEN, argv[2], &paths);
+
+    if (path_cnt == 0) {
+       bu_vls_printf(gedp->ged_result_str, "Cannot locate objects matching 
%s\n", argv[2]);
+       ret = GED_ERROR;
+       goto ged_attr_memfree;
+    }
+
+    if (scmd == ATTR_SORT) {
+       for (i = 0; i < path_cnt; i++) {
+           /* for pretty printing */
+           size_t j = 0;
+           size_t max_attr_value_len = 0;
+
+           struct bu_attribute_value_set avs;
+           bu_avs_init_empty(&avs);
+
+           dp = paths[i];
+
+           if (db5_get_attributes(gedp->ged_wdbp->dbip, &avs, dp)) {
+               bu_vls_printf(gedp->ged_result_str, "Cannot get attributes for 
object %s\n", dp->d_namep);
+               ret = GED_ERROR;
+               goto ged_attr_memfree;
+           }
+           bu_sort(&avs.avp[0], avs.count, sizeof(struct 
bu_attribute_value_pair), attr_cmp, NULL);
+           /* get a jump on calculating name and value lengths */
+           for (j = 0, avpp = avs.avp; j < avs.count; j++, avpp++) {
+               if (avpp->value) {
+                   size_t len = strlen(avpp->value);
+                   if (len > max_attr_value_len)
+                       max_attr_value_len = len;
+               }
+           }
+
+           /* pretty print */
+           if ((attr_pretty_print(gedp, dp, argv[2])) != GED_OK) {
+               ret = GED_ERROR;
+               goto ged_attr_memfree;
+           }
+           if (argc == 3) {
+               /* just list the already sorted attribute-value pairs */
+               attr_print(gedp, &avs, 0, NULL);
+           } else {
+               /* argv[3] is the sort type: 'case', 'nocase', 'value', 
'value-nocase' */
+               if (BU_STR_EQUIV(argv[3], NOCASE)) {
+                   bu_sort(&avs.avp[0], avs.count, sizeof(struct 
bu_attribute_value_pair), attr_cmp_nocase, NULL);
+               } else if (BU_STR_EQUIV(argv[3], VALUE)) {
+                   bu_sort(&avs.avp[0], avs.count, sizeof(struct 
bu_attribute_value_pair), attr_cmp_value, NULL);
+               } else if (BU_STR_EQUIV(argv[3], VALUE_NOCASE)) {
+                   bu_sort(&avs.avp[0], avs.count, sizeof(struct 
bu_attribute_value_pair), attr_cmp_value_nocase, NULL);
+               } else if (BU_STR_EQUIV(argv[3], CASE)) {
+                   ; /* don't need to do anything since this is the existing 
(default) sort */
+               }
+               /* just list the already sorted attribute-value pairs */
+               attr_print(gedp, &avs, 0, NULL);
+           }
+           bu_avs_free(&avs);
+       }
+    } else if (scmd == ATTR_GET) {
+       if (path_cnt == 1) {
+           struct bu_attribute_value_set avs;
+           bu_avs_init_empty(&avs);
+
+           dp = paths[0];
+
+           if (db5_get_attributes(gedp->ged_wdbp->dbip, &avs, dp)) {
+               bu_vls_printf(gedp->ged_result_str, "Cannot get attributes for 
object %s\n", dp->d_namep);
+               ret = GED_ERROR;
+               goto ged_attr_memfree;
+           }
+           bu_sort(&avs.avp[0], avs.count, sizeof(struct 
bu_attribute_value_pair), attr_cmp, NULL);
+
+           if (argc == 3) {
+               /* just list all the attributes */
+               for (i = 0, avpp = avs.avp; i < avs.count; i++, avpp++) {
+                   if (c_sep == -1)
+                       bu_vls_printf(gedp->ged_result_str, "%s {%s} ", 
avpp->name, avpp->value);
+                   else {
+                       if (i == 0)
+                           bu_vls_printf(gedp->ged_result_str, "%s%c%s", 
avpp->name, (char)c_sep, avpp->value);
+                       else
+                           bu_vls_printf(gedp->ged_result_str, "%c%s%c%s", 
(char)c_sep, avpp->name, (char)c_sep, avpp->value);
+                   }
+               }
+           } else {
+               const char *val;
+               int do_separators=argc-4; /* if more than one attribute */
+
+               for (i = 3; i < (size_t)argc; i++) {
+                   val = bu_avs_get(&avs, argv[i]);
+                   if (!val) {
+                       bu_vls_printf(gedp->ged_result_str,
+                               "Object %s does not have a %s attribute\n",
+                               dp->d_namep,
+                               argv[i]);
+                       bu_avs_free(&avs);
+                       ret = GED_ERROR;
+                       goto ged_attr_memfree;
+                   }
+                   if (do_separators) {
+                       if (c_sep == -1)
+                           bu_vls_printf(gedp->ged_result_str, "{%s} ", val);
+                       else {
+                           if (i == 3)
+                               bu_vls_printf(gedp->ged_result_str, "%s", val);
+                           else
+                               bu_vls_printf(gedp->ged_result_str, "%c%s", 
(char)c_sep, val);
+                       }
+                   } else {
+                       bu_vls_printf(gedp->ged_result_str, "%s", val);
+                   }
+               }
+           }
+           bu_avs_free(&avs);
+       } else {
+           for (i = 0; i < path_cnt; i++) {
+               size_t j = 0;
+               struct bu_vls obj_vals = BU_VLS_INIT_ZERO;
+               struct bu_attribute_value_set avs;
+               bu_avs_init_empty(&avs);
+               dp = paths[i];
+
+               if (db5_get_attributes(gedp->ged_wdbp->dbip, &avs, dp)) {
+                   bu_vls_printf(gedp->ged_result_str, "Cannot get attributes 
for object %s\n", dp->d_namep);
+                   ret = GED_ERROR;
+                   goto ged_attr_memfree;
+               }
+               bu_sort(&avs.avp[0], avs.count, sizeof(struct 
bu_attribute_value_pair), attr_cmp, NULL);
+
+               if (argc == 3) {
+                   /* just list all the attributes */
+                   for (j = 0, avpp = avs.avp; j < avs.count; j++, avpp++) {
+                       if (c_sep == -1)
+                           bu_vls_printf(&obj_vals, "%s {%s} ", avpp->name, 
avpp->value);
+                       else {
+                           if (j == 0)
+                               bu_vls_printf(&obj_vals, "%s%c%s", avpp->name, 
(char)c_sep, avpp->value);
+                           else
+                               bu_vls_printf(&obj_vals, "%c%s%c%s", 
(char)c_sep, avpp->name, (char)c_sep, avpp->value);
+                       }
+                   }
+               } else {
+                   const char *val;
+                   int do_separators=argc-4; /* if more than one attribute */
+
+                   for (j = 3; j < (size_t)argc; j++) {
+                       val = bu_avs_get(&avs, argv[j]);
+                       if (val) {
+                           if (do_separators) {
+                               if (c_sep == -1)
+                                   bu_vls_printf(&obj_vals, "{%s} ", val);
+                               else {
+                                   if (j == 0)
+                                       bu_vls_printf(&obj_vals, "%s", val);
+                                   else
+                                       bu_vls_printf(&obj_vals, "%c%s", 
(char)c_sep, val);
+                               }
+                           } else {
+                               bu_vls_printf(&obj_vals, "%s", val);
+                           }
+                       }
+                   }
+               }
+               if (strlen(bu_vls_addr(&obj_vals)) > 0) {
+                   bu_vls_printf(gedp->ged_result_str, "%s: ", dp->d_namep);
+                   bu_vls_printf(gedp->ged_result_str, "%s", 
bu_vls_addr(&obj_vals));
+
+                   if (i < path_cnt-1) {
+                       bu_vls_printf(gedp->ged_result_str, "\n");
+                   }
+               }
+
+               bu_vls_free(&obj_vals);
+               bu_avs_free(&avs);
+           }
+       }
+    } else if (scmd == ATTR_LIST) {
+       struct bu_attribute_value_set avs;
+       bu_avs_init_empty(&avs);
+
+       for (i = 0; i < path_cnt; i++) {
+           struct bu_attribute_value_set lavs;
+           bu_avs_init_empty(&lavs);
+           dp = paths[i];
+           if (db5_get_attributes(gedp->ged_wdbp->dbip, &lavs, dp)) {
+               bu_vls_printf(gedp->ged_result_str, "Cannot get attributes for 
object %s\n", dp->d_namep);
+               ret = GED_ERROR;
+               goto ged_attr_memfree;
+           }
+           bu_avs_merge(&avs, &lavs);
+           bu_avs_free(&lavs);
+       }
+       /* Now that we have them all, sort */
+       bu_sort(&avs.avp[0], avs.count, sizeof(struct bu_attribute_value_pair), 
attr_cmp, NULL);
+       /* list all the attributes */
+       for (i = 0, avpp = avs.avp; i < avs.count; i++, avpp++) {
+           bu_vls_printf(gedp->ged_result_str, "%s\n", avpp->name);
+       }
+       bu_avs_free(&avs);
+    } else if (scmd == ATTR_COPY) {
+       const char *oattr, *nattr;
+
+       if (argc != 5) {
+           bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", cmd_name, 
usage);
+           return GED_ERROR;
+       }
+       oattr = argv[3];
+       nattr = argv[4];
+
+       for (i = 0; i < path_cnt; i++) {
+           const char *val;
+           struct bu_attribute_value_set lavs;
+           bu_avs_init_empty(&lavs);
+           dp = paths[i];
+           if (db5_get_attributes(gedp->ged_wdbp->dbip, &lavs, dp)) {
+               bu_vls_printf(gedp->ged_result_str, "Cannot get attributes for 
object %s\n", dp->d_namep);
+               ret = GED_ERROR;
+               goto ged_attr_memfree;
+           }
+           val = bu_avs_get(&lavs, oattr);
+           if (val) {
+               (void)bu_avs_add(&lavs, nattr, val);
+               db5_standardize_avs(&lavs);
+               if (db5_update_attributes(dp, &lavs, gedp->ged_wdbp->dbip)) {
+                   bu_vls_printf(gedp->ged_result_str,
+                           "Error: failed to update attributes\n");
+                   bu_avs_free(&lavs);
+                   ret = GED_ERROR;
+                   goto ged_attr_memfree;
+               }
+               /* lavs is freed by db5_update_attributes() */
+           } else {
+               bu_avs_free(&lavs);
+           }
+       }
+
+    } else if (scmd == ATTR_SET) {
+       GED_CHECK_READ_ONLY(gedp, GED_ERROR);
+       /* setting attribute/value pairs */
+       if ((argc - 3) % 2) {
+           bu_vls_printf(gedp->ged_result_str,
+                   "Error: attribute names and values must be in pairs!!!\n");
+           ret = GED_ERROR;
+           goto ged_attr_memfree;
+       }
+       for (i = 0; i < path_cnt; i++) {
+           size_t j = 3;
+           struct bu_attribute_value_set avs;
+           bu_avs_init_empty(&avs);
+           dp = paths[i];
+
+           if (db5_get_attributes(gedp->ged_wdbp->dbip, &avs, dp)) {
+               bu_vls_printf(gedp->ged_result_str, "Cannot get attributes for 
object %s\n", dp->d_namep);
+               ret = GED_ERROR;
+               goto ged_attr_memfree;
+           }
+           bu_sort(&avs.avp[0], avs.count, sizeof(struct 
bu_attribute_value_pair), attr_cmp, NULL);
+           while (j < (size_t)argc) {
+               if (BU_STR_EQUAL(argv[j], "region") && BU_STR_EQUAL(argv[j+1], 
"R")) {
+                   dp->d_flags |= RT_DIR_REGION;
+               }
+               (void)bu_avs_add(&avs, argv[j], argv[j+1]);
+               j += 2;
+           }
+           db5_standardize_avs(&avs);
+           if (db5_update_attributes(dp, &avs, gedp->ged_wdbp->dbip)) {
+               bu_vls_printf(gedp->ged_result_str,
+                       "Error: failed to update attributes\n");
+               bu_avs_free(&avs);
+               ret = GED_ERROR;
+               goto ged_attr_memfree;
+           }
+           /* avs is freed by db5_update_attributes() */
+       }
+
+    } else if (scmd == ATTR_RM) {
+       GED_CHECK_READ_ONLY(gedp, GED_ERROR);
+       for (i = 0; i < path_cnt; i++) {
+           size_t j = 3;
+           struct bu_attribute_value_set avs;
+           bu_avs_init_empty(&avs);
+           dp = paths[i];
+
+           if (db5_get_attributes(gedp->ged_wdbp->dbip, &avs, dp)) {
+               bu_vls_printf(gedp->ged_result_str, "Cannot get attributes for 
object %s\n", dp->d_namep);
+               ret = GED_ERROR;
+               goto ged_attr_memfree;
+           }
+           bu_sort(&avs.avp[0], avs.count, sizeof(struct 
bu_attribute_value_pair), attr_cmp, NULL);
+
+           while (j < (size_t)argc) {
+               if (BU_STR_EQUAL(argv[j], "region")) {
+                   dp->d_flags = dp->d_flags & ~(RT_DIR_REGION);
+               }
+               (void)bu_avs_remove(&avs, argv[j]);
+               j++;
+           }
+           if (db5_replace_attributes(dp, &avs, gedp->ged_wdbp->dbip)) {
+               bu_vls_printf(gedp->ged_result_str,
+                       "Error: failed to update attributes\n");
+               bu_avs_free(&avs);
+               ret = GED_ERROR;
+               goto ged_attr_memfree;
+           }
+           /* avs is freed by db5_replace_attributes() */
+       }
+
+    } else if (scmd == ATTR_APPEND) {
+       GED_CHECK_READ_ONLY(gedp, GED_ERROR);
+       if ((argc-3) % 2) {
+           bu_vls_printf(gedp->ged_result_str,
+                         "Error: attribute names and values must be in 
pairs!!!\n");
+           ret = GED_ERROR;
+           goto ged_attr_memfree;
+       }
+       for (i = 0; i < path_cnt; i++) {
+           size_t j = 3;
+           struct bu_attribute_value_set avs;
+           bu_avs_init_empty(&avs);
+           dp = paths[i];
+
+           if (db5_get_attributes(gedp->ged_wdbp->dbip, &avs, dp)) {
+               bu_vls_printf(gedp->ged_result_str, "Cannot get attributes for 
object %s\n", dp->d_namep);
+               ret = GED_ERROR;
+               goto ged_attr_memfree;
+           }
+           bu_sort(&avs.avp[0], avs.count, sizeof(struct 
bu_attribute_value_pair), attr_cmp, NULL);
+
+           while (j < (size_t)argc) {
+               const char *old_val;
+               if (BU_STR_EQUAL(argv[j], "region") && BU_STR_EQUAL(argv[j+1], 
"R")) {
+                   dp->d_flags |= RT_DIR_REGION;
+               }
+               old_val = bu_avs_get(&avs, argv[j]);
+               if (!old_val) {
+                   (void)bu_avs_add(&avs, argv[j], argv[j+1]);
+               } else {
+                   struct bu_vls vls = BU_VLS_INIT_ZERO;
+
+                   bu_vls_strcat(&vls, old_val);
+                   bu_vls_strcat(&vls, argv[j+1]);
+                   bu_avs_add_vls(&avs, argv[j], &vls);
+                   bu_vls_free(&vls);
+               }
+
+               j += 2;
+           }
+           if (db5_replace_attributes(dp, &avs, gedp->ged_wdbp->dbip)) {
+               bu_vls_printf(gedp->ged_result_str,
+                       "Error: failed to update attributes\n");
+               bu_avs_free(&avs);
+               ret = GED_ERROR;
+               goto ged_attr_memfree;
+           }
+
+           /* avs is freed by db5_replace_attributes() */
+       }
+    } else if (scmd == ATTR_SHOW) {
+       for (i = 0; i < path_cnt; i++) {
+           /* for pretty printing */
+           size_t max_attr_value_len = 0;
+
+           size_t j = 0;
+           struct bu_attribute_value_set avs;
+           bu_avs_init_empty(&avs);
+           dp = paths[i];
+
+           if (db5_get_attributes(gedp->ged_wdbp->dbip, &avs, dp)) {
+               bu_vls_printf(gedp->ged_result_str, "Cannot get attributes for 
object %s\n", dp->d_namep);
+               ret = GED_ERROR;
+               goto ged_attr_memfree;
+           }
+
+           /* get a jump on calculating name and value lengths */
+           for (j = 0, avpp = avs.avp; j < avs.count; j++, avpp++) {
+               if (avpp->value) {
+                   size_t len = strlen(avpp->value);
+                   if (len > max_attr_value_len)
+                       max_attr_value_len = len;
+               }
+           }
+
+           /* pretty print */
+           if ((attr_pretty_print(gedp, dp, dp->d_namep)) != GED_OK) {
+               ret = GED_ERROR;
+               goto ged_attr_memfree;
+           }
+
+           if (argc == 3) {
+               /* just display all attributes */
+               attr_print(gedp, &avs, 0, NULL);
+           } else {
+               /* show just the specified attributes */
+               attr_print(gedp, &avs, argc - 3, argv + 3);
+           }
+       }
+    } else {
+       bu_vls_printf(gedp->ged_result_str, "ERROR: unrecognized attr 
subcommand %s\n", argv[1]);
+       bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", cmd_name, usage);
+
+       ret = GED_ERROR;
+       goto ged_attr_memfree;
+    }
+
+ged_attr_memfree:
+
+    bu_free(paths, "db_ls paths");
+
+    return ret;
+}
+
+
+/*
+ * Local Variables:
+ * tab-width: 8
+ * mode: C
+ * indent-tabs-mode: t
+ * c-file-style: "stroustrup"
+ * End:
+ * ex: shiftwidth=4 tabstop=8
+ */

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



_______________________________________________
BRL-CAD Source Commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/brlcad-commits

Reply via email to