Files
chat_rebot-connect-with-one…/c/tem/ctl.c
2025-10-01 19:30:44 +08:00

293 lines
7.8 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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;
}