ChibiOS/os/sb/apps/msh/main.c

267 lines
5.1 KiB
C

/*
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include "sbuser.h"
#define SHELL_MAX_LINE_LENGTH 128
#define SHELL_MAX_ARGUMENTS 20
#define SHELL_PROMPT_STR "> "
#define SHELL_NEWLINE_STR "\r\n"
#define SHELL_WELCOME_STR "ChibiOS/SB shell"
static const char *prompt;
static void shell_write(const char *s) {
size_t n = strlen(s);
(void) write(STDOUT_FILENO, s, n);
}
static void shell_error(const char *s) {
size_t n = strlen(s);
(void) write(STDERR_FILENO, s, n);
}
static void shell_putc(char c) {
(void) write(STDOUT_FILENO, &c, 1);
}
static void shell_usage(const char *s) {
shell_error("usage: ");
shell_error(s);
shell_error(SHELL_NEWLINE_STR);
}
bool shell_getline(char *line, size_t size) {
char *p = line;
while (true) {
char c;
if (read(STDIN_FILENO, &c, 1) == 0)
return true;
if (c == 4) {
shell_putc('^');
shell_putc('D');
return true;
}
if ((c == 8) || (c == 127)) {
if (p != line) {
shell_putc(8);
shell_putc(' ');
shell_putc(8);
p--;
}
continue;
}
if (c == '\r') {
shell_write(SHELL_NEWLINE_STR);
*p = 0;
return false;
}
if (c < 0x20)
continue;
if (p < line + size - 1) {
shell_putc(c);
*p++ = c;
}
}
}
static char *fetch_argument(char **pp) {
char *p, *ap;
/* Skipping white space.*/
ap = *pp;
ap += strspn(ap, " \t");
if (*ap == '\0') {
return NULL;
}
if (*ap == '"') {
/* If an argument starts with a double quote then its delimiter is another
quote.*/
ap++;
p = strpbrk(ap, "\"");
}
else {
/* The delimiter is white space.*/
p = strpbrk(ap, " \t");
}
if (p != NULL) {
/* Replacing the delimiter with a zero.*/
*p++ = '\0';
}
else {
/* Final one, pointing on the final zero.*/
p = ap + strlen(ap);
}
*pp = p;
return ap;
}
static void cmd_env(int argc, char *argv[]) {
extern char **environ;
char **pp;
(void)argv;
if (argc != 1) {
shell_usage("env");
return;
}
pp = environ;
while (*pp != NULL) {
shell_write(*pp++);
shell_write(SHELL_NEWLINE_STR);
}
}
static void cmd_exit(int argc, char *argv[]) {
msg_t msg;
if (argc == 1) {
msg = 0;
}
else if (argc == 2) {
msg = atoi(argv[1]);
}
else {
shell_usage("exit [n]");
return;
}
sbExit(msg);
}
static void cmd_path(int argc, char *argv[]) {
char *s;
(void)argv;
if (argc != 1) {
shell_usage("path");
return;
}
s = getenv("PATH");
if (s != NULL) {
shell_write(s);
shell_write(SHELL_NEWLINE_STR);
}
}
static bool shell_execute(int argc, char *argv[]) {
int i;
static const struct {
const char *name;
void (*cmdf)(int argc, char *argv[]);
} builtins[] = {
{"env", cmd_env},
{"exit", cmd_exit},
{"path", cmd_path},
{NULL, NULL}
};
i = 0;
while (builtins[i].name != NULL) {
if (strcmp(builtins[i].name, argv[0]) == 0) {
builtins[i].cmdf(argc, argv);
return false;
}
i++;
}
return true;
}
/*
* Application entry point.
*/
int main(int argc, char *argv[], char *envp[]) {
char line[SHELL_MAX_LINE_LENGTH];
char *args[SHELL_MAX_ARGUMENTS + 1];
char *ap, *tokp;
int i;
asm volatile ("bkpt");
(void)argc;
(void)argv;
(void)envp;
prompt = getenv("PROMPT");
if (prompt == NULL) {
prompt = SHELL_PROMPT_STR;
}
/* Welcome.*/
shell_write(SHELL_NEWLINE_STR SHELL_WELCOME_STR SHELL_NEWLINE_STR);
while (true) {
/* Prompt.*/
shell_write(prompt);
/* Reading input line.*/
if (shell_getline(line, SHELL_MAX_LINE_LENGTH)) {
shell_write(SHELL_NEWLINE_STR);
shell_write("logout");
break;
}
/* Parsing arguments.*/
tokp = line;
i = 0;
while ((ap = fetch_argument(&tokp)) != NULL) {
if (i < SHELL_MAX_ARGUMENTS) {
args[i++] = ap;
}
else {
i = 0;
shell_error("too many arguments" SHELL_NEWLINE_STR);
break;
}
}
args[i] = NULL;
/* Executing command, if any.*/
if (i > 0) {
if (shell_execute(i, args)){
shell_error(args[0]);
shell_error("?" SHELL_NEWLINE_STR);
}
}
}
}