source: rtems/c/src/libmisc/shell/shell.c @ d72caa6

4.104.114.84.95
Last change on this file since d72caa6 was d72caa6, checked in by Joel Sherrill <joel.sherrill@…>, on 05/07/01 at 13:17:25

2001-04-28 Ralf Corsepius <corsepiu@…>

  • shell/cmds.c, shell/shell.c: Remove fileno-hacks.
  • monitor/mon-symbols.c: Remove #undef STRICT_ANSI.
  • Property mode set to 100644
File size: 13.2 KB
Line 
1/*
2 *
3 *  Instantatiate a new terminal shell.
4 *
5 *  Author:
6 *
7 *   WORK: fernando.ruiz@ctv.es
8 *   HOME: correo@fernando-ruiz.com
9 *
10 *   Thanks at:
11 *    Chris John
12 *
13 *  $Id$
14 */
15
16#include <stdio.h>
17
18#include <rtems.h>
19#include <rtems/error.h>
20#include <rtems/libio.h>
21#include <rtems/libio_.h>
22
23#include <termios.h>
24#include <string.h>
25#include <stdlib.h>
26#include <ctype.h>
27#include <unistd.h>
28#include <errno.h>
29
30#include <rtems/shell.h>
31/* ----------------------------------------------- *
32 * This is a stupidity but is cute.
33 * ----------------------------------------------- */
34rtems_unsigned32 new_rtems_name(char * rtems_name) {
35        static char b[5];
36        sprintf(b,"%-4.4s",rtems_name);
37        return rtems_build_name(b[0],b[1],b[2],b[3]);
38}
39/* **************************************************************
40 * common linked list of shell commands.
41 * Because the help report is very long
42 * I have a topic for each command.
43 * Help list the topics
44 * help [topic] list the commands for the topic
45 * help [command] help for the command
46 * Can you see help rtems monitor report?
47 * ************************************************************** */
48
49struct shell_topic_tt;
50typedef struct shell_topic_tt shell_topic_t;
51
52struct shell_topic_tt {
53        char * topic;
54        shell_topic_t * next;
55};
56
57
58static shell_cmd_t   * shell_first_cmd;
59static shell_topic_t * shell_first_topic;
60/* ----------------------------------------------- *
61 * Using Chain I can reuse the rtems code.
62 * I am more comfortable with this, sorry.
63 * ----------------------------------------------- */
64shell_topic_t * shell_lookup_topic(char * topic) {
65  shell_topic_t * shell_topic;
66  shell_topic=shell_first_topic;
67  while (shell_topic) {
68   if (!strcmp(shell_topic->topic,topic)) return shell_topic;
69   shell_topic=shell_topic->next;
70  };
71  return (shell_topic_t *) NULL;
72}
73/* ----------------------------------------------- */
74shell_topic_t * shell_add_topic(char * topic) {
75 shell_topic_t * current,*aux;
76 if (!shell_first_topic) {
77  aux=malloc(sizeof(shell_topic_t));   
78  aux->topic=topic;
79  aux->next=(shell_topic_t*)NULL;
80  return shell_first_topic=aux;
81 } else {
82  current=shell_first_topic;
83  if (!strcmp(topic,current->topic)) return current;
84  while (current->next) {
85   if (!strcmp(topic,current->next->topic)) return current->next;
86   current=current->next;
87  };
88  aux=malloc(sizeof(shell_topic_t));   
89  aux->topic=topic;
90  aux->next=(shell_topic_t*)NULL;
91  current->next=aux;
92  return aux;
93 };
94}
95/* ----------------------------------------------- */
96shell_cmd_t * shell_lookup_cmd(char * cmd) {
97  shell_cmd_t * shell_cmd;
98  shell_cmd=shell_first_cmd;
99  while (shell_cmd) {
100   if (!strcmp(shell_cmd->name,cmd)) return shell_cmd;
101   shell_cmd=shell_cmd->next;
102  };
103  return (shell_cmd_t *) NULL;
104}
105/* ----------------------------------------------- */
106shell_cmd_t * shell_add_cmd(char * cmd,
107                      char * topic,
108                      char * usage,
109                      shell_command_t command) {
110  int shell_help(int argc,char * argv[]);
111  shell_cmd_t * shell_cmd,*shell_pvt;
112  if (!shell_first_cmd) {
113   shell_first_cmd=(shell_cmd_t *) malloc(sizeof(shell_cmd_t));
114   shell_first_cmd->name   ="help";
115   shell_first_cmd->topic  ="help";
116   shell_first_cmd->usage  ="help [topic] # list of usage of commands";
117   shell_first_cmd->command=shell_help;
118   shell_first_cmd->alias  =(shell_cmd_t *) NULL;
119   shell_first_cmd->next   =(shell_cmd_t *) NULL;
120   shell_add_topic(shell_first_cmd->topic);
121   register_cmds();
122  };
123  if (!cmd)     return (shell_cmd_t *) NULL;
124  if (!command) return (shell_cmd_t *) NULL;
125  shell_cmd=(shell_cmd_t *) malloc(sizeof(shell_cmd_t));
126  shell_cmd->name   =cmd;
127  shell_cmd->topic  =topic;
128  shell_cmd->usage  =usage;
129  shell_cmd->command=command;
130  shell_cmd->alias  =(shell_cmd_t *) NULL;
131  shell_cmd->next   =(shell_cmd_t *) NULL;
132  shell_add_topic(shell_cmd->topic);
133  shell_pvt=shell_first_cmd;
134  while (shell_pvt->next) shell_pvt=shell_pvt->next;
135  return shell_pvt->next=shell_cmd;
136}
137/* ----------------------------------------------- *
138 * you can make an alias for every command.
139 * ----------------------------------------------- */
140shell_cmd_t * shell_alias_cmd(char * cmd, char * alias) {
141  shell_cmd_t * shell_cmd,* shell_aux;
142  shell_aux=(shell_cmd_t *) NULL;
143  if (alias) {
144   if ((shell_aux=shell_lookup_cmd(alias))!=NULL) {
145    return NULL;
146   };
147   if ((shell_cmd=shell_lookup_cmd(cmd))!=NULL) {
148    shell_aux=shell_add_cmd(alias,shell_cmd->topic,
149                            shell_cmd->usage,shell_cmd->command);
150    if (shell_aux) shell_aux->alias=shell_cmd;
151   };
152  };
153  return shell_aux;
154}
155/* ----------------------------------------------- *
156 * Poor but enough..
157 * TODO: Redirection capture. "" evaluate, ... C&S welcome.
158 * ----------------------------------------------- */
159int shell_make_args(char * cmd,
160                 int  * pargc,
161                 char * argv[]) {
162  int argc=0;
163  while ((cmd=strtok(cmd," \t\r\n"))!=NULL) {
164    argv[argc++]=cmd;
165    cmd=(char*)NULL;
166   };
167  argv[argc]=(char*)NULL;
168  return *pargc=argc;
169}
170/* ----------------------------------------------- *
171 * show the help for one command.
172 * ----------------------------------------------- */
173int shell_help_cmd(shell_cmd_t * shell_cmd) {
174  char * pc;
175  int    col,line;
176  printf("%-10.10s -",shell_cmd->name);
177  col=12;
178  line=1;
179  if (shell_cmd->alias) {
180   printf("is an <alias> for command '%s'",shell_cmd->alias->name);
181  } else
182  if (shell_cmd->usage) {
183   pc=shell_cmd->usage;
184   while (*pc) {
185    switch(*pc) {
186     case '\r':break;
187     case '\n':putchar('\n');
188               col=0;
189               break;
190     default  :putchar(*pc);
191               col++;
192               break;
193    };
194    pc++;           
195    if(col>78) { /* What daring... 78?*/
196     if (*pc) {
197      putchar('\n');
198      col=0;
199     };
200    };
201    if (!col && *pc) {
202      printf("            ");
203      col=12;line++;
204    }; 
205   };
206  };
207  puts("");
208  return line;
209}
210/* ----------------------------------------------- *
211 * show the help. The first command implemented.
212 * Can you see the header of routine? Known?
213 * The same with all the commands....
214 * ----------------------------------------------- */
215int shell_help(int argc,char * argv[]) {
216  int col,line,arg;     
217  shell_topic_t *topic;
218  shell_cmd_t * shell_cmd=shell_first_cmd;
219  if (argc<2) {
220   printf("help: TOPIC? The topics are\n");       
221   topic=shell_first_topic;
222   col=0;
223   while (topic) {
224    if (!col){
225     col=printf("   %s",topic->topic);
226    } else {
227     if ((col+strlen(topic->topic)+2)>78){
228      printf("\n");
229      col=printf("   %s",topic->topic);
230     } else {
231      col+=printf(", %s",topic->topic);
232     };
233    };
234    topic=topic->next;
235   };
236   printf("\n");
237   return 1;
238  };
239  line=0;
240  for (arg=1;arg<argc;arg++) {
241   if (line>16) {
242    printf("Press any key to continue...");getchar();
243    printf("\n");
244    line=0;
245   };
246   topic=shell_lookup_topic(argv[arg]);
247   if (!topic){
248    if ((shell_cmd=shell_lookup_cmd(argv[arg]))==NULL) {
249     printf("help: topic or cmd '%s' not found. Try <help> alone for a list\n",argv[arg]);
250     line++;
251    } else {
252     line+=shell_help_cmd(shell_cmd);
253    }
254    continue;
255   };
256   printf("help: list for the topic '%s'\n",argv[arg]);
257   line++;
258   while (shell_cmd) {
259    if (!strcmp(topic->topic,shell_cmd->topic))
260     line+=shell_help_cmd(shell_cmd);
261    if (line>16) {
262     printf("Press any key to continue...");getchar();
263     printf("\n");
264     line=0;
265    };
266    shell_cmd=shell_cmd->next;
267   };
268  };
269  puts("");
270  return 0;
271}
272/* ----------------------------------------------- *
273 * TODO:Change to bash readline() better.
274 * ----------------------------------------------- */
275int shell_scanline(char * line,int size,FILE * in,FILE * out) {
276  int c,col;
277  col=0;
278  for (;;) {
279   line[col]=0;   
280   c=fgetc(in);
281   switch (c) {
282    case EOF :return 0;
283    case '\r':if (out) fputc('\n',out);
284              return 1;
285    case '\b':if (col) {
286               if (out) {
287                fputc('\b',out);
288                fputc(' ',out);
289                fputc('\b',out);
290               };
291               col--;
292              } else {
293               if (out) fputc('\a',out);
294              };
295              break;
296    default  :if (!iscntrl(c)) {
297                if (col<size-1) {
298                 line[col++]=c;
299                 if (out) fputc(c,out);
300                } else {
301                  if (out) fputc('\a',out);
302                };
303              } else {
304                if (out) fputc('\a',out);
305              };
306              break;
307   };
308  };
309}
310/* ----------------------------------------------- *
311 * - The shell TASK                               
312 * Poor but enough..
313 * TODO: Redirection. Tty Signals. ENVVARs. Shell language.
314 * ----------------------------------------------- */
315shell_env_t global_shell_env ,
316          * current_shell_env=&global_shell_env;
317
318extern char **environ;   
319
320rtems_task shell_shell(rtems_task_argument task_argument) {
321
322  shell_env_t * shell_env =(shell_env_t*) task_argument;
323  shell_cmd_t * shell_cmd;
324
325  rtems_status_code sc;
326
327  struct termios term; 
328  char * devname;
329  char * curdir;
330
331  char cmd[256];
332  char last_cmd[256]; /* to repeat 'r' */
333  int  argc;
334  char * argv[128];
335
336  sc=rtems_libio_set_private_env();
337  if (sc!=RTEMS_SUCCESSFUL) {
338   rtems_error(sc,"rtems_libio_set_private_env():");     
339   printk("rtems_libio_set_private_env():%d",sc);       
340   rtems_task_delete(RTEMS_SELF);
341  };
342
343  sc=rtems_task_variable_add(RTEMS_SELF,(void*)&current_shell_env,free);
344  if (sc!=RTEMS_SUCCESSFUL) {
345   rtems_error(sc,"rtems_task_variable_add():");         
346   printk("rtems_task_variable_add():%d",sc);   
347   rtems_task_delete(RTEMS_SELF);
348  };
349
350  current_shell_env=shell_env; /* Set the task var */
351
352  devname=shell_env->devname;
353
354  stdin =fopen(devname,"r+");
355   
356  if (!stdin) {
357   fprintf(stderr,"shell:unable to open stdin.%s:%s\n",devname,strerror(errno));
358   printk("shell:unable to open stdin.(%s)",strerror(errno));   
359   rtems_task_delete(RTEMS_SELF);
360  };
361  setvbuf(stdin,NULL,_IONBF,0); /* Not buffered*/
362  /* make a raw terminal,Linux MANuals */
363  if (tcgetattr (fileno(stdin), &term)>=0) {
364   term.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
365   term.c_oflag &= ~OPOST;
366   term.c_oflag |= (OPOST|ONLCR);
367   term.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
368   term.c_cflag  = CLOCAL | CREAD |(shell_env->tcflag);
369   term.c_cc[VMIN]  = 1;
370   term.c_cc[VTIME] = 0;
371   if (tcsetattr (fileno(stdin), TCSADRAIN, &term) < 0) {
372     fprintf(stderr,"shell:cannot set terminal attributes(%s)\n",devname);
373   };
374   stdout=fopen(devname,"r+");
375   if (!stdout) {
376    fprintf(stderr,"shell:unable to open stdout.%s:%s\n",devname,strerror(errno));
377   };
378   stderr=fopen(devname,"r+");
379   if (!stderr) {
380    printf("shell:unable to open stderr.%s:%s\n",devname,strerror(errno));
381   };
382   /* when the future user environment runs ok
383    * a freopen() reopens the terminals. Now this don't work
384    * (sorry but you can't use because FILENO_STDIN!=0. Better fileno(stdin))
385    */
386  };
387  shell_add_cmd(NULL,NULL,NULL,NULL); /* init the chain list*/
388  strcpy(cmd,"");
389  printf("\n"
390         "RTEMS-SHELL:%s. "__DATE__". 'help' to list commands.\n",devname);
391  curdir=malloc(1024);
392  chdir("/");
393  for (;;) {
394   /* Prompt section */   
395   /* XXX: show_prompt user adjustable */
396   getcwd(curdir,1024);
397   printf("%s [%s] # ",devname,curdir);
398   /* getcmd section */   
399   if (!shell_scanline(cmd,sizeof(cmd),stdin,stdout)) {
400    printf("shell:unable scanline(%s)\n",devname);     
401    break;
402   };
403   /* evaluate cmd section */     
404   if (!strcmp(cmd,"r")) {  /* repeat last command, forced, not automatic */
405    strcpy(cmd,last_cmd);
406   } else
407   if (strcmp(cmd,"")) { /* only for get a new prompt */
408    strcpy(last_cmd,cmd);
409   };
410   /* exec cmd section */         
411   /* TODO:
412    *  To avoid user crash catch the signals.
413    *  Open a new stdio files with posibility of redirection *
414    *  Run in a new shell task background. (unix &)
415    *  Resuming. A little bash.
416    */   
417   if (shell_make_args(cmd,&argc,argv)) {
418    if ((shell_cmd=shell_lookup_cmd(argv[0]))!=NULL) {
419     current_shell_env->errorlevel=shell_cmd->command(argc,argv);
420    } else {
421     printf("shell:%s command not found\n",argv[0]);
422     current_shell_env->errorlevel=-1;
423    };
424   };
425   /* end exec cmd section */     
426  };
427  free(curdir);
428  rtems_task_delete(RTEMS_SELF);
429}
430/* ----------------------------------------------- */
431rtems_status_code   shell_init (char * task_name,
432                                rtems_unsigned32    task_stacksize,
433                                rtems_task_priority task_priority,
434                                char * devname,
435                                tcflag_t tcflag) {
436 rtems_id task_id;
437 rtems_status_code sc;
438 shell_env_t * shell_env;
439 sc=rtems_task_create(new_rtems_name(task_name),
440                     task_priority,
441                     task_stacksize?task_stacksize:RTEMS_MINIMUM_STACK_SIZE,
442                     (RTEMS_DEFAULT_MODES&~RTEMS_ASR_MASK)|RTEMS_ASR,
443                     RTEMS_DEFAULT_ATTRIBUTES,
444                     &task_id);
445 if (sc!=RTEMS_SUCCESSFUL) {
446  rtems_error(sc,"creating task %s in shell_init()",task_name); 
447  return sc;
448 };
449 shell_env=malloc(sizeof(shell_env_t));
450 if (!shell_env) {
451  rtems_task_delete(task_id);
452  sc=RTEMS_NO_MEMORY;   
453  rtems_error(sc,"allocating shell_env %s in shell_init()",task_name);   
454  return sc;
455 };
456 if (global_shell_env.magic!=new_rtems_name("SENV")) {
457  global_shell_env.magic   =new_rtems_name("SENV");
458  global_shell_env.devname ="/dev/console";
459  global_shell_env.taskname="GLOBAL";
460  global_shell_env.tcflag   =0;
461 };
462 shell_env->magic   =global_shell_env.magic;
463 shell_env->devname =devname;
464 shell_env->taskname=task_name;
465 shell_env->tcflag  =tcflag;
466 return rtems_task_start(task_id,shell_shell,(rtems_task_argument) shell_env);
467}
468/* ----------------------------------------------- */
469
Note: See TracBrowser for help on using the repository browser.