diff options
Diffstat (limited to 'src/engine')
| -rw-r--r-- | src/engine/e_config.c | 1 | ||||
| -rw-r--r-- | src/engine/e_config.h | 6 | ||||
| -rw-r--r-- | src/engine/e_console.c | 368 | ||||
| -rw-r--r-- | src/engine/e_console.h | 64 | ||||
| -rw-r--r-- | src/engine/e_engine.c | 4 | ||||
| -rw-r--r-- | src/engine/e_system.c | 13 |
6 files changed, 455 insertions, 1 deletions
diff --git a/src/engine/e_config.c b/src/engine/e_config.c index a4c47ec1..44008b77 100644 --- a/src/engine/e_config.c +++ b/src/engine/e_config.c @@ -7,7 +7,6 @@ #include "e_system.h" #include "e_config.h" - /* buffered stream for reading lines, should perhaps be something smaller */ typedef struct { diff --git a/src/engine/e_config.h b/src/engine/e_config.h index 63933660..b6fbc93d 100644 --- a/src/engine/e_config.h +++ b/src/engine/e_config.h @@ -17,11 +17,17 @@ typedef struct extern CONFIGURATION config; +void config_init(); void config_set(const char *line); void config_reset(); void config_load(const char *filename); void config_save(const char *filename); +typedef int (*config_int_getter)(CONFIGURATION *c); +typedef const char *(*config_str_getter)(CONFIGURATION *c); +typedef void (*config_int_setter)(CONFIGURATION *c, int val); +typedef void (*config_str_setter)(CONFIGURATION *c, const char *str); + #define MACRO_CONFIG_INT(name,def,min,max) int config_get_ ## name (CONFIGURATION *c); #define MACRO_CONFIG_STR(name,len,def) const char *config_get_ ## name (CONFIGURATION *c); #include "e_config_variables.h" diff --git a/src/engine/e_console.c b/src/engine/e_console.c new file mode 100644 index 00000000..edcd90fd --- /dev/null +++ b/src/engine/e_console.c @@ -0,0 +1,368 @@ +#include "e_console.h" +#include "e_config.h" +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +enum +{ + STATE_START, + STATE_INT, + STATE_FLOAT, + STATE_POT_FLOAT, + STATE_STRING, + STATE_QUOTED, + STATE_ESCAPE +}; + +static const char *store_string(struct lexer_result *res, const char *str, int len) +{ + const char *ptr = res->next_string; + + memcpy(res->next_string, str, len); + res->next_string[len] = 0; + res->next_string += len+1; + + return ptr; +} + +static void save_token(struct lexer_result *res, int *index, const char **start, const char *end, int *state, int type) +{ + /* printf("Saving token with length %d\n", end - *start); */ + struct token *tok = &res->tokens[*index]; + tok->stored_string = store_string(res, *start, end - *start); + tok->type = type; + ++res->num_tokens; + + *start = end + 1; + *state = STATE_START; + ++*index; +} + +int digit(char c) +{ + return '0' <= c && c <= '9'; +} + +int lex(const char *line, struct lexer_result *res) +{ + int state = STATE_START, i = 0; + int length_left = CONSOLE_MAX_STR_LENGTH; + const char *start, *c; + res->num_tokens = 0; + + memset(res, 0, sizeof(*res)); + res->next_string = res->string_storage; + + for (c = start = line; *c != '\0' && res->num_tokens < MAX_TOKENS && length_left; ++c, --length_left) + { + /* printf("State: %d\n", state); */ + switch (state) + { + case STATE_START: + if (*c == ' ') + start = c + 1; + else if (digit(*c)) + state = STATE_INT; + else if (*c == '.') + state = STATE_POT_FLOAT; + else + state = STATE_STRING; + break; + + case STATE_INT: + if (digit(*c)) + ; + else if (*c == '.') + state = STATE_FLOAT; + else if (*c == ' ') + save_token(res, &i, &start, c, &state, TOKEN_INT); + else + state = STATE_STRING; + break; + + case STATE_FLOAT: + if (digit(*c)) + ; + else if (*c == ' ') + save_token(res, &i, &start, c, &state, TOKEN_FLOAT); + else + state = STATE_STRING; + break; + + case STATE_POT_FLOAT: + if (digit(*c)) + state = STATE_FLOAT; + else if (*c == ' ') + save_token(res, &i, &start, c, &state, TOKEN_STRING); + else + state = STATE_STRING; + break; + + case STATE_STRING: + if (*c == ' ') + save_token(res, &i, &start, c, &state, TOKEN_STRING); + break; + + case STATE_QUOTED: + if (*c == '"') + save_token(res, &i, &start, c, &state, TOKEN_STRING); + else if (*c == '\\') + state = STATE_ESCAPE; + break; + + case STATE_ESCAPE: + if (*c != ' ') + state = STATE_QUOTED; + break; + } + } + + switch (state) + { + case STATE_INT: + save_token(res, &i, &start, c, &state, TOKEN_INT); + break; + case STATE_FLOAT: + save_token(res, &i, &start, c, &state, TOKEN_FLOAT); + break; + case STATE_STRING: + case STATE_QUOTED: + case STATE_POT_FLOAT: + save_token(res, &i, &start, c, &state, TOKEN_STRING); + break; + case STATE_ESCAPE: + puts("LOL MALFORMED"); + break; + default: + break; + } + + return 0; +} + +int extract_result_string(struct lexer_result *result, int index, const char **str) +{ + if (index < 0 || index >= result->num_tokens) + return -1; + else + { + struct token *t = &result->tokens[index]; + + *str = t->stored_string; + + return 0; + } +} + +int extract_result_int(struct lexer_result *result, int index, int *i) +{ + if (index < 0 || index >= result->num_tokens) + return -1; + else + { + struct token *t = &result->tokens[index]; + const char *str; + + if (t->type != TOKEN_INT) + return -2; + + extract_result_string(result, index, &str); + + *i = atoi(str); + + return 0; + } +} + +int extract_result_float(struct lexer_result *result, int index, float *f) +{ + if (index < 0 || index >= result->num_tokens) + return -1; + else + { + struct token *t = &result->tokens[index]; + const char *str; + + if (t->type != TOKEN_INT && t->type != TOKEN_FLOAT) + return -2; + + extract_result_string(result, index, &str); + + *f = atof(str); + + return 0; + } +} + +static COMMAND *first_command = 0x0; + +COMMAND *console_find_command(const char *name) +{ + COMMAND *cmd; + for (cmd = first_command; cmd; cmd = cmd->next) + if (strcmp(cmd->name, name) == 0) + return cmd; + + return 0x0; +} + +void console_register(COMMAND *cmd) +{ + cmd->next = first_command; + first_command = cmd; +} + + +static int console_validate(COMMAND *command, struct lexer_result *result) +{ + const char *c = command->params; + int i = 1; + + const char *dummy_s; + int dummy_i; + float dummy_f; + + while (*c && *c != '?') + { + switch (*c) + { + case 's': + if (extract_result_string(result, i, &dummy_s)) + return -1; + break; + case 'i': + if (extract_result_int(result, i, &dummy_i)) + return -1; + break; + case 'f': + if (extract_result_float(result, i, &dummy_f)) + return -1; + break; + default: + // unknown char, so just continue... + c++; + continue; + } + + i++; + c++; + } + + return 0; +} + +static void (*print_callback)(const char *) = 0x0; + +void console_register_print_callback(void (*callback)(const char *)) +{ + print_callback = callback; +} + +void console_print(const char *str) +{ + if (print_callback) + print_callback(str); +} + +void console_execute(const char *str) +{ + struct lexer_result result; + int error; + + if ((error = lex(str, &result))) + printf("ERROR: %d\n", error); + else if (result.num_tokens > 0) + { + const char *name; + extract_result_string(&result, 0, &name); + + COMMAND *command = console_find_command(name); + + if (command) + { + if (console_validate(command, &result)) + { + char buf[256]; + sprintf(buf, "Invalid arguments... Usage: %s %s", command->name, command->params); + console_print(buf); + } + else + command->callback(&result, command->user_data); + } + else + { + char buf[256]; + sprintf(buf, "No such command: %s.", name); + console_print(buf); + } + } +} + +static void echo_command(struct lexer_result *result, void *user_data) +{ + const char *str; + extract_result_string(result, 1, &str); + + console_print(str); +} + + +struct int_variable_data +{ + config_int_getter getter; + config_int_setter setter; +}; + +struct str_variable_data +{ + config_str_getter getter; + config_str_setter setter; +}; + +static void int_variable_command(struct lexer_result *result, void *user_data) +{ + struct int_variable_data *data = (struct int_variable_data *)user_data; + int new_val; + + if (extract_result_int(result, 1, &new_val)) + { + char buf[256]; + sprintf(buf, "Value: %d", data->getter(&config)); + console_print(buf); + } + else + { + data->setter(&config, new_val); + } +} + +static void str_variable_command(struct lexer_result *result, void *user_data) +{ + struct str_variable_data *data = (struct str_variable_data *)user_data; + const char *new_val; + + if (extract_result_string(result, 1, &new_val)) + { + char buf[256]; + sprintf(buf, "Value: %s", data->getter(&config)); + console_print(buf); + } + else + { + data->setter(&config, new_val); + } +} + +void console_init() +{ + MACRO_REGISTER_COMMAND("echo", "s", echo_command, 0x0); + + #define MACRO_CONFIG_INT(name,def,min,max) { static struct int_variable_data data = { &config_get_ ## name, &config_set_ ## name }; MACRO_REGISTER_COMMAND(#name, "?i", int_variable_command, &data) } + #define MACRO_CONFIG_STR(name,len,def) { static struct str_variable_data data = { &config_get_ ## name, &config_set_ ## name }; MACRO_REGISTER_COMMAND(#name, "?s", str_variable_command, &data) } + + #include "e_config_variables.h" + + #undef MACRO_CONFIG_INT + #undef MACRO_CONFIG_STR +} diff --git a/src/engine/e_console.h b/src/engine/e_console.h new file mode 100644 index 00000000..c383e8b5 --- /dev/null +++ b/src/engine/e_console.h @@ -0,0 +1,64 @@ +#ifndef _CONSOLE_H +#define _CONSOLE_H + +#ifdef __cplusplus +extern "C"{ +#endif + +#define CONSOLE_MAX_STR_LENGTH 255 +/* the maximum number of tokens occurs in a string of length CONSOLE_MAX_STR_LENGTH with tokens size 1 separated by single spaces */ +#define MAX_TOKENS (CONSOLE_MAX_STR_LENGTH+1)/2 + +enum +{ + TOKEN_INT, + TOKEN_FLOAT, + TOKEN_STRING +}; + +struct token +{ + int type; + const char *stored_string; +}; + +struct lexer_result +{ + char string_storage[CONSOLE_MAX_STR_LENGTH+1]; + char *next_string; + + struct token tokens[MAX_TOKENS]; + unsigned int num_tokens; +}; + +int lex(const char *line, struct lexer_result *result); + +int extract_result_string(struct lexer_result *result, int index, const char **str); +int extract_result_int(struct lexer_result *result, int index, int *i); +int extract_result_float(struct lexer_result *result, int index, float *f); + +typedef void (*console_callback)(struct lexer_result *result, void *user_data); + +typedef struct COMMAND +{ + const char *name; + const char *params; + console_callback callback; + void *user_data; + struct COMMAND *next; + +} COMMAND; + +void console_init(); +void console_register(COMMAND *cmd); +void console_execute(const char *str); +void console_print(const char *str); +void console_register_print_callback(void (*callback)(const char *)); + +#define MACRO_REGISTER_COMMAND(name, params, func, ptr) { static COMMAND cmd = { name, params, func, ptr, 0x0 }; console_register(&cmd); } + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/engine/e_engine.c b/src/engine/e_engine.c index dc6484d6..06b82f7f 100644 --- a/src/engine/e_engine.c +++ b/src/engine/e_engine.c @@ -5,6 +5,7 @@ #include <engine/e_system.h> #include <engine/e_interface.h> #include <engine/e_config.h> +#include <engine/e_console.h> static char application_save_path[512] = {0}; @@ -39,6 +40,9 @@ void engine_init(const char *appname, int argc, char **argv) fs_makedir(path); } } + + /* init console */ + console_init(); /* reset the config */ config_reset(); diff --git a/src/engine/e_system.c b/src/engine/e_system.c index bf445c9c..e9c96fa3 100644 --- a/src/engine/e_system.c +++ b/src/engine/e_system.c @@ -8,6 +8,7 @@ #include "e_detect.h" #include "e_system.h" +#include "e_console.h" #if defined(CONF_FAMILY_UNIX) #include <sys/time.h> @@ -88,6 +89,18 @@ void dbg_msg(const char *sys, const char *fmt, ...) va_end(args); printf("\n"); fflush(stdout); + + { + char str[2048]; + + sprintf(str, "[%s]: ", sys); + + va_start(args, fmt); + vsprintf(str+strlen(str), fmt, args); + va_end(args); + + console_print(str); + } } int memory_alloced = 0; |