Skip to content

Instantly share code, notes, and snippets.

@amoshyc
Last active August 29, 2015 14:11
Show Gist options
  • Select an option

  • Save amoshyc/5de590f4bdb77f71ee31 to your computer and use it in GitHub Desktop.

Select an option

Save amoshyc/5de590f4bdb77f71ee31 to your computer and use it in GitHub Desktop.
DS Project 5

DS Project 5: simple line editor (sled)

Suppose program name is sled and myfile.txt is a text file.
After the "myfile.txt" has been read in the memory and the data structure built, the program
will enter interactive mode by prompting '>' to let user enter commands. The program should
print '>' for prompting after the execution of each command.
> l
This is the first line.

The following commands need to be supported

l print current line (have to show line number)
l k print k lines from current line
l .,.+10 print 11 lines from the current line
i "字串" insert a line below current line
d delete the current line
d 1,10 delete from the first line to the tenth line
d .,.+10 delete 11 lines from the current line
d 10,$ delete from the tenth line to the last line
p print previous line
n print next line
s /pat1/pat2/ replace pattern1 to pattern2 from current line
s /pat1/pat2/g replace pattern1 to pattern2 in the whole txt file
R another.txt insert lines from another file below current line
w new.txt write to a new file(if this file doesn't exist, open a new.txt and write out to it)
w! write out to original file
q quit the program
f "pat" find the first line that contains a match of pattern below current line
g lineNum go to the line number
g $ go to the last line

P.S: After the execution of 'd' command, you have to show some message like the example)

/*
* llist.c
*
* Created on: Dec 10, 2014
* Author: amoshuangyc
*/
#include <string.h>
#include <stdlib.h>
#include "llist.h"
ListNode* new_listnode(char* s) {
ListNode* ln = (ListNode*) malloc (sizeof(ListNode));
int len = strlen(s);
ln->data = (char*) malloc (sizeof(char) * (len+1));
ln->data[len+1] = '\0';
strcpy(ln->data, s);
ln->p = NULL;
ln->n = NULL;
return ln;
}
void free_listnode(ListNode* ln) {
if (ln == NULL) return;
free(ln->data);
free(ln);
}
/*
* llist.h
*
* Created on: Dec 10, 2014
* Author: amoshuangyc
*/
#ifndef LLIST_H_
#define LLIST_H_
#include <stdbool.h>
#include <string.h>
struct ListNode_ {
char* data;
struct ListNode_* p;
struct ListNode_* n;
};
typedef struct ListNode_ ListNode;
ListNode* new_listnode(char* s);
void free_listnode(ListNode* ln);
#endif /* LLIST_H_ */
#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;
}
utility.o: utility.h
clang -std=c99 -c utility.c
llist.o: llist.h
clang -std=c99 -c llist.c
main.o: utility.h llist.h
clang -std=c99 -c main.c
all: utility.o llist.o main.o
clang -std=c99 -o sled utility.o llist.o main.o
clean:
rm -f *.o
rm -f sled
/*
* utility.c
*
* Created on: Dec 10, 2014
* Author: amoshuangyc
*/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
bool is_str_digit(const char* s) {
int len = strlen(s);
for (int i=0; i<len; i++)
if (s[i] < '0' || s[i] > '9')
return false;
return true;
}
char* strreplace(const char* s, const char* pat, const char* target) {
char* result = (char*) malloc (sizeof(char) * (1024));
int r_idx = 0;
int s_idx = 0;
int p_len = strlen(pat);
int s_len = strlen(s);
int t_len = strlen(target);
bool found_flag = false;
while (s_idx < s_len) {
char* ptr = strstr(s + s_idx, pat);
if (ptr == NULL) {
strcpy(result + r_idx, s + s_idx);
break;
}
found_flag = true;
int i = ptr - s;
strncpy(result + r_idx, s + s_idx, (i-s_idx));
r_idx += (i-s_idx);
s_idx = i + p_len;
strncpy(result + r_idx, target, t_len);
r_idx += t_len;
}
if (found_flag == false)
return NULL;
return result;
}
char* strstrip_quote(const char* s) {
const int len = strlen(s);
char* result = (char*) malloc (sizeof(char) * (len+1));
for (int i=0; i<len+1; i++)
result[i] = '\0';
if (s[0] == '\"' && s[len-1] == '\"')
strncpy(result, s+1, len-2);
else
strncpy(result, s, len);
return result;
}
/*
* utility.h
*
* Created on: Dec 10, 2014
* Author: amoshuangyc
*/
#ifndef UTILITY_H_
#define UTILITY_H_
#include <string.h>
#include <stdbool.h>
bool is_str_digit(const char* s);
char* strreplace(const char* s, const char* pat, const char* target);
char* strstrip_quote(const char* s);
#endif /* UTILITY_H_ */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment