-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathalias.c
More file actions
347 lines (299 loc) · 9.87 KB
/
alias.c
File metadata and controls
347 lines (299 loc) · 9.87 KB
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
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
#include "alias.h"
/**
* Creates a new alias list.
*
* @return An empty list of aliases
*/
Alias_List new_alias_list() {
Alias_List list = malloc(sizeof(Alias*));
*list = NULL;
return list;
}
/**
* Checks whether or not the alias list is empty.
*
* @param list The list to be checked
*/
int is_empty(Alias_List list) {
return *list == NULL;
}
/**
* Creates and returns a new instance of an alias.
*
* @param alias The aliased command
* @param replacement The command to be used in place of the alias
*/
Alias* new_alias(char* alias, char* replacement) {
Alias* new_alias = malloc(sizeof(Alias));
strcpy(new_alias->alias, alias);
strcpy(new_alias->replacement, replacement);
new_alias->next = NULL;
return new_alias;
}
/**
* Checks whether an alias is already present in the list of aliases.
*
* @param list The list of aliases to be searched
* @param alias The new alias to be searched for
* @return 1 if the alias is found, otherwise 0
*/
int alias_exists(Alias_List list, char* alias) {
/* If the list is empty, the alias does not exist */
if(is_empty(list)) {
return 0;
}
/* Loop through the list, if we find the alias, return 1 */
Alias* current = *list;
while(current) {
if(!strcmp(current->alias, alias))
return 1;
current= current->next;
}
/* If we didn't find the alias, return 0 */
return 0;
}
/**
* Takes in a new alias and command and adds them to the list of aliases.
*
* @param list The list of aliases in which to insert the new one.
* @param alias The aliased command
* @param replacement The command to be used in place of the alias
*/
void add_alias(Alias_List list, char* alias, char* replacement) {
/** If the alias is already present in the list, give an error
* If the alias is one of the alias commands, give an error
*/
if(alias_exists(list, alias)) {
printf("alias: %s: alias already exists\n(to replace this, first try \"unalias %s\")\n", alias, alias);
return;
}
else if(!strncmp(alias, "alias", 5) || !strncmp(alias, "unalias", 7)) {
printf("This name for an alias is not allowed!\n");
return;
}
/* Create a new alias and insert it at the front of the list */
Alias* new = new_alias(alias, replacement);
new->next = *list;
*list = new;
}
/**
* Deletes an alias from memory
*
* @param alias The alias to be deleted
*/
void delete_alias(Alias* alias) {
free(alias);
alias = NULL;
}
/**
* Searches for an alias in the list and removes it if found.
*
* @param list The list of aliases to be searched
* @param alias The alias to search for
*/
void remove_alias(Alias_List list, char* alias) {
/* If the list is empty, there is nothing to remove */
if(is_empty(list)) {
printf("List is empty no aliases to remove!\n");
return;
}
/* If the alias is at the start of the list,
* set the next alias to be the start of the list
* and delete the alias */
Alias* current = *list;
if(!strcmp(current->alias, alias)) {
*list = current->next;
delete_alias(current);
return;
}
while(current->next) {
/* If we find the alias anywhere else, remove it from the list
* by making the current node point to the node after it
* and deleting the alias */
if(!strcmp(current->next->alias, alias)) {
Alias* next_alias = current->next->next;
delete_alias(current->next);
current->next = next_alias;
return;
}
current = current->next;
}
/* If we didn't find the alias, print an error */
printf("unalias: %s: alias not found\n", alias);
}
/**
* Searches a command for instances of a given alias,
* and swaps out the alias with its replacement if found.
*
* @param alias The alias to search for instances of
* @param args The command and its arguments split into words
* @param user_input The user input to be returned if no alias was found
* @param alias_cmd The alias and its arguments to be stored
* @return The command, having been altered if the alias was found
*/
char* insert_alias(Alias* alias, char** args, char* user_input, char* command, char* alias_cmd) {
/* Buffer in which the command with the inserted alias will be stored */
static char buffer[4096];
/* Check if the user has entered an alias and replace the alias with the actual command, otherwise return the user input unchanged */
if(!strcmp(command, alias->alias)) {
strcpy(command, alias->replacement);
strcpy(buffer, alias->replacement);
}
else {
return user_input;
}
/* Concatenate the user arguments to the user input
* Create a string which stores the alias and its arguments for the history to show the alias used rather than the actual command
*/
strcpy(alias_cmd, alias->alias);
int i = 1;
if(args[i] != NULL) {
strcat(buffer, " ");
strcat(alias_cmd, " ");
}
while(args[i] != NULL){
strcat(buffer, args[i]);
strcat(alias_cmd, args[i]);
if(args[i + 1] == NULL) break;
strcat(buffer, " ");
strcat(alias_cmd, " ");
i++;
}
/* Add a new line at the end so that history is printed properly */
strcat(buffer, "\n");
strcat(alias_cmd, "\n");
/* If the alias, aliases an invocation do not add alias name in history */
if(alias->replacement[0] == '!') {
strcpy(alias_cmd, "");
}
return buffer;
}
/**
* Searches a command for instances of each known alias, in turn.
*
* @param list The list of aliases to be applied
* @param args The command and its arguments split into words
* @param user_input The user input to be modified
* @param alias_cmd The alias and its arguments to be stored
*/
void insert_aliases(Alias_List list, char** args, char* user_input, char* alias_cmd) {
/* If the list if empty, there's nothing to alias.
* If this is an unalias command, it would never work if we applied the alias */
if(is_empty(list) || args[0] == NULL || !strncmp(args[0], "alias", 5) || !strncmp(args[0], "unalias", 7))
return;
char* command = malloc(sizeof(char) * 512);
char* command_before = malloc(sizeof(char) * 512);
strcpy(command, args[0]);
Alias* current = *list;
while(current) {
strcpy(command_before, command);
/* Replace the command with the one that has any potential aliases inserted */
strcpy(user_input, insert_alias(current, args, user_input, command, alias_cmd));
if(strcmp(command_before, command)) {
if(current->used == true) {
printf("Cycle found and resolved!\n");
strcpy(user_input, "");
strcpy(alias_cmd, "");
break;
}
current->used = true;
current = *list;
continue;
}
current = current->next;
}
reset_aliases(list);
free(command);
free(command_before);
}
/**
* Resets the bool value 'used' back to false
*
* @param list The list of aliases
*/
void reset_aliases(Alias_List list) {
Alias* current = *list;
while(current) {
current->used = false;
current = current->next;
}
}
/**
* Prints out each alias in a list
*
* @param list The list of aliases to be printed
*/
void print_aliases(Alias_List list) {
/* If the list is empty, there's nothing to print */
if(is_empty(list)) {
printf("No aliases exist\n");
return;
}
Alias* current = *list;
while(current) {
/* Print every alias in the format alias: replacement */
printf("%s: %s\n", current->alias, current->replacement);
current = current->next;
}
}
/**
* Loads a list of aliases from a file
* called .aliases in the user's home directory
*
* @return The loaded aliases, or a new list of aliases if there was an issue reading from file
*/
Alias_List load_aliases() {
/* Get a new alias list in which to add the loaded items */
Alias_List list = new_alias_list();
/* Get the path to the .aliases file in the user's home directory */
char path[255];
strcpy(path, getenv("HOME"));
strcat(path, "/.aliases");
/* Open the aliases file in reading mode */
FILE* alias_file = fopen(path, "r");
/* If we couldn't open the file, just return the empty list */
if(!alias_file)
return list;
/* Buffer in which each line from the file is held */
char line[1025];
/* Buffer in which the alias from each line is held */
char alias[512];
/* Buffer in which the replacement command from each line is held */
char replacement[512];
/* Read each line of the file,
* then store the alias and replacement commands
* and add them to the list */
while(fgets(line, 1025, alias_file)) {
sscanf(line, "%s %[^\n]s", alias, replacement);
add_alias(list, alias, replacement);
}
/* Once we're done, close the file and return the list */
fclose(alias_file);
return list;
}
/**
* Saves the list of aliases to a file
* called .aliases in the user's home directory
*
* @param list The list of aliases to be saved
*/
void save_aliases(Alias_List list) {
/* Get the path to the .aliases file in the user's home directory */
char path[255];
strcpy(path, getenv("HOME"));
strcat(path, "/.aliases");
/* Open the aliases file in writing mode */
FILE* alias_file = fopen(path, "w");
/* If we couldn't open the file, just return */
if(!alias_file)
return;
/* Add each alias and replacement command
* as a new line in the file */
Alias* current = *list;
while(current) {
fprintf(alias_file, "%s %s\n", current->alias, current->replacement);
current = current->next;
}
/* Once we're done, close the file */
fclose(alias_file);
}