преобразуйте строку в argv в C++

Любой код с поддержкой (или документация) пропавшие без вести. Будьте этим:

  • встроенные комментарии
  • техническая документация
  • разговорная документация (человек, который записал это)
  • модульные тесты, документирующие работы кода
8
задан aaronstacy 2 October 2009 в 21:17
поделиться

8 ответов

std::vector<char *> args;
std::istringstream iss(cmd);

std::string token;
while(iss >> token) {
  char *arg = new char[token.size() + 1];
  copy(token.begin(), token.end(), arg);
  arg[token.size()] = '\0';
  args.push_back(arg);
}
args.push_back(0);

// now exec with &args[0], and then:

for(size_t i = 0; i < args.size(); i++)
  delete[] args[i];

Конечно, это не будет работать с командами, использующими кавычки, например rm "a file.mp3" . Вы можете рассмотреть функцию POSIX wordexp , которая заботится об этом и многом другом.

5
ответ дан 5 December 2019 в 08:24
поделиться

Здесь очень не-unixy ответы. Что не так с:

std::string cmd = "echo hello world";
execl("/bin/sh", "/bin/sh", "-c", cmd.c_str(), NULL);

Зачем писать синтаксический анализатор командной строки, когда в системе уже есть совершенно исправный?

(Примечание: одна из веских причин заключается в том, что вы не доверяете строке, которую собираетесь выполнить. Можно надеяться, что это уже верно, но оболочка сделает с этой строкой «больше», чем наивный разделитель пробелов, и, таким образом, откроет больше дыр в безопасности, если вы не будете осторожны.)

10
ответ дан 5 December 2019 в 08:24
поделиться

Комбинация строкового метода c_str () и strtok () для разделения его на пробелы должна дать вам массив строк, который необходимо передать в exec () и связанные с ней функции.

2
ответ дан 5 December 2019 в 08:24
поделиться

Возможно split_winmain из Boost.ProgramOptions. Boost - хороший выбор в большинстве случаев. http://www.boost.org/doc/libs/1_40_0/doc/html/program_options/howto.html#id1396212

Если вас интересует только Windows (другие ядра обычно не знают о команде строк в смысле Windows), вы можете использовать функцию API CommandLineToArgvW , которая использует те же соглашения, что и среда выполнения MS C.

В целом это зависит от стиля цитирования платформы и / или оболочки . Среда выполнения Microsoft C использует совершенно другой стиль, чем, например, bash!

1
ответ дан 5 December 2019 в 08:24
поделиться

Это вариант ответа litb, но без ручного выделения памяти. Он по-прежнему не обрабатывает цитирование.

#include <vector>
#include <string>
#include <sstream>

std::string cmd = "mycommand arg1 arg2";
std::istringstream ss(cmd);
std::string arg;
std::list<std::string> ls;
std::vector<char*> v;
while (ss >> arg)
{
   ls.push_back(arg); 
   v.push_back(const_cast<char*>(ls.back().c_str()));
}
v.push_back(0);  // need terminating null pointer

execv(v[0], &v[0]);

Я чувствую себя немного грязным по поводу const_cast <>, но программы действительно не должны изменять содержимое строк argv.

1
ответ дан 5 December 2019 в 08:24
поделиться

Вы можете использовать функцию c_str () std :: string для преобразования в char *. Функция strtok разделит строку с помощью разделителя "".

0
ответ дан 5 December 2019 в 08:24
поделиться

LIBTINYC Мэтта Пейтрека имеет модуль argcargv.cpp, который принимает строку и преобразует ее в массив аргументов с учетом аргументов в кавычках. Обратите внимание, что он специфичен для Windows, но довольно прост, поэтому его должно быть легко перейти на любую платформу, которую вы хотите.

Если вы это сделаете, также измените его так, чтобы он принимал в качестве параметров loaction, чтобы поместить счетчик, и указатель на argv вместо использования externs (просто мой небольшой совет). Мэтту это не понадобилось, потому что LIBTINYC был средой выполнения.

Кроме того, вы можете посмотреть в исходном коде времени выполнения вашего компилятора (почти все его предоставляют), чтобы увидеть, что они делают для синтаксического анализа командной строки, и либо вызвать это напрямую (если это окажется возможным) или позаимствуйте идеи из этого фрагмента кода.

0
ответ дан 5 December 2019 в 08:24
поделиться

Хорошо, Я сам достаточно раз наталкивался на это. Это прямой "C", поэтому его можно подключить как к C, так и к C ++. Он по-разному обрабатывает строки с одинарными и двойными кавычками. Вызывающий отвечает за освобождение argv [0] (если не NULL) и argv.

