我正在编写一个不那么花哨但想要实现某些功能的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;
}
应清除屏幕,然后打印当前输入的命令。我不知道我做错了什么。
答案 0 :(得分:1)
这有几个问题。
为什么在世界上你想要清除屏幕以响应收到换页字符?这看起来非常随意。
如果您确实想要清除屏幕以响应该角色,那么可能会完成其工作。你为什么要把它复制到缓冲区?
更直接地转到您的问题,您似乎正在尝试输出ANSI转义序列。并非所有终端都认识到这些此外,
stdout
可能是行缓冲的,您编写的数据肯定不包含换行符。因此,缓冲区不太可能在此时刷新到输出设备。您可以在fflush()
来电后stdout
printf()
来解决问题。
但是,您的第二个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.
仔细看看,如果您有任何问题,请告诉我。