MYSH- Josh Wilmes When I initially started this project, I made the decision to be as modular as possible. I wanted to come up with some genuinely useful functions that I could use for future projects. With that in mind, I came up with the following modules which would make up my shell: main module: Main I/O loop. Get input, pass to parser, call resulting functions. (see shell.C) Command Parsing: I chose to keep the command parsing to a bare minimum. Since the shell commands are all so simple, this was easy to do. In a prior project, I had done a command parser built around a flex engine, and it proved to be much more trouble than it was worth. Keeping it simple really paid off on this project. This module was the easiest to implement, and the least troublesome. (see parse.C) Process Management: This module encompases the ps table management and kill functions. One unusual decision I made here was to use a linked list structure rather than a vector. This was simpler to implement dynamic allocation in, and the likely size was small, so the O(n) search time was not a major factor. It also handles user notification of the termination of backgrounded processes. I implemented this with a sweep through the process table with waitpid/WNOHANG, rather than using SIGCLD to notify the shell of child exits, because the SIGCLD method seemed to carry a nontrivial amount of lag and unreliability. Once again, since total numbers of backgrounded jobs are unlikely to exceed 10 or so in daily use, this polling technique is an acceptable tradeoff. (see ps.C) Process Invocation: This module also includes a large amount of string parsing functions that are not related directly to command parsing. The idea was to build a module that you could ask to run a command (passed as a string rather than some sort of argv vector), and it would do it, including backgrounding, redirection, and piping. I was able to accomplish this all, with only one limitation. Due to time constraints, I was forced to implement the pipe file descriptor structure as a fixed-size array. I set it fairly large, so this is unlikely to matter. It can be fixed fairly easily when time allows. (see run.C) All of the modules share a common header file, shell.h. It contains configurable options and extern declarations. This program was developed on my Linux machine, and later migrated to the RCS system, on the AIX platform. I have not attempted to build it on the suns, but it is likely to have some trouble with some of the SYSVish calls that I may have inadvertantly used. It uses the GNU ReadLine library, which provides line editing, commandline history, and emacs-like keys. GNU Readline is available from ftp://prep.ai.mit.edu/pub/GNU/readline*. I also used a simple string trimming function from the RPI SandBox library (/campus/rpi/ sandbox/1.2...) To track revisions, I chose to use the RCS Revision Control System, since it was available on all platforms I was using for development. This was my first experience with it, but I was very happy that I had used it. It maintains backups and revision histories, so it was easy to back out accidental changes. I chose to use the g++ compiler, even though my code is mostly plain C, because it allowed me to use c++ comments , memory allocation, and inline variable declarations. This was just a matter of convenience. The shell is written using C code almost exclusively. One problem I did have was that the IBM's do not seem to include the proper header file for setpgrp(). It gives a warning about implicit declaration, but links fine. I chose to let the warning go rather than kludging some sort of function prototype for it. To the best of my knowledge, the shell is without major bugs or problems. It seemed to survive my testing well. --Josh Wilmes