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!
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.
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 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
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.
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; }
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.
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.
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
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);