summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2010-04-14 15:08:12 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2010-04-14 16:05:50 +0200
commit647985a4f1ad2795158cd8d62e0eb79782518176 (patch)
treef345683beb20f8077d750c681f1292d24c7b652c
parent54c5725681d406360f5b580c7893c0d9f147ed7c (diff)
downloadmicrocom-cli.tar.gz
microcom-cli.tar.xz
implement a cli for microcomcli
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
-rw-r--r--Makefile9
-rw-r--r--commands.c161
-rw-r--r--help.c345
-rw-r--r--microcom.c61
-rw-r--r--microcom.h28
-rw-r--r--mux.c26
-rw-r--r--parser.c199
7 files changed, 456 insertions, 373 deletions
diff --git a/Makefile b/Makefile
index 760236a..f80b766 100644
--- a/Makefile
+++ b/Makefile
@@ -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]);
+}
diff --git a/help.c b/help.c
deleted file mode 100644
index b607ea9..0000000
--- a/help.c
+++ /dev/null
@@ -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;
-}
diff --git a/microcom.c b/microcom.c
index 46cbf0a..350c38e 100644
--- a/microcom.c
+++ b/microcom.c
@@ -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;
}
diff --git a/microcom.h b/microcom.h
index 2bf8a43..62c3900 100644
--- a/microcom.h
+++ b/microcom.h
@@ -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 */
diff --git a/mux.c b/mux.c
index be34078..b469479 100644
--- a/mux.c
+++ b/mux.c
@@ -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;
+}
+