In order to understand the operation of the tiny shell, the first things to look at are the data structures involved. To simplify the internals of the tiny shell, its data structures are all statically allocated at compile time. This means, for example, using arrays to store things rather than dynamically allocated linked lists. The consequence of this is that the tiny shell imposes fixed limits on the sizes of certain things, where a real shell need impose no such limits. In particular, the following things are fixed, in that you need to re-compile the tiny shell to change them. the maximum length of line entered at the shell prompt, the maximum length of a file name used for I/O redirection, the maximum number of command line parameters for each simple command and the maximum number of simple commands in a pipeline.
All these definitions and the declarations of the global variables and data structures appear in the file <def.h>, as follows:
#include <stdio.h> #include <limits.h> #include <signal.h> #include <fcntl.h> #define TRUE 1 #define FALSE 0 #define OKAY 1 #define ERROR 0 #define MAXLINE 200 /* Maximum length of input line */ #define MAXARG 20 /* Max number of args for each simple command */ #define PIPELINE 5 /* Max number of simple commands in a pipeline */ #define MAXNAME 100 /* Maximum length of i/o redirection filename */ char line[MAXLINE+1]; /* User typed input line */ char *lineptr; /* Pointer to current position in line[] */ char avline[MAXLINE+1]; /* Argv strings taken from line[] */ char *avptr; /* Pointer to current position in avline[] */ char infile[MAXNAME+1]; /* Input redirection filename */ char outfile[MAXNAME+1]; /* Ouput redirection filename */ int backgnd; /* TRUE if & ends pipeline else FALSE */ int lastpid; /* PID of last simple command in pipeline */ int append; /* TRUE for append redirection (») else FALSE */ struct cmd { char *av[MAXARG]; int infd; int outfd; } cmdlin[PIPELINE]; /* Argvs and fds, one per simple command */
When you type a command line to the tiny shell in response to its prompt, the characters you enter are stored directly into the line[] array. Suppose you enter the command:
tsh: echo hello world
you already know that in order to execute this command the tiny shell needs to fork() a child process and then exec() the echo command in the child. As the echo command takes parameters it is necessary to extract them from the command line (in the line[] array) and parcel them up into an argv type data structure to pass into exec() (the execvp() system call in this case).
In the tiny shell, the separate words on the command line are extracted and stored as a set of separate strings in the avline[] array. Then for each simple command in the command line an array of pointers is set up to point to the appropriate individual command line words for that command. The array of pointers is contained in the struct cmd structure, one of which is available for each simple command in the pipeline. This set of structures is itself stored as an array called cmdlin[]. Figure 1. is intended to illustrate this idea by showing the contents of the line[], avline[] and cmdlin[] arrays when the entered command pipeline is:
tsh: ls wc -w