Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdlib.h>
- #include "textbuffer.h"
- #include <stdio.h>
- #include <string.h>
- #include <stdbool.h>
- typedef struct textbufferNode {
- char *data;
- struct textbufferNode *next;
- struct textbufferNode *prev;
- } TBNode;
- struct textbuffer {
- int textbufferLength; //Number of lines in the textbuffer
- TBNode *first; //a pointer to the first node
- TBNode *last; //a pointer to the last node
- };
- static TBNode *newTBNode(char *text);
- static void freeTBNode(TBNode *node);
- static char* mystrsep(char **input, const char *delim);
- static char * mystrdup (const char *s);
- int numDigits (int n);
- static int sizeInBytes(TB tb);
- //static void printTB(TB tb);
- static Match createMatchNode(int line, int columnNumber);
- /* Allocate a new textbuffer whose contents is initialised with the text given
- * in the array.
- */
- static char * mystrdup (const char *s) {
- size_t len = strlen (s) + 1;
- void *new = malloc (len);
- if (new == NULL){
- return NULL;
- }
- return (char *) memcpy (new, s, len);
- }
- /*static void printTB(TB tb){
- TBNode *transverse = tb->first;
- while(transverse != NULL){
- fprintf(stderr,"%s\n", transverse->data);
- transverse = transverse->next;
- }
- }
- */
- static Match createMatchNode(int line, int columnNumber){
- Match new = malloc(sizeof(*new));
- if(new == NULL){
- fprintf(stderr,"couldn't allocate memory for match node\n");
- abort();
- }
- (*new) = (struct _matchNode){
- .lineNumber = line, .columnNumber = columnNumber, .next = NULL
- };
- return new;
- }
- static TBNode *newTBNode (char *text)
- {
- //Allocate memory to the node.
- TBNode *new = malloc (sizeof(*new));
- if (new == NULL){
- printf("couldn't allocate newTB node");
- abort();
- }
- (*new) = (struct textbufferNode){
- .data = mystrdup(text), .next = NULL, .prev = NULL
- };
- return new;
- }
- static int sizeInBytes(TB tb) {
- size_t size = 0;
- TBNode *search = tb->first;
- while(search != NULL){
- size += strlen(search->data) +1;
- search = search->next;
- }
- return size;
- }
- static char * mystrsep(char **input, const char *delim){
- char *begin, *end;
- begin = *input;
- if (begin == NULL || strcmp(*input, "") == 0){
- return NULL;
- }
- //Find the end of the token
- //get the string until character delim
- end = begin + strcspn (begin, delim);
- if (*end) {
- //Terminate the token and set *input past NULL character
- *end++ = '\0';
- *input = end;
- }
- else {
- //No more delimiters; this is the last token.
- *input = NULL;
- }
- //printf("returned is %s\n", begin);
- return begin;
- }
- int numDigits (int n){
- int count = 0;
- while(n != 0) {
- // n = n/10
- n /= 10;
- ++count;
- }
- return count;
- }
- TB newTB (char text[]) {
- //Allocate memory for a new textbuffer
- TB newTB = malloc(sizeof(struct textbuffer));
- if (newTB == NULL){
- printf("unable to allocate memory to new textbuffer\n");
- exit(1);
- }
- //Set the fields to null:
- (*newTB) = (struct textbuffer){
- .first = NULL, .last = NULL, .textbufferLength = 0
- };
- //break the string up and for every line of text allocate a node
- char *line;
- char *newText = mystrdup(text);
- char **splitString = &newText;
- while((line = mystrsep(splitString,"\n"))!= NULL){
- //create a new node.
- TBNode *newNode = newTBNode (line);
- //if we're the first node in the list
- if(newTB->first == NULL){
- newTB->first = newNode;
- newTB->last = newNode;
- //otherwise append to the end
- } else {
- newTB->last->next = newNode;
- newNode->prev = newTB->last;
- newTB->last = newNode;
- }
- newTB->textbufferLength++;
- }
- return newTB;
- }
- //A function to free a node
- static void freeTBNode (TBNode *node)
- {
- //printf("here with data %s\n", node->data);
- if (node == NULL) {
- return;
- }
- free(node->data);
- //printf("my node is at location %p\n", node);
- free(node);
- }
- /* Free the memory occupied by the given textbuffer. It is an error to access
- * the buffer afterwards.
- */
- void releaseTB (TB tb) {
- if (tb == NULL){
- printf("invalid text buffer!\n");
- abort();
- }
- if(tb->textbufferLength == 0){
- //free just the memory of the tb
- free(tb);
- return;
- }
- TBNode *current = tb->first;
- while(current != NULL){
- //printf("i am freeing %s, with current->next->data: %s\n", current->data, current->next->data);
- TBNode *temp = current->next;
- //printf("temp is at %p with data %s\n", temp, temp->data);
- //printf("current is at %p with data %s\n", current, current->data);
- freeTBNode(current);
- //somehow my data is getting corrupted.
- current = temp;
- }
- free(tb);
- }
- /* Allocate and return an array containing the text in the given textbuffer.
- * add a prefix corrosponding to line number iff showLineNumbers == TRUE
- */
- char *dumpTB (TB tb, bool showLineNumbers){
- size_t size = sizeInBytes(tb);
- if(size == 0){
- char *string = malloc(1);
- *string = '\0';
- return string;
- }
- if(showLineNumbers){
- int count = 1;
- //add to the size of the string
- TBNode *current = tb->first;
- while(current != NULL){
- size += 2 + numDigits(count);
- current = current->next;
- count++;
- }
- //printf("size is %zu\n", size);
- char *totalText = malloc(size +1);
- if(totalText == NULL){
- printf("malloc failed\n");
- abort();
- }
- char *addingPoint = totalText;
- TBNode *search = tb->first;
- int lineNumber = 1;
- while(search != NULL){
- sprintf(addingPoint, "%d. %s\n", lineNumber, search->data);
- addingPoint += strlen(search->data) + numDigits(lineNumber) + 3;
- search = search->next;
- lineNumber++;
- }
- //printf("text is : %s", totalText);
- return totalText;
- } else {
- char *totalText = malloc(size +1);
- if(totalText == NULL){
- printf("malloc failed\n");
- abort();
- }
- TBNode *current = tb->first;
- char *addingPoint = totalText;
- while(current != NULL){
- sprintf(addingPoint, "%s\n",current->data);
- addingPoint += strlen(current->data) +1;
- current = current->next;
- }
- //printf("text is : %s", totalText);
- return totalText;
- }
- }
- /* Return the number of lines of the given textbuffer.
- */
- int linesTB (TB tb){
- return(tb->textbufferLength);
- }
- /* Add a given prefix to all lines between pos1 and pos2
- *
- * - The program is to abort() with an error message if line 'pos1' or line
- * 'pos2' is out of range. The first line of a textbuffer is at position 0.
- */
- //You need to realloc
- void addPrefixTB (TB tb, int pos1, int pos2, char* prefix){
- if(prefix == NULL || strcmp(prefix, "") == 0){
- return;
- }
- if(pos1 > pos2){
- fprintf(stderr,"Invalid input\n");
- abort();
- }
- //printf("textbufferLength is %d\n", tb->textbufferLength);
- if(pos2 > tb->textbufferLength|| pos1 < 1){
- fprintf(stderr, "invalid input\n");
- abort();
- }
- TBNode *searchNode = tb->first;
- //This will count our index along the linked list.
- int count = 1;
- //find pos1's node
- while(count < pos1){
- searchNode = searchNode->next;
- count++;
- }
- //Now, for every node from there, add the prefix:
- while(count <= pos2){
- int size = strlen(searchNode->data) + strlen(prefix) +1;
- char *tmp = malloc(size);
- //printf("data is %s\n", tmp);
- sprintf(tmp, "%s%s",prefix, searchNode->data);
- //printf("value is now %s\n", tmp);
- free(searchNode->data);
- searchNode->data = tmp;
- searchNode = searchNode->next;
- count++;
- }
- }
- /* Merge 'tb2' into 'tb1' at line 'pos'.
- *
- * - Afterwards line 0 of 'tb2' will be line 'pos' of 'tb1'.
- * - The old line 'pos' of 'tb1' will follow after the last line of 'tb2'.
- * - After this operation 'tb2' can not be used anymore (as if we had used
- * releaseTB() on it).
- * - The program is to abort() with an error message if 'pos' is out of range.
- */
- void mergeTB (TB tb1, int pos, TB tb2){
- if(tb1 == NULL || tb2 == NULL){
- return;
- }
- if(tb1 == tb2){
- printf("can't merge textbuffers that are the same!\n");
- return;
- }
- if(pos < 1 || pos > (linesTB(tb1)+1)){
- printf("Invalid input\n");
- abort();
- }
- //Three cases:
- //printf("num lines of tb1 is %d\n", linesTB(tb1));
- //at the start of the textbuffer:
- if(pos == 1){
- //insert here.
- tb2->last->next = tb1->first;
- tb1->first->prev = tb2->last;
- tb1->first = tb2->first;
- }
- //at the end of the textbuffer:
- else if(pos == linesTB(tb1)+1){
- tb1->last->next = tb2->first;
- tb2->first->prev = tb1->last;
- tb1->last = tb2->last;
- }
- //in the middle of the textbuffer
- else {
- if(pos > 1 && pos < linesTB(tb1)){
- //find where to insert it.
- int insertionPoint = 1;
- TBNode *insertionNode = NULL;
- TBNode *current = tb1->first;
- TBNode *prevNode = NULL;
- while(current != NULL && insertionPoint < pos){
- prevNode = current;
- insertionPoint++;
- current = current->next;
- }
- if(prevNode == NULL){
- abort();
- }
- insertionNode = prevNode->next;
- prevNode->next = tb2->first;
- tb2->first->prev = prevNode;
- tb2->last->next = insertionNode;
- insertionNode->prev = tb2->last;
- }
- }
- tb1->textbufferLength += linesTB(tb2);
- free(tb2);
- //printTB(tb1);
- }
- /* Copy 'tb2' into 'tb1' at line 'pos'.
- *
- * - Afterwards line 0 of 'tb2' will be line 'pos' of 'tb1'.
- * - The old line 'pos' of 'tb1' will follow after the last line of 'tb2'.
- * - After this operation 'tb2' is unmodified and remains usable independent
- * of 'tb1'.
- * - The program is to abort() with an error message if 'pos' is out of range.
- */
- void pasteTB (TB tb1, int pos, TB tb2) {
- if(tb1 == NULL || tb2 == NULL){
- return;
- }
- if(pos <1 || pos > (linesTB(tb1)+2)){
- printf("Invalid input\n");
- abort();
- }
- //create a new TB that is a copy of tb2. I'm going to call dump TB then
- //call newTB.
- char *text = dumpTB(tb2, false);
- TB dupTb2 = newTB(text);
- //now call merge with these two.
- mergeTB(tb1, pos, dupTb2);
- //fprintf(stderr, "tb2 is \n");
- //printTB(tb2);
- return;
- }
- /* Cut the lines between and including 'from' and 'to' out of the textbuffer
- * 'tb'.
- *
- * - The result is a new textbuffer (much as one created with newTB()).
- * - The cut lines will be deleted from 'tb'.
- * - The program is to abort() with an error message if 'from' or 'to' is out
- * of range.
- */
- TB cutTB (TB tb, int from, int to){
- //grab the lines from the tb between from and to.
- if(tb == NULL) {
- printf("invalid TB\n");
- abort();
- }
- if(from > to){
- printf("Invalid input\n");
- abort();
- }
- int length = linesTB(tb);
- //printf("length is %d\n", length);
- if(from < 1 || to > length){
- printf("Invalid input\n");
- abort();
- }
- TBNode *searchNode = tb->first;
- //find the node at from
- int count = 0;
- while(count < from -1){
- searchNode = searchNode->next;
- count++;
- }
- //go up until to.
- size_t size = sizeInBytes(tb);
- char *totalText = malloc(size +1);
- if(totalText == NULL){
- printf("malloc failed\n");
- abort();
- }
- char *addingPoint = totalText;
- while(count < to){
- sprintf(addingPoint, "%s\n",searchNode->data);
- addingPoint += strlen(searchNode->data) +1;
- searchNode = searchNode->next;
- count++;
- }
- //now we have text, create a newTB with it.
- TB cutTB = newTB(totalText);
- deleteTB(tb, from, to);
- /*fprintf(stderr, "cutTB looks like: \n");
- printTB(cutTB);
- fprintf(stderr, "tb looks like: \n");
- printTB(tb);
- */
- return cutTB;
- }
- /* Return a linked list of Match nodes of all the matches of string search
- * in tb
- *
- * - The textbuffer 'tb' will remain unmodified.
- * - The user is responsible of freeing the returned list
- */
- Match searchTB (TB tb, char* search){
- //To keep track of the previous match node added to the list.
- Match prev = NULL;
- Match head = NULL;
- TBNode *curr = tb->first;
- int line = 1;
- //I'm going to assume the only matches are empty nodes.
- if(strncmp(search,"",1) == 0){
- while(curr != NULL){
- if(strncmp(curr->data,"", 1) == 0){
- Match newNode = createMatchNode(line, 0);
- if(prev == NULL){
- head = newNode;
- }
- if(prev != NULL){
- prev->next = newNode;
- }
- prev = newNode;
- }
- line++;
- curr = curr->next;
- }
- }
- while(curr != NULL){
- char *currentPointer = curr->data;
- char *pos;
- while((pos = strstr(currentPointer, search)) != NULL){
- int column = (pos - curr->data);
- //fprintf(stderr,"found a match at line %d and column %d\n", line, column);
- Match new = createMatchNode(line,column+1);
- if(prev == NULL){
- head = new;
- }
- if(prev != NULL){
- prev->next = new;
- }
- prev = new;
- currentPointer = pos + strlen(search);
- }
- line++;
- curr = curr->next;
- }
- /*
- if(head != NULL){
- Match current = head;
- while(current!= NULL){
- fprintf(stderr,"we are at %p, line %d, column %d, next is %p\n",current, current->lineNumber, current->columnNumber, current->next);
- current = current->next;
- }
- }
- if (head == NULL){
- fprintf(stderr,"no matches!\n");
- }
- */
- return head;
- }
- /* Remove the lines between and including 'from' and 'to' from the textbuffer
- * 'tb'.
- *
- * - The program is to abort() with an error message if 'from' or 'to' is out
- * of range.
- */
- void deleteTB (TB tb, int from, int to){
- if(from > to){
- printf("Invalid input\n");
- abort();
- }
- int length = linesTB(tb);
- //printf("length is %d\n", length);
- if(from < 1 || to > length){
- printf("Invalid input\n");
- abort();
- }
- TBNode *searchNode = tb->first;
- //find the node at from
- int count = 0;
- while(count < from -1){
- searchNode = searchNode->next;
- count++;
- }
- while(count < to){
- TBNode *newCurrent = searchNode->next;
- //Set the node to delete:
- TBNode *nodeToDelete = searchNode;
- //Cases:
- //if we're the last node but there are some before me
- if(searchNode == tb->last && tb->textbufferLength >1){
- //New Current is now the one before the current node
- newCurrent = searchNode->prev;
- //Set it to the last:
- tb->last = newCurrent;
- //it's next is now NULL
- newCurrent->next = NULL;
- //if we're the last node and the only one in the list
- } else if (searchNode == tb->last && tb->textbufferLength == 1){
- tb->first = NULL;
- tb->last = NULL;
- //if we're the first node
- } else if (searchNode == tb->first) {
- newCurrent->prev = NULL;
- searchNode->next = NULL;
- tb->first = newCurrent;
- //if we're somewhere in the middle
- } else {
- searchNode->prev->next = newCurrent;
- searchNode->next->prev = searchNode->prev;
- }
- //we've removed an item
- tb->textbufferLength--;
- //free the node to delete
- freeTBNode(nodeToDelete);
- searchNode = newCurrent;
- count++;
- }
- return;
- }
- /* Search every line of tb for each occurrence of a set of specified subsitituions
- * and alter them accordingly
- *
- * refer to spec for table.
- */
- void formRichText (TB tb){
- TBNode *current = tb->first;
- while(current != NULL){
- //go through for *
- char *pos1 = strchr(current->data, '*');
- while(pos1){
- //find an equivalent thing that is more than 2 away.
- char *search = pos1 +1;
- char *pos2 = NULL;
- while(*search != '\0'){
- if(*search == '*'){
- pos2 = search;
- break;
- }
- search++;
- }
- if(pos2 && pos2-pos1 >= 2){
- printf("pos1 is %p and %c\n", pos1, *pos1);
- printf("pos2 is %p and %c\n", pos2, *pos2);
- }
- pos1 = 0;
- //strchr(current->data, '*');
- }
- current = current->next;
- }
- }
- /* Your whitebox tests
- */
- void whiteBoxTests() {
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement