Разбор строки командной строки в формате argv - PullRequest
3 голосов
/ 23 декабря 2011

Мне нужно проанализировать строку командной строки в формате argv, чтобы я мог передать ее в execvpe. В основном Linux, эквивалентный CommandLineToArgvW () из Windows. Есть ли какая-либо функция или библиотека, которую я мог бы вызвать, чтобы сделать это? Или я должен написать свой собственный парсер? (Я надеялся, что смогу украсть у BASH, если мне нужно будет это сделать, поскольку моя программа GPL ...)

Пример: У меня есть три переменные:

const char* file = "someapplication";
const char* parameters = "param1 -option1 param2";
const char* environment[] = { "Something=something", NULL };

и я хочу передать его в execvpe:

execvpe(file, /* parsed parameters */, environment);

PS: я не хочу расширения имени файла, но хочу цитировать и экранировать

Ответы [ 5 ]

3 голосов
/ 18 января 2012

Я использовал ссылку, предоставленную rve в комментариях (http://bbgen.net/blog/2011/06/string-to-argc-argv)), и это решило мою проблему. Upvote его комментарий, а не мой ответ!

1 голос
/ 09 апреля 2012

Используйте мою nargv процедуру.Я буквально избил этот вопрос до смерти следующим ответом: https://stackoverflow.com/a/10071763/735796 nargv означает «Новые аргументы в векторе».Он поддерживает все, что может сделать оболочка при разборе строки на отдельные элементы.Например, он поддерживает двойные кавычки, одинарные кавычки и конкатенацию строк.

0 голосов
/ 29 мая 2015

Следующая моя первая попытка дублировать то, что делает функция CommandLineToArgvW() в библиотеке оболочки Windows. Он использует только стандартные функции и типы и не использует Boost. За исключением одного вызова strdup(), он не зависит от платформы и работает как в среде Windows, так и в Linux. Он обрабатывает аргументы, которые заключаются в одинарные или двойные кавычки.

// Snippet copied from a larger file.  I hope I added all the necessary includes.
#include <string>
#include <string.h>
#include <vector>

using namespace std;

char ** CommandLineToArgv( string const & line, int & argc )
{
    typedef vector<char *> CharPtrVector;
    char const * WHITESPACE_STR = " \n\r\t";
    char const SPACE = ' ';
    char const TAB = '\t';
    char const DQUOTE = '\"';
    char const SQUOTE = '\'';
    char const TERM = '\0';


    //--------------------------------------------------------------------------
    // Copy the command line string to a character array.
    // strdup() uses malloc() to get memory for the new string.
#if defined( WIN32 )
    char * pLine = _strdup( line.c_str() );
#else
    char * pLine = strdup( line.c_str() );
#endif


    //--------------------------------------------------------------------------
    // Crawl the character array and tokenize in place.
    CharPtrVector tokens;
    char * pCursor = pLine;
    while ( *pCursor )
    {
        // Whitespace.
        if ( *pCursor == SPACE || *pCursor == TAB )
        {
            ++pCursor;
        }

        // Double quoted token.
        else if ( *pCursor == DQUOTE )
        {
            // Begin of token is one char past the begin quote.
            // Replace the quote with whitespace.
            tokens.push_back( pCursor + 1 );
            *pCursor = SPACE;

            char * pEnd = strchr( pCursor + 1, DQUOTE );
            if ( pEnd )
            {
                // End of token is one char before the end quote.
                // Replace the quote with terminator, and advance cursor.
                *pEnd = TERM;
                pCursor = pEnd + 1;
            }
            else
            {
                // End of token is end of line.
                break;
            }
        }

        // Single quoted token.
        else if ( *pCursor == SQUOTE )
        {
            // Begin of token is one char past the begin quote.
            // Replace the quote with whitespace.
            tokens.push_back( pCursor + 1 );
            *pCursor = SPACE;

            char * pEnd = strchr( pCursor + 1, SQUOTE );
            if ( pEnd )
            {
                // End of token is one char before the end quote.
                // Replace the quote with terminator, and advance cursor.
                *pEnd = TERM;
                pCursor = pEnd + 1;
            }
            else
            {
                // End of token is end of line.
                break;
            }   
        }

        // Unquoted token.
        else
        {
            // Begin of token is at cursor.
            tokens.push_back( pCursor );

            char * pEnd = strpbrk( pCursor + 1, WHITESPACE_STR );
            if ( pEnd )
            {
                // End of token is one char before the next whitespace.
                // Replace whitespace with terminator, and advance cursor.
                *pEnd = TERM;
                pCursor = pEnd + 1;
            }
            else
            {
                // End of token is end of line.
                break;
            }
        }
    }


    //--------------------------------------------------------------------------
    // Fill the argv array.
    argc = tokens.size();
    char ** argv = static_cast<char **>( malloc( argc * sizeof( char * ) ) );
    int a = 0;
    for ( CharPtrVector::const_iterator it = tokens.begin(); it != tokens.end(); ++it )
    {
        argv[ a++ ] = (*it);
    }


    return argv;
}
0 голосов
/ 23 декабря 2011

Может быть, я что-то упускаю, но почему бы вам просто не передать &argv[1] в качестве параметров и среду, полученную с использованием getenv() в качестве среды?

EDIT: Если вам нужен другой разделитель, вы можете использовать переменную среды IFS (внутренний разделитель полей) для достижения этого.

0 голосов
/ 23 декабря 2011

char *strtok(char *s, const char *delim) - это то, что вы ищете

char *s будет стандартным вводом, а char *delim будет ' '

...