Revision: 76385
http://sourceforge.net/p/brlcad/code/76385
Author: starseeker
Date: 2020-07-21 13:01:44 +0000 (Tue, 21 Jul 2020)
Log Message:
-----------
Revert plugin changes in bioh - that work will now proceed in the gedplugins
branch
Modified Paths:
--------------
brlcad/branches/bioh/include/ged/commands.h
brlcad/branches/bioh/include/ged/defines.h
brlcad/branches/bioh/src/gtools/gsh.cpp
brlcad/branches/bioh/src/libged/CMakeLists.txt
brlcad/branches/bioh/src/libged/ged.c
brlcad/branches/bioh/src/libged/help/help.cpp
brlcad/branches/bioh/src/libged/zoom/zoom.c
Removed Paths:
-------------
brlcad/branches/bioh/src/libged/exec.cpp
brlcad/branches/bioh/src/libged/ged_init.cpp
brlcad/branches/bioh/src/libged/include/
brlcad/branches/bioh/src/libged/zoom/CMakeLists.txt
Modified: brlcad/branches/bioh/include/ged/commands.h
===================================================================
--- brlcad/branches/bioh/include/ged/commands.h 2020-07-21 12:58:27 UTC (rev
76384)
+++ brlcad/branches/bioh/include/ged/commands.h 2020-07-21 13:01:44 UTC (rev
76385)
@@ -34,8 +34,6 @@
__BEGIN_DECLS
-/* Execute plugin based command */
-GED_EXPORT extern int ged_exec(struct ged *gedp, int argc, const char *argv[]);
/**
* Adjust object's attribute(s)
Modified: brlcad/branches/bioh/include/ged/defines.h
===================================================================
--- brlcad/branches/bioh/include/ged/defines.h 2020-07-21 12:58:27 UTC (rev
76384)
+++ brlcad/branches/bioh/include/ged/defines.h 2020-07-21 13:01:44 UTC (rev
76385)
@@ -241,6 +241,22 @@
typedef void (*ged_create_vlist_callback_ptr)(struct display_list *);
typedef void (*ged_free_vlist_callback_ptr)(unsigned int, int);
+
+/**
+ * describes a command plugin
+ */
+struct ged_cmd {
+ struct bu_list l;
+
+ const char *name;
+ const char description[80];
+ const char *manpage;
+
+ int (*load)(struct ged *);
+ void (*unload)(struct ged *);
+ int (*exec)(struct ged *, int, const char *[]);
+};
+
/* accessor functions for ged_results - calling
* applications should not work directly with the
* internals of ged_results, which are not guaranteed
@@ -278,15 +294,7 @@
}
-struct ged_cmd_impl;
-struct ged_cmd {
- struct ged_cmd_impl *i;
-};
-struct ged_plugin {
- const struct ged_cmd * const p;
-};
-
__END_DECLS
#endif /* GED_DEFINES_H */
Modified: brlcad/branches/bioh/src/gtools/gsh.cpp
===================================================================
--- brlcad/branches/bioh/src/gtools/gsh.cpp 2020-07-21 12:58:27 UTC (rev
76384)
+++ brlcad/branches/bioh/src/gtools/gsh.cpp 2020-07-21 13:01:44 UTC (rev
76385)
@@ -169,6 +169,7 @@
/* Start the interactive loop */
while ((line = linenoise(gpmpt)) != NULL) {
+ int (*func)(struct ged *, int, char *[]);
bu_vls_sprintf(&iline, "%s", line);
free(line);
@@ -191,8 +192,7 @@
/* OK, try a GED command - make an argv array from the input line */
struct bu_vls ged_prefixed = BU_VLS_INIT_ZERO;
- //bu_vls_sprintf(&ged_prefixed, "ged_%s", bu_vls_addr(&iline));
- bu_vls_sprintf(&ged_prefixed, "%s", bu_vls_addr(&iline));
+ bu_vls_sprintf(&ged_prefixed, "ged_%s", bu_vls_addr(&iline));
char *input = bu_strdup(bu_vls_addr(&ged_prefixed));
bu_vls_free(&ged_prefixed);
char **av = (char **)bu_calloc(strlen(input) + 1, sizeof(char *), "argv
array");
@@ -201,7 +201,7 @@
/* The "open" and close commands require a bit of
* awareness at this level, since the gedp pointer
* must respond to them. */
- if (BU_STR_EQUAL(av[0], "open")) {
+ if (BU_STR_EQUAL(av[0], "ged_open")) {
if (ac > 1) {
if (gedp) ged_close(gedp);
gedp = ged_open("db", av[1], 0);
@@ -232,7 +232,7 @@
}
- if (BU_STR_EQUAL(av[0], "close")) {
+ if (BU_STR_EQUAL(av[0], "ged_close")) {
ged_close(gedp);
gedp = NULL;
printf("closed database %s\n", bu_vls_addr(&open_gfile));
@@ -245,11 +245,6 @@
/* If we're not opening or closing, and we have an active gedp,
* make a standard libged call */
- ged_exec(gedp, ac, (const char **)av);
- printf("%s\n", bu_vls_cstr(gedp->ged_result_str));
- bu_vls_trunc(gedp->ged_result_str, 0);
-#if 0
- int (*func)(struct ged *, int, char *[]);
*(void **)(&func) = bu_dlsym(libged, av[0]);
if (!func) {
printf("unrecognzied command: %s\n", av[0]);
@@ -257,7 +252,6 @@
(void)func(gedp, ac, av);
printf("%s\n", bu_vls_addr(gedp->ged_result_str));
}
-#endif
bu_free(input, "input copy");
bu_free(av, "input argv");
Modified: brlcad/branches/bioh/src/libged/CMakeLists.txt
===================================================================
--- brlcad/branches/bioh/src/libged/CMakeLists.txt 2020-07-21 12:58:27 UTC
(rev 76384)
+++ brlcad/branches/bioh/src/libged/CMakeLists.txt 2020-07-21 13:01:44 UTC
(rev 76385)
@@ -47,8 +47,6 @@
set(LIBGED_SOURCES
${LIBGED_SOURCES}
- exec.cpp
- ged_init.cpp
3ptarb/3ptarb.c
adc/adc.c
adjust/adjust.c
@@ -375,8 +373,6 @@
${LIBGED_CMD_SRCS}
)
-set_property(SOURCE ged_init.cpp APPEND PROPERTY COMPILE_DEFINITIONS
"GED_PLUGIN_SUFFIX=\"${CMAKE_SHARED_LIBRARY_SUFFIX}\"")
-
# Include directories needed by libged users
set(GED_INCLUDE_DIRS
${BRLCAD_BINARY_DIR}/include
@@ -445,13 +441,9 @@
simulate/rt_motion_state.hpp
simulate/simulation.hpp
simulate/utility.hpp
- include/plugin.h
)
CMAKEFILES(${ged_ignore_files})
-# Plugin test
-add_subdirectory(zoom)
-
# Local Variables:
# tab-width: 8
# mode: cmake
Deleted: brlcad/branches/bioh/src/libged/exec.cpp
===================================================================
--- brlcad/branches/bioh/src/libged/exec.cpp 2020-07-21 12:58:27 UTC (rev
76384)
+++ brlcad/branches/bioh/src/libged/exec.cpp 2020-07-21 13:01:44 UTC (rev
76385)
@@ -1,84 +0,0 @@
-/* E X E C . C P P
- * BRL-CAD
- *
- * Copyright (c) 2020 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 exec.cpp
- *
- * Brief description
- *
- */
-
-#include "common.h"
-
-#include <map>
-#include <string>
-
-#include "ged.h"
-#include "./include/plugin.h"
-
-extern "C" int
-ged_exec(struct ged *gedp, int argc, const char *argv[]) {
- if (!gedp || !argc || !argv) {
- return GED_ERROR;
- }
-
- // TODO - right now this is the map from the libged load - should probably
- // use this to initialize a struct ged copy when ged_init is called, so
- // client codes can add their own commands to their gedp...
- //
- // The ged_cmds map should always reflect the original, vanilla state of
- // libged's command set so we have a clean fallback available if we ever
- // need it to fall back on/recover with.
- std::map<std::string, const struct ged_cmd *> *cmap =
(std::map<std::string, const struct ged_cmd *> *)ged_cmds;
- std::string key(argv[0]);
- std::map<std::string, const struct ged_cmd *>::iterator c_it =
cmap->find(key);
- if (c_it == cmap->end()) {
- bu_vls_printf(gedp->ged_result_str, "unknown command: %s", argv[0]);
- return GED_ERROR;
- }
-
- const struct ged_cmd *cmd = c_it->second;
-
- // TODO - if interactive command via cmd->i->interactive, don't execute
- // unless we have the necessary callbacks defined in gedp
-
- int cret = (*cmd->i->cmd)(gedp, argc, argv);
-
- // TODO - for the moment these are the hardcoded default opts. Eventually
- // an opts var should be added to struct ged, and each exec call will set
- // the gedp->opts value to the command defaults. Then the command option
handling
- // will be able to alter the flags if desired (for example, a flag to
suppress
- // autoview behavior will simply remove the flag from gedp->opts.
- if (cmd->i->opts & GED_CMD_UPDATE_VIEW) {
- // Do update view callback
- if (gedp->ged_refresh_handler) {
- (*gedp->ged_refresh_handler)(gedp->ged_refresh_clientdata);
- }
- }
-
- return cret;
-}
-
-// Local Variables:
-// tab-width: 8
-// mode: C++
-// c-basic-offset: 4
-// indent-tabs-mode: t
-// c-file-style: "stroustrup"
-// End:
-// ex: shiftwidth=4 tabstop=8
Modified: brlcad/branches/bioh/src/libged/ged.c
===================================================================
--- brlcad/branches/bioh/src/libged/ged.c 2020-07-21 12:58:27 UTC (rev
76384)
+++ brlcad/branches/bioh/src/libged/ged.c 2020-07-21 13:01:44 UTC (rev
76385)
@@ -191,6 +191,49 @@
}
+
+HIDDEN int
+cmds_add(struct ged *gedp, const struct ged_cmd *cmd)
+{
+ struct ged_cmd *copy;
+ BU_GET(copy, struct ged_cmd);
+ memcpy(copy, cmd, sizeof(struct ged_cmd));
+ BU_LIST_INIT_MAGIC(&(copy->l), GED_CMD_MAGIC);
+ BU_LIST_PUSH(&(gedp->cmds->l), copy);
+ return 0;
+}
+
+
+HIDDEN int
+cmds_del(struct ged *gedp, const char *name)
+{
+ struct ged_cmd *cmd;
+ for (BU_LIST_FOR(cmd, ged_cmd, &(gedp->cmds->l))) {
+ if (BU_STR_EQUIV(cmd->name, name)) {
+ BU_LIST_POP(ged_cmd, &(gedp->cmds->l), cmd);
+ BU_PUT(cmd, struct ged_cmd);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+
+HIDDEN int
+cmds_run(struct ged *gedp, int ac, char *av[])
+{
+ struct ged_cmd *cmd;
+ for (BU_LIST_FOR(cmd, ged_cmd, &(gedp->cmds->l))) {
+ if (BU_STR_EQUIV(cmd->name, av[0])) {
+ return cmd->exec(gedp, ac, (const char **)av);
+ }
+ }
+
+ return 0;
+}
+
+
void
ged_init(struct ged *gedp)
{
@@ -239,6 +282,13 @@
gedp->ged_output_handler = NULL;
gedp->ged_output_script = NULL;
gedp->ged_internal_call = 0;
+
+ /* set up our command registration container */
+ BU_GET(gedp->cmds, struct ged_cmd);
+ BU_LIST_INIT(&(gedp->cmds->l));
+ gedp->add = &cmds_add;
+ gedp->del = &cmds_del;
+ gedp->run = &cmds_run;
}
@@ -650,6 +700,7 @@
rt_db_free_internal(&intern);
}
+
/*
* Local Variables:
* mode: C
Deleted: brlcad/branches/bioh/src/libged/ged_init.cpp
===================================================================
--- brlcad/branches/bioh/src/libged/ged_init.cpp 2020-07-21 12:58:27 UTC
(rev 76384)
+++ brlcad/branches/bioh/src/libged/ged_init.cpp 2020-07-21 13:01:44 UTC
(rev 76385)
@@ -1,160 +0,0 @@
-/* G E D _ I N I T . C P P
- * BRL-CAD
- *
- * Copyright (c) 2019-2020 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 init.c
- *
- * NOTE: as this init is global to ALL applications before main(),
- * care must be taken to not write to STDOUT or STDERR or app output
- * may be corrupted, signals can be raised, or worse.
- *
- */
-
-#include "common.h"
-
-#include <algorithm>
-#include <cctype>
-#include <map>
-#include <set>
-#include <string>
-
-#include "bu/defines.h"
-#include "bu/app.h"
-#include "bu/dylib.h"
-#include "bu/file.h"
-#include "bu/vls.h"
-#include "ged.h"
-
-#include "./include/plugin.h"
-
-static std::map<std::string, const struct ged_cmd *> ged_cmd_map;
-void *ged_cmds;
-
-static std::set<void *> ged_handles;
-struct bu_vls *ged_init_msg_str;
-
-const char *
-ged_init_msgs()
-{
- return bu_vls_cstr(ged_init_msg_str);
-}
-
-
-static void
-libged_init(void)
-{
-
- BU_GET(ged_init_msg_str, struct bu_vls);
- bu_vls_init(ged_init_msg_str);
-
- const char *ppath = bu_dir(NULL, 0, BU_DIR_LIBEXEC, "ged", NULL);
- char **filenames;
- struct bu_vls plugin_pattern = BU_VLS_INIT_ZERO;
- bu_vls_sprintf(&plugin_pattern, "*%s", GED_PLUGIN_SUFFIX);
- size_t nfiles = bu_file_list(ppath, bu_vls_cstr(&plugin_pattern),
&filenames);
- for (size_t i = 0; i < nfiles; i++) {
- char pfile[MAXPATHLEN] = {0};
- bu_dir(pfile, MAXPATHLEN, BU_DIR_LIBEXEC, "ged", filenames[i], NULL);
- void *dl_handle;
- if (!(dl_handle = bu_dlopen(pfile, BU_RTLD_NOW))) {
- const char * const error_msg = bu_dlerror();
- if (error_msg)
- bu_vls_printf(ged_init_msg_str, "%s\n", error_msg);
-
- bu_vls_printf(ged_init_msg_str, "Unable to dynamically load '%s'
(skipping)\n", pfile);
- continue;
- }
- {
- const char *psymbol = "ged_plugin_info";
- void *info_val = bu_dlsym(dl_handle, psymbol);
- const struct ged_plugin *(*plugin_info)() = (const struct
ged_plugin *(*)())(intptr_t)info_val;
- if (!plugin_info) {
- const char * const error_msg = bu_dlerror();
-
- if (error_msg)
- bu_vls_printf(ged_init_msg_str, "%s\n", error_msg);
-
- bu_vls_printf(ged_init_msg_str, "Unable to load symbols from
'%s' (skipping)\n", pfile);
- bu_vls_printf(ged_init_msg_str, "Could not find '%s' symbol in
plugin\n", psymbol);
- bu_dlclose(dl_handle);
- continue;
- }
-
- const struct ged_plugin *plugin = plugin_info();
-
- if (!plugin || !plugin->p) {
- bu_vls_printf(ged_init_msg_str, "Invalid plugin encountered
from '%s' (skipping)\n", pfile);
- bu_dlclose(dl_handle);
- continue;
- }
-
- const struct ged_cmd *c = plugin->p;
- std::string key(c->i->cname);
- if (ged_cmd_map.find(key) != ged_cmd_map.end()) {
- bu_vls_printf(ged_init_msg_str, "Warning - file '%s' provides
command '%s' but that command has already been loaded, skipping\n", pfile,
c->i->cname);
- bu_dlclose(dl_handle);
- continue;
- }
- ged_handles.insert(dl_handle);
- ged_cmd_map[key] = c;
- }
- }
-
- ged_cmds = (void *)&ged_cmd_map;
-}
-
-
-static void
-libged_clear(void)
-{
- ged_cmd_map.clear();
- std::set<void *>::iterator h_it;
- for (h_it = ged_handles.begin(); h_it != ged_handles.end(); h_it++) {
- void *handle = *h_it;
- bu_dlclose(handle);
- }
- ged_handles.clear();
-
- bu_vls_free(ged_init_msg_str);
- BU_PUT(ged_init_msg_str, struct bu_vls);
-}
-
-
-struct libged_initializer {
- /* constructor */
- libged_initializer() {
- libged_init();
- }
- /* destructor */
- ~libged_initializer() {
- libged_clear();
- }
-};
-
-static libged_initializer LIBGED;
-
-
-
-// Local Variables:
-// tab-width: 8
-// mode: C++
-// c-basic-offset: 4
-// indent-tabs-mode: t
-// c-file-style: "stroustrup"
-// End:
-// ex: shiftwidth=4 tabstop=8
Modified: brlcad/branches/bioh/src/libged/help/help.cpp
===================================================================
--- brlcad/branches/bioh/src/libged/help/help.cpp 2020-07-21 12:58:27 UTC
(rev 76384)
+++ brlcad/branches/bioh/src/libged/help/help.cpp 2020-07-21 13:01:44 UTC
(rev 76385)
@@ -27,6 +27,9 @@
#include "bu/file.h"
#include "ged.h"
+
+HIDDEN struct bu_list *help_cmd(void);
+
/**
* get a list of all the files under a given 'dir' filepath,
* dynamically allocated. returns the number of files found in an
@@ -267,6 +270,100 @@
return 0;
}
+
+HIDDEN int
+help_load(struct ged *gedp)
+{
+ int ret = 0;
+ struct bu_list *hp = help_cmd();
+ struct ged_cmd *cmd;
+
+ for (BU_LIST_FOR(cmd, ged_cmd, hp)) {
+ ret += gedp->add(gedp, cmd);
+ }
+
+ BU_PUT(hp, struct bu_list);
+
+ return ret;
+}
+
+
+HIDDEN void
+help_unload(struct ged *gedp)
+{
+ gedp->del(gedp, "help");
+ gedp->del(gedp, "apropos");
+ gedp->del(gedp, "info");
+ gedp->del(gedp, "man");
+ gedp->del(gedp, "?");
+}
+
+
+HIDDEN struct bu_list *
+help_cmd(void)
+{
+ struct bu_list *hp;
+
+ static struct ged_cmd cmd[6] = {
+ {
+ BU_LIST_INIT_ZERO, "help",
+ "the BRL-CAD help system",
+ "help",
+ &help_load, &help_unload, &ged_help
+ }, {
+ BU_LIST_INIT_ZERO, "apropos",
+ "the BRL-CAD help system",
+ "help",
+ &help_load, &help_unload, &ged_help
+ }, {
+ BU_LIST_INIT_ZERO, "info",
+ "the BRL-CAD help system",
+ "help",
+ &help_load, &help_unload, &ged_help
+ }, {
+ BU_LIST_INIT_ZERO, "man",
+ "the BRL-CAD help system",
+ "help",
+ &help_load, &help_unload, &ged_help
+ }, {
+ BU_LIST_INIT_ZERO, "?",
+ "the BRL-CAD help system",
+ "help",
+ &help_load, &help_unload, &ged_help
+ }, {
+ BU_LIST_INIT_ZERO, NULL, {0}, NULL, NULL, NULL, NULL
+ }
+ };
+
+ BU_GET(hp, struct bu_list);
+ BU_LIST_INIT(hp);
+
+ BU_LIST_PUSH(hp, &(cmd[0].l));
+ BU_LIST_PUSH(hp, &(cmd[1].l));
+ BU_LIST_PUSH(hp, &(cmd[2].l));
+ BU_LIST_PUSH(hp, &(cmd[3].l));
+ BU_LIST_PUSH(hp, &(cmd[4].l));
+
+ return hp;
+}
+
+
+#ifdef STANDALONE
+int main(int ac, char *av[])
+{
+ struct ged ged = {0};
+
+ bu_setprogname(av[0]);
+
+ GED_INIT(&ged, NULL);
+ help_load(&ged);
+ ged_help(&ged, ac, (const char **)av);
+ help_unload(&ged);
+
+ return 0;
+}
+#endif
+
/*
* Local Variables:
* tab-width: 8
Deleted: brlcad/branches/bioh/src/libged/zoom/CMakeLists.txt
===================================================================
--- brlcad/branches/bioh/src/libged/zoom/CMakeLists.txt 2020-07-21 12:58:27 UTC
(rev 76384)
+++ brlcad/branches/bioh/src/libged/zoom/CMakeLists.txt 2020-07-21 13:01:44 UTC
(rev 76385)
@@ -1,27 +0,0 @@
-include_directories(
- ${CMAKE_CURRENT_SOURCE_DIR}
- ${BRLCAD_BINARY_DIR}/include
- ${BRLCAD_SOURCE_DIR}/include
- ${BU_INCLUDE_DIRS}
- ${GED_INCLUDE_DIRS}
- )
-
-set(ZOOM_SRCS
- zoom.c
- )
-
-add_definitions(-DGED_PLUGIN)
-
-add_library(ged-zoom SHARED ${ZOOM_SRCS})
-target_link_libraries(ged-zoom libged libbu)
-set_property(TARGET ged-zoom APPEND PROPERTY COMPILE_DEFINITIONS BRLCADBUILD
HAVE_CONFIG_H)
-VALIDATE_STYLE(ged-zoom "${ZOOM_SRCS}")
-
-PLUGIN_SETUP(ged-zoom ged)
-
-# Local Variables:
-# tab-width: 8
-# mode: cmake
-# indent-tabs-mode: t
-# End:
-# ex: shiftwidth=2 tabstop=8
Modified: brlcad/branches/bioh/src/libged/zoom/zoom.c
===================================================================
--- brlcad/branches/bioh/src/libged/zoom/zoom.c 2020-07-21 12:58:27 UTC (rev
76384)
+++ brlcad/branches/bioh/src/libged/zoom/zoom.c 2020-07-21 13:01:44 UTC (rev
76385)
@@ -65,25 +65,40 @@
return zoom(gedp, sf);
}
-#ifdef GED_PLUGIN
-#include "../include/plugin.h"
-struct ged_cmd_impl zoom_cmd_impl = {
- "zoom",
- ged_zoom,
- GED_CMD_VIEW_CALLBACK | GED_CMD_UPDATE_VIEW
-};
-struct ged_cmd zoom_cmd = { &zoom_cmd_impl };
+HIDDEN int
+zoom_load(struct ged *gedp)
+{
+ extern const struct ged_cmd *zoom_cmd(void);
-static const struct ged_plugin pinfo = { &zoom_cmd };
+ const struct ged_cmd *cmd = zoom_cmd();
+ return gedp->add(gedp, cmd);
+}
-COMPILER_DLLEXPORT const struct ged_plugin *ged_plugin_info()
+
+HIDDEN void
+zoom_unload(struct ged *gedp)
{
- return &pinfo;
+ gedp->del(gedp, "zoom");
}
-#endif /* GED_PLUGIN */
+const struct ged_cmd *
+zoom_cmd(void)
+{
+ static struct ged_cmd cmd = {
+ BU_LIST_INIT_ZERO,
+ "zoom",
+ "zoom view by specified scale factor",
+ "zoom",
+ &zoom_load,
+ &zoom_unload,
+ &ged_zoom
+ };
+ BU_LIST_MAGIC_SET(&(cmd.l), GED_CMD_MAGIC);
+ return &cmd;
+}
+
/*
* Local Variables:
* tab-width: 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