[console] synchronize with external sources
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Travis Geiselbrecht
|
||||
* Copyright (c) 2008-2009 Travis Geiselbrecht
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
@@ -31,6 +31,7 @@ typedef struct {
|
||||
const char *str;
|
||||
unsigned int u;
|
||||
int i;
|
||||
bool b;
|
||||
} cmd_args;
|
||||
|
||||
typedef int (*console_cmd)(int argc, const cmd_args *argv);
|
||||
@@ -49,14 +50,38 @@ typedef struct _cmd_block {
|
||||
} cmd_block;
|
||||
|
||||
/* register a static block of commands at init time */
|
||||
#if WITH_LIB_CONSOLE
|
||||
#define STATIC_COMMAND_START static const cmd _cmd_list[] = {
|
||||
#define STATIC_COMMAND_END(name) }; const cmd_block _cmd_block_##name __SECTION(".commands")= { NULL, sizeof(_cmd_list) / sizeof(_cmd_list[0]), _cmd_list }
|
||||
#define STATIC_COMMAND_START_NAMED(name) static const cmd _cmd_list_##name[] = {
|
||||
#define STATIC_COMMAND_END_NAMED(name) }; const cmd_block _cmd_block_##name __SECTION(".commands")= { NULL, sizeof(_cmd_list_##name) / sizeof(_cmd_list_##name[0]), _cmd_list_##name }
|
||||
|
||||
#define STATIC_COMMAND(command_str, help_str, func) { command_str, help_str, func },
|
||||
|
||||
#else
|
||||
|
||||
/* no command blocks, so null them out */
|
||||
#define STATIC_COMMAND_START
|
||||
#define STATIC_COMMAND_END(name)
|
||||
#define STATIC_COMMAND_START_NAMED(name)
|
||||
#define STATIC_COMMAND_END_NAMED(name)
|
||||
|
||||
#define STATIC_COMMAND(command_str, help_str, func)
|
||||
|
||||
#endif
|
||||
|
||||
#define COMMAND_BLOCK_INIT_ITEM(cmd_block_ptr, cmd_ptr) {(cmd_block_ptr)->next = NULL; (cmd_block_ptr)->count = 1; (cmd_block_ptr)->list = cmd_ptr;}
|
||||
|
||||
/* external api */
|
||||
int console_init(void);
|
||||
void console_start(void);
|
||||
void console_register_commands(cmd_block *block);
|
||||
int console_run_command(const char *string);
|
||||
int console_run_script(const char *string);
|
||||
int console_run_script_locked(const char *string); // special case from inside a command
|
||||
console_cmd console_get_command_handler(const char *command);
|
||||
void console_abort_script(void);
|
||||
|
||||
extern int lastresult;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Travis Geiselbrecht
|
||||
* Copyright (c) 2008-2009 Travis Geiselbrecht
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
@@ -23,10 +23,41 @@
|
||||
#include <debug.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <kernel/thread.h>
|
||||
#include <kernel/mutex.h>
|
||||
#include <lib/console.h>
|
||||
#if WITH_LIB_ENV
|
||||
#include <lib/env.h>
|
||||
#endif
|
||||
|
||||
#define LINE_LEN 512
|
||||
|
||||
#define HISTORY_LEN 16
|
||||
|
||||
#define LOCAL_TRACE 0
|
||||
|
||||
/* debug buffer */
|
||||
static char *debug_buffer;
|
||||
|
||||
/* command processor state */
|
||||
static mutex_t *command_lock;
|
||||
int lastresult;
|
||||
static bool abort_script;
|
||||
|
||||
/* command history stuff */
|
||||
static char *history; // HISTORY_LEN rows of LINE_LEN chars a piece
|
||||
static uint history_next;
|
||||
|
||||
static void init_history(void);
|
||||
static void add_history(const char *line);
|
||||
static uint start_history_cursor(void);
|
||||
static const char *next_history(uint *cursor);
|
||||
static const char *prev_history(uint *cursor);
|
||||
static void dump_history(void);
|
||||
|
||||
/* list of installed commands */
|
||||
static cmd_block *command_list = NULL;
|
||||
|
||||
/* a linear array of statically defined command blocks,
|
||||
@@ -37,25 +68,125 @@ extern cmd_block __commands_end;
|
||||
|
||||
static int cmd_help(int argc, const cmd_args *argv);
|
||||
static int cmd_test(int argc, const cmd_args *argv);
|
||||
static int cmd_history(int argc, const cmd_args *argv);
|
||||
|
||||
STATIC_COMMAND_START
|
||||
{ "help", "this list", &cmd_help },
|
||||
{ "test", "test the command processor", &cmd_test },
|
||||
STATIC_COMMAND("help", "this list", &cmd_help)
|
||||
#if DEBUGLEVEL > 1
|
||||
STATIC_COMMAND("test", "test the command processor", &cmd_test)
|
||||
STATIC_COMMAND("history", "command history", &cmd_history)
|
||||
#endif
|
||||
STATIC_COMMAND_END(help);
|
||||
|
||||
int console_init(void)
|
||||
{
|
||||
printf("console_init: entry\n");
|
||||
LTRACE_ENTRY;
|
||||
|
||||
command_lock = malloc(sizeof(mutex_t));
|
||||
mutex_init(command_lock);
|
||||
|
||||
/* add all the statically defined commands to the list */
|
||||
cmd_block *block;
|
||||
for (block = &__commands_start; block != &__commands_end; block++) {
|
||||
console_register_commands(block);
|
||||
}
|
||||
|
||||
|
||||
init_history();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_history(int argc, const cmd_args *argv)
|
||||
{
|
||||
dump_history();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline char *history_line(uint line)
|
||||
{
|
||||
return history + line * LINE_LEN;
|
||||
}
|
||||
|
||||
static inline uint ptrnext(uint ptr)
|
||||
{
|
||||
return (ptr + 1) % HISTORY_LEN;
|
||||
}
|
||||
|
||||
static inline uint ptrprev(uint ptr)
|
||||
{
|
||||
return (ptr - 1) % HISTORY_LEN;
|
||||
}
|
||||
|
||||
static void dump_history(void)
|
||||
{
|
||||
printf("command history:\n");
|
||||
uint ptr = ptrprev(history_next);
|
||||
int i;
|
||||
for (i=0; i < HISTORY_LEN; i++) {
|
||||
if (history_line(ptr)[0] != 0)
|
||||
printf("\t%s\n", history_line(ptr));
|
||||
ptr = ptrprev(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
static void init_history(void)
|
||||
{
|
||||
/* allocate and set up the history buffer */
|
||||
history = calloc(1, HISTORY_LEN * LINE_LEN);
|
||||
history_next = 0;
|
||||
}
|
||||
|
||||
static void add_history(const char *line)
|
||||
{
|
||||
// reject some stuff
|
||||
if (line[0] == 0)
|
||||
return;
|
||||
|
||||
uint last = ptrprev(history_next);
|
||||
if (strcmp(line, history_line(last)) == 0)
|
||||
return;
|
||||
|
||||
strlcpy(history_line(history_next), line, LINE_LEN);
|
||||
history_next = ptrnext(history_next);
|
||||
}
|
||||
|
||||
static uint start_history_cursor(void)
|
||||
{
|
||||
return ptrprev(history_next);
|
||||
}
|
||||
|
||||
static const char *next_history(uint *cursor)
|
||||
{
|
||||
uint i = ptrnext(*cursor);
|
||||
|
||||
if (i == history_next)
|
||||
return ""; // can't let the cursor hit the head
|
||||
|
||||
*cursor = i;
|
||||
return history_line(i);
|
||||
}
|
||||
|
||||
static const char *prev_history(uint *cursor)
|
||||
{
|
||||
uint i;
|
||||
const char *str = history_line(*cursor);
|
||||
|
||||
/* if we are already at head, stop here */
|
||||
if (*cursor == history_next)
|
||||
return str;
|
||||
|
||||
/* back up one */
|
||||
i = ptrprev(*cursor);
|
||||
|
||||
/* if the next one is gonna be null */
|
||||
if (history_line(i)[0] == '\0')
|
||||
return str;
|
||||
|
||||
/* update the cursor */
|
||||
*cursor = i;
|
||||
return str;
|
||||
}
|
||||
|
||||
static const cmd *match_command(const char *command)
|
||||
{
|
||||
cmd_block *block;
|
||||
@@ -73,25 +204,28 @@ static const cmd *match_command(const char *command)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int read_line(char *buffer, int len)
|
||||
static int read_debug_line(const char **outbuffer, void *cookie)
|
||||
{
|
||||
int pos = 0;
|
||||
int escape_level = 0;
|
||||
uint history_cursor = start_history_cursor();
|
||||
|
||||
char *buffer = debug_buffer;
|
||||
|
||||
for (;;) {
|
||||
char c;
|
||||
|
||||
/* loop until we get a char */
|
||||
if (getc(&c) < 0)
|
||||
if (dgetc(&c) < 0)
|
||||
continue;
|
||||
|
||||
// printf("c = 0x%hhx\n", c);
|
||||
// TRACEF("c = 0x%hhx\n", c);
|
||||
|
||||
if (escape_level == 0) {
|
||||
switch (c) {
|
||||
case '\r':
|
||||
case '\n':
|
||||
putc(c);
|
||||
putc('\n');
|
||||
goto done;
|
||||
|
||||
case 0x7f: // backspace or delete
|
||||
@@ -134,9 +268,22 @@ static int read_line(char *buffer, int len)
|
||||
puts("\x1b[1D"); // move to the left one
|
||||
}
|
||||
break;
|
||||
case 65: // up arrow
|
||||
case 66: // down arrow
|
||||
// XXX do history here
|
||||
case 65: // up arrow -- previous history
|
||||
case 66: // down arrow -- next history
|
||||
// wipe out the current line
|
||||
while (pos > 0) {
|
||||
pos--;
|
||||
puts("\x1b[1D"); // move to the left one
|
||||
putc(' ');
|
||||
puts("\x1b[1D"); // move to the left one
|
||||
}
|
||||
|
||||
if (c == 65)
|
||||
strlcpy(buffer, prev_history(&history_cursor), LINE_LEN);
|
||||
else
|
||||
strlcpy(buffer, next_history(&history_cursor), LINE_LEN);
|
||||
pos = strlen(buffer);
|
||||
puts(buffer);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -145,7 +292,7 @@ static int read_line(char *buffer, int len)
|
||||
}
|
||||
|
||||
/* end of line. */
|
||||
if (pos == (len - 1)) {
|
||||
if (pos == (LINE_LEN - 1)) {
|
||||
puts("\nerror: line too long\n");
|
||||
pos = 0;
|
||||
goto done;
|
||||
@@ -153,73 +300,189 @@ static int read_line(char *buffer, int len)
|
||||
}
|
||||
|
||||
done:
|
||||
// printf("returning pos %d\n", pos);
|
||||
// dprintf("returning pos %d\n", pos);
|
||||
|
||||
// null terminate
|
||||
buffer[pos] = 0;
|
||||
|
||||
// add to history
|
||||
add_history(buffer);
|
||||
|
||||
// return a pointer to our buffer
|
||||
*outbuffer = buffer;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
static int tokenize_command(char *buffer, cmd_args *args, int arg_count)
|
||||
static int tokenize_command(const char *inbuffer, const char **continuebuffer, char *buffer, size_t buflen, cmd_args *args, int arg_count)
|
||||
{
|
||||
int pos;
|
||||
int inpos;
|
||||
int outpos;
|
||||
int arg;
|
||||
bool finished;
|
||||
enum {
|
||||
INITIAL = 0,
|
||||
NEXT_FIELD,
|
||||
SPACE,
|
||||
IN_SPACE,
|
||||
IN_TOKEN
|
||||
TOKEN,
|
||||
IN_TOKEN,
|
||||
QUOTED_TOKEN,
|
||||
IN_QUOTED_TOKEN,
|
||||
VAR,
|
||||
IN_VAR,
|
||||
COMMAND_SEP,
|
||||
} state;
|
||||
char varname[128];
|
||||
int varnamepos;
|
||||
|
||||
pos = 0;
|
||||
inpos = 0;
|
||||
outpos = 0;
|
||||
arg = 0;
|
||||
varnamepos = 0;
|
||||
state = INITIAL;
|
||||
finished = false;
|
||||
*continuebuffer = NULL;
|
||||
|
||||
for (;;) {
|
||||
char c = buffer[pos];
|
||||
char c = inbuffer[inpos];
|
||||
|
||||
if (c == '\0')
|
||||
finished = true;
|
||||
|
||||
// printf("c 0x%hhx state %d arg %d pos %d\n", c, state, arg, pos);
|
||||
// dprintf(SPEW, "c 0x%hhx state %d arg %d inpos %d pos %d\n", c, state, arg, inpos, outpos);
|
||||
|
||||
switch (state) {
|
||||
case INITIAL:
|
||||
if (isspace(c)) {
|
||||
state = IN_SPACE;
|
||||
case NEXT_FIELD:
|
||||
if (c == '\0')
|
||||
goto done;
|
||||
if (isspace(c))
|
||||
state = SPACE;
|
||||
else if (c == ';')
|
||||
state = COMMAND_SEP;
|
||||
else
|
||||
state = TOKEN;
|
||||
break;
|
||||
case SPACE:
|
||||
state = IN_SPACE;
|
||||
break;
|
||||
case IN_SPACE:
|
||||
if (c == '\0')
|
||||
goto done;
|
||||
if (c == ';') {
|
||||
state = COMMAND_SEP;
|
||||
} else if (!isspace(c)) {
|
||||
state = TOKEN;
|
||||
} else {
|
||||
inpos++; // consume the space
|
||||
}
|
||||
break;
|
||||
case TOKEN:
|
||||
// start of a token
|
||||
DEBUG_ASSERT(c != '\0');
|
||||
if (c == '"') {
|
||||
// start of a quoted token
|
||||
state = QUOTED_TOKEN;
|
||||
} else if (c == '$') {
|
||||
// start of a variable
|
||||
state = VAR;
|
||||
} else {
|
||||
// regular, unquoted token
|
||||
state = IN_TOKEN;
|
||||
args[arg].str = &buffer[pos];
|
||||
args[arg].str = &buffer[outpos];
|
||||
}
|
||||
break;
|
||||
case IN_TOKEN:
|
||||
if (finished) {
|
||||
if (c == '\0') {
|
||||
arg++;
|
||||
goto done;
|
||||
}
|
||||
if (isspace(c)) {
|
||||
if (isspace(c) || c == ';') {
|
||||
arg++;
|
||||
buffer[pos] = 0;
|
||||
buffer[outpos] = 0;
|
||||
outpos++;
|
||||
/* are we out of tokens? */
|
||||
if (arg == arg_count)
|
||||
goto done;
|
||||
state = IN_SPACE;
|
||||
state = NEXT_FIELD;
|
||||
} else {
|
||||
buffer[outpos] = c;
|
||||
outpos++;
|
||||
inpos++;
|
||||
}
|
||||
pos++;
|
||||
break;
|
||||
case IN_SPACE:
|
||||
if (finished)
|
||||
case QUOTED_TOKEN:
|
||||
// start of a quoted token
|
||||
DEBUG_ASSERT(c == '"');
|
||||
|
||||
state = IN_QUOTED_TOKEN;
|
||||
args[arg].str = &buffer[outpos];
|
||||
inpos++; // consume the quote
|
||||
break;
|
||||
case IN_QUOTED_TOKEN:
|
||||
if (c == '\0') {
|
||||
arg++;
|
||||
goto done;
|
||||
if (!isspace(c)) {
|
||||
state = IN_TOKEN;
|
||||
args[arg].str = &buffer[pos];
|
||||
}
|
||||
pos++;
|
||||
if (c == '"') {
|
||||
arg++;
|
||||
buffer[outpos] = 0;
|
||||
outpos++;
|
||||
/* are we out of tokens? */
|
||||
if (arg == arg_count)
|
||||
goto done;
|
||||
|
||||
state = NEXT_FIELD;
|
||||
}
|
||||
buffer[outpos] = c;
|
||||
outpos++;
|
||||
inpos++;
|
||||
break;
|
||||
case VAR:
|
||||
DEBUG_ASSERT(c == '$');
|
||||
|
||||
state = IN_VAR;
|
||||
args[arg].str = &buffer[outpos];
|
||||
inpos++; // consume the dollar sign
|
||||
|
||||
// initialize the place to store the variable name
|
||||
varnamepos = 0;
|
||||
break;
|
||||
case IN_VAR:
|
||||
if (c == '\0' || isspace(c) || c == ';') {
|
||||
// hit the end of variable, look it up and stick it inline
|
||||
varname[varnamepos] = 0;
|
||||
#if WITH_LIB_ENV
|
||||
int rc = env_get(varname, &buffer[outpos], buflen - outpos);
|
||||
#else
|
||||
int rc = -1;
|
||||
#endif
|
||||
if (rc < 0) {
|
||||
buffer[outpos++] = '0';
|
||||
buffer[outpos++] = 0;
|
||||
} else {
|
||||
outpos += strlen(&buffer[outpos]) + 1;
|
||||
}
|
||||
arg++;
|
||||
/* are we out of tokens? */
|
||||
if (arg == arg_count)
|
||||
goto done;
|
||||
|
||||
state = NEXT_FIELD;
|
||||
} else {
|
||||
varname[varnamepos] = c;
|
||||
varnamepos++;
|
||||
inpos++;
|
||||
}
|
||||
break;
|
||||
case COMMAND_SEP:
|
||||
// we hit a ;, so terminate the command and pass the remainder of the command back in continuebuffer
|
||||
DEBUG_ASSERT(c == ';');
|
||||
|
||||
inpos++; // consume the ';'
|
||||
*continuebuffer = &inbuffer[inpos];
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
buffer[outpos] = 0;
|
||||
return arg;
|
||||
}
|
||||
|
||||
@@ -230,37 +493,61 @@ static void convert_args(int argc, cmd_args *argv)
|
||||
for (i = 0; i < argc; i++) {
|
||||
argv[i].u = atoui(argv[i].str);
|
||||
argv[i].i = atoi(argv[i].str);
|
||||
|
||||
if (!strcmp(argv[i].str, "true") || !strcmp(argv[i].str, "on")) {
|
||||
argv[i].b = true;
|
||||
} else if (!strcmp(argv[i].str, "false") || !strcmp(argv[i].str, "off")) {
|
||||
argv[i].b = false;
|
||||
} else {
|
||||
argv[i].b = (argv[i].u == 0) ? false : true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void console_loop(void)
|
||||
static void command_loop(int (*get_line)(const char **, void *), void *get_line_cookie, bool showprompt, bool locked)
|
||||
{
|
||||
bool exit;
|
||||
bool report_result;
|
||||
cmd_args args[16];
|
||||
char buffer[256];
|
||||
const char *buffer;
|
||||
const char *continuebuffer;
|
||||
char *outbuf;
|
||||
|
||||
printf("entering main console loop\n");
|
||||
const size_t outbuflen = 1024;
|
||||
outbuf = malloc(outbuflen);
|
||||
|
||||
for (;;) {
|
||||
puts("] ");
|
||||
exit = false;
|
||||
continuebuffer = NULL;
|
||||
while (!exit) {
|
||||
// read a new line if it hadn't been split previously and passed back from tokenize_command
|
||||
if (continuebuffer == NULL) {
|
||||
if (showprompt)
|
||||
puts("] ");
|
||||
|
||||
int len = read_line(buffer, sizeof(buffer));
|
||||
if (len == 0)
|
||||
continue;
|
||||
int len = get_line(&buffer, get_line_cookie);
|
||||
if (len < 0)
|
||||
break;
|
||||
if (len == 0)
|
||||
continue;
|
||||
} else {
|
||||
buffer = continuebuffer;
|
||||
}
|
||||
|
||||
// printf("line = '%s'\n", buffer);
|
||||
// dprintf("line = '%s'\n", buffer);
|
||||
|
||||
/* tokenize the line */
|
||||
int argc = tokenize_command(buffer, args, 16);
|
||||
int argc = tokenize_command(buffer, &continuebuffer, outbuf, outbuflen, args, 16);
|
||||
if (argc < 0) {
|
||||
printf("syntax error\n");
|
||||
if (showprompt)
|
||||
printf("syntax error\n");
|
||||
continue;
|
||||
} else if (argc == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// printf("after tokenize: argc %d\n", argc);
|
||||
// dprintf("after tokenize: argc %d\n", argc);
|
||||
// for (int i = 0; i < argc; i++)
|
||||
// printf("%d: '%s'\n", i, args[i].str);
|
||||
// dprintf("%d: '%s'\n", i, args[i].str);
|
||||
|
||||
/* convert the args */
|
||||
convert_args(argc, args);
|
||||
@@ -268,42 +555,132 @@ static void console_loop(void)
|
||||
/* try to match the command */
|
||||
const cmd *command = match_command(args[0].str);
|
||||
if (!command) {
|
||||
printf("command not found\n");
|
||||
if (showprompt)
|
||||
printf("command not found\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
int result = command->cmd_callback(argc, args);
|
||||
if (!locked)
|
||||
mutex_acquire(command_lock);
|
||||
|
||||
// XXX do something with the result
|
||||
abort_script = false;
|
||||
lastresult = command->cmd_callback(argc, args);
|
||||
|
||||
#if WITH_LIB_ENV
|
||||
if ((env_get_bool("reportresult", &report_result, false) >= 0) &&
|
||||
(report_result))
|
||||
{
|
||||
if (lastresult < 0)
|
||||
printf("FAIL %d\n", lastresult);
|
||||
else
|
||||
printf("PASS %d\n", lastresult);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WITH_LIB_ENV
|
||||
// stuff the result in an environment var
|
||||
env_set_int("?", lastresult, true);
|
||||
#endif
|
||||
|
||||
// someone must have aborted the current script
|
||||
if (abort_script)
|
||||
exit = true;
|
||||
abort_script = false;
|
||||
|
||||
if (!locked)
|
||||
mutex_release(command_lock);
|
||||
}
|
||||
|
||||
free(outbuf);
|
||||
}
|
||||
|
||||
void console_abort_script(void)
|
||||
{
|
||||
abort_script = true;
|
||||
}
|
||||
|
||||
void console_start(void)
|
||||
{
|
||||
debug_buffer = malloc(LINE_LEN);
|
||||
|
||||
console_loop();
|
||||
dprintf(INFO, "entering main console loop\n");
|
||||
|
||||
for (;;)
|
||||
command_loop(&read_debug_line, NULL, true, false);
|
||||
}
|
||||
|
||||
int console_run_command(const char *string)
|
||||
struct line_read_struct {
|
||||
const char *string;
|
||||
int pos;
|
||||
char *buffer;
|
||||
size_t buflen;
|
||||
};
|
||||
|
||||
static int fetch_next_line(const char **buffer, void *cookie)
|
||||
{
|
||||
const cmd *command;
|
||||
struct line_read_struct *lineread = (struct line_read_struct *)cookie;
|
||||
|
||||
ASSERT(string != NULL);
|
||||
|
||||
command = match_command(string);
|
||||
if (!command)
|
||||
// we're done
|
||||
if (lineread->string[lineread->pos] == 0)
|
||||
return -1;
|
||||
|
||||
int result = command->cmd_callback(0, NULL);
|
||||
size_t bufpos = 0;
|
||||
while (lineread->string[lineread->pos] != 0) {
|
||||
if (lineread->string[lineread->pos] == '\n') {
|
||||
lineread->pos++;
|
||||
break;
|
||||
}
|
||||
if (bufpos == (lineread->buflen - 1))
|
||||
break;
|
||||
lineread->buffer[bufpos] = lineread->string[lineread->pos];
|
||||
lineread->pos++;
|
||||
bufpos++;
|
||||
}
|
||||
lineread->buffer[bufpos] = 0;
|
||||
|
||||
return result;
|
||||
*buffer = lineread->buffer;
|
||||
|
||||
return bufpos;
|
||||
}
|
||||
|
||||
static int console_run_script_etc(const char *string, bool locked)
|
||||
{
|
||||
struct line_read_struct lineread;
|
||||
|
||||
lineread.string = string;
|
||||
lineread.pos = 0;
|
||||
lineread.buffer = malloc(LINE_LEN);
|
||||
lineread.buflen = LINE_LEN;
|
||||
|
||||
command_loop(&fetch_next_line, (void *)&lineread, false, locked);
|
||||
|
||||
return lastresult;
|
||||
}
|
||||
|
||||
int console_run_script(const char *string)
|
||||
{
|
||||
return console_run_script_etc(string, false);
|
||||
}
|
||||
|
||||
int console_run_script_locked(const char *string)
|
||||
{
|
||||
return console_run_script_etc(string, true);
|
||||
}
|
||||
|
||||
console_cmd console_get_command_handler(const char *commandstr)
|
||||
{
|
||||
const cmd *command = match_command(commandstr);
|
||||
|
||||
if (command)
|
||||
return command->cmd_callback;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void console_register_commands(cmd_block *block)
|
||||
{
|
||||
ASSERT(block);
|
||||
ASSERT(block->next == NULL);
|
||||
DEBUG_ASSERT(block);
|
||||
DEBUG_ASSERT(block->next == NULL);
|
||||
|
||||
block->next = command_list;
|
||||
command_list = block;
|
||||
@@ -320,21 +697,24 @@ static int cmd_help(int argc, const cmd_args *argv)
|
||||
for (block = command_list; block != NULL; block = block->next) {
|
||||
const cmd *curr_cmd = block->list;
|
||||
for (i = 0; i < block->count; i++) {
|
||||
printf("\t%-16s: %s\n", curr_cmd[i].cmd_str, curr_cmd[i].help_str ? curr_cmd[i].help_str : "");
|
||||
if (curr_cmd[i].help_str)
|
||||
printf("\t%-16s: %s\n", curr_cmd[i].cmd_str, curr_cmd[i].help_str);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if DEBUGLEVEL > 1
|
||||
static int cmd_test(int argc, const cmd_args *argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
printf("argc %d, argv %p\n", argc, argv);
|
||||
for (i = 0; i < argc; i++)
|
||||
printf("\t%d: str '%s', i %d, u %#x\n", i, argv[i].str, argv[i].i, argv[i].u);
|
||||
printf("\t%d: str '%s', i %d, u %#x, b %d\n", i, argv[i].str, argv[i].i, argv[i].u, argv[i].b);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user