diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2010-04-14 15:08:12 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2010-04-14 16:05:50 +0200 |
commit | 647985a4f1ad2795158cd8d62e0eb79782518176 (patch) | |
tree | f345683beb20f8077d750c681f1292d24c7b652c | |
parent | 54c5725681d406360f5b580c7893c0d9f147ed7c (diff) | |
download | microcom-cli.tar.gz microcom-cli.tar.xz |
implement a cli for microcomcli
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
-rw-r--r-- | Makefile | 9 | ||||
-rw-r--r-- | commands.c | 161 | ||||
-rw-r--r-- | help.c | 345 | ||||
-rw-r--r-- | microcom.c | 61 | ||||
-rw-r--r-- | microcom.h | 28 | ||||
-rw-r--r-- | mux.c | 26 | ||||
-rw-r--r-- | parser.c | 199 |
7 files changed, 456 insertions, 373 deletions
@@ -20,19 +20,22 @@ #****************************************************************************/ CFLAGS += -Wall -O2 -g +LDFLAGS += -lreadline CPPFLAGS += -DPKG_VERSION="\"2009.06\"" -microcom: microcom.o mux.o help.o serial.o telnet.o +microcom: microcom.o mux.o serial.o telnet.o commands.o parser.o mux.o: mux.c microcom.h microcom.o: microcom.c microcom.h -help.o: help.c microcom.h - serial.o: serial.c microcom.h telnet.o: telnet.c microcom.h +commands.o: telnet.o microcom.h + +parser.o: parser.c microcom.h + clean: rm -f *.o microcom diff --git a/commands.c b/commands.c new file mode 100644 index 0000000..d7b6b3b --- /dev/null +++ b/commands.c @@ -0,0 +1,161 @@ +#include <stdlib.h> +#include "microcom.h" + +static int cmd_speed(int argc, char *argv[]) +{ + int speed; + speed_t flag; + + if (argc < 2) { + printf("current speed: %d\n", current_speed); + return 0; + } + + speed = strtoul(argv[1], NULL, 0); + flag = baudrate_to_flag(speed); + if (flag < 0) { + printf("invalid speed %d\n", speed); + return 1; + } + + current_speed = speed; + ios->set_speed(ios, flag); + + return 0; +} + +static int cmd_flow(int argc, char *argv[]) +{ + char *flow; + + if (argc < 2) { + switch (current_flow) { + default: + case FLOW_NONE: + flow = "none"; + break; + case FLOW_SOFT: + flow = "soft"; + break; + case FLOW_HARD: + flow = "hard"; + break; + } + printf("current flow: %s\n", flow); + return 0; + } + + switch (*argv[1]) { + case 'n': + current_flow = FLOW_NONE; + break; + case 's': + current_flow = FLOW_SOFT; + break; + case 'h': + current_flow = FLOW_HARD; + break; + default: + printf("unknown flow type \"%s\"\n", argv[1]); + return 1; + } + + ios->set_flow(ios, current_flow); + + return 0; +} + +static int cmd_exit(int argc, char *argv[]) +{ + return MICROCOM_CMD_START; +} + +static int cmd_break(int argc, char *argv[]) +{ + ios->send_break(ios); + return 0; +} + +static int cmd_quit(int argc, char *argv[]) +{ + microcom_exit(0); + return 0; +} + +static int cmd_help(int argc, char *argv[]) +{ + struct cmd *cmd; + + if (argc == 1) { + for_each_command(cmd) { + if (cmd->info) + printf("%s - %s\n", cmd->name, cmd->info); + else + printf("%s\n", cmd->name); + } + } else { + microcom_cmd_usage(argv[1]); + } + + return 0; +} + +static int cmd_execute(int argc, char *argv[]) +{ + if (argc < 2) + return MICROCOM_CMD_USAGE; + + return do_script(argv[1]); +} + +static int cmd_comment(int argc, char *argv[]) +{ + return 0; +} + +static struct cmd cmds[] = { + { + .name = "speed", + .fn = cmd_speed, + .info = "set terminal speed", + .help = "speed <newspeed>" + }, { + .name = "exit", + .fn = cmd_exit, + .info = "exit from command processing", + }, { + .name = "flow", + .fn = cmd_flow, + .info = "set flow control", + .help = "flow hard|soft|none", + }, { + .name = "break", + .fn = cmd_break, + .info = "send break", + }, { + .name = "quit", + .fn = cmd_quit, + .info = "quit microcom", + }, { + .name = "help", + .fn = cmd_help, + .info = "show help", + }, { + .name = "x", + .fn = cmd_execute, + .info = "execute a script", + .help = "x <scriptfile>", + }, { + .name = "#", + .fn = cmd_comment, + .info = "comment", + }, +}; + +void commands_init(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cmds); i++) + register_command(&cmds[i]); +} @@ -1,345 +0,0 @@ -/****************************************************************** -** File: help.c -** Description: implements the help screens -** -** Copyright (C)1999 Anca and Lucian Jurubita <ljurubita@hotmail.com>. -** All rights reserved. -**************************************************************************** -** 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 at www.gnu.org -**************************************************************************** -** Rev. 1.02 - June 2000 -****************************************************************************/ -#include "microcom.h" - -#include <sys/ioctl.h> -#include <arpa/telnet.h> - -extern int crnl_mapping; //0 - no mapping, 1 mapping -extern char device[MAX_DEVICE_NAME]; /* serial device name */ -extern int dolog; /* log active flag */ -extern FILE *flog; /* log file */ -extern int telnet; - -static int help_state = 0; -static int in_escape = 0; - -/****************************************************************** - Help handling functions -******************************************************************* - static void help_escape(void) - print the main help screen - static void help_terminal(void) - print terminal help screen - static void help_speed(void) - print the speed help screen - static void help_send_escape(int fd, char c) - - handle the main help sereen - - fd - file handle for comm port - - c - carachter to be processed; if it is not recognized - as a valid help character, it will be sent to the - com port (fd) - static void help_set_terminal(int fd, char c) - - handle terminal help screen - - same params as for help_send_escape() - static void help_set_speed(int fd, char c) - handle speed help screen - - same params as for help_send_escape() - void cook_buf(int fd, char *buf, int num) - - redirect escaped characters to the help handling functions; - the function is called from mux.c in the main character - processing ruoutine; - - fd - file handle for the comm port - - buf - pointer to the character buffer - - num - number of valid characters in the buffer -******************************************************************/ -static void help_done(void) -{ - char done_str[] = "Help done!\n"; - write(STDOUT_FILENO, done_str, strlen(done_str)); -} - -static void help_escape(void) -{ - char str1[] = - "\n" - "**********Help***********\n" - " x - exit microcom\n" - " q - quit microcom\n" - " b - send break\n"; - - char str2[] = - " t - set terminal\n" - " w - send window size\n" - " e - exit help\n" "*************************\n" "Command: "; - - write(STDOUT_FILENO, str1, strlen(str1)); - - if (dolog == 0) - write(STDOUT_FILENO, " l - log on \n", 26); - else - write(STDOUT_FILENO, " l - log off \n", 26); - - write(STDOUT_FILENO, str2, strlen(str2)); -} - -static void help_terminal(void) -{ - char str1[] = "\n" "******Set terminal ******\n" " p - set speed\n"; - - char str2[] = - " n - no flow control\n" - " h - hardware flow control\n" - " s - software flow control\n" - " q - quit help\n" "*************************\n" "Command: "; - - write(STDOUT_FILENO, str1, strlen(str1)); - if (crnl_mapping) - write(STDOUT_FILENO, " m - no CR/NL mapping \n", 26); - else - write(STDOUT_FILENO, " m - NL to CR/NL mapping\n", 26); - write(STDOUT_FILENO, str2, strlen(str2)); -} - -static void help_speed(void) -{ - char str[] = - "\n******Set speed *********\n" - " a - 1200\n" - " b - 2400\n" - " c - 4800\n" - " d - 9600\n" - " e - 19200\n" - " f - 38400\n" - " g - 57600\n" - " h - 115200\n" - " i - 230400\n" - " j - 460800\n" - " q - quit help\n" "*************************\n" "Command: "; - - write(STDOUT_FILENO, str, strlen(str)); -} - -/* process function for help_state=0 */ -static void help_send_escape(struct ios_ops *ios, char c) -{ - struct winsize win; - char buf[100]; - int sz; - - in_escape = 0; - help_state = 0; - - switch (c) { - case 'q': /* quit help */ - case 'x': - /* restore termios settings and exit */ - write(STDOUT_FILENO, "\n", 1); - microcom_exit(0); - break; - case 'l': /* log on/off */ - dolog = (dolog == 0) ? 1 : 0; - if (dolog) { /* open log file */ - if ((flog = fopen("microcom.log", "a")) == (FILE *) 0) { - write(STDOUT_FILENO, - "Cannot open microcom.log \n", 26); - dolog = 0; - } - } else { /* cloase log file */ - fflush(flog); - fclose(flog); - } - break; - case 'b': /* send break */ - if (ios->send_break) - /* send a break */ - ios->send_break(ios); - break; - case 't': /* set terminal */ - help_state = 1; - help_terminal(); - in_escape = 1; - break; - case '~': /* display it again */ - help_escape(); - break; - case 'w': - if(ioctl(0, TIOCGWINSZ, &win)) - break; - - sz = sprintf(buf, "stty rows %d cols %d\n", win.ws_row, win.ws_col); - write(ios->fd, &buf, sz); - break; - case 'e': - break; - default: - printf("unknown command '%c'\n",c); - break; - } - - if (in_escape == 0) - help_done(); - - return; -} - -/* process function for help_state=1 */ -static void help_set_terminal(struct ios_ops *ios, char c) -{ - struct termios pts; /* termios settings on port */ - tcgetattr(ios->fd, &pts); - switch (c) { - case 'm': /* CR/NL mapping */ - in_escape = 0; /* get it out from escape state */ - help_state = 0; - if (crnl_mapping) { - pts.c_oflag &= ~ONLCR; - crnl_mapping = 0; - } else { - pts.c_oflag |= ONLCR; - crnl_mapping = 1; - } - tcsetattr(ios->fd, TCSANOW, &pts); - break; - case 'p': /* port speed */ - in_escape = 1; - help_state = 2; - help_speed(); - break; - case 'h': /* hardware flow control */ - in_escape = 0; /* get it out from escape state */ - help_state = 0; - ios->set_flow(ios, FLOW_HARD); - /* hardware flow control */ - break; - case 's': /* software flow contrlol */ - in_escape = 0; /* get it out from escape state */ - help_state = 0; - ios->set_flow(ios, FLOW_SOFT); - /* software flow control */ - break; - case 'n': /* no flow control */ - in_escape = 0; /* get it out from escape state */ - help_state = 0; - /* no flow control */ - ios->set_flow(ios, FLOW_NONE); - break; - case '~': - case 'q': - in_escape = 0; - help_state = 0; - break; - default: - /* pass the character through */ - /* "C-\ C-\" sends "C-\" */ - write(ios->fd, &c, 1); - break; - } - - if (in_escape == 0) - help_done(); - - return; -} - -/* handle a single escape character */ -static void help_set_speed(struct ios_ops *ios, char c) -{ - speed_t speed[] = { - B1200, - B2400, - B4800, - B9600, - B19200, - B38400, - B57600, - B115200, - B230400, - B460800 - }; - - - if (c < 'a' && c > 'j') { - if (c == '~') { - help_speed(); - return; - } else if (c == 'q') { - in_escape = 0; - help_state = 0; - } - write(ios->fd, &c, 1); - return; - } - - ios->set_speed(ios, speed[c - 'a']); - - in_escape = 0; - help_state = 0; - help_done(); -} - -/* handle escape characters, writing to output */ -void cook_buf(struct ios_ops *ios, unsigned char *buf, int num) -{ - int current = 0; - - if (in_escape) { - /* cook_buf last called with an incomplete escape sequence */ - switch (help_state) { - case 0: - help_send_escape(ios, buf[0]); - break; - case 1: - help_set_terminal(ios, buf[0]); - break; - default: - help_set_speed(ios, buf[0]); - } - num--; /* advance to the next character in the buffer */ - buf++; - } - - while (current < num) { /* big while loop, to process all the charactes in buffer */ - - /* look for the next escape character '~' */ - while ((current < num) && (buf[current] != 28)) - current++; - /* and write the sequence befor esc char to the comm port */ - if (current) - write(ios->fd, buf, current); - - if (current < num) { /* process an escape sequence */ - /* found an escape character */ - if (help_state == 0) - help_escape(); - current++; - if (current >= num) { - /* interpret first character of next sequence */ - in_escape = 1; - return; - } - - switch (help_state) { - case 0: - help_send_escape(ios, buf[current]); - break; - case 1: - help_set_terminal(ios, buf[current]); - break; - default: - help_set_speed(ios, buf[current]); - } /* end switch */ - current++; - if (current >= num) - return; - } /* if - end of processing escape sequence */ - num -= current; - buf += current; - current = 0; - } /* while - end of processing all the charactes in the buffer */ - return; -} @@ -25,6 +25,9 @@ #include <getopt.h> #include <sys/socket.h> #include <string.h> +#include <stdint.h> +#include <sys/types.h> +#include <sys/stat.h> int dolog = 0; /* log active flag */ FILE *flog; /* log file */ @@ -35,17 +38,28 @@ int telnet = 0; struct ios_ops *ios; int debug = 0; -void init_stdin(struct termios *sts) +void init_terminal(void) { + struct termios sts; + + memcpy(&sts, &sots, sizeof (sots)); /* to be used upon exit */ + /* again, some arbitrary things */ - sts->c_iflag &= ~BRKINT; - sts->c_iflag |= IGNBRK; - sts->c_lflag &= ~ISIG; - sts->c_cc[VMIN] = 1; - sts->c_cc[VTIME] = 0; - sts->c_lflag &= ~ICANON; + sts.c_iflag &= ~BRKINT; + sts.c_iflag |= IGNBRK; + sts.c_lflag &= ~ISIG; + sts.c_cc[VMIN] = 1; + sts.c_cc[VTIME] = 0; + sts.c_lflag &= ~ICANON; /* no local echo: allow the other end to do the echoing */ - sts->c_lflag &= ~(ECHO | ECHOCTL | ECHONL); + sts.c_lflag &= ~(ECHO | ECHOCTL | ECHONL); + + tcsetattr(STDIN_FILENO, TCSANOW, &sts); +} + +void restore_terminal(void) +{ + tcsetattr(STDIN_FILENO, TCSANOW, &sots); } speed_t baudrate_to_flag(int speed) @@ -145,14 +159,16 @@ void main_usage(int exitcode, char *str, char *dev) } int opt_force = 0; +int current_speed = DEFAULT_BAUDRATE; +int current_flow = FLOW_NONE; int main(int argc, char *argv[]) { - struct termios sts; /* termios settings on stdout/in */ - struct sigaction sact; /* used to initialize the signal handler */ - int opt, speed = DEFAULT_BAUDRATE; + struct sigaction sact; /* used to initialize the signal handler */ + int opt; char *hostport = NULL; char *device = DEFAULT_DEVICE; + speed_t flag; struct option long_options[] = { { "help", no_argument, 0, 'h' }, @@ -173,7 +189,7 @@ int main(int argc, char *argv[]) device = optarg; break; case 's': - speed = strtoul(optarg, NULL, 0); + current_speed = strtoul(optarg, NULL, 0); break; case 't': telnet = 1; @@ -187,7 +203,7 @@ int main(int argc, char *argv[]) } } - printf("*** Welcome to microcom (%s) ***\n", PKG_VERSION); + commands_init(); if (telnet) ios = telnet_init(hostport); @@ -197,22 +213,20 @@ int main(int argc, char *argv[]) if (!ios) exit(1); - speed = baudrate_to_flag(speed); - if (speed < 0) - exit(1); - - ios->set_speed(ios, speed); + flag = baudrate_to_flag(current_speed); + if (flag < 0) + exit(1); - ios->set_flow(ios, FLOW_NONE); + current_flow = FLOW_NONE; + ios->set_speed(ios, flag); + ios->set_flow(ios, current_flow); printf("Escape character: Ctrl-\\\n"); printf("Type the escape character followed by c to get to the menu or q to quit\n"); /* Now deal with the local terminal side */ - tcgetattr(STDIN_FILENO, &sts); - memcpy(&sots, &sts, sizeof (sots)); /* to be used upon exit */ - init_stdin(&sts); - tcsetattr(STDIN_FILENO, TCSANOW, &sts); + tcgetattr(STDIN_FILENO, &sots); + init_terminal(); /* set the signal handler to restore the old * termios handler */ @@ -227,6 +241,5 @@ int main(int argc, char *argv[]) microcom_exit(0); - /* not reached */ return 0; } @@ -56,14 +56,17 @@ struct ios_ops { int fd; }; -void cook_buf(struct ios_ops *, unsigned char *buf, int num); /* microcom.c */ void mux_loop(struct ios_ops *); /* mux.c */ +void init_terminal(void); +void restore_terminal(void); struct ios_ops *telnet_init(char *hostport); struct ios_ops *serial_init(char *dev); void microcom_exit(int signal); +void microcom_cmd_usage(char *str); + void main_usage(int exitcode, char *str, char *dev); int flag_to_baudrate(speed_t speed); @@ -75,6 +78,29 @@ extern int dolog; extern FILE *flog; extern int opt_force; +struct cmd { + char *name; + int(*fn)(int argc, char *argv[]); + struct cmd *next; + char *info; + char *help; +}; + +int register_command(struct cmd *cmd); +#define MICROCOM_CMD_START 100 +#define MICROCOM_CMD_USAGE 101 +extern struct cmd *commands; + +#define for_each_command(cmd) for (cmd = commands; cmd; cmd = cmd->next) + +void commands_init(void); +void commands_fsl_imx_init(void); +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +extern int current_speed; +extern int current_flow; +int do_commandline(void); +int do_script(char *script); + #define dprintf(fmt,args...) ({ if (debug) printf (fmt ,##args); }) /* RFC2217 */ @@ -182,6 +182,32 @@ static int handle_command(unsigned char *buf, int len) return len; } +/* handle escape characters, writing to output */ +static void cook_buf(struct ios_ops *ios, unsigned char *buf, int num) +{ + int current = 0; + + while (current < num) { /* big while loop, to process all the charactes in buffer */ + + /* look for the next escape character '~' */ + while ((current < num) && (buf[current] != 28)) + current++; + /* and write the sequence befor esc char to the comm port */ + if (current) + write(ios->fd, buf, current); + + if (current < num) { /* process an escape sequence */ + /* found an escape character */ + do_commandline(); + return; + } /* if - end of processing escape sequence */ + num -= current; + buf += current; + current = 0; + } /* while - end of processing all the charactes in the buffer */ + return; +} + /* main program loop */ void mux_loop(struct ios_ops *ios) { diff --git a/parser.c b/parser.c new file mode 100644 index 0000000..fae951e --- /dev/null +++ b/parser.c @@ -0,0 +1,199 @@ +#include <stdio.h> +#include <readline/readline.h> +#include <readline/history.h> +#include "microcom.h" + +#define MAXARGS 64 + +static int parse_line(char *_line, int *argc, char *argv[]) +{ + char *line = _line; + int nargs = 0; + + if (!line) + goto out; + + while (nargs < MAXARGS) { + + /* skip any white space */ + while (*line == ' ' || *line == '\t') + ++line; + + if (*line == '\0' || *line == ';') /* end of line, no more args */ + goto out; + + argv[nargs] = line; /* begin of argument string */ + + if (*line == '\"') { + line++; + argv[nargs] = line; + while (*line && *line != '\"') + line++; + if (!*line) { + printf("could not find matching '\"'\n"); + return -EINVAL; + } else + *line++ = '\0'; + } else { + /* find end of string */ + while (*line && *line != ' ' && *line != '\t' && *line != ';') + ++line; + } + + nargs++; + + + if (*line == '\0') /* end of line, no more args */ + goto out; + if (*line == ';') { + *line = '\0'; + goto out; + } + + *line++ = '\0'; /* terminate current arg */ + } + + printf("Too many args (max. %d)\n", MAXARGS); +out: + argv[nargs] = NULL; + *argc = nargs; + + return line - _line + 1; +} + +struct cmd *commands; + +int register_command(struct cmd *cmd) +{ + struct cmd *tmp; + + cmd->next = NULL; + + if (!commands) { + commands = cmd; + return 0; + } + + tmp = commands; + + while (tmp->next) + tmp = tmp->next; + + tmp->next = cmd; + + return 0; +} + +void microcom_cmd_usage(char *command) +{ + struct cmd *cmd; + + for_each_command(cmd) { + if (!strcmp(command, cmd->name)) { + char *str = NULL; + if (cmd->info) + str = cmd->info; + if (cmd->help) + str = cmd->help; + if (!str) + str = "no help available\n"; + printf("usage:\n%s\n", str); + return; + } + } + printf("no such command\n"); +} + +static int __do_commandline(const char *prompt) +{ + char *cmd; + char *argv[MAXARGS + 1]; + int argc = 0, ret = 0, n, len; + + while (1) { + struct cmd *command; + cmd = readline(prompt); + if (!cmd) { + ret = MICROCOM_CMD_START; + break; + } + + if (!strlen(cmd)) + goto done; + + if (prompt) + add_history(cmd); + + len = strlen(cmd); + n = 0; + while (n < len) { + int handled = 0; + ret = parse_line(cmd + n, &argc, argv); + if (ret < 0) + break; + n += ret; + if (!argv[0]) + continue; + + for_each_command(command) { + if (!strcmp(argv[0], command->name)) { + ret = command->fn(argc, argv); + if (ret == MICROCOM_CMD_START) { + free(cmd); + return ret; + } + + if (ret == MICROCOM_CMD_USAGE) + microcom_cmd_usage(argv[0]); + + handled = 1; + break; + } + } + if (!handled) + printf("unknown command \'%s\', try \'help\'\n", argv[0]); + } +done: + free(cmd); + } + + if (cmd) + free(cmd); + return ret; +} + +int do_commandline(void) +{ + int ret; + + restore_terminal(); + printf("\nEnter command. Try \'help\' for a list of builtin commands\n"); + + do { + ret = __do_commandline("-> "); + } while (ret != MICROCOM_CMD_START); + + printf("\n----------------------\n"); + init_terminal(); + + return 0; +} + +int do_script(char *script) +{ + int fd = open(script, O_RDONLY); + int stdin = dup(1); + int ret; + + if (fd < 0) { + printf("could not open %s: %s\n", script, strerror(errno)); + return -1; + } + + dup2(fd, 0); + ret = __do_commandline(NULL); + dup2(stdin, 0); + + return ret; +} + |