-1

I am building a command line tool and at the beginning whole line is a string. How could I convert:

  string text = "-f input.gmn -output.jpg";

into

  const char *argv[] = { "ProgramNameHere", "-f", "input.gmn", "-output.jpg" };
Rafał Rawicki
  • 22,324
  • 5
  • 59
  • 79
strausionok
  • 99
  • 1
  • 2
  • 7
  • 2
    Have you tried anything or do you want us to build the tool for you? – Luchian Grigore May 08 '12 at 20:23
  • 2
    For context: previous questions: http://stackoverflow.com/questions/10502516/how-to-call-correctly-getopt-function http://stackoverflow.com/questions/10498744/how-to-convert-string-into-char-array – Robᵩ May 08 '12 at 20:24
  • @user1020174: Time to pick up a good book. Asking questions on Q&A sites can get you so far, but you won't learn anything fundamental this way. – dreamlax May 08 '12 at 20:26
  • I'd note that the answers posted thus far as pretty simplistic. Just for example, you'll need to do more work to handle a command line with quotes on it that are (suppose to) keep multiple words together as a single argument. – Jerry Coffin May 08 '12 at 20:54
  • @kisplit: I didn't downvote, but I'd venture to guess that it appears that OP hasn't done anything on their own yet, and is looking to SO to provide a complete solution. [Stack Overflow is not your personal research assistant](http://meta.stackexchange.com/a/128553/142865) – John Dibling May 08 '12 at 21:00
  • @kisplit I agree with ~John Dibling. What I've seen with downvote and close votes on SO is that's its harsh on, "You didn't do enough work on your own before asking SO." – Marlin Pierce May 08 '12 at 21:08

2 Answers2

3

If I had to use getopt, and I knew I was starting with a white-space separated std::string, I'd do this:

#include <iostream>
#include <string>
#include <sstream>
#include <algorithm>
#include <iterator>
#include <vector>
#include <cassert>
#include <cstring>

int main() {

    https://stackoverflow.com/questions/236129/how-to-split-a-string-in-c

    // My input
    std::string sentence = "-f input.gmn -output.jpg";

    // My input as a stream
    std::istringstream iss(sentence);

    // Create first entry
    std::vector<std::string> tokens;
    tokens.push_back("ProgramNameHere");

    // Split my input and put the result in the rest of the vector
    std::copy(std::istream_iterator<std::string>(iss),
        std::istream_iterator<std::string>(),
        std::back_inserter(tokens));

    // Now we have vector<string>, but we need array of char*. Convert to char*
    std::vector<char *> ptokens;
    for(auto& s : tokens)
        ptokens.push_back(&s[0]);

    // Now we have vector<char*>, but we need array of char*. Grab array
    char **argv = &ptokens[0];
    int argc = ptokens.size();

    // Use argc and argv as desired. Note that they will become invalid when
    // *either* of the previous vectors goes out of scope.
    assert(strcmp(argv[2], "input.gmn") == 0);
    assert(argc == 4);

}

See also: Split a string in C++?


Postscript: In the solution I provided, I used two language features introduced in C++2011: range-based for loops and type inference.

This code fragment will only compile if your compiler supports thew new features:

    for(auto& s : tokens)
        ptokens.push_back(&s[0]);

If you have an older C++ compiler, you might need to rewrite it using C++2003 features:

    for(std::vector<string>::iterator it = tokens.begin(); it != tokens.end(); ++it)
        ptokens.push_back(it->c_str());

or

    for(std::vector<string>::size_type i = 0; i < tokens.size(); ++i)
        ptokens.push_back(tokens[i].c_str());
Community
  • 1
  • 1
Robᵩ
  • 163,533
  • 20
  • 239
  • 308
  • 1
    Actually, I'd encapsulate that whole mess into an object that held the vectors. Then I'd use `obj.argc` and `obj.argv` when I needed them. – Robᵩ May 08 '12 at 20:42
  • Thank You very much! While compilation these errors occur: `check3.cpp:29:15: error: ISO C++ forbids declaration of ‘s’ with no type [-fpermissive]` `check3.cpp:29:19: error: range-based-for loops are not allowed in C++98 mode` `check3.cpp:30:31: error: invalid types ‘int[int]’ for array subscript` – strausionok May 08 '12 at 21:06
  • 1
    @user1020174 : That makes sense. I used features available in the 2011 C++ standard, but unavailable in the 1998 or 2003 standards. Either you need to adjust your compiler flags to support the new features, or you need to re-write the for loop to use iterators. – Robᵩ May 09 '12 at 14:04
1

I would recommend using boost::program_options to parse your program's arguments.

Otherwise if you are using MSVC, you might want to use the built-in __argc and __argv.

There is no portable way to get your program's image name, so you cannot get that information out of nowhere if you dropped it in the first place by discarding your original argv argument.

You could use the C strtok function to split your arguments ... actually scratch that, just use boost::algorithm::split with any_of(' ').

Klemens Baum
  • 551
  • 3
  • 14
  • Tempting to minus you for mentioning the function that shall not be mentioned. – Edward Strange May 08 '12 at 20:27
  • You should generally avoid `strtok`, *especially* in a C++ program where you can trivially write your own splitter with the help of `std::string` and its various member functions. – dreamlax May 08 '12 at 20:31
  • 1
    I was listing it for completeness, but I guess I should have added a DO NOT USE disclaimer. ;) – Klemens Baum May 08 '12 at 20:34
  • 1
    If the OP is lost on basic string parsing we probably shouldn't bring boost into the mix just yet. – AJG85 May 08 '12 at 20:40