diff --git a/ChangeLog b/ChangeLog
index 7eac5d27d78dbc70626e088d456bf7b311e1c0cd..dc6b155960d5609253f0fb02d74ceb616a868ca8 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 c4bd32656c9cf44ca2db27321d1c044a41f69d8c..2c5a79d753d9ca720b1374d0e21107fdc2a0c1f5 100644
--- a/src/files.c
+++ b/src/files.c
@@ -40,950 +40,950 @@
 static file_format fmt = NIX_FILE;
 	/* The format of the current file. */
 
-/* What happens when there is no file to open? aiee! */
-void new_file(void)
+#ifdef ENABLE_MULTIBUFFER
+/* Create a new openfilestruct node. */
+openfilestruct *make_new_opennode(void)
 {
-    fileage = make_new_node(NULL);
-    fileage->data = mallocstrcpy(NULL, "");
-    filebot = fileage;
-    edittop = fileage;
-    current = fileage;
-    current_x = 0;
-    totlines = 1;
-    totsize = 0;
+    openfilestruct *newnode =
+	(openfilestruct *)nmalloc(sizeof(openfilestruct));
+    newnode->filename = NULL;
 
-#ifdef ENABLE_COLOR
-    update_color();
-    if (!ISSET(NO_COLOR_SYNTAX))
-	edit_refresh();
-#endif
+    return newnode;
 }
 
-/* We make a new line of text from buf.  buf is length buf_len.  If
- * first_line_ins is TRUE, then we put the new line at the top of the
- * file.  Otherwise, we assume prevnode is the last line of the file,
- * and put our line after prevnode. */
-filestruct *read_line(char *buf, filestruct *prevnode, bool
-	*first_line_ins, size_t buf_len)
+/* Splice a node into an existing openfilestruct. */
+void splice_opennode(openfilestruct *begin, openfilestruct *newnode,
+	openfilestruct *end)
 {
-    filestruct *fileptr = (filestruct *)nmalloc(sizeof(filestruct));
-
-    /* Convert nulls to newlines.  buf_len is the string's real length
-     * here. */
-    unsunder(buf, buf_len);
-
-    assert(strlen(buf) == buf_len);
-
-    fileptr->data = mallocstrcpy(NULL, buf);
-
-#ifndef NANO_SMALL
-    /* If it's a DOS file ("\r\n"), and file conversion isn't disabled,
-     * strip the '\r' part from fileptr->data. */
-    if (!ISSET(NO_CONVERT) && buf_len > 0 && buf[buf_len - 1] == '\r')
-	fileptr->data[buf_len - 1] = '\0';
-#endif
+    assert(newnode != NULL && begin != NULL);
 
-    if (*first_line_ins == TRUE || fileage == NULL) {
-	/* Special case: We're inserting with the cursor on the first
-	 * line. */
-	fileptr->prev = NULL;
-	fileptr->next = fileage;
-	fileptr->lineno = 1;
-	if (*first_line_ins == TRUE) {
-	    *first_line_ins = FALSE;
-	    /* If we're inserting into the first line of the file, then
-	     * we want to make sure that our edit buffer stays on the
-	     * first line and that fileage stays up to date. */
-	    edittop = fileptr;
-	} else
-	    filebot = fileptr;
-	fileage = fileptr;
-    } else {
-	assert(prevnode != NULL);
+    newnode->next = end;
+    newnode->prev = begin;
+    begin->next = newnode;
+    if (end != NULL)
+	end->prev = newnode;
+}
 
-	fileptr->prev = prevnode;
-	fileptr->next = NULL;
-	fileptr->lineno = prevnode->lineno + 1;
-	prevnode->next = fileptr;
-    }
+/* 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);
 
-    return fileptr;
+    fileptr->prev->next = fileptr->next;
+    fileptr->next->prev = fileptr->prev;
+    delete_opennode(fileptr);
 }
 
-/* Load a file into the edit buffer.  This takes data from the file
- * struct. */
-void load_file(void)
+/* Delete a node from the openfilestruct. */
+void delete_opennode(openfilestruct *fileptr)
 {
-    current = fileage;
-
-#ifdef ENABLE_MULTIBUFFER
-    /* Add a new entry to the open_files structure. */
-    add_open_file(FALSE);
+    assert(fileptr != NULL && fileptr->filename != NULL && fileptr->fileage != NULL);
 
-    /* Reinitialize the shortcut list. */
-    shortcut_init(FALSE);
-#endif
+    free(fileptr->filename);
+    free_filestruct(fileptr->fileage);
+    free(fileptr);
 }
 
-void read_file(FILE *f, const char *filename)
+#ifdef DEBUG
+/* Deallocate all memory associated with this and later files, including
+ * the lines of text. */
+void free_openfilestruct(openfilestruct *src)
 {
-    size_t num_lines = 0;
-	/* The number of lines in the file. */
-    size_t num_chars;
-	/* The number of characters in the file. */
-    size_t len = 0;
-	/* The length of the current line of the file. */
-    size_t i = 0;
-	/* The position in the current line of the file. */
-    size_t bufx = MAX_BUF_SIZE;
-	/* The size of each chunk of the file that we read. */
-    char input = '\0';
-	/* The current input character. */
-    char *buf;
-	/* The buffer where we store chunks of the file. */
-    filestruct *fileptr = current;
-	/* The current line of the file. */
-    bool first_line_ins = FALSE;
-	/* Whether we're inserting with the cursor on the first line. */
-    int input_int;
-	/* The current value we read from the file, whether an input
-	 * character or EOF. */
-#ifndef NANO_SMALL
-    int format = 0;
-	/* 0 = *nix, 1 = DOS, 2 = Mac, 3 = both DOS and Mac. */
+    assert(src != NULL);
+
+    while (src != src->next) {
+	src = src->next;
+	delete_opennode(src->prev);
+    }
+    delete_opennode(src);
+}
 #endif
 
-    buf = charalloc(bufx);
-    buf[0] = '\0';
+/* 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 (current != NULL) {
-	if (current == fileage)
-	    first_line_ins = TRUE;
-	else
-	    fileptr = current->prev;
+    /* 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;
     }
 
-    /* For the assertion in read_line(), it must be true that if current
-     * is NULL, then so is fileage. */
-    assert(current != NULL || fileage == NULL);
+    /* Save the current filename. */
+    open_files->filename = mallocstrcpy(open_files->filename, filename);
 
 #ifndef NANO_SMALL
-    /* We don't know which file format we have yet, so assume it's a
-     * *nix file for now. */
-    fmt = NIX_FILE;
+    /* Save the current file's stat. */
+    open_files->originalfilestat = originalfilestat;
 #endif
 
-    /* Read the entire file into the file struct. */
-    while ((input_int = getc(f)) != EOF) {
-	input = (char)input_int;
+    /* Save the current file buffer. */
+    open_files->fileage = fileage;
+    open_files->filebot = filebot;
 
-	/* If it's a *nix file ("\n") or a DOS file ("\r\n"), and file
-	 * conversion isn't disabled, handle it! */
-	if (input == '\n') {
-#ifndef NANO_SMALL
-	    /* If there's a '\r' before the '\n', set format to DOS if
-	     * we currently think this is a *nix file, or to both if we
-	     * currently think it's a Mac file. */
-	    if (!ISSET(NO_CONVERT) && i > 0 && buf[i - 1] == '\r' &&
-		(format == 0 || format == 2))
-		format++;
-#endif
+    /* Save the current top of the edit window. */
+    open_files->edittop = edittop;
 
-	    /* Read in the line properly. */
-	    fileptr = read_line(buf, fileptr, &first_line_ins, len);
+    /* Save the current line. */
+    open_files->current = current;
 
-	    /* Reset the line length in preparation for the next
-	     * line. */
-	    len = 0;
+    /* Save the current cursor position. */
+    open_files->current_x = current_x;
 
-	    num_lines++;
-	    buf[0] = '\0';
-	    i = 0;
-#ifndef NANO_SMALL
-	/* If it's a Mac file ('\r' without '\n'), and file conversion
-	 * isn't disabled, handle it! */
-	} else if (!ISSET(NO_CONVERT) && i > 0 && buf[i - 1] == '\r') {
+    /* Save the current place we want. */
+    open_files->placewewant = placewewant;
 
-	    /* If we currently think the file is a *nix file, set format
-	     * to Mac.  If we currently think the file is a DOS file,
-	     * set format to both DOS and Mac. */
-	    if (format == 0 || format == 1)
-		format += 2;
+    /* Save the current total number of lines. */
+    open_files->totlines = totlines;
 
-	    /* Read in the line properly. */
-	    fileptr = read_line(buf, fileptr, &first_line_ins, len);
+    /* Save the current total size. */
+    open_files->totsize = totsize;
 
-	    /* Reset the line length in preparation for the next line.
-	     * Since we've already read in the next character, reset it
-	     * to 1 instead of 0. */
-	    len = 1;
+    /* Start with no flags saved. */
+    open_files->flags = 0;
 
-	    num_lines++;
-	    buf[0] = input;
-	    buf[1] = '\0';
-	    i = 1;
-#endif
-	} else {
-	    /* Calculate the total length of the line.  It might have
-	     * nulls in it, so we can't just use strlen() here. */
-	    len++;
+    /* Save the current modification status. */
+    if (ISSET(MODIFIED))
+	open_files->flags |= MODIFIED;
 
-	    /* Now we allocate a bigger buffer MAX_BUF_SIZE characters
-	     * at a time.  If we allocate a lot of space for one line,
-	     * we may indeed have to use a buffer this big later on, so
-	     * we don't decrease it at all.  We do free it at the end,
-	     * though. */
-	    if (i >= bufx - 1) {
-		bufx += MAX_BUF_SIZE;
-		buf = charealloc(buf, bufx);
-	    }
+#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;
+    }
 
-	    buf[i] = input;
-	    buf[i + 1] = '\0';
-	    i++;
-	}
-    }
+    /* Save the current file format. */
+    open_files->fmt = fmt;
+#endif
 
-    /* Perhaps this could use some better handling. */
-    if (ferror(f))
-	nperror(filename);
-    fclose(f);
+#ifdef DEBUG
+    fprintf(stderr, "filename is %s\n", open_files->filename);
+#endif
+}
 
-#ifndef NANO_SMALL
-    /* If file conversion isn't disabled and the last character in this
-     * file is '\r', read it in properly as a Mac format line. */
-    if (len == 0 && !ISSET(NO_CONVERT) && input == '\r') {
-	len = 1;
+/* 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);
 
-	buf[0] = input;
-	buf[1] = '\0';
-    }
-#endif
+    /* Restore the current filename. */
+    filename = mallocstrcpy(filename, open_files->filename);
 
-    /* Did we not get a newline and still have stuff to do? */
-    if (len > 0) {
 #ifndef NANO_SMALL
-	/* If file conversion isn't disabled and the last character in
-	 * this file is '\r', set format to Mac if we currently think
-	 * the file is a *nix file, or to both DOS and Mac if we
-	 * currently think the file is a DOS file. */
-	if (!ISSET(NO_CONVERT) && buf[len - 1] == '\r' &&
-		(format == 0 || format == 1))
-	    format += 2;
+    /* Restore the current file's stat. */
+    originalfilestat = open_files->originalfilestat;
 #endif
 
-	/* Read in the last line properly. */
-	fileptr = read_line(buf, fileptr, &first_line_ins, len);
-	num_lines++;
-    }
+    /* Restore the current file buffer. */
+    fileage = open_files->fileage;
+    filebot = open_files->filebot;
 
-    free(buf);
+    /* Restore the current top of the edit window. */
+    edittop = open_files->edittop;
 
-    /* If we didn't get a file and we don't already have one, make a new
-     * file. */
-    if (fileptr == NULL)
-	new_file();
+    /* Restore the current line. */
+    current = open_files->current;
 
-    /* Did we try to insert a file of 0 bytes? */
-    if (num_lines != 0) {
-	if (current != NULL) {
-	    fileptr->next = current;
-	    current->prev = fileptr;
-	    renumber(current);
-	    current_x = 0;
-	    placewewant = 0;
-	} else if (fileptr->next == NULL) {
-	    filebot = fileptr;
-	    new_magicline();
-	    totsize--;
-	}
-    }
+    /* Restore the current cursor position. */
+    current_x = open_files->current_x;
 
-    get_totals(fileage, filebot, NULL, &num_chars);
-    totsize += num_chars;
+    /* 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
-    if (format == 3)
-	statusbar(
-		P_("Read %lu line (Converted from DOS and Mac format)",
-		"Read %lu lines (Converted from DOS and Mac format)",
-		(unsigned long)num_lines), (unsigned long)num_lines);
-    else if (format == 2) {
-	fmt = MAC_FILE;
-	statusbar(P_("Read %lu line (Converted from Mac format)",
-		"Read %lu lines (Converted from Mac format)",
-		(unsigned long)num_lines), (unsigned long)num_lines);
-    } else if (format == 1) {
-	fmt = DOS_FILE;
-	statusbar(P_("Read %lu line (Converted from DOS format)",
-		"Read %lu lines (Converted from DOS format)",
-		(unsigned long)num_lines), (unsigned long)num_lines);
+    /* 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
-	statusbar(P_("Read %lu line", "Read %lu lines",
-		(unsigned long)num_lines), (unsigned long)num_lines);
 
-    totlines += num_lines;
+#ifdef ENABLE_COLOR
+    update_color();
+#endif
+    edit_refresh();
+
+    /* Update the titlebar. */
+    titlebar(NULL);
 }
 
