Question

I need to be able to parse the following two strings in my program:

cat myfile || sort
more myfile || grep DeKalb

The string is being saved in char buffer[1024]. What I need to end up with is a pointer to a char array for the left side, and a pointer to a char array for the right side so that I can use these to call the following for each side:

int execvp(const char *file, char *const argv[]); 

Anyone have any ideas as to how I can get the right arguments for the execvp command if the two strings above are saved in a character buffer char buffer[1024]; ?

I need char *left to hold the first word of the left side, then char *const leftArgv[] to hold both words on the left side. Then I need the same thing for the right. I have been messing around with strtok for like two hours now and I am hitting a wall. Anyone have any ideas?

Was it helpful?

Solution 3

In case this gives anyone else grief, this is how I solved the problem:

//variables for the input and arguments
char *command[2];
char *ptr;
char *LeftArg[3];
char *RightArg[3];

char buf[1024]; //input buffer

//parse left and right of the ||
number = 0;
command[0] = strtok(buf, "||");

//split left and right
while((ptr=strtok(NULL, "||")) != NULL)
{
    number++;
    command[number]=ptr;
}

//parse the spaces out of the left side
number = 0;
LeftArg[0] = strtok(command[0], " ");

//split the arguments
while((ptr=strtok(NULL, " ")) != NULL)
{
    number++;
    LeftArg[number]=ptr;
}

//put null at the end of the array
number++;
LeftArg[number] = NULL;

//parse the spaces out of the right side
number = 0;
RightArg[0] = strtok(command[1], " ");

//split the arguments
while((ptr=strtok(NULL, " ")) != NULL)
{
        number++;
        RightArg[number]=ptr;
}

//put null at the end of the array
number++;
RightArg[number] = NULL;

Now you can use LeftArg and RightArg in the command, after you get the piping right

execvp(LeftArg[0], LeftArg);//execute left side of the command

Then pipe to the right side of the command and do

execvp(RightArg[0], RightArg);//execute right side of command

OTHER TIPS

I recommend you to learn more about regular expressions. And in order to solve your problem painlessly, you could utilize the Boost.Regex library which provides a powerful regular expression engine. The solution would be just several lines of code, but I encourage you to do it yourself - that would be a good exercise. If you still have problems, come back with some results and clearly state where you were stuck.

You could use std::getline(stream, stringToReadInto, delimeter).

I personally use my own function, which has some addition features baked into it, that looks like this:

StringList Seperate(const std::string &str, char divider, SeperationFlags seperationFlags, CharValidatorFunc whitespaceFunc)
{
    return Seperate(str, CV_IS(divider), seperationFlags, whitespaceFunc);
}

StringList Seperate(const std::string &str, CharValidatorFunc isDividerFunc, SeperationFlags seperationFlags, CharValidatorFunc whitespaceFunc)
{
    bool keepEmptySegments     = (seperationFlags & String::KeepEmptySegments);
    bool keepWhitespacePadding = (seperationFlags & String::KeepWhitespacePadding);

    StringList stringList;

    size_t startOfSegment = 0;
    for(size_t pos = 0; pos < str.size(); pos++)
    {
        if(isDividerFunc(str[pos]))
        {
            //Grab the past segment.
            std::string segment = str.substr(startOfSegment, (pos - startOfSegment));
            if(!keepWhitespacePadding)
            {
                segment = String::RemovePadding(segment);
            }

            if(keepEmptySegments || !segment.empty())
            {
                stringList.push_back(segment);
            }

            //If we aren't keeping empty segments, speedily check for multiple seperators in a row.
            if(!keepEmptySegments)
            {
                //Keep looping until we don't find a divider.
                do
                {
                    //Increment and mark this as the (potential) beginning of a new segment.
                    startOfSegment = ++pos;

                    //Check if we've reached the end of the string.
                    if(pos >= str.size())
                    {
                        break;
                    }
                }
                while(isDividerFunc(str[pos]));
            }
            else
            {
                //Mark the beginning of a new segment.
                startOfSegment = (pos + 1);
            }
        }
    }

    //The final segment.
    std::string lastSegment = str.substr(startOfSegment, (str.size() - startOfSegment));
    if(keepEmptySegments || !lastSegment.empty())
    {
        stringList.push_back(lastSegment);
    }

    return stringList;
}

Where 'StringList' is a typedef of std::vector, and CharValidatorFunc is a function pointer (actually, std::function to allow functor and lambda support) for a function taking one char, and returning a bool. it can be used like so:

StringList results = String::Seperate(" Meow meow , Green, \t\t\nblue\n   \n, Kitties!", ',' /* delimeter */, DefaultFlags, is_whitespace);

And would return the results: {"Meow meow", "Green", "blue", "Kitties!"}

Preserving the internal whitespace of 'Meow meow', but removing the spaces and tabs and newlines surrounding the variables, and splitting upon commas.

(CV_IS is a functor object for matching a specific char or a specific collection of chars taken as a string-literal. I also have CV_AND and CV_OR for combining char validator functions)

For a string literal, I'd just toss it into a std::string() and then pass it to the function, unless extreme performance is required. Breaking on delimeters is fairly easy to roll your own - the above function is just customized to my projects' typical usage and requirements, but feel free to modify it and claim it for yourself.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top