/***********************************************************************/ /* */ /* Objective Caml */ /* */ /* Developed by Jacob Navia. */ /* Copyright 2001 Institut National de Recherche en Informatique et */ /* en Automatique. All rights reserved. This file is distributed */ /* under the terms of the GNU Library General Public License, with */ /* the special exception on linking described in file ../LICENSE. */ /* */ /***********************************************************************/ /***********************************************************************/ /* Changes made by Chris Watford to enhance the source editor */ /* Began 14 Sept 2003 - watford@uiuc.edu */ /***********************************************************************/ #include #include #include "inriares.h" #include "inria.h" /*------------------------------------------------------------------------ Procedure: editbuffer_addline ID:1 Author: Chris Watford watford@uiuc.edu Purpose: Adds a line to the current edit buffer Input: Line of text to append to the end Output: Errors: -------------------------------------------------------------------------- Edit History: 18 Sept 2003 - Chris Watford watford@uiuc.edu - Corrected doubly linked list issue ------------------------------------------------------------------------*/ BOOL editbuffer_addline(EditBuffer* edBuf, char* line) { LineList *tail = NULL; //head of the edit buffer line list LineList *newline = NULL; // sanity check if(edBuf == NULL) { return FALSE; } // perform edit buffer sanity checks if((edBuf->LineCount < 0) || (edBuf->Lines == NULL)) { edBuf->LineCount = 0; } // move to the end of the line list in the edit buffer if((tail = edBuf->Lines) != NULL) for( ; tail->Next != NULL; tail = tail->Next); // create the new line entry newline = (LineList*)SafeMalloc(sizeof(LineList)); newline->Next = NULL; newline->Prev = tail; newline->Text = (char*)SafeMalloc(strlen(line)+1); strncpy(newline->Text, line, strlen(line)+1); newline->Text[strlen(line)] = '\0'; // add it to the list as the head or the tail if(tail != NULL) { tail->Next = newline; } else { edBuf->Lines = newline; } // update the number of lines in the buffer edBuf->LineCount++; return TRUE; } /*------------------------------------------------------------------------ Procedure: editbuffer_updateline ID:1 Author: Chris Watford watford@uiuc.edu Purpose: Updates the edit buffer's internal contents for a line Input: idx - Line index line - String to add Output: if the line was updated or not Errors: ------------------------------------------------------------------------*/ BOOL editbuffer_updateline(EditBuffer* edBuf, int idx, char* line) { LineList *update = edBuf->Lines; //head of the edit buffer line list LineList *newline = NULL; int i; // sanity checks if(edBuf == NULL) { return FALSE; } else if( (edBuf->LineCount == 0) || (edBuf->Lines == NULL) || (idx >= edBuf->LineCount) || (idx < 0) ) { return FALSE; } // move to the index in the line list // i left in update != NULL as a sanity check for(i = 0; ((update != NULL) && (i != idx)); update = update->Next, i++); // did things mess up? if( (update == NULL) || (i != idx) ) { return FALSE; } // get rid of the old line free(update->Text); // get the new line updated update->Text = (char*)SafeMalloc(strlen(line)+1); strncpy(update->Text, line, strlen(line)+1); update->Text[strlen(line)] = '\0'; return TRUE; } /*------------------------------------------------------------------------ Procedure: editbuffer_updateoraddline ID:1 Author: Chris Watford watford@uiuc.edu Purpose: Updates the edit buffer's internal contents for a line Input: idx - Line index line - String to add Output: if the line was updated or not Errors: ------------------------------------------------------------------------*/ BOOL editbuffer_updateoraddline(EditBuffer* edBuf, int idx, char* line) { LineList *update; // sanity checks if(edBuf == NULL) { return FALSE; } else if((idx > edBuf->LineCount) || (idx < 0)) { return FALSE; } update = edBuf->Lines; //head of the edit buffer line list // do we update or add? if((idx < edBuf->LineCount) && (edBuf->Lines != NULL)) { //interior line, update return editbuffer_updateline(edBuf, idx, line); } else { //fence line, add return editbuffer_addline(edBuf, line); } } /*------------------------------------------------------------------------ Procedure: editbuffer_removeline ID:1 Author: Chris Watford watford@uiuc.edu Purpose: Removes a line from the edit buffer Input: idx - Line index to remove Output: if the line was removed or not Errors: -------------------------------------------------------------------------- Edit History: 18 Sept 2003 - Chris Watford watford@uiuc.edu - Added to allow backspace and delete support - Corrected doubly linked list issue ------------------------------------------------------------------------*/ BOOL editbuffer_removeline(EditBuffer* edBuf, int idx) { LineList *update = NULL; int i = 0; // sanity checks if(edBuf == NULL) { return FALSE; } else if( (edBuf->LineCount == 0) || (edBuf->Lines == NULL) || (idx >= edBuf->LineCount) || (idx < 0) ) { return FALSE; } // move to the index in the line list // i left in update != NULL as a sanity check for(i = 0, update = edBuf->Lines; ((update != NULL) && (i != idx)); update = update->Next, i++); // remove this line if(update != NULL) { // break links, removing our line if(update->Prev != NULL) { // we're not the first so just break the link update->Prev->Next = update->Next; // fix the prev check if(update->Next != NULL) update->Next->Prev = update->Prev; } else { // we're the first, attach the next guy to lines edBuf->Lines = update->Next; } // one less line to worry about edBuf->LineCount--; // get rid of the text if(update->Text != NULL) free(update->Text); // get rid of us free(update); return TRUE; } return FALSE; } /*------------------------------------------------------------------------ Procedure: editbuffer_getasline ID:1 Author: Chris Watford watford@uiuc.edu Purpose: Returns the edit buffer as one big line, \n's and \t's become spaces. Input: Output: Errors: ------------------------------------------------------------------------*/ char* editbuffer_getasline(EditBuffer* edBuf) { LineList *line = NULL; //head of the edit buffer line list char* retline = (char*)realloc(NULL, 1); unsigned int i = 0; // fix retline bug retline[0] = '\0'; // sanity checks if(edBuf == NULL) { return NULL; } else if (edBuf->LineCount == 0 || edBuf->Lines == NULL) { // fix any possible errors that may come from this edBuf->LineCount = 0; edBuf->Lines = NULL; return NULL; } // get the big line for(line = edBuf->Lines; line != NULL; line = line->Next) { if(line->Text != NULL) { retline = (char*)realloc(retline, (strlen(retline) + strlen(line->Text) + (strlen(retline) > 0 ? 2 : 1))); if(strlen(retline) > 0) retline = strcat(retline, " "); retline = strcat(retline, line->Text); //concat in the hoouuusssseee! } } // now we have the big line, so lets ditch all \n's \t's and \r's for(i = 0; i < strlen(retline); i++) { switch(retline[i]) { case '\n': case '\t': case '\r': retline[i] = ' '; } } return retline; } /*------------------------------------------------------------------------ Procedure: editbuffer_getasbuffer ID:1 Author: Chris Watford watford@uiuc.edu Purpose: Returns the edit buffer as one big line, \n's and \t's become spaces. Input: Output: Errors: ------------------------------------------------------------------------*/ char* editbuffer_getasbuffer(EditBuffer* edBuf) { LineList *line = NULL; //head of the edit buffer line list char* retbuf = (char*)realloc(NULL, 1); unsigned int i = 0; // fix retline bug retbuf[0] = '\0'; // sanity checks if(edBuf == NULL) { return NULL; } else if (edBuf->LineCount == 0 || edBuf->Lines == NULL) { // fix any possible errors that may come from this edBuf->LineCount = 0; edBuf->Lines = NULL; return NULL; } // get the big line for(line = edBuf->Lines; line != NULL; line = line->Next) { if(line->Text != NULL) { int len = strlen(retbuf); len += strlen(line->Text) + (len > 0 ? 3 : 1); retbuf = (char*)realloc(retbuf, len); if(strlen(retbuf) > 0) retbuf = strcat(retbuf, "\r\n"); retbuf = strcat(retbuf, line->Text); retbuf[len-1] = '\0'; //concat in the hoouuusssseee! } } return retbuf; } /*------------------------------------------------------------------------ Procedure: editbuffer_lastline ID:1 Author: Chris Watford watford@uiuc.edu Purpose: Returns the last line in the edit buffer Input: Output: Errors: ------------------------------------------------------------------------*/ char* editbuffer_lastline(EditBuffer* edBuf) { LineList *line = NULL; //head of the edit buffer line list // sanity checks if(edBuf == NULL) { return NULL; } else if (edBuf->LineCount == 0 || edBuf->Lines == NULL) { // fix any possible errors that may come from this edBuf->LineCount = 0; edBuf->Lines = NULL; return NULL; } // go to the last line for(line = edBuf->Lines; line->Next != NULL; line = line->Next); return line->Text; } /*------------------------------------------------------------------------ Procedure: editbuffer_copy ID:1 Author: Chris Watford watford@uiuc.edu Purpose: Makes an exact copy of an edit buffer Input: Output: Errors: -------------------------------------------------------------------------- Edit History: 16 Sept 2003 - Chris Watford watford@uiuc.edu - Added to make copies of history entries 18 Sept 2003 - Chris Watford watford@uiuc.edu - Corrected doubly linked list issue 06 Oct 2003 - Chris Watford watford@uiuc.edu - Added isCorrect flag ------------------------------------------------------------------------*/ EditBuffer* editbuffer_copy(EditBuffer* edBuf) { // sanity checks if(edBuf == NULL) { return NULL; } else { EditBuffer* copy = (EditBuffer*)SafeMalloc(sizeof(EditBuffer)); LineList* lines = edBuf->Lines; LineList* lastLine = NULL; // clear its initial values copy->LineCount = 0; copy->Lines = NULL; copy->isCorrect = FALSE; // well we don't have to copy much if((lines == NULL) || (edBuf->LineCount <= 0)) { return copy; } // get if its correct copy->isCorrect = edBuf->isCorrect; // go through each line, malloc it and add it for( ; lines != NULL; lines = lines->Next) { LineList* curline = (LineList*)SafeMalloc(sizeof(LineList)); curline->Next = NULL; curline->Prev = NULL; // if there was a last line, link them to us if(lastLine != NULL) { lastLine->Next = curline; curline->Prev = lastLine; } // are we the first line? add us to the edit buffer as the first if(copy->Lines == NULL) { copy->Lines = curline; } // check if there is text on the line if(lines->Text == NULL) { // no text, make it blankz0r curline->Text = (char*)SafeMalloc(sizeof(char)); curline->Text[0] = '\0'; } else { // there is text, copy it and null-terminate curline->Text = (char*)SafeMalloc(strlen(lines->Text) + 1); strncpy(curline->Text, lines->Text, strlen(lines->Text)); curline->Text[strlen(lines->Text)] = '\0'; } // up the line count and make us the last line copy->LineCount++; lastLine = curline; } // return our new copy return copy; } } /*------------------------------------------------------------------------ Procedure: editbuffer_destroy ID:1 Author: Chris Watford watford@uiuc.edu Purpose: Destroys an edit buffer Input: Output: Errors: ------------------------------------------------------------------------*/ void editbuffer_destroy(EditBuffer* edBuf) { // sanity checks if(edBuf == NULL) { // nothing to do return; } else if(edBuf->Lines != NULL) { LineList* lastline = NULL; // loop through each line free'ing its text for( ; edBuf->Lines != NULL; edBuf->Lines = edBuf->Lines->Next) { if(edBuf->Lines->Text != NULL) free(edBuf->Lines->Text); // if there was a line before us, free it if(lastline != NULL) { free(lastline); lastline = NULL; } lastline = edBuf->Lines; } // free the last line free(lastline); } // free ourself free(edBuf); } /*------------------------------------------------------------------------ Procedure: editbuffer_new ID:1 Author: Chris Watford watford@uiuc.edu Purpose: Creates an edit buffer Input: Output: Errors: -------------------------------------------------------------------------- Edit History: 06 Oct 2003 - Chris Watford watford@uiuc.edu - Added isCorrect flag ------------------------------------------------------------------------*/ EditBuffer* editbuffer_new(void) { // create a new one EditBuffer *edBuf = (EditBuffer*)SafeMalloc(sizeof(EditBuffer)); // default vals edBuf->LineCount = 0; edBuf->Lines = NULL; edBuf->isCorrect = FALSE; // return it return edBuf; }