/* Shell.c, Copyright (c) by George Fankhauser, Swiss Federal Institute of Technology, Computer Engineering and Networks Laboratory. TOPSY -- A Teachable Operating System. Implementation of a tiny and simple micro kernel for teaching purposes. For further information, please visit http://www.tik.ee.ethz.ch/~topsy This software is provided under the terms of the GNU General Public Licence. A full copy of the GNU GPL is provided in the file COPYING found in the development root of Topsy. */ /* File: $Source: /usr/drwho/vault/cvs/topsy/Topsy/User/Shell.c,v $ Author(s): George Fankhauser Affiliation: ETH Zuerich, TIK Version: $Revision: 1.36 $ Creation Date: Last Date of Change: $Date: 1999/12/13 21:48:42 $ by: $Author: ruf $ $Log: Shell.c,v $ Revision 1.36 1999/12/13 21:48:42 ruf GNU General Public Licence Update Revision 1.35 1999/06/06 20:55:29 jeker putting everything together for Topsy 2.0 Revision 1.34 1999/04/08 11:40:21 jeker added some new files, modified some others for unix port Revision 1.33 1999/02/02 23:04:03 cjeker latest fixes Revision 1.32 1998/04/09 12:16:06 fiedler *** empty log message *** Revision 1.31 1998/04/08 15:45:47 fiedler *** empty log message *** Revision 1.30 1998/04/08 12:02:13 fiedler *** empty log message *** Revision 1.29 1998/04/08 08:50:42 gfa added trap Revision 1.28 1998/04/08 08:27:25 fiedler *** empty log message *** Revision 1.27 1998/04/07 17:03:56 fiedler ? Revision 1.26 1998/04/07 15:59:06 fiedler *** empty log message *** Revision 1.24 1998/04/03 15:33:41 fiedler kill, & , problems with getargument! Revision 1.23 1997/05/16 14:30:46 stauffer test programme fuer fpga * Revision 1.22 1997/05/07 16:23:42 stauffer * *** empty log message *** * * Revision 1.21 1997/04/25 06:44:23 brunner * *** empty log message *** * * Revision 1.20 1997/04/25 06:41:51 brunner * *** empty log message *** * * Revision 1.19 1997/04/24 16:50:27 brunner * *** empty log message *** * * Revision 1.18 1997/04/24 13:01:35 brunner * *** empty log message *** * * Revision 1.17 1997/04/21 14:15:17 brunner * join branch * * Revision 1.14.1.6 1997/04/21 14:14:24 brunner * *** empty log message *** * * Revision 1.14.1.5 1997/04/21 10:32:37 brunner * *** empty log message *** * * Revision 1.14.1.4 1997/04/21 07:30:54 conrad * cleanup * * Revision 1.14.1.3 1997/04/18 16:32:28 conrad * *** empty log message *** * * Revision 1.14.1.2 1997/04/18 16:29:09 conrad * *** empty log message *** * * Revision 1.14.1.1 1997/04/18 09:10:03 conrad * in getArgument(), CR was not properly considered (only LF...) * * Revision 1.14 1997/04/17 10:58:00 conrad * *** empty log message *** * * Revision 1.13 1997/04/14 21:09:46 conrad * *** empty log message *** * * Revision 1.12 1997/04/12 10:14:14 gfa * fixed readLine() * * Revision 1.11 1997/04/08 14:12:23 brunner * added SeatReservation * * Revision 1.10 1997/04/08 14:10:58 conrad * stringCompare moved to userSupport.c * * Revision 1.9 1997/04/08 13:03:43 conrad * change of tmStart() syscall * * Revision 1.8 1997/04/08 12:11:19 conrad * parsing of arguments via Shell * * Revision 1.7 1997/04/04 20:04:20 gfa * introduced the NULL command (an empty newline pressed at the console) * * Revision 1.6 1997/04/02 14:49:06 brunner * added StartSyncThreads * * Revision 1.5 1997/04/02 10:26:52 brunner * added the hello world and the countthraed programm * print out invalid command on invalid input * * Revision 1.4 1997/03/31 20:29:40 gfa * testing, added memtest * * Revision 1.3 1997/03/28 12:10:45 conrad * updated thread manager syscalls * * Revision 1.2 1997/03/27 13:56:57 conrad * demo version (no read) * * Revision 1.1 1997/03/26 16:11:37 conrad * Initial revision * * Revision 1.3 1997/03/23 12:46:24 gfa * *** empty log message *** * * Revision 1.2 97/03/23 10:43:24 gfa * first hack (demo bp) * * Revision 1.1 97/03/21 21:34:32 gfa * Initial revision * */ #include "Shell.h" #include "UserSupport.h" #include "SeatReservation.h" #include "PacketDriverTest.h" #include "PacketStackControl.h" #include "Demo.h" #include "HelloWorld.h" #include "ThreadsDemo.h" #include "testtimer.h" #include "CrashMe.h" #define NUSERCOMMANDS 10 /* please set according to contents of userCommands (see below) */ #define MAXNBOFARGUMENTS 10 #define MAXCOMMANDSIZE 80 #define BLANK ' ' /* blank character, delimitor between arguments */ static char* argArray[MAXNBOFARGUMENTS+1]; static char cmdLine[MAXCOMMANDSIZE+1]; /* please set NUSERCOMMANDS to the right size -> see some lines above */ ShellFunction userCommands[NUSERCOMMANDS] = { {"shell", main, (ThreadArg)0}, {"trap", trap, (ThreadArg)0}, {"reserve", Start_Reservation, (ThreadArg)0 }, {"ptest", PacketDriverTest, (ThreadArg)0 }, {"test3", PacketStackControl, (ThreadArg)0 }, {"testback1", Testback1, (ThreadArg)" 1 2 3" }, {"hello", Hello, (ThreadArg)argArray}, {"demo", Demo, (ThreadArg)argArray}, {"timertest", test_timer, (ThreadArg)0 }, {"crashme", crashMeMaster, (ThreadArg)"1 2 3" } }; /* one output console per shell, even if cascaded */ static ThreadId tty; /* the userCommands array has moved to $(ARCH)/ShellArch.h */ extern ShellFunction userCommands[]; void __main() {} #define CR 13 #define LF 10 #define BS 8 #define ESC 27 char bs[4]={BS,' ',BS,'\0'}; char beep='\a', *newl="\n\r"; /* used as const */ static void readChar(ThreadId driver, char *c) { unsigned long int one = 1; do { one = 1; ioRead(driver, c, &one); } while (one != 1); } /* includes backspace and echo */ static void readLine(ThreadId driver, char* buf, char* oldbuf,int max) { unsigned char c = '\0'; int i = 0; unsigned long int one = 1; do { readChar(driver, &c); one = 1; if (c==BS) { if (i>0) { i--; display(driver, bs); } else { ioWrite(driver, &beep, &one); } } else if (c==ESC) { readChar(driver, &c); if (c=='[') { readChar(driver, &c); if (c=='A') { /* up arrow */ for (; i>0; i--) display(driver, bs); stringCopy(buf, oldbuf); i = stringLength(buf); display(driver, buf); } else { c='\0'; } } else { c='\0'; } } else if (c==CR || c==LF || (c>=32 && c<128) || (c>=160 && c<255)) { /* allowed char */ if (i < max) { buf[i++] = c; ioWrite(driver, &c, &one); } else { ioWrite(driver, &beep, &one); } } else { ioWrite(driver, &beep, &one); } } while (!((c == CR) || (c == LF)) && (i < max)); one = 1; display(driver, newl); if (i>0) i--; buf[i] = '\0'; /* replace the CR or LF by '\0' */ } static int getCommand(char* line) { if (stringNCompare(line, commandNames[SHELL_START],5) == EQUAL) return SHELL_START; if (stringNCompare(line, commandNames[SHELL_EXIT],4) == EQUAL) return SHELL_EXIT; if (stringNCompare(line, commandNames[SHELL_KILL],4) == EQUAL) return SHELL_KILL; if (stringNCompare(line, commandNames[SHELL_INFO],4) == EQUAL) return SHELL_INFO; if (stringNCompare(line, commandNames[SHELL_HELP],4) == EQUAL) return SHELL_HELP; if (stringNCompare(line, commandNames[SHELL_PS],2) == EQUAL) return SHELL_PS; if (stringNCompare(line, commandNames[SHELL_NULL],1) == EQUAL) return SHELL_NULL; return SHELL_INVALID; } /* FIE 9.4.98 this belongs to UserSupport.c (-> strtok in libc) */ static char* getArgument( int* lineIndex, char* line) { char* ret; /* start of argument */ /* looking for first character non BLANK, non '\0', and non '\n' */ while ( line[*lineIndex] == BLANK && line[*lineIndex] != '\0' && line[*lineIndex] != CR && line[*lineIndex] != '\n') { (*lineIndex)++; } if (line[*lineIndex] == '\0' || line[*lineIndex] == '\n' || line[*lineIndex] == CR) return NULL; ret = &(line[*lineIndex]); /* Positionning lineIndex onto next BLANK or '\0' or '\n' */ while ( line[*lineIndex] != BLANK && line[*lineIndex] != '\0' && line[*lineIndex] != CR && line[*lineIndex] != '\n' ) { (*lineIndex)++; } if (line[*lineIndex] != '\0') { line[*lineIndex] = '\0'; (*lineIndex)++; } return ret; } static void listThreads(){ ThreadInfo threadInfo ; char idString[12] ; char* statusString[] = {"running ", "ready ", "blocked "} ; char outputline[MAXCOMMANDSIZE]; int len; if (tmGetFirst(&threadInfo) != TM_INFOOK) { display(tty,"ps: Error - Cannot get first threadInfo!\n") ; return; } else { do { initmem((Address)outputline,40,BLANK); itoa((int)threadInfo.tid,idString); len=stringLength(idString); /* right bound */ byteCopy((Address)&outputline[6-len],(Address)idString,len); len=stringLength(statusString[threadInfo.status]); byteCopy((Address)&outputline[10],statusString[threadInfo.status],len); len=stringLength(threadInfo.name); byteCopy((Address)&outputline[20],threadInfo.name,len); outputline[20+len+1]='\n'; outputline[20+len+2]='\0'; display(tty,outputline); } while (tmGetNext(&threadInfo) != TM_INFOFAILED); } } static void kill_line(char* line) { int i; ThreadId threadId; int lineIndex = 4; /* sizeof string "kill" */ int argIndex = 0; while ((argArray[argIndex]=getArgument(&lineIndex, line)) != NULL && argIndex < MAXNBOFARGUMENTS) { argIndex++; } if (argIndex != 1) { display(tty,"Kill: Wrong number of arguments on the command line!\n"); return; } atoi(&i, argArray[0]); threadId=(ThreadId)i; if (TM_KILLOK != tmKill(threadId)) { display(tty,"Kill: This thread could not be killed!\n"); return; } } /* Setup Thread to memorize the threads parameters */ static void setupThread(ThreadArg arg) { char localLine[MAXCOMMANDSIZE+1]; /* memorized cmdLine */ char* localArgArray[MAXNBOFARGUMENTS+1]; /* reparsed args */ int argIndex = 0; int lineIndex = 5; /* sizeof string "start" */ Message msg; ThreadId shell, setup, child; int len=0; /* to reassemble cmdLine */ int arglen; int i; char* argument; tmGetInfo(SELF, &setup, &shell); /* copy args on cmdLine and setup localArgArray */ for (i=0; ifunction, localArgArray, (*((ShellFunction*)arg)).name)) { display(tty,"Setup: Background thread could not be started\n"); return; } tmMsgSend(shell, &msg); /* wakeup shell */ tmMsgRecv(&child, ANYMSGTYPE, &msg, INFINITY); } static void start(char* line) { int i; ThreadId child,setup; Message reply; int lineIndex = 5; /* sizeof string "start" */ int argIndex = 0; Boolean backgr = FALSE; Boolean cmdFound = FALSE; char* argument; stringNCopy(cmdLine,line,MAXCOMMANDSIZE); for(i=0; cmdLine[i] != '\0'; i++) { if (cmdLine[i] == BACKGRCOMMAND) { backgr = TRUE; cmdLine[i] = '\0'; break; } } /* Setting all arguments (thread name included) in a global null-terminated static array argArray */ while ((argArray[argIndex]=getArgument(&lineIndex, cmdLine)) != NULL && argIndex < MAXNBOFARGUMENTS) { argIndex++; } if (argIndex == MAXNBOFARGUMENTS) { display(tty,"Start: Too many arguments on the command line, last ignored !\n"); } for (i = 0; i < NUSERCOMMANDS; i++) { if (stringCompare(userCommands[i].name, argArray[0]) == EQUAL) { cmdFound=TRUE; if (!backgr) { if (tmStart( &child, userCommands[i].function, argArray, userCommands[i].name) != TM_STARTOK) { display(tty,"Start: Shell command could not be started\n"); return; } /* wait for child */ if (!backgr) tmMsgRecv(&child, ANYMSGTYPE, &reply, INFINITY); } else { /* use Setup Thread to start background thread */ if (tmStart(&setup, setupThread, (ThreadArg)(&userCommands[i]), "setupThread") != TM_STARTOK) { display(tty, "Start: Shell couldn't start background setup thread\n"); return; } /* Wait for setup child (until cmdLine is copied) */ tmMsgRecv(&setup, ANYMSGTYPE, &reply, INFINITY); } break; } } if (!cmdFound) { display(tty, "Start: Shell command not found!\n"); } } void main(ThreadArg arg) { char line[MAXCOMMANDSIZE+1]; char oldline[MAXCOMMANDSIZE+1]; int i; ioOpen(IO_CONSOLE, &tty); ioInit(tty); display(tty, WELCOME); oldline[0]='\0'; while (TRUE) { display(tty, PROMPT); /* write the $, > or whatever */ readLine(tty, line, oldline, sizeof(line)); /* read next command */ if (line[0] != '\0') stringCopy(oldline, line); switch (getCommand(line)) { case SHELL_START: start(line); break; case SHELL_EXIT: display(tty, EXITMESSAGE); ioClose(tty); tmExit(); break; case SHELL_KILL: kill_line(line); break; case SHELL_INFO: case SHELL_HELP: display(tty, HELP); /* help text */ display(tty,"\nUser-Commands:"); /* Display the user-Commands */ for (i=0;i