SwainG
SwainG

Reputation: 19

C trimming a string with multiple words

Here is part of my my c program.

cmdline = "ls | sort -r " 
char * cmd1 = strtok(cmdline, "|");
char * cmd2 = strtok(NULL, "");
sscanf(cmd1,"%s",cmd1);
sscanf(cmd2,"%s",cmd2);

I am try to get the output as

cmd1 = "ls" 
cmd2 = "sort -r"

But the output I get is

cmd1 = "ls" 
cmd2 = "sort"

I found out that the sscanf function make the "-r" disappear. But I have no idea how can I trim " sort -r " become "sort -r". and also " sort -r -r " become "sort -r -r"

I try

sscanf(cmd2, "%s %s %s", cmd3, cmd4, cmd5);

But it cant do the trick because the number of element is fixed.

So what can I do to solve this issue?

Upvotes: 0

Views: 69

Answers (1)

Oka
Oka

Reputation: 26345

When using strtok you must make sure that the string you are tokenizing is mutable, as strtok overwrites the delimiter characters with NUL bytes, forming the tokens in existing memory.

For example, it is important to know the difference between these two objects:

const char *immutable = "pointer to a string literal.";
char mutable[] = "a character array, initialized by a string literal.";

To trim leading space, you can find the first non-space character, and move it and all subsequent characters to the front. strspn (and strcspn) are useful functions for finding spans of characters.

Alternatively, in this case, you could advance the pointer until it points to the first non-space character. This strategy doesn't work when you need to retain the base pointer, however (e.g., to pass to free).

To trim trailing space, you can start from the end of the string, working backwards til you find the first non-space character, and place a NUL terminating byte after it.


Here is an example of a basic trimming function.

Note that, in this example, the contents of tokens have the same lifetime as cmd. Additionally, trim does not compress whitespace inside the string (e.g., sort -r).

#include <stddef.h>
#include <stdio.h>
#include <string.h>

#define MAX_TOKENS 8

char *trim(char *s) {
    size_t i = 0;
    size_t ll = strspn(s, " ");

    if (ll) {
        while (s[ll])
            s[i++] = s[ll++];
        s[i] = '\0';
    } else
        i = strlen(s);

    while (i && s[i - 1] == ' ')
        i--;

    s[i] = '\0';

    return s;
}

int main(void) {
    char cmd[] = "ls |  sort -r|    foo   |   | bar ";
    char *tokens[MAX_TOKENS];
    char *tok;
    size_t n = 0;

    tok = strtok(cmd, "|");

    while (n < MAX_TOKENS && tok) {
        tokens[n++] = trim(tok);
        tok = strtok(NULL, "|");
    }

    for (size_t i = 0; i < n; i++)
        printf("%zu:[%s]\n", i, tokens[i]);
}

Output:

0:[ls]
1:[sort -r]
2:[foo]
3:[]
4:[bar]

Upvotes: 1

Related Questions