欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 美食 > NR_shell运行流程简析

NR_shell运行流程简析

2025/1/26 14:05:02 来源:https://blog.csdn.net/sinat_34467747/article/details/145357128  浏览:    关键词: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 的运作流程,以及新指令的添加。注:特殊指令,比如:方向键等未做分析。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com