-/* Open the file (and decide if it exists).  If newfie is TRUE, display
- * "New File" if the file is missing.  Otherwise, say "[filename] not
- * found".
- *
- * Return -2 if we say "New File".  Otherwise, -1 if the file isn't
- * opened, 0 otherwise.  The file might still have an error while
- * reading with a 0 return value.  *f is set to the opened file. */
-int open_file(const char *filename, bool newfie, FILE **f)
+/* Open either the next or previous file buffer. */
+void open_prevnext_file(bool next_file)
 {
-    int fd;
-    struct stat fileinfo;
-
-    assert(f != NULL);
+    assert(open_files != NULL);
 
-    if (filename == NULL || filename[0] == '\0' ||
-	    stat(filename, &fileinfo) == -1) {
-	if (newfie) {
-	    statusbar(_("New File"));
-	    return -2;
-	}
-	statusbar(_("\"%s\" not found"), filename);
-	return -1;
-    } else if (S_ISDIR(fileinfo.st_mode) || S_ISCHR(fileinfo.st_mode) ||
-		S_ISBLK(fileinfo.st_mode)) {
-	/* Don't open character or block files.  Sorry, /dev/sndstat! */
-	statusbar(S_ISDIR(fileinfo.st_mode) ? _("\"%s\" is a directory")
-		: _("File \"%s\" is a device file"), filename);
-	return -1;
-    } else if ((fd = open(filename, O_RDONLY)) == -1) {
-	statusbar(_("Error reading %s: %s"), filename, strerror(errno));
- 	return -1;
-     } else {
-	/* File is A-OK.  Open it in binary mode for our own end-of-line
-	 * character munging. */
-	*f = fdopen(fd, "rb");
+    add_open_file(TRUE);
 
-	if (*f == NULL) {
-	    statusbar(_("Error reading %s: %s"), filename,
-		strerror(errno));
-	    close(fd);
-	} else
-	    statusbar(_("Reading File"));
+    /* 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;
     }
-    return 0;
+
+    /* 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
 }
 
-/* This function will return the name of the first available extension
- * of a filename (starting with [name][suffix], then [name][suffix].1,
- * etc.).  Memory is allocated for the return value.  If no writable
- * extension exists, we return "". */
-char *get_next_filename(const char *name, const char *suffix)
+/* Open the previous entry in the open_files structure.  This function
+ * is used by the shortcut list. */
+void open_prevfile_void(void)
 {
-    unsigned long i = 0;
-    char *buf;
-    size_t namelen, suffixlen;
-
-    assert(name != NULL && suffix != NULL);
+    open_prevnext_file(FALSE);
+}
 
-    namelen = strlen(name);
-    suffixlen = strlen(suffix);
+/* 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);
+}
 
-    buf = charalloc(namelen + suffixlen + digits(ULONG_MAX) + 2);
-    sprintf(buf, "%s%s", name, suffix);
+/* 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);
 
-    while (TRUE) {
-	struct stat fs;
+    /* If only one file is open, get out. */
+    if (open_files == open_files->next)
+	return FALSE;
 
-	if (stat(buf, &fs) == -1)
-	    return buf;
-	if (i == ULONG_MAX)
-	    break;
+    /* Open the next file. */
+    open_nextfile_void();
 
-	i++;
-	sprintf(buf + namelen + suffixlen, ".%lu", i);
-    }
+    /* Close the file we had open before. */
+    unlink_opennode(open_files->prev);
 
-    /* We get here only if there is no possible save file.  Blank out
-     * the filename to indicate this. */
-    null_at(&buf, 0);
+    /* Reinitialize the shortcut list. */
+    shortcut_init(FALSE);
+    display_main_list();
 
-    return buf;
+    return TRUE;
 }
+#endif /* ENABLE_MULTIBUFFER */
 
-#ifndef NANO_SMALL
-void execute_command(const char *command)
+/* What happens when there is no file to open? aiee! */
+void new_file(void)
 {
-#ifdef ENABLE_MULTIBUFFER
-    if (ISSET(MULTIBUFFER)) {
-	/* Update the current entry in the open_files structure. */
-	add_open_file(TRUE);
-	new_file();
-	UNSET(MODIFIED);
-	UNSET(MARK_ISSET);
-    }
-#endif /* ENABLE_MULTIBUFFER */
-    open_pipe(command);
-#ifdef ENABLE_MULTIBUFFER
-    /* Add this new entry to the open_files structure. */
-    if (ISSET(MULTIBUFFER))
-	load_file();
-#endif /* ENABLE_MULTIBUFFER */
+    fileage = make_new_node(NULL);
+    fileage->data = mallocstrcpy(NULL, "");
+    filebot = fileage;
+    edittop = fileage;
+    current = fileage;
+    current_x = 0;
+    totlines = 1;
+    totsize = 0;
+
+#ifdef ENABLE_COLOR
+    update_color();
+    if (!ISSET(NO_COLOR_SYNTAX))
+	edit_refresh();
+#endif
 }
-#endif /* !NANO_SMALL */
 
