1 Attachment(s)
URGENT: Initializing the size of a char*[]
I am writing a program that acts as a simple shell. Basically, my program outputs a prompt, then waits for the user to input a command. My program then handles that command and ouputs a new prompt. This process continues until the user quits. The specifics of the program are not relevant though. The only question I have is with the variable char *arg[] inside of my Info struct. I am not sure how to initialize it's size. I tried just saying char *arg[20], but that ended up giving it a size of 0 for some reason.
Can anyone correct this problem in my code for me?
Can anyone tell me how to initialize the size of a char*[]?
I have the entire program below, or you can download the attachment of it.
Thank You!
Code:
/*************************************************
DESCRIPTION: This program will mimic a shell, displaying a prompt and
allowing the user to enter commands. If the commands 'cd' or
'exit' are input, the program will handle them. All other commands
will be handled by a child process, which will be forked solely for
the purpose of executing a command, then terminates. The shell will
continue to display a prompt until the user inputs 'exit' or presses
CTRL-D.
*************************************************/
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <wait.h>
#include <cstring>
#include <string>
#include <iostream>
using namespace std;
//Info - holds the information used to execute a user command
struct Info {
char *path; //Path to the file
char *arg[]; //List of parsed user command
};
//PURPOSE: Displays a prompt and returns the user input
//PRECONDITION: None
//POSTCONDITION: The user input is returned
void getPrompt(char command[], Info& data);
//PURPOSE: Determines whether a command is intrinsic or not
//PRECONDITION: None
//POSTCONDITION: True is returned if command is intrinsic, False otherwise
int checkIntrinsic(char command[]);
//PURPOSE: Peforms the two intrinisc commands 'cd' and 'exit'
//PRECONDITION: User inputs the 'cd' or 'exit' command
//POSTCONDITION: The appropriate task is performed
void performIntrinsic(char command[]);
//PURPOSE: Sets the path when 'cd' is performed
//PRECONDITION: User inputs the 'cd' command
//POSTCONDITION: If a path is specified, it is set to that;
// otherwise, the path is HOME
void setPath(char command[], char path[]);
//PURPOSE: Parses the user command to be used with exec()
//PRECONDITION: None
//POSTCONDITION: The command is parsed and placed in *arg[]
void parseCmd(char command[], char *args[]);
// **************************************************
int main (int argc, char **argv, char **envp) {
//cmd - holds the command that is input by the user
char cmd[200] = "";
//status - holds the return status of the forked child
int status;
//chpid - holds the process ID of the child
//ret - holds the status of the wait
pid_t chpid, ret;
//pInfo - holds the information to be executed in the
// child process
Info pInfo;
//Prompt for user input
getPrompt(cmd, pInfo);
//Process the input
while (strlen(cmd) != 0 && !cin.eof()) {
//If the command is intrinsic, do not fork
if (checkIntrinsic(cmd) != 0)
performIntrinsic(cmd);
//Else, fork a child process and execute the command
else {
if ((chpid = fork()) == 0) {
parseCmd(cmd, pInfo.arg);
execvp(pInfo.path, pInfo.arg);
//If an error occurs, report it
// and exit with a 1
perror("Error: command failed ");
exit(1);
}
//wait until the child process has terminated
ret = wait(&status);
}
//Prompt for user input
getPrompt(cmd, pInfo);
}
cout << endl;
return 0;
}
// **************************************************
void getPrompt(char command[], Info& data) {
//Display a prompt
cout << "[" << getenv("PWD") << "]$ ";
//Get the user input
cin.getline (command, 200);
//Remove any leading blank spaces
while (isspace(command[0])) {
//Move each character forward 1 so the leading
// space is overwritten.
for (int i = 0; i < strlen(command) - 1; i++)
command[i] = command[i + 1];
//Since the new array is now 1 character shorter,
// make the extra element NULL
command[strlen(command) - 1] = '\0';
}
//Load the data structure's path
data.path = getenv("PWD");
}
// **************************************************
int checkIntrinsic(char command[]) {
//Convert the C-string to a string
string cmd = command;
//Check if the command is 'cd'
if (cmd.substr(0, 2) == "cd")
return 1;
//Else, check if the command is 'exit'
else if (cmd.substr(0, 4) == "exit")
return 2;
//Else, the command is not intrinsic
else
return 0;
}
// **************************************************
void performIntrinsic(char command[]) {
//path[] - holds the path used in 'cd'
char path[200] = "";
switch (checkIntrinsic(command)) {
//Perform 'cd' command
case 1:
//Set the path to 'cd' to
setPath(command, path);
//Now, 'cd' to the path if it exists
if (chdir(path) != 0)
cout << path << ": No such file or directory.\n";
break;
//Perform 'exit' command
case 2:
exit(0);
}
}
// **************************************************
void setPath(char command[], char path[]) {
//index - used to track the index of path[]
int index = 0;
//specified - flag for if a path is specified in the user command
bool specified = false;
//Check the rest of the command to see if
// a path was specified
for (int i = 2; command[i] != '\0'; i++) {
//If the character is not blank, assume that it is
// the part of the path
if (command[i] != ' ') {
specified = true;
path[index] = command[i];
index++;
}
}
//If the path was not specified, set it to the HOME directory
if (!specified)
path = getenv("HOME");
}
// **************************************************
void parseCmd(char command[], char *args[]) {
//Convert the C-string to a string
string cmd = command;
//temp - holds the parsed substrings of cmd
string temp;
//index - used to track the index of *args[]
int index = 0;
//Skip any spaces at the beginning of the string
string::size_type lastPos = cmd.find_first_not_of(" ", 0);
//Find the first non-space in the string
string::size_type pos = cmd.find_first_of(" ", lastPos);
while (string::npos != pos || string::npos != lastPos) {
//Found a token, so place it into the parse array
temp = cmd.substr(lastPos, pos - lastPos);
strcpy(args[index], temp.data());
//TEST LINE==============================
cout << "args[" << index << "]: " << args[index] << endl;
//=====================================
index++;
//Skip the spaces
lastPos = cmd.find_first_not_of(" ", pos);
//Find the next non-space
pos = cmd.find_first_of(" ", lastPos);
}
//TEST LINE==============================
cout << "Made it out!\n";
cout << "Index is at " << index << endl;
cout << "Size of args[] is " << strlen(*args) << endl;
//=====================================
//Add the NULL terminator
strcpy(args[index], '\0');
//TEST LINE==============================
cout << "Added NULL!\n";
//=====================================
}