-
Notifications
You must be signed in to change notification settings - Fork 0
/
mysh.c
172 lines (139 loc) · 4.63 KB
/
mysh.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
/// Author Owen Sullivan
/// File mysh.c
/// An implementation of a simple shell
#include <errno.h> // errno
#include <stdio.h> // printf
#include <string.h> //strtok, strcmp
#include <sys/wait.h> // wait
#include <sys/types.h> // pid
#include <unistd.h> // exec, fork
#include "trimit.h" // trim function
#include "history_queue.h" // all history queue functions and struct
#define _DEFAULT_SOURCE
#define QUIT 88
// prints out the history project
int mysh_history(History_Queue hq) {
hq_print(hq);
return 1;
}
// Executes a command from the history
int mysh_bang(History_Queue hq, long num) {
long low_index = hq->current_index;
long high_index = hq->last->current_index;
if(num >= low_index && num < high_index) {
handle_command(hq, hq_find_command(hq, num));
}
//TODO Handle this error somewhere, it is that the command isnt availble
return -1;
}
// This is the process that starts a new process and has the parent
// wait on the child to finish. Prints error and returns status
int mysh_external(int argc, char *argv[], int *verbose) {
pid_t pid = fork();
int status = 0;
if(pid == 0) {
if(*verbose) printf("execvp: %s\n", argv[0]);
status = execlp(argv[0], argv[0], argv[1], (char *)NULL);
if (status) perror("Error: ");
exit(status);
} else {
if(*verbose) printf("wait for pid %d: %s\n", pid, argv[0]);
wait(NULL);
}
}
// this function prints out the help message
int mysh_help(int argc, char *argv[]) {
printf("Welcome to mysh(ell)\n\nInternal Commands: \
\n\thelp - displays information about mysh and its functionality \
\n\tquit - exits the shell safely \
\n\t!n - reruns the command at the index n \
\n\thistory - prints out the last commands with its index next to it \
\n\tverbose [on/off] - turn verbose mode (more information) on or off\n \
\n\nAdditional information: \
\n\tExternal Commands- trigger commands exactly as you would in bash! \
\n\tAuthor - Owen Sullivan! \
\n\tContribution - Come find me on github! \
\n"
);
}
// This toggles the verbose mode or prints an error
int mysh_verbose(char *option, int *verbose) {
if (option == NULL) {
printf("usage: verbose on | off\n");
return 2;
} else if(!strncmp(option, "on", strlen(option))) {
*verbose = 1;
} else if(!strncmp(option, "off", strlen(option))) {
*verbose = 0;
} else {
printf("usage: verbose on | off\n");
return 2;
}
return 1;
}
// This is the general function that parses the command
// And then sends it to the correct funtion to run
int handle_command(History_Queue hq, char *command, int *verbose) {
if(*verbose) printf("command: %s\n", command);
char *token = strtok(command, " ");
int status = 0;
if (token == NULL) {
return 1;
} else if (!strcmp("history", token)) {
status = mysh_history(hq);
} else if (!strcmp("quit", token)) {
return QUIT;
} else if (!strcmp("help", token)) {
status = mysh_help(0, NULL);
} else if (!strncmp("verbose", token, strlen(token))) {
status = mysh_verbose(trim(strtok(NULL, " ")), verbose);
} else if (token[0] == '!') {
long num = strtol(token+1, NULL, 10);
status = mysh_bang(hq, num);
} else {
char *argv[2];
argv[0] = token;
argv[1] = strtok(NULL, "");
status = mysh_external(2,argv, verbose);
}
if(*verbose) printf("command status: %d\n", status);
}
// Controls the main loop of the shell
// Changes things based on the input flags
int main( int argc, char * argv[] ) {
int should_continue = 1;
char *line = NULL;
size_t length = 0;
ssize_t nread;
int opt;
int verbose = 0;
int history = 10;
while((opt = getopt(argc, argv, "h:v")) != -1) {
switch (opt) {
case 'v':
verbose = 1;
break;
case 'h':
history = (int) strtol(optarg, NULL, 10);
break;
}
}
// TODO implement the flags
History_Queue hq = NULL;
printf("mysh[0]> ");
while (nread = getline(&line, &length, stdin) != -1) {
char *trimmed = trim(line);
if(hq == NULL) {
hq = hq_create(history, 0, trimmed);
} else {
hq = hq_add(hq, trimmed);
}
int status = handle_command(hq, trimmed, &verbose);
if(status == QUIT) {
free(trimmed);
break;
}
printf("mysh[%lu]> ", hq->last->current_index + 1);
}
hq_free_all(hq);
}