mirror of https://github.com/zrafa/xinu-avr.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
330 lines
8.1 KiB
330 lines
8.1 KiB
/* shell.c - shell */ |
|
|
|
#include <xinu.h> |
|
//#include <stdio.h> |
|
#include "shprototypes.h" |
|
|
|
/************************************************************************/ |
|
/* Table of Xinu shell commands and the function associated with each */ |
|
/************************************************************************/ |
|
const struct cmdent cmdtab[] = { |
|
{"memstat", FALSE, xsh_memstat}, /* Make built-in */ |
|
{"editor", FALSE, xsh_editor}, /* Make built-in */ |
|
{"basic", FALSE, xsh_basic}, /* Make built-in */ |
|
{"echo", FALSE, xsh_echo} |
|
// {"argecho", TRUE, xsh_argecho}, |
|
// {"cat", FALSE, xsh_cat}, |
|
// {"clear", TRUE, xsh_clear}, |
|
// {"date", FALSE, xsh_date}, |
|
// {"devdump", FALSE, xsh_devdump}, |
|
// {"echo", FALSE, xsh_echo}, |
|
// {"exit", TRUE, xsh_exit}, |
|
// {"help", FALSE, xsh_help}, |
|
// {"kill", TRUE, xsh_kill}, |
|
// {"memdump", FALSE, xsh_memdump}, |
|
// {"ps", FALSE, xsh_ps}, |
|
// {"sleep", FALSE, xsh_sleep}, |
|
// {"uptime", FALSE, xsh_uptime}, |
|
// {"?", FALSE, xsh_help} |
|
|
|
}; |
|
|
|
uint32 ncmd = sizeof(cmdtab) / sizeof(struct cmdent); |
|
|
|
/************************************************************************/ |
|
/* shell - Provide an interactive user interface that executes */ |
|
/* commands. Each command begins with a command name, has */ |
|
/* a set of optional arguments, has optional input or */ |
|
/* output redirection, and an optional specification for */ |
|
/* background execution (ampersand). The syntax is: */ |
|
/* */ |
|
/* command_name [args*] [redirection] [&] */ |
|
/* */ |
|
/* Redirection is either or both of: */ |
|
/* */ |
|
/* < input_file */ |
|
/* or */ |
|
/* > output_file */ |
|
/* */ |
|
/************************************************************************/ |
|
|
|
process shell ( |
|
// did32 dev /* ID of tty device from which */ |
|
) /* to accept commands */ |
|
{ |
|
char buf[SHELL_BUFLEN]; /* Input line (large enough for */ |
|
int32 len; /* Length of line read */ |
|
char tokbuf[SHELL_BUFLEN + /* Buffer to hold a set of */ |
|
SHELL_MAXTOK]; /* Contiguous null-terminated */ |
|
int32 tlen; /* Current length of all data */ |
|
/* in array tokbuf */ |
|
int32 tok[SHELL_MAXTOK]; /* Index of each token in */ |
|
int32 toktyp[SHELL_MAXTOK]; /* Type of each token in tokbuf */ |
|
int32 ntok; /* Number of tokens on line */ |
|
pid32 child; /* Process ID of spawned child */ |
|
bool8 backgnd; /* Run command in background? */ |
|
char *outname, *inname; /* Pointers to strings for file */ |
|
/* names that follow > and < */ |
|
did32 stdinput, stdoutput; /* Descriptors for redirected */ |
|
/* input and output */ |
|
int32 i; /* Index into array of tokens */ |
|
int32 j; /* Index into array of commands */ |
|
int32 msg; /* Message from receive() for */ |
|
/* child termination */ |
|
int32 tmparg; /* Address of this var is used */ |
|
/* when first creating child */ |
|
/* process, but is replaced */ |
|
char *src, *cmp; /* Pointers used during name */ |
|
/* comparison */ |
|
bool8 diff; /* Was difference found during */ |
|
char *args[SHELL_MAXTOK]; /* Argument vector passed to */ |
|
/* builtin commands */ |
|
did32 dev = 0; /* ID of tty device from which */ |
|
|
|
/* Print shell banner and startup message */ |
|
|
|
/* |
|
fprintf(dev, "\n\n%s%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", |
|
SHELL_BAN0,SHELL_BAN1,SHELL_BAN2,SHELL_BAN3,SHELL_BAN4, |
|
SHELL_BAN5,SHELL_BAN6,SHELL_BAN7,SHELL_BAN8,SHELL_BAN9,SHELL_BAN10); |
|
|
|
fprintf(dev, "%s\n\n", SHELL_STRTMSG); |
|
*/ |
|
|
|
/* Continually prompt the user, read input, and execute command */ |
|
|
|
|
|
while (TRUE) { |
|
|
|
// RAFA |
|
// fprintf(dev, "\033[2J"); |
|
// fprintf(dev, "\033[H"); |
|
|
|
/* Display prompt */ |
|
fprintf(dev, SHELL_PROMPT); |
|
|
|
|
|
len = read(dev, buf, sizeof(buf)); |
|
|
|
/* Exit gracefully on end-of-file */ |
|
|
|
if (len == EOF) { |
|
break; |
|
} |
|
|
|
/* If line contains only NEWLINE, go to next line */ |
|
|
|
if (len <= 1) { |
|
continue; |
|
} |
|
|
|
buf[len] = SH_NEWLINE; /* terminate line */ |
|
|
|
/* Parse input line and divide into tokens */ |
|
|
|
ntok = lexan(buf, len, tokbuf, &tlen, tok, toktyp); |
|
|
|
/* Handle parsing error */ |
|
|
|
if (ntok == SYSERR) { |
|
// fprintf(dev,"%s\n", SHELL_SYNERRMSG); |
|
continue; |
|
} |
|
|
|
/* If line is empty, go to next input line */ |
|
|
|
if (ntok == 0) { |
|
// fprintf(dev, "\n"); |
|
continue; |
|
} |
|
|
|
/* If last token is '&', set background */ |
|
|
|
if (toktyp[ntok-1] == SH_TOK_AMPER) { |
|
ntok-- ; |
|
tlen-= 2; |
|
backgnd = TRUE; |
|
} else { |
|
backgnd = FALSE; |
|
} |
|
|
|
|
|
/* Check for input/output redirection (default is none) */ |
|
|
|
outname = inname = NULL; |
|
if ( (ntok >=3) && ( (toktyp[ntok-2] == SH_TOK_LESS) |
|
||(toktyp[ntok-2] == SH_TOK_GREATER))){ |
|
if (toktyp[ntok-1] != SH_TOK_OTHER) { |
|
// fprintf(dev,"%s\n", SHELL_SYNERRMSG); |
|
continue; |
|
} |
|
if (toktyp[ntok-2] == SH_TOK_LESS) { |
|
inname = &tokbuf[tok[ntok-1]]; |
|
} else { |
|
outname = &tokbuf[tok[ntok-1]]; |
|
} |
|
ntok -= 2; |
|
tlen = tok[ntok]; |
|
} |
|
|
|
|
|
if ( (ntok >=3) && ( (toktyp[ntok-2] == SH_TOK_LESS) |
|
||(toktyp[ntok-2] == SH_TOK_GREATER))){ |
|
if (toktyp[ntok-1] != SH_TOK_OTHER) { |
|
// fprintf(dev,"%s\n", SHELL_SYNERRMSG); |
|
continue; |
|
} |
|
if (toktyp[ntok-2] == SH_TOK_LESS) { |
|
if (inname != NULL) { |
|
// fprintf(dev,"%s\n", SHELL_SYNERRMSG); |
|
continue; |
|
} |
|
inname = &tokbuf[tok[ntok-1]]; |
|
} else { |
|
if (outname != NULL) { |
|
// fprintf(dev,"%s\n", SHELL_SYNERRMSG); |
|
continue; |
|
} |
|
outname = &tokbuf[tok[ntok-1]]; |
|
} |
|
ntok -= 2; |
|
tlen = tok[ntok]; |
|
} |
|
|
|
/* Verify remaining tokens are type "other" */ |
|
|
|
for (i=0; i<ntok; i++) { |
|
if (toktyp[i] != SH_TOK_OTHER) { |
|
break; |
|
} |
|
} |
|
if ((ntok == 0) || (i < ntok)) { |
|
// fprintf(dev, SHELL_SYNERRMSG); |
|
continue; |
|
} |
|
|
|
stdinput = stdoutput = dev; |
|
|
|
/* Lookup first token in the command table */ |
|
|
|
for (j = 0; j < ncmd; j++) { |
|
src = cmdtab[j].cname; |
|
cmp = tokbuf; |
|
diff = FALSE; |
|
while (*src != NULLCH) { |
|
if (*cmp != *src) { |
|
diff = TRUE; |
|
break; |
|
} |
|
src++; |
|
cmp++; |
|
} |
|
if (diff || (*cmp != NULLCH)) { |
|
continue; |
|
} else { |
|
break; |
|
} |
|
} |
|
|
|
/* Handle command not found */ |
|
|
|
if (j >= ncmd) { |
|
// fprintf(dev, "command %s not found\n", tokbuf); |
|
continue; |
|
} |
|
|
|
/* Handle built-in command */ |
|
|
|
if (cmdtab[j].cbuiltin) { /* No background or redirect. */ |
|
if (inname != NULL || outname != NULL || backgnd){ |
|
// fprintf(dev, SHELL_BGERRMSG); |
|
continue; |
|
} else { |
|
/* Set up arg vector for call */ |
|
|
|
for (i=0; i<ntok; i++) { |
|
args[i] = &tokbuf[tok[i]]; |
|
} |
|
|
|
/* Call builtin shell function */ |
|
|
|
if ((*cmdtab[j].cfunc)(ntok, args) |
|
== SHELL_EXIT) { |
|
break; |
|
} |
|
} |
|
continue; |
|
} |
|
|
|
/* Open files and redirect I/O if specified */ |
|
|
|
if (inname != NULL) { |
|
stdinput = open(NAMESPACE,inname,"ro"); |
|
if (stdinput == SYSERR) { |
|
// fprintf(dev, SHELL_INERRMSG, inname); |
|
continue; |
|
} |
|
} |
|
if (outname != NULL) { |
|
stdoutput = open(NAMESPACE,outname,"w"); |
|
if (stdoutput == SYSERR) { |
|
// fprintf(dev, SHELL_OUTERRMSG, outname); |
|
continue; |
|
} else { |
|
control(stdoutput, F_CTL_TRUNC, 0, 0); |
|
} |
|
} |
|
|
|
// int eeprom_fd = open(RAM0, nombre, "w"); |
|
// char raf[32] = "pepe"; |
|
// write(fd, pepe, 32); |
|
// int eeprom_fd = open(RAM0, nombre, "w"); |
|
|
|
/* Spawn child thread for non-built-in commands */ |
|
|
|
// RAFA child = create(cmdtab[j].cfunc, |
|
// RAFA SHELL_CMDSTK, SHELL_CMDPRIO, |
|
// RAFA cmdtab[j].cname, 2, ntok, &tmparg); |
|
/* 160 bytes de stack perfecto */ |
|
child = create(cmdtab[j].cfunc, |
|
460, SHELL_CMDPRIO, |
|
cmdtab[j].cname, 2, ntok, &tmparg); |
|
|
|
/* If creation or argument copy fails, report error */ |
|
|
|
// serial_put_char('X'); |
|
// if (child == SYSERR) |
|
// serial_put_char('Y'); |
|
if ((child == SYSERR) || |
|
(addargs(child, ntok, tok, tlen, tokbuf, &tmparg) |
|
== SYSERR) ) { |
|
// serial_put_char('Z'); |
|
fprintf(dev, SHELL_CREATMSG); |
|
continue; |
|
} |
|
|
|
/* Set stdinput and stdoutput in child to redirect I/O */ |
|
|
|
proctab[child].prdesc[0] = stdinput; |
|
proctab[child].prdesc[1] = stdoutput; |
|
|
|
msg = recvclr(); |
|
resume(child); |
|
|
|
// RAFA AGREGA |
|
resched(); |
|
// serial_put_char('X'); |
|
|
|
if (! backgnd) { |
|
msg = receive(); |
|
while (msg != child) { |
|
msg = receive(); |
|
} |
|
} |
|
} |
|
|
|
/* Terminate the shell process by returning from the top level */ |
|
|
|
// fprintf(dev,SHELL_EXITMSG); |
|
return OK; |
|
}
|
|
|