diff --git a/src/Makefile b/src/Makefile index f3065141..856a9a9d 100644 --- a/src/Makefile +++ b/src/Makefile @@ -91,6 +91,7 @@ CFLAGS += -I include -I arch/$(ARCH)/include -I . -DARCH=$(ARCH) CFLAGS += -Os -ffreestanding CFLAGS += -Wall -W CFLAGS += -g +CFLAGS += -DCONSOLE_DUAL -DCOMCONSOLE=0x3F8 -DCONSPEED=9600 CFLAGS += $(EXTRA_CFLAGS) ASFLAGS += $(EXTRA_ASFLAGS) LDFLAGS += $(EXTRA_LDFLAGS) @@ -145,6 +146,8 @@ SRCDIRS += interface/pxe SRCDIRS += tests SRCDIRS += crypto SRCDIRS += hci/mucurses +SRCDIRS += commandline +SRCDIRS += commandline/commands # NON_AUTO_SRCS lists files that are excluded from the normal # automatic build system. diff --git a/src/commandline/cmdline.c b/src/commandline/cmdline.c new file mode 100644 index 00000000..28632196 --- /dev/null +++ b/src/commandline/cmdline.c @@ -0,0 +1,81 @@ +#include +#include "etherboot.h" +#include "cmdline.h" +#include "cmdlinelib.h" +#include "cmdlist.h" + + +#define CMDL_DELAY (2000 * TICKS_PER_SEC) / 1000; + +void cmdl_exec_cmdline(); +char cmdl_spin(); + +void cmdl_start() +{ + unsigned int stop; + //int spin; + + //printf("gPXE %s (GPL) etherboot.org ... ", VERSION); + printf("gPXE %s (GPL) etherboot.org\n", VERSION); + + stop = currticks() + CMDL_DELAY; + + while(currticks() < stop){ + + /*if(spin++ % 250 == 0){ + putchar(8); + putchar(cmdl_spin()); + }*/ + + if(iskey()){ + if(getchar() == 2){ + putchar('\n'); + cmdl_exec_cmdline(); + break; + }else{ + putchar('\n'); + printf("Skipping command line.\n"); + break; + } + } + } + putchar('\n'); + + // empty the input buffer + while(iskey()) { + getchar(); + } +} + +/*char cmdl_spin() +{ + static int state;*/ + //int spinner[4] = {'-', '\\', '|', '/'}; <- undefined reference to memcpy! +/* int spinner[4]; + + spinner[0] = '-'; + spinner[1] = '\\'; + spinner[2] = '|'; + spinner[3] = '/'; + + return spinner[state++ % 4]; +}*/ + +void cmdl_exec_cmdline(){ + cmd_line* cmd; + cmd = cmdl_create(); + + cmdl_setputchar(cmd, putchar); + cmdl_setgetchar(cmd, getchar); + cmdl_setprintf(cmd, printf); + + cmdl_setpropmt(cmd, "gPXE>"); + + printf("Welcome to Etherboot\n\n"); + + + cmdl_enterloop(cmd); + + cmdl_free(cmd); +} + diff --git a/src/commandline/cmdlinelib.c b/src/commandline/cmdlinelib.c new file mode 100644 index 00000000..e38d729e --- /dev/null +++ b/src/commandline/cmdlinelib.c @@ -0,0 +1,564 @@ +#include "cmdlinelib.h" +#include "command.h" +#include +#include +#include +#include +#include + +static struct command cmd_start[0] __table_start ( commands ); +static struct command cmd_end[0] __table_end ( commands ); + +void cmdl_setgetchar(cmd_line* cmd, cmdl_getchar_t in) +{ + cmd->getchar = in; +} + +void cmdl_setputchar(cmd_line* cmd, cmdl_putchar_t in) +{ + cmd->putchar = in; +} + +void cmdl_setprintf(cmd_line* cmd, cmdl_printf_t in) +{ + cmd->printf = in; +} + +int cmdl_getexit(cmd_line* cmd) +{ + if(cmdl_check(cmd) && !cmd->exit){ + return 0; + }else{ + return 1; + } + +} + +void cmdl_setexit(cmd_line* cmd, int exit) +{ + if(cmdl_check(cmd)){ + cmd->exit = exit; + } +} + +int cmdl_printf(cmd_line* cmd, const char *format, ...) +{ + int ret; + char string[CMDL_BUFFER_SIZE]; + va_list ap; + + va_start(ap, format); + ret = vsprintf(string, format, ap); + cmdl_addstr(cmd, string); + va_end(ap); + return ret; +} + +void cmdl_addstr(cmd_line* cmd, char* str) +{ + unsigned int i; + for(i = 0; i < strlen(str); i++){ + cmdl_addchar(cmd, str[i]); + } +} + +/*void cmdl_addoutput_str(cmd_line* cmd, char output[CMDL_OUTPUT_SIZE]) +{ + if(cmdl_check(cmd) && output != NULL){ + if(!cmd->has_output){ + cmdl_clearoutput(cmd); + } + strncat(cmd->output, output, CMDL_OUTPUT_SIZE); + cmd->has_output = 1; + } +}*/ + +/*char* cmdl_getoutput(cmd_line* cmd) +{ + if(cmdl_check(cmd) && cmd->has_output){ + cmd->has_output = 0; + return cmd->output; + }else{ + return ""; + } +}*/ + +void cmdl_setpropmt(cmd_line* cmd, char prompt[CMDL_PROMPT_SIZE]) +{ + if(cmdl_check(cmd) && prompt != NULL){ + strncat(cmd->prompt, prompt, CMDL_PROMPT_SIZE); + } +} + +char *cmdl_getprompt(cmd_line* cmd) +{ + if(cmdl_check(cmd)){ + return cmd->prompt; + }else{ + return ""; + } +} + +char* cmdl_getbuffer(cmd_line* cmd){ + if(cmdl_check(cmd)){ + return cmd->buffer; + }else{ + return ""; + } +} + +void cmdl_enterloop(cmd_line* cmd) +{ + while(!cmdl_getexit(cmd)){ + if(cmd->refresh){ + cmd->printf("%s %s", cmd->prompt, cmd->buffer); + cmd->refresh = 0; + } +// cmd->printf("Got %d\n", cmd->getchar()); + cmdl_parsechar(cmd, cmd->getchar()); + } +} + +void cmdl_addreplace(cmd_line* cmd, char in) +{ + if(cmd->cursor < CMDL_BUFFER_SIZE - 2){ + cmd->buffer[cmd->cursor] = in; + cmd->cursor++; + cmd->putchar((int)in); + } +} + +void cmdl_addinsert(cmd_line* cmd, char in) +{ + int i; + int to; + if(cmd->cursor < CMDL_BUFFER_SIZE - 2 && cmd->cursor >= 0){ + if(strlen(cmd->buffer) < CMDL_BUFFER_SIZE - 2){ + to = strlen(cmd->buffer); + }else{ + to = CMDL_BUFFER_SIZE - 2; + } + for(i=to; i > cmd->cursor; i--){ + cmd->buffer[i] = cmd->buffer[i-1]; + } + cmd->buffer[cmd->cursor] = in; + + for(i=cmd->cursor; i < to; i++){ + cmd->putchar(cmd->buffer[i]); + } + + for(i=cmd->cursor; i < to - 1; i++){ + cmd->putchar(CMDLK_BS); + } + cmd->cursor++; + //cmdl_movecursor(cmd, CMDL_RIGHT); + } +} + +void cmdl_addchar(cmd_line* cmd, char in){ + if(cmd->insert){ + cmdl_addinsert(cmd, in); + }else{ + cmdl_addreplace(cmd, in); + } +} + +void cmdl_parsechar(cmd_line* cmd, char in) +{ + if(cmdl_check(cmd)){ + if(in >= 32){ + cmdl_addchar(cmd, in); + }else{ + switch(in){ + case CMDLK_BS: + if(cmdl_movecursor(cmd, CMDL_LEFT)){ + cmdl_del(cmd); + } + break; + + case CMDLK_RETURN: + cmd->putchar('\n'); + cmdl_exec(cmd); + cmd->refresh = 1; + break; + + case CMDLK_BW: + cmdl_movecursor(cmd, CMDL_LEFT); + break; + + case CMDLK_FW: + //cmdl_movecursor(cmd, CMDL_RIGHT); + break; + + case CMDLK_TAB: + cmdl_tabcomplete(cmd); + break; + + } + } + } +} + +void cmdl_tabcomplete(cmd_line *cmd) +{ + struct command *ccmd; + int count=0; + char* result[CMDL_MAX_TAB_COMPLETE_RESULT]; + + for ( ccmd = cmd_start ; ccmd < cmd_end ; ccmd++ ) { + if(!strncmp(ccmd->name, cmd->buffer, strlen(cmd->buffer))){ + if(count <= CMDL_MAX_TAB_COMPLETE_RESULT){ + result[count++] = (char*)(ccmd->name); + } + } + } + + + if( count == 1 ){ + cmdl_addstr(cmd, (char*)(result[0] + strlen(cmd->buffer))); + cmd->tabstate = 0; + cmdl_addchar(cmd, ' '); + } else if( count > 1 ) { + int i, i2, minlen=CMDL_BUFFER_SIZE, same=1; + char last; + + for(i = 0; i < count; i ++) { + if(minlen > (int)strlen( result[i] ) ){ + minlen = strlen(result[i]); + } + + } + if((int)strlen(cmd->buffer) < minlen){ + for(i = strlen(cmd->buffer); i < minlen; i++){ + last = result[0][i]; + for(i2 = 1; i2 < count; i2 ++) { + if(result[i2][i] != last){ + same = 0; + break; + } + } + if(same){ + cmdl_addchar(cmd, last); + } + + } + } + cmd->tabstate++; + } + + if(count > 1 && cmd->tabstate > 1){ + int i; + cmd->tabstate = 0; + cmd->refresh = 1; + cmd->putchar('\n'); + for(i = 0; i < count; i ++){ + cmd->printf("%s\t", result[i]); + } + cmd->putchar('\n'); + } + + + +} + + +void cmdl_exec(cmd_line* cmd) +{ + cmdl_param_list* params; + int unknown=1; + struct command *ccmd; + + params = cmdl_getparams(cmd->buffer); + + if(params == NULL){ + cmdl_clearbuffer(cmd); + return; + } + + if(params->argc > 0){ + if(!strcmp(params->argv[0], "exit") || !strcmp(params->argv[0], "quit")){ + cmdl_setexit(cmd, 1); +/* }else if(!strcmp(params->argv[0], "help")){ + if(params->argc > 1){ + cmdl_builtin_help(cmd, params->argv[1]); + }else{ + cmdl_builtin_help(cmd, ""); + }*/ + }else{ + for ( ccmd = cmd_start ; ccmd < cmd_end ; ccmd++ ) { + if(!strcmp(ccmd->name, params->argv[0])){ + unknown = 0; + ccmd->exec(params->argc, params->argv); + break; + } + } + if(unknown){ + cmd->printf("%s: unknown command\n", params->argv[0]); + } + } + } + + free(params); + cmdl_clearbuffer(cmd); +} + +/*void cmdl_builtin_help(cmd_line* cmd, char* command){ + struct command *ccmd; + int unknown = 1; + if(strcmp(command, "") == 0){ + cmd->printf("Built in commands:\n\n\thelp\t\tCommand usage help (\"help help\" for more info)\n\texit, quit\t\tExit the command line and boot\n\nCompiled in commands:\n\n"); + + for ( ccmd = cmd_start ; ccmd < cmd_end ; ccmd++ ) { + cmd->printf ("\t%s\t\t%s\n", ccmd->name, ccmd->desc ); + } + }else{ + if(!strcmp(command, "help")){ + cmd->printf("help - The help command\n\nUsage: help \n\n\tExample:\n\t\thelp help\n"); + }else if(!strcmp(command, "exit") || !strcmp(command, "quit")){ + cmd->printf("exit, quit - The quit command\n\nUsage:\nquit or exit\n\n\tExample:\n\t\texit\n"); + }else{ + for ( ccmd = cmd_start ; ccmd < cmd_end ; ccmd++ ) { + if(!strcmp(ccmd->name, command)){ + unknown = 0; + cmd->printf ("\t%s - %s\n\nUsage:\n%s\n", ccmd->name, ccmd->desc, ccmd->usage ); + break; + } + if(unknown){ + cmd->printf("\"%s\" isn't compiled in (does it exist?).\n", command); + } + } + } + + } +}*/ + +cmdl_param_list* cmdl_getparams(const char* command){ + cmdl_param_list* this; + char *result = NULL; + int count=0; + char *command2; + + this = (cmdl_param_list*)malloc(sizeof(cmdl_param_list)); + + if(this == NULL){ + return NULL; + } + + command2 = malloc(strlen(command) + 1); + + this->argc=0; + + strcpy(command2, command); + result = strtok(command2, " "); + + while( result != NULL ) { + this->argc++; + result = strtok( NULL, " "); + } + + this->argv = (char**)malloc(sizeof(char*) * this->argc); + if(this->argv == NULL){ + free(this); + return NULL; + } + + + strcpy(command2, command); + result = strtok(command2, " "); + + while( result != NULL && this->argc > count) { + this->argv[count] = (char*)malloc(sizeof(char) * (strlen(result) + 1)); + if(this->argv[count] == NULL){ + free(this); + return NULL; + } + strcpy(this->argv[count], result); + count++; + result = strtok( NULL, " "); + } + free(command2); + return this; +} + +/*char* cmdl_parse_getcmd(cmd_line* cmd){ + int i; + char* ret; + ret = (char*)malloc(1); + ret[0] = 0; + + for(i=0; i < CMDL_BUFFER_SIZE - 1; i++){ + if(cmd->buffer[i + 1] == ' ' || cmd->buffer[i + 1] == '\0'){ + free(ret); + ret = (char*)malloc(i+1); + strncat(ret, cmd->buffer, i+1); + break; + } + } + return ret; +}*/ + +void cmdl_clearbuffer(cmd_line* cmd) +{ + if(cmdl_check(cmd)){ + int i; + cmd->cursor = 0; + for(i=0; i < CMDL_BUFFER_SIZE; i++){ + cmd->buffer[i] = 0; + } + } +} + +/*void cmdl_clearoutput(cmd_line* cmd) +{ + if(cmdl_check(cmd)){ + int i; + for(i=0; i < CMDL_OUTPUT_SIZE; i++){ + cmd->output[i] = 0; + } + } +}*/ + +int cmdl_movecursor(cmd_line* cmd, int direction) +{ + if(cmdl_check(cmd)){ + switch(direction){ + case CMDL_LEFT: + if(cmd->cursor > 0){ + cmd->cursor--; + cmd->putchar(CMDLK_BS); + }else{ + return 0; + } + break; + case CMDL_RIGHT: + if(cmd->cursor < CMDL_BUFFER_SIZE - 2){ + cmd->cursor++; + cmd->putchar(' '); + }else{ + return 0; + } + break; + } + } + return 1; +} + +void cmdl_del(cmd_line* cmd) +{ + if(cmdl_check(cmd) && cmd->cursor < CMDL_BUFFER_SIZE - 2 && cmd->cursor >= 0){ + int i; + for(i = cmd->cursor; i < (int)strlen(cmd->buffer); i++){ + cmd->buffer[i] = cmd->buffer[i + 1]; + if(!cmd->buffer[i]){ + cmd->putchar(' '); + }else{ + cmd->putchar(cmd->buffer[i]); + } + } + for(i = cmd->cursor; i < (int)strlen(cmd->buffer) + 1; i++){ + cmd->putchar(CMDLK_BS); + } + } +} + + +int cmdl_check(cmd_line* cmd) +{ + if( + cmd != NULL && + cmd->buffer != NULL && + cmd->prompt != NULL && + cmd->cursor >= 0 && + cmd->cursor < CMDL_BUFFER_SIZE - 1 && + cmd->buffer[CMDL_BUFFER_SIZE - 1] == 0 && + cmd->prompt[CMDL_PROMPT_SIZE - 1] == 0 + ){ + return 1; + }else{ + return 0; + } +} + +cmd_line* cmdl_create() +{ + cmd_line* this; + int i; + + /* Initiate the command line */ + + this = (cmd_line*)malloc(sizeof(cmd_line)); + + if(this == NULL){ + return NULL; + } + + + /* Allocate output buffer */ + + /*this->output = (char*)malloc(CMDL_OUTPUT_SIZE); + if(this->output == NULL){ + free(this); + return NULL; + }*/ + +/* for(i = 0; i < CMDL_OUTPUT_SIZE; i++){ + this->output[i] = 0; + }*/ + + /* Allocate command line buffer */ + + this->buffer = (char*)malloc(CMDL_BUFFER_SIZE); + if(this->buffer == NULL){ + free(this); + return NULL; + } + + for(i = 0; i < CMDL_BUFFER_SIZE; i++){ + this->buffer[i] = 0; + } + + /* Allocate prompt buffer */ + + this->prompt = (char*)malloc(CMDL_PROMPT_SIZE); + if(this->prompt == NULL){ + free(this); + return NULL; + } + + for(i = 0; i < CMDL_PROMPT_SIZE; i++){ + this->prompt[i] = 0; + } + + /* Initiate cursor position etc.*/ + + this->cursor = 0; + //this->has_output = 0; + this->exit = 0; + this->refresh = 1; + this->tabstate = 0; + this->insert = 0; + + /* set callbacks to NULL */ + + this->getchar = NULL; + this->putchar = NULL; + this->printf = NULL; + + /* List the commands */ + + struct command *cmd; + + printf ( "Compiled in commands: "); + for ( cmd = cmd_start ; cmd < cmd_end ; cmd++ ) { + printf("%s ", cmd->name); + } + printf("\n"); + + return this; +} + +void cmdl_free(cmd_line* cmd) +{ + free(cmd); +} + diff --git a/src/commandline/commands/help.c b/src/commandline/commands/help.c new file mode 100644 index 00000000..30ab9623 --- /dev/null +++ b/src/commandline/commands/help.c @@ -0,0 +1,48 @@ +#include "command.h" +#include "console.h" +#include +#include + +static struct command cmd_start[0] __table_start ( commands ); +static struct command cmd_end[0] __table_end ( commands ); + +void help_req(){} + +static int cmd_help_exec ( int argc, char **argv ) { + + struct command *ccmd; + int unknown = 1; + if(argc == 1){ + printf("Built in commands:\n\n\texit, quit\t\tExit the command line and boot\n\nCompiled in commands:\n\n"); + + for ( ccmd = cmd_start ; ccmd < cmd_end ; ccmd++ ) { + printf ("\t%s\t\t%s\n", ccmd->name, ccmd->desc ); + } + }else{ + if(!strcmp(argv[1], "exit") || !strcmp(argv[1], "quit")){ + printf("exit, quit - The quit command\n\nUsage:\nquit or exit\n\n\tExample:\n\t\texit\n"); + }else{ + for ( ccmd = cmd_start ; ccmd < cmd_end ; ccmd++ ) { + if(!strcmp(ccmd->name, argv[1])){ + unknown = 0; + printf ("\t%s - %s\n\nUsage:\n%s\n", ccmd->name, ccmd->desc, ccmd->usage ); + break; + } + } + if(unknown){ + printf("\"%s\" isn't compiled in (does it exist?).\n", argv[1]); + } + } + + } + return 0; +} + +struct command help_command __command = { + .name = "help", + .usage = "help \n\n\tExample:\n\t\thelp help\n", + .desc = "The help command", + .exec = cmd_help_exec, +}; + + diff --git a/src/commandline/commands/test.c b/src/commandline/commands/test.c new file mode 100644 index 00000000..1d370124 --- /dev/null +++ b/src/commandline/commands/test.c @@ -0,0 +1,22 @@ +#include "command.h" +#include "console.h" + +void test_req(){} + +static int cmd_test_exec ( int argc, char **argv ) { + int i; + + printf("Hello, world!\nI got the following arguments passed to me: \n"); + for(i = 0; i < argc; i++){ + printf("%d: \"%s\"\n", i, argv[i]); + } + return 0; +} + +struct command test_command __command = { + .name = "test", + .usage = "A test command\nIt does nothing at all\n\nExample:\n\ttest", + .desc = "Does nothing", + .exec = cmd_test_exec, +}; + diff --git a/src/commandline/commands/test2.c b/src/commandline/commands/test2.c new file mode 100644 index 00000000..077933d0 --- /dev/null +++ b/src/commandline/commands/test2.c @@ -0,0 +1,22 @@ +#include "command.h" +#include "console.h" + +void test2_req(){} + +static int cmd_test2_exec ( int argc, char **argv ) { + int i; + + printf("Hello, world!\nI got the following arguments passed to me: \n"); + for(i = 0; i < argc; i++){ + printf("%d: \"%s\"\n", i, argv[i]); + } + return 0; +} + +struct command test2_command __command = { + .name = "test2", + .usage = "A test command\nIt does nothing at all\n\nExample:\n\ttest2", + .desc = "Does nothing", + .exec = cmd_test2_exec, +}; + diff --git a/src/core/cmdline.c b/src/core/cmdline.c new file mode 100644 index 00000000..6fb27947 --- /dev/null +++ b/src/core/cmdline.c @@ -0,0 +1,31 @@ +#include "cmdline.h" +#include "cmdlinelib.h" +#include + +void cmdl_start() +{ + cmd_line* cmd; + + cmd = cmdl_create(); + + cmdl_setpropmt(cmd, "?>"); + + cmdl_printf(cmd, "Welcome to Etherboot\n\n"); + + while(!cmdl_getexit(cmd)){ + int i; + + printf("%s%s %s", cmdl_getoutput(cmd), cmdl_getprompt(cmd), cmdl_getbuffer(cmd)); + + cmdl_addchar(cmd, getchar()); + + /* TODO HACK temporary clear line */ + putchar(0xd); + for(i=0; i < 79; i++){ + putchar(0x20); + } + putchar(0xd); + } + cmdl_free(cmd); +} + diff --git a/src/core/cmdlinelib.c b/src/core/cmdlinelib.c new file mode 100644 index 00000000..ead5b043 --- /dev/null +++ b/src/core/cmdlinelib.c @@ -0,0 +1,272 @@ +#include "cmdlinelib.h" +#include +#include +#include +#include + +int cmdl_getexit(cmd_line* cmd) +{ + if(cmdl_check(cmd) && !cmd->exit){ + return 0; + }else{ + return 1; + } + +} + +void cmdl_setexit(cmd_line* cmd, int exit) +{ + if(cmdl_check(cmd)){ + cmd->exit = exit; + } +} + +int cmdl_printf(cmd_line* cmd, const char *format, ...) +{ + int ret; + char string[CMDL_OUTPUT_SIZE]; + va_list ap; + + va_start(ap, format); + ret = vsprintf(string, format, ap); + cmdl_addoutput_str(cmd, string); + va_end(ap); + return ret; +} + + +void cmdl_addoutput_str(cmd_line* cmd, char output[CMDL_OUTPUT_SIZE]) +{ + if(cmdl_check(cmd) && output != NULL){ + if(!cmd->has_output){ + cmdl_clearoutput(cmd); + } + strncat(cmd->output, output, CMDL_OUTPUT_SIZE); + cmd->has_output = 1; + } +} + +char* cmdl_getoutput(cmd_line* cmd) +{ + if(cmdl_check(cmd) && cmd->has_output){ + cmd->has_output = 0; + return cmd->output; + }else{ + return ""; + } +} + +void cmdl_setpropmt(cmd_line* cmd, char prompt[CMDL_PROMPT_SIZE]) +{ + if(cmdl_check(cmd) && prompt != NULL){ + strncat(cmd->prompt, prompt, CMDL_PROMPT_SIZE); + } +} + +char *cmdl_getprompt(cmd_line* cmd) +{ + if(cmdl_check(cmd)){ + return cmd->prompt; + }else{ + return ""; + } +} + +char* cmdl_getbuffer(cmd_line* cmd){ + if(cmdl_check(cmd)){ + return cmd->buffer; + }else{ + return ""; + } +} + +void cmdl_addchar(cmd_line* cmd, char in) +{ + if(in >= 32){ + if(cmdl_check(cmd)){ + cmd->buffer[cmd->cursor] = in; + cmdl_movecursor(cmd, CMDL_RIGHT); + } + }else{ + switch(in){ + case 0x08: /* Backspace */ + + cmdl_delat(cmd, cmd->cursor); + cmdl_movecursor(cmd, CMDL_LEFT); + break; + case 0x0a: + case 0x0d: /* Enter */ + cmdl_exec(cmd); + break; + } + } +} + +void cmdl_exec(cmd_line* cmd) +{ + char* command; + cmdl_printf(cmd, "%s %s\n", cmd->prompt, cmd->buffer); + + command = cmdl_parse_getcmd(cmd); + if(strlen(command) != 0){ + if(strcmp(command, "exit") == 0 || strcmp(command, "quit") == 0){ + cmdl_setexit(cmd, 1); + }else if(strcmp(command, "help") == 0){ + cmdl_printf(cmd, "Don't panic\n"); + }else{ + cmdl_printf(cmd, "%s: unknown command\n", command); + } + } + free(command); + + cmdl_clearbuffer(cmd); +} + +char* cmdl_parse_getcmd(cmd_line* cmd){ + int i; + char* ret; + ret = (char*)malloc(1); + ret[0] = 0; + + for(i=0; i < CMDL_BUFFER_SIZE - 1; i++){ + if(cmd->buffer[i + 1] == ' ' || cmd->buffer[i + 1] == '\0'){ + free(ret); + ret = (char*)malloc(i+1); + strncat(ret, cmd->buffer, i+1); + break; + } + } + return ret; +} + +void cmdl_clearbuffer(cmd_line* cmd) +{ + if(cmdl_check(cmd)){ + int i; + cmd->cursor = 0; + for(i=0; i < CMDL_BUFFER_SIZE; i++){ + cmd->buffer[i] = 0; + } + } +} + +void cmdl_clearoutput(cmd_line* cmd) +{ + if(cmdl_check(cmd)){ + int i; + for(i=0; i < CMDL_OUTPUT_SIZE; i++){ + cmd->output[i] = 0; + } + } +} + +void cmdl_movecursor(cmd_line* cmd, int direction) +{ + if(cmdl_check(cmd)){ + switch(direction){ + case CMDL_LEFT: + if(cmd->cursor > 0){ + cmd->cursor--; + } + break; + case CMDL_RIGHT: + if(cmd->cursor < CMDL_BUFFER_SIZE - 1){ + cmd->cursor++; + } + break; + } + } +} + +void cmdl_delat(cmd_line* cmd, int at) +{ + if(cmdl_check(cmd) && at < CMDL_BUFFER_SIZE - 1 && at >= 0){ + int i; + for(i = at; i < CMDL_BUFFER_SIZE - 1; i++){ + cmd->buffer[i] = cmd->buffer[i + 1]; + } + } +} + + +int cmdl_check(cmd_line* cmd) +{ + if( + cmd != NULL && + cmd->buffer != NULL && + cmd->prompt != NULL && + cmd->cursor >= 0 && + cmd->cursor < CMDL_BUFFER_SIZE - 1 && + cmd->buffer[CMDL_BUFFER_SIZE - 1] == 0 && + cmd->prompt[CMDL_PROMPT_SIZE - 1] == 0 + ){ + return 1; + }else{ + return 0; + } +} + +cmd_line* cmdl_create() +{ + cmd_line* this; + int i; + + // Initiate the command line + + this = (cmd_line*)malloc(sizeof(cmd_line)); + + if(this == NULL){ + return NULL; + } + + + /* Allocate output buffer */ + + this->output = (char*)malloc(CMDL_OUTPUT_SIZE); + if(this->output == NULL){ + free(this); + return NULL; + } + + for(i = 0; i < CMDL_OUTPUT_SIZE; i++){ + this->output[i] = 0; + } + + /* Allocate command line buffer */ + + this->buffer = (char*)malloc(CMDL_BUFFER_SIZE); + if(this->buffer == NULL){ + free(this); + return NULL; + } + + for(i = 0; i < CMDL_BUFFER_SIZE; i++){ + this->buffer[i] = 0; + } + + /* Allocate prompt buffer */ + + this->prompt = (char*)malloc(CMDL_PROMPT_SIZE); + if(this->prompt == NULL){ + free(this); + return NULL; + } + + for(i = 0; i < CMDL_PROMPT_SIZE; i++){ + this->prompt[i] = 0; + } + + /* Initiate cursor position */ + + this->cursor = 0; + this->has_output = 0; + this->exit = 0; + + return this; +} + +void cmdl_free(cmd_line* cmd) +{ + free(cmd); +} + diff --git a/src/core/main.c b/src/core/main.c index 0cc30f57..5d3b9e68 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -22,6 +22,7 @@ Literature dealing with the network protocols: #include "disk.h" #include "timer.h" #include "cpu.h" +#include "cmdline.h" #include "console.h" #include #include "image.h" @@ -155,6 +156,8 @@ int main ( void ) { netdev = next_netdev (); if ( netdev ) { test_dhcp ( netdev ); + //cmdl_start(); + //test_aoeboot ( &static_single_netdev ); } else { printf ( "No network device found\n" ); } diff --git a/src/include/cmdline.h b/src/include/cmdline.h new file mode 100644 index 00000000..9ab29c53 --- /dev/null +++ b/src/include/cmdline.h @@ -0,0 +1,8 @@ +#ifndef CMDLINE_H +#define CMDLINE_H + +/* Command line external functions */ + +void cmdl_start(); + +#endif diff --git a/src/include/cmdlinelib.h b/src/include/cmdlinelib.h new file mode 100644 index 00000000..1eb68994 --- /dev/null +++ b/src/include/cmdlinelib.h @@ -0,0 +1,99 @@ +/* Command line library */ +#ifndef CMDLINELIB_H +#define CMDLINELIB_H + +#define CMDL_BUFFER_SIZE 256 +//#define CMDL_OUTPUT_SIZE 256 +#define CMDL_PROMPT_SIZE 8 +#define CMDL_MAX_TAB_COMPLETE_RESULT 256 + +typedef int (*cmdl_putchar_t)(int); +typedef int (*cmdl_printf_t)( const char *format, ... ); +typedef int (*cmdl_getchar_t)(); + +#ifndef NULL +#define NULL ((void *)0) +#endif + +enum{ + CMDL_LEFT, + CMDL_RIGHT +}; + +enum{ + CMDLK_FW=6, + CMDLK_BW=2, + CMDLK_BS=8, + CMDLK_HOME=2, + CMDLK_END=5, + CMDLK_DELTOEND=11, + CMDLK_DELARG=23, + CMDLK_ENTER=0x0d, + CMDLK_RETURN=0x0a, + CMDLK_TAB=9 +}; + +typedef struct{ + + // buffers + + //char* output; + char* buffer; + char* prompt; + + // options and values + + int cursor; + //int has_output; + int exit; + int refresh; + int tabstate; + int insert; + + // callbacks + + cmdl_putchar_t putchar; + cmdl_getchar_t getchar; + cmdl_printf_t printf; + +}cmd_line; + +typedef struct{ + int argc; + char **argv; +}cmdl_param_list; + +void cmdl_setputchar(cmd_line* cmd, cmdl_putchar_t in); +void cmdl_setgetchar(cmd_line* cmd, cmdl_getchar_t in); +void cmdl_setprintf(cmd_line* cmd, cmdl_printf_t in); + +//void cmdl_builtin_help(cmd_line* cmd, char* command); + +void cmdl_parsechar(cmd_line* cmd, char in); + +void cmdl_addreplace(cmd_line* cmd, char in); +void cmdl_addinsert(cmd_line* cmd, char in); +void cmdl_enterloop(cmd_line* cmd); +void cmdl_exec(cmd_line* cmd); +void cmdl_setexit(cmd_line* cmd, int exit); +int cmdl_getexit(cmd_line* cmd); +void cmdl_clearoutput(cmd_line* cmd); +void cmdl_clearbuffer(cmd_line* cmd); +int cmdl_printf(cmd_line* cmd, const char *format, ...); +char* cmdl_getoutput(cmd_line* cmd); +//void cmdl_addoutput_str(cmd_line* cmd, char output[CMDL_OUTPUT_SIZE]); +void cmdl_addstr(cmd_line* cmd, char* str); +int cmdl_movecursor(cmd_line* cmd, int direction); +char* cmdl_getbuffer(cmd_line* cmd); +void cmdl_addchar(cmd_line* cmd, char in); +int cmdl_check(cmd_line* cmd); +void cmdl_del(cmd_line* cmd); +cmd_line* cmdl_create(); +void cmdl_free(cmd_line* cmd); +char *cmdl_getprompt(cmd_line* cmd); +void cmdl_setpropmt(cmd_line* cmd, char prompt[CMDL_PROMPT_SIZE]); +cmdl_param_list* cmdl_getparams(const char* command); +void cmdl_tabcomplete(cmd_line *cmd); + +#endif + diff --git a/src/include/cmdlist.h b/src/include/cmdlist.h new file mode 100644 index 00000000..623cac76 --- /dev/null +++ b/src/include/cmdlist.h @@ -0,0 +1,16 @@ +#ifndef COMMANDLIST_H +#define COMMANDLIST_H + +void test_req(); +void test2_req(); +void help_req(); + +void commandlist() +{ + test_req(); + test2_req(); + help_req(); +} + +#endif + diff --git a/src/include/command.h b/src/include/command.h new file mode 100644 index 00000000..113ca2f0 --- /dev/null +++ b/src/include/command.h @@ -0,0 +1,15 @@ +#ifndef COMMAND_H +#define COMMAND_H + +#include + +struct command { + const char *name; // The name of the command + const char *usage; // Description of how to use the command + const char *desc; // Short description of the command + int ( *exec ) ( int argc, char **argv); // The command function to call +}; + +#define __command __table ( commands, 01 ) +#endif +