Revision: 65099
http://sourceforge.net/p/brlcad/code/65099
Author: starseeker
Date: 2015-05-29 19:24:09 +0000 (Fri, 29 May 2015)
Log Message:
-----------
Checkpoint work on advanced libbu option parsing. Unlike other attempts, this
is implemented entirely in libbu and uses no external dependencies. It's not
yet in a finished state, but it can do enough that's its worth checkpointing
now.
Modified Paths:
--------------
brlcad/trunk/include/bu/CMakeLists.txt
brlcad/trunk/src/conv/gcv/gcv.cpp
brlcad/trunk/src/libbu/CMakeLists.txt
brlcad/trunk/src/libbu/tests/CMakeLists.txt
Added Paths:
-----------
brlcad/trunk/include/bu/opt.h
brlcad/trunk/src/libbu/opt.c
brlcad/trunk/src/libbu/tests/opt.c
Modified: brlcad/trunk/include/bu/CMakeLists.txt
===================================================================
--- brlcad/trunk/include/bu/CMakeLists.txt 2015-05-29 19:10:07 UTC (rev
65098)
+++ brlcad/trunk/include/bu/CMakeLists.txt 2015-05-29 19:24:09 UTC (rev
65099)
@@ -18,6 +18,7 @@
malloc.h
mapped_file.h
mime.h
+ opt.h
parallel.h
parse.h
path.h
Added: brlcad/trunk/include/bu/opt.h
===================================================================
--- brlcad/trunk/include/bu/opt.h (rev 0)
+++ brlcad/trunk/include/bu/opt.h 2015-05-29 19:24:09 UTC (rev 65099)
@@ -0,0 +1,277 @@
+/* O P T . H
+ * BRL-CAD
+ *
+ * Copyright (c) 2015 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.
+ */
+
+#ifndef BU_OPT_H
+#define BU_OPT_H
+
+#include "common.h"
+#include "bu/defines.h"
+#include "bu/ptbl.h"
+#include "bu/vls.h"
+
+__BEGIN_DECLS
+
+/** @addtogroup bu_opt
+ * @brief
+ * Generalized option handling.
+ *
+ */
+/** @{ */
+/** @file bu/opt.h */
+
+/* Pick an arbitrary maximum pending a good reason to pick some specific value
*/
+#define BU_OPT_MAX_ARGS 2000
+
+struct bu_opt_data; /* Forward declaration for bu_opt_desc */
+
+/**
+ * Convenience typedef for function callback to validate bu_opt
+ * arguments
+ */
+typedef int (*bu_opt_arg_process_t)(struct bu_vls *, struct bu_opt_data *);
+
+/**
+ * "Option description" structure
+ */
+struct bu_opt_desc {
+ int index;
+ size_t arg_cnt_min;
+ size_t arg_cnt_max;
+ const char *shortopt;
+ const char *longopt;
+ bu_opt_arg_process_t arg_process;
+ const char *shortopt_doc;
+ const char *longopt_doc;
+ const char *help_string;
+};
+#define BU_OPT_DESC_NULL {-1, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL}
+
+/** Initialize a struct bu_opt_desc to BU_OPT_DESC_NULL */
+BU_EXPORT extern void bu_opt_desc_init(struct bu_opt_desc *d);
+
+/** Set the values in a struct bu_opt_desc */
+BU_EXPORT extern void bu_opt_desc_set(struct bu_opt_desc *d, int ind,
+ size_t min, size_t max, const char *shortopt,
+ const char *longopt, bu_opt_arg_process_t arg_process,
+ const char *shortopt_doc, const char *longopt_doc, const char
*help_str);
+
+/** Free an option description structure */
+BU_EXPORT extern void bu_opt_desc_free(struct bu_opt_desc *d);
+
+/**
+ * Most of the time bu_opt_desc structs that need to be freed will be in
bu_ptbl
+ * containers, so handle that case
+ */
+BU_EXPORT extern void bu_opt_desc_free_tbl(struct bu_ptbl *tbl);
+
+#define BU_OPT_DESC_PTBL_INIT(_i, _ptbl) {\
+ int ptbl_cnt = 0; \
+ bu_ptbl_init(_ptbl, 8, "init table"); \
+ for (ptbl_cnt = 0; ptbl_cnt < _i; ptbl_cnt++) {\
+ struct bu_opt_desc *d; \
+ BU_GET(d, struct bu_opt_desc);\
+ bu_opt_desc_init(d); \
+ bu_ptbl_ins(_ptbl, (long *)d);\
+ } \
+}
+#define BU_OPT_DESC_GET_PTBL(_i, _ptbl) (struct bu_opt_desc
*)(_ptbl)->buffer[_i]
+
+
+
+/**
+ * Parsed option data container
+ */
+struct bu_opt_data {
+ struct bu_opt_desc *desc;
+ unsigned int valid;
+ const char *name;
+ struct bu_ptbl *args;
+ void *user_data; /* place for arg_process to stash data */
+};
+#define BU_OPT_DATA_NULL {NULL, 0, NULL, NULL, NULL}
+/** Initialize a bu_opt_data structure to BU_OPT_DATA_NULL */
+BU_EXPORT extern void bu_opt_data_init(struct bu_opt_data *d);
+
+/**
+ * Note - description objects pointed to by bu_opt_data strucures
+ * are not freed by this function, since they may be multiply
+ * referenced by many bu_opt_data struct instances */
+BU_EXPORT extern void bu_opt_data_free(struct bu_opt_data *d);
+
+/**
+ * Most of the time bu_opt_data containers will be in bu_ptbl structs,
+ * so handle that case */
+BU_EXPORT extern void bu_opt_data_free_tbl(struct bu_ptbl *t);
+
+/**
+ * Convenience function for extracting args from a bu_opt_data container.
+ * Returns NULL if the specified arg is not present. ind starts from 0. */
+BU_EXPORT extern const char *bu_opt_data_arg(struct bu_opt_data *d, int ind);
+
+
+/**
+ * Parse argv array using option descs.
+ *
+ * returns a bu_ptbl of bu_opt_data structure pointers, or NULL if the parsing
+ * failed. If a desc has an arg process, function, the valid field in
+ * bu_opt_data for each option will indicate if the value in arg was
+ * successfully processed by arg_process. In situations where multiple options
+ * are present, the general rule is that the last one in the list wins.
+ *
+ * bu_opt_desc array ds must be null terminated with BU_OPT_DESC_NULL.
+ *
+ * Return 0 if parse successful (all options valid) and 1 otherwise.
+ *
+ *
+ * Style to use when static definitions are possible
+ *
+ * enum d1_opt_ind {D1_HELP, D1_VERBOSITY};
+ * struct bu_opt_desc d1[4] = {
+ * {D1_HELP, 0, 0, "h", "help", NULL, help_str},
+ * {D1_HELP, 0, 0, "?", "", NULL, help_str},
+ * {D1_VERBOSITY, 0, 1, "v", "verbosity", &(d1_verbosity), "Set
verbosity"},
+ * BU_OPT_DESC_NULL
+ * };
+ * bu_opt_parse(argc, argv, d1);
+ */
+BU_EXPORT extern int bu_opt_parse(struct bu_ptbl **tbl, struct bu_vls *msgs,
int ac, const char **argv, struct bu_opt_desc *ds);
+/** parse argv array defined as a space separated string */
+BU_EXPORT extern int bu_opt_parse_str(struct bu_ptbl **tbl, struct bu_vls
*msgs, const char *str, struct bu_opt_desc *ds);
+
+
+/**
+ * For situations requiring a dynamic bu_opt_desc generation mechanism,
+ * the procedure is slightly different
+ *
+ * If we need dynamic definitions, need to take a slightly different approach
+ *
+ * enum d1_opt_ind {D1_HELP, D1_VERBOSITY};
+ * struct bu_ptbl dtbl;
+ * BU_OPT_DESC_PTBL_INIT(4, &dtbl);
+ * bu_opt_desc_set(BU_OPT_DESC_GET_PTBL(0), D1_HELP, 0, 0, "h", "help", NULL,
help_str);
+ * bu_opt_desc_set(BU_OPT_DESC_GET_PTBL(1), D1_HELP, 0, 0, "?", "", NULL,
help_str);
+ * bu_opt_desc_set(BU_OPT_DESC_GET_PTBL(2), D1_VERBOSITY, 0, 1, "v",
"verbosity", &(dtbl_verbosity), "Set verbosity");
+ * bu_opt_parse_ptbl(argc, argv, dtbl);
+ */
+BU_EXPORT extern int bu_opt_parse_dtbl(struct bu_ptbl **tbl, struct bu_vls
*msgs, int ac, const char **argv, struct bu_ptbl *dtbl);
+/** parse argv array defined as a space separated string */
+BU_EXPORT extern int bu_opt_parse_str_dtbl(struct bu_ptbl **tbl, struct bu_vls
*msgs, const char *str, struct bu_ptbl *dtbl);
+
+/**
+ * In situations where multiple options are present, the general rule is that
+ * the last one in the list wins but there are situations where a program may
+ * want to (say) accumulate multiple values past with multiple instances of the
+ * same opt. bu_opt_compact implements the "last opt is winner"
+ * rule, guaranteeing that the last instance of any given option is the only
one
+ * in the results. This is a destructive operation, so a copy should be made
+ * of the input table before compacting if the user desires to examine the
original
+ * parsing data.
+ */
+BU_EXPORT extern void bu_opt_compact(struct bu_ptbl *opts);
+
+
+/* Standard option validators - if a custom option argument
+ * validation isn't needed, the functions below can be
+ * used for most valid data types. When data conversion is successful,
+ * the user_data pointer in bu_opt_data will point to the results
+ * of the string->[type] translation in order to allow a calling
+ * program to use the int/long/etc. without having to repeat the
+ * conversion */
+BU_EXPORT extern int bu_opt_arg_int(struct bu_vls *msg, struct bu_opt_data
*data);
+BU_EXPORT extern int bu_opt_arg_long(struct bu_vls *msg, struct bu_opt_data
*data);
+BU_EXPORT extern int bu_opt_arg_bool(struct bu_vls *msg, struct bu_opt_data
*data);
+BU_EXPORT extern int bu_opt_arg_double(struct bu_vls *msg, struct bu_opt_data
*data);
+BU_EXPORT extern int bu_opt_arg_string(struct bu_vls *msg, struct bu_opt_data
*data);
+
+
+/**
+ * Find and return a specific option from a bu_ptbl of options using an enum
+ * integer as the lookup key. Will only return an option if its valid entry
+ * is set to 1. A key value of -1 retrieves the bu_opt_data struct with the
+ * unknown entries stored in its args table.
+ */
+BU_EXPORT struct bu_opt_data *bu_opt_find(int key, struct bu_ptbl *opts);
+
+
+/**
+ * If an option has a message string associated with it, this function will
+ * get it. This works for both valid and invalid opts, to allow for error
+ * message retrieval. If multiple instances of a key are present, the msg
+ * from the last instance is returned. */
+BU_EXPORT const char *bu_opt_msg(int key, struct bu_ptbl *opts);
+
+/**
+ * Find and return a specific option from a bu_ptbl of options using an option
+ * string as the lookup key. Will only return an option if its valid entry
+ * is set to 1. A NULL value passed in for name retrieves the bu_opt_data
struct with the
+ * unknown entries stored in its args table.
+ */
+BU_EXPORT struct bu_opt_data *bu_opt_find_name(const char *name, struct
bu_ptbl *opts);
+
+/**
+ * If an option has a message string associated with it, this function will
+ * get it. This works for both valid and invalid opts, to allow for error
+ * message retrieval. If multiple instances of a name are present, the msg
+ * from the last instance is returned. */
+BU_EXPORT const char *bu_opt_msg_name(const char *name, struct bu_ptbl *opts);
+
+
+/** Output format options for bu_opt */
+typedef enum {
+ BU_OPT_ASCII,
+ BU_OPT_DOCBOOK,
+ BU_OPT_HTML,
+ BU_OPT_LATEX,
+ BU_OPT_MARKDOWN
+} bu_opt_format_t;
+
+/**
+ * Construct a textual description of the options defined by
+ * the array.
+ *
+ * The structure is as follows:
+ *
+ * Options |Descriptions EOL
+ * -------------- ******************
+ *
+ * Opt_col specifies how wide the options column is, and desc_cols
+ * specifies how wide the description column is.
+ *
+ *
+ */
+BU_EXPORT extern const char *bu_opt_describe(struct bu_opt_desc *ds,
bu_opt_format_t type, int opt_cols, int desc_cols);
+BU_EXPORT extern const char *bu_opt_describe_tbl(struct bu_ptbl *dtbl,
bu_opt_format_t type, int opt_cols, int desc_cols);
+
+
+/** @} */
+
+__END_DECLS
+
+#endif /* BU_OPT_H */
+
+/*
+ * Local Variables:
+ * mode: C
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * c-file-style: "stroustrup"
+ * End:
+ * ex: shiftwidth=4 tabstop=8
+ */
Property changes on: brlcad/trunk/include/bu/opt.h
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: brlcad/trunk/src/conv/gcv/gcv.cpp
===================================================================
--- brlcad/trunk/src/conv/gcv/gcv.cpp 2015-05-29 19:10:07 UTC (rev 65098)
+++ brlcad/trunk/src/conv/gcv/gcv.cpp 2015-05-29 19:24:09 UTC (rev 65099)
@@ -29,182 +29,50 @@
#include <iostream>
#include "bu.h"
-#include "optionparser.h"
-struct GcvArgs: public option::Arg
-{
- /* By default, unknown args are bad */
- static option::ArgStatus Unknown(const option::Option& UNUSED(option),
bool UNUSED(msg))
- {
- return option::ARG_ILLEGAL;
- }
- /* We may also want to require an arg */
- static option::ArgStatus Required(const option::Option& option, bool
UNUSED(msg))
- {
- if (!option.arg) return option::ARG_ILLEGAL;
- return option::ARG_OK;
- }
+/* Emulate a FASTGEN4 format option processer */
+enum fg4_opt_enums { FG4_WARN_DEFAULT_NAMES };
+struct bu_opt_desc fg4_opt_desc[2] = {
+ {FG4_WARN_DEFAULT_NAMES, 0, 0, "w", "warn-default-names", NULL, "-w",
"--warn-default-names", "File format of input file." },
+ BU_OPT_DESC_NULL
};
-
-enum FAST4OptionIndex { FAST4_UNKNOWN, FAST4_WARN_DEFAULT_NAMES };
-
-const option::Descriptor Fast4Usage[] = {
- { FAST4_UNKNOWN, 0, "", "", option::Arg::Optional, "FASTGEN 4
format\n"},
- { FAST4_WARN_DEFAULT_NAMES, 0, "w", "warn-default-names",
option::Arg::None, "-w\t --warn-default-names\t File format of input file." },
- { 0, 0, 0, 0, 0, 0 }
-};
-
-
-enum STLOptionIndex { STL_UNKNOWN, STL_UNITS };
-
-const option::Descriptor STLUsage[] = {
- { STL_UNKNOWN, 0, "", "", option::Arg::Optional, "STL format\n"},
- { STL_UNITS, 0, "u", "units", GcvArgs::Required, "-u\t --units\t Units of
input file." },
- { 0, 0, 0, 0, 0, 0 }
-};
-
-
-
void fast4_arg_process(const char *args) {
if (!args) return;
- char *input = bu_strdup(args);
- char **argv = (char **)bu_calloc(strlen(args) + 1, sizeof(char *), "argv
array");
- int argc = bu_argv_from_string(argv, strlen(args), input);
+ struct bu_opt_data *d;
+ struct bu_ptbl *results;
- option::Stats stats(Fast4Usage, argc, argv);
- option::Option *options = (option::Option *)bu_calloc(stats.options_max,
sizeof(option::Option), "options");
- option::Option *buffer= (option::Option *)bu_calloc(stats.buffer_max,
sizeof(option::Option), "options");
- option::Parser parse(Fast4Usage, argc, argv, options, buffer);
-
- if (options[FAST4_WARN_DEFAULT_NAMES]) {
- bu_log("FASTGEN 4 opt: %s:%s\n",
options[FAST4_WARN_DEFAULT_NAMES].name, options[FAST4_WARN_DEFAULT_NAMES].arg);
+ (void)bu_opt_parse_str(&results, NULL, args, fg4_opt_desc);
+ d = bu_opt_find(FG4_WARN_DEFAULT_NAMES, results);
+ if (d) {
+ bu_log("FASTGEN 4 opt: %s\n", d->name);
}
- bu_free(input, "input");
- bu_free(options, "free options");
- bu_free(buffer, "free buffer");
+ bu_opt_data_free_tbl(results);
}
+/* Emulate a STL format option processer */
+enum stl_opt_enums { STL_UNITS };
+struct bu_opt_desc stl_opt_desc[2] = {
+ {STL_UNITS, 1, 1, "u", "units", NULL, "-u unit", "--units unit", "Units
of input file." },
+ BU_OPT_DESC_NULL
+};
void stl_arg_process(const char *args) {
if (!args) return;
- char *input = bu_strdup(args);
- char **argv = (char **)bu_calloc(strlen(args) + 1, sizeof(char *), "argv
array");
- int argc = bu_argv_from_string(argv, strlen(args), input);
+ struct bu_opt_data *d;
+ struct bu_ptbl *results;
- option::Stats stats(STLUsage, argc, argv);
- option::Option *options = (option::Option *)bu_calloc(stats.options_max,
sizeof(option::Option), "options");
- option::Option *buffer= (option::Option *)bu_calloc(stats.buffer_max,
sizeof(option::Option), "options");
- option::Parser parse(STLUsage, argc, argv, options, buffer);
-
-
- if (options[STL_UNITS]) {
- bu_log("STL opt: %s:%s\n", options[STL_UNITS].name,
options[STL_UNITS].arg);
+ (void)bu_opt_parse_str(&results, NULL, args, stl_opt_desc);
+ d = bu_opt_find(STL_UNITS, results);
+ if (d) {
+ bu_log("STL opt: %s:%s\n", d->name, bu_opt_data_arg(d, 0));
}
- bu_free(input, "input");
- bu_free(options, "free options");
- bu_free(buffer, "free buffer");
+ bu_opt_data_free_tbl(results);
}
-
-
-struct TopLevelArg: public option::Arg
-{
- /* At the top level, if we don't recognize the option, assume
- * a format option parser at a lower level will and ignore it */
- static option::ArgStatus Unknown(const option::Option& option, bool
UNUSED(msg))
- {
- if (!option.arg) return option::ARG_NONE;
- if (option.arg[0] == '-') return option::ARG_IGNORE;
- return option::ARG_OK;
- }
- /* Help may or may not get a format argument */
- static option::ArgStatus Help(const option::Option& option, bool
UNUSED(msg))
- {
- if (!option.arg) return option::ARG_NONE;
- if (option.arg[0] == '-') return option::ARG_IGNORE;
- return option::ARG_OK;
- }
-
- /* Format specifiers, on the other hand, must be validated - that
- * means that the options used at the top level for format specification
- * will not be usable at any lower level */
- static option::ArgStatus Format(const option::Option& option, bool msg)
- {
- int type_int = 0;
- mime_model_t type = MIME_MODEL_UNKNOWN;
- type_int = bu_file_mime(option.arg, MIME_MODEL);
- type = (mime_model_t)type_int;
- if (type == MIME_MODEL_UNKNOWN) {
- if (msg) bu_log("Unknown format %s supplied to %s\n", option.arg,
option.name);
- return option::ARG_ILLEGAL;
- } else {
- return option::ARG_OK;
- }
- }
-};
-
-
-enum TopOptionIndex { UNKNOWN, HELP, IN_FORMAT, OUT_FORMAT, IN_OPT, OUT_OPT,
BOTH_OPT };
-
-const option::Descriptor TopUsage[] = {
- { UNKNOWN, 0, "", "", TopLevelArg::Unknown, "USAGE: gcv
[options] [fmt:]input [fmt:]output\n"},
- { HELP, 0, "h", "help", TopLevelArg::Help, "-h\t --help
[format]\t Print help and exit. If a format is specified to --help, print help
specific to that format" },
- { IN_FORMAT , 0, "", "in-format", TopLevelArg::Format, "\t --in-format\t
File format of input file." },
- { OUT_FORMAT , 0, "", "out-format", TopLevelArg::Format, "\t
--out-format\t File format of output file." },
- { IN_OPT , 0, "", "in-<OPTION>", TopLevelArg::Unknown, "\t
--in-<OPTION>\t Options to be passed only to the input handler." },
- { OUT_OPT , 0, "", "out-<OPTION>", TopLevelArg::Unknown, "\t
--out-<OPTION>\t Options to be passed only to the output handler." },
- { BOTH_OPT , 0, "", "OPTION", TopLevelArg::Unknown, "-<O>\t --<OPTION>\t
Non-prefixed options are passed to both input and output." },
- { 0, 0, 0, 0, 0, 0 }
-};
-
-
-HIDDEN void
-reassemble_argstr(struct bu_vls *instr, struct bu_vls *outstr, option::Option
*unknowns)
-{
- for (option::Option* opt = unknowns; opt; opt = opt->next()) {
- int input_only = 0;
- int output_only = 0;
- char *inputcpy = NULL;
- if (!instr || !outstr) return;
- inputcpy = bu_strdup(opt->name);
- if (!bu_strncmp(inputcpy, "--in-", 5)) input_only = 1;
- if (!bu_strncmp(inputcpy, "--out-", 5)) output_only = 1;
- char *equal_pos = strchr(inputcpy, '=');
- if (equal_pos) {
- struct bu_vls vopt = BU_VLS_INIT_ZERO;
- struct bu_vls varg = BU_VLS_INIT_ZERO;
- bu_vls_sprintf(&vopt, "%s", inputcpy);
- bu_vls_trunc(&vopt, -1 * strlen(equal_pos));
- bu_vls_sprintf(&varg, "%s", inputcpy);
- bu_vls_nibble(&varg, strlen(inputcpy) - strlen(equal_pos) + 1);
- if (!output_only) {
- (bu_vls_strlen(&vopt) == 1) ? bu_vls_printf(instr, "-%s ",
bu_vls_addr(&vopt)) : bu_vls_printf(instr, "%s ", bu_vls_addr(&vopt));
- if (bu_vls_strlen(&varg)) bu_vls_printf(instr, "%s ",
bu_vls_addr(&varg));
- }
- if (!input_only) {
- (bu_vls_strlen(&vopt) == 1) ? bu_vls_printf(outstr, "-%s ",
bu_vls_addr(&vopt)) : bu_vls_printf(outstr, "%s ", bu_vls_addr(&vopt));
- if (bu_vls_strlen(&varg)) bu_vls_printf(outstr, "%s ",
bu_vls_addr(&varg));
- }
- bu_vls_free(&vopt);
- bu_vls_free(&varg);
- } else {
- if (!output_only) {
- (strlen(opt->name) == 1) ? bu_vls_printf(instr, "-%s ",
opt->name) : bu_vls_printf(instr, "%s ", opt->name);
- if (opt->arg) bu_vls_printf(instr, "%s ", opt->arg);
- }
- if (!input_only) {
- (strlen(opt->name) == 1) ? bu_vls_printf(outstr, "-%s ",
opt->name) : bu_vls_printf(outstr, "%s ", opt->name);
- if (opt->arg) bu_vls_printf(outstr, "%s ", opt->arg);
- }
- }
- bu_free(inputcpy, "input cpy");
- }
-}
-
HIDDEN int
extract_path(struct bu_vls *path, const char *input)
{
@@ -341,51 +209,114 @@
return (int)type;
}
+int
+file_stat(struct bu_vls *UNUSED(msg), struct bu_opt_data *data)
+{
+ if (!data) return 0;
+ if (!data->args) {
+ data->valid = 0;
+ return 0;
+ }
+ if (!bu_file_exists(bu_opt_data_arg(data, 0), NULL)){
+ data->valid = 0;
+ }
+ return 0;
+}
+ int
+file_null(struct bu_vls *msg, struct bu_opt_data *data)
+{
+ if (!data) return 0;
+ if (!data->args) {
+ data->valid = 0;
+ return 0;
+ }
+ if (!bu_file_exists(bu_opt_data_arg(data, 0), NULL)){
+ data->valid = 0;
+ if (msg) bu_vls_sprintf(msg, "Error - file %s already exists!\n",
bu_opt_data_arg(data, 0));
+ }
+ return 0;
+}
+
int
+model_mime(struct bu_vls *UNUSED(msg), struct bu_opt_data *data)
+{
+ int type_int;
+ mime_model_t type = MIME_MODEL_UNKNOWN;
+ if (!data) return 0;
+ if (!data->args) {
+ data->valid = 0;
+ return 0;
+ }
+ type_int = bu_file_mime(bu_opt_data_arg(data, 0), MIME_MODEL);
+ type = (type_int < 0) ? MIME_MODEL_UNKNOWN : (mime_model_t)type_int;
+ if (type == MIME_MODEL_UNKNOWN) {
+ data->valid = 0;
+ return 0;
+ }
+ return 0;
+}
+
+
+#define gcv_help_str "Print help and exit. If a format is specified to
--help, print help specific to that format"
+enum gcv_opt_enums { GCV_HELP, IN_FILE, OUT_FILE, IN_FORMAT, OUT_FORMAT,
IN_OPTS, OUT_OPTS };
+struct bu_opt_desc gcv_opt_desc[8] = {
+ {GCV_HELP, 0, 1, "h", "help", NULL, "-h [format]",
"--help [format]", gcv_help_str},
+ {IN_FILE , 1, 1, "i", "input", &(file_stat), "-i file",
"--input file", "Input file." },
+ {OUT_FILE, 1, 1, "o", "output", &(file_null), "-o file",
"--output file", "Output file." },
+ {IN_FORMAT , 1, 1, "", "input-format", &(model_mime), "",
"--input-format format", "File format of input file." },
+ {OUT_FORMAT , 1, 1, "", "output-format", &(model_mime), "",
"--output-format format", "File format of output file." },
+ {IN_OPTS , 1, 1, "I", "input-only-opts", NULL, "-I
\"[opts]\"", "--input-only-opts \"[opts]\"", "Options to apply only while
processing input file. Quotes around the opts are always necessary, but
brackets are only necessary when supplying a single option without arguments
that would otherwise be interpreted as an argv entry by the shell, even with
quotes. Brackets will never hurt, and for robustness when scripting they
should always be used." },
+ {OUT_OPTS, 1, 1, "O", "output-only-opts", NULL, "-O
\"[opts]\"", "--output-only-opts \"[opts]\"", "Options to apply only while
preparing output file. Quotes around the opts are always necessary, but
brackets are only necessary when supplying a single option without arguments
that would otherwise be interpreted as an argv entry by the shell, even with
quotes. Brackets will never hurt, and for robustness when scripting they
should always be used." },
+ BU_OPT_DESC_NULL
+};
+
+
+int
main(int ac, char **av)
{
+ size_t i;
int fmt = 0;
int ret = 0;
- int ac_offset = 0;
const char *in_fmt = NULL;
const char *out_fmt = NULL;
mime_model_t in_type = MIME_MODEL_UNKNOWN;
mime_model_t out_type = MIME_MODEL_UNKNOWN;
struct bu_vls in_format = BU_VLS_INIT_ZERO;
+ struct bu_vls in_path_raw = BU_VLS_INIT_ZERO;
struct bu_vls in_path = BU_VLS_INIT_ZERO;
struct bu_vls out_format = BU_VLS_INIT_ZERO;
+ struct bu_vls out_path_raw = BU_VLS_INIT_ZERO;
struct bu_vls out_path = BU_VLS_INIT_ZERO;
struct bu_vls log = BU_VLS_INIT_ZERO;
struct bu_vls input_opts = BU_VLS_INIT_ZERO;
struct bu_vls output_opts = BU_VLS_INIT_ZERO;
+ struct bu_opt_data *d = NULL;
+ struct bu_ptbl *unknown_tbl = NULL;
+ struct bu_ptbl *results = NULL;
ac-=(ac>0); av+=(ac>0); // skip program name argv[0] if present
- ac_offset = (ac > 2) ? 2 : 0; // The last two argv entries must always be
the input and output paths
- /* Handle anything else as options */
- option::Stats stats(TopUsage, ac - ac_offset, av);
- option::Option *options = (option::Option *)bu_calloc(stats.options_max,
sizeof(option::Option), "options");
- option::Option *buffer= (option::Option *)bu_calloc(stats.buffer_max,
sizeof(option::Option), "options");
- option::Parser parse(TopUsage, ac - ac_offset, av, options, buffer);
+ if (ac == 0) {
+ const char *help = bu_opt_describe(gcv_opt_desc, BU_OPT_ASCII, 30, 50);
+ bu_log("%s\n", help);
+ bu_free((char *)help, "help str");
+ // TODO - print some help
+ goto cleanup;
+ }
- /* Now that we've parsed them, start using them */
- if (options[HELP] || ac == 0) {
- if (options[HELP].arg) {
- int help_type_int = bu_file_mime(options[HELP].arg, MIME_MODEL);
- switch (help_type_int) {
- case MIME_MODEL_VND_FASTGEN:
- option::printUsage(std::cout, Fast4Usage);
- break;
- case MIME_MODEL_STL:
- option::printUsage(std::cout, STLUsage);
- break;
- default:
- option::printUsage(std::cout, TopUsage);
- break;
- }
+ (void)bu_opt_parse(&results, NULL, ac, (const char **)av, gcv_opt_desc);
+ bu_opt_compact(results);
+
+ /* First, see if help was supplied */
+ d = bu_opt_find(GCV_HELP, results);
+ if (d) {
+ const char *help_fmt = bu_opt_data_arg(d, 0);
+ if (help_fmt) {
+ // TODO - generate some help based on format
} else {
- option::printUsage(std::cout, TopUsage);
+ // TODO - generate some generic gcv help
+
// TODO - figure out how to get this info from each plugin to
construct this table
// on the fly...
bu_log("\nSupported formats:\n");
@@ -401,42 +332,62 @@
bu_log(" | iges | Initial Graphics | Yes | No
|\n");
bu_log(" | | Exchange Specification | |
|\n");
bu_log("
|----------------------------------------------------------|\n");
+
}
goto cleanup;
}
- /* Any args that weren't top level args will get passed to the
- * format specific arg processing routines, after we use the known
- * top level options and the path inputs to determine what the file
- * types in question are. Steps:
- *
- * 1. Reassemble the unknown args into strings. */
- reassemble_argstr(&input_opts, &output_opts, options[UNKNOWN]);
- if (bu_vls_strlen(&input_opts) > 0) bu_log("Unknown options (input):
%s\n", bu_vls_addr(&input_opts));
- if (bu_vls_strlen(&output_opts) > 0) bu_log("Unknown options (output):
%s\n", bu_vls_addr(&output_opts));
- /*
- * 2. Use bu_argv_from_string to create new
- * arrays to be fed to the format specific option parsers.*/
+ /* TODO - Do a general check on option validity here - if anything fails,
hault and
+ * report it */
- /* TODO - determine whether we want to have a specific option prefix,
- * such as in- and out-, to identify an option as specific to the
- * input file format suboption parser only. i.e.:
- *
- * --in-tol=1.0 -> --tol=1.0 to the input file's suboptions only
- * --out-tol=2.0 -> --tol=2.0 to the input file's suboptions only
- * --tol=1.5 -> --tol=1.5 to both input and output suboptions
- *
- * consistent with top level --in-format and --out-format options
- *
- */
+ /* Did we get explicit options for an input and/or output file? */
+ d = bu_opt_find(IN_FILE, results);
+ if (d) bu_vls_sprintf(&in_path_raw, "%s", bu_opt_data_arg(d, 0));
+ d = bu_opt_find(OUT_FILE, results);
+ if (d) bu_vls_sprintf(&out_path_raw, "%s", bu_opt_data_arg(d, 0));
+
+ /* If not specified explicitly with -i or -o, the input and output paths
must always
+ * be the last two arguments supplied */
+ d = bu_opt_find(-1, results);
+ if (d) {
+ unknown_tbl = d->args;
+ bu_vls_sprintf(&in_path_raw, "%s", (const char
*)BU_PTBL_GET(unknown_tbl, BU_PTBL_LEN(unknown_tbl) - 2));
+ bu_vls_sprintf(&out_path_raw, "%s", (const char
*)BU_PTBL_GET(unknown_tbl, BU_PTBL_LEN(unknown_tbl) - 1));
+ }
+
+ /* Any unknown strings not otherwise processed are passed to both input
and output.
+ * These are deliberately placed at the beginning of the input strings, so
any
+ * input/output specific options have a chance to override them. */
+ if (unknown_tbl) {
+ for (i = 0; i < BU_PTBL_LEN(unknown_tbl) - 2; i++) {
+ bu_vls_printf(&input_opts, " %s ", (const char
*)BU_PTBL_GET(unknown_tbl, i));
+ bu_vls_printf(&output_opts, " %s ", (const char
*)BU_PTBL_GET(unknown_tbl, i));
+ }
+ if (bu_vls_strlen(&input_opts) > 0) bu_log("Unknown options (input):
%s\n", bu_vls_addr(&input_opts));
+ if (bu_vls_strlen(&output_opts) > 0) bu_log("Unknown options (output):
%s\n", bu_vls_addr(&output_opts));
+ }
+
+ /* If we have input and/or output specific options, append them now */
+ d = bu_opt_find(IN_OPTS, results);
+ if (d) {
+ bu_vls_printf(&input_opts, "%s", bu_opt_data_arg(d, 0));
+ if (bu_vls_strlen(&input_opts) > 0) bu_log("Input only opts: %s\n",
bu_opt_data_arg(d, 0));
+ }
+ d = bu_opt_find(OUT_OPTS, results);
+ if (d) {
+ bu_vls_printf(&output_opts, "%s", bu_opt_data_arg(d, 0));
+ if (bu_vls_strlen(&output_opts) > 0) bu_log("Output only opts: %s\n",
bu_opt_data_arg(d, 0));
+ }
+
+
/* See if we have input and output files specified */
- if (!extract_path(&in_path, av[ac-2])) {
- bu_vls_printf(&log, "Error: no input path identified: %s\n", av[ac-2]);
+ if (!extract_path(&in_path, bu_vls_addr(&in_path_raw))) {
+ bu_vls_printf(&log, "Error: no input path identified: %s\n",
bu_vls_addr(&in_path_raw));
ret = 1;
}
- if (!extract_path(&out_path, av[ac-1])) {
- bu_vls_printf(&log, "Error: no output path identified: %s\n", av[ac-1]);
+ if (!extract_path(&out_path, bu_vls_addr(&out_path_raw))) {
+ bu_vls_printf(&log, "Error: no output path identified: %s\n",
bu_vls_addr(&in_path_raw));
ret = 1;
}
@@ -447,8 +398,11 @@
}
/* Find out what input file type we are dealing with */
- if (options[IN_FORMAT]) {
- in_fmt = options[IN_FORMAT].arg;
+
+ /* If we have input and/or output specific options, append them now */
+ d = bu_opt_find(IN_FORMAT, results);
+ if (d) {
+ in_fmt = bu_opt_data_arg(d, 0);
} else {
/* If we aren't overridden by an option, it's worth doing file
* introspection to see if the file contents identify the input
@@ -457,13 +411,14 @@
/* fake type introspection for testing: */
//bu_vls_sprintf(&in_format, "step");
}
- fmt = parse_model_string(&in_format, &log, in_fmt, av[ac-2]);
+ fmt = parse_model_string(&in_format, &log, in_fmt,
bu_vls_addr(&in_path_raw));
in_type = (fmt < 0) ? MIME_MODEL_UNKNOWN : (mime_model_t)fmt;
in_fmt = NULL;
/* Identify output file type */
- if (options[OUT_FORMAT]) out_fmt = options[OUT_FORMAT].arg;
- fmt = parse_model_string(&out_format, &log, out_fmt, av[ac-1]);
+ d = bu_opt_find(OUT_FORMAT, results);
+ if (d) out_fmt = bu_opt_data_arg(d, 0);
+ fmt = parse_model_string(&out_format, &log, out_fmt,
bu_vls_addr(&out_path_raw));
out_type = (fmt < 0) ? MIME_MODEL_UNKNOWN : (mime_model_t)fmt;
out_fmt = NULL;
@@ -517,8 +472,6 @@
if (bu_vls_strlen(&log) > 0) bu_log("%s", bu_vls_addr(&log));
if (in_fmt) bu_free((char *)in_fmt, "input format string");
if (out_fmt) bu_free((char *)out_fmt, "output format string");
- bu_free(options, "free options");
- bu_free(buffer, "free buffer");
bu_vls_free(&in_format);
bu_vls_free(&in_path);
bu_vls_free(&out_format);
@@ -526,6 +479,7 @@
bu_vls_free(&log);
bu_vls_free(&input_opts);
bu_vls_free(&output_opts);
+ bu_opt_data_free_tbl(results);
return ret;
}
Modified: brlcad/trunk/src/libbu/CMakeLists.txt
===================================================================
--- brlcad/trunk/src/libbu/CMakeLists.txt 2015-05-29 19:10:07 UTC (rev
65098)
+++ brlcad/trunk/src/libbu/CMakeLists.txt 2015-05-29 19:24:09 UTC (rev
65099)
@@ -74,6 +74,7 @@
${MIME_C_FILE}
mread.c
observer.c
+ opt.c
parallel.c
parse.c
path.c
Added: brlcad/trunk/src/libbu/opt.c
===================================================================
--- brlcad/trunk/src/libbu/opt.c (rev 0)
+++ brlcad/trunk/src/libbu/opt.c 2015-05-29 19:24:09 UTC (rev 65099)
@@ -0,0 +1,666 @@
+/* O P T . C
+ * BRL-CAD
+ *
+ * Copyright (c) 2015 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.
+ */
+
+#include "common.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h> /* for isspace */
+
+#include "bu/log.h"
+#include "bu/malloc.h"
+#include "bu/opt.h"
+#include "bu/ptbl.h"
+#include "bu/str.h"
+#include "bu/vls.h"
+
+#define BU_OPT_DATA_GET(_od, _name) {\
+ BU_GET(_od, struct bu_opt_data); \
+ if (_name) { \
+ _od->name = _name; \
+ } else { \
+ _od->name = NULL; \
+ } \
+ _od->args = NULL; \
+ _od->valid = 1; \
+ _od->desc = NULL; \
+ _od->user_data = NULL; \
+}
+
+HIDDEN char *
+opt_process(char **eq_arg, const char *opt_candidate)
+{
+ int offset = 1;
+ char *inputcpy;
+ char *final_opt;
+ char *equal_pos;
+ if (!eq_arg && !opt_candidate) return NULL;
+ inputcpy = bu_strdup(opt_candidate);
+ if (inputcpy[1] == '-') offset++;
+ equal_pos = strchr(inputcpy, '=');
+
+ /* If we've got a single opt, things are handled differently */
+ if (offset == 1) {
+ if (strlen(opt_candidate+offset) == 1) {
+ final_opt = bu_strdup(opt_candidate+offset);
+ } else {
+ /* single letter opt, but the string is longer - the
+ * interpretation in this context is everything after
+ * the first letter is arg.*/
+ struct bu_vls vopt = BU_VLS_INIT_ZERO;
+ struct bu_vls varg = BU_VLS_INIT_ZERO;
+ bu_vls_strncat(&vopt, inputcpy+1, 1);
+ bu_vls_sprintf(&varg, "%s", inputcpy);
+ bu_vls_nibble(&varg, 2);
+
+#if 0
+ /* A possible exception is an equals sign, e.g. -s=1024 - in that
+ * instance, the expectation might be that = would be interpreted
+ * as an assignment. This means that to get the literal =1024 as
+ * an option, you would need a space after the s, e.g.: -s =1024
+ *
+ * For now, commented out to favor consistent behavior over what
+ * "looks right" - may be worth revisiting or even an option at
+ * some point...*/
+
+ if (equal_pos && equal_pos == inputcpy+2) {
+ bu_vls_nibble(&varg, 1);
+ }
+#endif
+
+ (*eq_arg) = bu_strdup(bu_vls_addr(&varg));
+ final_opt = bu_strdup(bu_vls_addr(&vopt));
+ bu_vls_free(&vopt);
+ bu_vls_free(&varg);
+ }
+ } else {
+ if (equal_pos) {
+ struct bu_vls vopt = BU_VLS_INIT_ZERO;
+ struct bu_vls varg = BU_VLS_INIT_ZERO;
+ bu_vls_sprintf(&vopt, "%s", inputcpy);
+ bu_vls_trunc(&vopt, -1 * strlen(equal_pos));
+ bu_vls_nibble(&vopt, offset);
+ bu_vls_sprintf(&varg, "%s", inputcpy);
+ bu_vls_nibble(&varg, strlen(inputcpy) - strlen(equal_pos) + 1);
+ (*eq_arg) = bu_strdup(bu_vls_addr(&varg));
+ final_opt = bu_strdup(bu_vls_addr(&vopt));
+ bu_vls_free(&vopt);
+ bu_vls_free(&varg);
+ } else {
+ final_opt = bu_strdup(opt_candidate+offset);
+ }
+ }
+ bu_free(inputcpy, "cleanup working copy");
+ return final_opt;
+}
+
+void
+bu_opt_compact(struct bu_ptbl *opts)
+{
+ int i;
+ int ptblpos = BU_PTBL_LEN(opts) - 1;
+ struct bu_ptbl tbl;
+ bu_ptbl_init(&tbl, 8, "local table");
+ while (ptblpos >= 0) {
+ struct bu_opt_data *data = (struct bu_opt_data *)BU_PTBL_GET(opts,
ptblpos);
+ if (!data) {
+ ptblpos--;
+ continue;
+ }
+ bu_ptbl_ins(&tbl, (long *)data);
+ BU_PTBL_CLEAR_I(opts, ptblpos);
+ for (i = ptblpos - 1; i >= 0; i--) {
+ struct bu_opt_data *dc = (struct bu_opt_data *)BU_PTBL_GET(opts, i);
+ if ((dc && dc->desc && data->desc) && dc->desc->index ==
data->desc->index) {
+ bu_free(dc, "free duplicate");
+ BU_PTBL_CLEAR_I(opts, i);
+ }
+ }
+ ptblpos--;
+ }
+ bu_ptbl_reset(opts);
+ for (i = BU_PTBL_LEN(&tbl) - 1; i >= 0; i--) {
+ bu_ptbl_ins(opts, BU_PTBL_GET(&tbl, i));
+ }
+ bu_ptbl_free(&tbl);
+}
+
+/* This implements criteria for deciding when an argv string is
+ * an option. Right now the criteria are:
+ *
+ * 1. Must have a '-' char as first character
+ * 2. Must not have white space characters present in the string.
+ */
+HIDDEN int
+is_opt(const char *opt) {
+ size_t i = 0;
+ if (!opt) return 0;
+ if (!strlen(opt)) return 0;
+ if (opt[0] != '-') return 0;
+ for (i = 1; i < strlen(opt); i++) {
+ if (isspace(opt[i])) return 0;
+ }
+ return 1;
+}
+
+HIDDEN struct bu_ptbl *
+bu_opt_parse_internal(int argc, const char **argv, struct bu_opt_desc *ds,
struct bu_ptbl *dptbl, struct bu_vls *UNUSED(msgs))
+{
+ int i = 0;
+ int offset = 0;
+ const char *ns = NULL;
+ struct bu_ptbl *opt_data;
+ struct bu_opt_data *unknowns = NULL;
+ if (!argv || (!ds && !dptbl) || (ds && dptbl)) return NULL;
+
+ BU_GET(opt_data, struct bu_ptbl);
+ bu_ptbl_init(opt_data, 8, "opt_data");
+
+ /* Now identify opt/arg pairs.*/
+ while (i < argc) {
+ int desc_found = 0;
+ int desc_ind = 0;
+ size_t arg_cnt = 0;
+ char *opt = NULL;
+ char *eq_arg = NULL;
+ struct bu_opt_data *data = NULL;
+ struct bu_opt_desc *desc = NULL;
+ /* If 'opt' isn't an option, make a container for non-option values and
build it up until
+ * we reach an option */
+ if (!is_opt(argv[i])) {
+ if (!unknowns) {
+ BU_OPT_DATA_GET(unknowns, NULL);
+ BU_GET(unknowns->args, struct bu_ptbl);
+ bu_ptbl_init(unknowns->args, 8, "args init");
+ }
+ ns = bu_strdup(argv[i]);
+ bu_ptbl_ins(unknowns->args, (long *)ns);
+ i++;
+ while (i < argc && !is_opt(argv[i])) {
+ ns = bu_strdup(argv[i]);
+ bu_ptbl_ins(unknowns->args, (long *)ns);
+ i++;
+ }
+ continue;
+ }
+
+ /* It may be that an = has been used instead of a space. Handle that,
and
+ * strip leading '-' characters. Also, short-opt options may not have a
+ * space between their option and the argument. That is also handled
here */
+ opt = opt_process(&eq_arg, argv[i]);
+
+ /* Find the corresponding desc, if we have one */
+ if (ds) {
+ desc = &(ds[0]);
+ } else {
+ desc = (struct bu_opt_desc *)BU_PTBL_GET(dptbl, 0);
+ }
+ while (!desc_found && (desc && desc->index != -1)) {
+ if (BU_STR_EQUAL(opt+offset, desc->shortopt) ||
BU_STR_EQUAL(opt+offset, desc->longopt)) {
+ desc_found = 1;
+ continue;
+ }
+ desc_ind++;
+ if (ds) {
+ desc = &(ds[desc_ind]);
+ } else {
+ desc = (struct bu_opt_desc *)BU_PTBL_GET(dptbl, desc_ind);
+ }
+ }
+
+ /* If we don't know what we're dealing with, keep going */
+ if (!desc_found) {
+ struct bu_vls rebuilt_opt = BU_VLS_INIT_ZERO;
+ if (!unknowns) {
+ BU_OPT_DATA_GET(unknowns, NULL);
+ BU_GET(unknowns->args, struct bu_ptbl);
+ bu_ptbl_init(unknowns->args, 8, "args init");
+ }
+ if (strlen(opt) == 1) {
+ bu_vls_sprintf(&rebuilt_opt, "-%s", opt);
+ } else {
+ bu_vls_sprintf(&rebuilt_opt, "--%s", opt);
+ }
+ bu_ptbl_ins(unknowns->args, (long
*)bu_strdup(bu_vls_addr(&rebuilt_opt)));
+ bu_free(opt, "free opt");
+ bu_vls_free(&rebuilt_opt);
+ if (eq_arg)
+ bu_ptbl_ins(unknowns->args, (long *)eq_arg);
+ i++;
+ continue;
+ }
+
+ /* Initialize with opt */
+ BU_OPT_DATA_GET(data, opt);
+ data->desc = desc;
+ if (eq_arg) {
+ /* Okay, we actually need it - initialize the arg table */
+ BU_GET(data->args, struct bu_ptbl);
+ bu_ptbl_init(data->args, 8, "args init");
+ bu_ptbl_ins(data->args, (long *)eq_arg);
+ arg_cnt = 1;
+ }
+
+ /* handled the option - any remaining processing is on args, if any*/
+ i = i + 1;
+
+ /* If we already got an arg from the equals mechanism and we aren't
+ * supposed to have one, we're invalid */
+ if (arg_cnt > 0 && desc->arg_cnt_max == 0) data->valid = 0;
+
+ /* If we're looking for args, do so */
+ if (desc->arg_cnt_max > 0) {
+ while (arg_cnt < desc->arg_cnt_max && i < argc && !is_opt(argv[i]))
{
+ ns = bu_strdup(argv[i]);
+ if (!data->args) {
+ /* Okay, we actually need it - initialize the arg table */
+ BU_GET(data->args, struct bu_ptbl);
+ bu_ptbl_init(data->args, 8, "args init");
+ }
+ bu_ptbl_ins(data->args, (long *)ns);
+ i++;
+ arg_cnt++;
+ }
+ if (arg_cnt < desc->arg_cnt_min) {
+ data->valid = 0;
+ }
+ }
+
+ /* Now see if we need to validate the arg(s) */
+ if (desc->arg_process) {
+ int arg_offset = (*desc->arg_process)(NULL, data);
+ if (arg_offset < 0) {
+ /* arg(s) present but not associated with opt, back them out of
data
+ *
+ * test example for this - color option
+ *
+ * --color 200/30/10 input output (1 arg to color, 3 args
total)
+ * --color 200 30 10 input output (3 args to color, 5 total)
+ *
+ * to handle the color case, need to process all three in
first case,
+ * recognize that first one is sufficient, and release the
latter two.
+ * for the second case all three are necessary
+ *
+ * */
+ int len = BU_PTBL_LEN(data->args);
+ int j = 0;
+ i = i + arg_offset;
+ while (j > arg_offset) {
+ bu_free((void *)BU_PTBL_GET(data->args, len + j - 1), "free
str");
+ j--;
+ }
+ bu_ptbl_trunc(data->args, len + arg_offset);
+ }
+ }
+ bu_ptbl_ins(opt_data, (long *)data);
+ }
+ if (unknowns) bu_ptbl_ins(opt_data, (long *)unknowns);
+
+ return opt_data;
+}
+
+int
+bu_opt_parse(struct bu_ptbl **tbl, struct bu_vls *msgs, int ac, const char
**argv, struct bu_opt_desc *ds)
+{
+ struct bu_ptbl *results = NULL;
+ if (!tbl || !argv || !ds) return 1;
+ results = bu_opt_parse_internal(ac, argv, ds, NULL, msgs);
+ if (results) {
+ (*tbl) = results;
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+int
+bu_opt_parse_str(struct bu_ptbl **tbl, struct bu_vls *msgs, const char *str,
struct bu_opt_desc *ds)
+{
+ int ret = 0;
+ char *input = NULL;
+ char **argv = NULL;
+ int argc = 0;
+ if (!tbl || !str || !ds) return 1;
+ input = bu_strdup(str);
+ argv = (char **)bu_calloc(strlen(input) + 1, sizeof(char *), "argv array");
+ argc = bu_argv_from_string(argv, strlen(input), input);
+
+ ret = bu_opt_parse(tbl, msgs, argc, (const char **)argv, ds);
+
+ bu_free(input, "free str copy");
+ bu_free(argv, "free argv memory");
+ return ret;
+}
+
+int
+bu_opt_parse_dtbl(struct bu_ptbl **tbl, struct bu_vls *msgs, int ac, const
char **argv, struct bu_ptbl *dtbl)
+{
+ struct bu_ptbl *results = NULL;
+ if (!tbl || !argv || !dtbl) return 1;
+ results = bu_opt_parse_internal(ac, argv, NULL, dtbl, msgs);
+ if (results) {
+ (*tbl) = results;
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+int
+bu_opt_parse_str_dtbl(struct bu_ptbl **tbl, struct bu_vls *msgs, const char
*str, struct bu_ptbl *dtbl)
+{
+ int ret = 0;
+ char *input = NULL;
+ char **argv = NULL;
+ int argc = 0;
+ if (!tbl || !str || !dtbl) return 1;
+ input = bu_strdup(str);
+ argv = (char **)bu_calloc(strlen(input) + 1, sizeof(char *), "argv array");
+ argc = bu_argv_from_string(argv, strlen(input), input);
+
+ ret = bu_opt_parse_dtbl(tbl, msgs, argc, (const char **)argv, dtbl);
+
+ bu_free(input, "free str copy");
+ bu_free(argv, "free argv memory");
+ return ret;
+}
+
+
+struct bu_opt_data *
+bu_opt_find_name(const char *name, struct bu_ptbl *opts)
+{
+ size_t i;
+ if (!opts) return NULL;
+
+ for (i = 0; i < BU_PTBL_LEN(opts); i++) {
+ struct bu_opt_data *opt = (struct bu_opt_data *)BU_PTBL_GET(opts, i);
+ /* Don't check the unknown opts - they were already marked as not
+ * valid opts per the current descriptions in the parsing pass */
+ if (!name && !opt->name) return opt;
+ if (!opt->name) continue;
+ if (!opt->desc) continue;
+ if (BU_STR_EQUAL(opt->desc->shortopt, name) ||
BU_STR_EQUAL(opt->desc->longopt, name)) {
+ /* option culling guarantees us one "winner" if multiple instances
+ * of an option were originally supplied, so if we find a match we
+ * have found what we wanted. Now, just need to check validity */
+ return (opt->valid) ? opt : NULL;
+ }
+ }
+ return NULL;
+}
+
+struct bu_opt_data *
+bu_opt_find(int key, struct bu_ptbl *opts)
+{
+ size_t i;
+ if (!opts) return NULL;
+
+ for (i = 0; i < BU_PTBL_LEN(opts); i++) {
+ struct bu_opt_data *opt = (struct bu_opt_data *)BU_PTBL_GET(opts, i);
+ /* Don't check the unknown opts - they were already marked as not
+ * valid opts per the current descriptions in the parsing pass */
+ if (key == -1 && !opt->name) return opt;
+ if (!opt->name) continue;
+ if (!opt->desc) continue;
+ if (key == opt->desc->index) {
+ /* option culling guarantees us one "winner" if multiple instances
+ * of an option were originally supplied, so if we find a match we
+ * have found what we wanted. Now, just need to check validity */
+ return (opt->valid) ? opt : NULL;
+ }
+ }
+ return NULL;
+}
+
+void
+bu_opt_data_init(struct bu_opt_data *d)
+{
+ if (!d) return;
+ d->desc = NULL;
+ d->valid = 0;
+ d->name = NULL;
+ d->args = NULL;
+ d->user_data = NULL;
+}
+
+void
+bu_opt_data_free(struct bu_opt_data *d)
+{
+ if (!d) return;
+ if (d->name) bu_free((char *)d->name, "free data name");
+ if (d->user_data) bu_free(d->user_data, "free user data");
+ if (d->args) {
+ size_t i;
+ for (i = 0; i < BU_PTBL_LEN(d->args); i++) {
+ char *arg = (char *)BU_PTBL_GET(d->args, i);
+ bu_free(arg, "free arg");
+ }
+ bu_ptbl_free(d->args);
+ BU_PUT(d->args, struct bu_ptbl);
+ }
+}
+
+
+void
+bu_opt_data_free_tbl(struct bu_ptbl *tbl)
+{
+ size_t i;
+ if (!tbl) return;
+ for (i = 0; i < BU_PTBL_LEN(tbl); i++) {
+ struct bu_opt_data *opt = (struct bu_opt_data *)BU_PTBL_GET(tbl, i);
+ bu_opt_data_free(opt);
+ }
+ bu_ptbl_free(tbl);
+ BU_PUT(tbl, struct bu_ptbl);
+}
+
+const char *
+bu_opt_data_arg(struct bu_opt_data *d, int ind)
+{
+ if (!d) return NULL;
+ if (d->args) {
+ if (ind > (int)(BU_PTBL_LEN(d->args) - 1)) return NULL;
+ return (const char *)BU_PTBL_GET(d->args, ind);
+ }
+ return NULL;
+}
+
+void
+bu_opt_desc_init(struct bu_opt_desc *d)
+{
+ if (!d) return;
+ d->index = -1;
+ d->arg_cnt_min = 0;
+ d->arg_cnt_max = 0;
+ d->shortopt = NULL;
+ d->longopt = NULL;
+ d->arg_process = NULL;
+ d->shortopt_doc = NULL;
+ d->longopt_doc = NULL;
+ d->help_string = NULL;
+}
+
+void
+bu_opt_desc_set(struct bu_opt_desc *d, int ind,
+ size_t min, size_t max, const char *shortopt,
+ const char *longopt, bu_opt_arg_process_t arg_process,
+ const char *shortopt_doc, const char *longopt_doc, const char *help_str)
+{
+ if (!d) return;
+ d->index = ind;
+ d->arg_cnt_min = min;
+ d->arg_cnt_max = max;
+ d->shortopt = shortopt;
+ d->longopt = longopt;
+ d->arg_process = arg_process;
+ d->shortopt_doc= shortopt_doc;
+ d->longopt_doc = longopt_doc;
+ d->help_string = help_str;
+}
+
+void
+bu_opt_desc_free(struct bu_opt_desc *d)
+{
+ if (!d) return;
+ if (d->shortopt) bu_free((char *)d->shortopt, "shortopt");
+ if (d->longopt) bu_free((char *)d->longopt, "shortopt");
+ if (d->shortopt_doc) bu_free((char *)d->shortopt_doc, "shortopt");
+ if (d->longopt_doc) bu_free((char *)d->longopt_doc, "shortopt");
+ if (d->help_string) bu_free((char *)d->help_string, "shortopt");
+}
+
+void
+bu_opt_desc_free_tbl(struct bu_ptbl *tbl)
+{
+ size_t i;
+ if (!tbl) return;
+ for (i = 0; i < BU_PTBL_LEN(tbl); i++) {
+ struct bu_opt_desc *opt = (struct bu_opt_desc *)BU_PTBL_GET(tbl, i);
+ bu_opt_desc_free(opt);
+ }
+ bu_ptbl_free(tbl);
+ BU_PUT(tbl, struct bu_ptbl);
+}
+
+HIDDEN void
+wrap_help(struct bu_vls *help, int offset, int len)
+{
+ int i, sc = 0;
+ char *input = NULL;
+ char **argv = NULL;
+ int argc = 0;
+ struct bu_vls new_help = BU_VLS_INIT_ZERO;
+ struct bu_vls working = BU_VLS_INIT_ZERO;
+ bu_vls_trunc(&working, 0);
+ bu_vls_trunc(&new_help, 0);
+
+ input = bu_strdup(bu_vls_addr(help));
+ argv = (char **)bu_calloc(strlen(input) + 1, sizeof(char *), "argv array");
+ argc = bu_argv_from_string(argv, strlen(input), input);
+
+ for (i = 0; i < argc; i++) {
+ int avl = strlen(argv[i]);
+ if ((int)bu_vls_strlen(&working) + avl + 1 > len) {
+ bu_vls_printf(&new_help, "%s\n", bu_vls_addr(&working));
+ for (sc = 0; sc < offset; sc++) bu_vls_printf(&new_help, " ");
+ bu_vls_trunc(&working, 0);
+ }
+ bu_vls_printf(&working, "%s ", argv[i]);
+ }
+ bu_vls_printf(&new_help, "%s", bu_vls_addr(&working));
+
+ bu_vls_sprintf(help, "%s", bu_vls_addr(&new_help));
+ bu_vls_free(&new_help);
+ bu_vls_free(&working);
+ bu_free(input, "input");
+ bu_free(argv, "argv");
+}
+
+HIDDEN const char *
+bu_opt_describe(struct bu_opt_desc *ds, bu_opt_format_t UNUSED(type), int
opt_cols, int desc_cols)
+{
+ size_t i = 0;
+ size_t j = 0;
+ size_t opt_cnt = 0;
+ int sc = 0;
+ const char *finalized;
+ struct bu_vls description = BU_VLS_INIT_ZERO;
+ int *status;
+ if (!ds || ds[0].index == -1) return NULL;
+ while (ds[i].index != -1) i++;
+ opt_cnt = i;
+ status = (int *)bu_calloc(opt_cnt, sizeof(int), "opt status");
+ i = 0;
+ while (i < opt_cnt) {
+ struct bu_opt_desc *curr = &(ds[i]);
+ if (!status[i]) {
+ struct bu_vls opts = BU_VLS_INIT_ZERO;
+ struct bu_vls help_str = BU_VLS_INIT_ZERO;
+ /* Collect the short options first - may be multiple instances with
+ * the same index defining aliases, so accumulate all of them. */
+ j = i;
+ while (j < opt_cnt) {
+ struct bu_opt_desc *d = &(ds[j]);
+ if (d->index == curr->index) {
+ int new_len = strlen(d->shortopt_doc);
+ if (new_len > 0) {
+ if ((int)bu_vls_strlen(&opts) + new_len + 2 > opt_cols
+ desc_cols) {
+ bu_vls_printf(&description, "%s\n",
bu_vls_addr(&opts));
+ bu_vls_sprintf(&opts, "%s, ", d->shortopt_doc);
+ } else {
+ bu_vls_printf(&opts, "%s, ", d->shortopt_doc);
+ }
+ }
+ if (strlen(d->help_string) > 0) bu_vls_sprintf(&help_str,
"%s", d->help_string);
+ }
+ j++;
+ }
+ j = i;
+ while (j < opt_cnt) {
+ struct bu_opt_desc *d = &(ds[j]);
+ if (d->index == curr->index) {
+ int new_len = strlen(d->longopt_doc);
+ if (new_len > 0) {
+ if ((int)bu_vls_strlen(&opts) + new_len + 2 > opt_cols
+ desc_cols) {
+ bu_vls_printf(&description, "%s\n",
bu_vls_addr(&opts));
+ bu_vls_sprintf(&opts, "%s, ", d->longopt_doc);
+ } else {
+ bu_vls_printf(&opts, "%s, ", d->longopt_doc);
+ }
+ }
+ }
+ j++;
+ }
+
+ bu_vls_trunc(&opts, -2);
+ bu_vls_printf(&description, "%s", bu_vls_addr(&opts));
+ if ((int)bu_vls_strlen(&opts) > opt_cols) {
+ bu_vls_printf(&description, "\n");
+ for (sc = 0; sc < opt_cols; sc++) bu_vls_printf(&description, "
");
+ } else {
+ for (sc = 0; sc < opt_cols - (int)bu_vls_strlen(&opts); sc++)
bu_vls_printf(&description, " ");
+ }
+ if ((int)bu_vls_strlen(&help_str) > desc_cols) {
+ wrap_help(&help_str, opt_cols, desc_cols);
+ }
+ bu_vls_printf(&description, "%s\n", bu_vls_addr(&help_str));
+ bu_vls_free(&help_str);
+ bu_vls_free(&opts);
+ status[i] = 1;
+ }
+ i++;
+ }
+ finalized = bu_strdup(bu_vls_addr(&description));
+ bu_vls_free(&description);
+ return finalized;
+}
+
+
+
+
+/*
+ * Local Variables:
+ * mode: C
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * c-file-style: "stroustrup"
+ * End:
+ * ex: shiftwidth=4 tabstop=8
+ */
Property changes on: brlcad/trunk/src/libbu/opt.c
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: brlcad/trunk/src/libbu/tests/CMakeLists.txt
===================================================================
--- brlcad/trunk/src/libbu/tests/CMakeLists.txt 2015-05-29 19:10:07 UTC (rev
65098)
+++ brlcad/trunk/src/libbu/tests/CMakeLists.txt 2015-05-29 19:24:09 UTC (rev
65099)
@@ -430,6 +430,48 @@
add_test(NAME bu_badmagic_misaligned COMMAND tester_bu_badmagic 4)
#
+# *********** opt.c tests ************
+#
+
+BRLCAD_ADDEXEC(tester_bu_opt opt.c libbu NO_INSTALL)
+add_test(NAME bu_opt_0 COMMAND tester_bu_opt 0)
+add_test(NAME bu_opt_1_00 COMMAND tester_bu_opt 1)
+add_test(NAME bu_opt_1_01 COMMAND tester_bu_opt 1 -v1)
+add_test(NAME bu_opt_1_02 COMMAND tester_bu_opt 1 -v 1)
+add_test(NAME bu_opt_1_03 COMMAND tester_bu_opt 1 -v=1)
+add_test(NAME bu_opt_1_04 COMMAND tester_bu_opt 1 --v 1)
+add_test(NAME bu_opt_1_05 COMMAND tester_bu_opt 1 --v=1)
+add_test(NAME bu_opt_1_06 COMMAND tester_bu_opt 1 --verbosity 1)
+add_test(NAME bu_opt_1_07 COMMAND tester_bu_opt 1 --verbosity=1)
+add_test(NAME bu_opt_1_08 COMMAND tester_bu_opt 1 --verbosity 4)
+add_test(NAME bu_opt_1_09 COMMAND tester_bu_opt 1 --verbosity=4)
+add_test(NAME bu_opt_1_10 COMMAND tester_bu_opt 1 -h)
+add_test(NAME bu_opt_1_11 COMMAND tester_bu_opt 1 -?)
+add_test(NAME bu_opt_1_12 COMMAND tester_bu_opt 1 --help)
+add_test(NAME bu_opt_1_13 COMMAND tester_bu_opt 1 --help=4)
+add_test(NAME bu_opt_1_14 COMMAND tester_bu_opt 1 -?4)
+add_test(NAME bu_opt_1_15 COMMAND tester_bu_opt 1 -? 4)
+add_test(NAME bu_opt_1_16 COMMAND tester_bu_opt 1 -?=4)
+add_test(NAME bu_opt_1_17 COMMAND tester_bu_opt 1 --?4)
+add_test(NAME bu_opt_1_18 COMMAND tester_bu_opt 1 --? 4)
+add_test(NAME bu_opt_1_19 COMMAND tester_bu_opt 1 --?=4)
+add_test(NAME bu_opt_2_00 COMMAND tester_bu_opt 2 -c)
+add_test(NAME bu_opt_2_01 COMMAND tester_bu_opt 2 --color)
+add_test(NAME bu_opt_2_02 COMMAND tester_bu_opt 2 --color 200/10/30)
+add_test(NAME bu_opt_2_03 COMMAND tester_bu_opt 2 --color 200/10/30 35 33)
+add_test(NAME bu_opt_2_04 COMMAND tester_bu_opt 2 --color 200 10 30)
+add_test(NAME bu_opt_2_05 COMMAND tester_bu_opt 2 --color 200 10 30 35 33)
+add_test(NAME bu_opt_2_06 COMMAND tester_bu_opt 2 --color file 200 35 33)
+add_test(NAME bu_opt_2_07 COMMAND tester_bu_opt 2 -c 200/10/30)
+add_test(NAME bu_opt_2_08 COMMAND tester_bu_opt 2 -c 200/10/30 35 33)
+add_test(NAME bu_opt_2_09 COMMAND tester_bu_opt 2 -c 200 10 30)
+add_test(NAME bu_opt_2_10 COMMAND tester_bu_opt 2 -c 200 10 30 35 33)
+add_test(NAME bu_opt_2_11 COMMAND tester_bu_opt 2 -c file 200 35 33)
+add_test(NAME bu_opt_2_12 COMMAND tester_bu_opt 2 --color=200 10 30)
+add_test(NAME bu_opt_2_13 COMMAND tester_bu_opt 2 --color=200/10/30)
+add_test(NAME bu_opt_2_14 COMMAND tester_bu_opt 2 --color=200 10 30 file)
+
+#
# *********** date-time.c tests ************
#
Added: brlcad/trunk/src/libbu/tests/opt.c
===================================================================
--- brlcad/trunk/src/libbu/tests/opt.c (rev 0)
+++ brlcad/trunk/src/libbu/tests/opt.c 2015-05-29 19:24:09 UTC (rev 65099)
@@ -0,0 +1,171 @@
+/* O P T . C
+ * BRL-CAD
+ *
+ * Copyright (c) 2015 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.
+ */
+
+#include "common.h"
+#include <ctype.h>
+#include "bu.h"
+#include "bn.h"
+#include "string.h"
+
+int
+d1_verbosity(struct bu_vls *msg, struct bu_opt_data *data)
+{
+ int verb;
+ if (!data) return -1;
+ if (msg) bu_vls_sprintf(msg, "d1");
+ sscanf((const char *)BU_PTBL_GET(data->args, 0), "%d", &verb);
+ if (verb < 0 || verb > 3) data->valid = 0;
+ return 0;
+}
+
+int
+isnum(const char *str) {
+ int i, sl;
+ if (!str) return 0;
+ sl = strlen(str);
+ for (i = 0; i < sl; i++) if (!isdigit(str[i])) return 0;
+ return 1;
+}
+
+int
+d2_color(struct bu_vls *msg, struct bu_opt_data *data)
+{
+ unsigned int *rgb;
+ int color_arg_cnt;
+ if (!data) return 0;
+ if (!data->args) {
+ data->valid = 0;
+ return 0;
+ }
+ if (msg) bu_vls_sprintf(msg, "d2");
+
+ color_arg_cnt = BU_PTBL_LEN(data->args);
+ rgb = (unsigned int *)bu_calloc(3, sizeof(unsigned int), "fastf_t array");
+
+ /* First, see if the first string converts to rgb */
+ if (!bu_str_to_rgb((char *)BU_PTBL_GET(data->args, 0), (unsigned char
*)&rgb)) {
+ /* nope - maybe we have 3 args? */
+ if (BU_PTBL_LEN(data->args) == 3) {
+ int rn, gn, bn = 0;
+ if (isnum((const char *)BU_PTBL_GET(data->args, 0)))
+ rn = sscanf((const char *)BU_PTBL_GET(data->args, 0), "%02x",
&rgb[0]);
+ if (isnum((const char *)BU_PTBL_GET(data->args, 1)))
+ gn = sscanf((const char *)BU_PTBL_GET(data->args, 1), "%02x",
&rgb[1]);
+ if (isnum((const char *)BU_PTBL_GET(data->args, 2)))
+ bn = sscanf((const char *)BU_PTBL_GET(data->args, 2), "%02x",
&rgb[2]);
+ if (rn != 1 || gn != 1 || bn != 1) {
+ data->valid = 0;
+ bu_free(rgb, "free rgb");
+ } else {
+ data->user_data = (void *)rgb;
+ }
+ } else {
+ data->valid = 0;
+ bu_free(rgb, "free rgb");
+ }
+ } else {
+ /* yep - if we've got more args, tell the option parser we don't need
them */
+ data->user_data = (void *)rgb;
+ if (BU_PTBL_LEN(data->args) > 1) return 1 - BU_PTBL_LEN(data->args);
+ }
+
+ return 0;
+}
+
+void
+print_results(struct bu_ptbl *results)
+{
+ size_t i = 0;
+ struct bu_opt_data *data;
+ for (i = 0; i < BU_PTBL_LEN(results); i++) {
+ data = (struct bu_opt_data *)BU_PTBL_GET(results, i);
+ bu_log("option name: %s\n", data->name);
+ if (data->args) {
+ size_t j = 0;
+ bu_log("option args: ");
+ for (j = 0; j < BU_PTBL_LEN(data->args); j++) {
+ char *arg = (char *)BU_PTBL_GET(data->args, j);
+ bu_log("%s ", arg);
+ }
+ bu_log("\n");
+ }
+ bu_log("option is valid: %d\n\n", data->valid);
+ }
+}
+
+#define help_str "Print help string and exit."
+
+int
+main(int argc, const char **argv)
+{
+ int function_num;
+ struct bu_ptbl *results = NULL;
+
+ enum d1_opt_ind {D1_HELP, D1_VERBOSITY};
+ struct bu_opt_desc d1[4] = {
+ {D1_HELP, 0, 0, "h", "help", NULL, "-h",
"--help", help_str},
+ {D1_HELP, 0, 0, "?", "", NULL, "-?", "", help_str},
+ {D1_VERBOSITY, 0, 1, "v", "verbosity", &(d1_verbosity), "-v #",
"--verbosity #", "Set verbosity (range is 0 to 3)"},
+ BU_OPT_DESC_NULL
+ };
+
+ enum d2_opt_ind {D2_HELP, D2_COLOR};
+ struct bu_opt_desc d2[4] = {
+ {D2_HELP, 0, 0, "h", "help", NULL, "-h", "--help", help_str},
+ {D2_COLOR, 1, 3, "C", "color", &(d2_color), "-c r/g/b", "--color
r/g/b", "Set color"},
+ BU_OPT_DESC_NULL
+ };
+
+
+ if (argc < 2)
+ bu_exit(1, "ERROR: wrong number of parameters");
+
+ sscanf(argv[1], "%d", &function_num);
+
+ switch (function_num) {
+ case 0:
+ (void)bu_opt_parse(&results, NULL, 0, NULL, NULL);
+ return (results == NULL) ? 0 : 1;
+ break;
+ case 1:
+ (void)bu_opt_parse(&results, NULL, argc-2, argv+2, d1);
+ break;
+ case 2:
+ (void)bu_opt_parse(&results, NULL, argc-2, argv+2, d2);
+ break;
+ }
+
+ if (results) {
+ bu_opt_compact(results);
+ print_results(results);
+ }
+
+ return 0;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * c-file-style: "stroustrup"
+ * End:
+ * ex: shiftwidth=4 tabstop=8
+ */
Property changes on: brlcad/trunk/src/libbu/tests/opt.c
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
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