[linux]C言語でLinuxのmyshellを実現
LinuxカーネルのShellコマンドライン解釈プログラムとしてC言語プログラムmyshellを作成し、以下の機能を実現します.
(1)ユーザーが提出したコマンドラインを解析する;環境変数に従ってディレクトリシステムを検索します.コマンドを実行します.バックグラウンドでコマンドを実行する場合は、「&」で終わります.
(2)ls,mkdir rmdir,pwd,psなどの内部コマンドを提供する.
(3)履歴照会機能を提供する.ユーザがCtrl+Cを押すと、信号プロセッサは最近の10個のコマンドリストを出力する.
(4)'r'は最近のコマンドを繰り返し実行し、履歴コマンドのリストが空の場合、ヒントを与える
(5)'r x'は、コマンドリストに存在しない場合にヒントを与えるように、文字xで始まる最近のコマンド(逆検索)を実行する
HNUers、先輩はあなたたちを助けるしかありません.終わりの記号を直すかもしれません.
(1)ユーザーが提出したコマンドラインを解析する;環境変数に従ってディレクトリシステムを検索します.コマンドを実行します.バックグラウンドでコマンドを実行する場合は、「&」で終わります.
(2)ls,mkdir rmdir,pwd,psなどの内部コマンドを提供する.
(3)履歴照会機能を提供する.ユーザがCtrl+Cを押すと、信号プロセッサは最近の10個のコマンドリストを出力する.
(4)'r'は最近のコマンドを繰り返し実行し、履歴コマンドのリストが空の場合、ヒントを与える
(5)'r x'は、コマンドリストに存在しない場合にヒントを与えるように、文字xで始まる最近のコマンド(逆検索)を実行する
HNUers、先輩はあなたたちを助けるしかありません.終わりの記号を直すかもしれません.
#include // to include printf
#include // to include struct sigaction handler
#include // to include the system function 'execvp'
#include // to include exit()
#include // to include pid_t
#include // to include wait()
#include // to include strcpy
#define BUFFERSIZE 50
#define MAXLINE 80
#define true 1
#define false 0
char buffer[BUFFERSIZE];
char historyCommands[10][81];
int currentCommandIndex = -1; // where to storage the current command
void printHis () {
int i = 0;
printf("
");
for (i = 0 ; i < 10 ; ++i) {
printf("%d : %s", i, historyCommands[i]);
}
}
void handle_SIGINTO() {
write(STDOUT_FILENO, buffer, strlen(buffer));
printHis();
}
void addHistory(char *inputBuffer) {
//add history into the message queue
currentCommandIndex = (currentCommandIndex + 1) % 10;
strcpy(historyCommands[currentCommandIndex], inputBuffer);
}
char* checkHis (char ch, int type) {
if (type == 3) {
int i = 0;
for (i = currentCommandIndex ; i >= 0 ; --i) {
if (historyCommands[i][0] == ch) {
return historyCommands[i];
}
}
for (i = 9 ; i >= currentCommandIndex ; --i) {
if (historyCommands[i][0] == ch) {
return historyCommands[i];
}
}
}
return NULL;
}
void setup(char inputBuffer[], char *args[],int *background) {
int i = 0;
int length = -1; // storage the length of the command
length = read(STDIN_FILENO, inputBuffer, MAXLINE);
inputBuffer[length] = '\0'; // read method don't add '\0' automatically
if (length == 0) {
exit(0);
}
else if (length == -1) {
args[0] = NULL;
return; // caught nothing, return
}
int currParamStartIndex = -1; // to storage the current parameters'
int currPos = 0; // args[currentPosition]
int copyFlag = false; // did not call r or 'r x'
char* pCommand = NULL;
if (inputBuffer[0] == 'r') {
// condition 3 : 'r
' get the most recent one
if (inputBuffer[1] == '
') {
if (currentCommandIndex == -1) {
printf("No valid commands
");
return;
}
else {
strcpy(inputBuffer, historyCommands[currentCommandIndex]);
copyFlag = true;
}
}
else if (inputBuffer[1] == ' ' && inputBuffer[2] != ' ') {
if ((pCommand = checkHis(inputBuffer[2], 3)) == NULL) {
printf("No recent valid commands begin with %c
", inputBuffer[2]);
return;
}
else {
strcpy(inputBuffer, pCommand);
copyFlag = true;
}
}
}
if (!copyFlag) {
addHistory(inputBuffer);
}
else {
length = strlen(inputBuffer);
addHistory(inputBuffer);
}
for (i = 0 ; i < length ; ++i) {
if (inputBuffer[i] == '&') {
*background = 1;
inputBuffer[i] = '\0';
}
else if (inputBuffer[i] == ' ' || inputBuffer[i] == '\t') {
if (currParamStartIndex != -1) {
args[currPos++] = &inputBuffer[currParamStartIndex];
inputBuffer[i] = '\0';
currParamStartIndex = -1;
}
}
else if (inputBuffer[i] == '
') { // end of the current command
if (currParamStartIndex != -1) {
args[currPos++] = &inputBuffer[currParamStartIndex];
inputBuffer[i] = '\0';
args[currPos] = NULL;
currParamStartIndex = -1;
}
}
else { // storage the valid phrase of the order
if (currParamStartIndex == -1) {
currParamStartIndex = i;
}
}
}
args[currPos] = NULL; // command length > MAX_LINE
}
int main() {
int i = 0;
for (i = 0 ; i < 10 ; i++) {
historyCommands[i][0] = '\0'; // Initailize the command Array
}
// create signal handler
struct sigaction handler;
handler.sa_handler = handle_SIGINTO;
sigaction(SIGINT, &handler, NULL);
char inputBuffer[MAXLINE+1]; // maximum for 80 characters
int background = 0;
char* args[MAXLINE/2 + 1];
while (true) {
background = 0; // default value to call wait(0)
printf("COMMAND->");
fflush(stdout); // print the order to the screen
setup(inputBuffer, args, &background);
pid_t pid = fork();
if (pid == -1) {
perror("fork");
exit(1); // exit the process by accident
}
if (pid == 0) { // child code
execvp(args[0], args);
exit(0); // exit the process simoutaneously
}
if (background == 0) {
wait(0);
}
}
return 0;
}