CSCI 352 - UNIX Software Development
Fall 2009 - Assignment 2
125 points
Due: Friday, October 9, 2009
Start with the code you turned in for assignment 1. You should
have a single file ``msh.c'' which has three primary functions,
arg_parse(), processline() and main().
This assignment's work consists of the following steps:
- In a new work directory, start with a copy of your msh.c file.
Do not work in your cs352/f09a1 turn in directory. This
could make you lose points on Assignment 1.
- Create a new file called ``arg_parse.c''.
Move all code for the function arg_parse() to this new file.
Any helper functions should be moved and declared ``static''.
Also, create a new file called ``proto.h'' that contains the proper prototype
of arg_parse() so both your main program and arg_parse.c can #include
the file to get the proper prototype definition. (Note: msh.c should
#include ``proto.h'', not ``arg_parse.c''. Also, proto.h should NOT #include ``arg_parse.c''. Both ``msh.c'' and ``arg_parse.c''
need to #include ``proto.h''.) Note: you can still compile both files on
one command line by giving the command:
gcc -g -o msh -Wall msh.c arg_parse.c
- Change arg_parse() to have the prototype ``int arg_parse(char
*line, char ***argvp)'' where arg_parse() returns the number of
parameters in the argv. argvp is a pointer to the variable where the
pointer to the malloced structure (the argv you are building in
arg_parse) must be stored. You should not have to change very much in
the implementation of arg_parse() unless you are fixing errors from
Assignment 1. Also, you should not change any variable declarations
in processline(). The prototype change does not change what the
function does. In most cases, this prototype change requires changing
at most 3 lines of code. It just changes how processline() calls
arg_parse() and how arg_parse() returns the resulting pointer. This
is the C equivalent to passing reference parameters ... except C
doesn't have reference parameters and so must pass a pointer to a
variable in the calling function. You should not have any variables in
your program declared of type ``char ***''. The only place for the
type ``char ***'' is in the parameter list for arg_parse(). If you
have ``char ***'' in any other place except the argument list (and
prototype) you will lose points.
- Make sure your argv is correctly built with only one malloc. It
must have the correct size. Also, make sure that arg_parse() is
called by the parent shell before your fork(2) and you properly free
the argument array in the parent.
- Do the above work (change of prototype and splitting out the
file ``arg_parse.c'') BEFORE doing anything else for this
assignment. The commands for separate compilation are available
in several places including at the end of this assignment.
- Change arg_parse() to also look for quotes. (Do this AFTER you
have a working arg_parse() with the new prototype.) If a quote is given,
look for a matching quote and everything between the two quotes is considered
to be consecutive characters in the same argument. For example:
prog "this is a single arg"
has 2 arguments and
prog this" "is" "a" "single" "arg
also has exactly 2 arguments. And again,
prog thi"s is a s"ingl"e a"rg
has exactly 2 arguments and is identical in result to the above 2.
Also, you can have a program name with spaces like:
"prog name with spaces"
Note: a quote may appear in the middle of an argument as you can see
by the second example above. Also, the actual quote character is
removed from the final version of the argument. If you find an odd
number of quotes in the line, print an error message to ``standard
error'' and stop processing the current line.
- Change processline() so that if arg_parse() finds zero arguments,
for example, a blank line, processline() just ignores that line. (Does
nothing!)
- Start a new file for built-in commands, ``builtin.c''.
- Build a framework for executing built-in commands. These commands
are done directly by the shell and are not forked to another process to
do. Your processline() function should call arg_parse() and then call
a routine to check to see if the command is a built-in command. (This
function may execute the built-in if it is a built-in before returning to
processline(). You may also have two functions, one to check if the command
is a built-in and one to execute it.)
After processline() determines it is not a built-in command, that is the
time to call fork(). Remember, your parent process must free the argument
list after it is done using it.
Note: in later assignments you will be required
to add more built-in commands. A good ``framework'' will provide a
very easy way to add new built-in commands. While a series of
``if (strcmp(...,...)...) ... else if (strcmp(...,...)...) ...'' will work,
try to think of a way to to use strcmp only once (in a loop) to determine
which built-in command needs to be executed. (Function pointers are really
nice to use here.)
- All the identification and execution of built-in commands must be
implemented in code in your builtin.c file. You should have at most
two functions that processline() calls directly to implement your built-in
commands. If you have two functions,
one should answer the question ``is the command described by this argv a
built-in function'' and the other one should do the built-in command.
A single function would combine the functionality of the two into a single
function.
Add the prototype for your built-in commands function(s) to your ``proto.h''.
Note: if you are calling strcmp() in processline, you are not implementing
this as requested and will lose points. Also, if you put definitions
in msh.c to help you with built-in commands, you are also not doing as
requested. All code implementing built-in commands must be in
builtin.c or builtin.h. This includes global variables (should be static).
- Implement exactly the following two built-in commands. (The brackets
([...]) in the descriptions do not appear in the real command, they just show
that that part is optional.)
- exit [value] - exit the shell with the value. If value is not
given, exit with value 0. This built-in command should call the
exit(3) library call. Hint: man 3 atoi
- aecho [-n] [arguments] - echo the command arguments with a single
space between arguments. After all the arguments are echoed, a newline
should be printed. If the -n flag is given, the newline should not be
printed. The word ``aecho'' and the ``-n'' flag should not be printed.
``aecho'' with no arguments just prints a newline. Hint: Plan for later
modifications. In this assignment, you are to print the output to
standard out (file descriptor 1). In a later assignment, you may need
to send it out to a different file descriptor. Creating a string
using snprintf(3) and writing that string using write(2) may be more
difficult now, but may later save some problems on future assignments.
It may also save you problems in this assignment.
Some final notes:
- None of your source files should #include a .c file and no
executable code may appear in your .h file. You can compile all
three files on one command like:
gcc -g -Wall -o msh msh.c arg_parse.c builtin.c
You can also compile using several commands like:
gcc -g -c -Wall msh.c
gcc -g -c -Wall arg_parse.c
gcc -g -c -Wall builtin.c
gcc -g -o msh minishell.o arg_parse.o builtin.o
- Again, make your source code available to me online like you did
for assignment 1. Put all your source files in the directory
``cs352/f09a2'' relative to your home directory. Make sure the permissions
are correctly set or you will lose points. I will grade your
assignment by getting your sources and compiling them. Also, you must
turn in your sources on paper and turn in a sample run where
you tested your shell. The test must not be running my grading
script on your shell. You will get graded on the quality of
the tests you turn in.
- My reference executable is available for you to run. On the
LDC, you may run the program /home/phil/.bin/msh. If you have a question like
``What should the shell do if I type .....'', ask my shell instead
of asking me. Of course, if you don't understand what it does, ask
me.
- Finally, I will making my test script available sometime on or before
Wednesday, October 7 in the directory
/home/phil/public/cs352/testa2 on the LDC. To use use the script, cd
to the /home/phil/public/cs352/testa2 directory and give the command
./try when there. It will create a directory /home/username/testa2
where it will test your work. (username is your user name.)
It is possible that not all tests done by
my real grading script are done by the public one. The public one does most
of them. If your program passes all my tests, the script says
Script output same
Exit values correct
This document was generated using the
LaTeX2HTML translator Version 2002-2-1 (1.70)
Copyright © 1993, 1994, 1995, 1996,
Nikos Drakos,
Computer Based Learning Unit, University of Leeds.
Copyright © 1997, 1998, 1999,
Ross Moore,
Mathematics Department, Macquarie University, Sydney.
The command line arguments were:
latex2html -split 0 -nonavigation assgn2
The translation was initiated by Phil Nelson on 2009-10-02
Phil Nelson
2009-10-02