Parse string into argv/argc

前端 未结 13 917
生来不讨喜
生来不讨喜 2020-11-28 07:45

Is there a way in C to parse a piece of text and obtain values for argv and argc, as if the text had been passed to an application on the command line?

This doesn\'

13条回答
  •  余生分开走
    2020-11-28 08:09

    My project requires breaking a string into argc and argv.

    Found a pretty excellent code of Torek. But it alters the input buffer so I made some modifications to fit my needs.

    I just put a little bit more to handle quote mixing when input in the command line so the behavior is more (not completely) like Linux Shell.

    Note: This function doesn't edit the original string, so you can reuse the input buffer (error report,etc).

    void remove_quote(char* input){
       //Implementing yourself to remove quotes so it would be completely like Linux shell
    }
    size_t cmd_param_split(char *buffer, char *argv[], size_t argv_max_size)
    {
        char *p, *start_of_word;
        int c, i;
        enum states { DULL=0, IN_WORD, IN_STRING, QUOTE_DOUBLE,QUOTE_SINGLE } state = DULL;
        size_t argc = 0;
        int quote = 0;
        for (p = buffer; argc < argv_max_size && *p != '\0'; p++) {
            c = (unsigned char) *p;
            printf("processing %c, state = %d\n", c,state);
            switch (state) {
            case DULL:
                if (isspace(c)) {
                    continue;
                }
    
                if (c == '"' ||c == '\'') {
                    quote = c;
                    state = IN_STRING;
                    start_of_word = p + 1;
                    continue;
                }
                state = IN_WORD;
                start_of_word = p;
                continue;
    
            case IN_STRING:
                if (c == '"' || c == '\'') {
                    if (c!=quote)
                        continue;
                    else
                        quote = 0;
                    strncpy(argv[argc],start_of_word, p - start_of_word);
                    remove_quote(argv[argc]);
                    argc++;
                    state = DULL;
                }
                continue;
    
            case IN_WORD:
                if(quote==0 && (c == '\"' ||c == '\''))
                    quote = c;
                else if (quote == c)
                        quote = 0;
    
                if (isspace(c) && quote==0) {
                    strncpy(argv[argc],start_of_word, p - start_of_word);
                    remove_quote(argv[argc]);
                    argc++;
                    state = DULL;
                }
                continue;
            }
        }
    
        if (state != DULL && argc < argv_max_size){
            strncpy(argv[argc],start_of_word, p - start_of_word);
            remove_quote(argv[argc]);
            argc++;
        }
    
        if (quote){
            printf("WARNING: Quote is unbalanced. This could lead to unwanted-behavior\n");
            for(i = 0;i

    Tested with below strings

     1. "1 2 3 \'3 4\"567\' \"bol\'obala\" 2x2=\"foo\""
       arg 0 = [1]
       arg 1 = [2]
       arg 2 = [3]
       arg 3 = [3 4"567]
       arg 4 = [bol'obala]
       arg 5 = [2x2="foo"]
     2. "./foo bar=\"Hanoi HoChiMinh\" exp='foo123 \"boo111' mixquote \"hanoi \'s\""
       arg 0 = [./foo]
       arg 1 = [bar="Hanoi HoChiMinh"]
       arg 2 = [exp='foo123 "boo111']
       arg 3 = [mixquote]
       arg 4 = [hanoi 's]
    

    However, Linux shell would remove quotes, even in mixed case, as below when running from cmd line, tested in a RaspberryPi.

    ./foo bar="Hanoi HoChiMinh" exp='foo123 "boo111' mixquote "hanoi 's"
       arg 0 = [./foo]
       arg 1 = [bar=Hanoi HoChiMinh]
       arg 2 = [exp=foo123 "boo111]
       arg 3 = [mixquote]
       arg 4 = [hanoi 's]
    

    So if you really want to mimic the whole Linux shell's behavior, just put a little bit more effort into removing quotes remove_quote() function as I leave blank above.

提交回复
热议问题