-
Notifications
You must be signed in to change notification settings - Fork 0
/
shell.c
126 lines (103 loc) · 2.69 KB
/
shell.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
//
// shell.c
// yxsh
//
// Created by Kirill on 14.03.2018.
// Copyright © 2018 Kirill. All rights reserved.
//
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <readline/readline.h>
#include <readline/history.h>
#include "executor.h"
#include "parseline.h"
#include "shell.h"
#include "tasks.h"
#define INPUT_BUFF 1024
#define PROMPT_PREFIX "[yx!>"
#define PROMPT_SUFFIX "]> "
static bool form_prompt(char*);
static void print_prompt();
static void child_update_signal_handler(int);
static void resetup_signals();
static void shell_add_history(char*);
static tasks_env_t environment;
int main(int argc, char* argv[]) {
commandline_t commandline;
char prompt[INPUT_BUFF];
char* line;
int ncmds;
tasks_create_env(&environment);
resetup_signals();
while (form_prompt(prompt) && (line = readline(prompt)) != NULL) {
if ((ncmds = parseline(line, &commandline)) > 0) {
shell_add_history(line);
if (!execute(&environment, &commandline)) {
free_cmds_strings(&commandline, ncmds);
tasks_collect_zombies(&environment);
tasks_release_env(&environment);
free(line);
clear_history();
exit(0);
}
free_cmds_strings(&commandline, ncmds);
}
free(line);
tasks_collect_zombies(&environment);
resetup_signals();
}
return 0;
}
static void shell_add_history(char* cmd) {
HIST_ENTRY* tmp = previous_history();
if (!tmp) {
add_history(cmd);
return;
}
if (!strcmp(tmp->line, cmd)) {
tmp = remove_history(where_history());
free_history_entry(tmp);
}
add_history(cmd);
}
static void resetup_signals() {
signal(SIGINT, SIG_IGN);
signal(SIGTSTP, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
signal(SIGCHLD, &child_update_signal_handler);
}
static bool form_prompt(char* prompt) {
char path[INPUT_BUFF];
char* home;
if (getcwd(path, sizeof(path)) == NULL) {
perror("yxsh: Cannot read current path");
return false;
}
if (!(home = getenv("HOME"))) {
fprintf(stderr, "yxsh: Home path variable is not set.");
return false;
}
if (!strncmp(path, home, strlen(home))) {
memcpy(path + 1, path + strlen(home), strlen(path) - strlen(home) + 1);
path[0] = '~';
}
if (snprintf(prompt, INPUT_BUFF, "%s%s%s", PROMPT_PREFIX, path, PROMPT_SUFFIX) <= 0) {
fprintf(stderr, "yxsh: Cannot form prompt.");
return false;
}
return true;
}
static void print_prompt() {
char prompt[INPUT_BUFF];
if (!form_prompt(prompt))
exit(-1);
write(STDOUT_FILENO, prompt, strlen(prompt));
}
static void child_update_signal_handler(int sig) {
if (tasks_update_status(&environment))
print_prompt();
}