编写解释器或更像是命令提示程序
我应该编写一个更像是命令提示符的解释程序。 这是一些背景信息:
General flow of basic interpreter 1. Prompt for user request. 2. Carry out the user request. 3. Unless user terminates the program, go to step 1. Run a command. Format: R command_path [arg1 to arg4] //a single character 'R' which stands for 'Run', followed by the path of the command //the user can supply up to 4 command line arguments Behavior: a. If command exist, run the command in a child process with the supplied command line arguments Wait until the child process is done b. Else print error message “XXXX not found”, where XXXX is the user entered command
例如
YWIMC > R /bin/ls a.out ex2.c ...... //output from the “ls” command YWIMC > R /bin/ls –l //same as executing “ls –l” total 144 -rwx------ 1 sooyj compsc 8548 Aug 13 12:06 a.out -rwx------ 1 sooyj compsc 6388 Aug 13 11:36 alarmClock .................... //other files not shown
我到目前为止的想法是,在文件路径中读取,读入参数,使用execv(filePath,args)。 但是,我无法得到循环和语法。
while(scanf("%s", args[i]) !=0) { //read in arguments i++; } execv(filePath,args);
这读取了无数个参数。 正如我所说,我不能正确的语法。 处理C中的字符串是这样的痛苦:(
重新编辑。 这是我目前的代码,相当不完整
#include #include //For stat() #include #include #include //for fork(), wait() int main() { char request, filePath[100]; int result, pathExist, childID, status; struct stat buf; //read user input printf("YWIMC > "); scanf("%c", &request); while (request != 'Q'){ //if 'Q' then just exit program // Handle 'R' request scanf("%s", &filePath); //Read the filePath/program name pathExist = stat(filePath, &buf); if(pathExist "); scanf("%c", &request); } printf("Goodbye!\n"); return 0; }
好吧,我想我终于明白你想做什么了。 要创建YWIMC
解释器环境并能够使用传递给execv
的命令处理执行中的命令和错误,以及在成功命令后返回到YWIMC
,您必须将对execv
的调用fork
到一个单独的进程防止execv
终止程序。
基本上,您使用外部while
循环创建YWIMC
shell,在每次迭代while
显示提示并读取命令行( cmdline
)。 在循环中,分离命令行的最简单方法是使用下面使用的strtok
或strsep
( strtok
)。 您可以通过在for
循环中调用strtok
来简化该过程:
for (p = strtok (line, " \n"); p && i < MAXA - 1; p = strtok (NULL, " \n")) cmdline[i++] = strdup (p);
注意: strtok
会修改原始字符串,因此您必须复制该字符串才能提供包含原始命令行的error
消息。
如果用户输入请求R
作为第一个令牌并且它至少有一个附加参数,那么您将fork
该过程。 在子( pid == 0
)中,您将正确的/path/to/command
和参数传递给execv
。 传递正确命令和参数的最简单方法是创建指向cmdline
的第二个元素的指针args
(以便从传递给execv
的数组中有效地丢弃R
)。 如果将错误的命令传递给execv
您还需要为子进程提供一种退出方式(否则用户会想知道为什么在传递错误命令后必须输入q
两次才能退出。)
此时,执行命令execv
执行,或者在失败时提供错误。 当用户输入q
,shell将需要释放strdup
分配的所有内存,然后退出。
尝试以下内容,让我知道我是否终于理解了您的尝试。 如果您有任何疑问,请告诉我。
#include #include #include #include #include #include /* MAXC - maximum characters that can be entered by user at prompt MAXA - maximum arguments to read (R + path + 1 2 3 4 + NULL) */ #define MAXC 256 #define MAXA 7 void trimcrnl (char *s); int main (void) { char line[MAXC] = {0}; printf ("\n Entering 'YWIMC' environment\n" " usage: R command_path [arg1 to arg4]\n" " ('q' to quit).\n\n"); while (printf ("YWIMC > ") && fgets (line, MAXC, stdin)) { if (*line == 'q') break; if (*line != 'R') continue; trimcrnl (line); /* strip newline from end of line */ char *p = line; char *cmdline[MAXA] = {NULL}; char **args = &cmdline[1]; char *err = strdup (line); int i = 0, nargs = 0, status = 0; pid_t pid; /* parse line into separate tokens (arguments) */ for (p = strtok (line, " \n"); p && i < MAXA - 1; p = strtok (NULL, " \n")) cmdline[i++] = strdup (p); nargs = i; /* save the number of arguments found */ if (nargs < 2) continue; #ifdef DEBUG /* output command line & arguments read */ for (i = 0; i < nargs; i++) printf (" cmdline[%d] = %s\n", i, cmdline[i]); for (i = 0; i < nargs - 1; i++) printf (" args[%d] = %s\n", i, args[i]); #endif if ((pid = fork ()) == -1) { fprintf (stderr, "error: fork failed returning -1.\n"); exit (EXIT_FAILURE); } if (pid == 0) { /* child process */ /* call execv (NOTE: you must provide a full-path to the program being executed, eg /usr/bin/ls) */ if (execv (args[0], args) == -1) fprintf (stderr, "error: '%s' not found.\n", err); _exit (EXIT_FAILURE); } waitpid (pid, &status, 0); } return 0; } /* strip newline or carriage return from string 's' */ void trimcrnl (char *s) { if (!s) return; size_t len = strlen (s); while (len > 0 && (s[len-1] == '\n' || s[len-1] == '\r')) s[--len] = 0; }
编
$ gcc -Wall -Wextra -o bin/execvargs execvargs.c
或者在启用调试输出的情况下编译:
$ gcc -Wall -Wextra -o bin/execvargs execvargs.c -DDEBUG
使用/输出
$ ./bin/execvargsfile Entering 'YWIMC' environment usage: R command_path [arg1 to arg4] ('q' to quit). YWIMC > anything not starting with 'R' YWIMC > R badpath badcommand error: 'R badpath badcommand' not found. YWIMC > R /bin/ls /home/david/cnf/LVM Lvm.pdf YWIMC > R /bin/ls -al /home/david/cnf/LVM total 380 drwxr-xr-x 2 david david 4096 May 21 22:22 . drwxr-xr-x 41 david david 4096 Aug 27 17:58 .. -rw-r--r-- 1 david david 380862 May 21 22:22 Lvm.pdf YWIMC > q