/
main.c
172 lines (144 loc) · 3.5 KB
/
main.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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#include "header.h"
/* Steps:
1 - Fetch
2 - Tokenize
3 - Fork
4 - Exec
5 - Wait
*/
//// The important stuff! ////
int main(int argc, char *argv[])
{
FILE *input = stdin;
// Used to keep track of which buffer should be read in (added for scripting purposes)
char *tokens[100];
// An array storing argvs for the program to be executed
char commands[80]; // Stores the string entered on the 'command line'
// Note - command must be kept intact due to the way strtok functions!
int times_run = 0;
printf("Welcome to the terminal.\n");
catch_signals();
do
{
if (times_run >= 1)
{
commands[strlen(commands) - 1] = '\0';
tokenize(commands, tokens);
check_commands(tokens);
}
pid_t pid = fork();
if(pid > 0)
{ // Parent; prompt for new command
printf(">");
if (argc > 1 && times_run == 0)
{
FILE *script = fopen(argv[1], "r");
input = script;
times_run++;
continue;
}
int status;
wait(&status);
times_run++;
}
else if (pid == 0 && times_run >=1)
{ // This program is child process
if (execvp(tokens[0], tokens) == -1)
{
error("Unable to run command, please try again.");
}
}
else //if (pid < 0)
{ // Error, quit child process
exit(1);
}
} while (fgets(commands, 100, input) != NULL);
return 0;
}
void get_commands(char commands[80])
// Call this function to read in commands
{
}
int check_commands(char *tokens[100])
// Accepts a token array and checks to see if the command entered matches a built-in command.
// Returns a 1 (true) if the command is built in, otherwise returns 0 (false)
{
if (strcmp(tokens[0], "exit") == 0)
{ quit(); return 1; }
else if (strcmp(tokens[0], "cd") == 0)
{ chdir(tokens[1]); printf(">"); return 1; }
else return 0;
}
void tokenize(char commands[80], char *tokens[100])
// Takes a pointer to a space to store a token array and a pointer to the command string ,
// converts the command into tokens, and adds them into the token array.
{
int i = 0;
tokens[i] = strtok(commands, " ");
// Stores first command, ie program name
while(tokens[i])
{ // Fetches arguments
i++;
tokens[i] = strtok(NULL, " ");
}
}
/* void execute(char *tokens[100], int *argc, int *called_with_script)
// Takes an array of argvs and uses them to start a child process
{
pid_t pid = fork();
if (pid == 0)
{ // This program is child process
if (execvp(tokens[0], tokens) == -1)
{
error("Unable to run command, please try again.");
}
}
else if(pid > 0)
{ // Parent; prompt for new command
if (argc > 1) {
called_with_script = 1;
}
printf(">");
int status;
wait(&status);
}
else
{ // Error, quit child process
error("Unable to fork process.");
}
}
*/
//// Error handling and signal processing ////
void error(const char *error_message)
// Pass this function an error message to gracefully exit
{
fprintf(stderr, "%s: %s\n", error_message, strerror(errno));
exit(1);
}
void catch_signals()
{
if (catch_signal(SIGINT, graceful_exit) == -1)
{
puts("Error: Unable to map handler");
exit(2);
}
}
int catch_signal(int sig, void (*handler) (int))
{
struct sigaction action;
action.sa_handler = handler;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
return sigaction (sig, &action, NULL);
}
void graceful_exit(int sig)
{
puts("\nIgnored!");
}
void quit()
// Function to display "goodbye" message
// #TODO: Can this be combined with other exit handlers?
{
printf("Thanks for using the best terminal ever!\n");
exit(0);
}