我正在通过 git@github.com:brenns10/lsh 这个项目学习如何实现一个 Shell。今天为源码添加了第一遍注释。

还有很多问号hhh

/***************************************************************************//**@file         main.c@author       Stephen Brennan@date         Thursday,  8 January 2015@brief        LSH (Libstephen SHell)*******************************************************************************/#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>/*Function Declarations for builtin shell commands:*/
int lsh_cd(char **args);
int lsh_help(char **args);
int lsh_exit(char **args);/*List of builtin commands, followed by their corresponding functions.*/
char *builtin_str[] = {"cd","help","exit"
};int (*builtin_func[]) (char **) = {&lsh_cd,&lsh_help,&lsh_exit
};int lsh_num_builtins() {return sizeof(builtin_str) / sizeof(char *);
}/*Builtin function implementations.
*//**@brief Builtin command: change directory.@param args List of args.  args[0] is "cd".  args[1] is the directory.@return Always returns 1, to continue executing.*/
// lsh 内置的函数中,只有 cd 是执行了有效功能的(help 用来打印帮助,exit 用于退出)
// 看起来 cd 命令使用的是 chdir 函数实现的功能
// 在 chdir 函数执行失败时(返回值不为 0 时),还会调用 perror 来打印错误信息
// 该函数总是返回 1,这是因为每个 builtin_func 都应该返回 int 值,这一点在 lsh_execute 的注释中解释过
int lsh_cd(char **args)
{if (args[1] == NULL) {fprintf(stderr, "lsh: expected argument to \"cd\"\n");} else {// 这个 chdir 是外部函数,是哪个库中的?if (chdir(args[1]) != 0) {// 这个 perror 函数也是外部的,是哪个库中的?perror("lsh");}}return 1;
}/**@brief Builtin command: print help.@param args List of args.  Not examined.@return Always returns 1, to continue executing.*/
int lsh_help(char **args)
{int i;printf("Stephen Brennan's LSH\n");printf("Type program names and arguments, and hit enter.\n");printf("The following are built in:\n");for (i = 0; i < lsh_num_builtins(); i++) {printf("  %s\n", builtin_str[i]);}printf("Use the man command for information on other programs.\n");return 1;
}/**@brief Builtin command: exit.@param args List of args.  Not examined.@return Always returns 0, to terminate execution.*/
// lsh_exit 通过返回 0 来使 REPL 终止,原因在 lsh_execute 的注释中有解释
int lsh_exit(char **args)
{return 0;
}/**@brief Launch a program and wait for it to terminate.@param args Null terminated list of arguments (including program).@return Always returns 1, to continue execution.*/
int lsh_launch(char **args)
{pid_t pid;int status;// 这里使用 fork 克隆了一个子进程pid = fork();// 克隆成功(pid == 0)后,使用 execvp 函数执行参数列表// 这个 execvp 看来也是外部函数了。它可以调用将参数列表传给 bash 执行?// 不对,并不是“传给bash”,bash 脚本的重定向和管道功能,lsh 并不能使用。// 那么 execvp 的作用究竟是什么?if (pid == 0) {// Child processif (execvp(args[0], args) == -1) {perror("lsh");}exit(EXIT_FAILURE);} else if (pid < 0) {// 子进程 fork 失败,直接报错。// 话说,这个情况该怎么复现呢?怎么手动使子进程 fork 失败?// Error forkingperror("lsh");} else {// 这里处理 pid > 0 的情况,似乎在等待父进程?等待什么呢?// 等待的过程中,执行了 waitpid 函数,也是一个外部函数。// waitpid 函数会修改状态码 status,而 WIFEXITED 宏和 WIFSIGNALED 宏会检测 status// 这两个宏并没有在本文件中定义o,不过看起来是检测状态码是否代表 exited 和 signaled 的// Parent processdo {waitpid(pid, &status, WUNTRACED);} while (!WIFEXITED(status) && !WIFSIGNALED(status));}return 1;
}/**@brief Execute shell built-in or launch program.@param args Null terminated list of arguments.@return 1 if the shell should continue running, 0 if it should terminate该函数的返回值为 0 时,REPL 终止因此,无论它返回 1、函数指针还是其他非假值,REPL 都将继续*/
int lsh_execute(char **args)
{int i;// 没有输入if (args[0] == NULL) {// An empty command was entered.return 1;}// 遍历匹配命令// 命令的执行函数存放在一个函数指针数组 builtin_func 中,// 使用时只需要传入 args 就行for (i = 0; i < lsh_num_builtins(); i++) {if (strcmp(args[0], builtin_str[i]) == 0) {// 匹配到就调用对应的函数指针,这个函数指针显然是一定返回 int 值的return (*builtin_func[i])(args);}}// 没有匹配到就返回 lsh_launch 函数的返回值,这个函数返回一个 int 值// lsh_launch 函数似乎就是用来打印命令不存在的报错值的,为什么还需要传入 args ?为什么里面还需要开子进程?// 原来,没有匹配到内置命令,lsh_launch 就会将参数作为 bash 的命令运行,所以 pwd、cp、rm 这样的命令仍然可以在 lsh 中使用。// 但这是怎么做到的呢?return lsh_launch(args);
}/**@brief Read a line of input from stdin.@return The line from stdin.*/
char *lsh_read_line(void)
{
#ifdef LSH_USE_STD_GETLINEchar *line = NULL;ssize_t bufsize = 0; // have getline allocate a buffer for usif (getline(&line, &bufsize, stdin) == -1) {if (feof(stdin)) {exit(EXIT_SUCCESS);  // We received an EOF} else  {perror("lsh: getline\n");exit(EXIT_FAILURE);}}return line;
#else
#define LSH_RL_BUFSIZE 1024int bufsize = LSH_RL_BUFSIZE;int position = 0;char *buffer = malloc(sizeof(char) * bufsize);int c;if (!buffer) {fprintf(stderr, "lsh: allocation error\n");exit(EXIT_FAILURE);}while (1) {// Read a characterc = getchar();if (c == EOF) {exit(EXIT_SUCCESS);} else if (c == '\n') {buffer[position] = '\0';return buffer;} else {buffer[position] = c;}position++;// If we have exceeded the buffer, reallocate.if (position >= bufsize) {bufsize += LSH_RL_BUFSIZE;buffer = realloc(buffer, bufsize);if (!buffer) {fprintf(stderr, "lsh: allocation error\n");exit(EXIT_FAILURE);}}}
#endif
}#define LSH_TOK_BUFSIZE 64
#define LSH_TOK_DELIM " \t\r\n\a"
/**@brief Split a line into tokens (very naively).@param line The line.@return Null-terminated array of tokens.*/
char **lsh_split_line(char *line)
{int bufsize = LSH_TOK_BUFSIZE, position = 0;char **tokens = malloc(bufsize * sizeof(char*));char *token, **tokens_backup;if (!tokens) {fprintf(stderr, "lsh: allocation error\n");exit(EXIT_FAILURE);}token = strtok(line, LSH_TOK_DELIM);while (token != NULL) {tokens[position] = token;position++;if (position >= bufsize) {bufsize += LSH_TOK_BUFSIZE;tokens_backup = tokens;tokens = realloc(tokens, bufsize * sizeof(char*));if (!tokens) {free(tokens_backup);fprintf(stderr, "lsh: allocation error\n");exit(EXIT_FAILURE);}}token = strtok(NULL, LSH_TOK_DELIM);}tokens[position] = NULL;return tokens;
}/**@brief Loop getting input and executing it.*/
void lsh_loop(void)
{char *line;char **args;int status;do {printf("> ");line = lsh_read_line();args = lsh_split_line(line);status = lsh_execute(args);free(line);free(args);} while (status);
}/**@brief Main entry point.@param argc Argument count.@param argv Argument vector.@return status code*/
int main(int argc, char **argv)
{// Load config files, if any.// Run command loop.lsh_loop();// Perform any shutdown/cleanup.return EXIT_SUCCESS;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/934182.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!