DavidMG
DavidMG

Reputation: 105

Parsing commands shell-like in C

I want to parse user input commands in my C (just C) program. Sample commands:

add node ID

add arc ID from ID to ID

print

exit

and so on. Then I want to do some validation with IDs and forward them to specified functions. Functions and validations are of course ready. It's all about parsing and matching functions...

I've made it with many ifs and strtoks, but I'm sure it's not the best way... Any ideas (libs)?

Upvotes: 2

Views: 8423

Answers (4)

Teja
Teja

Reputation: 13524

All your command line parameters will be stored into a array of strings called argv.

You can access those values using argv[0], argv[1] ... argv[n].

Upvotes: 0

Fernando
Fernando

Reputation: 97

I just wanted to add something to Richard Ross's reply: Check the returned value from malloc and realloc. It may lead to hard-to-find crashes in your program.

Upvotes: 1

Richard J. Ross III
Richard J. Ross III

Reputation: 55533

I think what you want is something like this:

while (1) 
{
    char *line = malloc(128); // we need to be able to increase the pointer
    char *origLine = line;
    fgets(line, 128, stdin);

    char command[20];
    sscanf(line, "%20s ", command);

    line = strchr(line, ' ');

    printf("The Command is: %s\n", command);

    unsigned argumentsCount = 0;
    char **arguments = malloc(sizeof(char *));

    while (1)
    {
        char arg[20];
        if (line && (sscanf(++line, "%20s", arg) == 1))
        {
            arguments[argumentsCount] = malloc(sizeof(char) * 20);
            strncpy(arguments[argumentsCount], arg, 20);

            argumentsCount++;

            arguments = realloc(arguments, sizeof(char *) * argumentsCount + 1);
            line = strchr(line, ' ');
        }
        else {
            break;
        }
    }

    for (int i = 0; i < argumentsCount; i++) {
        printf("Argument %i is: %s\n", i, arguments[i]);
    }

    for (int i = 0; i < argumentsCount; i++) {
        free(arguments[i]);
    }

    free(arguments);
    free(origLine);
}  

You can do what you wish with 'command' and 'arguments' just before you free it all.

Upvotes: 3

John Bode
John Bode

Reputation: 123458

It depends on how complicated your command language is. It might be worth going to the trouble of womping up a simple recursive descent parser if you have more than a couple of commands, or if each command can take multiple forms, such as your add command.

I've done a couple of RDPs by hand for some projects in the past. It's a bit of work, but it allows you to handle some fairly complex commands that wouldn't be straightforward to parse otherwise. You could also use a parser generator like lex/yacc or flex/bison, although that may be overkill for what you are doing.

Otherwise, it's basically what you've described; strok and a bunch of nested if statements.

Upvotes: 1

Related Questions