0

I am coding a basic shell and my first requirement is to test for cd, I have all my conditions for the possible cd commands, after which, I will handing commands like ls. As for now I am really confused about one block of code.

 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
 #include <stdlib.h>

 #define MAX_TOK 50
 #define MAX_LEN 100
 #define BUFSIZE 81

 int tokenize(char *cmd, char tokens[MAX_TOK][MAX_LEN]){
     char *token;
     int NUM_TOKENS = 0;
     //printf("Splitting the string \"%s\" into tokens:\n",cmd);
     token = strtok(cmd, " ");

    while(token != NULL){
         strcpy(tokens[NUM_TOKENS],token);
         token = strtok(NULL, " ");
         NUM_TOKENS++;
     }
      return NUM_TOKENS;
  }

void decide(char tokens[MAX_TOK][MAX_LEN], int NUM_TOKENS){

    char *home = getenv("HOME");
    int success;
    char *cd = {"cd"};
    char *string = tokens[1];
    //printf("Number of tokens %d\n", NUM_TOKENS);
    //printf("%d\n",strcmp(tokens[0], cd));

    if(strcmp(tokens[0], cd) == 0){
        if(NUM_TOKENS > 2){
            printf("error: Too many arguments\n");
        }
        else{
           printf("Changing to new directory %s \n",tokens[1]);
           char *string = tokens[0];
           //printf("%s\n", tokens[1]);
           success = chdir(tokens[1]);
           printf("%d\n",success);
        }
    }
    else{
        printf("Completing the %s request\n",tokens[0]);
        take_action(tokens[0]);
    } 
 }

void take_action(char *cmd){
     printf("%s\n",cmd);
     int len;
     int return_code;
     char buffer[BUFSIZE];
     int pid;
     pid = fork();
     if(pid != 0){
         //parent process executing
         wait(NULL);
     }else{
         //child process executing
         len = strlen(buffer);
         if(buffer[len-1] == '\n'){
         buffer[len-1] = '\0';
       }
    return_code = execlp(cmd, cmd, NULL);
    if(return_code != 0){
        printf("Error executing %s.\n", cmd);
    }
   }//end else
}

int main(){
char *cmd;
char tokens[MAX_TOK][MAX_LEN];
int len;
int return_code;
char buffer[BUFSIZE];
int pid;

while(cmd != NULL){
    printf("Enter a command\n");
    cmd = fgets(buffer, BUFSIZE, stdin);
    // find the command
    int NUM_TOKENS = tokenize(cmd, tokens);
    //print_tokens(NUM_TOKENS, tokens);
    decide(tokens,NUM_TOKENS);
}



}//end main

When hardcoding chdir("test") the code runs fine, if a user on the command line enters "cd test" tokens[0] is cd and tokens[1] is the string "test" but chdir(tokens[1]) fails and I don't understand why.

Printing tokens[1] also shows "test" as the string stored. As well when passing a parameter to take_action I am told conflicting types occurs. In both print statements the proper string is shown. As far as I can tell there are no extra spaces because my tokentize function strips them all. I am so confused, these two parts seem so simple but just wont work.

user2045236
  • 23
  • 1
  • 4
  • 4
    if `chdir()` failed, it set `errno`, so it should tell you why it failed. You'll probably find it helpful to print `string` too so you can see exactly what was passed in – Mike May 30 '13 at 16:32
  • @user2045236 if you are not doing wrong, `chdir("test")` is fine but on command prompt you don't need `"` explicitly, just `ch test` is fine... print `token[i]` before `chdir()` call and put in question what does it prints. – Grijesh Chauhan May 30 '13 at 17:52
  • @GrijeshChauhan when I print out the tokens[1] as in the line printf("%s\n", tokens[1]); the output is test. – user2045236 May 30 '13 at 18:37
  • @user2045236 ok what is current working directory, test should be in that path where your program is running – Grijesh Chauhan May 30 '13 at 18:40
  • @GrijeshChauhan yes, my program is in a folder called Lab01 and the folder test is in the folder Lab01. So the folder test is in the working directory – user2045236 May 30 '13 at 19:02
  • @user2045236 Then hard to know :( ...Sorry Try to print error using `perror()` just after `chdir(token[0/1])` call – Grijesh Chauhan May 30 '13 at 19:04
  • @GrijeshChauhan how would i do that? what arguments do i need for perror()? – user2045236 May 30 '13 at 19:19
  • noting! :) :) its simple to use [`void perror ( const char * str );`](http://www.cplusplus.com/reference/cstdio/perror/) go to the link – Grijesh Chauhan May 30 '13 at 19:20
  • @GrijeshChauhan I did that and I get invalid arguement. I am sending chdir() the string "test" nothing more. How is that invalid? – user2045236 May 30 '13 at 19:23
  • no call like: `peeror("chdir")` just after `success = chdir(string);` in your code. – Grijesh Chauhan May 30 '13 at 19:25
  • it's only giving an invalid argument error. – user2045236 May 30 '13 at 19:29

3 Answers3

4

The user does not enter cd test. He enters cd test and then hits the Enter key.

This means that you will have:

token[0] = "cd";
token[1] = "test\n";

And you don't have a directory named "test\n" , it would be "test". You need to strip off the newline character in the last token.

e.g. change main to do

char *tmp;
cmd = fgets(buffer, BUFSIZE, stdin);
if (cmd && (tmp = strrchr(buffer, '\n')) != NULL) {
   *tmp = 0;
}
nos
  • 223,662
  • 58
  • 417
  • 506
  • are you serious? The enter key adds a \n character? How does one strip this character????? – user2045236 May 30 '13 at 19:31
  • 1
    @user2045236 It most certainly do. On some systems it would add `\r\n` – nos May 30 '13 at 19:31
  • I do not understand why that works (my university said i needed this course after only teaching me java) but it does! I am going to look up strrchr in the man pages! Thank you very much! – user2045236 May 30 '13 at 19:36
  • @user2045236 strrchr(buffer, '\n') starts from the end of buffer and searches left for a \n character. It then returns a pointer to that character if finds one. In C, strings end with a 0 byte, so we overwrite the \n with a 0 byte, which makes the string end there. – nos May 30 '13 at 19:38
  • could the same have been done, if say I myself made a function to search the string, and if I found the '\n' character replace it with a 0? – user2045236 May 30 '13 at 19:46
3

The code

char *string = tokens[0];
printf("%s\n", tokens[1]);
success = chdir(string);

will translate to

success = chdir("cd");

I think you wanted

char *string = tokens[1];
//                    ^

instead.

simonc
  • 41,632
  • 12
  • 85
  • 103
  • Simonc I thought both of yours answers are correct, but OP also saying `chdir(tokens[1]) fails` ...as I understand this implies your answer it not correct. Am I wrong? or misunderstood something? – Grijesh Chauhan May 30 '13 at 17:00
  • That was a mistake that I missed, but even with the correction the chdir() returns -1 which means it failed to change the directory. I am not sure why though. – user2045236 May 30 '13 at 17:01
  • Grijesh Chauhan you are correct, neither using a pointer to the string or using the stored token value works. This is why I am confused. – user2045236 May 30 '13 at 17:14
  • @user2045236 You don't show us how you calculate/assign `tokens[1]` so its hard to give any specific advice. Have you tried logging its value, including checking for any leading spaces? – simonc May 30 '13 at 17:55
  • @simonc not sure how else to send it besides doing this – user2045236 May 30 '13 at 19:08
1

token[0] is cd and token[1] is the path. So use char* string=token[1]

Grijesh Chauhan
  • 57,103
  • 20
  • 141
  • 208
akhil
  • 732
  • 3
  • 13