在C ++中模仿shell参数解析器 [英] Mimicking the shell argument parser in C++

查看:132
本文介绍了在C ++中模仿shell参数解析器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在研究一个模拟shell终端的程序,我遇到了比我预想的更难实现的问题。基本上,我试图拆分参数,很像shell如何传递给它的可执行文件。所以,想象一个输入像:



$> ./foo一些参数



我们期望传递给程序的参数是一个类似的数组(假设C / C ++) p>

char ** argv = {foo,somearguments}



但是,如果参数是:



$> ./foo我的名字是foobar



数组将是:



char ** argv = {foo,我的名字是foo,bar}



任何人都可以建议一个有效的方法来实现这个,这样的界面是:



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



我可以,当然,只是迭代和阅读单词/阅读引用的文本的状态之间切换,但我觉得这不是有效的,因为它可能是。我也玩弄了regex的想法,但我不太熟悉如何这在C ++中完成。对于这个项目,我确实已经安装了boost库,如果这有帮助。



谢谢!
RR

解决方案

我有时候仍然使用这个简单的C效用函数。我大多在嵌入式系统中使用这个标准库,所以大多数代码可以更改为使用标准的lib控件更高效,但基本技术应该保持不变,标记引用的字符串的部分在分析之前,然后通过拆分标记分解单独的标记中的字符串,最后消除单个部分的报价。

  / ** 
*将一行分成单独的单词。
* /
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;
}



/ **
*将一行分成多个参数。
*
* @param io_pLine要分解的行。
* @param o_pArgc找到的组件数。
* @param io_pargc个别组件的数组
* /
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);

//保护引号内的空格,但不输入引号
for(i = 0; i< len; i ++){
if((!quoted)&& ;(''== io_pLine [i])){
quoted = 1;
io_pLine [i] ='';
} else if((quotated)&& ''== io_pLine [i])){
quoted = 0;
io_pLine [i] ='';
} else if((quotated)&&(''== 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 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 if('\1'== o_pArgv [j] [i]){
o_pArgv [j] [i ] ='';
}
}
}
}


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 split arguments, much like how the shell does to pass to its executable. So, imagining an input like:

$> ./foo some arguments

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

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

However, if the arguments were:

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

The array would be:

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

Can anyone suggest an efficient way to implement this, such that the interface is like:

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

I can, of course, simply iterate and switch between states of 'reading words'/'reading quoted text', but I feel that that's not as effective as it could be. I also toyed with the idea of regex, but I'm not familiar enough with how this is done in C++. For this project, I do have the boost libraries installed too, if that helps.

Thanks! RR

解决方案

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] = ' ';
            }
        }
    }
}

这篇关于在C ++中模仿shell参数解析器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