当前位置: 首页 > news >正文

NR_shell运行流程简析

nr_shell 是一套开源 shell 框架,基于框架可创建终端交互功能。
为了记录终端输入指令,以及进行解析处理,nr_shell 提供了一套 cmd 结构体,具体如下:
typedef struct static_cmd_function_struct
{char cmd[NR_SHELL_CMD_NAME_MAX_LENGTH]void (*fp)(char argc, char *argv);char *description;
} static_cmd_st;typedef struct shell_history_queue_struct
{unsigned short int fp;unsigned short int rp;unsigned short int len;unsigned short int index;unsigned short int store_front;unsigned short int store_rear;unsigned short int store_num;char queue[NR_SHELL_MAX_CMD_HISTORY_NUM + 1];char buf[NR_SHELL_CMD_HISTORY_BUF_LENGTH + 1];
} shell_his_queue_t;typedef struct nr_shell
{char user_name[NR_SHELL_USER_NAME_MAX_LENGTH];const static_cmd_st *static_cmd;shell_his_queue_st cmd_his;
} shell_st;
nr_shell 启动后,shell_st 结构体将作为 nr_shell 的实例对象维护 nr_shell 的运行环境。
根据结构体可知 shell_st 结构将记录当前用户的名称,当前运行的指令,以及运行过的历史指令。当输入指令格式后,将通过 shell 函数进行解析处理。
对于指令的具体解析,nr_shell 提供了 ansi_st 进行处理。关于 ansi_st 结构体的作用如下:
ansi_st nr_ansi;typedef struct nr_ansi_struct
{short p;unsigned int counter;char current_line[NR_ANSI_LINE_SIZE];char combine_buf[NR_ANSI_CTRL_MAX_LEN];char cmd_num;char combine_state;
} ansi_st;//初始阶段,counter 代表指令格式字符串计数为0,p 代表当前字符索引为 -1,current_line 代表指令格式字符串
void ansi_init(ansi_st *ansi)
{ansi->counter = 0;		ansi->p = -1;ansi->current_line[ansi->counter] = '\0';ansi->cmd_num = 0;ansi->combine_state = ANSI_NO_CTRL_CHAR;
}
接下来是完整的字符串解析过程:
对输入的字符串逐字解析,首先判断其是否为特殊符号,比如:'\b','\n','\033' 等,若不是则进行通用处理,否则参考对应的处理办法处理。
#define shell(c)												\{															\if (ansi_get_char(c, &nr_ansi) == NR_SHELL_END_CHAR)	\{														\shell_parser(&nr_shell, nr_ansi.current_line);		\ansi_clear_current_line(&nr_ansi);					\}														\}char ansi_get_char(char x, ansi_st *ansi)
{int cmd_id = -1;if (ansi->combine_state == ANSI_NO_CTRL_CHAR)	{cmd_id = ansi_search_char(x, nr_ansi_in_special_symbol);if (cmd_id >= 0){if (nr_ansi_in_special_symbol_fun[cmd_id] != NULL){nr_ansi_in_special_symbol_fun[cmd_id](ansi);}}else if (x == '\033'){ansi->combine_state = ANSI_WAIT_CTRL_CHAR_END;ansi->combine_buf[ansi->cmd_num] = x;ansi->cmd_num++;}else{nr_ansi_common_char_slover(ansi, x);}}else if (ansi->combine_state == ANSI_WAIT_CTRL_CHAR_END){ansi->combine_buf[ansi->cmd_num] = x;if (('a' <= x && 'z' >= x) || ('A' <= x && 'Z' >= x) || x == '~'){cmd_id = ansi_search_char(x, nr_ansi_in_cmd);nr_ansi_in_cmd_fun[cmd_id](ansi);ansi->cmd_num = 0;anis->combine_state = ANSI_NO_CTRL_CHAR;}else if (ansi->cmd_num > 18){ansi->cmd_num = 0;ansi->combine_state = ANSI_NO_CTRL_CHAR;}else{ansi->cmd_num++;}}else {ansi->combine_state = ANSI_NO_CTRL_CHAR;}return x;
}int ansi_search_char(char x, const char *buf)
{int i = 0;for (i = 0; (buf[i] != x) && (buf[i] != '\0'); i++);if (buf[i] != '\0') {return i;}else {return -1;}
}void nr_ansi_common_char_slover(ansi_st *ansi, char x)
{unsigned int i;if (ansi->counter < NR_ANSI_LINE_SIZE - 2){//该判断条件的目的是将 '\0' 字符向后复制,空出中间字符添加新的字符if (ansi->p < ansi->counter)	{for (i = ansi->counter; i > ansi->p; i--){ansi->current_line[i] = ansi->current_line[i - 1];}}//当前字符位置与字符串个数自增ansi->p++;ansi->counter++;//添加输入的字符ansi->current_line[ansi->p] = x;//字符串添加结束标志符ansi->current_line[ansi->counter] = '\0'if (ansi->p + 1 < ansi->counter) {shell_printf("\033[1@");}#ifndef NR_MICRO_SHELL_SIMULATORansi_show_char(x);
#endif}	else{ansi->counter = NR_ANSI_LINE_SIZE - 3;if (ansi->p >= ansi->counter){ansi->p = ansi->counter - 1;}ansi->current_line[ansi->counter] = '\0';}
}void shell_parser(shell_st *shell, char *str)
{char argc = 0;char argv[NR_SHELL_CMD_LINE_MAX_LENGTH + NR_SHELL_CMD_PARAS_MAX_NUM];char *token = str;shell_fun_t fp;char index = NR_SHELL_CMD_PARAS_MAX_NUM;if (shell_his_queue_search_cmd(&shell->cmd_his, str) == 0 && str[0] != '\0'){shell_his_queue_add_cmd(&shell->cmd_his, str);}if (strlen(str) > NR_SHELL_CMD_LINE_MAX_LENGTH){shell_printf("this command is too long."NR_SHELL_NEXT_LINE);shell_printf("%s", shell->user_name);return;}token = nr_shell_strtok(token, " ");//从指令表中查看当前指令是否存在,因此需根据实际情况在指令表中添加fp = shell_search_cmd(shell, str);if (fp == NULL){if (isalpha(str[0])){shell_printf("no command named: %s"NR_SHELL_NEXT_LINE, token);}}else{argv[argc] = index;strcpy(argv + index, str);index += strlen(str) + 1;argc++;token = nr_shell_strtok(NULL, " ");//循环获取指令参数while (token != NULL){argv[argc] = index;strcpy(argv + index, token);index += strlen(token) + 1;argc++;token = nr_shell_strtok(NULL, " ");}}if (fp != NULL){fp(argc, argv);		//执行指令对应的函数接口}	
}
关于 nr_shell 对指令的支持,主要通过框架中的全局变量 nr_shell 完成。
新指令目前不支持接口添加,只能直接在数组表中直接添加。
shell_st nr_shell = {
{.user_name = NR_SHELL_USER_NAME,.static_cmd = nr_cmd_start_add;
};#define nr_cmd_start_add (&static_cmd[0])const static_cmd_st static_cmd[] =
{{"ls", shell_ls_cmd},{"test", shell_test_cmd},{"\0", NULL}
};
以上,就是对 nr_shell 框架的简单分析,只针对 nr_shell 的运作流程,以及新指令的添加。注:特殊指令,比如:方向键等未做分析。
http://www.lryc.cn/news/526927.html

相关文章:

  • CSS Fonts(字体)
  • 基于Django的Boss直聘IT岗位可视化分析系统的设计与实现
  • linux系统中的 scp的使用方法
  • x5music3.0 admin_index.php 后台权限绕过漏洞复现(附脚本)
  • 【单链表算法实战】解锁数据结构核心谜题——相交链表
  • Crewai框架添加日志功能
  • 【2025年数学建模美赛E题】(农业生态系统)完整解析+模型代码+论文
  • Linux(Centos、Ubuntu) 系统安装jenkins服务
  • 2013年蓝桥杯第四届CC++大学B组真题及代码
  • TDengine 做为 FLINK 数据源技术参考手册
  • 21.2、网络设备安全机制与实现技术
  • 数据结构:二叉树—面试题(二)
  • OFD、PDF 电子签章系统处理流程
  • 分布式微服务系统简述
  • 【Linux】列出所有连接的 WiFi 网络的密码
  • 电脑无法开机,重装系统后没有驱动且驱动安装失败
  • 基于SpringBoot格式化实体的时间类型以及静态注入依赖
  • 技术总结:FPGA基于GTX+RIFFA架构实现多功能SDI视频转PCIE采集卡设计方案
  • Flink读写Kafka(Table API)
  • 【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】1.2 ndarray解剖课:多维数组的底层实现
  • 冯诺依曼架构和哈佛架构的主要区别?
  • Gurobi基础语法之字典
  • ceph新增节点,OSD设备,标签管理(二)
  • 利用metaGPT多智能体框架实现智能体-2
  • Hadoop 与 Spark:大数据处理的比较
  • Django 日志配置实战指南
  • 传输层协议TCP与UDP:深入解析与对比
  • doris:JSON导入数据
  • Ubuntu18.04 搭建DHCP服务器
  • Spring Boot 邂逅Netty:构建高性能网络应用的奇妙之旅