在c中读取shell的输入

时间:2016-05-21 21:13:04

标签: c shell

我正在编写一个不那么花哨但想要实现某些功能的shell。这是我目前的代码。

int readCommand(char * buffer, char * commandInput) {
    buf_chars = 0;
    char c;
    while((*commandInput != '\n') && (buf_chars < LINE_LEN)) {
        buffer[buf_chars++] = *commandInput;
        scanf("%c", &c);
        if(c==0x0C)
        {
            buffer[buf_chars] = '\0';
            printf("\033[2J\033[1;1H");//clear screen
            printf("%s",buffer);
            continue;
        }
        *commandInput = c;
    }
    buffer[buf_chars] = '\0';
    return 0;
}

应清除屏幕,然后打印当前输入的命令。我不知道我做错了什么。

2 个答案:

答案 0 :(得分:1)

这有几个问题。

  1. 为什么在世界上你想要清除屏幕以响应收到换页字符?这看起来非常随意。

  2. 如果您确实想要清除屏幕以响应该角色,那么可能会完成其工作。你为什么要把它复制到缓冲区?

  3. 更直接地转到您的问题,您似乎正在尝试输出ANSI转义序列。并非所有终端都认识到这些此外,

  4. stdout可能是行缓冲的,您编写的数据肯定不包含换行符。因此,缓冲区不太可能在此时刷新到输出设备。您可以在fflush()来电后stdout printf()来解决问题。

  5. 但是,您的第二个printf()有问题,因为您尚未确保已复制到缓冲区的数据以空值终止,并且printf()格式不包含字段在缓冲区结束之前停止的宽度。

答案 1 :(得分:0)

使用fgets(或getline)可以更好地完成shell的输入。然后你需要做的就是(1)验证fgets返回的指针(检查EOF),(2)检查缓冲区中的最后一个字符,以确定它是否为'\n'(否则发生短读,还有更多字符需要读取)和(3)在使用缓冲区作为命令之前从缓冲区末尾删除'\n'

您可以使用当前使用的相同代码长度完成所有三个。例如,您可以执行以下操作:

char *readcmd (char *buf, size_t max, FILE *fp)
{
    if (!buf)       /* validate buf not NULL */
        return NULL;

    char *p = NULL

    /* read input from fp, return NULL on EOF */
    if (!(p = fgets (buf, max, fp)))
        return NULL;

    /* find '\n' or nul-terminating char */
    for (; *p && *p != '\n'; p++) {}

    /* if not '\n' - short read occurred, read/discard remaining */
    if (*p != '\n')
    {
        int c;
        fprintf (stderr, "error: line too long, exceeds %zu chars.\n", max);

        /* read/discard chars reamining in buffer to '\n' */
        while ((c = fgetc (fp)) != '\n' && c != EOF) {}

        return NULL;
    }
    *p =  0;    /* overwrite '\n' with nul-terminating char */

    return buf;
}

注意:您可以更改对简短阅读的响应方式以满足您自己的需求。如果您动态分配buf,则可以{{ 1}}并继续阅读。您还可以查看使用realloc而不是getline,它将自动分配足够的内存来读取任何行,无论多长时间(可用内存的范围),但请考虑fgets的潜在问题 - 无论多长时间都会读取任何行< - >当用户输入时可能不是你想要的那样)

显示如何利用该函数为shell输入输入的简短示例可能是:

getline

提示用户输入#include <stdio.h> #include <string.h> #define MAXC 256 char *readcmd (char *buf, size_t max, FILE *fp); int main (int argc, char **argv) { char buf[MAXC] = ""; FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin; if (!fp) { fprintf (stderr, "error: file open failed '%s'.\n", argv[1]); return 1; } for (;;) { /* prompt & read command until 'quit or EOF */ printf ("> "); if (!readcmd (buf, MAXC, fp)) { /* EOF or short read */ putchar ('\n'); /* no '\n', so tidy up */ break; } if (!strcmp (buf, "quit")) /* 'quit' entered */ break; /* handle command here */ printf (" execute command : '%s'\n", buf); } if (fp != stdin) fclose (fp); /* close if not reading stdin */ return 0; } /* -- include readcmd definition here -- */ ,并将命令中的字符数限制为>(包括终止字符)。当256遇到readcmd或输入的字符太多(简短阅读)时,代码会退出。如果用户输入EOF,它也会退出。

处理密钥扫描码

如果要处理关键扫描代码,例如检测 Control + l ,则必须处理构成代码的整数值。有很多方法可以做到这一点,但基本方法是生成一个整数列表,组成系统上的多字节扫描代码,然后在代码中检查它们。这是通过向quit 5-int数组填充scncode读取的信息的最多5-int来完成的。然后,您可以检查整数代码与任何 Control,Shift,Alt等代码和字母使用的整数代码,以确定是否按下了已知的组合键。

Control + l(ell)提供fgets的单个整数扫描码组合。在单独接收 Control + l 作为输入时,将生成12的消息。

==> [ctrl + l (ell)] pressed.

仔细看看,如果您有任何问题,请告诉我。