trying to use strtok for CL shell

Discussion in 'C' started by ohaqqi, Jun 30, 2007.

  1. ohaqqi

    ohaqqi New Member

    Joined:
    Jun 30, 2007
    Messages:
    6
    Likes Received:
    0
    Trophy Points:
    0
    Occupation:
    hardware engineer
    Location:
    maryland, USA
    Hi everybody. I haven't programmed anything in about 8 years, I've read up a little bit on C and need to write a shell in C. I want to use strtok() to take an input from a user and parse it into the command and its arguments.

    for example: copy <file1> <file2> will copy file 2 to file 1, del <file1> will delete a file, etc. The exit command is all I've implemented right now, but even that produces an error when executed...I'm sure I've got a problem with how I've implemented strtok().

    I've tried to implement it below, but when I compile it using gcc (no errors/warnings) and try to execute it I get the following output:

    o-shell>exit
    com = exit
    Segmentation fault (core dumped)


    Here is the code snippet:
    ****************************
    Code:
    [I]char command[50]; //Command line input
    
    char com[10]; //Primary command
    char file1[20]; //File affected by command (if necessary)
    char file2[20]; //2nd file affected by command (if necessary)
    
    char *token; //Used for strtok() function
    
    for(;;)
    {
    
    printf("o-shell>"); //user prompts for o-shell
    
    scanf("%s", command); //command line input from user
    
    //tokenize the command line input using strtok() function
    //this produces the command as well as any command line arguments
    
    while(token != NULL)
    {
    token = strtok(command, " ");
    strcpy(com, token);
    
    printf("com = %s\n", com);
    
    token = strtok(NULL, " ");
    strcpy(file1, token);
    
    printf("file1 = %s\n", file1);
    
    token = strtok(NULL, " ");
    strcpy(file2, token);
    
    printf("file2 = %s\n", file2);
    }[/I]
    
    ****************************
    When I run the program, I get a segmentation fault. Will this code run OK if there are no arguments, just a command? I'm sure the problem is with strtok() either way. thanks!
     
    Last edited by a moderator: Jun 30, 2007
  2. DaWei

    DaWei New Member

    Joined:
    Dec 6, 2006
    Messages:
    835
    Likes Received:
    5
    Trophy Points:
    0
    Occupation:
    Semi-retired EE
    Location:
    Texan now in Central NY
    Home Page:
    http://www.daweidesigns.com
    Your while test isn't doing you any good down in the sequence. Let's say the second strtok doesn't find a token. It returns NULL. You aren't testing for that, you're dereferencing a NULL pointer when you attemp the strcpy. The problem isn't with strtok. As usual, it's with the coder.
     
  3. ohaqqi

    ohaqqi New Member

    Joined:
    Jun 30, 2007
    Messages:
    6
    Likes Received:
    0
    Trophy Points:
    0
    Occupation:
    hardware engineer
    Location:
    maryland, USA
    I admit that I'm a total newbie, this is the first C program I've written in a long while, and that was just freshman intro to programming :D

    So I'm trying to break the command[50] input from the user into 3 (or less) character strings. If I remove the while(token != NULL) and change it to if(&token == NULL) after each strtok() function indicating the end of the input by the user, is that correct? I'm totally confused :confused:
     
  4. DaWei

    DaWei New Member

    Joined:
    Dec 6, 2006
    Messages:
    835
    Likes Received:
    5
    Trophy Points:
    0
    Occupation:
    Semi-retired EE
    Location:
    Texan now in Central NY
    Home Page:
    http://www.daweidesigns.com
    Did you try it? It's just logic. Strtok says it will deliver you the address of the next token, for each call, or a NULL when there's no new token. That's pretty clear. It doesn't promise to deliver the address of a token when there's no token. It's YOUR job to check that out. It doesn't promise to work if you dereference a NULL. It leaves the results of that up to the language (which forbids it) and the implementation, which seems, in this case, to give you a seg fault. It could burn your machine to a slag heap and cause your homework to eat the dog, and still comply with the standard.

    You are flirting with danger in other respects. Just because you define the command to have a maximum of 9 characters, and the arguments to have a maximum of 19 characters, do you think that forces your user to obey? I don't know about you, but MY users are uninformed or lazy or malicious or fall asleep with their forehead on the keyboard. It is MY job, and YOUR job, to handle those eventualities.

    We can ignore our jobs and issue updates to our programs for years, like MS, so long as we can convince people that they should pay us for the privilege of giving them crap code. Personally, I haven't been able to do that.
     
  5. ohaqqi

    ohaqqi New Member

    Joined:
    Jun 30, 2007
    Messages:
    6
    Likes Received:
    0
    Trophy Points:
    0
    Occupation:
    hardware engineer
    Location:
    maryland, USA
    I redid my code and it partially works right now. I can use strtok to find the first input in the command line, but cannot get the arguments.

    The format is <command> <arg1> <arg2>

    So far, I've only implemented 'exit' and 'help'. When I run this code, it compiles fine but I get a segmentation fault. I've placed a couple printf to help debug. One of the problems is that the arguments are not detected/counted.

    Here is the output:

    ************************************************** *
    Welcome to O-Shell! A UNIX shell by O Haqqi

    Type 'help' for list of commands, 'exit' to exit
    ************************************************** *

    o-shell>exit
    exit was entered
    There are 0 arguments
    Command is exit
    Segmentation fault (core dumped)


    Code:
    #include <stdio.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <string.h>
    
    int main(int argc, char *argv[])
    {
    char command[50]; //Command line input
    
    //tokens for strtok() funtion
    char * com; //Primary command
    char * arg1; //First argument of command (usually a file name)
    char * arg2; //2nd argument of command (usually a file name)
    
    int args; //Number of arguments entered
    
    printf("************************************************** *\n");
    printf("Welcome to O-Shell! A UNIX shell by O Haqqi\n\n");
    printf("Type 'help' for list of commands, 'exit' to exit\n");
    printf("************************************************** *\n\n");
    
    for(;;)
    {
    
    printf("o-shell>"); //user prompts for o-shell
    
    scanf("%s", command); //command line input from user
    
    printf("%s was entered\n", command);
    
    com = strtok(command, " \r\n\t");
    
    args = 0;
    arg1 = strtok(NULL, " \r\n\t");
    if(arg1) args++; //to see if arguments being tracked
    arg2 = strtok(NULL, " \r\n\t");
    if(arg2) args++; //to see if arguments being tracked
    
    printf("There are %d arguments\n", args);
    printf("Command is %s\n", com);
    printf("File1 is %s\n", arg1);
    printf("File2 is %s\n", arg2);
    
    if ((strcmp(com,"help")) ==0 || (strcmp(com,"Help")) ==0)
    {
    printf("\nO-Shell Help Menu:\n");
    printf("\nhelp - Print help menu\n");
    printf("\nexit - Exit O-Shell\n");
    printf("\ntype <file> - Print contents of <file>\n");
    printf("\ncopy <file1> <file2> - Copy contents of <file1> to <file2>.");
    printf("\n <file2> must be a non-existent file and must be created\n");
    printf("\ndelete <file> - Delete <file>\n\n");
    }
    
    else if ((strcmp(com,"exit")) ==0 || (strcmp(com,"Exit")) ==0)
    {
    printf("Exiting O-Shell...Goodbye!\n");
    break;
    }
    
    else
    printf("Invalid command!!! No operation performed...\n");
    
    }
    
    
    return 0;
    }
     
  6. DaWei

    DaWei New Member

    Joined:
    Dec 6, 2006
    Messages:
    835
    Likes Received:
    5
    Trophy Points:
    0
    Occupation:
    Semi-retired EE
    Location:
    Texan now in Central NY
    Home Page:
    http://www.daweidesigns.com
    You ask for help, you get a response, you don't pay attention. Is that nice? Suppose there is no arg1. That pointer is NULL. Do not dereference it with a statement like printf("File1 is %s\n", arg1);. That's invalid. Won't work. Seg fault. Core dump. Slag heap.
     
  7. ohaqqi

    ohaqqi New Member

    Joined:
    Jun 30, 2007
    Messages:
    6
    Likes Received:
    0
    Trophy Points:
    0
    Occupation:
    hardware engineer
    Location:
    maryland, USA
    But if I type the following this is what I see:

    o-shell>exit exit exit
    exit was entered
    There are 0 arguments
    Command is exit
    Segmentation fault (core dumped)


    There should be two arguments (two exits after the command exit) counted. So the args pointer shouldn't be NULL, unless the strtok code that I entered is wrong...which is what I'm looking for --- the error.
     
  8. ohaqqi

    ohaqqi New Member

    Joined:
    Jun 30, 2007
    Messages:
    6
    Likes Received:
    0
    Trophy Points:
    0
    Occupation:
    hardware engineer
    Location:
    maryland, USA
    Changing scanf to fgets fixed it (not sure why). As long as I don't try to printf NULL pointers, like you said dawei.
    thanks
     
  9. DaWei

    DaWei New Member

    Joined:
    Dec 6, 2006
    Messages:
    835
    Likes Received:
    5
    Trophy Points:
    0
    Occupation:
    Semi-retired EE
    Location:
    Texan now in Central NY
    Home Page:
    http://www.daweidesigns.com
    That's because scanf %s only returns the first token. Therefore there's nothing for strtok to find as the second and third arguments. Fgets returns the whole line. You still need to protect against using the args pointers for cases with fewer than three tokens. For example, just modifying your existing code:
    Code:
    printf("There are %d arguments\n", args);
    printf("Command is %s\n", com);
    if (arg1) printf("File1 is %s\n", arg1);
    if (arg2) printf("File2 is %s\n", arg2);
    
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice