views:

115

answers:

5

I'm writing a program for a school project that is supposed to emulate the Unix shell, in a very basic form. It's basically parsing input, then doing a fork/exec. I need to be able to read arguments in the program (not as arguments passed to the program from the command line) individually. For example, I will prompt:

Please enter a command:

...and I need to be able to parse both...

ls

OR

ls -l

but the trouble is that there seems to be no easy way to do this. scanf() will pull each argument individually, but I see no way to place them into differing slots in a char* array. For example, if I do...

char * user_input[10];
for (int i=0; i<10; i++){
    user_input[i] = (char *) malloc(100*sizeof(char));
}

for (int i=0; *(user_input[i]) != '@'; i++)
{
    scanf("%s", user_input[index]);
    index++;
}

...then user_input[0] will get "ls", then the loop will start over, then user_input[0] will get "-l".

gets and fgets just take the whole line. Obviously this problem can be logically solved by going through and plucking out each individual argument...but I'd like to avoid having to do that if there is an easy way that I'm missing. Is there?

Thanks!

+1  A: 

You can use strtok_r to break the string up on whitespace. Note that it is a destructive operation (modifies the input string).

Logan Capaldo
+6  A: 

If your use case is simple enough, you can do this with strtok:

char *strtok(char *str, const char *delim);
char *strtok_r(char *str, const char *delim, char **saveptr);

The strtok() function parses a string into a sequence of tokens. On the first call to strtok() the string to be parsed should be specified in str. In each subsequent call that should parse the same string, str should be NULL.

You can use strtok or strtok_r to split the string on spaces.

If you're doing something more complex, where some of the arguments could have (quoted) spaces in them, you're pretty much stuck parsing it yourself - though you could have a look at the source of a shell (e.g. bash) to see how it handles it.

kilanash helpfully reminds me of my obvious omission - GNU getopt. You'll still have to have parsed into separate arguments yourself first, though.

Jefromi
getopt is the fairly well-known GNU standard library for this. http://www.gnu.org/s/libc/manual/html_node/Parsing-Program-Arguments.html
Kilanash
@Kilanash: Oh, duh. I've used it a dozen times, no idea why I didn't put it in my answer. Of course... getopt works on `argv` - the shell has already split the arguments up when they get to getopt. So it's more of a second step, after the initial splitting the OP's asking about.
Jefromi
Thank you. This seems like it will work...this is a very, very basic shell simulator, so I don't think I need to worry about quoted spaces. I appreciate your help!
Ryan
+2  A: 

Forget that scanf exists for it rarely does what you want. Get the whole line at once and then write code to split it up. strtok - the second most favored answer to this question - is also problem ridden.

msw
For the typical, simple use cases that homework problems present, strtok is usually more than sufficient. You get a +1 anyway for saying "avoid scanf" because I don't think I've ever seen scanf get used well.
JUST MY correct OPINION
Sufficient, sure. Teaches bad habits? Probably.
msw
+1  A: 

man strtok.

the_void
A: 

Try to see if anything of this will help you:

ANSI C Command Line Option Parsing Library

The Argtable Homepage

Regards, Tiho

Tiho