编写解释器或更像是命令提示程序

时间:2015-09-12 03:09:30

标签: c command-prompt execv

我应该编写一个更像是命令提示符的解释程序。这是一些背景信息:

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

E.g。

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 <stdio.h>
#include <fcntl.h>      //For stat()
#include <sys/types.h>   
#include <sys/stat.h>
#include <unistd.h>     //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  < 0)  {   
            printf("%s not found\n", filePath);
        }
        else    {
            result = fork();
            if(result != 0) {   //Parent Code
                childID = wait(&status);
            }
            else    {   //Child Code
                if(strcmp(filePath, "/bin/ls") == 0)    {
                    execl("/bin/ls", "ls", NULL); //change to execv
                }                                 //with the use of a 2D
                                                  //string array
                else    {  //same for this
                    execl(filePath, NULL);
                }
                return 256;
            }
        }


        fflush(stdin);      //remove all left over inputs

        printf("YWIMC > ");
        scanf("%c", &request);
    }

    printf("Goodbye!\n");
    return 0;

}

1 个答案:

答案 0 :(得分:4)

好吧,我想我终于明白你想做什么了。创建YWIMC解释器环境,并能够使用传递给command not found的命令处理执行中的execv和错误,并在成功后返回YWIMC命令,您必须fork调用execv到单独的进程,以防止execv终止该程序。

基本上,您创建YWIMC shell,其外部while循环显示提示并在每次迭代时读取命令行(cmdline)。在循环中,分隔命令行的最简单方法是使用下面使用的strtokstrsepstrtok)。您可以通过在strtok循环中调用for来简化该过程:

    for (p = strtok (line, " \n"); 
            p && i < MAXA - 1;
            p = strtok (NULL, " \n"))
        cmdline[i++] = strdup (p);

注意: strtok修改原始字符串,因此您必须复制字符串才能提供包含原始命令行的error消息。< / p>

如果用户输入请求R作为第一个令牌且至少有一个附加参数,则fork进程。pid == 0。在孩子(/path/to/command)中,您将正确的execv和参数传递给args。传递正确命令和参数的最简单方法是创建指向cmdline的第二个元素的指针R(以便execv从传递给{{的数组中被有效地丢弃1}})。在将错误命令传递给execv的情况下,您还需要为子进程提供一种退出的方法(否则用户会想知道为什么他们必须输入q两次才能在错误命令输出后退出通过。)

此时,执行命令最多为execv,或者失败时提供错误。当用户输入q时,shell将需要释放strdup分配的所有内存,然后退出。

尝试以下操作,让我知道我是否终于理解了您的尝试。如果您有任何问题,请告诉我。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

/* 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, e.g. /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