/
driver.c
executable file
·244 lines (210 loc) · 8.46 KB
/
driver.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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
#include <stdio.h>
#include <string.h>
#include "filesystem.h"
#include "memory-checking.h"
/* This driver uses some features of C I/O that won't be explained in the
* course. You don't need to read or to understand this code (unless you
* want to).
*
* Note that it imposes a limit of 511 characters for an input line, and 80
* characters for any individual argument. These limits are NOT part of
* your code- the project does not specify any maximum length for an
* argument- but are just part of this driver.
*
* Lastly note that the project tests may or may not use this driver (or
* some may and some might not).
*/
#define LINE_MAX 512
#define WORD_MAX (80 + 1)
static int command_idx(char name[]);
/* these are all the commands the driver recognizes, which include a few that
are not functions appearing in filesystem.h */
enum COMMANDS {LOGOUT, EXIT, MKFS, TOUCH, MKDIR, CD, LS, PWD, RM, RENAME, RMFS,
SET, UNSET} commands;
static char *command_names[]= {"logout", "exit", "mkfs", "touch", "mkdir",
"cd", "ls", "pwd", "rm", "rename", "rmfs",
"set", "unset"};
/* convert command names to indices that match the value of one of the enum
constants in COMMANDS; an unrecognized command name results in -1 being
returned */
static int command_idx(char name[]) {
int i= 0, pos= -1;
while (i < sizeof(command_names) / sizeof(command_names[0]) && pos == -1)
if (strcmp(name, command_names[i]) == 0)
pos= i;
else i++;
/* returns -1 if the command name was not found */
return pos;
}
int main() {
Filesystem filesystem;
char line[LINE_MAX]= "", command[WORD_MAX]= "", temp[WORD_MAX],
arg1[WORD_MAX]= "", arg2[WORD_MAX]= "", prompt[WORD_MAX]= "%";
int verbose= 0, length= 0, num_matched= 0, argument_error, done= 0;
setup_memory_checking();
printf("%s ", prompt);
/* continue reading lines until the end of the input */
while (!done && fgets(line, sizeof(line) - sizeof(*line), stdin) != NULL) {
temp[0]= '\0';
sscanf(line, "%[ \t\n]%n", temp, &length);
if (strcmp(temp, "") != 0 && length == strlen(temp))
printf("%s ", prompt); /* ignore empty input lines */
else {
/* num_matched is the number of format specifiers that were matched */
num_matched= sscanf(line, "%s %s %s %s", command, arg1, arg2, temp);
if (verbose == 1)
printf("%s", line);
/* argument_error will be 1 if the wrong number of arguments are
given for any command */
argument_error= 0;
switch(command_idx(command)) {
case LOGOUT:
case EXIT:
if (num_matched == 1)
done= 1; /* also quit if the command entered is logout or
exit */
else argument_error= 1;
break;
/* call mkfs() if the line began with "mkfs" with no following
arguments */
case MKFS:
if (num_matched == 1)
mkfs(&filesystem);
else argument_error= 1;
break;
/* call touch() if the line began with "touch" and had one
following argument; if touch() returns -1 print an appropriate
error message */
case TOUCH:
if (num_matched != 2)
argument_error= 1;
else
if (touch(&filesystem, arg1) == -1)
printf("Missing or invalid operand.\n");
break;
/* call mkdir() if the line began with "mkdir" and had one
following argument; if mkdir() returns -1 or -2 print an
appropriate error message */
case MKDIR:
if (num_matched != 2)
argument_error= 1;
else
switch (mkdir(&filesystem, arg1)) {
case -1: printf("Missing or invalid operand.\n");
break;
case -2: printf("Cannot create directory %s: File exists.\n",
arg1);
break;
default: break; /* no-op; 0 return is expected */
}
break;
/* call cd() if the line began with "cd" and had one following
argument; if cd() returns -1 or -2 print an appropriate error
message */
case CD:
if (num_matched != 1 && num_matched != 2)
argument_error= 1;
else
switch (cd(&filesystem, arg1)) {
case -1: printf("%s: No such file or directory.\n", arg1);
break;
case -2: printf("%s: Not a directory.\n", arg1);
break;
default: break; /* no-op; 0 return is expected */
}
break;
/* call ls() if the line began with "ls" and had one following
argument; if ls() returns -1 print an appropriate error
message */
case LS:
if (num_matched != 1 && num_matched != 2)
argument_error= 1;
else
if (ls(filesystem, arg1) == -1)
printf("%s: No such file or directory.\n", arg1);
break;
/* call pwd() if the line began with "pwd" with no following
arguments */
case PWD:
if (num_matched == 1)
pwd(filesystem);
else argument_error= 1;
break;
/* call rm() if the line began with "rm" and had one following
argument; if rm() returns -1, -2, or -3 print an appropriate
error message */
case RM:
if (num_matched != 2)
argument_error= 1;
else
switch (rm(&filesystem, arg1)) {
case -1: printf("%s: No such file or directory.\n", arg1);
break;
case -2: printf("Cannot remove directory '%s'.\n", arg1);
break;
case -3: printf("Missing or invalid operand.\n");
break;
default: break; /* no-op; 0 return is expected */
}
break;
/* call re_name() if the line began with "rename" with two
following arguments; if it returns an error code (-1 through
-4) print an appopriate error message */
case RENAME:
if (num_matched != 3)
argument_error= 1;
else
switch (re_name(&filesystem, arg1, arg2)) {
case -1: printf("%s: No such file or directory.\n", arg1);
break;
case -2: printf("Missing or invalid operand.\n");
break;
case -3: printf("File or directory %s already exists.\n",
arg1);
break;
case -4: printf("%s and %s are the same file.\n", arg1, arg2);
break;
default: break; /* no-op; 0 return is expected */
}
break;
/* call rmfs() if the line began with "rmfs" with no following
arguments */
case RMFS:
if (num_matched == 1)
rmfs(&filesystem);
else argument_error= 1;
break;
/* the variable verbose is set to 1 if the "set verbose" command
is entered. */
case SET:
if (num_matched == 2 && strcmp(arg1, "verbose") == 0)
verbose= 1;
else argument_error= 1;
break;
/* the variable verbose is set to 0 if "unset verbose" is
entered. */
case UNSET:
if (num_matched == 2 && strcmp(arg1, "verbose") == 0)
verbose= 0;
else argument_error= 1;
break;
/* error message for a command not matching one of the function
names */
default: printf("%s: Command not found.\n", command);
break;
}
/* error message for a command with the wrong number of arguments */
if (argument_error)
printf("Invalid arguments.\n");
if (verbose == 1)
printf("\n");
printf("%s ", prompt);
/* sscanf() will fail if the line read is empty, in which case the
prior command will be executed again unless it's first cleared
out */
arg1[0]= arg2[0]= command[0]= '\0';
}
}
check_memory_leak();
return 0;
}