-/* name is a file name to open.  We make a new buffer if necessary, then
- * open and read the file. */
-void load_buffer(const char *name)
+/* We make a new line of text from buf.  buf is length buf_len.  If
+ * first_line_ins is TRUE, then we put the new line at the top of the
+ * file.  Otherwise, we assume prevnode is the last line of the file,
+ * and put our line after prevnode. */
+filestruct *read_line(char *buf, filestruct *prevnode, bool
+	*first_line_ins, size_t buf_len)
 {
-    bool new_buffer = (fileage == NULL
-#ifdef ENABLE_MULTIBUFFER
-	 || ISSET(MULTIBUFFER)
-#endif
-	);
-	/* new_buffer says whether we load into this buffer or a new
-	 * one.  If new_buffer is TRUE, we display "New File" if the
-	 * file is not found, and if it is found we set filename and add
-	 * a new open_files entry. */
-    FILE *f;
-    int rc;
-	/* rc == -2 means that the statusbar displayed "New File".  -1
-	 * means that the open failed.  0 means success. */
+    filestruct *fileptr = (filestruct *)nmalloc(sizeof(filestruct));
 
-#ifndef DISABLE_OPERATINGDIR
-    if (check_operating_dir(name, FALSE)) {
-	statusbar(_("Can't insert file from outside of %s"),
-		operating_dir);
-	return;
-    }
-#endif
+    /* Convert nulls to newlines.  buf_len is the string's real length
+     * here. */
+    unsunder(buf, buf_len);
 
-#ifdef ENABLE_MULTIBUFFER
-    /* Update the current entry in the open_files structure. */
-    add_open_file(TRUE);
-#endif
+    assert(strlen(buf) == buf_len);
 
-    rc = open_file(name, new_buffer, &f);
+    fileptr->data = mallocstrcpy(NULL, buf);
 
-#ifdef ENABLE_MULTIBUFFER
-    if (rc != -1 && ISSET(MULTIBUFFER)) {
-	UNSET(MODIFIED);
 #ifndef NANO_SMALL
-	UNSET(MARK_ISSET);
-#endif
-    }
+    /* If it's a DOS file ("\r\n"), and file conversion isn't disabled,
+     * strip the '\r' part from fileptr->data. */
+    if (!ISSET(NO_CONVERT) && buf_len > 0 && buf[buf_len - 1] == '\r')
+	fileptr->data[buf_len - 1] = '\0';
 #endif
 
-    if (rc != -1 && new_buffer) {
-	filename = mallocstrcpy(filename, name);
-	new_file();
+    if (*first_line_ins == TRUE || fileage == NULL) {
+	/* Special case: We're inserting with the cursor on the first
+	 * line. */
+	fileptr->prev = NULL;
+	fileptr->next = fileage;
+	fileptr->lineno = 1;
+	if (*first_line_ins == TRUE) {
+	    *first_line_ins = FALSE;
+	    /* If we're inserting into the first line of the file, then
+	     * we want to make sure that our edit buffer stays on the
+	     * first line and that fileage stays up to date. */
+	    edittop = fileptr;
+	} else
+	    filebot = fileptr;
+	fileage = fileptr;
+    } else {
+	assert(prevnode != NULL);
+
+	fileptr->prev = prevnode;
+	fileptr->next = NULL;
+	fileptr->lineno = prevnode->lineno + 1;
+	prevnode->next = fileptr;
     }
 
-    if (rc == 0) {
-	file_format fmt_save = fmt;
+    return fileptr;
+}
 
-	read_file(f, filename);
+/* Load a file into the edit buffer.  This takes data from the file
+ * struct. */
+void load_file(void)
+{
+    current = fileage;
 
-	/* If we're not loading into a new buffer, preserve the file
-	 * format. */
-	if (!new_buffer)
-	    fmt = fmt_save;
+#ifdef ENABLE_MULTIBUFFER
+    /* Add a new entry to the open_files structure. */
+    add_open_file(FALSE);
 
-#ifndef NANO_SMALL
-	stat(filename, &originalfilestat);
+    /* Reinitialize the shortcut list. */
+    shortcut_init(FALSE);
 #endif
-    }
-
-    /* Add this new entry to the open_files structure if we have
-     * multibuffer support, or to the main filestruct if we don't. */
-    if (rc != -1 && new_buffer)
-	load_file();
 }
 
-void do_insertfile(
+void read_file(FILE *f, const char *filename)
+{
+    size_t num_lines = 0;
+	/* The number of lines in the file. */
+    size_t num_chars;
+	/* The number of characters in the file. */
+    size_t len = 0;
+	/* The length of the current line of the file. */
+    size_t i = 0;
+	/* The position in the current line of the file. */
+    size_t bufx = MAX_BUF_SIZE;
+	/* The size of each chunk of the file that we read. */
+    char input = '\0';
+	/* The current input character. */
+    char *buf;
+	/* The buffer where we store chunks of the file. */
+    filestruct *fileptr = current;
+	/* The current line of the file. */
+    bool first_line_ins = FALSE;
+	/* Whether we're inserting with the cursor on the first line. */
+    int input_int;
+	/* The current value we read from the file, whether an input
+	 * character or EOF. */
 #ifndef NANO_SMALL
-	bool execute
-#else
-	void
+    int format = 0;
+	/* 0 = *nix, 1 = DOS, 2 = Mac, 3 = both DOS and Mac. */
 #endif
-	)
-{
-    int i;
-    const char *msg;
-    char *ans = mallocstrcpy(NULL, "");
-	/* The last answer the user typed on the statusbar. */
-    filestruct *edittop_save = edittop;
-    ssize_t current_y_save = current_y;
-    bool at_edittop = FALSE;
-	/* Whether we're at the top of the edit window. */
 
-#ifndef DISABLE_WRAPPING
-    wrap_reset();
-#endif
+    buf = charalloc(bufx);
+    buf[0] = '\0';
 
-    while (TRUE) {
-#ifndef NANO_SMALL
-	if (execute) {
-#ifdef ENABLE_MULTIBUFFER
-	    if (ISSET(MULTIBUFFER))
-		msg = N_("Command to execute in new buffer [from %s] ");
-	    else
-#endif
-		msg = N_("Command to execute [from %s] ");
-	} else {
-#endif
-#ifdef ENABLE_MULTIBUFFER
-	    if (ISSET(MULTIBUFFER)) {
-		msg = N_("File to insert into new buffer [from %s] ");
-	    } else
-#endif
-		msg = N_("File to insert [from %s] ");
-#ifndef NANO_SMALL
-	}
-#endif
+    if (current != NULL) {
+	if (current == fileage)
+	    first_line_ins = TRUE;
+	else
+	    fileptr = current->prev;
+    }
+
+    /* For the assertion in read_line(), it must be true that if current
+     * is NULL, then so is fileage. */
+    assert(current != NULL || fileage == NULL);
 
-	i = statusq(TRUE,
 #ifndef NANO_SMALL
-		execute ? extcmd_list :
+    /* We don't know which file format we have yet, so assume it's a
+     * *nix file for now. */
+    fmt = NIX_FILE;
 #endif
-		insertfile_list, ans,
+
+    /* Read the entire file into the file struct. */
+    while ((input_int = getc(f)) != EOF) {
+	input = (char)input_int;
+
+	/* If it's a *nix file ("\n") or a DOS file ("\r\n"), and file
+	 * conversion isn't disabled, handle it! */
+	if (input == '\n') {
 #ifndef NANO_SMALL
-		NULL,
-#endif
-		_(msg),
-#ifndef DISABLE_OPERATINGDIR
-		operating_dir != NULL && strcmp(operating_dir, ".") != 0 ?
-		operating_dir :
+	    /* If there's a '\r' before the '\n', set format to DOS if
+	     * we currently think this is a *nix file, or to both if we
+	     * currently think it's a Mac file. */
+	    if (!ISSET(NO_CONVERT) && i > 0 && buf[i - 1] == '\r' &&
+		(format == 0 || format == 2))
+		format++;
 #endif
-		"./");
 
-	/* If we're in multibuffer mode and the filename or command is
-	 * blank, open a new buffer instead of canceling. */
-	if (i == -1 || (i == -2
-#ifdef ENABLE_MULTIBUFFER
-		&& !ISSET(MULTIBUFFER)
-#endif
-		)) {
-	    statusbar(_("Cancelled"));
-	    break;
-	} else {
-	    size_t pww_save = placewewant;
+	    /* Read in the line properly. */
+	    fileptr = read_line(buf, fileptr, &first_line_ins, len);
 
-	    ans = mallocstrcpy(ans, answer);
+	    /* Reset the line length in preparation for the next
+	     * line. */
+	    len = 0;
 
+	    num_lines++;
+	    buf[0] = '\0';
+	    i = 0;
 #ifndef NANO_SMALL
-#ifdef ENABLE_MULTIBUFFER
-	    if (i == TOGGLE_MULTIBUFFER_KEY) {
-		/* Don't allow toggling if we're in view mode. */
-		if (!ISSET(VIEW_MODE))
-		    TOGGLE(MULTIBUFFER);
-		continue;
-	    } else
-#endif
-	    if (i == NANO_TOOTHERINSERT_KEY) {
-		execute = !execute;
-		continue;
-	    }
-#ifndef DISABLE_BROWSER
-	    else
-#endif
-#endif /* !NANO_SMALL */
-
-#ifndef DISABLE_BROWSER
-	    if (i == NANO_TOFILES_KEY) {
-		char *tmp = do_browse_from(answer);
+	/* If it's a Mac file ('\r' without '\n'), and file conversion
+	 * isn't disabled, handle it! */
+	} else if (!ISSET(NO_CONVERT) && i > 0 && buf[i - 1] == '\r') {
 
-		if (tmp == NULL)
-		    continue;
+	    /* If we currently think the file is a *nix file, set format
+	     * to Mac.  If we currently think the file is a DOS file,
+	     * set format to both DOS and Mac. */
+	    if (format == 0 || format == 1)
+		format += 2;
 
-		free(answer);
-		answer = tmp;
+	    /* Read in the line properly. */
+	    fileptr = read_line(buf, fileptr, &first_line_ins, len);
 
-		/* We have a file now.  Indicate this and get out of the
-		 * statusbar prompt cleanly. */
-		i = 0;
-		statusq_abort();
-	    }
-#endif
+	    /* Reset the line length in preparation for the next line.
+	     * Since we've already read in the next character, reset it
+	     * to 1 instead of 0. */
+	    len = 1;
 
-	    /* If we don't have a file yet, go back to the statusbar
-	     * prompt. */
-	    if (i != 0
-#ifdef ENABLE_MULTIBUFFER
-		&& (i != -2 || !ISSET(MULTIBUFFER))
+	    num_lines++;
+	    buf[0] = input;
+	    buf[1] = '\0';
+	    i = 1;
 #endif
-		)
-		continue;
+	} else {
+	    /* Calculate the total length of the line.  It might have
+	     * nulls in it, so we can't just use strlen() here. */
+	    len++;
 
-#ifdef ENABLE_MULTIBUFFER
-	    if (!ISSET(MULTIBUFFER)) {
-#endif
-		/* If we're not inserting into a new buffer, partition
-		 * the filestruct so that it contains no text and hence
-		 * looks like a new buffer, 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);
-#ifdef ENABLE_MULTIBUFFER
+	    /* Now we allocate a bigger buffer MAX_BUF_SIZE characters
+	     * at a time.  If we allocate a lot of space for one line,
+	     * we may indeed have to use a buffer this big later on, so
+	     * we don't decrease it at all.  We do free it at the end,
+	     * though. */
+	    if (i >= bufx - 1) {
+		bufx += MAX_BUF_SIZE;
+		buf = charealloc(buf, bufx);
 	    }
-#endif
+
+	    buf[i] = input;
+	    buf[i + 1] = '\0';
+	    i++;
+	}
+    }
+
+    /* Perhaps this could use some better handling. */
+    if (ferror(f))
+	nperror(filename);
+    fclose(f);
 
 #ifndef NANO_SMALL
-	    if (execute)
-		execute_command(answer);
-	    else {
-#endif
-		answer = mallocstrassn(answer,
-			real_dir_from_tilde(answer));
-		load_buffer(answer);
-#ifndef NANO_SMALL
-	    }
+    /* If file conversion isn't disabled and the last character in this
+     * file is '\r', read it in properly as a Mac format line. */
+    if (len == 0 && !ISSET(NO_CONVERT) && input == '\r') {
+	len = 1;
+
+	buf[0] = input;
+	buf[1] = '\0';
+    }
 #endif
 
-#ifdef ENABLE_MULTIBUFFER
-	    if (!ISSET(MULTIBUFFER))
+    /* Did we not get a newline and still have stuff to do? */
+    if (len > 0) {
+#ifndef NANO_SMALL
+	/* If file conversion isn't disabled and the last character in
+	 * this file is '\r', set format to Mac if we currently think
+	 * the file is a *nix file, or to both DOS and Mac if we
+	 * currently think the file is a DOS file. */
+	if (!ISSET(NO_CONVERT) && buf[len - 1] == '\r' &&
+		(format == 0 || format == 1))
+	    format += 2;
 #endif
-	    {
-		filestruct *top_save = fileage;
 
-		/* If we didn't insert into a new buffer, and we were at
-		 * the top of the edit window before, set the saved
-		 * value of edittop to the new top of the edit window,
-		 * and update the current y-coordinate to account for
-		 * the number of lines inserted. */
-		if (at_edittop)
-		    edittop_save = fileage;
-		current_y += current_y_save;
+	/* Read in the last line properly. */
+	fileptr = read_line(buf, fileptr, &first_line_ins, len);
+	num_lines++;
+    }
 
-		/* If we didn't insert into a new buffer, unpartition
-		 * the filestruct so that it contains all the text
-		 * again.  Note that we've replaced the non-text
-		 * originally in the partition with the text in the
-		 * inserted file/executed command output. */
-		unpartition_filestruct(&filepart);
+    free(buf);
 
-		/* Renumber starting with the beginning line of the old
-		 * partition. */
-		renumber(top_save);
+    /* If we didn't get a file and we don't already have one, make a new
+     * file. */
+    if (fileptr == NULL)
+	new_file();
 
-		/* Set edittop back to what it was before. */
-		edittop = edittop_save;
-	    }
+    /* Did we try to insert a file of 0 bytes? */
+    if (num_lines != 0) {
+	if (current != NULL) {
+	    fileptr->next = current;
+	    current->prev = fileptr;
+	    renumber(current);
+	    current_x = 0;
+	    placewewant = 0;
+	} else if (fileptr->next == NULL) {
+	    filebot = fileptr;
+	    new_magicline();
+	    totsize--;
+	}
+    }
 
-#ifdef ENABLE_MULTIBUFFER
-	    if (ISSET(MULTIBUFFER)) {
-		/* Update the titlebar. */
-		titlebar(NULL);
+    get_totals(fileage, filebot, NULL, &num_chars);
+    totsize += num_chars;
 
-		/* Reinitialize the shortcut list. */
-		shortcut_init(FALSE);
-	    } else {
+#ifndef NANO_SMALL
+    if (format == 3)
+	statusbar(
+		P_("Read %lu line (Converted from DOS and Mac format)",
+		"Read %lu lines (Converted from DOS and Mac format)",
+		(unsigned long)num_lines), (unsigned long)num_lines);
+    else if (format == 2) {
+	fmt = MAC_FILE;
+	statusbar(P_("Read %lu line (Converted from Mac format)",
+		"Read %lu lines (Converted from Mac format)",
+		(unsigned long)num_lines), (unsigned long)num_lines);
+    } else if (format == 1) {
+	fmt = DOS_FILE;
+	statusbar(P_("Read %lu line (Converted from DOS format)",
+		"Read %lu lines (Converted from DOS format)",
+		(unsigned long)num_lines), (unsigned long)num_lines);
+    } else
 #endif
-		/* Mark the file as modified. */
-		set_modified();
+	statusbar(P_("Read %lu line", "Read %lu lines",
+		(unsigned long)num_lines), (unsigned long)num_lines);
 
-		/* Restore the old place we want. */
-		placewewant = pww_save;
-#ifdef ENABLE_MULTIBUFFER
-	    }
-#endif
+    totlines += num_lines;
+}
 
-	    /* Refresh the screen. */
-	    edit_refresh();
+/* Open the file (and decide if it exists).  If newfie is TRUE, display
+ * "New File" if the file is missing.  Otherwise, say "[filename] not
+ * found".
+ *
+ * Return -2 if we say "New File".  Otherwise, -1 if the file isn't
+ * opened, 0 otherwise.  The file might still have an error while
+ * reading with a 0 return value.  *f is set to the opened file. */
+int open_file(const char *filename, bool newfie, FILE **f)
+{
+    int fd;
+    struct stat fileinfo;
+
+    assert(f != NULL);
+
+    if (filename == NULL || filename[0] == '\0' ||
+	    stat(filename, &fileinfo) == -1) {
+	if (newfie) {
+	    statusbar(_("New File"));
+	    return -2;
+	}
+	statusbar(_("\"%s\" not found"), filename);
+	return -1;
+    } else if (S_ISDIR(fileinfo.st_mode) || S_ISCHR(fileinfo.st_mode) ||
+		S_ISBLK(fileinfo.st_mode)) {
+	/* Don't open character or block files.  Sorry, /dev/sndstat! */
+	statusbar(S_ISDIR(fileinfo.st_mode) ? _("\"%s\" is a directory")
+		: _("File \"%s\" is a device file"), filename);
+	return -1;
+    } else if ((fd = open(filename, O_RDONLY)) == -1) {
+	statusbar(_("Error reading %s: %s"), filename, strerror(errno));
+ 	return -1;
+     } else {
+	/* File is A-OK.  Open it in binary mode for our own end-of-line
+	 * character munging. */
+	*f = fdopen(fd, "rb");
 
-	    break;
-	}
+	if (*f == NULL) {
+	    statusbar(_("Error reading %s: %s"), filename,
+		strerror(errno));
+	    close(fd);
+	} else
+	    statusbar(_("Reading File"));
     }
-
-    free(ans);
+    return 0;
 }
 
-void do_insertfile_void(void)
+/* This function will return the name of the first available extension
+ * of a filename (starting with [name][suffix], then [name][suffix].1,
+ * etc.).  Memory is allocated for the return value.  If no writable
+ * extension exists, we return "". */
+char *get_next_filename(const char *name, const char *suffix)
 {
-#ifdef ENABLE_MULTIBUFFER
-    if (ISSET(VIEW_MODE) && !ISSET(MULTIBUFFER))
-	statusbar(_("Key illegal in non-multibuffer mode"));
-    else
-#endif
-	do_insertfile(
-#ifndef NANO_SMALL
-		FALSE
-#endif
-		);
-
-    display_main_list();
-}
+    unsigned long i = 0;
+    char *buf;
+    size_t namelen, suffixlen;
 
-#ifdef ENABLE_MULTIBUFFER
-/* Create a new openfilestruct node. */
-openfilestruct *make_new_opennode(void)
-{
-    openfilestruct *newnode =
-	(openfilestruct *)nmalloc(sizeof(openfilestruct));
-    newnode->filename = NULL;
+    assert(name != NULL && suffix != NULL);
 
-    return newnode;
-}
+    namelen = strlen(name);
+    suffixlen = strlen(suffix);
 
-/* Splice a node into an existing openfilestruct. */
-void splice_opennode(openfilestruct *begin, openfilestruct *newnode,
-	openfilestruct *end)
-{
-    assert(newnode != NULL && begin != NULL);
+    buf = charalloc(namelen + suffixlen + digits(ULONG_MAX) + 2);
+    sprintf(buf, "%s%s", name, suffix);
 
-    newnode->next = end;
-    newnode->prev = begin;
-    begin->next = newnode;
-    if (end != NULL)
-	end->prev = newnode;
-}
+    while (TRUE) {
+	struct stat fs;
 
-/* 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);
+	if (stat(buf, &fs) == -1)
+	    return buf;
+	if (i == ULONG_MAX)
+	    break;
 
-    fileptr->prev->next = fileptr->next;
-    fileptr->next->prev = fileptr->prev;
-    delete_opennode(fileptr);
-}
+	i++;
+	sprintf(buf + namelen + suffixlen, ".%lu", i);
+    }
 
-/* Delete a node from the openfilestruct. */
-void delete_opennode(openfilestruct *fileptr)
-{
-    assert(fileptr != NULL && fileptr->filename != NULL && fileptr->fileage != NULL);
+    /* We get here only if there is no possible save file.  Blank out
+     * the filename to indicate this. */
+    null_at(&buf, 0);
 
-    free(fileptr->filename);
-    free_filestruct(fileptr->fileage);
-    free(fileptr);
+    return buf;
 }
 
-#ifdef DEBUG
-/* Deallocate all memory associated with this and later files, including
- * the lines of text. */
-void free_openfilestruct(openfilestruct *src)
+#ifndef NANO_SMALL
+void execute_command(const char *command)
 {
-    assert(src != NULL);
-
-    while (src != src->next) {
-	src = src->next;
-	delete_opennode(src->prev);
+#ifdef ENABLE_MULTIBUFFER
+    if (ISSET(MULTIBUFFER)) {
+	/* Update the current entry in the open_files structure. */
+	add_open_file(TRUE);
+	new_file();
+	UNSET(MODIFIED);
+	UNSET(MARK_ISSET);
     }
-    delete_opennode(src);
+#endif /* ENABLE_MULTIBUFFER */
+    open_pipe(command);
+#ifdef ENABLE_MULTIBUFFER
+    /* Add this new entry to the open_files structure. */
+    if (ISSET(MULTIBUFFER))
+	load_file();
+#endif /* ENABLE_MULTIBUFFER */
 }
-#endif
+#endif /* !NANO_SMALL */
 
-/* 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)
+/* name is a file name to open.  We make a new buffer if necessary, then
+ * open and read the file. */
+void load_buffer(const char *name)
 {
-    if (update && open_files == NULL)
-	return;
+    bool new_buffer = (fileage == NULL
+#ifdef ENABLE_MULTIBUFFER
+	 || ISSET(MULTIBUFFER)
+#endif
+	);
+	/* new_buffer says whether we load into this buffer or a new
+	 * one.  If new_buffer is TRUE, we display "New File" if the
+	 * file is not found, and if it is found we set filename and add
+	 * a new open_files entry. */
+    FILE *f;
+    int rc;
+	/* rc == -2 means that the statusbar displayed "New File".  -1
+	 * means that the open failed.  0 means success. */
 
-    /* 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;
+#ifndef DISABLE_OPERATINGDIR
+    if (check_operating_dir(name, FALSE)) {
+	statusbar(_("Can't insert file from outside of %s"),
+		operating_dir);
+	return;
     }
+#endif
 
-    /* Save the current filename. */
-    open_files->filename = mallocstrcpy(open_files->filename, filename);
+#ifdef ENABLE_MULTIBUFFER
+    /* Update the current entry in the open_files structure. */
+    add_open_file(TRUE);
+#endif
 
+    rc = open_file(name, new_buffer, &f);
+
+#ifdef ENABLE_MULTIBUFFER
+    if (rc != -1 && ISSET(MULTIBUFFER)) {
+	UNSET(MODIFIED);
 #ifndef NANO_SMALL
-    /* Save the current file's stat. */
-    open_files->originalfilestat = originalfilestat;
+	UNSET(MARK_ISSET);
+#endif
+    }
 #endif
 
-    /* Save the current file buffer. */
-    open_files->fileage = fileage;
-    open_files->filebot = filebot;
+    if (rc != -1 && new_buffer) {
+	filename = mallocstrcpy(filename, name);
+	new_file();
+    }
 
-    /* Save the current top of the edit window. */
-    open_files->edittop = edittop;
+    if (rc == 0) {
+	file_format fmt_save = fmt;
 
-    /* Save the current line. */
-    open_files->current = current;
+	read_file(f, filename);
 
-    /* Save the current cursor position. */
-    open_files->current_x = current_x;
+	/* If we're not loading into a new buffer, preserve the file
+	 * format. */
+	if (!new_buffer)
+	    fmt = fmt_save;
 
-    /* Save the current place we want. */
-    open_files->placewewant = placewewant;
+#ifndef NANO_SMALL
+	stat(filename, &originalfilestat);
+#endif
+    }
 
-    /* Save the current total number of lines. */
-    open_files->totlines = totlines;
+    /* Add this new entry to the open_files structure if we have
+     * multibuffer support, or to the main filestruct if we don't. */
+    if (rc != -1 && new_buffer)
+	load_file();
+}
 
-    /* Save the current total size. */
-    open_files->totsize = totsize;
+void do_insertfile(
+#ifndef NANO_SMALL
+	bool execute
+#else
+	void
+#endif
+	)
+{
+    int i;
+    const char *msg;
+    char *ans = mallocstrcpy(NULL, "");
+	/* The last answer the user typed on the statusbar. */
+    filestruct *edittop_save = edittop;
+    ssize_t current_y_save = current_y;
+    bool at_edittop = FALSE;
+	/* Whether we're at the top of the edit window. */
 
-    /* Start with no flags saved. */
-    open_files->flags = 0;
+#ifndef DISABLE_WRAPPING
+    wrap_reset();
+#endif
 
-    /* Save the current modification status. */
-    if (ISSET(MODIFIED))
-	open_files->flags |= MODIFIED;
+    while (TRUE) {
+#ifndef NANO_SMALL
+	if (execute) {
+#ifdef ENABLE_MULTIBUFFER
+	    if (ISSET(MULTIBUFFER))
+		msg = N_("Command to execute in new buffer [from %s] ");
+	    else
+#endif
+		msg = N_("Command to execute [from %s] ");
+	} else {
+#endif
+#ifdef ENABLE_MULTIBUFFER
+	    if (ISSET(MULTIBUFFER)) {
+		msg = N_("File to insert into new buffer [from %s] ");
+	    } else
+#endif
+		msg = N_("File to insert [from %s] ");
+#ifndef NANO_SMALL
+	}
+#endif
 
+	i = statusq(TRUE,
 #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;
+		execute ? extcmd_list :
 #endif
-
-#ifdef DEBUG
-    fprintf(stderr, "filename is %s\n", open_files->filename);
+		insertfile_list, ans,
+#ifndef NANO_SMALL
+		NULL,
 #endif
-}
+		_(msg),
+#ifndef DISABLE_OPERATINGDIR
+		operating_dir != NULL && strcmp(operating_dir, ".") != 0 ?
+		operating_dir :
+#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);
+	/* If we're in multibuffer mode and the filename or command is
+	 * blank, open a new buffer instead of canceling. */
+	if (i == -1 || (i == -2
+#ifdef ENABLE_MULTIBUFFER
+		&& !ISSET(MULTIBUFFER)
+#endif
+		)) {
+	    statusbar(_("Cancelled"));
+	    break;
+	} else {
+	    size_t pww_save = placewewant;
 
-    /* Restore the current filename. */
-    filename = mallocstrcpy(filename, open_files->filename);
+	    ans = mallocstrcpy(ans, answer);
 
 #ifndef NANO_SMALL
-    /* Restore the current file's stat. */
-    originalfilestat = open_files->originalfilestat;
+#ifdef ENABLE_MULTIBUFFER
+	    if (i == TOGGLE_MULTIBUFFER_KEY) {
+		/* Don't allow toggling if we're in view mode. */
+		if (!ISSET(VIEW_MODE))
+		    TOGGLE(MULTIBUFFER);
+		continue;
+	    } else
 #endif
+	    if (i == NANO_TOOTHERINSERT_KEY) {
+		execute = !execute;
+		continue;
+	    }
+#ifndef DISABLE_BROWSER
+	    else
+#endif
+#endif /* !NANO_SMALL */
 
-    /* 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;
+#ifndef DISABLE_BROWSER
+	    if (i == NANO_TOFILES_KEY) {
+		char *tmp = do_browse_from(answer);
 
-    /* Restore the current cursor position. */
-    current_x = open_files->current_x;
+		if (tmp == NULL)
+		    continue;
 
-    /* Restore the current place we want. */
-    placewewant = open_files->placewewant;
+		free(answer);
+		answer = tmp;
 
-    /* Restore the current total number of lines. */
-    totlines = open_files->totlines;
+		/* We have a file now.  Indicate this and get out of the
+		 * statusbar prompt cleanly. */
+		i = 0;
+		statusq_abort();
+	    }
+#endif
 
-    /* Restore the current total size. */
-    totsize = open_files->totsize;
+	    /* If we don't have a file yet, go back to the statusbar
+	     * prompt. */
+	    if (i != 0
+#ifdef ENABLE_MULTIBUFFER
+		&& (i != -2 || !ISSET(MULTIBUFFER))
+#endif
+		)
+		continue;
 
-    /* Restore the current modification status. */
-    if (open_files->flags & MODIFIED)
-	SET(MODIFIED);
-    else
-	UNSET(MODIFIED);
+#ifdef ENABLE_MULTIBUFFER
+	    if (!ISSET(MULTIBUFFER)) {
+#endif
+		/* If we're not inserting into a new buffer, partition
+		 * the filestruct so that it contains no text and hence
+		 * looks like a new buffer, 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);
+#ifdef ENABLE_MULTIBUFFER
+	    }
+#endif
 
 #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;
+	    if (execute)
+		execute_command(answer);
+	    else {
+#endif
+		answer = mallocstrassn(answer,
+			real_dir_from_tilde(answer));
+		load_buffer(answer);
+#ifndef NANO_SMALL
+	    }
 #endif
 
-#ifdef ENABLE_COLOR
-    update_color();
+#ifdef ENABLE_MULTIBUFFER
+	    if (!ISSET(MULTIBUFFER))
 #endif
-    edit_refresh();
+	    {
+		filestruct *top_save = fileage;
 
-    /* Update the titlebar. */
-    titlebar(NULL);
-}
+		/* If we didn't insert into a new buffer, and we were at
+		 * the top of the edit window before, set the saved
+		 * value of edittop to the new top of the edit window,
+		 * and update the current y-coordinate to account for
+		 * the number of lines inserted. */
+		if (at_edittop)
+		    edittop_save = fileage;
+		current_y += current_y_save;
 
-/* Open either the next or previous file buffer. */
-void open_prevnext_file(bool next_file)
-{
-    assert(open_files != NULL);
+		/* If we didn't insert into a new buffer, unpartition
+		 * the filestruct so that it contains all the text
+		 * again.  Note that we've replaced the non-text
+		 * originally in the partition with the text in the
+		 * inserted file/executed command output. */
+		unpartition_filestruct(&filepart);
 
-    add_open_file(TRUE);
+		/* Renumber starting with the beginning line of the old
+		 * partition. */
+		renumber(top_save);
 
-    /* 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;
-    }
+		/* Set edittop back to what it was before. */
+		edittop = edittop_save;
+	    }
 
-    /* Switch to the next or previous file, depending on the value of
-     * next. */
-    open_files = next_file ? open_files->next : open_files->prev;
+#ifdef ENABLE_MULTIBUFFER
+	    if (ISSET(MULTIBUFFER)) {
+		/* Update the titlebar. */
+		titlebar(NULL);
 
-#ifdef DEBUG
-    fprintf(stderr, "filename is %s\n", open_files->filename);
+		/* Reinitialize the shortcut list. */
+		shortcut_init(FALSE);
+	    } else {
 #endif
+		/* Mark the file as modified. */
+		set_modified();
 
-    /* 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);
+		/* Restore the old place we want. */
+		placewewant = pww_save;
+#ifdef ENABLE_MULTIBUFFER
+	    }
 #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);
-}
+	    /* Refresh the screen. */
+	    edit_refresh();
 
-/* 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);
+	    break;
+	}
+    }
+
+    free(ans);
 }
 
-/* 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)
+void do_insertfile_void(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);
+#ifdef ENABLE_MULTIBUFFER
+    if (ISSET(VIEW_MODE) && !ISSET(MULTIBUFFER))
+	statusbar(_("Key illegal in non-multibuffer mode"));
+    else
+#endif
+	do_insertfile(
+#ifndef NANO_SMALL
+		FALSE
+#endif
+		);
 
-    /* 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,
diff --git a/src/nano.c b/src/nano.c
index e20c18adb36bb6ad800f52439925d7d82d901209..c6257e8480e242b757a86157f8d881b1afad9d1a 100644
--- a/src/nano.c
+++ b/src/nano.c
@@ -78,903 +78,903 @@ static filestruct *jusbottom = NULL;
 	/* Pointer to end of justify buffer. */
 #endif
 
-void print_view_warning(void)
+/* 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)
 {
-    statusbar(_("Key illegal in VIEW mode"));
+    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;
 }
 
-/* What we do when we're all set to exit. */
-void finish(void)
+/* Make a copy of a filestruct node. */
+filestruct *copy_node(const filestruct *src)
 {
-    if (!ISSET(NO_HELP))
-	blank_bottombars();
-    else
-	blank_statusbar();
-
-    wrefresh(bottomwin);
-    endwin();
+    filestruct *dst;
 
-    /* Restore the old terminal settings. */
-    tcsetattr(0, TCSANOW, &oldterm);
+    assert(src != NULL);
 
-#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
-    if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
-	save_history();
-#endif
+    dst = (filestruct *)nmalloc(sizeof(filestruct));
 
-#ifdef DEBUG
-    thanks_for_all_the_fish();
-#endif
+    dst->data = mallocstrcpy(NULL, src->data);
+    dst->next = src->next;
+    dst->prev = src->prev;
+    dst->lineno = src->lineno;
 
-    exit(0);
+    return dst;
 }
 
-/* Die (gracefully?). */
-void die(const char *msg, ...)
+/* Splice a node into an existing filestruct. */
+void splice_node(filestruct *begin, filestruct *newnode, filestruct
+	*end)
 {
-    va_list ap;
-
-    endwin();
-    curses_ended = TRUE;
-
-    /* Restore the old terminal settings. */
-    tcsetattr(0, TCSANOW, &oldterm);
-
-    va_start(ap, msg);
-    vfprintf(stderr, msg, ap);
-    va_end(ap);
-
-    /* Save the current file buffer if it's been modified. */
-    if (ISSET(MODIFIED)) {
-	/* If we've partitioned the filestruct, unpartition it now. */
-	if (filepart != NULL)
-	    unpartition_filestruct(&filepart);
+    assert(newnode != NULL && begin != NULL);
 
-	die_save_file(filename);
-    }
+    newnode->next = end;
+    newnode->prev = begin;
+    begin->next = newnode;
+    if (end != NULL)
+	end->prev = newnode;
+}
 
-#ifdef ENABLE_MULTIBUFFER
-    /* Save all of the other modified file buffers, if any. */
-    if (open_files != NULL) {
-	openfilestruct *tmp = open_files;
+/* Unlink a node from the rest of the filestruct. */
+void unlink_node(const filestruct *fileptr)
+{
+    assert(fileptr != NULL);
 
-	while (tmp != open_files->next) {
-	    open_files = open_files->next;
+    if (fileptr->prev != NULL)
+	fileptr->prev->next = fileptr->next;
+    if (fileptr->next != NULL)
+	fileptr->next->prev = fileptr->prev;
+}
 
-	    /* Save the current file buffer if it's been modified. */
-	    if (open_files->flags & MODIFIED) {
-		/* Set fileage and filebot to match the current file
-		 * buffer, and then write it to disk. */
-		fileage = open_files->fileage;
-		filebot = open_files->filebot;
-		die_save_file(open_files->filename);
-	    }
-	}
-    }
-#endif
+/* Delete a node from the filestruct. */
+void delete_node(filestruct *fileptr)
+{
+    assert(fileptr != NULL && fileptr->data != NULL);
 
-    /* Get out. */
-    exit(1);
+    if (fileptr->data != NULL)
+	free(fileptr->data);
+    free(fileptr);
 }
 
-void die_save_file(const char *die_filename)
+/* Duplicate a whole filestruct. */
+filestruct *copy_filestruct(const filestruct *src)
 {
-    char *retval;
-    bool failed = TRUE;
+    filestruct *head, *copy;
 
-    /* If we're using restricted mode, don't write any emergency backup
-     * files, since that would allow reading from or writing to files
-     * not specified on the command line. */
-    if (ISSET(RESTRICTED))
-	return;
+    assert(src != NULL);
 
-    /* If we can't save, we have REAL bad problems, but we might as well
-     * TRY. */
-    if (die_filename[0] == '\0')
-	die_filename = "nano";
+    copy = copy_node(src);
+    copy->prev = NULL;
+    head = copy;
+    src = src->next;
 
-    retval = get_next_filename(die_filename, ".save");
-    if (retval[0] != '\0')
-	failed = (write_file(retval, NULL, TRUE, FALSE, TRUE) == -1);
+    while (src != NULL) {
+	copy->next = copy_node(src);
+	copy->next->prev = copy;
+	copy = copy->next;
 
-    if (!failed)
-	fprintf(stderr, _("\nBuffer written to %s\n"), retval);
-    else if (retval[0] != '\0')
-	fprintf(stderr, _("\nBuffer not written to %s: %s\n"), retval,
-		strerror(errno));
-    else
-	fprintf(stderr, _("\nBuffer not written: %s\n"),
-		_("Too many backup files?"));
+	src = src->next;
+    }
+    copy->next = NULL;
 
-    free(retval);
+    return head;
 }
 
-/* Die with an error message that the screen was too small if, well, the
- * screen is too small. */
-void check_die_too_small(void)
+/* Frees a filestruct. */
+void free_filestruct(filestruct *src)
 {
-    editwinrows = LINES - 5 + no_more_space() + no_help();
-    if (editwinrows < MIN_EDITOR_ROWS)
-	die(_("Window size is too small for nano...\n"));
+    assert(src != NULL);
+
+    while (src->next != NULL) {
+	src = src->next;
+	delete_node(src->prev);
+    }
+    delete_node(src);
 }
 
-/* Reinitialize the variables that depend on the window size.  That is,
- * fill and hblank. */
-void resize_variables(void)
+void renumber_all(void)
 {
-#ifndef DISABLE_WRAPJUSTIFY
-    fill = wrap_at;
-    if (fill <= 0)
-	fill += COLS;
-    if (fill < 0)
-	fill = 0;
-#endif
+    filestruct *temp;
+    ssize_t line = 1;
 
-    hblank = charealloc(hblank, COLS + 1);
-    charset(hblank, ' ', COLS);
-    hblank[COLS] = '\0';
+    assert(fileage == NULL || fileage != fileage->next);
+
+    for (temp = fileage; temp != NULL; temp = temp->next)
+	temp->lineno = line++;
 }
 
-/* Initialize global variables -- no better way for now.  If
- * save_cutbuffer is TRUE, don't set cutbuffer to NULL. */
-void global_init(bool save_cutbuffer)
+void renumber(filestruct *fileptr)
 {
-    check_die_too_small();
-    resize_variables();
+    if (fileptr == NULL || fileptr->prev == NULL || fileptr == fileage)
+	renumber_all();
+    else {
+	ssize_t line = fileptr->prev->lineno;
 
-    fileage = NULL;
-    edittop = NULL;
-    current = NULL;
-    if (!save_cutbuffer)
-	cutbuffer = NULL;
-    current_x = 0;
-    placewewant = 0;
-    current_y = 0;
-    totlines = 0;
-    totsize = 0;
+	assert(fileptr != fileptr->next);
+
+	for (; fileptr != NULL; fileptr = fileptr->next)
+	    fileptr->lineno = ++line;
+    }
 }
 
-void window_init(void)
+/* 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)
 {
-    check_die_too_small();
-
-    if (topwin != NULL)
-	delwin(topwin);
-    if (edit != NULL)
-	delwin(edit);
-    if (bottomwin != NULL)
-	delwin(bottomwin);
+    partition *p;
 
-    /* Set up the windows. */
-    topwin = newwin(2 - no_more_space(), COLS, 0, 0);
-    edit = newwin(editwinrows, COLS, 2 - no_more_space(), 0);
-    bottomwin = newwin(3 - no_help(), COLS, editwinrows +
-	(2 - no_more_space()), 0);
+    assert(top != NULL && bot != NULL && fileage != NULL && filebot != NULL);
 
-    /* Turn the keypad back on. */
-    keypad(edit, TRUE);
-    keypad(bottomwin, TRUE);
-}
+    /* Initialize the partition. */
+    p = (partition *)nmalloc(sizeof(partition));
 
-#ifndef DISABLE_MOUSE
-void mouse_init(void)
-{
-    if (ISSET(USE_MOUSE)) {
-	mousemask(BUTTON1_RELEASED, NULL);
-	mouseinterval(50);
+    /* 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
-	mousemask(0, NULL);
-}
-#endif
+	p->fileage = NULL;
+    if (bot != filebot) {
+	p->filebot = filebot;
+	filebot = bot;
+    } else
+	p->filebot = NULL;
 
-#ifndef DISABLE_HELP
-/* This function allocates help_text, and stores the help string in it. 
- * help_text should be NULL initially. */
-void help_init(void)
-{
-    size_t allocsize = 0;	/* Space needed for help_text. */
-    const char *htx[3];		/* Untranslated help message.  We break
-				 * it up into three chunks in case the
-				 * full string is too long for the
-				 * compiler to handle. */
-    char *ptr;
-    const shortcut *s;
-#ifndef NANO_SMALL
-    const toggle *t;
-#ifdef ENABLE_NANORC
-    bool old_whitespace = ISSET(WHITESPACE_DISPLAY);
-
-    UNSET(WHITESPACE_DISPLAY);
-#endif
-#endif
-
-    /* First, set up the initial help text for the current function. */
-    if (currshortcut == whereis_list || currshortcut == replace_list
-	     || currshortcut == replace_list_2) {
-	htx[0] = N_("Search Command Help Text\n\n "
-		"Enter the words or characters you would like to "
-		"search for, and then press Enter.  If there is a "
-		"match for the text you entered, the screen will be "
-		"updated to the location of the nearest match for the "
-		"search string.\n\n The previous search string will be "
-		"shown in brackets after the search prompt.  Hitting "
-		"Enter without entering any text will perform the "
-		"previous search.  ");
-	htx[1] = N_("If you have selected text with the mark and then "
-		"search to replace, only matches in the selected text "
-		"will be replaced.\n\n The following function keys are "
-		"available in Search mode:\n\n");
-	htx[2] = NULL;
-    } else if (currshortcut == gotoline_list) {
-	htx[0] = N_("Go To Line Help Text\n\n "
-		"Enter the line number that you wish to go to and hit "
-		"Enter.  If there are fewer lines of text than the "
-		"number you entered, you will be brought to the last "
-		"line of the file.\n\n The following function keys are "
-		"available in Go To Line mode:\n\n");
-	htx[1] = NULL;
-	htx[2] = NULL;
-    } else if (currshortcut == insertfile_list) {
-	htx[0] = N_("Insert File Help Text\n\n "
-		"Type in the name of a file to be inserted into the "
-		"current file buffer at the current cursor "
-		"location.\n\n If you have compiled nano with multiple "
-		"file buffer support, and enable multiple file buffers "
-		"with the -F or --multibuffer command line flags, the "
-		"Meta-F toggle, or a nanorc file, inserting a file "
-		"will cause it to be loaded into a separate buffer "
-		"(use Meta-< and > to switch between file buffers).  ");
-	htx[1] = N_("If you need another blank buffer, do not enter "
-		"any filename, or type in a nonexistent filename at "
-		"the prompt and press Enter.\n\n The following "
-		"function keys are available in Insert File mode:\n\n");
-	htx[2] = NULL;
-    } else if (currshortcut == writefile_list) {
-	htx[0] = N_("Write File Help Text\n\n "
-		"Type the name that you wish to save the current file "
-		"as and press Enter to save the file.\n\n If you have "
-		"selected text with the mark, you will be prompted to "
-		"save only the selected portion to a separate file.  To "
-		"reduce the chance of overwriting the current file with "
-		"just a portion of it, the current filename is not the "
-		"default in this mode.\n\n The following function keys "
-		"are available in Write File mode:\n\n");
-	htx[1] = NULL;
-	htx[2] = NULL;
-    }
-#ifndef DISABLE_BROWSER
-    else if (currshortcut == browser_list) {
-	htx[0] = N_("File Browser Help Text\n\n "
-		"The file browser is used to visually browse the "
-		"directory structure to select a file for reading "
-		"or writing.  You may use the arrow keys or Page Up/"
-		"Down to browse through the files, and S or Enter to "
-		"choose the selected file or enter the selected "
-		"directory.  To move up one level, select the "
-		"directory called \"..\" at the top of the file "
-		"list.\n\n The following function keys are available "
-		"in the file browser:\n\n");
-	htx[1] = NULL;
-	htx[2] = NULL;
-    } else if (currshortcut == gotodir_list) {
-	htx[0] = N_("Browser Go To Directory Help Text\n\n "
-		"Enter the name of the directory you would like to "
-		"browse to.\n\n If tab completion has not been "
-		"disabled, you can use the Tab key to (attempt to) "
-		"automatically complete the directory name.\n\n The "
-		"following function keys are available in Browser Go "
-		"To Directory mode:\n\n");
-	htx[1] = NULL;
-	htx[2] = NULL;
-    }
-#endif
-#ifndef DISABLE_SPELLER
-    else if (currshortcut == spell_list) {
-	htx[0] = N_("Spell Check Help Text\n\n "
-		"The spell checker checks the spelling of all text in "
-		"the current file.  When an unknown word is "
-		"encountered, it is highlighted and a replacement can "
-		"be edited.  It will then prompt to replace every "
-		"instance of the given misspelled word in the current "
-		"file, or, if you have selected text with the mark, in "
-		"the selected text.\n\n The following other functions "
-		"are available in Spell Check mode:\n\n");
-	htx[1] = NULL;
-	htx[2] = NULL;
-    }
-#endif
-#ifndef NANO_SMALL
-    else if (currshortcut == extcmd_list) {
-	htx[0] = N_("Execute Command Help Text\n\n "
-		"This menu allows you to insert the output of a "
-		"command run by the shell into the current buffer (or "
-		"a new buffer in multiple file buffer mode). If you "
-		"need another blank buffer, do not enter any "
-		"command.\n\n The following keys are available in "
-		"Execute Command mode:\n\n");
-	htx[1] = NULL;
-	htx[2] = NULL;
-    }
-#endif
-    else {
-	/* Default to the main help list. */
-	htx[0] = N_(" nano help text\n\n "
-		"The nano editor is designed to emulate the "
-		"functionality and ease-of-use of the UW Pico text "
-		"editor.  There are four main sections of the editor.  "
-		"The top line shows the program version, the current "
-		"filename being edited, and whether or not the file "
-		"has been modified.  Next is the main editor window "
-		"showing the file being edited.  The status line is "
-		"the third line from the bottom and shows important "
-		"messages.  The bottom two lines show the most "
-		"commonly used shortcuts in the editor.\n\n ");
-	htx[1] = N_("The notation for shortcuts is as follows: "
-		"Control-key sequences are notated with a caret (^) "
-		"symbol and can be entered either by using the Control "
-		"(Ctrl) key or pressing the Escape (Esc) key twice.  "
-		"Escape-key sequences are notated with the Meta (M) "
-		"symbol and can be entered using either the Esc, Alt, "
-		"or Meta key depending on your keyboard setup.  ");
-	htx[2] = N_("Also, pressing Esc twice and then typing a "
-		"three-digit decimal number from 000 to 255 will enter "
-		"the character with the corresponding value.  The "
-		"following keystrokes are available in the main editor "
-		"window.  Alternative keys are shown in "
-		"parentheses:\n\n");
-    }
-
-    htx[0] = _(htx[0]);
-    if (htx[1] != NULL)
-	htx[1] = _(htx[1]);
-    if (htx[2] != NULL)
-	htx[2] = _(htx[2]);
+    /* 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';
 
-    allocsize += strlen(htx[0]);
-    if (htx[1] != NULL)
-	allocsize += strlen(htx[1]);
-    if (htx[2] != NULL)
-	allocsize += strlen(htx[2]);
+    /* 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);
 
-    /* The space needed for the shortcut lists, at most COLS characters,
-     * plus '\n'. */
-    allocsize += (COLS < 24 ? (24 * mb_cur_max()) :
-	((COLS + 1) * mb_cur_max())) * length_of_list(currshortcut);
+    /* Remove all text after bot_x at the bottom of the partition. */
+    null_at(&bot->data, bot_x);
 
-#ifndef NANO_SMALL
-    /* If we're on the main list, we also count the toggle help text.
-     * Each line has "M-%c\t\t\t", which fills 24 columns, plus a space,
-     * plus translated text, plus '\n'. */
-    if (currshortcut == main_list) {
-	size_t endis_len = strlen(_("enable/disable"));
+    /* 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);
 
-	for (t = toggles; t != NULL; t = t->next)
-	    allocsize += 8 + strlen(t->desc) + endis_len;
-    }
-#endif
+    /* Return the partition. */
+    return p;
+}
 
-    /* help_text has been freed and set to NULL unless the user resized
-     * while in the help screen. */
-    free(help_text);
+/* Unpartition a filestruct so it begins at (fileage, 0) and ends at
+ * (filebot, strlen(filebot)) again. */
+void unpartition_filestruct(partition **p)
+{
+    char *tmp;
 
-    /* Allocate space for the help text. */
-    help_text = charalloc(allocsize + 1);
+    assert(p != NULL && fileage != NULL && filebot != NULL);
 
-    /* Now add the text we want. */
-    strcpy(help_text, htx[0]);
-    if (htx[1] != NULL)
-	strcat(help_text, htx[1]);
-    if (htx[2] != NULL)
-	strcat(help_text, htx[2]);
+    /* 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);
 
-    ptr = help_text + strlen(help_text);
+    /* 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);
 
-    /* Now add our shortcut info.  Assume that each shortcut has, at the
-     * very least, an equivalent control key, an equivalent primary meta
-     * key sequence, or both.  Also assume that the meta key values are
-     * not control characters.  We can display a maximum of 3 shortcut
-     * entries. */
-    for (s = currshortcut; s != NULL; s = s->next) {
-	int entries = 0;
+    /* 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;
 
-	/* Control key. */
-	if (s->ctrlval != NANO_NO_KEY) {
-	    entries++;
-	    /* Yucky sentinel values that we can't handle a better
-	     * way. */
-	    if (s->ctrlval == NANO_CONTROL_SPACE) {
-		char *space_ptr = display_string(_("Space"), 0, 6,
-			FALSE);
+    /* Uninitialize the partition. */
+    free(*p);
+    *p = NULL;
+}
 
-		ptr += sprintf(ptr, "^%s", space_ptr);
+/* 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
 
-		free(space_ptr);
-	    } else if (s->ctrlval == NANO_CONTROL_8)
-		ptr += sprintf(ptr, "^?");
-	    /* Normal values. */
-	    else
-		ptr += sprintf(ptr, "^%c", s->ctrlval + 64);
-	    *(ptr++) = '\t';
-	}
+    assert(file_top != NULL && file_bot != NULL && top != NULL && bot != NULL);
 
-	/* Function key. */
-	if (s->funcval != NANO_NO_KEY) {
-	    entries++;
-	    /* If this is the first entry, put it in the middle. */
-	    if (entries == 1) {
-		entries++;
-		*(ptr++) = '\t';
-	    }
-	    ptr += sprintf(ptr, "(F%d)", s->funcval - KEY_F0);
-	    *(ptr++) = '\t';
-	}
+    /* If (top, top_x)-(bot, bot_x) doesn't cover any text, get out. */
+    if (top == bot && top_x == bot_x)
+	return;
 
-	/* Primary meta key sequence.  If it's the first entry, don't
-	 * put parentheses around it. */
-	if (s->metaval != NANO_NO_KEY) {
-	    entries++;
-	    /* If this is the last entry, put it at the end. */
-	    if (entries == 2 && s->miscval == NANO_NO_KEY) {
-		entries++;
-		*(ptr++) = '\t';
-	    }
-	    /* Yucky sentinel values that we can't handle a better
-	     * way. */
-	    if (s->metaval == NANO_ALT_SPACE && entries == 1) {
-		char *space_ptr = display_string(_("Space"), 0, 5,
-			FALSE);
+    /* 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
 
-		ptr += sprintf(ptr, "M-%s", space_ptr);
+    /* Get the number of characters in the text, and subtract it from
+     * totsize. */
+    get_totals(top, bot, NULL, &part_totsize);
+    totsize -= part_totsize;
 
-		free(space_ptr);
-	    } else
-		/* Normal values. */
-		ptr += sprintf(ptr, (entries == 1) ? "M-%c" : "(M-%c)",
-			toupper(s->metaval));
-	    *(ptr++) = '\t';
-	}
+    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);
 
-	/* Miscellaneous meta key sequence. */
-	if (entries < 3 && s->miscval != NANO_NO_KEY) {
-	    entries++;
-	    /* If this is the last entry, put it at the end. */
-	    if (entries == 2) {
-		entries++;
-		*(ptr++) = '\t';
-	    }
-	    ptr += sprintf(ptr, "(M-%c)", toupper(s->miscval));
-	    *(ptr++) = '\t';
+	/* 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;
 	}
+    }
 
-	/* Make sure all the help text starts at the same place. */
-	while (entries < 3) {
-	    entries++;
-	    *(ptr++) = '\t';
-	}
+    /* 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
 
-	assert(s->help != NULL);
+    /* Restore the current line and cursor position. */
+    current = fileage;
+    current_x = top_x;
 
-	if (COLS > 24) {
-	    char *help_ptr = display_string(s->help, 0, COLS - 24,
-		FALSE);
+    top_save = fileage;
 
-	    ptr += sprintf(ptr, help_ptr);
+    /* Unpartition the filestruct so that it contains all the text
+     * again, minus the saved text. */
+    unpartition_filestruct(&filepart);
 
-	    free(help_ptr);
-	}
+    /* Renumber starting with the beginning line of the old
+     * partition. */
+    renumber(top_save);
 
-	ptr += sprintf(ptr, "\n");
-    }
+    if (filebot->data[0] != '\0')
+	new_magicline();
 
-#ifndef NANO_SMALL
-    /* And the toggles... */
-    if (currshortcut == main_list) {
-	for (t = toggles; t != NULL; t = t->next) {
+    /* Set totlines to the new number of lines in the file. */
+    totlines = filebot->lineno;
+}
 
-	    assert(t->desc != NULL);
+/* 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;
 
-	    ptr += sprintf(ptr, "M-%c\t\t\t%s %s\n", toupper(t->val),
-		t->desc, _("enable/disable"));
-	}
-    }
+    assert(file_top != NULL && file_bot != NULL);
 
-#ifdef ENABLE_NANORC
-    if (old_whitespace)
-	SET(WHITESPACE_DISPLAY);
-#endif
-#endif
+    /* 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);
 
-    /* If all went well, we didn't overwrite the allocated space for
-     * help_text. */
-    assert(strlen(help_text) <= allocsize + 1);
-}
-#endif
+    /* 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;
 
-/* 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));
+    /* Restore the current line and cursor position. */
+    current = filebot;
+    current_x = strlen(filebot->data);
+    if (fileage == filebot)
+	current_x += strlen(filepart->top_data);
 
-    newnode->data = NULL;
-    newnode->prev = prevnode;
-    newnode->next = NULL;
-    newnode->lineno = (prevnode != NULL) ? prevnode->lineno + 1 : 1;
+    /* 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;
 
-    return newnode;
-}
+    /* 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;
 
-/* Make a copy of a filestruct node. */
-filestruct *copy_node(const filestruct *src)
-{
-    filestruct *dst;
+    top_save = fileage;
 
-    assert(src != NULL);
+    /* Unpartition the filestruct so that it contains all the text
+     * again, minus the saved text. */
+    unpartition_filestruct(&filepart);
 
-    dst = (filestruct *)nmalloc(sizeof(filestruct));
+    /* Renumber starting with the beginning line of the old
+     * partition. */
+    renumber(top_save);
 
-    dst->data = mallocstrcpy(NULL, src->data);
-    dst->next = src->next;
-    dst->prev = src->prev;
-    dst->lineno = src->lineno;
+    if (filebot->data[0] != '\0')
+	new_magicline();
 
-    return dst;
+    /* Set totlines to the new number of lines in the file. */
+    totlines = filebot->lineno;
 }
 
-/* Splice a node into an existing filestruct. */
-void splice_node(filestruct *begin, filestruct *newnode, filestruct
-	*end)
+void print_view_warning(void)
 {
-    assert(newnode != NULL && begin != NULL);
-
-    newnode->next = end;
-    newnode->prev = begin;
-    begin->next = newnode;
-    if (end != NULL)
-	end->prev = newnode;
+    statusbar(_("Key illegal in VIEW mode"));
 }
 
-/* Unlink a node from the rest of the filestruct. */
-void unlink_node(const filestruct *fileptr)
+/* What we do when we're all set to exit. */
+void finish(void)
 {
-    assert(fileptr != NULL);
+    if (!ISSET(NO_HELP))
+	blank_bottombars();
+    else
+	blank_statusbar();
 
-    if (fileptr->prev != NULL)
-	fileptr->prev->next = fileptr->next;
-    if (fileptr->next != NULL)
-	fileptr->next->prev = fileptr->prev;
-}
+    wrefresh(bottomwin);
+    endwin();
 
-/* Delete a node from the filestruct. */
-void delete_node(filestruct *fileptr)
-{
-    assert(fileptr != NULL && fileptr->data != NULL);
+    /* Restore the old terminal settings. */
+    tcsetattr(0, TCSANOW, &oldterm);
 
-    if (fileptr->data != NULL)
-	free(fileptr->data);
-    free(fileptr);
+#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
+    if (!ISSET(NO_RCFILE) && ISSET(HISTORYLOG))
+	save_history();
+#endif
+
+#ifdef DEBUG
+    thanks_for_all_the_fish();
+#endif
+
+    exit(0);
 }
 
-/* Duplicate a whole filestruct. */
-filestruct *copy_filestruct(const filestruct *src)
+/* Die (gracefully?). */
+void die(const char *msg, ...)
 {
-    filestruct *head, *copy;
+    va_list ap;
 
-    assert(src != NULL);
+    endwin();
+    curses_ended = TRUE;
 
-    copy = copy_node(src);
-    copy->prev = NULL;
-    head = copy;
-    src = src->next;
+    /* Restore the old terminal settings. */
+    tcsetattr(0, TCSANOW, &oldterm);
 
-    while (src != NULL) {
-	copy->next = copy_node(src);
-	copy->next->prev = copy;
-	copy = copy->next;
+    va_start(ap, msg);
+    vfprintf(stderr, msg, ap);
+    va_end(ap);
 
-	src = src->next;
+    /* Save the current file buffer if it's been modified. */
+    if (ISSET(MODIFIED)) {
+	/* If we've partitioned the filestruct, unpartition it now. */
+	if (filepart != NULL)
+	    unpartition_filestruct(&filepart);
+
+	die_save_file(filename);
     }
-    copy->next = NULL;
 
-    return head;
-}
+#ifdef ENABLE_MULTIBUFFER
+    /* Save all of the other modified file buffers, if any. */
+    if (open_files != NULL) {
+	openfilestruct *tmp = open_files;
 
-/* Frees a filestruct. */
-void free_filestruct(filestruct *src)
-{
-    assert(src != NULL);
+	while (tmp != open_files->next) {
+	    open_files = open_files->next;
 
-    while (src->next != NULL) {
-	src = src->next;
-	delete_node(src->prev);
+	    /* Save the current file buffer if it's been modified. */
+	    if (open_files->flags & MODIFIED) {
+		/* Set fileage and filebot to match the current file
+		 * buffer, and then write it to disk. */
+		fileage = open_files->fileage;
+		filebot = open_files->filebot;
+		die_save_file(open_files->filename);
+	    }
+	}
     }
-    delete_node(src);
+#endif
+
+    /* Get out. */
+    exit(1);
 }
 
-/* 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)
+void die_save_file(const char *die_filename)
 {
-    partition *p;
+    char *retval;
+    bool failed = TRUE;
 
-    assert(top != NULL && bot != NULL && fileage != NULL && filebot != NULL);
+    /* If we're using restricted mode, don't write any emergency backup
+     * files, since that would allow reading from or writing to files
+     * not specified on the command line. */
+    if (ISSET(RESTRICTED))
+	return;
 
-    /* Initialize the partition. */
-    p = (partition *)nmalloc(sizeof(partition));
+    /* If we can't save, we have REAL bad problems, but we might as well
+     * TRY. */
+    if (die_filename[0] == '\0')
+	die_filename = "nano";
 
-    /* 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;
+    retval = get_next_filename(die_filename, ".save");
+    if (retval[0] != '\0')
+	failed = (write_file(retval, NULL, TRUE, FALSE, TRUE) == -1);
 
-    /* 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';
+    if (!failed)
+	fprintf(stderr, _("\nBuffer written to %s\n"), retval);
+    else if (retval[0] != '\0')
+	fprintf(stderr, _("\nBuffer not written to %s: %s\n"), retval,
+		strerror(errno));
+    else
+	fprintf(stderr, _("\nBuffer not written: %s\n"),
+		_("Too many backup files?"));
 
-    /* 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);
+    free(retval);
+}
 
-    /* Remove all text after bot_x at the bottom of the partition. */
-    null_at(&bot->data, bot_x);
+/* Die with an error message that the screen was too small if, well, the
+ * screen is too small. */
+void check_die_too_small(void)
+{
+    editwinrows = LINES - 5 + no_more_space() + no_help();
+    if (editwinrows < MIN_EDITOR_ROWS)
+	die(_("Window size is too small for nano...\n"));
+}
 
-    /* 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);
+/* Reinitialize the variables that depend on the window size.  That is,
+ * fill and hblank. */
+void resize_variables(void)
+{
+#ifndef DISABLE_WRAPJUSTIFY
+    fill = wrap_at;
+    if (fill <= 0)
+	fill += COLS;
+    if (fill < 0)
+	fill = 0;
+#endif
 
-    /* Return the partition. */
-    return p;
+    hblank = charealloc(hblank, COLS + 1);
+    charset(hblank, ' ', COLS);
+    hblank[COLS] = '\0';
 }
 
-/* Unpartition a filestruct so it begins at (fileage, 0) and ends at
- * (filebot, strlen(filebot)) again. */
-void unpartition_filestruct(partition **p)
+/* Initialize global variables -- no better way for now.  If
+ * save_cutbuffer is TRUE, don't set cutbuffer to NULL. */
+void global_init(bool save_cutbuffer)
 {
-    char *tmp;
+    check_die_too_small();
+    resize_variables();
 
-    assert(p != NULL && fileage != NULL && filebot != NULL);
+    fileage = NULL;
+    edittop = NULL;
+    current = NULL;
+    if (!save_cutbuffer)
+	cutbuffer = NULL;
+    current_x = 0;
+    placewewant = 0;
+    current_y = 0;
+    totlines = 0;
+    totsize = 0;
+}
 
-    /* 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);
+void window_init(void)
+{
+    check_die_too_small();
 
-    /* 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);
+    if (topwin != NULL)
+	delwin(topwin);
+    if (edit != NULL)
+	delwin(edit);
+    if (bottomwin != NULL)
+	delwin(bottomwin);
 
-    /* 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;
+    /* Set up the windows. */
+    topwin = newwin(2 - no_more_space(), COLS, 0, 0);
+    edit = newwin(editwinrows, COLS, 2 - no_more_space(), 0);
+    bottomwin = newwin(3 - no_help(), COLS, editwinrows +
+	(2 - no_more_space()), 0);
 
-    /* Uninitialize the partition. */
-    free(*p);
-    *p = NULL;
+    /* Turn the keypad back on. */
+    keypad(edit, TRUE);
+    keypad(bottomwin, TRUE);
 }
 
-/* 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)
+#ifndef DISABLE_MOUSE
+void mouse_init(void)
 {
-    filestruct *top_save;
-    size_t part_totsize;
-    bool at_edittop;
-#ifndef NANO_SMALL
-    bool mark_inside = FALSE;
+    if (ISSET(USE_MOUSE)) {
+	mousemask(BUTTON1_RELEASED, NULL);
+	mouseinterval(50);
+    } else
+	mousemask(0, NULL);
+}
 #endif
 
-    assert(file_top != NULL && file_bot != NULL && top != NULL && bot != NULL);
+#ifndef DISABLE_HELP
+/* This function allocates help_text, and stores the help string in it. 
+ * help_text should be NULL initially. */
+void help_init(void)
+{
+    size_t allocsize = 0;	/* Space needed for help_text. */
+    const char *htx[3];		/* Untranslated help message.  We break
+				 * it up into three chunks in case the
+				 * full string is too long for the
+				 * compiler to handle. */
+    char *ptr;
+    const shortcut *s;
+#ifndef NANO_SMALL
+    const toggle *t;
+#ifdef ENABLE_NANORC
+    bool old_whitespace = ISSET(WHITESPACE_DISPLAY);
 
-    /* If (top, top_x)-(bot, bot_x) doesn't cover any text, get out. */
-    if (top == bot && top_x == bot_x)
-	return;
+    UNSET(WHITESPACE_DISPLAY);
+#endif
+#endif
 
-    /* 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);
+    /* First, set up the initial help text for the current function. */
+    if (currshortcut == whereis_list || currshortcut == replace_list
+	     || currshortcut == replace_list_2) {
+	htx[0] = N_("Search Command Help Text\n\n "
+		"Enter the words or characters you would like to "
+		"search for, and then press Enter.  If there is a "
+		"match for the text you entered, the screen will be "
+		"updated to the location of the nearest match for the "
+		"search string.\n\n The previous search string will be "
+		"shown in brackets after the search prompt.  Hitting "
+		"Enter without entering any text will perform the "
+		"previous search.  ");
+	htx[1] = N_("If you have selected text with the mark and then "
+		"search to replace, only matches in the selected text "
+		"will be replaced.\n\n The following function keys are "
+		"available in Search mode:\n\n");
+	htx[2] = NULL;
+    } else if (currshortcut == gotoline_list) {
+	htx[0] = N_("Go To Line Help Text\n\n "
+		"Enter the line number that you wish to go to and hit "
+		"Enter.  If there are fewer lines of text than the "
+		"number you entered, you will be brought to the last "
+		"line of the file.\n\n The following function keys are "
+		"available in Go To Line mode:\n\n");
+	htx[1] = NULL;
+	htx[2] = NULL;
+    } else if (currshortcut == insertfile_list) {
+	htx[0] = N_("Insert File Help Text\n\n "
+		"Type in the name of a file to be inserted into the "
+		"current file buffer at the current cursor "
+		"location.\n\n If you have compiled nano with multiple "
+		"file buffer support, and enable multiple file buffers "
+		"with the -F or --multibuffer command line flags, the "
+		"Meta-F toggle, or a nanorc file, inserting a file "
+		"will cause it to be loaded into a separate buffer "
+		"(use Meta-< and > to switch between file buffers).  ");
+	htx[1] = N_("If you need another blank buffer, do not enter "
+		"any filename, or type in a nonexistent filename at "
+		"the prompt and press Enter.\n\n The following "
+		"function keys are available in Insert File mode:\n\n");
+	htx[2] = NULL;
+    } else if (currshortcut == writefile_list) {
+	htx[0] = N_("Write File Help Text\n\n "
+		"Type the name that you wish to save the current file "
+		"as and press Enter to save the file.\n\n If you have "
+		"selected text with the mark, you will be prompted to "
+		"save only the selected portion to a separate file.  To "
+		"reduce the chance of overwriting the current file with "
+		"just a portion of it, the current filename is not the "
+		"default in this mode.\n\n The following function keys "
+		"are available in Write File mode:\n\n");
+	htx[1] = NULL;
+	htx[2] = NULL;
+    }
+#ifndef DISABLE_BROWSER
+    else if (currshortcut == browser_list) {
+	htx[0] = N_("File Browser Help Text\n\n "
+		"The file browser is used to visually browse the "
+		"directory structure to select a file for reading "
+		"or writing.  You may use the arrow keys or Page Up/"
+		"Down to browse through the files, and S or Enter to "
+		"choose the selected file or enter the selected "
+		"directory.  To move up one level, select the "
+		"directory called \"..\" at the top of the file "
+		"list.\n\n The following function keys are available "
+		"in the file browser:\n\n");
+	htx[1] = NULL;
+	htx[2] = NULL;
+    } else if (currshortcut == gotodir_list) {
+	htx[0] = N_("Browser Go To Directory Help Text\n\n "
+		"Enter the name of the directory you would like to "
+		"browse to.\n\n If tab completion has not been "
+		"disabled, you can use the Tab key to (attempt to) "
+		"automatically complete the directory name.\n\n The "
+		"following function keys are available in Browser Go "
+		"To Directory mode:\n\n");
+	htx[1] = NULL;
+	htx[2] = NULL;
+    }
+#endif
+#ifndef DISABLE_SPELLER
+    else if (currshortcut == spell_list) {
+	htx[0] = N_("Spell Check Help Text\n\n "
+		"The spell checker checks the spelling of all text in "
+		"the current file.  When an unknown word is "
+		"encountered, it is highlighted and a replacement can "
+		"be edited.  It will then prompt to replace every "
+		"instance of the given misspelled word in the current "
+		"file, or, if you have selected text with the mark, in "
+		"the selected text.\n\n The following other functions "
+		"are available in Spell Check mode:\n\n");
+	htx[1] = NULL;
+	htx[2] = NULL;
+    }
+#endif
 #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));
+    else if (currshortcut == extcmd_list) {
+	htx[0] = N_("Execute Command Help Text\n\n "
+		"This menu allows you to insert the output of a "
+		"command run by the shell into the current buffer (or "
+		"a new buffer in multiple file buffer mode). If you "
+		"need another blank buffer, do not enter any "
+		"command.\n\n The following keys are available in "
+		"Execute Command mode:\n\n");
+	htx[1] = NULL;
+	htx[2] = NULL;
+    }
 #endif
+    else {
+	/* Default to the main help list. */
+	htx[0] = N_(" nano help text\n\n "
+		"The nano editor is designed to emulate the "
+		"functionality and ease-of-use of the UW Pico text "
+		"editor.  There are four main sections of the editor.  "
+		"The top line shows the program version, the current "
+		"filename being edited, and whether or not the file "
+		"has been modified.  Next is the main editor window "
+		"showing the file being edited.  The status line is "
+		"the third line from the bottom and shows important "
+		"messages.  The bottom two lines show the most "
+		"commonly used shortcuts in the editor.\n\n ");
+	htx[1] = N_("The notation for shortcuts is as follows: "
+		"Control-key sequences are notated with a caret (^) "
+		"symbol and can be entered either by using the Control "
+		"(Ctrl) key or pressing the Escape (Esc) key twice.  "
+		"Escape-key sequences are notated with the Meta (M) "
+		"symbol and can be entered using either the Esc, Alt, "
+		"or Meta key depending on your keyboard setup.  ");
+	htx[2] = N_("Also, pressing Esc twice and then typing a "
+		"three-digit decimal number from 000 to 255 will enter "
+		"the character with the corresponding value.  The "
+		"following keystrokes are available in the main editor "
+		"window.  Alternative keys are shown in "
+		"parentheses:\n\n");
+    }
 
-    /* Get the number of characters in the text, and subtract it from
-     * totsize. */
-    get_totals(top, bot, NULL, &part_totsize);
-    totsize -= part_totsize;
+    htx[0] = _(htx[0]);
+    if (htx[1] != NULL)
+	htx[1] = _(htx[1]);
+    if (htx[2] != NULL)
+	htx[2] = _(htx[2]);
 
-    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);
+    allocsize += strlen(htx[0]);
+    if (htx[1] != NULL)
+	allocsize += strlen(htx[1]);
+    if (htx[2] != NULL)
+	allocsize += strlen(htx[2]);
 
-	/* 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;
-	}
-    }
+    /* The space needed for the shortcut lists, at most COLS characters,
+     * plus '\n'. */
+    allocsize += (COLS < 24 ? (24 * mb_cur_max()) :
+	((COLS + 1) * mb_cur_max())) * length_of_list(currshortcut);
 
-    /* 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;
+    /* If we're on the main list, we also count the toggle help text.
+     * Each line has "M-%c\t\t\t", which fills 24 columns, plus a space,
+     * plus translated text, plus '\n'. */
+    if (currshortcut == main_list) {
+	size_t endis_len = strlen(_("enable/disable"));
+
+	for (t = toggles; t != NULL; t = t->next)
+	    allocsize += 8 + strlen(t->desc) + endis_len;
     }
 #endif
 
-    /* Restore the current line and cursor position. */
-    current = fileage;
-    current_x = top_x;
+    /* help_text has been freed and set to NULL unless the user resized
+     * while in the help screen. */
+    free(help_text);
 
-    top_save = fileage;
+    /* Allocate space for the help text. */
+    help_text = charalloc(allocsize + 1);
 
-    /* Unpartition the filestruct so that it contains all the text
-     * again, minus the saved text. */
-    unpartition_filestruct(&filepart);
+    /* Now add the text we want. */
+    strcpy(help_text, htx[0]);
+    if (htx[1] != NULL)
+	strcat(help_text, htx[1]);
+    if (htx[2] != NULL)
+	strcat(help_text, htx[2]);
 
-    /* Renumber starting with the beginning line of the old
-     * partition. */
-    renumber(top_save);
+    ptr = help_text + strlen(help_text);
 
-    if (filebot->data[0] != '\0')
-	new_magicline();
+    /* Now add our shortcut info.  Assume that each shortcut has, at the
+     * very least, an equivalent control key, an equivalent primary meta
+     * key sequence, or both.  Also assume that the meta key values are
+     * not control characters.  We can display a maximum of 3 shortcut
+     * entries. */
+    for (s = currshortcut; s != NULL; s = s->next) {
+	int entries = 0;
 
-    /* Set totlines to the new number of lines in the file. */
-    totlines = filebot->lineno;
-}
+	/* Control key. */
+	if (s->ctrlval != NANO_NO_KEY) {
+	    entries++;
+	    /* Yucky sentinel values that we can't handle a better
+	     * way. */
+	    if (s->ctrlval == NANO_CONTROL_SPACE) {
+		char *space_ptr = display_string(_("Space"), 0, 6,
+			FALSE);
 
-/* 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;
+		ptr += sprintf(ptr, "^%s", space_ptr);
 
-    assert(file_top != NULL && file_bot != NULL);
+		free(space_ptr);
+	    } else if (s->ctrlval == NANO_CONTROL_8)
+		ptr += sprintf(ptr, "^?");
+	    /* Normal values. */
+	    else
+		ptr += sprintf(ptr, "^%c", s->ctrlval + 64);
+	    *(ptr++) = '\t';
+	}
 
-    /* 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);
+	/* Function key. */
+	if (s->funcval != NANO_NO_KEY) {
+	    entries++;
+	    /* If this is the first entry, put it in the middle. */
+	    if (entries == 1) {
+		entries++;
+		*(ptr++) = '\t';
+	    }
+	    ptr += sprintf(ptr, "(F%d)", s->funcval - KEY_F0);
+	    *(ptr++) = '\t';
+	}
 
-    /* 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;
+	/* Primary meta key sequence.  If it's the first entry, don't
+	 * put parentheses around it. */
+	if (s->metaval != NANO_NO_KEY) {
+	    entries++;
+	    /* If this is the last entry, put it at the end. */
+	    if (entries == 2 && s->miscval == NANO_NO_KEY) {
+		entries++;
+		*(ptr++) = '\t';
+	    }
+	    /* Yucky sentinel values that we can't handle a better
+	     * way. */
+	    if (s->metaval == NANO_ALT_SPACE && entries == 1) {
+		char *space_ptr = display_string(_("Space"), 0, 5,
+			FALSE);
 
-    /* Restore the current line and cursor position. */
-    current = filebot;
-    current_x = strlen(filebot->data);
-    if (fileage == filebot)
-	current_x += strlen(filepart->top_data);
+		ptr += sprintf(ptr, "M-%s", space_ptr);
 
-    /* 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;
+		free(space_ptr);
+	    } else
+		/* Normal values. */
+		ptr += sprintf(ptr, (entries == 1) ? "M-%c" : "(M-%c)",
+			toupper(s->metaval));
+	    *(ptr++) = '\t';
+	}
 
-    /* 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;
+	/* Miscellaneous meta key sequence. */
+	if (entries < 3 && s->miscval != NANO_NO_KEY) {
+	    entries++;
+	    /* If this is the last entry, put it at the end. */
+	    if (entries == 2) {
+		entries++;
+		*(ptr++) = '\t';
+	    }
+	    ptr += sprintf(ptr, "(M-%c)", toupper(s->miscval));
+	    *(ptr++) = '\t';
+	}
 
-    top_save = fileage;
+	/* Make sure all the help text starts at the same place. */
+	while (entries < 3) {
+	    entries++;
+	    *(ptr++) = '\t';
+	}
 
-    /* Unpartition the filestruct so that it contains all the text
-     * again, minus the saved text. */
-    unpartition_filestruct(&filepart);
+	assert(s->help != NULL);
 
-    /* Renumber starting with the beginning line of the old
-     * partition. */
-    renumber(top_save);
+	if (COLS > 24) {
+	    char *help_ptr = display_string(s->help, 0, COLS - 24,
+		FALSE);
 
-    if (filebot->data[0] != '\0')
-	new_magicline();
+	    ptr += sprintf(ptr, help_ptr);
 
-    /* Set totlines to the new number of lines in the file. */
-    totlines = filebot->lineno;
-}
+	    free(help_ptr);
+	}
 
-void renumber_all(void)
-{
-    filestruct *temp;
-    ssize_t line = 1;
+	ptr += sprintf(ptr, "\n");
+    }
 
-    assert(fileage == NULL || fileage != fileage->next);
+#ifndef NANO_SMALL
+    /* And the toggles... */
+    if (currshortcut == main_list) {
+	for (t = toggles; t != NULL; t = t->next) {
 
-    for (temp = fileage; temp != NULL; temp = temp->next)
-	temp->lineno = line++;
-}
+	    assert(t->desc != NULL);
 
-void renumber(filestruct *fileptr)
-{
-    if (fileptr == NULL || fileptr->prev == NULL || fileptr == fileage)
-	renumber_all();
-    else {
-	ssize_t line = fileptr->prev->lineno;
+	    ptr += sprintf(ptr, "M-%c\t\t\t%s %s\n", toupper(t->val),
+		t->desc, _("enable/disable"));
+	}
+    }
 
-	assert(fileptr != fileptr->next);
+#ifdef ENABLE_NANORC
+    if (old_whitespace)
+	SET(WHITESPACE_DISPLAY);
+#endif
+#endif
 
-	for (; fileptr != NULL; fileptr = fileptr->next)
-	    fileptr->lineno = ++line;
-    }
+    /* If all went well, we didn't overwrite the allocated space for
+     * help_text. */
+    assert(strlen(help_text) <= allocsize + 1);
 }
+#endif
 
 #ifdef HAVE_GETOPT_LONG
 #define print1opt(shortflag, longflag, desc) print1opt_full(shortflag, longflag, desc)
diff --git a/src/proto.h b/src/proto.h
index 33c26f4bb8709b44281f1a7cfb8bf16fde49c67d..53d7ab503105bf8e5590f39d66b9ea048d90b72a 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,20 +359,6 @@ void do_right(bool allow_update);
 void do_right_void(void);
 
 /* Public functions in nano.c. */
-void print_view_warning(void);
-void finish(void);
-void die(const char *msg, ...);
-void die_save_file(const char *die_filename);
-void check_die_too_small(void);
-void resize_variables(void);
-void global_init(bool save_cutbuffer);
-void window_init(void);
-#ifndef DISABLE_MOUSE
-void mouse_init(void);
-#endif
-#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
@@ -381,14 +367,28 @@ 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 renumber_all(void);
-void renumber(filestruct *fileptr);
+void print_view_warning(void);
+void finish(void);
+void die(const char *msg, ...);
+void die_save_file(const char *die_filename);
+void check_die_too_small(void);
+void resize_variables(void);
+void global_init(bool save_cutbuffer);
+void window_init(void);
+#ifndef DISABLE_MOUSE
+void mouse_init(void);
+#endif
+#ifndef DISABLE_HELP
+void help_init(void);
+#endif
 void print1opt_full(const char *shortflag
 #ifdef HAVE_GETOPT_LONG
 	, const char *longflag