I have been working on a program that mimics a shell terminal, and I\'ve come across an implementation issue that is harder than I anticipated. Basically, I\'m trying to spl
I sometimes still use this plain C utility function for this. I mostly use this on embedded systems where there is a very limited standard library, so most of the code can be changed to be more efficient using standard lib controls, but the basic technique should remain the same being, mark the quoted parts of the string prior to parsing, then just break up the string in separate tokens by splitting on the markers, and finally eliminate the quotes from the individual parts.
/**
* Split a line into separate words.
*/
static void splitLine(char *pLine, char **pArgs) {
char *pTmp = strchr(pLine, ' ');
if (pTmp) {
*pTmp = '\0';
pTmp++;
while ((*pTmp) && (*pTmp == ' ')) {
pTmp++;
}
if (*pTmp == '\0') {
pTmp = NULL;
}
}
*pArgs = pTmp;
}
/**
* Breaks up a line into multiple arguments.
*
* @param io_pLine Line to be broken up.
* @param o_pArgc Number of components found.
* @param io_pargc Array of individual components
*/
static void parseArguments(char *io_pLine, int *o_pArgc, char **o_pArgv) {
char *pNext = io_pLine;
size_t i;
int j;
int quoted = 0;
size_t len = strlen(io_pLine);
// Protect spaces inside quotes, but lose the quotes
for(i = 0; i < len; i++) {
if ((!quoted) && ('"' == io_pLine[i])) {
quoted = 1;
io_pLine[i] = ' ';
} else if ((quoted) && ('"' == io_pLine[i])) {
quoted = 0;
io_pLine[i] = ' ';
} else if ((quoted) && (' ' == io_pLine[i])) {
io_pLine[i] = '\1';
}
}
// init
MY_memset(o_pArgv, 0x00, sizeof(char*) * C_MAXARGS);
*o_pArgc = 1;
o_pArgv[0] = io_pLine;
while ((NULL != pNext) && (*o_pArgc < C_MAXARGS)) {
splitLine(pNext, &(o_pArgv[*o_pArgc]));
pNext = o_pArgv[*o_pArgc];
if (NULL != o_pArgv[*o_pArgc]) {
*o_pArgc += 1;
}
}
for(j = 0; j < *o_pArgc; j++) {
len = strlen(o_pArgv[j]);
for(i = 0; i < len; i++) {
if('\1' == o_pArgv[j][i]) {
o_pArgv[j][i] = ' ';
}
}
}
}
Just passing the whole string to the shell might suit your needs:
eg:
System("./foo some arguments");
This isn't the best solution though.
The better way seems to be write a parser to find each argument and pass it to a exec style function.