我正在为程序创建一个shell接口,起初我使用getline
结合strtok
来分割用户条目,但这不是一个很好的选择,因为如果引用了一个带引号的字符串,它将是在多个参数中分割,或者如果引用的字符串中存在空格,它们将被忽略。此外,我想实现shell的一些基本功能,如快捷方式Ctrl-L
,用于清除shell。
所以我决定使用termios
并以shell方式创建我自己的输入函数。
现在代码看起来像
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>
char *read_cmdline() {
struct termios oldt;
struct termios newt;
tcgetattr(STDIN_FILENO, &oldt); /*store old settings */
newt = oldt; /* copy old settings to new settings */
newt.c_lflag &= ~(ICANON | ECHO); /* make one change to old settings in new settings */
tcsetattr(STDIN_FILENO, TCSANOW, &newt); /*apply the new settings immediatly */
char *line = malloc(128);
int end_of_line = 0;
char c, y, z;
unsigned lus = 0;
unsigned size = 128;
while (!end_of_line) {
if (lus+1 == size) {
size *= 2;
line = realloc(line, size);
}
c = getc(stdin);
switch (c)
{
case 27:
y = getchar();
switch (y)
{
case 91:
z = getchar();
switch (z)
{
case 65:
printf("up arrow key pressed\n");
continue;
case 66:
printf("down arrow key pressed\n");
continue;
case 67:
printf("right arrow key pressed\n");
continue;
case 68:
printf("left arrow key pressed\n");
continue;
}
break;
}
case 12:
system("clear");
break;
}
if (c >= 32 && c <= 126) {
putchar(c);
line[lus++] = c;
}
else if (c == 13)
end_of_line = 1;
}
tcsetattr(STDIN_FILENO, TCSANOW, &oldt); /*reapply the old settings */
return line;
}
尚未实现解析,只是实现了快捷Ctrl-L
的基本字符串读取。
如何在字符串中进行左/右箭头导航?
编辑:我有一个实现,现在可以浏览一个sigle行,但是多行不能用于该代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <termios.h>
#define MIN_SIZE 128
char *line = NULL;
static unsigned pos = 0;
static int size;
static int b_size;
static unsigned length = 0;
char *buff = NULL;
static unsigned b_pos = 0;
static unsigned b_length = 0;
void insert(char c)
{
if (pos == length) {
++length;
if (length == size) {
size *= 2;
line = realloc(line, size);
}
line[pos++] = c;
}
else {
++length;
if (length == b_size) {
b_size = size;
size *= 2;
buff = realloc(buff, size);
}
strncpy(buff, line, pos);
strncpy(&buff[pos+1], &line[pos], length-pos);
buff[pos++] = c;
char *temp = buff;
buff = line;
line = temp;
}
}
int move_cursor(int delta) {
int pos2 = pos + delta;
if (pos2 >= 0 && pos2 <= length) {
pos = pos2;
return 1;
}
else
return 0;
}
int backspace() {
if (pos == 0)
return 0;
else {
strncpy(&line[pos-1], &line[pos], length - pos);
--pos;
--length;
return 1;
}
}
int suppr() {
if (pos == length)
return 0;
else {
strncpy(&line[pos], &line[pos+1], length-pos);
--length;
}
}
char *read_cmdline() {
if (line == NULL)
line = malloc(MIN_SIZE);
if (buff == NULL)
buff = malloc(MIN_SIZE);
struct termios oldt;
struct termios newt;
tcgetattr(STDIN_FILENO, &oldt); /*store old settings */
newt = oldt; /* copy old settings to new settings */
newt.c_lflag &= ~(ICANON | ECHO); /* make one change to old settings in new settings */
tcsetattr(STDIN_FILENO, TCSANOW, &newt); /*apply the new settings immediatly */
int end_of_line = 0;
char c, y, z;
while (!end_of_line) {
c = getc(stdin);
switch (c)
{
case 127:
backspace();
putchar('\b');
case 27:
y = getchar();
switch (y)
{
case 91:
z = getchar();
switch (z)
{
case 65:
printf("up arrow key pressed\n");
continue;
case 66:
printf("down arrow key pressed\n");
continue;
case 67:
printf("right arrow key pressed\n");
continue;
case 68:
printf("\033[1D");
move_cursor(-1);
continue;
}
break;
}
case 12:
system("clear");
break;
}
if (c >= 32 && c <= 126) {
insert(c);
printf("\033[%dD", length);
printf("%s", line);
if (pos < length)
printf("\033[%dD", length-pos);
}
else if (c == 13)
end_of_line = 1;
}
tcsetattr(STDIN_FILENO, TCSANOW, &oldt); /*reapply the old settings */
return line;
}
问题是我如何在while循环中实现打印,我应该恢复终端大小并打印到这个大小...这是一个棘手的问题!我没有提到我不想在我的项目中添加依赖项,因此不允许使用ncurses,但它是一个UNIX项目,所以不需要平台兼容性。 (是curses标准吗?)