#include 
#include 
#include 
#include 

typedef enum {
    STR2AV_OK       = 0,
    STR2AV_UNBALANCED_QUOTE
} str_to_argv_err_t;

#ifndef NUL
#define NUL '\0'
#endif

static char const nomem[] = "no memory for %d byte allocation\n";

static str_to_argv_err_t
copy_raw_string(char ** dest_p, char ** src_p);

static str_to_argv_err_t
copy_cooked_string(char ** dest_p, char ** src_p);

static inline void *
Xmalloc(size_t sz)
{
    void * res = malloc(sz);
    if (res == NULL) {
        fprintf(stderr, nomem, sz);
        exit(EXIT_FAILURE);
    }
    return res;
}

static inline void *
Xrealloc(void * ptr, size_t sz)
{
    void * res = realloc(ptr, sz);
    if (res == NULL) {
        fprintf(stderr, nomem, sz);
        exit(EXIT_FAILURE);
    }
    return res;
}

str_to_argv_err_t
string_to_argv(char const * str, int * argc_p, char *** argv_p)
{
    int     argc = 0;
    int     act  = 10;
    char ** res  = Xmalloc(sizeof(char *) * 10);
    char ** argv = res;
    char *  scan;
    char *  dest;
    str_to_argv_err_t err;

    while (isspace((unsigned char)*str))  str++;
    str = scan = strdup(str);

    for (;;) {
        while (isspace((unsigned char)*scan))  scan++;
        if (*scan == NUL)
            break;

        if (++argc >= act) {
            act += act / 2;
            res  = Xrealloc(res, act * sizeof(char *));
            argv = res + (argc - 1);
        }

        *(argv++) = dest = scan;

        for (;;) {
            char ch = *(scan++);
            switch (ch) {
            case NUL:
                goto done;

            case '\\':
                if ( (*(dest++) = *(scan++)) == NUL)
                    goto done;
                break;

            case '\'':
                err = copy_raw_string(&dest, &scan);
                if (err != STR2AV_OK)
                    goto error_leave;
                break;

            case '"':
                err = copy_cooked_string(&dest, &scan);
                if (err != STR2AV_OK)
                    goto error_leave;
                break;

            case ' ':
            case '\t':
            case '\n':
            case '\f':
            case '\r':
            case '\v':
            case '\b':
                goto token_done;

            default:
                *(dest++) = ch;
            }
        }

    token_done:
        *dest = NUL;
    }

done:

    *argv_p = res;
    *argc_p = argc;
    *argv   = NULL;
    if (argc == 0)
        free((void *)str);

    return STR2AV_OK;

error_leave:

    free(res);
    free((void *)str);
    return err;
}

static str_to_argv_err_t
copy_raw_string(char ** dest_p, char ** src_p)
{
    for (;;) {
        char ch = *((*src_p)++);

        switch (ch) {
        case NUL: return STR2AV_UNBALANCED_QUOTE;
        case '\'':
            *(*dest_p) = NUL;
            return STR2AV_OK;

        case '\\':
            ch = *((*src_p)++);
            switch (ch) {
            case NUL:
                return STR2AV_UNBALANCED_QUOTE;

            default:
                /*
                 * unknown/invalid escape.  Copy escape character.
                 */
                *((*dest_p)++) = '\\';
                break;

            case '\\':
            case '\'':
                break;
            }
            /* FALLTHROUGH */

        default:
            *((*dest_p)++) = ch;
            break;
        }
    }
}

static char
escape_convt(char ** src_p)
{
    char ch = *((*src_p)++);

    /*
     *  Escape character is always eaten.  The next character is sometimes
     *  treated specially.
     */
    switch (ch) {
    case 'a': ch = '\a'; break;
    case 'b': ch = '\b'; break;
    case 't': ch = '\t'; break;
    case 'n': ch = '\n'; break;
    case 'v': ch = '\v'; break;
    case 'f': ch = '\f'; break;
    case 'r': ch = '\r'; break;
    }

    return ch;
}


static str_to_argv_err_t
copy_cooked_string(char ** dest_p, char ** src_p)
{
    for (;;) {
        char ch = *((*src_p)++);
        switch (ch) {
        case NUL: return STR2AV_UNBALANCED_QUOTE;
        case '"':
            *(*dest_p) = NUL;
            return STR2AV_OK;

        case '\\':
            ch = escape_convt(src_p);
            if (ch == NUL)
                return STR2AV_UNBALANCED_QUOTE;
            /* FALLTHROUGH */

        default:
            *((*dest_p)++) = ch;
            break;
        }
    }
}
1
ответ дан 5 December 2019 в 08:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: