commit 5b3dd0f42355d5c3552564a98cf8cf080dced580
parent 329d6a32590aa806530a7262f4bb9f295c377c91
Author: David Lawrence Ramsey <pooka109@gmail.com>
Date: Thu, 25 Nov 2004 04:39:07 +0000
add DB's overhaul of the multibuffer code for efficiency, plus a few
tweaks and additions of mine
git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@2134 35c25a1d-7b9e-4130-9fde-d3aeb78583b8
Diffstat:
6 files changed, 194 insertions(+), 303 deletions(-)
diff --git a/ChangeLog b/ChangeLog
@@ -12,6 +12,20 @@ CVS code -
simplifies how they work, and to store such text in its own
buffer rather than the cutbuffer. Changes to backup_lines(),
do_justify(), etc. (DLR)
+ - Overhaul the multibuffer routines to increase efficiency, most
+ importantly making them use a doubly linked list for the open
+ files so that switching between them is no longer O(N), and
+ only including free_openfilestruct() when --enable-debug is
+ used. Also use some of the same efficiency tweaks when
+ dealing with filestruct nodes. New function
+ open_prevnext_file(); changes to make_new_opennode(),
+ splice_opennode(), unlink_opennode(), delete_opennode(),
+ free_openfilestruct(), add_open_file(), load_open_file(),
+ close_open_file(), shortcut_init(), die(), make_new_node(),
+ copy_node(), splice_node(), delete_node(), and
+ free_filestruct(); removal of open_prevfile() and
+ open_nextfile(). (David Benbennick, minor tweaks and additions
+ by DLR)
- cut.c:
do_cut_text()
- If keep_cutbuffer is FALSE, only blow away the text in the
diff --git a/src/files.c b/src/files.c
@@ -694,17 +694,11 @@ void do_insertfile_void(void)
#ifdef ENABLE_MULTIBUFFER
/* Create a new openfilestruct node. */
-openfilestruct *make_new_opennode(openfilestruct *prevnode)
+openfilestruct *make_new_opennode(void)
{
- openfilestruct *newnode = (openfilestruct *)nmalloc(sizeof(openfilestruct));
-
+ openfilestruct *newnode =
+ (openfilestruct *)nmalloc(sizeof(openfilestruct));
newnode->filename = NULL;
- newnode->fileage = NULL;
- newnode->filebot = NULL;
-
- newnode->prev = prevnode;
- newnode->next = NULL;
-
return newnode;
}
@@ -712,6 +706,7 @@ openfilestruct *make_new_opennode(openfilestruct *prevnode)
void splice_opennode(openfilestruct *begin, openfilestruct *newnode,
openfilestruct *end)
{
+ assert(newnode != NULL && begin != NULL);
newnode->next = end;
newnode->prev = begin;
begin->next = newnode;
@@ -719,240 +714,203 @@ void splice_opennode(openfilestruct *begin, openfilestruct *newnode,
end->prev = newnode;
}
-/* Unlink a node from the rest of the openfilestruct. */
-void unlink_opennode(const openfilestruct *fileptr)
+/* Unlink a node from the rest of the openfilestruct, and delete it. */
+void unlink_opennode(openfilestruct *fileptr)
{
- assert(fileptr != NULL);
-
- if (fileptr->prev != NULL)
- fileptr->prev->next = fileptr->next;
-
- if (fileptr->next != NULL)
- fileptr->next->prev = fileptr->prev;
+ 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)
{
- if (fileptr != NULL) {
- if (fileptr->filename != NULL)
- free(fileptr->filename);
- if (fileptr->fileage != NULL)
- free_filestruct(fileptr->fileage);
- free(fileptr);
- }
+ assert(fileptr != NULL && fileptr->filename != NULL && fileptr->fileage != NULL);
+ free(fileptr->filename);
+ free_filestruct(fileptr->fileage);
+ free(fileptr);
}
-/* Deallocate all memory associated with this and later files,
- * including the lines of text. */
+#ifdef DEBUG
+/* Deallocate all memory associated with this and later files, including
+ * the lines of text. */
void free_openfilestruct(openfilestruct *src)
{
- if (src != NULL) {
- while (src->next != NULL) {
- src = src->next;
- delete_opennode(src->prev);
-#ifdef DEBUG
- fprintf(stderr, "%s: free'd a node, YAY!\n", "delete_opennode()");
-#endif
- }
- delete_opennode(src);
-#ifdef DEBUG
- fprintf(stderr, "%s: free'd last node.\n", "delete_opennode()");
-#endif
+ 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
+/* Add/update an entry to the open_files openfilestruct. If update is
* FALSE, a new entry is created; otherwise, the current entry is
- * updated.
- */
+ * updated. */
void add_open_file(bool update)
{
- openfilestruct *tmp;
-
- if (fileage == NULL || current == NULL || filename == NULL)
+ if (open_files == NULL && update)
return;
- /* if no entries, make the first one */
- if (open_files == NULL)
- open_files = make_new_opennode(NULL);
-
- else if (!update) {
-
- /* otherwise, if we're not updating, make a new entry for
- open_files and splice it in after the current one */
-
-#ifdef DEBUG
- fprintf(stderr, "filename is %s\n", open_files->filename);
-#endif
-
- tmp = make_new_opennode(NULL);
- splice_opennode(open_files, tmp, open_files->next);
+ /* 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 current filename */
+ /* Save the current filename. */
open_files->filename = mallocstrcpy(open_files->filename, filename);
#ifndef NANO_SMALL
- /* save the file's stat */
+ /* Save the current file's stat. */
open_files->originalfilestat = originalfilestat;
#endif
- /* save current total number of lines */
- open_files->file_totlines = totlines;
+ /* 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 current total size */
- open_files->file_totsize = totsize;
+ /* Save the current cursor position. */
+ open_files->current_x = current_x;
- /* save current x-coordinate position */
- open_files->file_current_x = current_x;
+ /* Save the current place we want. */
+ open_files->placewewant = placewewant;
- /* save current y-coordinate position */
- open_files->file_current_y = current_y;
+ /* Save the current total number of lines. */
+ open_files->totlines = totlines;
- /* save current place we want */
- open_files->file_placewewant = placewewant;
+ /* Save the current total size. */
+ open_files->totsize = totsize;
- /* save current line number */
- open_files->file_lineno = current->lineno;
+ /* Start with no flags saved. */
+ open_files->flags = 0;
- /* start with default modification status: unmodified, unmarked (if
- available), not in DOS format (if available), and not in Mac
- format (if available) */
- open_files->file_flags = 0;
+ /* Save the current modification status. */
+ if (ISSET(MODIFIED))
+ open_files->flags |= MODIFIED;
- /* if we're updating, save current modification status, current
- marking status (if available), and current file format (if
- available) */
- if (update) {
- if (ISSET(MODIFIED))
- open_files->file_flags |= MODIFIED;
#ifndef NANO_SMALL
- if (ISSET(MARK_ISSET)) {
- open_files->file_mark_beginbuf = mark_beginbuf;
- open_files->file_mark_beginx = mark_beginx;
- open_files->file_flags |= MARK_ISSET;
- }
- open_files->file_fmt = fmt;
-#endif
+ /* 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;
}
- /* if we're not in view mode and not updating, the file contents
- might have changed, so save the filestruct; otherwise, don't */
- if (!(ISSET(VIEW_MODE) && !update)) {
- /* save current file buffer */
- open_files->fileage = fileage;
- open_files->filebot = filebot;
- }
+ /* 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 using that entry's information.
- */
+/* Read the current entry in the open_files structure and set up the
+ * currently open file using that entry's information. */
void load_open_file(void)
{
- if (open_files == NULL)
- return;
+ assert(open_files != NULL);
- /* set up the filename, the file buffer, the total number of lines in
- the file, and the total file size */
+ /* 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;
- current = fileage;
filebot = open_files->filebot;
- totlines = open_files->file_totlines;
- totsize = open_files->file_totsize;
- /* restore modification status */
- if (open_files->file_flags & MODIFIED)
+ /* 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 marking status */
- if (open_files->file_flags & MARK_ISSET) {
- mark_beginbuf = open_files->file_mark_beginbuf;
- mark_beginx = open_files->file_mark_beginx;
+ /* 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 file format */
- fmt = open_files->file_fmt;
+ /* Restore the current file format. */
+ fmt = open_files->fmt;
#endif
#ifdef ENABLE_COLOR
update_color();
#endif
+ edit_refresh();
- /* restore full file position: line number, x-coordinate, y-
- coordinate, place we want */
- do_gotopos(open_files->file_lineno, open_files->file_current_x,
- open_files->file_current_y, open_files->file_placewewant);
-
- /* update the titlebar */
+ /* Update the titlebar. */
clearok(topwin, FALSE);
titlebar(NULL);
}
-/*
- * Open the previous entry in the open_files structure. If closing_file
- * is FALSE, update the current entry before switching from it.
- * Otherwise, we are about to close that entry, so don't bother doing
- * so.
- */
-void open_prevfile(bool closing_file)
+/* Open either the next or previous file. */
+void open_prevnext_file(bool next)
{
- if (open_files == NULL)
- return;
-
- /* if we're not about to close the current entry, update it before
- doing anything */
- if (!closing_file)
- add_open_file(TRUE);
+ add_open_file(TRUE);
- if (open_files->prev == NULL && open_files->next == NULL) {
+ assert(open_files != NULL);
- /* only one file open */
- if (!closing_file)
- statusbar(_("No more open file buffers"));
+ /* If only one file is open, indicate it on the statusbar and get
+ * out. */
+ if (open_files == open_files->next) {
+ statusbar(_("No more open files"));
return;
}
- if (open_files->prev != NULL) {
- open_files = open_files->prev;
+ /* Switch to the next or previous file, depending on the value of
+ * next. */
+ open_files = next ? open_files->next : open_files->prev;
#ifdef DEBUG
- fprintf(stderr, "filename is %s\n", open_files->filename);
-#endif
-
- }
-
- else if (open_files->next != NULL) {
-
- /* if we're at the beginning, wrap around to the end */
- while (open_files->next != NULL)
- open_files = open_files->next;
-
-#ifdef DEBUG
- fprintf(stderr, "filename is %s\n", open_files->filename);
+ 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));
@@ -962,102 +920,41 @@ void open_prevfile(bool closing_file)
#endif
}
+/* Open the previous entry in the open_files structure. This function
+ * is used by the shortcut list. */
void open_prevfile_void(void)
{
- open_prevfile(FALSE);
-}
-
-/*
- * Open the next entry in the open_files structure. If closing_file is
- * FALSE, update the current entry before switching from it. Otherwise,
- * we are about to close that entry, so don't bother doing so.
- */
-void open_nextfile(bool closing_file)
-{
- if (open_files == NULL)
- return;
-
- /* if we're not about to close the current entry, update it before
- doing anything */
- if (!closing_file)
- add_open_file(TRUE);
-
- if (open_files->prev == NULL && open_files->next == NULL) {
-
- /* only one file open */
- if (!closing_file)
- statusbar(_("No more open file buffers"));
- return;
- }
-
- if (open_files->next != NULL) {
- open_files = open_files->next;
-
-#ifdef DEBUG
- fprintf(stderr, "filename is %s\n", open_files->filename);
-#endif
-
- }
- else if (open_files->prev != NULL) {
-
- /* if we're at the end, wrap around to the beginning */
- while (open_files->prev != NULL) {
- open_files = open_files->prev;
-
-#ifdef DEBUG
- fprintf(stderr, "filename is %s\n", open_files->filename);
-#endif
-
- }
- }
-
- load_open_file();
-
- statusbar(_("Switched to %s"),
- ((open_files->filename[0] == '\0') ? _("New Buffer") :
- open_files->filename));
-
-#ifdef DEBUG
- dump_buffer(current);
-#endif
+ 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_nextfile(FALSE);
+ open_prevnext_file(TRUE);
}
-/*
- * Delete an entry from the open_files filestruct. After deletion of an
- * entry, the next or previous entry is opened, whichever is found first.
- * Return TRUE on success or FALSE on error.
- */
+/* 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 files. */
bool close_open_file(void)
{
- openfilestruct *tmp;
+ assert(open_files != NULL);
- if (open_files == NULL)
+ /* If only one file is open, get out. */
+ if (open_files == open_files->next)
return FALSE;
- /* make sure open_files->fileage and fileage, and open_files->filebot
- and filebot, are in sync; they might not be if lines have been cut
- from the top or bottom of the file */
- open_files->fileage = fileage;
- open_files->filebot = filebot;
-
- tmp = open_files;
- if (open_files->next != NULL)
- open_nextfile(TRUE);
- else if (open_files->prev != NULL)
- open_prevfile(TRUE);
- else
- return FALSE;
+ /* Open the next file. */
+ open_nextfile_void();
- unlink_opennode(tmp);
- delete_opennode(tmp);
+ /* 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 */
diff --git a/src/global.c b/src/global.c
@@ -382,19 +382,14 @@ void shortcut_init(bool unjustify)
#endif
);
-#ifdef ENABLE_MULTIBUFFER
- if (open_files != NULL && (open_files->prev != NULL ||
- open_files->next != NULL))
/* Translators: try to keep this string under 10 characters long */
- sc_init_one(&main_list, NANO_EXIT_KEY, N_("Close"),
- IFHELP(nano_exit_msg, NANO_NO_KEY), NANO_EXIT_FKEY,
- NANO_NO_KEY, VIEW, do_exit);
- else
+ sc_init_one(&main_list, NANO_EXIT_KEY,
+#ifdef ENABLE_MULTIBUFFER
+ open_files != NULL && open_files != open_files->next ?
+ N_("Close") :
#endif
- /* Translators: try to keep this string under 10 characters long */
- sc_init_one(&main_list, NANO_EXIT_KEY, exit_msg,
- IFHELP(nano_exit_msg, NANO_NO_KEY), NANO_EXIT_FKEY,
- NANO_NO_KEY, VIEW, do_exit);
+ exit_msg, IFHELP(nano_exit_msg, NANO_NO_KEY), NANO_EXIT_FKEY,
+ NANO_NO_KEY, VIEW, do_exit);
/* Translators: try to keep this string under 10 characters long */
sc_init_one(&main_list, NANO_WRITEOUT_KEY, N_("WriteOut"),
diff --git a/src/nano.c b/src/nano.c
@@ -150,7 +150,7 @@ void die(const char *msg, ...)
fileage = open_files->fileage;
filebot = open_files->filebot;
/* save the file if it's been modified */
- if (open_files->file_flags & MODIFIED)
+ if (open_files->flags & MODIFIED)
die_save_file(open_files->filename);
}
open_files = open_files->next;
@@ -520,28 +520,22 @@ void help_init(void)
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;
-
+ newnode->lineno = (prevnode != NULL) ? prevnode->lineno + 1 : 1;
return newnode;
}
-/* Make a copy of a node to a pointer (space will be malloc()ed). */
+/* Make a copy of a filestruct node. */
filestruct *copy_node(const filestruct *src)
{
filestruct *dst = (filestruct *)nmalloc(sizeof(filestruct));
-
assert(src != NULL);
-
- dst->data = charalloc(strlen(src->data) + 1);
+ dst->data = mallocstrcpy(NULL, src->data);
dst->next = src->next;
dst->prev = src->prev;
- strcpy(dst->data, src->data);
dst->lineno = src->lineno;
-
return dst;
}
@@ -549,12 +543,10 @@ filestruct *copy_node(const filestruct *src)
void splice_node(filestruct *begin, filestruct *newnode, filestruct
*end)
{
- if (newnode != NULL) {
- newnode->next = end;
- newnode->prev = begin;
- }
- if (begin != NULL)
- begin->next = newnode;
+ assert(newnode != NULL && begin != NULL);
+ newnode->next = end;
+ newnode->prev = begin;
+ begin->next = newnode;
if (end != NULL)
end->prev = newnode;
}
@@ -563,10 +555,8 @@ void splice_node(filestruct *begin, filestruct *newnode, 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;
}
@@ -574,11 +564,10 @@ void unlink_node(const filestruct *fileptr)
/* Delete a node from the filestruct. */
void delete_node(filestruct *fileptr)
{
- if (fileptr != NULL) {
- if (fileptr->data != NULL)
- free(fileptr->data);
- free(fileptr);
- }
+ assert(fileptr != NULL && fileptr->data != NULL);
+ if (fileptr->data != NULL)
+ free(fileptr->data);
+ free(fileptr);
}
/* Okay, now let's duplicate a whole struct! */
@@ -608,19 +597,13 @@ filestruct *copy_filestruct(const filestruct *src)
/* Frees a filestruct. */
void free_filestruct(filestruct *src)
{
- if (src != NULL) {
- while (src->next != NULL) {
- src = src->next;
- delete_node(src->prev);
-#ifdef DEBUG
- fprintf(stderr, "%s: free'd a node, YAY!\n", "delete_node()");
-#endif
- }
- delete_node(src);
-#ifdef DEBUG
- fprintf(stderr, "%s: free'd last node.\n", "delete_node()");
-#endif
+ 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,
diff --git a/src/nano.h b/src/nano.h
@@ -175,30 +175,31 @@ typedef struct openfilestruct {
#ifndef NANO_SMALL
struct stat originalfilestat;
#endif
- struct openfilestruct *next; /* Next node. */
- struct openfilestruct *prev; /* Previous node. */
- struct filestruct *fileage; /* Current file. */
- struct filestruct *filebot; /* Current file's last line. */
+ struct openfilestruct *next;
+ /* Next node. */
+ struct openfilestruct *prev;
+ /* Previous node. */
+ filestruct *fileage; /* Current file. */
+ filestruct *filebot; /* Current file's last line. */
+ filestruct *edittop; /* Current top of edit window. */
+ filestruct *current; /* Current file's line. */
#ifndef NANO_SMALL
- struct filestruct *file_mark_beginbuf;
+ filestruct *mark_beginbuf;
/* Current file's beginning marked
* line. */
- size_t file_mark_beginx; /* Current file's beginning marked
+ size_t mark_beginx; /* Current file's beginning marked
* line's x-coordinate position. */
#endif
- size_t file_current_x; /* Current file's x-coordinate
+ size_t current_x; /* Current file's x-coordinate
* position. */
- int file_current_y; /* Current file's y-coordinate
- * position. */
- size_t file_placewewant; /* Current file's place we want. */
- int file_totlines; /* Current file's total number of
+ size_t placewewant; /* Current file's place we want. */
+ int totlines; /* Current file's total number of
* lines. */
- long file_totsize; /* Current file's total size. */
- int file_lineno; /* Current file's line number. */
- long file_flags; /* Current file's flags: modification
+ long totsize; /* Current file's total size. */
+ long flags; /* Current file's flags: modification
* status (and marking status, if
* available). */
- file_format file_fmt; /* Current file's format. */
+ file_format fmt; /* Current file's format. */
} openfilestruct;
#endif
diff --git a/src/proto.h b/src/proto.h
@@ -190,17 +190,18 @@ void do_insertfile(
);
void do_insertfile_void(void);
#ifdef ENABLE_MULTIBUFFER
-openfilestruct *make_new_opennode(openfilestruct *prevnode);
+openfilestruct *make_new_opennode(void);
void splice_opennode(openfilestruct *begin, openfilestruct *newnode,
openfilestruct *end);
-void unlink_opennode(const openfilestruct *fileptr);
+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_prevfile(bool closing_file);
+void open_prevnext_file(bool next);
void open_prevfile_void(void);
-void open_nextfile(bool closing_file);
void open_nextfile_void(void);
bool close_open_file(void);
#endif