All pastes #885860 Raw Edit

Something

public text v1 · immutable
#885860 ·published 2008-01-31 05:17 UTC
rendered paste body
// CSE421 - Project 1 Part 1c

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <string.h>

#define ASCII_TAB 0x09
#define ASCII_SPACE 0x20

//FUNCTION PROTOTYPES:

// Function to parse user input:
int parseInput(char* myString, char* &file, char** args, int maxArgs);


///////////////////////////////////////////////////////////////////////
int main()
{
        int pid1;                       // PID of spawned child
        int i;                          // temporary int
        char inputBuffer[256]="\x00";   // buffer for user input
        char* file;                     // pointer to a file name or path
        char* args[64];                 // pointer to an arguments array

        while(true)
        {
                // Show prompt, get user input:
                fputs("shell> ",stdout);
                if(fgets(inputBuffer, 255, stdin) == NULL)
                        break;

                // Strip the trailing newline character from the end of string:
                inputBuffer[strlen(inputBuffer) - 1] = 0x00;

                // Parse the user input, this will modifly the inputBuffer string as well as the file and args[] pointers
                if(parseInput(inputBuffer, file, args,64) < 0)
                {
                        fprintf(stderr,"Unable to parse command!  Try again...\n");
                        continue;
                }

                //  If user entered "exit" then break out of loop and exit.
                if(strcmp(file,"exit")==0)
                        break;

                // Spawn a child to attempt to run the command:
                pid1=fork();
                if(pid1 < 0)
                {
                        perror("fork");
                        return -1;
                }

                if(pid1 != 0)   //PARENT
                {
                        waitpid(pid1,NULL,0);
                }
                else            //CHILD
                {
                        // The file and args pointers should have been set by parseInput (they point into the modifed
                        // user input string), so they can be fed directly into execvp:
                        i=execvp(file, args);
                        if(i < 0)
                        {
                                perror("execvp");
                                return -1;
                        }
                        exit(0);
                }
        }

        return 0; //redundant & unneccessary?
}

//////////////////////////////////////////////////////////////////////////////
//  parseInput function:
//
//  PARAMETERS:
//      myString - pointer to an existing input string (this string WILL get modified)
//      file -  address of an existing pointer.  the pointer will be set to point to the first argument in myString,
//              presumably a filename or path.
//      args -  address of an existing array of pointers.  These pointers will be set to point to each individual
//              argument in the input string.
//      maxArgs - The number of pointers in the existing array of pointers passed into this function.  Represents the
//              maximum number of arguments that can be parsed.
//
//  DESCRIPTION:
//  Takes a null terminated string pointed to by myString, and modifies this string.  First it removes any leading and trailing
//  spaces/tabs from the string, then replaces any consecutive spaces and/or tabs with a single space.  Then changes each
//  single space to a null byte, effectively breaking the string into several smaller strings which represent the
//  individual arguments of the original string.  It then sets the file and args[] pointers to point to different locations inside
//  the myString buffer in the following manner:
//
//      file - will be set to point to the first argument
//      args[0] - will point to the same string as file, but if file contains a '/' symbol, args[0] will point to the first
//              character after the LAST '/' symbol.  For example, if file == "/bin/ls",
//              then args[0] will be just "ls"
//      args[1]-args[?] - these point to each subsequent argument in the buffer
//
//      RETURNS 0 for success, and <0 for failure
///////////////////////////////////////////////////////////////////////////////
// EXAMPLE:
//              myString="    /bin/ls    -l    -a   /home   "
//  The myString string would be changed to this (where # is a NULL byte):
//              myString="/bin/ls#-l#-a#/home#"
//                        ^    ^  ^  ^  ^
//
//  The ^ symbols above represent the pointed to locations of file, args[0], args[1], args[2], and args[3] respectively.
//  And args[4] would be set to NULL.
//
///////////////////////////////////////////////////////////////////////////////
int parseInput(char* myString, char* &file, char** args, int maxArgs)
{
        int i=0;                // temp int
        int j=0;                //.temp int
        int curArg=0;           // current argument # being processed
        file=NULL;              // set the file pointer to be NULL (for good measure).

        if(maxArgs<2)           // args will need at least need 2 pointers, one for the command, the 2nd for the null term.
                return -1;

        args[0]=NULL;   // set the first args[] pointer to be NULL, for good measure

        // Remove any TRAILING spaces or tabs from myString:
        i=strlen(myString);
        while(i>0  &&  (myString[i-1]==ASCII_SPACE || myString[i-1]==ASCII_TAB))
        {
                myString[i-1]=0;
                i--;
        }

        // Remove any LEADING spaces or tabs from myString:
        while(myString[0] == ASCII_SPACE || myString[0] == ASCII_TAB)
                myString++;     // increase the pointer by 1 byte, so as to "lose" the 1st char of the string.

        // if after removeing leading/trailing spaces the buffer is empty, then theres nothing to do:
        if(strlen(myString) == 0)
                return -1;

        //
        // i is the "read index", j is the "write index"
        // the string is read, processed, and written back into the same location:
        // It reads through myString 1 char at a time.  If a series of spaces/tabs is encountered, they're replaced with
        // a SINGLE SPACE.
        i=j=0;
        while(myString[i] != 0)
        {
                if(myString[i] == ASCII_SPACE || myString[i] == ASCII_TAB) // if the char currently being READ is a space,
                {
                        if(myString[j-1] == ASCII_SPACE)                // check to see if the last char WRITTEN was also a space,
                        {
                                i++;                    // if so, then continue reading the next char
                                continue;
                        }
                        else                            // otherwise, write a single space:
                        {
                                myString[j++]=ASCII_SPACE;
                                i++;
                                continue;
                        }
                }
                myString[j++]=myString[i++];                    // if the char being read is not a space, then just
                                                        // write it.
        }
        myString[j]=0;                                  // add the null termination to the new myString string


        // position i so that myString[i-1] is the LAST CHAR of the first argument
        i=0;
        while(myString[i] != 0 && myString[i] != ASCII_SPACE)
                i++;

        // position i so that IF the first argument is a path name such as "/bin/ls" then myString[i] points to just "ls".
        while(i>0)
        {
                if(myString[i-1] == '/')
                {
                        break;
                }
                i--;
        }
        args[curArg++] = &(myString[i]);  //set args[0] to point to just the file name, ie "ls" not "/bin/ls'

        // position i again so that myString[i] is the char AFTER the first argument (which will be either a space or a null byte.)
        while(myString[i]!=0 && myString[i] != ASCII_SPACE)
                i++;

        // Change each space in myString to a null byte and set the args[] pointers so that they point to each individual
        // argument string.
        while(myString[i]!=0 && curArg < (maxArgs-1))
        {
                if(myString[i]== ASCII_SPACE)   // a space can only come BETWEEN 2 arguments, so if one is encountered,
                                                // the NEXT char must be the first char of a new argument:
                {
                        args[curArg++]=&(myString[i+1]);        // set the next args[] pointer
                        myString[i]=0;                  // null terminate the previous arg string
                }
                i++;
        }

        args[curArg]=NULL;  // NULL-terminate the args[] array.

        // set the file name pointer to first argument which should be the entire file name & maybe path, ie "/bin/ls"
        file=myString;

        return 0;
}