我想特别了解这段代码的parse_args。这段代码就像pwd cat一样运行基本的linux命令等。我想了解parse_args是如何工作的。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#define BUFFER_SIZE 1<<16
#define ARR_SIZE 1<<16
void parse_args(char *buffer, char** args,
size_t args_size, size_t *nargs)
{
char *buf_args[args_size]; /* You need C99 */
char **cp;
char *wbuf;
size_t i, j;
wbuf=buffer;
buf_args[0]=buffer;
args[0] =buffer;
for(cp=buf_args; (*cp=strsep(&wbuf, " \n\t")) != NULL ;){
if ((*cp != '\0') && (++cp >= &buf_args[args_size]))
break;
}
for (j=i=0; buf_args[i]!=NULL; i++){
if(strlen(buf_args[i])>0)
args[j++]=buf_args[i];
}
*nargs=j;
args[j]=NULL;
}
int main(int argc, char *argv[], char *envp[]){
char buffer[BUFFER_SIZE];
char *args[ARR_SIZE];
int *ret_status;
size_t nargs;
pid_t pid;
while(1){
printf("$ ");
fgets(buffer, BUFFER_SIZE, stdin);
parse_args(buffer, args, ARR_SIZE, &nargs);
if (nargs==0) continue;
if (!strcmp(args[0], "exit" )) exit(0);
pid = fork();
if (pid){
printf("Waiting for child (%d)\n", pid);
pid = wait(ret_status);
printf("Child (%d) finished\n", pid);
} else {
if( execvp(args[0], args)) {
puts(strerror(errno));
exit(127);
}
}
}
return 0;
}
答案 0 :(得分:4)
这很有趣。该函数将缓冲区分隔为一个字符串数组,它会命中一个空格分隔符。
void parse_args(char *buffer, char** args,
size_t args_size, size_t *nargs)
{
char *buf_args[args_size]; /* You need C99 */
char **cp;
char *wbuf;
size_t i, j;
初始化代码......
wbuf=buffer;
buf_args[0]=buffer;
args[0] =buffer;
将所有指针设置为缓冲区的开头
for(cp=buf_args; (*cp=strsep(&wbuf, " \n\t")) != NULL ;){
cp
设置为指向buf_args数组中的第一个元素。将* cp设置为缓冲区中非空白字符的下一个实例,并将wbuf
前进到其结束位置
if ((*cp != '\0') && (++cp >= &buf_args[args_size]))
break;
当strsep
返回NULL时,或者当它指向缓冲区的末尾时,或者当它指向buf_args []
}
for (j=i=0; buf_args[i]!=NULL; i++){
if(strlen(buf_args[i])>0)
args[j++]=buf_args[i];
}
此循环创建buf_args []数组的精简副本:它仅复制非空字符串的参数。我想如果你的源缓冲区有一系列连续的空白字符,就会发生这种情况。
*nargs=j;
args[j]=NULL;
}
在输出数组的末尾放置一个NULL并设置nargs
输出参数。
答案 1 :(得分:3)
好的,让我们来看看解析args中的一些行
wbuf=buffer;
buf_args[0]=buffer;
args[0] =buffer;
这会将wbuf
设置为指向buffer
中的内容。它还将buf_args
数组中的第一个指针设置为buffer
。它也为args
的第一个元素做了同样的事情。
for(cp=buf_args; (*cp=strsep(&wbuf, " \n\t")) != NULL ;){
if ((*cp != '\0') && (++cp >= &buf_args[args_size]))
break;
}
函数strsep
通过wbuf
查找分隔符空格,换行符或制表符,并返回指向令牌开头的指针,并将wbuf
更新到令牌的末尾。如果字符串中没有更多分隔符,则函数返回NULL
。因此,for
语句的中间部分会一直持续到*cp
等于NULL
。
因此,指针cp
最初指向buf_args[0]
中的字符串(指针)。字符串分隔符函数使用令牌的地址填充*cp
。然后,if
语句检查1)for
循环是否已超过buf_args
的容量,检查指针cp
是否已超过最后一个元素,2)返回标记的第一个字符是字符串字符的结尾。
注意:我认为该行应为*(*cp) != '\0'
?
for (j=i=0; buf_args[i]!=NULL; i++){
if(strlen(buf_args[i])>0)
args[j++]=buf_args[i];
}
然后,它遍历所有buf_args
,直到找到NULL
个buf_args
。如果args
指向的字符串长于0,即它有字符,则数组*nargs=j;
args[j]=NULL;
将获得指向该标记的指针的副本。
args
填充条目后NULL
的最后一个元素设置为nargs
。并且args
的值设置为{{1}}数组中已填充元素数的长度。
答案 2 :(得分:2)
这段代码
for(cp=buf_args; (*cp=strsep(&wbuf, " \n\t")) != NULL ;){
if ((*cp != '\0') && (++cp >= &buf_args[args_size]))
break;
}
检查wbuf数组中的“\ n \ t”分隔符(首先是空格)并将其位置保存在buf_args中
for (j=i=0; buf_args[i]!=NULL; i++){
if(strlen(buf_args[i])>0)
args[j++]=buf_args[i];
}
部分将参数展开到args数组中以使结果脱离函数