Simulating shell arguments parser in C ++

I am working on a program that mimics a shell terminal, and I ran into an implementation problem that is harder than I expected. Basically, I am trying to separate the arguments, just as the shell goes to its executable. So, presenting the input as:

$> ./foo some arguments

One would expect the arguments passed to the program to be similar to an array (assuming C / C ++):

char ** argv = {"foo", "some" "arguments"}

However, if the arguments were:

$> ./foo "My name is foo" bar

The array will be:

char ** argv = {"foo", "My name is foo", "bar"}

Can anyone suggest an efficient way to implement this, so the interface looks like this:

vector<string> splitArgs(string allArgs); or string[] splitArgs(string allArgs);

Of course, I can simply iterate over and switch between the states of "reading words" / "reading quoted text", but I feel that it is not as effective as it could be. I also played with the idea of ​​regex, but I'm not good enough at how this is done in C ++. I also have boost libraries installed for this project, if that helps.

Thanks! Rr

+4
source share
2 answers

I sometimes still use this regular C function for this. I mainly use this on embedded systems where there is a very limited standard library, so most of the code can be modified to be more efficient using standard lib controls, but the main technique should remain the same, mark the quoted parts of the line before parsing , then simply break the string in separate tokens, breaking the markers and finally remove the quotation marks 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] = ' '; } } } } 
0
source

Just passing the entire line to the shell can suit your needs:

eg:

 System("./foo some arguments"); 

This is not the best option .

It is best to write a parser to find each argument and pass it an exec style function .

0
source

Source: https://habr.com/ru/post/1346505/


All Articles