Parse string into argv/argc

前端 未结 13 821
生来不讨喜
生来不讨喜 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:19

    Consider yet another implementation. Run.

    #include <cctype>  // <ctype.h>  for isspace()
    
    /** 
     * Parse out the next non-space word from a string.
     * @note No nullptr protection
     * @param str  [IN]   Pointer to pointer to the string. Nested pointer to string will be changed.
     * @param word [OUT]  Pointer to pointer of next word. To be filled.
     * @return  pointer to string - current cursor. Check it for '\0' to stop calling this function   
     */
    static char* splitArgv(char **str, char **word)
    {
        constexpr char QUOTE = '\'';
        bool inquotes = false;
    
        // optimization
        if( **str == 0 )
            return NULL;
    
        // Skip leading spaces.
        while (**str && isspace(**str)) 
            (*str)++;
    
        if( **str == '\0')
            return NULL;
    
        // Phrase in quotes is one arg
        if( **str == QUOTE ){
            (*str)++;
            inquotes = true;
        }
    
        // Set phrase begining
        *word = *str;
    
        // Skip all chars if in quotes
        if( inquotes ){
            while( **str && **str!=QUOTE )
                (*str)++;
            //if( **str!= QUOTE )
        }else{
            // Skip non-space characters.
            while( **str && !isspace(**str) )
                (*str)++;
        }
        // Null terminate the phrase and set `str` pointer to next symbol
        if(**str)
            *(*str)++ = '\0';
    
        return *str;
    }
    
    
    /// To support standart convetion last `argv[argc]` will be set to `NULL`
    ///\param[IN]  str : Input string. Will be changed - splitted to substrings
    ///\param[IN]  argc_MAX : Maximum a rgc, in other words size of input array \p argv
    ///\param[OUT] argc : Number of arguments to be filled
    ///\param[OUT] argv : Array of c-string pointers to be filled. All of these strings are substrings of \p str
    ///\return Pointer to the rest of string. Check if for '\0' and know if there is still something to parse. \
    ///        If result !='\0' then \p argc_MAX is too small to parse all. 
    char* parseStrToArgcArgvInsitu( char *str, const int argc_MAX, int *argc, char* argv[] )
    {
        *argc = 0;
        while( *argc<argc_MAX-1  &&  splitArgv(&str, &argv[*argc]) ){
            ++(*argc);
            if( *str == '\0' )
                break;
        }
        argv[*argc] = nullptr;
        return str;
    };
    

    Usage code

    #include <iostream>
    using namespace std;
    
    void parseAndPrintOneString(char *input)
    {
        constexpr size_t argc_MAX = 5;
        char* v[argc_MAX] = {0};
        int c=0;
    
        char* rest = parseStrToArgcArgvInsitu(input,argc_MAX,&c,v);
        if( *rest!='\0' )  // or more clear `strlen(rest)==0` but not efficient
            cout<<"There is still something to parse. argc_MAX is too small."<<endl;
    
        cout << "argc : "<< c << endl;
        for( int i=0; i<c; i++ )
            cout<<"argv["<<i<<"] : "<<v[i] <<endl;
        /*//or condition is `v[i]`
        for( int i=0; v[i]; i++ )
            cout<<"argv["<<i<<"] : "<<v[i] <<endl;*/
    }
    
    
    
    int main(int argc, char* argv[])
    {
        char inputs[][500] ={
                  "Just another TEST\r\n"
                , "  Hello my world 'in quotes' \t !"
                , "./hi 'Less is more'"
                , "Very long line with \"double quotes\" should be parsed several times if argv[] buffer is small"
                , "   \t\f \r\n"
        };
    
        for( int i=0; i<5; ++i ){
            cout<<"Parsing line \""<<inputs[i]<<"\":"<<endl;
            parseAndPrintOneString(inputs[i]);
            cout<<endl;
        }
    }
    

    Output:

    Parsing line "Just another TEST\r\n":
    argc : 3
    argv[0] : Just
    argv[1] : another
    argv[2] : TEST
    
    Parsing line "  Hello my world 'in quotes'   !":
    There is still something to parse. argc_MAX is too small.
    argc : 4
    argv[0] : Hello
    argv[1] : my
    argv[2] : world
    argv[3] : in quotes
    
    Parsing line "./hi 'Less is more'":
    argc : 2
    argv[0] : ./hi
    argv[1] : Less is more
    
    Parsing line "Very long line with "double quotes" should be parsed several times if argv[] buffer is small":
    There is still something to parse. argc_MAX is too small.
    argc : 4
    argv[0] : Very
    argv[1] : long
    argv[2] : line
    argv[3] : with
    
    Parsing line "       
    
    ":
    argc : 0
    
    0 讨论(0)
提交回复
热议问题