From 984ffe6e88d705abc9b87b0428403e811e9719f4 Mon Sep 17 00:00:00 2001 From: Daniel Beer Date: Fri, 13 Aug 2010 15:14:15 +1200 Subject: [PATCH] Separate option database. --- Makefile | 2 +- cproc.c | 193 +++++++++++++++++++------------------------------------ cproc.h | 33 ---------- gdb.c | 18 +----- main.c | 2 + opdb.c | 150 ++++++++++++++++++++++++++++++++++++++++++ opdb.h | 65 +++++++++++++++++++ 7 files changed, 285 insertions(+), 178 deletions(-) create mode 100644 opdb.c create mode 100644 opdb.h diff --git a/Makefile b/Makefile index 3eaeda6..8716326 100644 --- a/Makefile +++ b/Makefile @@ -56,7 +56,7 @@ install: mspdebug mspdebug.man mspdebug: main.o fet.o rf2500.o dis.o uif.o olimex.o ihex.o elf32.o stab.o \ util.o bsl.o sim.o symmap.o gdb.o btree.o rtools.o sym.o devcmd.o \ cproc.o vector.o cproc_util.o expr.o fet_error.o binfile.o fet_db.o \ - usbutil.o titext.o srec.o device.o coff.o + usbutil.o titext.o srec.o device.o coff.o opdb.o $(CC) $(LDFLAGS) $(MACPORTS_LDFLAGS) -o $@ $^ -lusb $(READLINE_LIBS) .c.o: diff --git a/cproc.c b/cproc.c index e1882fd..fb54b1a 100644 --- a/cproc.c +++ b/cproc.c @@ -28,6 +28,7 @@ #include #endif +#include "opdb.h" #include "expr.h" #include "cproc.h" #include "vector.h" @@ -36,28 +37,12 @@ struct cproc { struct vector command_list; - struct vector option_list; int lists_modified; int modify_flags; int in_reader_loop; }; -static struct cproc_option *find_option(cproc_t cp, const char *name) -{ - int i; - - for (i = 0; i < cp->option_list.size; i++) { - struct cproc_option *opt = - VECTOR_PTR(cp->option_list, i, struct cproc_option); - - if (!strcasecmp(opt->name, name)) - return opt; - } - - return NULL; -} - static struct cproc_command *find_command(cproc_t cp, const char *name) { int i; @@ -90,10 +75,6 @@ static void sort_lists(cproc_t cp) qsort(cp->command_list.ptr, cp->command_list.size, cp->command_list.elemsize, namelist_cmp); - if (cp->option_list.ptr) - qsort(cp->option_list.ptr, cp->option_list.size, - cp->option_list.elemsize, namelist_cmp); - cp->lists_modified = 0; } @@ -136,58 +117,73 @@ static void namelist_print(struct vector *v) } } -static const char *type_text(cproc_option_type_t type) +static const char *type_text(opdb_type_t type) { switch (type) { - case CPROC_OPTION_BOOL: + case OPDB_TYPE_BOOLEAN: return "boolean"; - case CPROC_OPTION_NUMERIC: + case OPDB_TYPE_NUMERIC: return "numeric"; - case CPROC_OPTION_STRING: + case OPDB_TYPE_STRING: return "text"; } return "unknown"; } +static int push_option_name(void *user_data, const struct opdb_key *key, + const union opdb_value *value) +{ + struct vector *v = (struct vector *)user_data; + + return vector_push(v, &key->name, 1); +} + static int cmd_help(cproc_t cp, char **arg) { const char *topic = get_arg(arg); if (topic) { const struct cproc_command *cmd = find_command(cp, topic); - const struct cproc_option *opt = find_option(cp, topic); + struct opdb_key key; if (cmd) { cproc_printf(cp, "\x1b[1mCOMMAND: %s\x1b[0m\n", cmd->name); fputs(cmd->help, stdout); - if (opt) - printf("\n"); + return 0; } - if (opt) { + if (!opdb_get(topic, &key, NULL)) { cproc_printf(cp, "\x1b[1mOPTION: %s (%s)\x1b[0m\n", - opt->name, type_text(opt->type)); - fputs(opt->help, stdout); + key.name, type_text(key.type)); + fputs(key.help, stdout); + return 0; } - if (!(cmd || opt)) { - fprintf(stderr, "help: unknown command: %s\n", topic); - return -1; - } + fprintf(stderr, "help: unknown command: %s\n", topic); + return -1; } else { + struct vector v; + + vector_init(&v, sizeof(const char *)); sort_lists(cp); printf("Available commands:\n"); namelist_print(&cp->command_list); printf("\n"); - printf("Available options:\n"); - namelist_print(&cp->option_list); - printf("\n"); + if (!opdb_enum(push_option_name, &v)) { + printf("Available options:\n"); + namelist_print(&v); + printf("\n"); + } else { + perror("failed to allocate memory"); + } + + vector_destroy(&v); printf("Type \"help \" for more information.\n"); printf("Press Ctrl+D to quit.\n"); @@ -196,59 +192,59 @@ static int cmd_help(cproc_t cp, char **arg) return 0; } -static int parse_option(struct cproc_option *o, const char *word) +static int parse_option(opdb_type_t type, union opdb_value *value, + const char *word) { - switch (o->type) { - case CPROC_OPTION_BOOL: - o->data.numeric = (isdigit(word[0]) && word[0] > '0') || + switch (type) { + case OPDB_TYPE_BOOLEAN: + value->numeric = (isdigit(word[0]) && word[0] > '0') || word[0] == 't' || word[0] == 'y' || (word[0] == 'o' && word[1] == 'n'); break; - case CPROC_OPTION_NUMERIC: - return expr_eval(stab_default, word, &o->data.numeric); + case OPDB_TYPE_NUMERIC: + return expr_eval(stab_default, word, &value->numeric); - case CPROC_OPTION_STRING: - strncpy(o->data.text, word, sizeof(o->data.text)); - o->data.text[sizeof(o->data.text) - 1] = 0; + case OPDB_TYPE_STRING: + strncpy(value->string, word, sizeof(value->string)); + value->string[sizeof(value->string) - 1] = 0; break; } return 0; } -static void display_option(const struct cproc_option *o) +static int display_option(void *user_data, const struct opdb_key *key, + const union opdb_value *value) { - printf("%32s = ", o->name); + printf("%32s = ", key->name); - switch (o->type) { - case CPROC_OPTION_BOOL: - printf("%s", o->data.numeric ? "true" : "false"); + switch (key->type) { + case OPDB_TYPE_BOOLEAN: + printf("%s", value->boolean ? "true" : "false"); break; - case CPROC_OPTION_NUMERIC: - printf("0x%x (%u)", o->data.numeric, - o->data.numeric); + case OPDB_TYPE_NUMERIC: + printf("0x%x (%u)", value->numeric, value->numeric); break; - case CPROC_OPTION_STRING: - printf("%s", o->data.text); + case OPDB_TYPE_STRING: + printf("%s", value->string); break; } printf("\n"); + return 0; } static int cmd_opt(cproc_t cp, char **arg) { const char *opt_text = get_arg(arg); - struct cproc_option *opt = NULL; - - sort_lists(cp); + struct opdb_key key; + union opdb_value value; if (opt_text) { - opt = find_option(cp, opt_text); - if (!opt) { + if (opdb_get(opt_text, &key, &value) < 0) { fprintf(stderr, "opt: no such option: %s\n", opt_text); return -1; @@ -256,19 +252,17 @@ static int cmd_opt(cproc_t cp, char **arg) } if (**arg) { - if (parse_option(opt, *arg) < 0) { + if (parse_option(key.type, &value, *arg) < 0) { fprintf(stderr, "opt: can't parse option: %s\n", *arg); return -1; } - } else if (opt_text) { - display_option(opt); - } else { - int i; - for (i = 0; i < cp->option_list.size; i++) - display_option(VECTOR_PTR(cp->option_list, i, - struct cproc_option)); + opdb_set(key.name, &value); + } else if (opt_text) { + display_option(NULL, &key, &value); + } else { + opdb_enum(display_option, NULL); } return 0; @@ -312,14 +306,6 @@ static const struct cproc_command built_in_commands[] = { } }; -static const struct cproc_option built_in_options[] = { - { - .name = "color", - .type = CPROC_OPTION_BOOL, - .help = "Colorize debugging output.\n" - } -}; - cproc_t cproc_new(void) { cproc_t cp = malloc(sizeof(*cp)); @@ -330,14 +316,10 @@ cproc_t cproc_new(void) memset(cp, 0, sizeof(*cp)); vector_init(&cp->command_list, sizeof(struct cproc_command)); - vector_init(&cp->option_list, sizeof(struct cproc_option)); if (vector_push(&cp->command_list, &built_in_commands, - ARRAY_LEN(built_in_commands)) < 0 || - vector_push(&cp->option_list, &built_in_options, - ARRAY_LEN(built_in_options)) < 0) { + ARRAY_LEN(built_in_commands)) < 0) { vector_destroy(&cp->command_list); - vector_destroy(&cp->option_list); free(cp); return NULL; } @@ -348,7 +330,6 @@ cproc_t cproc_new(void) void cproc_destroy(cproc_t cp) { vector_destroy(&cp->command_list); - vector_destroy(&cp->option_list); free(cp); } @@ -362,28 +343,16 @@ int cproc_register_commands(cproc_t cp, const struct cproc_command *cmd, return 0; } -int cproc_register_options(cproc_t cp, const struct cproc_option *opt, - int count) -{ - if (vector_push(&cp->option_list, opt, count) < 0) - return -1; - - cp->lists_modified = 1; - return 0; -} - void cproc_printf(cproc_t cp, const char *fmt, ...) { char buf[256]; va_list ap; - int want_color = 0; va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); - cproc_get_int(cp, "color", &want_color); - if (!want_color) { + if (!opdb_get_boolean("color")) { char *src = buf; char *dst = buf; @@ -445,38 +414,6 @@ int cproc_prompt_abort(cproc_t cp, int flags) return 0; } -int cproc_get_int(cproc_t cp, const char *name, int *value) -{ - struct cproc_option *opt = find_option(cp, name); - - if (!opt) - return -1; - - if (opt->type == CPROC_OPTION_NUMERIC || - opt->type == CPROC_OPTION_BOOL) { - *value = opt->data.numeric; - return 0; - } - - return -1; -} - -int cproc_get_string(cproc_t cp, const char *name, char *value, int max_len) -{ - struct cproc_option *opt = find_option(cp, name); - - if (!opt) - return -1; - - if (opt->type == CPROC_OPTION_STRING) { - strncpy(value, opt->data.text, max_len); - value[max_len - 1] = 0; - return 0; - } - - return -1; -} - #ifndef USE_READLINE #define LINE_BUF_SIZE 128 diff --git a/cproc.h b/cproc.h index a812308..e87c2da 100644 --- a/cproc.h +++ b/cproc.h @@ -42,31 +42,6 @@ struct cproc_command { const char *help; }; -/* Option definitions. - * - * Options come in three different types, and can be manipulated with the - * in-built "set" function. - * - * Default values may be specified by filling out the value portion in the - * option's definition. - */ -typedef enum { - CPROC_OPTION_STRING, - CPROC_OPTION_NUMERIC, - CPROC_OPTION_BOOL -} cproc_option_type_t; - -struct cproc_option { - const char *name; - cproc_option_type_t type; - const char *help; - - union { - char text[128]; - address_t numeric; - } data; -}; - /* Commmand processor modification flags. * * Within the context of a command processor, various data items may be @@ -95,8 +70,6 @@ void cproc_destroy(cproc_t cp); */ int cproc_register_commands(cproc_t cp, const struct cproc_command *cmd, int count); -int cproc_register_options(cproc_t cp, const struct cproc_option *opt, - int count); /* Print a line of text on the command processor's standard output. * @@ -115,12 +88,6 @@ void cproc_modify(cproc_t cp, int flags); void cproc_unmodify(cproc_t cp, int flags); int cproc_prompt_abort(cproc_t cp, int flags); -/* Retrieve option values. These functions return 0 on success or -1 if - * an error occurs. - */ -int cproc_get_int(cproc_t cp, const char *opt, int *value); -int cproc_get_string(cproc_t cp, const char *opt, char *value, int max_len); - /* Run the reader loop */ void cproc_reader_loop(cproc_t cp); diff --git a/gdb.c b/gdb.c index bcf3019..261a2c6 100644 --- a/gdb.c +++ b/gdb.c @@ -29,6 +29,7 @@ #include #include "device.h" #include "util.h" +#include "opdb.h" #include "gdb.h" #define MAX_MEM_XFER 1024 @@ -665,9 +666,6 @@ static int cmd_gdb(cproc_t cp, char **arg) { char *port_text = get_arg(arg); int port = 2000; - int want_loop = 0; - - cproc_get_int(cp, "gdb_loop", &want_loop); if (port_text) port = atoi(port_text); @@ -680,7 +678,7 @@ static int cmd_gdb(cproc_t cp, char **arg) do { if (gdb_server(port) < 0) return -1; - } while (want_loop); + } while (opdb_get_boolean("gdb_loop")); return 0; } @@ -693,19 +691,7 @@ static const struct cproc_command command_gdb = { " Run a GDB remote stub on the given TCP/IP port.\n" }; -static const struct cproc_option option_gdb = { - .name = "gdb_loop", - .type = CPROC_OPTION_BOOL, - .help = -"Automatically restart the GDB server after disconnection. If this\n" -"option is set, then the GDB server keeps running until an error occurs,\n" -"or the user interrupts with Ctrl+C.\n" -}; - int gdb_register(cproc_t cp) { - if (cproc_register_options(cp, &option_gdb, 1) < 0) - return -1; - return cproc_register_commands(cp, &command_gdb, 1); } diff --git a/main.c b/main.c index e900190..53c490f 100644 --- a/main.c +++ b/main.c @@ -35,6 +35,7 @@ #include "sym.h" #include "devcmd.h" #include "expr.h" +#include "opdb.h" #include "sim.h" #include "bsl.h" @@ -465,6 +466,7 @@ int main(int argc, char **argv) return -1; ctrlc_init(); + opdb_reset(); cp = setup_cproc(&args); if (!cp) diff --git a/opdb.c b/opdb.c new file mode 100644 index 0000000..9f61548 --- /dev/null +++ b/opdb.c @@ -0,0 +1,150 @@ +/* MSPDebug - debugging tool for MSP430 MCUs + * Copyright (C) 2009, 2010 Daniel Beer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include "opdb.h" +#include "util.h" + +const static struct opdb_key keys[] = { + { + .name = "color", + .type = OPDB_TYPE_BOOLEAN, + .help = "Colorize debugging output.\n", + .defval = { + .boolean = 0 + } + }, + { + .name = "gdb_loop", + .type = OPDB_TYPE_BOOLEAN, + .help = +"Automatically restart the GDB server after disconnection. If this\n" +"option is set, then the GDB server keeps running until an error occurs,\n" +"or the user interrupts with Ctrl+C.\n", + .defval = { + .boolean = 0 + } + } +}; + +static union opdb_value values[ARRAY_LEN(keys)]; + +static int opdb_find(const char *name) +{ + int i; + + for (i = 0; i < ARRAY_LEN(keys); i++) { + const struct opdb_key *key = &keys[i]; + + if (!strcasecmp(key->name, name)) + return i; + } + + return -1; +} + +void opdb_reset(void) +{ + int i; + + for (i = 0; i < ARRAY_LEN(keys); i++) { + const struct opdb_key *key = &keys[i]; + union opdb_value *value = &values[i]; + + memcpy(value, &key->defval, sizeof(*value)); + } +} + +int opdb_enum(opdb_enum_func_t func, void *user_data) +{ + int i; + + for (i = 0; i < ARRAY_LEN(keys); i++) { + const struct opdb_key *key = &keys[i]; + const union opdb_value *value = &values[i]; + + if (func(user_data, key, value) < 0) + return -1; + } + + return 0; +} + +int opdb_get(const char *name, struct opdb_key *key, + union opdb_value *value) +{ + int i; + + i = opdb_find(name); + if (i < 0) + return -1; + + if (key) + memcpy(key, &keys[i], sizeof(*key)); + if (value) + memcpy(value, &values[i], sizeof(*value)); + + return 0; +} + +int opdb_set(const char *name, const union opdb_value *value) +{ + int i; + union opdb_value *v; + + i = opdb_find(name); + if (i < 0) + return -1; + + v = &values[i]; + memcpy(v, value, sizeof(values[i])); + if (keys[i].type == OPDB_TYPE_STRING) + v->string[sizeof(v->string) - 1] = 0; + + return 0; +} + +const char *opdb_get_string(const char *name) +{ + int idx = opdb_find(name); + + if (idx < 0) + return ""; + + return values[idx].string; +} + +int opdb_get_boolean(const char *name) +{ + int idx = opdb_find(name); + + if (idx < 0) + return 0; + + return values[idx].boolean; +} + +address_t opdb_get_numeric(const char *name) +{ + int idx = opdb_find(name); + + if (idx < 0) + return 0; + + return values[idx].numeric; +} diff --git a/opdb.h b/opdb.h new file mode 100644 index 0000000..f1e8f2f --- /dev/null +++ b/opdb.h @@ -0,0 +1,65 @@ +/* MSPDebug - debugging tool for MSP430 MCUs + * Copyright (C) 2009, 2010 Daniel Beer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef OPDB_H_ +#define OPDB_H_ + +#include "util.h" + +typedef enum { + OPDB_TYPE_BOOLEAN, + OPDB_TYPE_NUMERIC, + OPDB_TYPE_STRING +} opdb_type_t; + +union opdb_value { + char string[128]; + address_t numeric; + int boolean; +}; + +struct opdb_key { + const char *name; + const char *help; + opdb_type_t type; + union opdb_value defval; +}; + +/* Reset all options to default values. This should be called on start-up + * to initialize the database. + */ +void opdb_reset(void); + +/* Enumerate all option key/value pairs */ +typedef int (*opdb_enum_func_t)(void *user_data, const struct opdb_key *key, + const union opdb_value *value); + +int opdb_enum(opdb_enum_func_t func, void *user_data); + +/* Retrieve information about an option. Returns 0 if found, -1 otherwise. */ +int opdb_get(const char *name, struct opdb_key *key, + union opdb_value *value); + +int opdb_set(const char *name, const union opdb_value *value); + +/* Get wrappers */ +const char *opdb_get_string(const char *name); +int opdb_get_boolean(const char *name); +address_t opdb_get_numeric(const char *name); + +#endif