Implemented command aliases.
This commit is contained in:
parent
5e5b118e74
commit
f6ecf7bd56
2
Makefile
2
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 \
|
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 \
|
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 \
|
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)
|
$(CC) $(LDFLAGS) $(PORTS_LDFLAGS) -o $@ $^ -lusb $(READLINE_LIBS)
|
||||||
|
|
||||||
.c.o:
|
.c.o:
|
||||||
|
|
|
@ -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 <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
|
@ -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
|
12
cmddb.c
12
cmddb.c
|
@ -27,6 +27,7 @@
|
||||||
#include "sym.h"
|
#include "sym.h"
|
||||||
#include "stdcmd.h"
|
#include "stdcmd.h"
|
||||||
#include "simio.h"
|
#include "simio.h"
|
||||||
|
#include "aliasdb.h"
|
||||||
|
|
||||||
const struct cmddb_record commands[] = {
|
const struct cmddb_record commands[] = {
|
||||||
{
|
{
|
||||||
|
@ -260,6 +261,17 @@ const struct cmddb_record commands[] = {
|
||||||
" Change settings of an attached device.\n"
|
" Change settings of an attached device.\n"
|
||||||
"simio info <name>\n"
|
"simio info <name>\n"
|
||||||
" Print status information for an attached device.\n"
|
" Print status information for an attached device.\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "alias",
|
||||||
|
.func = cmd_alias,
|
||||||
|
.help =
|
||||||
|
"alias\n"
|
||||||
|
" List all defined aliases.\n"
|
||||||
|
"alias <name>\n"
|
||||||
|
" Remove an alias definition.\n"
|
||||||
|
"alias <name> <command>\n"
|
||||||
|
" Define a new alias.\n"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
10
mspdebug.man
10
mspdebug.man
|
@ -143,6 +143,16 @@ question.
|
||||||
|
|
||||||
See the section marked \fBADDRESS EXPRESSIONS\fR for more information on
|
See the section marked \fBADDRESS EXPRESSIONS\fR for more information on
|
||||||
the syntax of expressions.
|
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"
|
.IP "\fBbreak\fR"
|
||||||
Show a list of active breakpoints. Breakpoints can be added and removed
|
Show a list of active breakpoints. Breakpoints can be added and removed
|
||||||
with the \fBsetbreak\fR and \fBdelbreak\fR commands. Each breakpoint is
|
with the \fBsetbreak\fR and \fBdelbreak\fR commands. Each breakpoint is
|
||||||
|
|
9
reader.c
9
reader.c
|
@ -35,6 +35,7 @@
|
||||||
#include "stdcmd.h"
|
#include "stdcmd.h"
|
||||||
#include "reader.h"
|
#include "reader.h"
|
||||||
#include "opdb.h"
|
#include "opdb.h"
|
||||||
|
#include "aliasdb.h"
|
||||||
|
|
||||||
#define MAX_READER_LINE 1024
|
#define MAX_READER_LINE 1024
|
||||||
|
|
||||||
|
@ -124,8 +125,16 @@ static int do_command(char *arg, int interactive)
|
||||||
|
|
||||||
cmd_text = get_arg(&arg);
|
cmd_text = get_arg(&arg);
|
||||||
if (cmd_text) {
|
if (cmd_text) {
|
||||||
|
char translated[1024];
|
||||||
struct cmddb_record cmd;
|
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)) {
|
if (!cmddb_get(cmd_text, &cmd)) {
|
||||||
int old = in_reader_loop;
|
int old = in_reader_loop;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
54
vector.c
54
vector.c
|
@ -57,30 +57,39 @@ int vector_realloc(struct vector *v, int capacity)
|
||||||
return 0;
|
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 vector_push(struct vector *v, const void *data, int count)
|
||||||
{
|
{
|
||||||
int needed = v->size + count;
|
int needed = v->size + count;
|
||||||
|
|
||||||
assert (count >= 0);
|
assert (count >= 0);
|
||||||
|
|
||||||
if (needed > v->capacity) {
|
if (size_for(v, needed) < 0)
|
||||||
int cap = needed;
|
return -1;
|
||||||
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy((char *)v->ptr + v->size * v->elemsize,
|
memcpy((char *)v->ptr + v->size * v->elemsize,
|
||||||
data,
|
data,
|
||||||
|
@ -89,3 +98,12 @@ int vector_push(struct vector *v, const void *data, int count)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void vector_pop(struct vector *v)
|
||||||
|
{
|
||||||
|
if (v->size <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
size_for(v, v->size - 1);
|
||||||
|
v->size--;
|
||||||
|
}
|
||||||
|
|
3
vector.h
3
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);
|
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
|
/* Dereference a vector, giving an expression for the element of type t at
|
||||||
* position i in vector v. Use as follows:
|
* position i in vector v. Use as follows:
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue