diff --git a/Makefile b/Makefile index 02db465..6e112b3 100644 --- a/Makefile +++ b/Makefile @@ -64,7 +64,7 @@ mspdebug: main.o fet.o rf2500.o dis.o uif.o olimex.o ihex.o elf32.o stab.o \ reader.o vector.o output_util.o expr.o fet_error.o binfile.o \ fet_db.o usbutil.o titext.o srec.o device.o coff.o opdb.o output.o \ cmddb.o stdcmd.o prog.o flash_bsl.o list.o simio.o simio_tracer.o \ - simio_timer.o simio_wdt.o simio_hwmult.o simio_gpio.o + simio_timer.o simio_wdt.o simio_hwmult.o simio_gpio.o aliasdb.o $(CC) $(LDFLAGS) $(PORTS_LDFLAGS) -o $@ $^ -lusb $(READLINE_LIBS) .c.o: diff --git a/aliasdb.c b/aliasdb.c new file mode 100644 index 0000000..15c3d68 --- /dev/null +++ b/aliasdb.c @@ -0,0 +1,180 @@ +/* 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 +#include +#include + +#include "aliasdb.h" +#include "vector.h" +#include "output.h" +#include "util.h" + +struct alias { + char src[256]; + char dst[256]; +}; + +static struct vector alias_list = { + .ptr = NULL, + .capacity = 0, + .size = 0, + .elemsize = sizeof(struct alias) +}; + +static int list_is_sorted; + +static struct alias *find_alias(const char *name) +{ + int i; + + for (i = 0; i < alias_list.size; i++) { + struct alias *a = + VECTOR_PTR(alias_list, i, struct alias); + + if (!strcasecmp(name, a->src)) + return a; + } + + return NULL; +} + +struct recurse_list { + const char *cmd; + struct recurse_list *next; +}; + +static int translate_rec(struct recurse_list *l, + const char *command, const char *args, + char *out_cmd, int max_len) +{ + struct recurse_list *c; + const struct alias *a; + + if (*command == '\\') { + snprintf(out_cmd, max_len, "%s %s", command + 1, args); + return 0; + } + + for (c = l; c; c = c->next) + if (!strcasecmp(c->cmd, command)) { + printc_err("recursive alias: %s\n", command); + return -1; + } + + a = find_alias(command); + if (a) { + struct recurse_list r; + char tmp_buf[1024]; + char *new_args = tmp_buf; + char *cmd; + + snprintf(tmp_buf, sizeof(tmp_buf), "%s %s", a->dst, args); + r.next = l; + r.cmd = command; + + cmd = get_arg(&new_args); + return translate_rec(&r, cmd, new_args, out_cmd, max_len); + } + + snprintf(out_cmd, max_len, "%s %s", command, args); + return 0; +} + +int translate_alias(const char *command, const char *args, + char *out_cmd, int max_len) +{ + return translate_rec(NULL, command, args, out_cmd, max_len); +} + +static int cmp_alias(const void *a, const void *b) +{ + const struct alias *aa = (const struct alias *)a; + const struct alias *ab = (const struct alias *)b; + + return strcasecmp(aa->src, ab->src); +} + +int cmd_alias(char **arg) +{ + const char *src = get_arg(arg); + const char *dst = get_arg(arg); + struct alias *a; + struct alias na; + + if (!src) { /* List aliases */ + int i; + + if (!list_is_sorted) { + qsort(alias_list.ptr, alias_list.size, + alias_list.elemsize, cmp_alias); + list_is_sorted = 1; + } + + printf("%d aliases defined:\n", alias_list.size); + for (i = 0; i < alias_list.size; i++) { + struct alias *a = + VECTOR_PTR(alias_list, i, struct alias); + + printc(" %20s = %s\n", a->src, a->dst); + } + + return 0; + } + + a = find_alias(src); + + if (!dst) { /* Delete alias */ + struct alias *end = VECTOR_PTR(alias_list, + alias_list.size - 1, struct alias); + + if (!a) { + printc_err("alias: no such alias defined: %s\n", src); + return -1; + } + + if (end != a) + memcpy(a, end, sizeof(*a)); + + vector_pop(&alias_list); + list_is_sorted = 0; + return 0; + } + + if (a) { /* Overwrite old alias */ + strncpy(a->dst, dst, sizeof(a->dst)); + a->dst[sizeof(a->dst) - 1] = 0; + return 0; + } + + /* New alias */ + strncpy(na.src, src, sizeof(na.src)); + na.src[sizeof(na.src) - 1] = 0; + strncpy(na.dst, dst, sizeof(na.dst)); + na.dst[sizeof(na.dst) - 1] = 0; + + if (vector_push(&alias_list, &na, 1) < 0) { + printc_err("alias: can't allocate memory: %s\n", + strerror(errno)); + return -1; + } + + list_is_sorted = 0; + return 0; +} diff --git a/aliasdb.h b/aliasdb.h new file mode 100644 index 0000000..ced5604 --- /dev/null +++ b/aliasdb.h @@ -0,0 +1,29 @@ +/* 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 ALIASDB_H_ +#define ALIASDB_H_ + +/* "alias" command */ +int cmd_alias(char **arg); + +/* Translate a command using the aliases table. */ +int translate_alias(const char *command, const char *args, + char *out_cmd, int max_len); + +#endif diff --git a/cmddb.c b/cmddb.c index c27a969..1220cba 100644 --- a/cmddb.c +++ b/cmddb.c @@ -27,6 +27,7 @@ #include "sym.h" #include "stdcmd.h" #include "simio.h" +#include "aliasdb.h" const struct cmddb_record commands[] = { { @@ -260,6 +261,17 @@ const struct cmddb_record commands[] = { " Change settings of an attached device.\n" "simio info \n" " Print status information for an attached device.\n" + }, + { + .name = "alias", + .func = cmd_alias, + .help = +"alias\n" +" List all defined aliases.\n" +"alias \n" +" Remove an alias definition.\n" +"alias \n" +" Define a new alias.\n" } }; diff --git a/mspdebug.man b/mspdebug.man index ba4d21c..536f175 100644 --- a/mspdebug.man +++ b/mspdebug.man @@ -143,6 +143,16 @@ question. See the section marked \fBADDRESS EXPRESSIONS\fR for more information on the syntax of expressions. +.IP "\fBalias\fR" +Show a list of defined command aliases. +.IP "\fBalias\fR \fIname\fR" +Remove a previously defined command alias. +.IP "\fBalias\fR \fIname\fR \fIcommand\fR" +Define a command alias. The text \fIcommand\fR will be substituted for +\fIname\fR when looking up commands. The given command text may contain +a command plus arguments, if the entire text is wrapped in quotes when +defining the alias. To avoid alias substitution when interpreting +commands, prefix the command with \\ (a backslash character). .IP "\fBbreak\fR" Show a list of active breakpoints. Breakpoints can be added and removed with the \fBsetbreak\fR and \fBdelbreak\fR commands. Each breakpoint is diff --git a/reader.c b/reader.c index 6f13433..dc88c7c 100644 --- a/reader.c +++ b/reader.c @@ -35,6 +35,7 @@ #include "stdcmd.h" #include "reader.h" #include "opdb.h" +#include "aliasdb.h" #define MAX_READER_LINE 1024 @@ -124,8 +125,16 @@ static int do_command(char *arg, int interactive) cmd_text = get_arg(&arg); if (cmd_text) { + char translated[1024]; struct cmddb_record cmd; + if (translate_alias(cmd_text, arg, + translated, sizeof(translated)) < 0) + return -1; + + arg = translated; + cmd_text = get_arg(&arg); + if (!cmddb_get(cmd_text, &cmd)) { int old = in_reader_loop; int ret; diff --git a/vector.c b/vector.c index c748a0c..7eeffc2 100644 --- a/vector.c +++ b/vector.c @@ -57,30 +57,39 @@ int vector_realloc(struct vector *v, int capacity) return 0; } +static int size_for(struct vector *v, int needed) +{ + int cap = needed; + + /* Find the smallest power of 2 which is greater than the + * necessary capacity. + */ + while (cap & (cap - 1)) + cap &= (cap - 1); + if (cap < needed) + cap <<= 1; + + /* Don't allocate fewer than 8 elements */ + if (cap < 8) + cap = 8; + + if (v->capacity >= cap && v->capacity <= cap * 2) + return 0; + + if (vector_realloc(v, cap) < 0) + return -1; + + return 0; +} + int vector_push(struct vector *v, const void *data, int count) { int needed = v->size + count; assert (count >= 0); - if (needed > v->capacity) { - int cap = needed; - - /* Find the smallest power of 2 which is greater than the - * necessary capacity. - */ - while (cap & (cap - 1)) - cap &= (cap - 1); - if (cap < needed) - cap <<= 1; - - /* Don't allocate fewer than 8 elements */ - if (cap < 8) - cap = 8; - - if (vector_realloc(v, cap) < 0) - return -1; - } + if (size_for(v, needed) < 0) + return -1; memcpy((char *)v->ptr + v->size * v->elemsize, data, @@ -89,3 +98,12 @@ int vector_push(struct vector *v, const void *data, int count) return 0; } + +void vector_pop(struct vector *v) +{ + if (v->size <= 0) + return; + + size_for(v, v->size - 1); + v->size--; +} diff --git a/vector.h b/vector.h index a1ed0d7..fcbb601 100644 --- a/vector.h +++ b/vector.h @@ -47,6 +47,9 @@ int vector_realloc(struct vector *v, int capacity); */ int vector_push(struct vector *v, const void *data, int count); +/* Remove the last element from a vector. */ +void vector_pop(struct vector *v); + /* Dereference a vector, giving an expression for the element of type t at * position i in vector v. Use as follows: *