From 90573296ea2541a79684c890c55f093d770932da Mon Sep 17 00:00:00 2001 From: David Lawrence Ramsey Date: Fri, 8 Jul 2005 02:47:05 +0000 Subject: [PATCH] reorder some functions for consistency git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@2830 35c25a1d-7b9e-4130-9fde-d3aeb78583b8 --- ChangeLog | 1 + src/files.c | 542 ++++++++++++++++++------------------ src/nano.c | 772 ++++++++++++++++++++++++++-------------------------- src/proto.h | 64 ++--- 4 files changed, 690 insertions(+), 689 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7eac5d27..dc6b1559 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,7 @@ CVS code - saved as an int instead of a ssize_t. Changes to renumber_all(), renumber(), do_alt_speller(), and backup_lines(). (DLR) + - Reorder some functions for consistency. (DLR) - global.c: shortcut_init() - Simplify wording of nano_gotoline_msg. (Jordi) diff --git a/src/files.c b/src/files.c index c4bd3265..2c5a79d7 100644 --- a/src/files.c +++ b/src/files.c @@ -40,6 +40,277 @@ static file_format fmt = NIX_FILE; /* The format of the current file. */ +#ifdef ENABLE_MULTIBUFFER +/* Create a new openfilestruct node. */ +openfilestruct *make_new_opennode(void) +{ + openfilestruct *newnode = + (openfilestruct *)nmalloc(sizeof(openfilestruct)); + newnode->filename = NULL; + + return newnode; +} + +/* Splice a node into an existing openfilestruct. */ +void splice_opennode(openfilestruct *begin, openfilestruct *newnode, + openfilestruct *end) +{ + assert(newnode != NULL && begin != NULL); + + newnode->next = end; + newnode->prev = begin; + begin->next = newnode; + if (end != NULL) + end->prev = newnode; +} + +/* Unlink a node from the rest of the openfilestruct, and delete it. */ +void unlink_opennode(openfilestruct *fileptr) +{ + assert(fileptr != NULL && fileptr->prev != NULL && fileptr->next != NULL && fileptr != fileptr->prev && fileptr != fileptr->next); + + fileptr->prev->next = fileptr->next; + fileptr->next->prev = fileptr->prev; + delete_opennode(fileptr); +} + +/* Delete a node from the openfilestruct. */ +void delete_opennode(openfilestruct *fileptr) +{ + assert(fileptr != NULL && fileptr->filename != NULL && fileptr->fileage != NULL); + + free(fileptr->filename); + free_filestruct(fileptr->fileage); + free(fileptr); +} + +#ifdef DEBUG +/* Deallocate all memory associated with this and later files, including + * the lines of text. */ +void free_openfilestruct(openfilestruct *src) +{ + assert(src != NULL); + + while (src != src->next) { + src = src->next; + delete_opennode(src->prev); + } + delete_opennode(src); +} +#endif + +/* Add/update an entry to the open_files openfilestruct. If update is + * FALSE, a new entry is created; otherwise, the current entry is + * updated. */ +void add_open_file(bool update) +{ + if (update && open_files == NULL) + return; + + /* If there are no entries in open_files, make the first one. */ + if (open_files == NULL) { + open_files = make_new_opennode(); + splice_opennode(open_files, open_files, open_files); + /* Otherwise, if we're not updating, make a new entry for + * open_files and splice it in after the current entry. */ + } else if (!update) { + splice_opennode(open_files, make_new_opennode(), + open_files->next); + open_files = open_files->next; + } + + /* Save the current filename. */ + open_files->filename = mallocstrcpy(open_files->filename, filename); + +#ifndef NANO_SMALL + /* Save the current file's stat. */ + open_files->originalfilestat = originalfilestat; +#endif + + /* Save the current file buffer. */ + open_files->fileage = fileage; + open_files->filebot = filebot; + + /* Save the current top of the edit window. */ + open_files->edittop = edittop; + + /* Save the current line. */ + open_files->current = current; + + /* Save the current cursor position. */ + open_files->current_x = current_x; + + /* Save the current place we want. */ + open_files->placewewant = placewewant; + + /* Save the current total number of lines. */ + open_files->totlines = totlines; + + /* Save the current total size. */ + open_files->totsize = totsize; + + /* Start with no flags saved. */ + open_files->flags = 0; + + /* Save the current modification status. */ + if (ISSET(MODIFIED)) + open_files->flags |= MODIFIED; + +#ifndef NANO_SMALL + /* Save the current marking status and mark, if applicable. */ + if (ISSET(MARK_ISSET)) { + open_files->flags |= MARK_ISSET; + open_files->mark_beginbuf = mark_beginbuf; + open_files->mark_beginx = mark_beginx; + } + + /* Save the current file format. */ + open_files->fmt = fmt; +#endif + +#ifdef DEBUG + fprintf(stderr, "filename is %s\n", open_files->filename); +#endif +} + +/* Read the current entry in the open_files structure and set up the + * currently open file buffer using that entry's information. */ +void load_open_file(void) +{ + assert(open_files != NULL); + + /* Restore the current filename. */ + filename = mallocstrcpy(filename, open_files->filename); + +#ifndef NANO_SMALL + /* Restore the current file's stat. */ + originalfilestat = open_files->originalfilestat; +#endif + + /* Restore the current file buffer. */ + fileage = open_files->fileage; + filebot = open_files->filebot; + + /* Restore the current top of the edit window. */ + edittop = open_files->edittop; + + /* Restore the current line. */ + current = open_files->current; + + /* Restore the current cursor position. */ + current_x = open_files->current_x; + + /* Restore the current place we want. */ + placewewant = open_files->placewewant; + + /* Restore the current total number of lines. */ + totlines = open_files->totlines; + + /* Restore the current total size. */ + totsize = open_files->totsize; + + /* Restore the current modification status. */ + if (open_files->flags & MODIFIED) + SET(MODIFIED); + else + UNSET(MODIFIED); + +#ifndef NANO_SMALL + /* Restore the current marking status and mark, if applicable. */ + if (open_files->flags & MARK_ISSET) { + mark_beginbuf = open_files->mark_beginbuf; + mark_beginx = open_files->mark_beginx; + SET(MARK_ISSET); + } else + UNSET(MARK_ISSET); + + /* Restore the current file format. */ + fmt = open_files->fmt; +#endif + +#ifdef ENABLE_COLOR + update_color(); +#endif + edit_refresh(); + + /* Update the titlebar. */ + titlebar(NULL); +} + +/* Open either the next or previous file buffer. */ +void open_prevnext_file(bool next_file) +{ + assert(open_files != NULL); + + add_open_file(TRUE); + + /* If only one file buffer is open, indicate it on the statusbar and + * get out. */ + if (open_files == open_files->next) { + statusbar(_("No more open file buffers")); + return; + } + + /* Switch to the next or previous file, depending on the value of + * next. */ + open_files = next_file ? open_files->next : open_files->prev; + +#ifdef DEBUG + fprintf(stderr, "filename is %s\n", open_files->filename); +#endif + + /* Load the file we switched to. */ + load_open_file(); + + /* And indicate the switch on the statusbar. */ + statusbar(_("Switched to %s"), + ((open_files->filename[0] == '\0') ? _("New Buffer") : + open_files->filename)); + +#ifdef DEBUG + dump_buffer(current); +#endif +} + +/* Open the previous entry in the open_files structure. This function + * is used by the shortcut list. */ +void open_prevfile_void(void) +{ + open_prevnext_file(FALSE); +} + +/* Open the next entry in the open_files structure. This function is + * used by the shortcut list. */ +void open_nextfile_void(void) +{ + open_prevnext_file(TRUE); +} + +/* Delete an entry from the open_files filestruct. After deletion of an + * entry, the next entry is opened. Return TRUE on success or FALSE if + * there are no more open file buffers. */ +bool close_open_file(void) +{ + assert(open_files != NULL); + + /* If only one file is open, get out. */ + if (open_files == open_files->next) + return FALSE; + + /* Open the next file. */ + open_nextfile_void(); + + /* Close the file we had open before. */ + unlink_opennode(open_files->prev); + + /* Reinitialize the shortcut list. */ + shortcut_init(FALSE); + display_main_list(); + + return TRUE; +} +#endif /* ENABLE_MULTIBUFFER */ + /* What happens when there is no file to open? aiee! */ void new_file(void) { @@ -714,277 +985,6 @@ void do_insertfile_void(void) display_main_list(); } -#ifdef ENABLE_MULTIBUFFER -/* Create a new openfilestruct node. */ -openfilestruct *make_new_opennode(void) -{ - openfilestruct *newnode = - (openfilestruct *)nmalloc(sizeof(openfilestruct)); - newnode->filename = NULL; - - return newnode; -} - -/* Splice a node into an existing openfilestruct. */ -void splice_opennode(openfilestruct *begin, openfilestruct *newnode, - openfilestruct *end) -{ - assert(newnode != NULL && begin != NULL); - - newnode->next = end; - newnode->prev = begin; - begin->next = newnode; - if (end != NULL) - end->prev = newnode; -} - -/* Unlink a node from the rest of the openfilestruct, and delete it. */ -void unlink_opennode(openfilestruct *fileptr) -{ - assert(fileptr != NULL && fileptr->prev != NULL && fileptr->next != NULL && fileptr != fileptr->prev && fileptr != fileptr->next); - - fileptr->prev->next = fileptr->next; - fileptr->next->prev = fileptr->prev; - delete_opennode(fileptr); -} - -/* Delete a node from the openfilestruct. */ -void delete_opennode(openfilestruct *fileptr) -{ - assert(fileptr != NULL && fileptr->filename != NULL && fileptr->fileage != NULL); - - free(fileptr->filename); - free_filestruct(fileptr->fileage); - free(fileptr); -} - -#ifdef DEBUG -/* Deallocate all memory associated with this and later files, including - * the lines of text. */ -void free_openfilestruct(openfilestruct *src) -{ - assert(src != NULL); - - while (src != src->next) { - src = src->next; - delete_opennode(src->prev); - } - delete_opennode(src); -} -#endif - -/* Add/update an entry to the open_files openfilestruct. If update is - * FALSE, a new entry is created; otherwise, the current entry is - * updated. */ -void add_open_file(bool update) -{ - if (update && open_files == NULL) - return; - - /* If there are no entries in open_files, make the first one. */ - if (open_files == NULL) { - open_files = make_new_opennode(); - splice_opennode(open_files, open_files, open_files); - /* Otherwise, if we're not updating, make a new entry for - * open_files and splice it in after the current entry. */ - } else if (!update) { - splice_opennode(open_files, make_new_opennode(), - open_files->next); - open_files = open_files->next; - } - - /* Save the current filename. */ - open_files->filename = mallocstrcpy(open_files->filename, filename); - -#ifndef NANO_SMALL - /* Save the current file's stat. */ - open_files->originalfilestat = originalfilestat; -#endif - - /* Save the current file buffer. */ - open_files->fileage = fileage; - open_files->filebot = filebot; - - /* Save the current top of the edit window. */ - open_files->edittop = edittop; - - /* Save the current line. */ - open_files->current = current; - - /* Save the current cursor position. */ - open_files->current_x = current_x; - - /* Save the current place we want. */ - open_files->placewewant = placewewant; - - /* Save the current total number of lines. */ - open_files->totlines = totlines; - - /* Save the current total size. */ - open_files->totsize = totsize; - - /* Start with no flags saved. */ - open_files->flags = 0; - - /* Save the current modification status. */ - if (ISSET(MODIFIED)) - open_files->flags |= MODIFIED; - -#ifndef NANO_SMALL - /* Save the current marking status and mark, if applicable. */ - if (ISSET(MARK_ISSET)) { - open_files->flags |= MARK_ISSET; - open_files->mark_beginbuf = mark_beginbuf; - open_files->mark_beginx = mark_beginx; - } - - /* Save the current file format. */ - open_files->fmt = fmt; -#endif - -#ifdef DEBUG - fprintf(stderr, "filename is %s\n", open_files->filename); -#endif -} - -/* Read the current entry in the open_files structure and set up the - * currently open file buffer using that entry's information. */ -void load_open_file(void) -{ - assert(open_files != NULL); - - /* Restore the current filename. */ - filename = mallocstrcpy(filename, open_files->filename); - -#ifndef NANO_SMALL - /* Restore the current file's stat. */ - originalfilestat = open_files->originalfilestat; -#endif - - /* Restore the current file buffer. */ - fileage = open_files->fileage; - filebot = open_files->filebot; - - /* Restore the current top of the edit window. */ - edittop = open_files->edittop; - - /* Restore the current line. */ - current = open_files->current; - - /* Restore the current cursor position. */ - current_x = open_files->current_x; - - /* Restore the current place we want. */ - placewewant = open_files->placewewant; - - /* Restore the current total number of lines. */ - totlines = open_files->totlines; - - /* Restore the current total size. */ - totsize = open_files->totsize; - - /* Restore the current modification status. */ - if (open_files->flags & MODIFIED) - SET(MODIFIED); - else - UNSET(MODIFIED); - -#ifndef NANO_SMALL - /* Restore the current marking status and mark, if applicable. */ - if (open_files->flags & MARK_ISSET) { - mark_beginbuf = open_files->mark_beginbuf; - mark_beginx = open_files->mark_beginx; - SET(MARK_ISSET); - } else - UNSET(MARK_ISSET); - - /* Restore the current file format. */ - fmt = open_files->fmt; -#endif - -#ifdef ENABLE_COLOR - update_color(); -#endif - edit_refresh(); - - /* Update the titlebar. */ - titlebar(NULL); -} - -/* Open either the next or previous file buffer. */ -void open_prevnext_file(bool next_file) -{ - assert(open_files != NULL); - - add_open_file(TRUE); - - /* If only one file buffer is open, indicate it on the statusbar and - * get out. */ - if (open_files == open_files->next) { - statusbar(_("No more open file buffers")); - return; - } - - /* Switch to the next or previous file, depending on the value of - * next. */ - open_files = next_file ? open_files->next : open_files->prev; - -#ifdef DEBUG - fprintf(stderr, "filename is %s\n", open_files->filename); -#endif - - /* Load the file we switched to. */ - load_open_file(); - - /* And indicate the switch on the statusbar. */ - statusbar(_("Switched to %s"), - ((open_files->filename[0] == '\0') ? _("New Buffer") : - open_files->filename)); - -#ifdef DEBUG - dump_buffer(current); -#endif -} - -/* Open the previous entry in the open_files structure. This function - * is used by the shortcut list. */ -void open_prevfile_void(void) -{ - open_prevnext_file(FALSE); -} - -/* Open the next entry in the open_files structure. This function is - * used by the shortcut list. */ -void open_nextfile_void(void) -{ - open_prevnext_file(TRUE); -} - -/* Delete an entry from the open_files filestruct. After deletion of an - * entry, the next entry is opened. Return TRUE on success or FALSE if - * there are no more open file buffers. */ -bool close_open_file(void) -{ - assert(open_files != NULL); - - /* If only one file is open, get out. */ - if (open_files == open_files->next) - return FALSE; - - /* Open the next file. */ - open_nextfile_void(); - - /* Close the file we had open before. */ - unlink_opennode(open_files->prev); - - /* Reinitialize the shortcut list. */ - shortcut_init(FALSE); - display_main_list(); - - return TRUE; -} -#endif /* ENABLE_MULTIBUFFER */ - /* When passed "[relative path]" or "[relative path][filename]" in * origpath, return "[full path]" or "[full path][filename]" on success, * or NULL on error. Do this if the file doesn't exist but the relative diff --git a/src/nano.c b/src/nano.c index e20c18ad..c6257e84 100644 --- a/src/nano.c +++ b/src/nano.c @@ -78,6 +78,392 @@ static filestruct *jusbottom = NULL; /* Pointer to end of justify buffer. */ #endif +/* Create a new filestruct node. Note that we specifically do not set + * prevnode->next equal to the new line. */ +filestruct *make_new_node(filestruct *prevnode) +{ + filestruct *newnode = (filestruct *)nmalloc(sizeof(filestruct)); + + newnode->data = NULL; + newnode->prev = prevnode; + newnode->next = NULL; + newnode->lineno = (prevnode != NULL) ? prevnode->lineno + 1 : 1; + + return newnode; +} + +/* Make a copy of a filestruct node. */ +filestruct *copy_node(const filestruct *src) +{ + filestruct *dst; + + assert(src != NULL); + + dst = (filestruct *)nmalloc(sizeof(filestruct)); + + dst->data = mallocstrcpy(NULL, src->data); + dst->next = src->next; + dst->prev = src->prev; + dst->lineno = src->lineno; + + return dst; +} + +/* Splice a node into an existing filestruct. */ +void splice_node(filestruct *begin, filestruct *newnode, filestruct + *end) +{ + assert(newnode != NULL && begin != NULL); + + newnode->next = end; + newnode->prev = begin; + begin->next = newnode; + if (end != NULL) + end->prev = newnode; +} + +/* Unlink a node from the rest of the filestruct. */ +void unlink_node(const filestruct *fileptr) +{ + assert(fileptr != NULL); + + if (fileptr->prev != NULL) + fileptr->prev->next = fileptr->next; + if (fileptr->next != NULL) + fileptr->next->prev = fileptr->prev; +} + +/* Delete a node from the filestruct. */ +void delete_node(filestruct *fileptr) +{ + assert(fileptr != NULL && fileptr->data != NULL); + + if (fileptr->data != NULL) + free(fileptr->data); + free(fileptr); +} + +/* Duplicate a whole filestruct. */ +filestruct *copy_filestruct(const filestruct *src) +{ + filestruct *head, *copy; + + assert(src != NULL); + + copy = copy_node(src); + copy->prev = NULL; + head = copy; + src = src->next; + + while (src != NULL) { + copy->next = copy_node(src); + copy->next->prev = copy; + copy = copy->next; + + src = src->next; + } + copy->next = NULL; + + return head; +} + +/* Frees a filestruct. */ +void free_filestruct(filestruct *src) +{ + assert(src != NULL); + + while (src->next != NULL) { + src = src->next; + delete_node(src->prev); + } + delete_node(src); +} + +void renumber_all(void) +{ + filestruct *temp; + ssize_t line = 1; + + assert(fileage == NULL || fileage != fileage->next); + + for (temp = fileage; temp != NULL; temp = temp->next) + temp->lineno = line++; +} + +void renumber(filestruct *fileptr) +{ + if (fileptr == NULL || fileptr->prev == NULL || fileptr == fileage) + renumber_all(); + else { + ssize_t line = fileptr->prev->lineno; + + assert(fileptr != fileptr->next); + + for (; fileptr != NULL; fileptr = fileptr->next) + fileptr->lineno = ++line; + } +} + +/* Partition a filestruct so it begins at (top, top_x) and ends at (bot, + * bot_x). */ +partition *partition_filestruct(filestruct *top, size_t top_x, + filestruct *bot, size_t bot_x) +{ + partition *p; + + assert(top != NULL && bot != NULL && fileage != NULL && filebot != NULL); + + /* Initialize the partition. */ + p = (partition *)nmalloc(sizeof(partition)); + + /* If the top and bottom of the partition are different from the top + * and bottom of the filestruct, save the latter and then set them + * to top and bot. */ + if (top != fileage) { + p->fileage = fileage; + fileage = top; + } else + p->fileage = NULL; + if (bot != filebot) { + p->filebot = filebot; + filebot = bot; + } else + p->filebot = NULL; + + /* Save the line above the top of the partition, detach the top of + * the partition from it, and save the text before top_x in + * top_data. */ + p->top_prev = top->prev; + top->prev = NULL; + p->top_data = mallocstrncpy(NULL, top->data, top_x + 1); + p->top_data[top_x] = '\0'; + + /* Save the line below the bottom of the partition, detach the + * bottom of the partition from it, and save the text after bot_x in + * bot_data. */ + p->bot_next = bot->next; + bot->next = NULL; + p->bot_data = mallocstrcpy(NULL, bot->data + bot_x); + + /* Remove all text after bot_x at the bottom of the partition. */ + null_at(&bot->data, bot_x); + + /* Remove all text before top_x at the top of the partition. */ + charmove(top->data, top->data + top_x, strlen(top->data) - + top_x + 1); + align(&top->data); + + /* Return the partition. */ + return p; +} + +/* Unpartition a filestruct so it begins at (fileage, 0) and ends at + * (filebot, strlen(filebot)) again. */ +void unpartition_filestruct(partition **p) +{ + char *tmp; + + assert(p != NULL && fileage != NULL && filebot != NULL); + + /* Reattach the line above the top of the partition, and restore the + * text before top_x from top_data. Free top_data when we're done + * with it. */ + tmp = mallocstrcpy(NULL, fileage->data); + fileage->prev = (*p)->top_prev; + if (fileage->prev != NULL) + fileage->prev->next = fileage; + fileage->data = charealloc(fileage->data, strlen((*p)->top_data) + + strlen(fileage->data) + 1); + strcpy(fileage->data, (*p)->top_data); + free((*p)->top_data); + strcat(fileage->data, tmp); + free(tmp); + + /* Reattach the line below the bottom of the partition, and restore + * the text after bot_x from bot_data. Free bot_data when we're + * done with it. */ + filebot->next = (*p)->bot_next; + if (filebot->next != NULL) + filebot->next->prev = filebot; + filebot->data = charealloc(filebot->data, strlen(filebot->data) + + strlen((*p)->bot_data) + 1); + strcat(filebot->data, (*p)->bot_data); + free((*p)->bot_data); + + /* Restore the top and bottom of the filestruct, if they were + * different from the top and bottom of the partition. */ + if ((*p)->fileage != NULL) + fileage = (*p)->fileage; + if ((*p)->filebot != NULL) + filebot = (*p)->filebot; + + /* Uninitialize the partition. */ + free(*p); + *p = NULL; +} + +/* Move all the text between (top, top_x) and (bot, bot_x) in the + * current filestruct to a filestruct beginning with file_top and ending + * with file_bot. If no text is between (top, top_x) and (bot, bot_x), + * don't do anything. */ +void move_to_filestruct(filestruct **file_top, filestruct **file_bot, + filestruct *top, size_t top_x, filestruct *bot, size_t bot_x) +{ + filestruct *top_save; + size_t part_totsize; + bool at_edittop; +#ifndef NANO_SMALL + bool mark_inside = FALSE; +#endif + + assert(file_top != NULL && file_bot != NULL && top != NULL && bot != NULL); + + /* If (top, top_x)-(bot, bot_x) doesn't cover any text, get out. */ + if (top == bot && top_x == bot_x) + return; + + /* Partition the filestruct so that it contains only the text from + * (top, top_x) to (bot, bot_x), keep track of whether the top of + * the partition is the top of the edit window, and keep track of + * whether the mark begins inside the partition. */ + filepart = partition_filestruct(top, top_x, bot, bot_x); + at_edittop = (fileage == edittop); +#ifndef NANO_SMALL + if (ISSET(MARK_ISSET)) + mark_inside = (mark_beginbuf->lineno >= fileage->lineno && + mark_beginbuf->lineno <= filebot->lineno && + (mark_beginbuf != fileage || mark_beginx >= top_x) && + (mark_beginbuf != filebot || mark_beginx <= bot_x)); +#endif + + /* Get the number of characters in the text, and subtract it from + * totsize. */ + get_totals(top, bot, NULL, &part_totsize); + totsize -= part_totsize; + + if (*file_top == NULL) { + /* If file_top is empty, just move all the text directly into + * it. This is equivalent to tacking the text in top onto the + * (lack of) text at the end of file_top. */ + *file_top = fileage; + *file_bot = filebot; + } else { + /* Otherwise, tack the text in top onto the text at the end of + * file_bot. */ + (*file_bot)->data = charealloc((*file_bot)->data, + strlen((*file_bot)->data) + strlen(fileage->data) + 1); + strcat((*file_bot)->data, fileage->data); + + /* Attach the line after top to the line after file_bot. Then, + * if there's more than one line after top, move file_bot down + * to bot. */ + (*file_bot)->next = fileage->next; + if ((*file_bot)->next != NULL) { + (*file_bot)->next->prev = *file_bot; + *file_bot = filebot; + } + } + + /* Since the text has now been saved, remove it from the filestruct. + * If the top of the partition was the top of the edit window, set + * edittop to where the text used to start. If the mark began + * inside the partition, set the beginning of the mark to where the + * text used to start. */ + fileage = (filestruct *)nmalloc(sizeof(filestruct)); + fileage->data = mallocstrcpy(NULL, ""); + filebot = fileage; + if (at_edittop) + edittop = fileage; +#ifndef NANO_SMALL + if (mark_inside) { + mark_beginbuf = fileage; + mark_beginx = top_x; + } +#endif + + /* Restore the current line and cursor position. */ + current = fileage; + current_x = top_x; + + top_save = fileage; + + /* Unpartition the filestruct so that it contains all the text + * again, minus the saved text. */ + unpartition_filestruct(&filepart); + + /* Renumber starting with the beginning line of the old + * partition. */ + renumber(top_save); + + if (filebot->data[0] != '\0') + new_magicline(); + + /* Set totlines to the new number of lines in the file. */ + totlines = filebot->lineno; +} + +/* Copy all the text from the filestruct beginning with file_top and + * ending with file_bot to the current filestruct at the current cursor + * position. */ +void copy_from_filestruct(filestruct *file_top, filestruct *file_bot) +{ + filestruct *top_save; + size_t part_totlines, part_totsize; + bool at_edittop; + + assert(file_top != NULL && file_bot != NULL); + + /* Partition the filestruct so that it contains no text, and keep + * track of whether the top of the partition is the top of the edit + * window. */ + filepart = partition_filestruct(current, current_x, current, + current_x); + at_edittop = (fileage == edittop); + + /* Put the top and bottom of the filestruct at copies of file_top + * and file_bot. */ + fileage = copy_filestruct(file_top); + filebot = fileage; + while (filebot->next != NULL) + filebot = filebot->next; + + /* Restore the current line and cursor position. */ + current = filebot; + current_x = strlen(filebot->data); + if (fileage == filebot) + current_x += strlen(filepart->top_data); + + /* Get the number of lines and the number of characters in the saved + * text, and add the latter to totsize. */ + get_totals(fileage, filebot, &part_totlines, &part_totsize); + totsize += part_totsize; + + /* If the top of the partition was the top of the edit window, set + * edittop to where the saved text now starts, and update the + * current y-coordinate to account for the number of lines it + * has, less one since the first line will be tacked onto the + * current line. */ + if (at_edittop) + edittop = fileage; + current_y += part_totlines - 1; + + top_save = fileage; + + /* Unpartition the filestruct so that it contains all the text + * again, minus the saved text. */ + unpartition_filestruct(&filepart); + + /* Renumber starting with the beginning line of the old + * partition. */ + renumber(top_save); + + if (filebot->data[0] != '\0') + new_magicline(); + + /* Set totlines to the new number of lines in the file. */ + totlines = filebot->lineno; +} + void print_view_warning(void) { statusbar(_("Key illegal in VIEW mode")); @@ -590,392 +976,6 @@ void help_init(void) } #endif -/* Create a new filestruct node. Note that we specifically do not set - * prevnode->next equal to the new line. */ -filestruct *make_new_node(filestruct *prevnode) -{ - filestruct *newnode = (filestruct *)nmalloc(sizeof(filestruct)); - - newnode->data = NULL; - newnode->prev = prevnode; - newnode->next = NULL; - newnode->lineno = (prevnode != NULL) ? prevnode->lineno + 1 : 1; - - return newnode; -} - -/* Make a copy of a filestruct node. */ -filestruct *copy_node(const filestruct *src) -{ - filestruct *dst; - - assert(src != NULL); - - dst = (filestruct *)nmalloc(sizeof(filestruct)); - - dst->data = mallocstrcpy(NULL, src->data); - dst->next = src->next; - dst->prev = src->prev; - dst->lineno = src->lineno; - - return dst; -} - -/* Splice a node into an existing filestruct. */ -void splice_node(filestruct *begin, filestruct *newnode, filestruct - *end) -{ - assert(newnode != NULL && begin != NULL); - - newnode->next = end; - newnode->prev = begin; - begin->next = newnode; - if (end != NULL) - end->prev = newnode; -} - -/* Unlink a node from the rest of the filestruct. */ -void unlink_node(const filestruct *fileptr) -{ - assert(fileptr != NULL); - - if (fileptr->prev != NULL) - fileptr->prev->next = fileptr->next; - if (fileptr->next != NULL) - fileptr->next->prev = fileptr->prev; -} - -/* Delete a node from the filestruct. */ -void delete_node(filestruct *fileptr) -{ - assert(fileptr != NULL && fileptr->data != NULL); - - if (fileptr->data != NULL) - free(fileptr->data); - free(fileptr); -} - -/* Duplicate a whole filestruct. */ -filestruct *copy_filestruct(const filestruct *src) -{ - filestruct *head, *copy; - - assert(src != NULL); - - copy = copy_node(src); - copy->prev = NULL; - head = copy; - src = src->next; - - while (src != NULL) { - copy->next = copy_node(src); - copy->next->prev = copy; - copy = copy->next; - - src = src->next; - } - copy->next = NULL; - - return head; -} - -/* Frees a filestruct. */ -void free_filestruct(filestruct *src) -{ - assert(src != NULL); - - while (src->next != NULL) { - src = src->next; - delete_node(src->prev); - } - delete_node(src); -} - -/* Partition a filestruct so it begins at (top, top_x) and ends at (bot, - * bot_x). */ -partition *partition_filestruct(filestruct *top, size_t top_x, - filestruct *bot, size_t bot_x) -{ - partition *p; - - assert(top != NULL && bot != NULL && fileage != NULL && filebot != NULL); - - /* Initialize the partition. */ - p = (partition *)nmalloc(sizeof(partition)); - - /* If the top and bottom of the partition are different from the top - * and bottom of the filestruct, save the latter and then set them - * to top and bot. */ - if (top != fileage) { - p->fileage = fileage; - fileage = top; - } else - p->fileage = NULL; - if (bot != filebot) { - p->filebot = filebot; - filebot = bot; - } else - p->filebot = NULL; - - /* Save the line above the top of the partition, detach the top of - * the partition from it, and save the text before top_x in - * top_data. */ - p->top_prev = top->prev; - top->prev = NULL; - p->top_data = mallocstrncpy(NULL, top->data, top_x + 1); - p->top_data[top_x] = '\0'; - - /* Save the line below the bottom of the partition, detach the - * bottom of the partition from it, and save the text after bot_x in - * bot_data. */ - p->bot_next = bot->next; - bot->next = NULL; - p->bot_data = mallocstrcpy(NULL, bot->data + bot_x); - - /* Remove all text after bot_x at the bottom of the partition. */ - null_at(&bot->data, bot_x); - - /* Remove all text before top_x at the top of the partition. */ - charmove(top->data, top->data + top_x, strlen(top->data) - - top_x + 1); - align(&top->data); - - /* Return the partition. */ - return p; -} - -/* Unpartition a filestruct so it begins at (fileage, 0) and ends at - * (filebot, strlen(filebot)) again. */ -void unpartition_filestruct(partition **p) -{ - char *tmp; - - assert(p != NULL && fileage != NULL && filebot != NULL); - - /* Reattach the line above the top of the partition, and restore the - * text before top_x from top_data. Free top_data when we're done - * with it. */ - tmp = mallocstrcpy(NULL, fileage->data); - fileage->prev = (*p)->top_prev; - if (fileage->prev != NULL) - fileage->prev->next = fileage; - fileage->data = charealloc(fileage->data, strlen((*p)->top_data) + - strlen(fileage->data) + 1); - strcpy(fileage->data, (*p)->top_data); - free((*p)->top_data); - strcat(fileage->data, tmp); - free(tmp); - - /* Reattach the line below the bottom of the partition, and restore - * the text after bot_x from bot_data. Free bot_data when we're - * done with it. */ - filebot->next = (*p)->bot_next; - if (filebot->next != NULL) - filebot->next->prev = filebot; - filebot->data = charealloc(filebot->data, strlen(filebot->data) + - strlen((*p)->bot_data) + 1); - strcat(filebot->data, (*p)->bot_data); - free((*p)->bot_data); - - /* Restore the top and bottom of the filestruct, if they were - * different from the top and bottom of the partition. */ - if ((*p)->fileage != NULL) - fileage = (*p)->fileage; - if ((*p)->filebot != NULL) - filebot = (*p)->filebot; - - /* Uninitialize the partition. */ - free(*p); - *p = NULL; -} - -/* Move all the text between (top, top_x) and (bot, bot_x) in the - * current filestruct to a filestruct beginning with file_top and ending - * with file_bot. If no text is between (top, top_x) and (bot, bot_x), - * don't do anything. */ -void move_to_filestruct(filestruct **file_top, filestruct **file_bot, - filestruct *top, size_t top_x, filestruct *bot, size_t bot_x) -{ - filestruct *top_save; - size_t part_totsize; - bool at_edittop; -#ifndef NANO_SMALL - bool mark_inside = FALSE; -#endif - - assert(file_top != NULL && file_bot != NULL && top != NULL && bot != NULL); - - /* If (top, top_x)-(bot, bot_x) doesn't cover any text, get out. */ - if (top == bot && top_x == bot_x) - return; - - /* Partition the filestruct so that it contains only the text from - * (top, top_x) to (bot, bot_x), keep track of whether the top of - * the partition is the top of the edit window, and keep track of - * whether the mark begins inside the partition. */ - filepart = partition_filestruct(top, top_x, bot, bot_x); - at_edittop = (fileage == edittop); -#ifndef NANO_SMALL - if (ISSET(MARK_ISSET)) - mark_inside = (mark_beginbuf->lineno >= fileage->lineno && - mark_beginbuf->lineno <= filebot->lineno && - (mark_beginbuf != fileage || mark_beginx >= top_x) && - (mark_beginbuf != filebot || mark_beginx <= bot_x)); -#endif - - /* Get the number of characters in the text, and subtract it from - * totsize. */ - get_totals(top, bot, NULL, &part_totsize); - totsize -= part_totsize; - - if (*file_top == NULL) { - /* If file_top is empty, just move all the text directly into - * it. This is equivalent to tacking the text in top onto the - * (lack of) text at the end of file_top. */ - *file_top = fileage; - *file_bot = filebot; - } else { - /* Otherwise, tack the text in top onto the text at the end of - * file_bot. */ - (*file_bot)->data = charealloc((*file_bot)->data, - strlen((*file_bot)->data) + strlen(fileage->data) + 1); - strcat((*file_bot)->data, fileage->data); - - /* Attach the line after top to the line after file_bot. Then, - * if there's more than one line after top, move file_bot down - * to bot. */ - (*file_bot)->next = fileage->next; - if ((*file_bot)->next != NULL) { - (*file_bot)->next->prev = *file_bot; - *file_bot = filebot; - } - } - - /* Since the text has now been saved, remove it from the filestruct. - * If the top of the partition was the top of the edit window, set - * edittop to where the text used to start. If the mark began - * inside the partition, set the beginning of the mark to where the - * text used to start. */ - fileage = (filestruct *)nmalloc(sizeof(filestruct)); - fileage->data = mallocstrcpy(NULL, ""); - filebot = fileage; - if (at_edittop) - edittop = fileage; -#ifndef NANO_SMALL - if (mark_inside) { - mark_beginbuf = fileage; - mark_beginx = top_x; - } -#endif - - /* Restore the current line and cursor position. */ - current = fileage; - current_x = top_x; - - top_save = fileage; - - /* Unpartition the filestruct so that it contains all the text - * again, minus the saved text. */ - unpartition_filestruct(&filepart); - - /* Renumber starting with the beginning line of the old - * partition. */ - renumber(top_save); - - if (filebot->data[0] != '\0') - new_magicline(); - - /* Set totlines to the new number of lines in the file. */ - totlines = filebot->lineno; -} - -/* Copy all the text from the filestruct beginning with file_top and - * ending with file_bot to the current filestruct at the current cursor - * position. */ -void copy_from_filestruct(filestruct *file_top, filestruct *file_bot) -{ - filestruct *top_save; - size_t part_totlines, part_totsize; - bool at_edittop; - - assert(file_top != NULL && file_bot != NULL); - - /* Partition the filestruct so that it contains no text, and keep - * track of whether the top of the partition is the top of the edit - * window. */ - filepart = partition_filestruct(current, current_x, current, - current_x); - at_edittop = (fileage == edittop); - - /* Put the top and bottom of the filestruct at copies of file_top - * and file_bot. */ - fileage = copy_filestruct(file_top); - filebot = fileage; - while (filebot->next != NULL) - filebot = filebot->next; - - /* Restore the current line and cursor position. */ - current = filebot; - current_x = strlen(filebot->data); - if (fileage == filebot) - current_x += strlen(filepart->top_data); - - /* Get the number of lines and the number of characters in the saved - * text, and add the latter to totsize. */ - get_totals(fileage, filebot, &part_totlines, &part_totsize); - totsize += part_totsize; - - /* If the top of the partition was the top of the edit window, set - * edittop to where the saved text now starts, and update the - * current y-coordinate to account for the number of lines it - * has, less one since the first line will be tacked onto the - * current line. */ - if (at_edittop) - edittop = fileage; - current_y += part_totlines - 1; - - top_save = fileage; - - /* Unpartition the filestruct so that it contains all the text - * again, minus the saved text. */ - unpartition_filestruct(&filepart); - - /* Renumber starting with the beginning line of the old - * partition. */ - renumber(top_save); - - if (filebot->data[0] != '\0') - new_magicline(); - - /* Set totlines to the new number of lines in the file. */ - totlines = filebot->lineno; -} - -void renumber_all(void) -{ - filestruct *temp; - ssize_t line = 1; - - assert(fileage == NULL || fileage != fileage->next); - - for (temp = fileage; temp != NULL; temp = temp->next) - temp->lineno = line++; -} - -void renumber(filestruct *fileptr) -{ - if (fileptr == NULL || fileptr->prev == NULL || fileptr == fileage) - renumber_all(); - else { - ssize_t line = fileptr->prev->lineno; - - assert(fileptr != fileptr->next); - - for (; fileptr != NULL; fileptr = fileptr->next) - fileptr->lineno = ++line; - } -} - #ifdef HAVE_GETOPT_LONG #define print1opt(shortflag, longflag, desc) print1opt_full(shortflag, longflag, desc) #else diff --git a/src/proto.h b/src/proto.h index 33c26f4b..53d7ab50 100644 --- a/src/proto.h +++ b/src/proto.h @@ -246,6 +246,22 @@ void do_cut_till_end(void); void do_uncut_text(void); /* Public functions in files.c. */ +#ifdef ENABLE_MULTIBUFFER +openfilestruct *make_new_opennode(void); +void splice_opennode(openfilestruct *begin, openfilestruct *newnode, + openfilestruct *end); +void unlink_opennode(openfilestruct *fileptr); +void delete_opennode(openfilestruct *fileptr); +#ifdef DEBUG +void free_openfilestruct(openfilestruct *src); +#endif +void add_open_file(bool update); +void load_open_file(void); +void open_prevnext_file(bool next_file); +void open_prevfile_void(void); +void open_nextfile_void(void); +bool close_open_file(void); +#endif void new_file(void); filestruct *read_line(char *buf, filestruct *prevnode, bool *first_line_ins, size_t buf_len); @@ -265,22 +281,6 @@ void do_insertfile( #endif ); void do_insertfile_void(void); -#ifdef ENABLE_MULTIBUFFER -openfilestruct *make_new_opennode(void); -void splice_opennode(openfilestruct *begin, openfilestruct *newnode, - openfilestruct *end); -void unlink_opennode(openfilestruct *fileptr); -void delete_opennode(openfilestruct *fileptr); -#ifdef DEBUG -void free_openfilestruct(openfilestruct *src); -#endif -void add_open_file(bool update); -void load_open_file(void); -void open_prevnext_file(bool next_file); -void open_prevfile_void(void); -void open_nextfile_void(void); -bool close_open_file(void); -#endif char *get_full_path(const char *origpath); char *check_writable_directory(const char *path); char *safe_tempfile(FILE **f); @@ -359,6 +359,22 @@ void do_right(bool allow_update); void do_right_void(void); /* Public functions in nano.c. */ +filestruct *make_new_node(filestruct *prevnode); +filestruct *copy_node(const filestruct *src); +void splice_node(filestruct *begin, filestruct *newnode, filestruct + *end); +void unlink_node(const filestruct *fileptr); +void delete_node(filestruct *fileptr); +filestruct *copy_filestruct(const filestruct *src); +void free_filestruct(filestruct *src); +void renumber_all(void); +void renumber(filestruct *fileptr); +partition *partition_filestruct(filestruct *top, size_t top_x, + filestruct *bot, size_t bot_x); +void unpartition_filestruct(partition **p); +void move_to_filestruct(filestruct **file_top, filestruct **file_bot, + filestruct *top, size_t top_x, filestruct *bot, size_t bot_x); +void copy_from_filestruct(filestruct *file_top, filestruct *file_bot); void print_view_warning(void); void finish(void); void die(const char *msg, ...); @@ -373,22 +389,6 @@ void mouse_init(void); #ifndef DISABLE_HELP void help_init(void); #endif -filestruct *make_new_node(filestruct *prevnode); -filestruct *copy_node(const filestruct *src); -void splice_node(filestruct *begin, filestruct *newnode, filestruct - *end); -void unlink_node(const filestruct *fileptr); -void delete_node(filestruct *fileptr); -filestruct *copy_filestruct(const filestruct *src); -void free_filestruct(filestruct *src); -partition *partition_filestruct(filestruct *top, size_t top_x, - filestruct *bot, size_t bot_x); -void unpartition_filestruct(partition **p); -void move_to_filestruct(filestruct **file_top, filestruct **file_bot, - filestruct *top, size_t top_x, filestruct *bot, size_t bot_x); -void copy_from_filestruct(filestruct *file_top, filestruct *file_bot); -void renumber_all(void); -void renumber(filestruct *fileptr); void print1opt_full(const char *shortflag #ifdef HAVE_GETOPT_LONG , const char *longflag