From dd74e612f1ffe208ad1e20f28ac4da3f08764879 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Fri, 20 Apr 2001 20:35:45 +0000 Subject: 2001-04-20 Correo Fernando-ruiz * Added initial shell functionality. * Makefile.am, configure.in, wrapup/Makefile.am: * shell/.cvsignore, shell/Makefile.am, shell/README, shell/cmds.c, shell/shell.c, shell/shell.h: New files. --- cpukit/libmisc/shell/shell.c | 470 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 470 insertions(+) create mode 100644 cpukit/libmisc/shell/shell.c (limited to 'cpukit/libmisc/shell/shell.c') diff --git a/cpukit/libmisc/shell/shell.c b/cpukit/libmisc/shell/shell.c new file mode 100644 index 0000000000..d7c2502d90 --- /dev/null +++ b/cpukit/libmisc/shell/shell.c @@ -0,0 +1,470 @@ +/* + * + * Instantatiate a new terminal shell. + * + * Author: + * + * WORK: fernando.ruiz@ctv.es + * HOME: correo@fernando-ruiz.com + * + * Thanks at: + * Chris John + * + * $Id$ + */ + +#undef __STRICT_ANSI__ /* fileno() */ +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +/* ----------------------------------------------- * + * This is a stupidity but is cute. + * ----------------------------------------------- */ +rtems_unsigned32 new_rtems_name(char * rtems_name) { + static char b[5]; + sprintf(b,"%-4.4s",rtems_name); + return rtems_build_name(b[0],b[1],b[2],b[3]); +} +/* ************************************************************** + * common linked list of shell commands. + * Because the help report is very long + * I have a topic for each command. + * Help list the topics + * help [topic] list the commands for the topic + * help [command] help for the command + * Can you see help rtems monitor report? + * ************************************************************** */ + +struct shell_topic_tt; +typedef struct shell_topic_tt shell_topic_t; + +struct shell_topic_tt { + char * topic; + shell_topic_t * next; +}; + + +static shell_cmd_t * shell_first_cmd; +static shell_topic_t * shell_first_topic; +/* ----------------------------------------------- * + * Using Chain I can reuse the rtems code. + * I am more comfortable with this, sorry. + * ----------------------------------------------- */ +shell_topic_t * shell_lookup_topic(char * topic) { + shell_topic_t * shell_topic; + shell_topic=shell_first_topic; + while (shell_topic) { + if (!strcmp(shell_topic->topic,topic)) return shell_topic; + shell_topic=shell_topic->next; + }; + return (shell_topic_t *) NULL; +} +/* ----------------------------------------------- */ +shell_topic_t * shell_add_topic(char * topic) { + shell_topic_t * current,*aux; + if (!shell_first_topic) { + aux=malloc(sizeof(shell_topic_t)); + aux->topic=topic; + aux->next=(shell_topic_t*)NULL; + return shell_first_topic=aux; + } else { + current=shell_first_topic; + if (!strcmp(topic,current->topic)) return current; + while (current->next) { + if (!strcmp(topic,current->next->topic)) return current->next; + current=current->next; + }; + aux=malloc(sizeof(shell_topic_t)); + aux->topic=topic; + aux->next=(shell_topic_t*)NULL; + current->next=aux; + return aux; + }; +} +/* ----------------------------------------------- */ +shell_cmd_t * shell_lookup_cmd(char * cmd) { + shell_cmd_t * shell_cmd; + shell_cmd=shell_first_cmd; + while (shell_cmd) { + if (!strcmp(shell_cmd->name,cmd)) return shell_cmd; + shell_cmd=shell_cmd->next; + }; + return (shell_cmd_t *) NULL; +} +/* ----------------------------------------------- */ +shell_cmd_t * shell_add_cmd(char * cmd, + char * topic, + char * usage, + shell_command_t command) { + int shell_help(int argc,char * argv[]); + shell_cmd_t * shell_cmd,*shell_pvt; + if (!shell_first_cmd) { + shell_first_cmd=(shell_cmd_t *) malloc(sizeof(shell_cmd_t)); + shell_first_cmd->name ="help"; + shell_first_cmd->topic ="help"; + shell_first_cmd->usage ="help [topic] # list of usage of commands"; + shell_first_cmd->command=shell_help; + shell_first_cmd->alias =(shell_cmd_t *) NULL; + shell_first_cmd->next =(shell_cmd_t *) NULL; + shell_add_topic(shell_first_cmd->topic); + register_cmds(); + }; + if (!cmd) return (shell_cmd_t *) NULL; + if (!command) return (shell_cmd_t *) NULL; + shell_cmd=(shell_cmd_t *) malloc(sizeof(shell_cmd_t)); + shell_cmd->name =cmd; + shell_cmd->topic =topic; + shell_cmd->usage =usage; + shell_cmd->command=command; + shell_cmd->alias =(shell_cmd_t *) NULL; + shell_cmd->next =(shell_cmd_t *) NULL; + shell_add_topic(shell_cmd->topic); + shell_pvt=shell_first_cmd; + while (shell_pvt->next) shell_pvt=shell_pvt->next; + return shell_pvt->next=shell_cmd; +} +/* ----------------------------------------------- * + * you can make an alias for every command. + * ----------------------------------------------- */ +shell_cmd_t * shell_alias_cmd(char * cmd, char * alias) { + shell_cmd_t * shell_cmd,* shell_aux; + shell_aux=(shell_cmd_t *) NULL; + if (alias) { + if ((shell_aux=shell_lookup_cmd(alias))!=NULL) { + return NULL; + }; + if ((shell_cmd=shell_lookup_cmd(cmd))!=NULL) { + shell_aux=shell_add_cmd(alias,shell_cmd->topic, + shell_cmd->usage,shell_cmd->command); + if (shell_aux) shell_aux->alias=shell_cmd; + }; + }; + return shell_aux; +} +/* ----------------------------------------------- * + * Poor but enough.. + * TODO: Redirection capture. "" evaluate, ... C&S welcome. + * ----------------------------------------------- */ +int shell_make_args(char * cmd, + int * pargc, + char * argv[]) { + int argc=0; + while ((cmd=strtok(cmd," \t\r\n"))!=NULL) { + argv[argc++]=cmd; + cmd=(char*)NULL; + }; + argv[argc]=(char*)NULL; + return *pargc=argc; +} +/* ----------------------------------------------- * + * show the help for one command. + * ----------------------------------------------- */ +int shell_help_cmd(shell_cmd_t * shell_cmd) { + char * pc; + int col,line; + printf("%-10.10s -",shell_cmd->name); + col=12; + line=1; + if (shell_cmd->alias) { + printf("is an for command '%s'",shell_cmd->alias->name); + } else + if (shell_cmd->usage) { + pc=shell_cmd->usage; + while (*pc) { + switch(*pc) { + case '\r':break; + case '\n':putchar('\n'); + col=0; + break; + default :putchar(*pc); + col++; + break; + }; + pc++; + if(col>78) { /* What daring... 78?*/ + if (*pc) { + putchar('\n'); + col=0; + }; + }; + if (!col && *pc) { + printf(" "); + col=12;line++; + }; + }; + }; + puts(""); + return line; +} +/* ----------------------------------------------- * + * show the help. The first command implemented. + * Can you see the header of routine? Known? + * The same with all the commands.... + * ----------------------------------------------- */ +int shell_help(int argc,char * argv[]) { + int col,line,arg; + shell_topic_t *topic; + shell_cmd_t * shell_cmd=shell_first_cmd; + if (argc<2) { + printf("help: TOPIC? The topics are\n"); + topic=shell_first_topic; + col=0; + while (topic) { + if (!col){ + col=printf(" %s",topic->topic); + } else { + if ((col+strlen(topic->topic)+2)>78){ + printf("\n"); + col=printf(" %s",topic->topic); + } else { + col+=printf(", %s",topic->topic); + }; + }; + topic=topic->next; + }; + printf("\n"); + return 1; + }; + line=0; + for (arg=1;arg16) { + printf("Press any key to continue...");getchar(); + printf("\n"); + line=0; + }; + topic=shell_lookup_topic(argv[arg]); + if (!topic){ + if ((shell_cmd=shell_lookup_cmd(argv[arg]))==NULL) { + printf("help: topic or cmd '%s' not found. Try alone for a list\n",argv[arg]); + line++; + } else { + line+=shell_help_cmd(shell_cmd); + } + continue; + }; + printf("help: list for the topic '%s'\n",argv[arg]); + line++; + while (shell_cmd) { + if (!strcmp(topic->topic,shell_cmd->topic)) + line+=shell_help_cmd(shell_cmd); + if (line>16) { + printf("Press any key to continue...");getchar(); + printf("\n"); + line=0; + }; + shell_cmd=shell_cmd->next; + }; + }; + puts(""); + return 0; +} +/* ----------------------------------------------- * + * TODO:Change to bash readline() better. + * ----------------------------------------------- */ +int shell_scanline(char * line,int size,FILE * in,FILE * out) { + int c,col; + col=0; + for (;;) { + line[col]=0; + c=fgetc(in); + switch (c) { + case EOF :return 0; + case '\r':if (out) fputc('\n',out); + return 1; + case '\b':if (col) { + if (out) { + fputc('\b',out); + fputc(' ',out); + fputc('\b',out); + }; + col--; + } else { + if (out) fputc('\a',out); + }; + break; + default :if (!iscntrl(c)) { + if (coldevname; + + stdin =fopen(devname,"r+"); + + if (!stdin) { + fprintf(stderr,"shell:unable to open stdin.%s:%s\n",devname,strerror(errno)); + printk("shell:unable to open stdin.(%s)",strerror(errno)); + rtems_task_delete(RTEMS_SELF); + }; + setvbuf(stdin,NULL,_IONBF,0); /* Not buffered*/ + /* make a raw terminal,Linux MANuals */ + if (tcgetattr (fileno(stdin), &term)>=0) { + term.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); + term.c_oflag &= ~OPOST; + term.c_oflag |= (OPOST|ONLCR); + term.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); + term.c_cflag = CLOCAL | CREAD |(shell_env->tcflag); + term.c_cc[VMIN] = 1; + term.c_cc[VTIME] = 0; + if (tcsetattr (fileno(stdin), TCSADRAIN, &term) < 0) { + fprintf(stderr,"shell:cannot set terminal attributes(%s)\n",devname); + }; + stdout=fopen(devname,"r+"); + if (!stdout) { + fprintf(stderr,"shell:unable to open stdout.%s:%s\n",devname,strerror(errno)); + }; + stderr=fopen(devname,"r+"); + if (!stderr) { + printf("shell:unable to open stderr.%s:%s\n",devname,strerror(errno)); + }; + /* when the future user environment runs ok + * a freopen() reopens the terminals. Now this don't work + * (sorry but you can't use because FILENO_STDIN!=0. Better fileno(stdin)) + */ + }; + shell_add_cmd(NULL,NULL,NULL,NULL); /* init the chain list*/ + strcpy(cmd,""); + printf("\n" + "RTEMS-SHELL:%s. "__DATE__". 'help' to list commands.\n",devname); + curdir=malloc(1024); + chdir("/"); + for (;;) { + /* Prompt section */ + /* XXX: show_prompt user adjustable */ + getcwd(curdir,1024); + printf("%s [%s] # ",devname,curdir); + /* getcmd section */ + if (!shell_scanline(cmd,sizeof(cmd),stdin,stdout)) { + printf("shell:unable scanline(%s)\n",devname); + break; + }; + /* evaluate cmd section */ + if (!strcmp(cmd,"r")) { /* repeat last command, forced, not automatic */ + strcpy(cmd,last_cmd); + } else + if (strcmp(cmd,"")) { /* only for get a new prompt */ + strcpy(last_cmd,cmd); + }; + /* exec cmd section */ + /* TODO: + * To avoid user crash catch the signals. + * Open a new stdio files with posibility of redirection * + * Run in a new shell task background. (unix &) + * Resuming. A little bash. + */ + if (shell_make_args(cmd,&argc,argv)) { + if ((shell_cmd=shell_lookup_cmd(argv[0]))!=NULL) { + current_shell_env->errorlevel=shell_cmd->command(argc,argv); + } else { + printf("shell:%s command not found\n",argv[0]); + current_shell_env->errorlevel=-1; + }; + }; + /* end exec cmd section */ + }; + free(curdir); + rtems_task_delete(RTEMS_SELF); +} +/* ----------------------------------------------- */ +rtems_status_code shell_init (char * task_name, + rtems_unsigned32 task_stacksize, + rtems_task_priority task_priority, + char * devname, + tcflag_t tcflag) { + rtems_id task_id; + rtems_status_code sc; + shell_env_t * shell_env; + sc=rtems_task_create(new_rtems_name(task_name), + task_priority, + task_stacksize?task_stacksize:RTEMS_MINIMUM_STACK_SIZE, + (RTEMS_DEFAULT_MODES&~RTEMS_ASR_MASK)|RTEMS_ASR, + RTEMS_DEFAULT_ATTRIBUTES, + &task_id); + if (sc!=RTEMS_SUCCESSFUL) { + rtems_error(sc,"creating task %s in shell_init()",task_name); + return sc; + }; + shell_env=malloc(sizeof(shell_env_t)); + if (!shell_env) { + rtems_task_delete(task_id); + sc=RTEMS_NO_MEMORY; + rtems_error(sc,"allocating shell_env %s in shell_init()",task_name); + return sc; + }; + if (global_shell_env.magic!=new_rtems_name("SENV")) { + global_shell_env.magic =new_rtems_name("SENV"); + global_shell_env.devname ="/dev/console"; + global_shell_env.taskname="GLOBAL"; + global_shell_env.tcflag =0; + }; + shell_env->magic =global_shell_env.magic; + shell_env->devname =devname; + shell_env->taskname=task_name; + shell_env->tcflag =tcflag; + return rtems_task_start(task_id,shell_shell,(rtems_task_argument) shell_env); +} +/* ----------------------------------------------- */ + -- cgit v1.2.3