Reputation: 165
I'm writing a program to execute Unix commands with any amount of arguments. I have no problem receiving input and making tokens as I use regular strings. However, execvp will only accept an array of pointers and I'm not sure how to go about converting the array of strings to this. Here's what I have:
#include <cstring>
#include <iostream>
#include <sstream>
#include <string>
#include <unistd.h>
int main()
{
while (true)
{
int argc = 0;
std::istringstream iss;
std::string command;
std::cout << "$> ";
getline(std::cin, command);
iss.str(command);
for (unsigned i = 0; i <= command.length(); i++)
{
if (command[i] == ' ' || command[i] == '\0')
{
argc++;
}
}
std::string arr[argc+1];
for (int i = 0; i < argc; i++)
{
iss >> arr[i];
}
if (arr[0].compare("quit"))
{
break;
}
else
{
char*argv[argc+1];
for (int i = 0; i < argc; i++)
{
argv[i] = arr[i].c_str(); //This line is wrong
}
argv[argc] = NULL;
execvp(argv[0], argv);
}
}
return 0;
}
I've tried various methods and can't figure out how to convert a string to a char array in the proper manner. Methods like strcpy won't work because the length of each argument will vary. Any help would be greatly appreciated.
Upvotes: 3
Views: 3025
Reputation: 904
You have very small mistakes.
Replace:
argv[i] = arr[i].c_str();
with argv[i] = const_cast<char*>(arr[i].c_str());
if(arr[0].compare("quit"))
with if(!arr[0].compare("quit"))
And you are good to go, and this would work in any compiler.
Run here
But I have some advice to make it using fork so it won't run only one command at a time.
Example here
Upvotes: 2
Reputation: 7737
You can ensure null
terminator at the end of each string in the array this way:
for (int i = 0; i < argc; i++)
{
iss >> arr[i];
arr[i].push_back('\0');
}
Then you can simply capture pointer to the first character of each string. Clean and safe, without any const_cast
:
for (int i = 0; i < argc; i++)
{
argv[i] = &arr[i][0];
}
Upvotes: 0
Reputation: 13993
Your problem is that your array is holding char*
, while std::string::c_str()
returns const char*
. It can't be stored in your array, because it would lose const-ness.
If you're using a C++11 compliant compiler, you can use &arr[i][0]
to obtain a non-const pointer to the internal string buffer.
If you aren't using a C++11 compliant compiler, the internal buffer may not be null-terminated, so your only option is to use new
or malloc
to allocate correctly sized buffers, then strcpy
the strings into them.
char* buffer = new char[arr[i].length() + 1];
strcpy(buffer, arr[i].c_str());
argv[i] = buffer;
Upvotes: 1