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 \
|
||||
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:
|
||||
|
|
|
@ -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 "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 <name>\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
|
||||
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
|
||||
|
|
9
reader.c
9
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;
|
||||
|
|
54
vector.c
54
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--;
|
||||
}
|
||||
|
|
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);
|
||||
|
||||
/* 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:
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue