-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathprase.c
225 lines (215 loc) · 6.54 KB
/
prase.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
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "prase.h"
// Initialize a command
// Precondition: none
// Postcondition: a initialized CMD
static CMD InitializeCommand()
{
CMD command = NULL;
command = (CMD)malloc(sizeof(struct Command));
// if malloc failed
if (command == NULL)
{
Error("Cannot allocate space");
return NULL;
}
// initialize process
command->cmd = NULL;
command->argv = NULL;
command->argc = 0;
command->in = NULL;
command->out = NULL;
command->append = false;
command->background = false;
}
// Initialize a CommandLine
// Precondition: none
// Postcondition: a initialized CMDL
static CMDL InitializeCommandLine()
{
CMDL cmdl = NULL;
cmdl = (CMDL) malloc(sizeof(struct CommandLine));
cmdl->command = NULL;
cmdl->size = 0;
}
// read a line
// Precondition: none
// Postcondition: return a line of string, NULL for error
static char *ReadLine()
{
char *buffer = (char *)malloc(sizeof(char) * MAX_LINE);
size_t n = 0;
int pos = 0;
char ch = '\0';
// cannot allocate space for buffer
if (buffer == NULL)
{
Error("Cannot allocate new space");
return NULL; // emergency return an empty line
}
// read till meeting with a new line or end of file or exceeding the line limit
while ((ch = fgetc(stdin)) != '\n' && ch != EOF && pos < MAX_LINE - 1)
{
buffer[pos++] = ch;
}
if (ch == EOF)
exit(EXIT_SUCCESS);
buffer[pos] = '\0';
// command too long
if (pos == MAX_LINE - 1)
{
// prompt the error
Error("Command is too long");
// free the space and return instantly with NULL
free(buffer);
return NULL;
}
return buffer;
}
// split a line of string by the delimiter DELIM
// Precondition: a line of string
// Postcondition: array of string
static char **SplitToken(char *line)
{
char *token = NULL;
char **tokens = (char **)malloc(sizeof(char *) * MAX_TOKEN);
int position = 0;
// cannot allocate space for token
if (!tokens)
{
Error("Cannot allocate new space");
return NULL; // emergency return
}
// delimit
token = strtok(line, DELIMIT);
while (token != NULL && position < MAX_TOKEN - 1)
{
tokens[position++] = token;
token = strtok(NULL, DELIMIT);
}
tokens[position] = NULL;
// if too many commands a line
if (position == MAX_TOKEN - 1)
{
Error("Line has too many commands");
// free(tokens);
return NULL;
}
return tokens;
}
// split tokens into commands
// precondition: tokens
// postcondition: commands
static CMDL SplitCommand(char **tokens)
{
int i;
int position = 0;
CMD commandList[MAX_TOKEN] = {NULL}; // temporarily store the cmd
CMD command = NULL;
char* argumentList[MAX_TOKEN] = {NULL}; // temporarily store the arguments
char* argument = NULL; // temporarily store the argument
bool begin = true; // mark whther the beginning of a command
bool redirect_out = false; // '>' or '>>'
bool redirect_in = false; // '<'
CMDL cmdl = NULL;
cmdl = InitializeCommandLine();
for (position = 0; position < MAX_TOKEN - 1 && tokens[position] != NULL; ++position)
{
if (begin)
{
begin = false;
// copy the arguments into the cmd for the fommer command
if (position != 0)
{
argumentList[command->argc++] = NULL;
command->argv = (char**) malloc(sizeof(char*) * command->argc);
for (i = command->argc - 1; i >= 0; --i)
{
command->argv[i] = argumentList[i];
}
commandList[cmdl->size++] = command;
// command = Initiali zeCommand();
}
// create a command
command = InitializeCommand();
command->cmd = (char*) malloc(sizeof(char) * (strlen(tokens[position]) + 1));
strcpy(command->cmd, tokens[position]);
}
if (redirect_out) // redirect out file
{
redirect_out = false;
command->out = (char*) malloc(sizeof(char) * (strlen(tokens[position]) + 1));
strcpy(command->out, tokens[position]);
continue;
}
if (redirect_in) // redirect in file
{
redirect_in = false;
command->in = (char*) malloc(sizeof(char) * sizeof(strlen(tokens[position]) + 1));
strcpy(command->in, tokens[position]);
continue;
}
if (!strcmp(tokens[position], "&")) // find &, run in the background
{
command->background = true;
begin = true;
continue;
}
if (!strcmp(tokens[position], ">") || !strcmp(tokens[position], ">>")) // find '>' or '>>', redirect out
{
redirect_out = true;
command->append = (strcmp(tokens[position], ">>") == 0);
continue;
}
if (!strcmp(tokens[position], "<")) // find '<', redirect in
{
redirect_in = true;
continue;
}
if (!strcmp(tokens[position], "|")) // find '|', pipe
{
command->pipe = true;
begin = true;
continue;
}
argument = (char*) malloc(sizeof(char) * (strlen(tokens[position] + 1))); // if normal string, then it's am argument
strcpy(argument, tokens[position]);
argumentList[command->argc++] = argument;
}
if (command) // if there is any command, copy it into coommandList
{
// the last command's arguments
commandList[command->argc++] = NULL;
command->argv = (char**) malloc(sizeof(char*) * command->argc);
for (i = command->argc - 1; i >= 0; --i)
{
command->argv[i] = argumentList[i];
}
commandList[cmdl->size++] = command;
// copy from commandList into CMDL
cmdl->command = (CMD*) malloc(sizeof(CMD) * cmdl->size);
for (i = 0; i < cmdl->size; ++i)
{
cmdl->command[i] = commandList[i];
}
}
return cmdl;
}
CMDL ReadCommand()
{
int i = 0;
char *line = NULL;
char **tokens = NULL;
CMDL commandList = NULL;
reading = true;
line = ReadLine(); // read form stdin
reading = false;
tokens = SplitToken(line); // split a stirng into different tokens
commandList = SplitCommand(tokens); // tokens to commands
// free no use space
free(line);
free(tokens);
return commandList;
}