|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <stdbool.h> |
|
#include <string.h> |
|
|
|
#include "utility.h" |
|
#include "llist.h" |
|
|
|
#define GREEN "\x1b[32m" |
|
#define RED "\x1b[31m" |
|
#define RESET "\x1b[0m" |
|
|
|
ListNode* parse_arg(const char* s, ListNode* head, ListNode* tail, |
|
ListNode* curr) { |
|
if (strcmp(s, ".") == 0) |
|
return curr; |
|
|
|
if (strcmp(s, "$") == 0) |
|
return tail; |
|
|
|
if (strncmp(s, ".+", 2) == 0) { |
|
const char* arg = s + 2; |
|
if (is_str_digit(arg) == false) |
|
return NULL; |
|
|
|
int value = atoi(arg); |
|
|
|
ListNode* temp = curr; |
|
while (value--) { |
|
if (temp == NULL) |
|
return NULL; |
|
|
|
temp = temp->n; |
|
} |
|
|
|
return temp; |
|
} |
|
|
|
if (strncmp(s, ".-", 2) == 0) { |
|
const char* arg = s + 2; |
|
if (is_str_digit(arg) == false) |
|
return NULL; |
|
|
|
int value = atoi(arg); |
|
|
|
ListNode* temp = curr; |
|
while (value--) { |
|
if (temp == NULL) |
|
return NULL; |
|
|
|
temp = temp->p; |
|
} |
|
|
|
return temp; |
|
} |
|
|
|
if (is_str_digit(s) == false) |
|
return NULL; |
|
|
|
int value = atoi(s) - 1; |
|
if (value < 0) |
|
return NULL; |
|
ListNode* temp = head; |
|
while (value--) { |
|
if (temp == NULL) |
|
return NULL; |
|
|
|
temp = temp->n; |
|
} |
|
|
|
return temp; |
|
} |
|
|
|
bool list_node(ListNode* start, ListNode* end) { |
|
ListNode* temp = start; |
|
while (temp != end) { |
|
if (temp == NULL) |
|
return false; |
|
|
|
printf(GREEN "%s\n" RESET, temp->data); |
|
temp = temp->n; |
|
} |
|
|
|
printf(GREEN "%s\n" RESET, temp->data); |
|
|
|
return true; |
|
} |
|
|
|
ListNode* delete_node(ListNode* start, ListNode* end) { |
|
ListNode* p = start->p; |
|
ListNode* n = end->n; |
|
|
|
if (p != NULL) { |
|
p->n = n; |
|
} |
|
if (n != NULL) { |
|
n->p = p; |
|
} |
|
|
|
ListNode* temp = start; |
|
while (temp != end) { |
|
if (temp == NULL) |
|
return NULL; |
|
|
|
printf(GREEN "%s Deleted\n" RESET, temp->data); |
|
free_listnode(temp); |
|
temp = temp->n; |
|
} |
|
printf(GREEN "%s Deleted\n" RESET, end->data); |
|
|
|
return ((p != NULL) ? p : n); |
|
|
|
} |
|
|
|
bool process_cmd(char* cmd1, char* cmd2, ListNode** head, ListNode** tail, |
|
ListNode** curr, const char* filename) { |
|
|
|
if (cmd1 == NULL) |
|
return NULL; |
|
|
|
if (strcmp(cmd1, "l") == 0) { |
|
if (cmd2 == NULL) { |
|
return list_node(*curr, *curr); |
|
} |
|
|
|
if (strchr(cmd2, ',') != NULL) { |
|
char* arg1 = strtok(cmd2, ", "); |
|
char* arg2 = strtok(NULL, ", "); |
|
|
|
if (arg1 == NULL || arg2 == NULL) |
|
return false; |
|
|
|
ListNode* start = parse_arg(arg1, *head, *tail, *curr); |
|
ListNode* end = parse_arg(arg2, *head, *tail, *curr); |
|
|
|
if (start == NULL || end == NULL) |
|
return false; |
|
|
|
return list_node(start, end); |
|
} |
|
else { |
|
ListNode* end = parse_arg(cmd2, *curr, *tail, *curr); |
|
if (end == NULL) |
|
return false; |
|
|
|
return list_node(*curr, end); |
|
} |
|
} |
|
|
|
if (strcmp(cmd1, "n") == 0) { |
|
if (cmd2 != NULL) |
|
return false; |
|
|
|
if ((*curr)->n == NULL) |
|
return false; |
|
|
|
*curr = (*curr)->n; |
|
list_node(*curr, *curr); |
|
|
|
return true; |
|
} |
|
|
|
if (strcmp(cmd1, "p") == 0) { |
|
if (cmd2 != NULL) |
|
return false; |
|
|
|
if ((*curr)->p == NULL) |
|
return false; |
|
|
|
*curr = (*curr)->p; |
|
list_node(*curr, *curr); |
|
|
|
return true; |
|
} |
|
|
|
if (strcmp(cmd1, "i") == 0) { |
|
if (cmd2 == NULL) |
|
return false; |
|
|
|
char* data = strstrip_quote(cmd2); |
|
|
|
// insert to list |
|
if (*head == NULL) { |
|
*head = new_listnode(data); |
|
*tail = *head; |
|
*curr = *head; |
|
} |
|
else { |
|
ListNode* new_node = new_listnode(data); |
|
|
|
if ((*curr)->n != NULL) { |
|
(*curr)->n->p = new_node; |
|
new_node->n = (*curr)->n; |
|
} |
|
else { |
|
*tail = new_node; |
|
} |
|
|
|
(*curr)->n = new_node; |
|
new_node->p = (*curr); |
|
|
|
*curr = (*curr)->n; |
|
} |
|
|
|
puts("Added!"); |
|
|
|
free(data); |
|
return true; |
|
} |
|
|
|
if (strcmp(cmd1, "d") == 0) { |
|
if (cmd2 == NULL) { |
|
if (*head == *tail) { |
|
if (*head == NULL) |
|
return false; |
|
|
|
delete_node(*head, *head); |
|
*head = NULL; |
|
*curr = NULL; |
|
*tail = NULL; |
|
|
|
return true; |
|
} |
|
|
|
if (*curr == *head) { |
|
|
|
*head = delete_node(*head, *head); |
|
*curr = *head; |
|
|
|
return true; |
|
} |
|
|
|
if (*curr == *tail) { |
|
*tail = delete_node(*curr, *curr); |
|
*curr = *tail; |
|
|
|
return true; |
|
} |
|
|
|
*curr = delete_node(*curr, *curr); |
|
return true; |
|
} |
|
|
|
if (strchr(cmd2, ',') != NULL) { |
|
char* arg1 = strtok(cmd2, ", "); |
|
char* arg2 = strtok(NULL, ", "); |
|
|
|
if (arg1 == NULL || arg2 == NULL) |
|
return false; |
|
|
|
ListNode* start = parse_arg(arg1, *head, *tail, *curr); |
|
ListNode* end = parse_arg(arg2, *head, *tail, *curr); |
|
|
|
if (start == NULL || end == NULL) |
|
return false; |
|
|
|
*curr = delete_node(start, end); |
|
|
|
if (*curr == NULL) { |
|
*head = NULL; |
|
*tail = NULL; |
|
return true; |
|
} |
|
|
|
// Update head, tail |
|
*head = *curr; |
|
while ((*head)->p != NULL) |
|
*head = (*head)->p; |
|
|
|
*tail = *curr; |
|
while ((*tail)->n != NULL) |
|
*tail = (*tail)->n; |
|
|
|
return true; |
|
} |
|
else { |
|
ListNode* end = parse_arg(cmd2, *curr, *tail, *curr); |
|
if (end == NULL) |
|
return false; |
|
|
|
*curr = delete_node(*curr, end); |
|
if (*curr == NULL) { |
|
*head = NULL; |
|
*tail = NULL; |
|
return true; |
|
} |
|
|
|
// Update head, tail |
|
*head = *curr; |
|
while ((*head)->p != NULL) |
|
*head = (*head)->p; |
|
|
|
*tail = *curr; |
|
while ((*tail)->n != NULL) |
|
*tail = (*tail)->n; |
|
|
|
return true; |
|
} |
|
} |
|
|
|
if (strcmp(cmd1, "s") == 0) { |
|
if (cmd2 == NULL) |
|
return false; |
|
|
|
// pre-check |
|
if (cmd2[0] != '/') |
|
return false; |
|
char* idx1 = strchr(cmd2, '/'); |
|
if (idx1 == NULL) |
|
return false; |
|
char* idx2 = strchr(idx1 + 1, '/'); |
|
if (idx2 == NULL) |
|
return false; |
|
char* idx3 = strchr(idx2 + 1, '/'); |
|
if (idx3 == NULL) |
|
return false; |
|
|
|
// no pattern |
|
if (idx2 == idx1 + 1) |
|
return false; |
|
|
|
cmd2[idx1 - cmd2] = '\0'; |
|
cmd2[idx2 - cmd2] = '\0'; |
|
cmd2[idx3 - cmd2] = '\0'; |
|
|
|
// point to tokens |
|
idx1++; |
|
idx2++; |
|
idx3++; |
|
|
|
printf("%s,%s,%s\n", idx1, idx2, idx3); |
|
|
|
if (idx3[0] == '\0') { // Without /g |
|
char* result = strreplace((*curr)->data, idx1, idx2); |
|
if (result == NULL) { |
|
puts("Nothing to be replaced"); |
|
return true; |
|
} |
|
printf(GREEN "Replace %s to %s\n" RESET, (*curr)->data, result); |
|
free((*curr)->data); |
|
(*curr)->data = (char*) malloc(sizeof(char) * (strlen(result) + 1)); |
|
strcpy((*curr)->data, result); |
|
free(result); |
|
|
|
return true; |
|
} |
|
else if (idx3[0] == 'g') { |
|
ListNode* temp = *head; |
|
bool found = false; |
|
while (temp != NULL) { |
|
char* result = strreplace(temp->data, idx1, idx2); |
|
if (result == NULL) { |
|
temp = temp->n; |
|
continue; |
|
} |
|
else { |
|
found = true; |
|
} |
|
printf(GREEN "Replace %s to %s\n" RESET, temp->data, result); |
|
free(temp->data); |
|
temp->data = (char*) malloc( |
|
sizeof(char) * (strlen(result) + 1)); |
|
strcpy(temp->data, result); |
|
free(result); |
|
|
|
temp = temp->n; |
|
} |
|
|
|
if (found == false) { |
|
puts("Nothing to be replaced!"); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
if (strcmp(cmd1, "f") == 0) { |
|
if (cmd2 == NULL) |
|
return false; |
|
|
|
char* key = strstrip_quote(cmd2); |
|
|
|
ListNode* temp = *curr; |
|
bool found = false; |
|
while (temp != NULL) { |
|
if (strstr(temp->data, key) != NULL) { |
|
printf(GREEN "%s\n" RESET, temp->data); |
|
found = true; |
|
*curr = temp; |
|
break; |
|
} |
|
|
|
temp = temp->n; |
|
} |
|
|
|
if (found == false) { |
|
printf(RED "(Not Found!)\n" RESET); |
|
} |
|
|
|
free(key); |
|
return true; |
|
} |
|
|
|
if (strcmp(cmd1, "g") == 0) { |
|
if (cmd2 == NULL) |
|
return false; |
|
|
|
ListNode* ln = parse_arg(cmd2, *head, *tail, *curr); |
|
if (ln == NULL) |
|
return false; |
|
|
|
printf(GREEN "set curr to %s\n" RESET, ln->data); |
|
*curr = ln; |
|
|
|
return true; |
|
} |
|
|
|
if (strcmp(cmd1, "w!") == 0) { |
|
if (cmd2 != NULL) |
|
return false; |
|
|
|
FILE* f = fopen(filename, "w"); |
|
if (f == NULL) |
|
return false; |
|
|
|
ListNode* temp = *head; |
|
while (temp != NULL) { |
|
fprintf(f, "%s\n", temp->data); |
|
temp = temp->n; |
|
} |
|
fclose(f); |
|
|
|
puts("Success!"); |
|
return true; |
|
} |
|
|
|
if (strcmp(cmd1, "w") == 0) { |
|
if (cmd2 == NULL) |
|
return false; |
|
|
|
FILE* f = fopen(cmd2, "w"); |
|
if (f == NULL) |
|
return false; |
|
|
|
ListNode* temp = *head; |
|
while (temp != NULL) { |
|
fprintf(f, "%s\n", temp->data); |
|
temp = temp->n; |
|
} |
|
fclose(f); |
|
|
|
puts("Success!"); |
|
return true; |
|
} |
|
|
|
if (strcmp(cmd1, "R") == 0) { |
|
if (cmd2 == NULL) |
|
return false; |
|
|
|
FILE* f = fopen(cmd2, "r"); |
|
if (f == NULL) |
|
return false; |
|
|
|
ListNode* nhead = NULL; |
|
ListNode* ntail = NULL; |
|
|
|
// Get input from file and establish linked list |
|
char inp[1024]; |
|
while (fgets(inp, 1024, f) != NULL) { |
|
int len = strlen(inp); |
|
if (inp[len - 1] == '\n') |
|
inp[len - 1] = '\0'; |
|
|
|
// establish linked list |
|
if (nhead == NULL) { |
|
nhead = new_listnode(inp); |
|
ntail = nhead; |
|
} |
|
else { |
|
ListNode* new_node = new_listnode(inp); |
|
new_node->p = ntail; |
|
ntail->n = new_node; |
|
ntail = ntail->n; |
|
} |
|
} |
|
fclose(f); |
|
|
|
// merge |
|
|
|
if (*head == NULL) { |
|
*head = nhead; |
|
*tail = ntail; |
|
*curr = nhead; |
|
|
|
puts("Success!"); |
|
return true; |
|
} |
|
|
|
(*curr)->n->p = ntail; |
|
ntail->n = (*curr)->n; |
|
|
|
(*curr)->n = nhead; |
|
nhead->p = *curr; |
|
|
|
puts("Success!"); |
|
|
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
int main(int argc, char* argv[]) { |
|
if (argc != 2) |
|
return -1; |
|
|
|
FILE* f = fopen(argv[1], "r"); |
|
if (f == NULL) |
|
return -1; |
|
|
|
ListNode* head = NULL; |
|
ListNode* tail = NULL; |
|
|
|
// Get input from file and establish linked list |
|
char inp[1024]; |
|
while (fgets(inp, 1024, f) != NULL) { |
|
int len = strlen(inp); |
|
if (inp[len - 1] == '\n') |
|
inp[len - 1] = '\0'; |
|
|
|
// establish linked list |
|
if (head == NULL) { |
|
head = new_listnode(inp); |
|
tail = head; |
|
} |
|
else { |
|
ListNode* new_node = new_listnode(inp); |
|
new_node->p = tail; |
|
tail->n = new_node; |
|
tail = tail->n; |
|
} |
|
} |
|
fclose(f); |
|
|
|
// Print Input to check the list is correct |
|
printf("Read from: %s\n", argv[1]); |
|
ListNode* temp = head; |
|
while (temp != NULL) { |
|
printf("%s\n", temp->data); |
|
temp = temp->n; |
|
} |
|
free_listnode(temp); |
|
puts("--------------\n"); |
|
|
|
// Main loop |
|
ListNode* curr = head; |
|
while (true) { |
|
printf("head: %s\n", ((head == NULL) ? "(None)" : head->data)); |
|
printf("tail: %s\n", ((tail == NULL) ? "(None)" : tail->data)); |
|
printf("curr: %s\n", ((curr == NULL) ? "(None)" : curr->data)); |
|
|
|
char cmd[256]; |
|
printf("> "); |
|
fgets(cmd, 256, stdin); |
|
|
|
int len = strlen(cmd); |
|
if (cmd[len - 1] == '\n') |
|
cmd[len - 1] = '\0'; |
|
|
|
if (strcmp(cmd, "q") == 0) |
|
break; |
|
|
|
/*split cmd into two tokens by space*/ |
|
char* cmd1; |
|
char* cmd2; |
|
char* space_ = strchr(cmd, ' '); |
|
if (space_ == NULL) { |
|
cmd1 = cmd; |
|
cmd2 = NULL; |
|
} |
|
else { |
|
int space_idx = space_ - cmd; |
|
cmd[space_idx] = '\0'; |
|
cmd1 = cmd; |
|
cmd2 = cmd + space_idx + 1; |
|
} |
|
|
|
bool result = process_cmd(cmd1, cmd2, &head, &tail, &curr, argv[1]); |
|
|
|
if (result == false) |
|
printf(RED "Illegal Commands\n" RESET); |
|
|
|
printf("\n"); |
|
} |
|
|
|
// free linked list |
|
temp = head; |
|
while (head != NULL) { |
|
temp = head; |
|
head = head->n; |
|
free_listnode(temp); |
|
} |
|
|
|
puts("program exits."); |
|
|
|
return 0; |
|
} |