2008-08-14 17:19:13 +00:00
|
|
|
#include <base/system.h>
|
2008-09-23 13:14:04 +00:00
|
|
|
#include "e_if_other.h"
|
2008-01-16 22:14:06 +00:00
|
|
|
#include "e_console.h"
|
|
|
|
#include "e_config.h"
|
2008-03-01 14:36:36 +00:00
|
|
|
#include "e_linereader.h"
|
2008-01-16 22:14:06 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
2008-02-02 12:38:36 +00:00
|
|
|
|
2008-03-29 14:34:40 +00:00
|
|
|
#define CONSOLE_MAX_STR_LENGTH 1024
|
2008-02-02 12:38:36 +00:00
|
|
|
/* the maximum number of tokens occurs in a string of length CONSOLE_MAX_STR_LENGTH with tokens size 1 separated by single spaces */
|
2008-03-14 23:39:52 +00:00
|
|
|
#define MAX_PARTS (CONSOLE_MAX_STR_LENGTH+1)/2
|
|
|
|
|
2008-02-02 12:38:36 +00:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
char string_storage[CONSOLE_MAX_STR_LENGTH+1];
|
2008-03-14 23:39:52 +00:00
|
|
|
char *args_start;
|
|
|
|
|
|
|
|
const char *command;
|
|
|
|
const char *args[MAX_PARTS];
|
|
|
|
unsigned int num_args;
|
|
|
|
} PARSE_RESULT;
|
2008-02-02 12:38:36 +00:00
|
|
|
|
2008-03-14 23:39:52 +00:00
|
|
|
static char *str_skipblanks(char *str)
|
2008-01-16 22:14:06 +00:00
|
|
|
{
|
2008-03-14 23:39:52 +00:00
|
|
|
while(*str && (*str == ' ' || *str == '\t' || *str == '\n'))
|
2008-01-17 23:04:53 +00:00
|
|
|
str++;
|
2008-03-14 23:39:52 +00:00
|
|
|
return str;
|
2008-01-16 22:14:06 +00:00
|
|
|
}
|
|
|
|
|
2008-03-14 23:39:52 +00:00
|
|
|
static char *str_skiptoblank(char *str)
|
|
|
|
{
|
|
|
|
while(*str && (*str != ' ' && *str != '\t' && *str != '\n'))
|
|
|
|
str++;
|
|
|
|
return str;
|
2008-01-16 22:14:06 +00:00
|
|
|
}
|
|
|
|
|
2008-03-14 23:39:52 +00:00
|
|
|
/* static int digit(char c) { return '0' <= c && c <= '9'; } */
|
|
|
|
|
2008-03-21 20:32:05 +00:00
|
|
|
static int console_parse_start(PARSE_RESULT *result, const char *string, int length)
|
2008-01-16 22:14:06 +00:00
|
|
|
{
|
2008-03-14 23:39:52 +00:00
|
|
|
char *str;
|
2008-03-21 20:32:05 +00:00
|
|
|
int len = sizeof(result->string_storage);
|
|
|
|
if(length < len)
|
|
|
|
len = length;
|
|
|
|
|
|
|
|
str_copy(result->string_storage, string, length);
|
2008-03-14 23:39:52 +00:00
|
|
|
str = result->string_storage;
|
2008-02-02 12:38:36 +00:00
|
|
|
|
2008-03-14 23:39:52 +00:00
|
|
|
/* get command */
|
|
|
|
str = str_skipblanks(str);
|
|
|
|
result->command = str;
|
|
|
|
str = str_skiptoblank(str);
|
|
|
|
|
|
|
|
if(*str)
|
2008-01-16 22:14:06 +00:00
|
|
|
{
|
2008-03-14 23:39:52 +00:00
|
|
|
str[0] = 0;
|
|
|
|
str++;
|
2008-01-16 22:14:06 +00:00
|
|
|
}
|
2008-03-14 23:39:52 +00:00
|
|
|
|
|
|
|
result->args_start = str;
|
|
|
|
result->num_args = 0;
|
|
|
|
return 0;
|
2008-01-16 22:14:06 +00:00
|
|
|
}
|
|
|
|
|
2008-03-14 23:39:52 +00:00
|
|
|
static int console_parse_args(PARSE_RESULT *result, const char *format)
|
2008-01-16 22:14:06 +00:00
|
|
|
{
|
2008-03-14 23:39:52 +00:00
|
|
|
char command;
|
|
|
|
char *str;
|
|
|
|
int optional = 0;
|
|
|
|
int error = 0;
|
2008-02-02 12:38:36 +00:00
|
|
|
|
2008-03-14 23:39:52 +00:00
|
|
|
str = result->args_start;
|
2008-01-16 22:14:06 +00:00
|
|
|
|
2008-03-14 23:39:52 +00:00
|
|
|
while(1)
|
|
|
|
{
|
|
|
|
/* fetch command */
|
|
|
|
command = *format;
|
|
|
|
format++;
|
|
|
|
|
|
|
|
if(!command)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if(command == '?')
|
|
|
|
optional = 1;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
str = str_skipblanks(str);
|
|
|
|
|
|
|
|
if(!(*str)) /* error, non optional command needs value */
|
|
|
|
{
|
|
|
|
if(!optional)
|
|
|
|
error = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add token */
|
2008-03-30 12:46:58 +00:00
|
|
|
if(*str == '"')
|
2008-03-14 23:39:52 +00:00
|
|
|
{
|
2008-03-30 12:46:58 +00:00
|
|
|
char *dst;
|
2008-03-14 23:39:52 +00:00
|
|
|
str++;
|
2008-03-30 12:46:58 +00:00
|
|
|
result->args[result->num_args++] = str;
|
|
|
|
|
|
|
|
dst = str; /* we might have to process escape data */
|
|
|
|
while(1)
|
|
|
|
{
|
|
|
|
if(str[0] == '"')
|
|
|
|
break;
|
|
|
|
else if(str[0] == '\\')
|
|
|
|
{
|
|
|
|
if(str[1] == '\\')
|
|
|
|
str++; /* skip due to escape */
|
|
|
|
else if(str[1] == '"')
|
|
|
|
str++; /* skip due to escape */
|
|
|
|
}
|
|
|
|
else if(str[0] == 0)
|
|
|
|
return 1; /* return error */
|
|
|
|
|
|
|
|
*dst = *str;
|
|
|
|
dst++;
|
|
|
|
str++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* write null termination */
|
|
|
|
*dst = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
result->args[result->num_args++] = str;
|
|
|
|
|
|
|
|
if(command == 'r') /* rest of the string */
|
|
|
|
break;
|
|
|
|
else if(command == 'i') /* validate int */
|
|
|
|
str = str_skiptoblank(str);
|
|
|
|
else if(command == 'f') /* validate float */
|
|
|
|
str = str_skiptoblank(str);
|
|
|
|
else if(command == 's') /* validate string */
|
|
|
|
str = str_skiptoblank(str);
|
|
|
|
|
|
|
|
if(str[0] != 0) /* check for end of string */
|
|
|
|
{
|
|
|
|
str[0] = 0;
|
|
|
|
str++;
|
|
|
|
}
|
2008-03-14 23:39:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-01-16 22:14:06 +00:00
|
|
|
|
2008-03-14 23:39:52 +00:00
|
|
|
return error;
|
|
|
|
}
|
2008-01-16 22:14:06 +00:00
|
|
|
|
2008-03-14 23:39:52 +00:00
|
|
|
const char *console_arg_string(void *res, int index)
|
|
|
|
{
|
|
|
|
PARSE_RESULT *result = (PARSE_RESULT *)res;
|
|
|
|
if (index < 0 || index >= result->num_args)
|
|
|
|
return "";
|
|
|
|
return result->args[index];
|
|
|
|
}
|
2008-01-16 22:14:06 +00:00
|
|
|
|
2008-03-14 23:39:52 +00:00
|
|
|
int console_arg_int(void *res, int index)
|
|
|
|
{
|
|
|
|
PARSE_RESULT *result = (PARSE_RESULT *)res;
|
|
|
|
if (index < 0 || index >= result->num_args)
|
2008-01-16 22:14:06 +00:00
|
|
|
return 0;
|
2008-03-14 23:39:52 +00:00
|
|
|
return atoi(result->args[index]);
|
2008-01-16 22:14:06 +00:00
|
|
|
}
|
|
|
|
|
2008-03-14 23:39:52 +00:00
|
|
|
float console_arg_float(void *res, int index)
|
2008-01-16 22:14:06 +00:00
|
|
|
{
|
2008-03-14 23:39:52 +00:00
|
|
|
PARSE_RESULT *result = (PARSE_RESULT *)res;
|
|
|
|
if (index < 0 || index >= result->num_args)
|
|
|
|
return 0.0f;
|
|
|
|
return atof(result->args[index]);
|
|
|
|
}
|
2008-01-16 22:14:06 +00:00
|
|
|
|
2008-03-14 23:39:52 +00:00
|
|
|
int console_arg_num(void *result)
|
|
|
|
{
|
|
|
|
return ((PARSE_RESULT *)result)->num_args;
|
2008-01-16 22:14:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static COMMAND *first_command = 0x0;
|
|
|
|
|
|
|
|
COMMAND *console_find_command(const char *name)
|
|
|
|
{
|
|
|
|
COMMAND *cmd;
|
|
|
|
for (cmd = first_command; cmd; cmd = cmd->next)
|
2008-03-14 23:39:52 +00:00
|
|
|
{
|
2008-01-16 22:14:06 +00:00
|
|
|
if (strcmp(cmd->name, name) == 0)
|
|
|
|
return cmd;
|
2008-03-14 23:39:52 +00:00
|
|
|
}
|
2008-01-16 22:14:06 +00:00
|
|
|
|
|
|
|
return 0x0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void console_register(COMMAND *cmd)
|
|
|
|
{
|
|
|
|
cmd->next = first_command;
|
|
|
|
first_command = cmd;
|
|
|
|
}
|
|
|
|
|
2008-08-27 16:23:15 +00:00
|
|
|
static void (*print_callback)(const char *, void *) = 0x0;
|
|
|
|
static void *print_callback_userdata;
|
2008-01-16 22:14:06 +00:00
|
|
|
|
2008-08-27 16:23:15 +00:00
|
|
|
void console_register_print_callback(void (*callback)(const char *, void *), void *user_data)
|
2008-01-16 22:14:06 +00:00
|
|
|
{
|
|
|
|
print_callback = callback;
|
2008-08-27 16:23:15 +00:00
|
|
|
print_callback_userdata = user_data;
|
2008-01-16 22:14:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void console_print(const char *str)
|
|
|
|
{
|
|
|
|
if (print_callback)
|
2008-08-27 16:23:15 +00:00
|
|
|
print_callback(str, print_callback_userdata);
|
2008-01-16 22:14:06 +00:00
|
|
|
}
|
|
|
|
|
2008-03-01 20:03:04 +00:00
|
|
|
void console_execute_line_stroked(int stroke, const char *str)
|
2008-01-16 22:14:06 +00:00
|
|
|
{
|
2008-03-14 23:39:52 +00:00
|
|
|
PARSE_RESULT result;
|
|
|
|
COMMAND *command;
|
|
|
|
|
|
|
|
char strokestr[2] = {'0', 0};
|
2008-03-01 20:03:04 +00:00
|
|
|
if(stroke)
|
|
|
|
strokestr[0] = '1';
|
2008-01-16 22:14:06 +00:00
|
|
|
|
2008-03-21 20:32:05 +00:00
|
|
|
while(str)
|
2008-03-14 23:39:52 +00:00
|
|
|
{
|
2008-03-21 20:32:05 +00:00
|
|
|
const char *end = str;
|
|
|
|
const char *next_part = 0;
|
2008-03-30 12:46:58 +00:00
|
|
|
int in_string = 0;
|
2008-03-21 20:32:05 +00:00
|
|
|
|
|
|
|
while(*end)
|
2008-01-16 22:14:06 +00:00
|
|
|
{
|
2008-03-30 12:46:58 +00:00
|
|
|
if(*end == '"')
|
|
|
|
in_string ^= 1;
|
2008-04-05 07:38:48 +00:00
|
|
|
else if(*end == '\\') /* escape sequences */
|
2008-03-30 12:46:58 +00:00
|
|
|
{
|
|
|
|
if(end[1] == '"')
|
|
|
|
end++;
|
|
|
|
}
|
2008-04-05 07:38:48 +00:00
|
|
|
else if(!in_string)
|
2008-03-21 20:32:05 +00:00
|
|
|
{
|
2008-04-05 07:38:48 +00:00
|
|
|
if(*end == ';') /* command separator */
|
|
|
|
{
|
|
|
|
next_part = end+1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if(*end == '#') /* comment, no need to do anything more */
|
|
|
|
break;
|
2008-03-21 20:32:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
end++;
|
2008-01-16 22:14:06 +00:00
|
|
|
}
|
2008-03-14 23:39:52 +00:00
|
|
|
|
2008-03-21 20:32:05 +00:00
|
|
|
if(console_parse_start(&result, str, (end-str) + 1) != 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
command = console_find_command(result.command);
|
|
|
|
|
|
|
|
if(command)
|
2008-01-16 22:14:06 +00:00
|
|
|
{
|
2008-03-21 20:32:05 +00:00
|
|
|
int is_stroke_command = 0;
|
|
|
|
if(result.command[0] == '+')
|
2008-03-14 23:39:52 +00:00
|
|
|
{
|
2008-03-21 20:32:05 +00:00
|
|
|
/* insert the stroke direction token */
|
|
|
|
result.args[result.num_args] = strokestr;
|
|
|
|
result.num_args++;
|
|
|
|
is_stroke_command = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(stroke || is_stroke_command)
|
|
|
|
{
|
|
|
|
if(console_parse_args(&result, command->params))
|
|
|
|
{
|
|
|
|
char buf[256];
|
|
|
|
str_format(buf, sizeof(buf), "Invalid arguments... Usage: %s %s", command->name, command->params);
|
|
|
|
console_print(buf);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
command->callback(&result, command->user_data);
|
2008-03-14 23:39:52 +00:00
|
|
|
}
|
2008-01-16 22:14:06 +00:00
|
|
|
}
|
2008-03-21 20:32:05 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
char buf[256];
|
|
|
|
str_format(buf, sizeof(buf), "No such command: %s.", result.command);
|
|
|
|
console_print(buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
str = next_part;
|
2008-03-14 23:39:52 +00:00
|
|
|
}
|
2008-01-16 22:14:06 +00:00
|
|
|
}
|
|
|
|
|
2008-03-01 20:03:04 +00:00
|
|
|
void console_execute_line(const char *str)
|
|
|
|
{
|
|
|
|
console_execute_line_stroked(1, str);
|
|
|
|
}
|
|
|
|
|
2008-03-18 21:10:03 +00:00
|
|
|
static void console_execute_file_real(const char *filename)
|
2008-03-01 14:36:36 +00:00
|
|
|
{
|
|
|
|
IOHANDLE file;
|
|
|
|
file = io_open(filename, IOFLAG_READ);
|
|
|
|
|
|
|
|
if(file)
|
|
|
|
{
|
|
|
|
char *line;
|
|
|
|
LINEREADER lr;
|
|
|
|
|
|
|
|
dbg_msg("console", "executing '%s'", filename);
|
|
|
|
linereader_init(&lr, file);
|
|
|
|
|
|
|
|
while((line = linereader_get(&lr)))
|
|
|
|
console_execute_line(line);
|
|
|
|
|
|
|
|
io_close(file);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
dbg_msg("console", "failed to open '%s'", filename);
|
|
|
|
}
|
|
|
|
|
2008-03-18 21:10:03 +00:00
|
|
|
struct exec_file
|
|
|
|
{
|
|
|
|
const char *filename;
|
|
|
|
struct exec_file *next;
|
|
|
|
};
|
|
|
|
|
|
|
|
void console_execute_file(const char *filename)
|
|
|
|
{
|
|
|
|
static struct exec_file *first = 0;
|
|
|
|
struct exec_file this;
|
|
|
|
struct exec_file *cur;
|
|
|
|
struct exec_file *prev;
|
|
|
|
|
|
|
|
/* make sure that this isn't being executed already */
|
|
|
|
for(cur = first; cur; cur = cur->next)
|
|
|
|
if(strcmp(filename, cur->filename) == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* push this one to the stack */
|
|
|
|
prev = first;
|
|
|
|
this.filename = filename;
|
|
|
|
this.next = first;
|
|
|
|
first = &this;
|
|
|
|
|
|
|
|
/* execute file */
|
|
|
|
console_execute_file_real(filename);
|
|
|
|
|
|
|
|
/* pop this one from the stack */
|
|
|
|
first = prev;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void con_echo(void *result, void *user_data)
|
2008-01-16 22:14:06 +00:00
|
|
|
{
|
2008-03-14 23:39:52 +00:00
|
|
|
console_print(console_arg_string(result, 0));
|
2008-01-16 22:14:06 +00:00
|
|
|
}
|
|
|
|
|
2008-03-18 21:10:03 +00:00
|
|
|
static void con_exec(void *result, void *user_data)
|
|
|
|
{
|
|
|
|
console_execute_file(console_arg_string(result, 0));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2008-01-16 22:14:06 +00:00
|
|
|
|
2008-02-02 12:38:36 +00:00
|
|
|
typedef struct
|
2008-01-16 22:14:06 +00:00
|
|
|
{
|
2008-02-02 12:38:36 +00:00
|
|
|
CONFIG_INT_GETTER getter;
|
|
|
|
CONFIG_INT_SETTER setter;
|
|
|
|
} INT_VARIABLE_DATA;
|
2008-01-16 22:14:06 +00:00
|
|
|
|
2008-02-02 12:38:36 +00:00
|
|
|
typedef struct
|
2008-01-16 22:14:06 +00:00
|
|
|
{
|
2008-02-02 12:38:36 +00:00
|
|
|
CONFIG_STR_GETTER getter;
|
|
|
|
CONFIG_STR_SETTER setter;
|
|
|
|
} STR_VARIABLE_DATA;
|
2008-01-16 22:14:06 +00:00
|
|
|
|
2008-02-02 12:38:36 +00:00
|
|
|
static void int_variable_command(void *result, void *user_data)
|
2008-01-16 22:14:06 +00:00
|
|
|
{
|
2008-02-02 12:38:36 +00:00
|
|
|
INT_VARIABLE_DATA *data = (INT_VARIABLE_DATA *)user_data;
|
2008-01-16 22:14:06 +00:00
|
|
|
|
2008-03-14 23:39:52 +00:00
|
|
|
if(console_arg_num(result))
|
|
|
|
data->setter(&config, console_arg_int(result, 0));
|
|
|
|
else
|
2008-01-16 22:14:06 +00:00
|
|
|
{
|
2008-03-29 14:34:40 +00:00
|
|
|
char buf[1024];
|
2008-02-11 21:49:26 +00:00
|
|
|
str_format(buf, sizeof(buf), "Value: %d", data->getter(&config));
|
2008-01-16 22:14:06 +00:00
|
|
|
console_print(buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-02 12:38:36 +00:00
|
|
|
static void str_variable_command(void *result, void *user_data)
|
2008-01-16 22:14:06 +00:00
|
|
|
{
|
2008-02-02 12:38:36 +00:00
|
|
|
STR_VARIABLE_DATA *data = (STR_VARIABLE_DATA *)user_data;
|
2008-01-16 22:14:06 +00:00
|
|
|
|
2008-03-14 23:39:52 +00:00
|
|
|
if(console_arg_num(result))
|
|
|
|
data->setter(&config, console_arg_string(result, 0));
|
|
|
|
else
|
2008-01-16 22:14:06 +00:00
|
|
|
{
|
2008-03-29 14:34:40 +00:00
|
|
|
char buf[1024];
|
2008-02-11 21:49:26 +00:00
|
|
|
str_format(buf, sizeof(buf), "Value: %s", data->getter(&config));
|
2008-01-16 22:14:06 +00:00
|
|
|
console_print(buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void console_init()
|
|
|
|
{
|
2008-03-18 21:10:03 +00:00
|
|
|
MACRO_REGISTER_COMMAND("echo", "r", con_echo, 0x0);
|
|
|
|
MACRO_REGISTER_COMMAND("exec", "r", con_exec, 0x0);
|
2008-01-16 22:14:06 +00:00
|
|
|
|
2008-02-11 21:44:36 +00:00
|
|
|
#define MACRO_CONFIG_INT(name,def,min,max) { static INT_VARIABLE_DATA data = { &config_get_ ## name, &config_set_ ## name }; MACRO_REGISTER_COMMAND(#name, "?i", int_variable_command, &data) }
|
2008-03-15 13:27:24 +00:00
|
|
|
#define MACRO_CONFIG_STR(name,len,def) { static STR_VARIABLE_DATA data = { &config_get_ ## name, &config_set_ ## name }; MACRO_REGISTER_COMMAND(#name, "?r", str_variable_command, &data) }
|
2008-01-16 22:14:06 +00:00
|
|
|
|
2008-02-11 21:44:36 +00:00
|
|
|
#include "e_config_variables.h"
|
2008-01-16 22:14:06 +00:00
|
|
|
|
2008-02-11 21:44:36 +00:00
|
|
|
#undef MACRO_CONFIG_INT
|
|
|
|
#undef MACRO_CONFIG_STR
|
2008-01-16 22:14:06 +00:00
|
|
|
}
|