293 lines
7.8 KiB
C
293 lines
7.8 KiB
C
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <fcntl.h>
|
||
#include <unistd.h>
|
||
#include <stddef.h>
|
||
#include <string.h>
|
||
#include <termios.h>
|
||
#include <pthread.h>
|
||
#include <signal.h>
|
||
|
||
#include "ctl.h"
|
||
|
||
#include "interpreter/interpreter.h"
|
||
#include "tools/log/log.h"
|
||
|
||
static void goto_col(int x)
|
||
{
|
||
char seq[32];
|
||
int n = snprintf(seq, sizeof(seq), "\r\033[%dC", x+1); /* 1-based */
|
||
write(STDOUT_FILENO, seq, n);
|
||
}
|
||
|
||
int replace_chars(int start_pos, int old_len, const char *new_str) {
|
||
// 1. 移动光标到起始位置
|
||
if(new_str == NULL)
|
||
return -1;
|
||
char move_cmd[16];
|
||
int move_len = snprintf(move_cmd, sizeof(move_cmd), "\033[%dG", start_pos + 1); // ANSI 列从1开始
|
||
write(STDOUT_FILENO, move_cmd, move_len);
|
||
|
||
// 2. 写入新内容
|
||
int new_len = strlen(new_str);
|
||
write(STDOUT_FILENO, new_str, new_len-1);
|
||
|
||
// 3. 如果新内容比原内容短,删除剩余部分
|
||
if (new_len < old_len) {
|
||
write(STDOUT_FILENO, "\033[K", 3);
|
||
}
|
||
}
|
||
|
||
int take_history(Ctl *self,int *currant_index,int *length,char *buf,int toward)
|
||
{
|
||
if(toward ==1)
|
||
{
|
||
if(*currant_index>0)
|
||
(*currant_index)--;
|
||
else
|
||
*currant_index = HISTORY_BUF-1;
|
||
|
||
}
|
||
else if(toward == 0)
|
||
{
|
||
if(*currant_index <HISTORY_BUF-1)
|
||
(*currant_index)++;
|
||
else
|
||
*currant_index = 0;
|
||
}
|
||
|
||
if(self->history[*currant_index] == NULL){
|
||
*length = *length-2;
|
||
return 0;
|
||
}
|
||
replace_chars(sizeof(PROMPT)-1,*length,self->history[*currant_index]);
|
||
memcpy(buf,self->history[*currant_index],MAX_BUF);
|
||
buf[strlen(buf)-1] = '\0';
|
||
*length = strlen(buf);
|
||
return 0;
|
||
}
|
||
|
||
|
||
|
||
int del_char(int length, int index, char *buf)
|
||
{
|
||
int buf_idx = index - sizeof(PROMPT); // 待删字符在 buf 中的下标
|
||
|
||
if (length == index) // 行尾退格
|
||
{
|
||
write(STDOUT_FILENO, "\b \b", 3);
|
||
return 1;
|
||
}
|
||
|
||
int str_len = length - index;
|
||
char *new_str = (char*)malloc(str_len);
|
||
memcpy(new_str, &buf[buf_idx+2], str_len-1);
|
||
write(STDOUT_FILENO, new_str, str_len);
|
||
goto_col(length - 2);
|
||
write(STDOUT_FILENO, "\033[K", 3);
|
||
goto_col(index - 1);
|
||
char *restr = buf+index-sizeof(PROMPT)+1;
|
||
memcpy(restr,new_str,str_len);
|
||
free(new_str);
|
||
return 1;
|
||
}
|
||
|
||
|
||
int get_cursor(int *col)
|
||
{
|
||
int row;
|
||
struct termios old, tmp;
|
||
tcgetattr(STDIN_FILENO, &old);
|
||
tmp = old;
|
||
cfmakeraw(&tmp);
|
||
tcsetattr(STDIN_FILENO, TCSADRAIN, &tmp);
|
||
|
||
/* 发 DSR 查询:ESC [ 6 n */
|
||
write(STDOUT_FILENO, "\033[6n", 4);
|
||
|
||
/* 读应答,最大 16 字节足够:ESC [ rr ; cc R */
|
||
char buf[16] = {0};
|
||
int i = 0;
|
||
while (i < sizeof(buf) - 1) {
|
||
read(STDIN_FILENO, &buf[i], 1);
|
||
if (buf[i] == 'R') break;
|
||
++i;
|
||
}
|
||
buf[++i] = '\0';
|
||
|
||
tcsetattr(STDIN_FILENO, TCSADRAIN, &old); /* 恢复终端属性 */
|
||
|
||
/* 解析 ESC [ row ; col R */
|
||
if (sscanf(buf, "\033[%d;%dR",&row, col) != 2)
|
||
return -1;
|
||
return 0;
|
||
}
|
||
|
||
int read_line(char *buf,Ctl *self)
|
||
{
|
||
int length = 0;
|
||
char input_buf;
|
||
int cursor_index = 0;
|
||
int currant_index = self->index;
|
||
while(read(0,&input_buf,1)==1&&length<MAX_BUF)
|
||
{
|
||
switch (input_buf) {
|
||
case '\n':
|
||
buf[length++] = input_buf;
|
||
write(STDOUT_FILENO,"\n",1);
|
||
buf[length] = '\0';
|
||
return length;
|
||
|
||
//backspace
|
||
case 0x7F:
|
||
buf[length] = '\0';
|
||
if(length == 0)
|
||
break;
|
||
length--;
|
||
get_cursor(&cursor_index);
|
||
del_char(length+sizeof(PROMPT),cursor_index-1,buf);
|
||
break;
|
||
//方向键
|
||
case 0x41: case 0x42: case 0x43: case 0x44:
|
||
if (length >= 2 &&
|
||
buf[length - 1] == 0x5B &&
|
||
buf[length - 2] == 0x1B)
|
||
{
|
||
switch(input_buf)
|
||
{
|
||
case 0x41:
|
||
take_history(self,&currant_index,&length,buf,1);
|
||
break;
|
||
//一定记得加break!!!
|
||
case 0x42:
|
||
take_history(self,&currant_index,&length,buf,0);
|
||
break;
|
||
case 0x43:
|
||
get_cursor(&cursor_index);
|
||
length = length-2;
|
||
if(cursor_index == sizeof(PROMPT)+length)
|
||
{
|
||
break;
|
||
}
|
||
write(STDOUT_FILENO, "\x1b[C", 3);
|
||
break;
|
||
case 0x44:
|
||
get_cursor(&cursor_index);
|
||
length = length -2;
|
||
if(cursor_index == sizeof(PROMPT))
|
||
{
|
||
break;
|
||
}
|
||
write(STDOUT_FILENO, "\x1b[D", 3);
|
||
break;
|
||
|
||
}
|
||
break;
|
||
}
|
||
default:
|
||
write(STDOUT_FILENO, &input_buf, 1);
|
||
buf[length++] = input_buf;
|
||
cursor_index = length;
|
||
break;
|
||
}
|
||
|
||
}
|
||
if(length>=MAX_BUF)
|
||
{
|
||
perror("SYS:input pass edge");
|
||
}
|
||
|
||
}
|
||
|
||
int infifo(Ctl *self,const char *cmd)
|
||
{
|
||
if(self->history[self->index]!=NULL){
|
||
memcpy(self->history[self->index],cmd,MAX_BUF);
|
||
}
|
||
else{
|
||
self->history[self->index] = (char*)malloc(MAX_BUF*sizeof(char));
|
||
memcpy(self->history[self->index],cmd,MAX_BUF);
|
||
}
|
||
//存储命令历史s
|
||
if(self->index<HISTORY_BUF){
|
||
self->index++;
|
||
}
|
||
else{
|
||
self->index = 0;
|
||
}
|
||
|
||
}
|
||
|
||
int free_history(Ctl *self)
|
||
{
|
||
for(int i = 0;i<6;i++)
|
||
{
|
||
if(self->history[i]!=NULL)
|
||
{
|
||
free(self->history[i]);
|
||
}
|
||
}
|
||
return 1;
|
||
}
|
||
|
||
int teml(Ctl *self,int fifo[2])
|
||
{
|
||
char input[MAX_BUF] = {'\0'};
|
||
ctx *command = (ctx*)malloc(sizeof(ctx));
|
||
Cmd cmd_dir[10];
|
||
init_interpreter(cmd_dir,command,fifo);//初始化解释器
|
||
//创建线程用于定期清理日志
|
||
pthread_create(&self->logwathcher,NULL,self->logmanager->clear_log,self->logmanager);
|
||
command->statue = 0;
|
||
self->command = command;
|
||
do
|
||
{ //设置缓冲区,接收用户输入
|
||
write(STDOUT_FILENO,PROMPT,sizeof(PROMPT));
|
||
command->line = read_line(input,self);
|
||
if(command->line == -1)
|
||
perror("sys error");
|
||
//将用户输入入队
|
||
infifo(self,input);
|
||
memcpy(command->command,input,sizeof(input));
|
||
interpret(SIG_MOD,command,cmd_dir);
|
||
const char fexp[256] = {'\0'};
|
||
memcpy(&input,&fexp,MAX_BUF);
|
||
}while(command->statue == 0);
|
||
log_manager_stop(self->logmanager);
|
||
pthread_join(self->logwathcher,NULL);
|
||
//关闭log定期清理程序
|
||
close(fifo[0]);
|
||
|
||
close(fifo[1]);
|
||
free_history(self);
|
||
self->command = NULL;
|
||
free(command);
|
||
}
|
||
|
||
Ctl *init_tem(log_manager *logmanager)
|
||
{
|
||
//初始化终端对象
|
||
Ctl *tem = (Ctl*)malloc(sizeof(Ctl));
|
||
tem->run = teml;
|
||
tem->infifo = infifo;
|
||
tem->index = 0;
|
||
tem->logmanager = logmanager;
|
||
char *his_buf[HISTORY_BUF] = {NULL};
|
||
memcpy(tem->history,his_buf,HISTORY_BUF);
|
||
for(int i =0;i<6;i++)
|
||
{
|
||
tem->history[i] = NULL;
|
||
}
|
||
struct termios tio_setting;
|
||
tcgetattr(STDIN_FILENO,&tio_setting);
|
||
tio_setting.c_lflag &= ~(ICANON|ECHO);
|
||
tio_setting.c_cflag |=ISIG;
|
||
tio_setting.c_cc[VMIN] =1;
|
||
tio_setting.c_cc[VTIME] = 0;
|
||
tcsetattr(STDERR_FILENO,TCSAFLUSH,&tio_setting);
|
||
|
||
return tem;
|
||
}
|
||
|
||
|