C中我自己的Shell的历史问题

时间:2018-04-07 22:53:29

标签: c shell

作为一个项目,我必须制作自己的shell。我做到了,但我对历史记录功能有一些问题。

这是我的代码:

int main(int argc, char* argv[])
{
    char saisie[300], cwd[1024];
    char* nom = getenv("USER");
    char* backup[MAXCMD];
    int boucle = 1, n = 0, i, u = 0, b = 0;

    for(i = 0; i < MAXCMD; i++) 
    {
        backup[i] = NULL;
    }
    for(i = 0; i < MAX_INPUT_SZ; i++)
    {
        saisie[i] = 0;
    }
    char* cmd[MAXPARAMS];    //MAXPARAMS is 20

    while( boucle == 1)
    {   
        printf("%s@sam:~ %s> ", nom, (getcwd(cwd, sizeof(cwd))));
        fgets(saisie,MAX_INPUT_SZ,stdin);
        printf("\n");
        split_input(saisie, cmd);

        free(backup[u]);
        backup[u] = strdup(saisie);
        u = (u + 1) % MAXCMD;

        b = switchcmd(cmd,backup,b,u);
        start(cmd,b);
        b = 0;                      //débloquage fonction start
    }
    return 0;
}

我用这个功能打印历史记录:

int historique(char* backup[], int u)
{
    int i = u;
    int place = 1;
    do
    {
        if (backup[i])
        {
            printf("%4d:  %s\n", place, backup[i]);
            place++;
        }
        i = (i + 1) % MAXCMD;
    } while (i != u);
        return 0;   
}

B用于在用户输入“cd”或“history”时阻止执行功能(启动),因为它会产生错误。

这是用户输入“cd”,“history”或“exit”时触发的功能:

int switchcmd(char** cmd,char** backup, int b,int u)

{
    int i, n = 3, switch_value = 0;
    char* error;
    char* listcmd[n];
    listcmd[0] = "cd";
    listcmd[1] = "exit";
    listcmd[2]  = "history";

for (i = 0; i < n; ++i)
{
    if(strcmp(cmd[0], listcmd[i]) == 0)
    {
        switch_value = i + 1;
        break;
    }
}

switch (switch_value)
{
    case 1:
        chdir(cmd[1]);
        b = 1;
        error = strerror(errno);
        if (*error != 0)
        {
            printf("sam: %s: %s\n", cmd[0], error);
        }
        break;

    case 2:

        printf("Bye bye\n");
        exit(0);

    case 3:
        historique((char**)backup,u);
        b = 1;
        break;
}
return b;
}

当我执行我的shell并连续输入这些命令时,它们可以工作。的°I1

> clear    
> ls -a -l
> ls -a
> cd ..
> man chdir

然后打印历史的“历史”,我有:°i2

   1:  clear
   2:  ls
   3:  ls
   4:  cd
   5:  man
   6:  history

我希望此输出包含所有参数:°i3

1:  clear
2:  ls -a -l
3:  ls -a
4:  cd ..
5:  man chdir
6:  history`

我不知道为什么,我不明白为什么strdup不会在备份中复制我的cmd。

请帮忙吗?

1 个答案:

答案 0 :(得分:1)

  

当用户命令存储在&#39; saisie&#39;,此命令是重复的,并在参数数组中拆分。我使用&#39; cmd&#39;在执行功能中,使用execvp。

然后有一个大问题,cmd的固定长度为1,如果你用它来存储execvp的命令参数,那么你只能存储一件事:{{1} }。

您有两种选择:

  1. 使用较大的固定大小,例如NULL,您可以在其中存储 到99个参数,没有更多。这是最简单的解决方案,但不灵活 足够。虽然有些系统可以限制争论的数量 转到新流程,我不知道所有系统是否有限制, thisthis可能对您有帮助。

  2. 根据命令行动态创建char *cmd[100]指针数组。 这是更多的工作,但这也是更灵活的解决方案。假如说 您的命令行不支持管道(char)和重定向(|<<<>),然后>>可能如下所示:

    split_input

    现在您可以像这样使用它:

    char **split_input(const char *cmd)
    {
        if(cmd == NULL)
            return NULL;
    
        char **argv = NULL, **tmp;
    
        char *line = strdup(cmd);
        if(line == NULL)
            return NULL;
    
        const char *delim = " \t\n";
    
        char *token = strtok(line, delim);
        if(token == NULL)
        {
            free(line);
            return NULL;
        }
    
        size_t len = 0;
    
        do {
            char *arg = strdup(token);
            if(arg == NULL)
            {
                free_argv(argv);
                free(line);
                return NULL;
            }
    
            tmp = realloc(argv, (len + 2) * sizeof *argv);
    
            if(tmp == NULL)
            {
                free_argv(argv);
                free(line);
                return NULL;
            }
    
            argv = tmp;
            argv[len++] = arg;
            argv[len] = NULL; // argv must be NULL terminated
        } while(token = strtok(NULL, delim));
    
        free(line);
        return argv;
    }
    
    void free_argv(char **argv)
    {
        if(argv == NULL)
            return;
    
        for(size_t i = 0; argv[i]; ++i)
            free(argv[i]);
        free(argv);
    }
    
  3. 你也在做

    while( boucle == 1)
    {   
        printf("%s@sam:~ %s> ", nom, (getcwd(cwd, sizeof(cwd))));
        fgets(saisie,MAX_INPUT_SZ,stdin);
        printf("\n");
        char **argv = split_input(saisie);
    
        if(argv == NULL)
        {
            fprintf(stderr, "Cannot split command line, not enough memory\n");
            continue;
        }
    
        free(backup[u]);
        backup[u] = strdup(argv[0]); // <-- passing argv[0], not argv
                                     // but perhaps what you really want
                                     // is strdup(saisie)
        u = (u + 1) % MAXCMD;
    
        b = switchcmd(argv,backup,b,u);
        start(argv,b);
        b = 0;                      //débloquage fonction start
        free_argv(argv);
    }
    

    但问题是backup[u] = strdup(cmd); 是一个cmd指针数组,char期望一个 strdup,你传的错误类型。它应该是const char*strdup(cmd[0])如果你想存储整个命令。