1

I am trying to create a shell, and am having trouble trying to fill the *argv[] array with user input. I call my parse function, and store each word into a 2d array. I tried many different ways to store it directly into *argv[], but eventually decided to try using the 2d array. Is there anyway to fill *argv[] with pointers to the strings stored in the 2d array? Or fill *argv[] with pointers to strings without use of the 2d array?

Ive tried many other things but my current attempt is the while loop after calling the parse function.

int main() {
   int status, fRedirect, i;
   pid_t pid;
   char s[STORAGE];
   char p[MAXITEM][STORAGE];
   char *argv[MAXITEM];
   for(;;) {
       printf("\2: ");
       scanf("%s", s);
       parse(s, p);
       while(p[i] != '\0') {
           args[i] = *p[i];
       }
       if(p[0] == EOF)
           break;
       if(p[0] == '\0')
          continue;
    pid = fork();
    if(pid == 0) {
        if(execvp(*p, p) == -1) {
            printf("Execution failed!\n");
            exit(9);
        }
    }
    if(pid != 0) {
        wait(-1, &status, 0);
    }
    else {
        fRedirect = open("/dev/null", O_WRONLY);
        dup2(fRedirect, STDOUT_FILENO);
    }

}
/*killpg(getpid(), SIGTERM);*/
printf("p2 terminated. \n");
exit(0);
}

void parse(char *s, char p[][STORAGE]) {
    int i, j = 0;
    while(*s != EOF && *s != '&' && *s != '\n' && *s != ';' && *s != '\0') {
        for(i=0; i < strlen(s); i++)
            p[j][i] = s[i];
        i = i+getword(s);
        j++;
    }
}
trawww
  • 103
  • 1
  • 6
  • 14
  • Hint: Your parse function should fill argv from s, probably using strdup for each entry, then your execvp should look like execvp(argv[0], argv);. Note that your string scanned from scanf will never contain EOF. – Charlie Burns Oct 15 '13 at 02:24
  • In the above comment I should have said "strtok and strdup" not just strdup – Charlie Burns Oct 15 '13 at 02:35
  • should my parse function then be returning char **? or is it being filled outside of the parse function as well? – trawww Oct 15 '13 at 02:42
  • Curious, Is it a requirement that you fill `*argv[]` from within your main function?, or would it be ok to fill it from the command line in conjunction with argc? If you need to fill it within main(), then I believe you will need to do some memory allocation first. If used in the traditional way, the main function definitions handle this for you as the arguments are read in from command line. – ryyker Oct 15 '13 at 03:39
  • did a complete overhaul and now argv seems to be getting filled with arguments. I tried to post my updated code as an answer, but I cant for another 5 hours because I dont have enough reputation! I will post it back up at the end of the night. @ryyker I wanted to use argv[] to execute commands, which i am working on now. – trawww Oct 15 '13 at 04:00
  • Misunderstood your intentions with using `*argv[]`. Looking forward to seeing how it turned out though. – ryyker Oct 15 '13 at 15:14

2 Answers2

0

I see in your code that you have included char *argv[MAXITEM]; in the function body of main(). This is traditionally not the way *argv[] is used. The main function definition has code within it that handles memory for *argv[]. Parsing the command line arguments into strings, integers, floating point numbers can be done the usual way, using string parsing and conversion functions inside main(). If you are interested, Here is a post explaining char *argv[] with a little more detail,

For a simple example of string arguments (similar to what you are doing) take a look below at how it is used, it may solve a couple of issues for you right away, such as simplifying the way you are obtaining and parsing your input.

First, the answer to your question: Is there anyway to fill *argv[] with pointers to the strings stored in the 2d array? Or fill *argv[] with pointers to strings without use of the 2d array?

No.

However, you can fill it with string constants. char *Argv[] is itself a variable that can contain an array of strings (pointer to an array of strings) when used in main like this:

#include <ansi_c.h>
int main(int argc, char *argv[]) //Note: the`[]` blank brackets allow any string length.  
                                 // the `*` allows multiple arguments
{
     int i;
     for(i=0;i<argc;i++)         //argc contains the count of cmd line arguments
    {
        printf("%s\n", argv[i]); //*argv[] holds multiple string arguments 
    }                         

     getchar();                  //optional - pauses execution so I can see output
    return 0;
}

To test:
Build as play.exe, then run it with command line arguments such as:

"argument1" "argument2" "Hello"

The output should be: (essentially, parsing your input into variable strings)

enter image description here

Community
  • 1
  • 1
ryyker
  • 22,849
  • 3
  • 43
  • 87
  • I used your idea of a for loop to print the contents of the *argv[], and seems to be working as I wanted it to now. Thank you – trawww Oct 15 '13 at 21:59
0

Ok, after working on it some more and adding in more features, Here is what I'm currently working with. To my knowledge, the parse() command now fills *argv[] with the words taken in from the command line.

int main() {
    pid_t pid, child_pid;
    int argc, inputRedirect;
    char *devNull;
    devNull = (char *) malloc(10);
    strcpy(devNull, "/dev/null");
    char *argv[MAXITEM];
    char commandLine[STORAGE];

    signal(SIGTERM, myhandler);

    for (;;) {
        printf("p2: ");
        scanf("%s", commandLine);
        if(commandLine == EOF)
            break;
        argc = parse(commandLine, argv);
        if (argv[0] == '\0')
            continue;
        if(argv[0] = "cd")
            changeDir(argv[1]);
        child_pid = fork();
        if (child_pid < 0) {
            printf("Cannot fork! Terminating...");
            exit(1);
        } else if (child_pid == 0) {
            CHK(inputRedirect = open(devNull, O_RDONLY));
            CHK(dup2(inputRedirect, STDIN_FILENO));
            CHK(close(inputRedirect));
            CHK(execvp(*argv, argv));
        }
        else {
            for(;;) {
                CHK(pid = wait(NULL));
                if(pid == child_pid)
                    break;
            }
            printf("Child's pid is %d\n", child_pid);
        }
    }
    killpg(getpid(), SIGTERM);
    printf("p2 Terminated.\n");
    exit(0);
}

int parse(char *commandLine, char *argv[]) {
    int argc = 0;
    char *commandPointer = commandLine;
    while (*commandPointer != '\0') {
        *argv = commandPointer;
        argc++;
        getword(commandPointer);
    }
    *commandPointer = '\0';
    *argv = '\0';
    return argc;
}
trawww
  • 103
  • 1
  • 6
  • 14