diff --git a/ChangeLog b/ChangeLog
index a9eb0e12174af5c7b22a40925f5a37eff8da1bab..98192dcb74ff3e7057502da1fe54ac41c3878c80 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -29,13 +29,26 @@ CVS code -
 	  shortcut display routines to handle them.  Also modify the
 	  shortcut list code to not treat non-control character values
 	  of val as Meta-sequences, and fix dependencies on that
-	  behavior. (DLR)
+	  behavior.  Also rename several variables: "alt" -> "meta",
+	  "altval" -> "metaval". (DLR)
 	- Hook up the verbatim input functions so that verbatim input
 	  can be used in the edit window.  New function
 	  do_verbatim_input(); changes to do_char(). (DLR)  Additional
 	  minor tweaks to do_char() by David Benbennick.
 	- Clarify the description of the --rebinddelete option. (DLR)
+- cut.c:
+	- Overhaul to increase efficiency and add various cleanups.
+	  Changes to add_to_cutbuffer(), cut_marked_segment(), and
+	  do_uncut_text(). (David Benbennick)
 - files.c:
+  check_operating_dir()
+	- Add an assert to ensure that full_operatingdir isn't NULL,
+	  a fix for reporting nonexistent (incomplete) directory names
+	  as being outside the operating directory when tab completion
+	  is being used, and cosmetic cleanups. (David Benbennick)
+  copy_file()
+	- New function containing part of the functionality formerly in
+	  do_writeout. (David Benbennick)
   do_writeout()
 	- Prompt the user if we're trying to save an existing file (and
 	  not just a selection of it) under a different name. (DLR;
@@ -56,6 +69,10 @@ CVS code -
 	- Convert to use the new low-level input functions. (DLR)
   main()
 	- Remove unused variable option_index. (DLR)
+	- Fix omission of NANO_NO_KEY in the shortcut list scanning
+	  code. (DLR)
+- nano.h:
+	- Comment additions and cosmetic tweaks. (DLR)
 - search.c:
   findnextstr(), do_replace_loop()
 	- Fix potential infinite loops and other misbehavior when doing
@@ -95,6 +112,9 @@ CVS code -
 	- Modify to take an extra parameter indicating if we should
 	  ungetch() the key equivalents of shortcuts we click on or not.
 	  (DLR)
+  nanogetstr()
+	- Properly interpret the Meta key value in misc if we hit it at
+	  the statusbar prompt. (DLR)
   do_yesno()
 	- Add a few efficiency/extensibility tweaks. (David Benbennick)
 	- Convert to use the new low-level input functions, and remove
diff --git a/src/cut.c b/src/cut.c
index 61d88bf982e99d5f0b3b81959e5a3fe06a92033f..7652c17f304f4bdaaefdd7cd981b30c4f3389811 100644
--- a/src/cut.c
+++ b/src/cut.c
@@ -28,15 +28,17 @@
 #include "proto.h"
 #include "nano.h"
 
-static int marked_cut;		/* Is the cutbuffer from a mark? */
+static int marked_cut;		/* Is the cutbuffer from a mark?
+				 * 0 means whole-line cut, 1 means mark,
+				 * 2 means cut-from-cursor. */
 
 #ifndef NANO_SMALL
 static int concatenate_cut;	/* Should we add this cut string to the
-				   end of the last one? */
+				 * end of the last one? */
 #endif
 
 static filestruct *cutbottom = NULL;
-				/* Pointer to end of cutbuffer */
+				/* Pointer to end of cutbuffer. */
 
 filestruct *get_cutbottom(void)
 {
@@ -46,29 +48,27 @@ filestruct *get_cutbottom(void)
 void add_to_cutbuffer(filestruct *inptr)
 {
 #ifdef DEBUG
-    fprintf(stderr, "add_to_cutbuffer() called with inptr->data = %s\n",
-	    inptr->data);
+    fprintf(stderr, "add_to_cutbuffer(): inptr->data = %s\n", inptr->data);
 #endif
 
-    if (cutbuffer == NULL) {
+    if (cutbuffer == NULL)
 	cutbuffer = inptr;
-	inptr->prev = NULL;
 #ifndef NANO_SMALL
-    } else if (concatenate_cut && !ISSET(JUSTIFY_MODE)) {
+    else if (concatenate_cut && !ISSET(JUSTIFY_MODE)) {
 	/* Just tack the text in inptr onto the text in cutbottom,
-	   unless we're backing up lines while justifying text. */
+	 * unless we're backing up lines while justifying text. */
 	cutbottom->data = charealloc(cutbottom->data,
 		strlen(cutbottom->data) + strlen(inptr->data) + 1);
 	strcat(cutbottom->data, inptr->data);
 	return;
+    }
 #endif
-    } else {
+    else {
 	cutbottom->next = inptr;
 	inptr->prev = cutbottom;
     }
-
-    inptr->next = NULL;
     cutbottom = inptr;
+    cutbottom->next = NULL;
 }
 
 #ifndef NANO_SMALL
@@ -78,112 +78,115 @@ void add_to_cutbuffer(filestruct *inptr)
  * last cut line has length bot_x.  That is, if bot_x > 0 then we cut to
  * bot->data[bot_x - 1].
  *
- * destructive is whether to actually modify the file structure, if not
- * then just copy the buffer into cutbuffer and don't pull it from the
- * file.
+ * We maintain totsize, totlines, filebot, the magicline, and line
+ * numbers.  Also, we set current and current_x so the cursor will be on
+ * the first character after what was cut.  We do not do any screen
+ * updates.
  *
- * If destructive, then we maintain totsize, totlines, filebot, the
- * magic line, and line numbers.  Also, we set current and current_x so
- * the cursor will be on the first character after what was cut.  We do
- * not do any screen updates. */
-void cut_marked_segment(filestruct *top, size_t top_x, filestruct *bot,
-			size_t bot_x, int destructive)
+ * Note cutbuffer might not be NULL if "cut to end" is used. */
+void cut_marked_segment(void)
 {
-    filestruct *tmp, *next;
+    filestruct *top;
+    filestruct *bot;
+    filestruct *tmp;
+    size_t top_x;
+    size_t bot_x;
     size_t newsize;
 
-    if (top == bot && top_x == bot_x)
+    /* If the mark doesn't cover any text, get out. */
+    if (current == mark_beginbuf && current_x == mark_beginx)
 	return;
-    assert(top != NULL && bot != NULL);
-
-    /* Make top be no later than bot. */
-    if (top->lineno > bot->lineno) {
-	filestruct *swap = top;
-	int swap2 = top_x;
+    assert(current != NULL && mark_beginbuf != NULL);
 
-	top = bot;
-	bot = swap;
+    /* Set up the top and bottom lines and coordinates of the marked
+     * text. */
+    mark_order((const filestruct **)&top, &top_x,
+		(const filestruct **)&bot, &bot_x);
 
-	top_x = bot_x;
-	bot_x = swap2;
-    } else if (top == bot && top_x > bot_x) {
-	/* And bot_x can't be an earlier character than top_x. */
-	int swap = top_x;
-
-	top_x = bot_x;
-	bot_x = swap;
-    }
-
-    /* Make the first cut line manually. */
+    /* Make the first cut line manually.  Move the cut part of the top
+     * line into tmp, and set newsize to that partial line's length. */
     tmp = copy_node(top);
     newsize = (top == bot ? bot_x - top_x : strlen(top->data + top_x));
-    charmove(tmp->data, top->data + top_x, newsize);
+    charmove(tmp->data, tmp->data + top_x, newsize);
     null_at(&tmp->data, newsize);
-    add_to_cutbuffer(tmp);
-
-    /* And make the remainder line manually too. */
-    if (destructive) {
-	current_x = top_x;
-	totsize -= newsize;
-	totlines -= bot->lineno - top->lineno;
-
-	newsize = top_x + strlen(bot->data + bot_x) + 1;
-	if (top == bot) {
-	    /* In this case, the remainder line is shorter, so we must
-	       move text from the end forward first. */
-	    charmove(top->data + top_x, bot->data + bot_x,
-			newsize - top_x);
-	    top->data = charealloc(top->data, newsize);
-	} else {
-	    totsize -= bot_x + 1;
 
-	    /* Here, the remainder line might get longer, so we
-	       realloc() it first. */
-	    top->data = charealloc(top->data, newsize);
-	    charmove(top->data + top_x, bot->data + bot_x,
-			newsize - top_x);
-	}
+    /* Add the contents of tmp to the cutbuffer.  Note that cutbuffer
+     * might be non-NULL if we have cut to end enabled. */
+    if (cutbuffer == NULL) {
+	cutbuffer = tmp;
+	cutbottom = tmp;
+    } else {
+	cutbottom->next = tmp;
+	tmp->prev = cutbottom;
+	cutbottom = tmp;
     }
 
+    /* And make the top remainder line manually too.  Update current_x
+     * and totlines to account for all the cut text, and update totsize
+     * to account for the length of the cut part of the first line. */
+    current_x = top_x;
+    totsize -= newsize;
+    totlines -= bot->lineno - top->lineno;
+
+    /* Now set newsize to be the length of the top remainder line plus
+     * the bottom remainder line, plus one for the null terminator. */
+    newsize = top_x + strlen(bot->data + bot_x) + 1;
+
     if (top == bot) {
+	/* In this case, we're only cutting one line or part of one
+	 * line, so the remainder line is shorter.  This means that we
+	 * must move text from the end forward first. */
+	charmove(top->data + top_x, bot->data + bot_x, newsize - top_x);
+	top->data = charealloc(top->data, newsize);
+
+	cutbottom->next = NULL;
 #ifdef DEBUG
 	dump_buffer(cutbuffer);
 #endif
 	return;
     }
 
-    tmp = top->next;
-    while (tmp != bot) {
-	next = tmp->next;
-	if (!destructive)
-	    tmp = copy_node(tmp);
-	else
-	    totsize -= strlen(tmp->data) + 1;
-	add_to_cutbuffer(tmp);
-	tmp = next;
-    }
+    /* Update totsize to account for the cut part of the last line. */
+    totsize -= bot_x + 1;
 
-    /* Make the last cut line manually. */
-    tmp = copy_node(bot);
-    null_at(&tmp->data, bot_x);
-    add_to_cutbuffer(tmp);
-#ifdef DEBUG
-    dump_buffer(cutbuffer);
-#endif
+    /* Here, the top remainder line might get longer (if the bottom
+     * remainder line is added to the end of it), so we realloc() it
+     * first. */
+    top->data = charealloc(top->data, newsize);
+    charmove(top->data + top_x, bot->data + bot_x, newsize - top_x);
 
-    if (destructive) {
-	top->next = bot->next;
-	if (top->next != NULL)
-	    top->next->prev = top;
-	delete_node(bot);
-	renumber(top);
-	current = top;
-	if (bot == filebot) {
-	    filebot = top;
-	    assert(bot_x == 0);
-	    if (top_x > 0)
-		new_magicline();
-	}
+    assert(cutbottom != NULL && cutbottom->next != NULL);
+    /* We're cutting multiple lines, so in particular the next line is
+     * cut too. */
+    cutbottom->next->prev = cutbottom;
+
+    /* Update totsize to account for all the complete lines that have
+     * been cut.  After this, totsize is fully up to date. */
+    for (tmp = top->next; tmp != bot; tmp = tmp->next)
+	totsize -= strlen(tmp->data) + 1;
+
+    /* Make the last cut line manually. */
+    null_at(&bot->data, bot_x);
+
+    /* Move the rest of the cut text (other than the cut part of the top
+     * line) from the buffer to the end of the cutbuffer, and fix the
+     * edit buffer to account for the cut text. */
+    top->next = bot->next;
+    cutbottom = bot;
+    cutbottom->next = NULL;
+    if (top->next != NULL)
+	top->next->prev = top;
+    renumber(top);
+    current = top;
+
+    /* If the bottom line of the cut was the magicline, set filebot
+     * properly, and add a new magicline if the top remainder line
+     * (which is now the new bottom line) is non-blank. */
+    if (bot == filebot) {
+	filebot = top;
+	assert(bot_x == 0);
+	if (top_x > 0)
+	    new_magicline();
     }
 #ifdef DEBUG
     dump_buffer(cutbuffer);
@@ -194,9 +197,6 @@ void cut_marked_segment(filestruct *top, size_t top_x, filestruct *bot,
 int do_cut_text(void)
 {
     filestruct *fileptr;
-#ifndef NANO_SMALL
-    int dontupdate = 0;
-#endif
 
     assert(current != NULL && current->data != NULL);
 
@@ -214,8 +214,8 @@ int do_cut_text(void)
 #endif
     }
 
-    /* You can't cut the magic line except with the mark.  But
-       trying does clear the cutbuffer if KEEP_CUTBUFFER is not set. */
+    /* You can't cut the magicline except with the mark.  But trying
+     * does clear the cutbuffer if KEEP_CUTBUFFER is not set. */
     if (current == filebot
 #ifndef NANO_SMALL
 			&& !ISSET(MARK_ISSET)
@@ -231,11 +231,12 @@ int do_cut_text(void)
 
 	if (current->data[current_x] == '\0') {
 	    /* If the line is empty and we didn't just cut a non-blank
-	       line, create a dummy line and add it to the cutbuffer */
+	     * line, create a dummy blank line and add it to the
+	     * cutbuffer. */
 	    if (marked_cut != 1 && current->next != filebot) {
 		filestruct *junk = make_new_node(current);
 
-	        junk->data = charalloc(1);
+		junk->data = charalloc(1);
 		junk->data[0] = '\0';
 		add_to_cutbuffer(junk);
 #ifdef DEBUG
@@ -251,33 +252,22 @@ int do_cut_text(void)
 
 	    mark_beginx = strlen(current->data);
 	    mark_beginbuf = current;
-	    dontupdate = 1;
 	}
     }
 
     if (ISSET(MARK_ISSET)) {
-	/* Don't do_update() and move the screen position if the marked
-	   area lies entirely within the screen buffer */
-	dontupdate |= current->lineno >= edittop->lineno &&
-			current->lineno <= editbot->lineno &&
-			mark_beginbuf->lineno >= edittop->lineno &&
-			mark_beginbuf->lineno <= editbot->lineno;
-	cut_marked_segment(current, current_x, mark_beginbuf,
-				mark_beginx, 1);
+	cut_marked_segment();
 
 	placewewant = xplustabs();
 	UNSET(MARK_ISSET);
 
 	/* If we just did a marked cut of part of a line, we should add
-	   the first line of any cut done immediately afterward to the
-	   end of this cut, as Pico does. */
+	 * the first line of any cut done immediately afterward to the
+	 * end of this cut, as Pico does. */
 	if (current == mark_beginbuf && current_x < strlen(current->data))
 	    concatenate_cut = 1;
 	marked_cut = 1;
-	if (dontupdate)
-	    edit_refresh();
-	else
-	    edit_update(current, CENTER);
+	edit_refresh();
 	set_modified();
 
 	return 1;
@@ -310,29 +300,26 @@ int do_cut_text(void)
 #ifndef NANO_SMALL
     concatenate_cut = 0;
 #endif
-    placewewant = 0;
     return 1;
 }
 
 int do_uncut_text(void)
 {
-    filestruct *tmp = current, *fileptr = current;
-    filestruct *newbuf = NULL, *newend = NULL;
-    char *tmpstr, *tmpstr2;
-    filestruct *hold = current;
-    int i;
+    filestruct *tmp = current;
+    filestruct *newbuf = NULL;
+    filestruct *newend = NULL;
 
 #ifndef DISABLE_WRAPPING
     wrap_reset();
 #endif
     check_statblank();
-    if (cutbuffer == NULL || fileptr == NULL)
+    if (cutbuffer == NULL || current == NULL)
 	return 0;		/* AIEEEEEEEEEEEE */
 
     /* If we're uncutting a previously non-marked block, uncut to end if
-       we're not at the beginning of the line.  If we are at the
-       beginning of the line, set placewewant to 0.  Pico does both of
-       these. */
+     * we're not at the beginning of the line.  If we are at the
+     * beginning of the line, set placewewant to 0.  Pico does both of
+     * these. */
     if (marked_cut == 0) {
 	if (current_x != 0)
 	    marked_cut = 2;
@@ -341,24 +328,22 @@ int do_uncut_text(void)
     }
 
     /* If we're going to uncut on the magicline, always make a new
-       magicline in advance. */
+     * magicline in advance, as Pico does. */
     if (current->next == NULL)
 	new_magicline();
 
-    if (marked_cut == 0 || cutbuffer->next != NULL)
-    {
+    if (marked_cut == 0 || cutbuffer->next != NULL) {
 	newbuf = copy_filestruct(cutbuffer);
 	for (newend = newbuf; newend->next != NULL && newend != NULL;
 		newend = newend->next)
 	    totlines++;
     }
 
-    /* Hook newbuf into fileptr */
+    /* Hook newbuf in at current. */
     if (marked_cut != 0) {
-	int recenter_me = 0;
-	    /* Should we eventually use edit_update(CENTER)? */
+	filestruct *hold = current;
 
-	/* If there's only one line in the cutbuffer */
+	/* If there's only one line in the cutbuffer... */
 	if (cutbuffer->next == NULL) {
 	    size_t buf_len = strlen(cutbuffer->data);
 	    size_t cur_len = strlen(current->data);
@@ -367,22 +352,24 @@ int do_uncut_text(void)
 	    charmove(current->data + current_x + buf_len,
 			current->data + current_x, cur_len - current_x + 1);
 	    strncpy(current->data + current_x, cutbuffer->data, buf_len);
-		/* Use strncpy() to not copy the terminal '\0'. */
+		/* Use strncpy() to not copy the null terminator. */
 
 	    current_x += buf_len;
 	    totsize += buf_len;
 
 	    placewewant = xplustabs();
-	    update_cursor();
-	} else {		/* yuck -- no kidding! */
+	} else {		/* Yuck -- no kidding! */
+	    char *tmpstr, *tmpstr2;
+
 	    tmp = current->next;
-	    /* New beginning */
+
+	    /* New beginning. */
 	    tmpstr = charalloc(current_x + strlen(newbuf->data) + 1);
 	    strncpy(tmpstr, current->data, current_x);
 	    strcpy(&tmpstr[current_x], newbuf->data);
 	    totsize += strlen(newbuf->data) + strlen(newend->data) + 1;
 
-	    /* New end */
+	    /* New end. */
 	    tmpstr2 = charalloc(strlen(newend->data) +
 			      strlen(&current->data[current_x]) + 1);
 	    strcpy(tmpstr2, newend->data);
@@ -401,35 +388,28 @@ int do_uncut_text(void)
 
 	    newend->next = tmp;
 
-	    /* If tmp isn't null, we're in the middle: update the
-	       prev pointer.  If it IS null, we're at the end; update
-	       the filebot pointer */
-
+	    /* If tmp isn't NULL, we're in the middle: update the
+	     * prev pointer.  If it IS NULL, we're at the end; update
+	     * the filebot pointer. */
 	    if (tmp != NULL)
 		tmp->prev = newend;
 	    else {
-		/* Fix the editbot pointer too */
-		if (editbot == filebot)
-		    editbot = newend;
 		filebot = newend;
 		new_magicline();
 	    }
 
-	    /* Now why don't we update the totsize also */
+	    /* Now why don't we update the totsize also? */
 	    for (tmp = current->next; tmp != newend; tmp = tmp->next)
 		totsize += strlen(tmp->data) + 1;
 
 	    current = newend;
-	    if (editbot->lineno < newend->lineno)
-		recenter_me = 1;
 	}
 
 	/* If marked cut == 2, that means that we're doing a cut to end
-	   and we don't want anything else on the line, so we have to
-	   screw up all the work we just did and separate the line.
-	   There must be a better way to do this, but not at 1AM on a
-	   work night. */
-
+	 * and we don't want anything else on the line, so we have to
+	 * screw up all the work we just did and separate the line.
+	 * There must be a better way to do this, but not at 1 AM on a
+	 * work night. */
 	if (marked_cut == 2) {
 	    tmp = make_new_node(current);
 	    tmp->data = mallocstrcpy(NULL, current->data + current_x);
@@ -439,7 +419,7 @@ int do_uncut_text(void)
 	    current_x = 0;
 	    placewewant = 0;
 
-	    /* Extra line added, update stuff */
+	    /* Extra line added; update stuff. */
 	    totlines++;
 	    totsize++;
 	}
@@ -451,41 +431,32 @@ int do_uncut_text(void)
 	dump_buffer(cutbuffer);
 #endif
 	set_modified();
-	if (recenter_me)
-	    edit_update(current, CENTER);
-	else
-	    edit_refresh();
+	edit_refresh();
 	return 0;
     }
 
-    if (fileptr != fileage) {
-	tmp = fileptr->prev;
+    if (current != fileage) {
+	tmp = current->prev;
 	tmp->next = newbuf;
 	newbuf->prev = tmp;
     } else
 	fileage = newbuf;
-    totlines++;		/* Unmarked uncuts don't split lines */
+    totlines++;		/* Unmarked uncuts don't split lines. */
 
     /* This is so uncutting at the top of the buffer will work => */
     if (current_y == 0)
 	edittop = newbuf;
 
-    /* Connect the end of the buffer to the filestruct */
-    newend->next = fileptr;
-    fileptr->prev = newend;
+    /* Connect the end of the buffer to the filestruct. */
+    newend->next = current;
+    current->prev = newend;
 
     /* Recalculate size *sigh* */
-    for (tmp = newbuf; tmp != fileptr; tmp = tmp->next)
+    for (tmp = newbuf; tmp != current; tmp = tmp->next)
 	totsize += strlen(tmp->data) + 1;
 
-    i = editbot->lineno;
     renumber(newbuf);
-    /* Center the screen if we've moved beyond the line numbers of both
-       the old and new editbots */
-    if (i < newend->lineno && editbot->lineno < newend->lineno)
-	edit_update(fileptr, CENTER);
-    else
-	edit_refresh();
+    edit_refresh();
 
 #ifdef DEBUG
     dump_buffer_reverse();
diff --git a/src/files.c b/src/files.c
index 46422a105cfee771864fc581ae56f5f627ca45c3..3fc823327052c20dcb2b77e3a293e9d59b3741ae 100644
--- a/src/files.c
+++ b/src/files.c
@@ -522,7 +522,7 @@ int do_insertfile(int loading_file)
 #endif
 
 #ifndef DISABLE_OPERATINGDIR
-	if (i != NANO_EXTCMD_KEY && check_operating_dir(answer, FALSE)) {
+	if (i != NANO_EXTCMD_KEY && check_operating_dir(answer, 0) != 0) {
 	    statusbar(_("Can't insert file from outside of %s"),
 			operating_dir);
 	    return 0;
@@ -1272,409 +1272,375 @@ void init_operating_dir(void)
     }
 }
 
-/*
- * Check to see if we're inside the operating directory.  Return 0 if we
+/* Check to see if we're inside the operating directory.  Return 0 if we
  * are, or 1 otherwise.  If allow_tabcomp is nonzero, allow incomplete
  * names that would be matches for the operating directory, so that tab
- * completion will work.
- */
+ * completion will work. */
 int check_operating_dir(const char *currpath, int allow_tabcomp)
 {
-    /* The char *full_operating_dir is global for mem cleanup, and
-       therefore we only need to get it the first time this function
-       is called; also, a relative operating directory path will
-       only be handled properly if this is done */
+    /* The char *full_operating_dir is global for mem cleanup.  It
+     * should have already been initialized by init_operating_dir().
+     * Also, a relative operating directory path will only be handled
+     * properly if this is done. */
 
     char *fullpath;
     int retval = 0;
     const char *whereami1, *whereami2 = NULL;
 
-    /* if no operating directory is set, don't bother doing anything */
+    /* If no operating directory is set, don't bother doing anything. */
     if (operating_dir == NULL)
 	return 0;
+    assert(full_operating_dir != NULL);
 
     fullpath = get_full_path(currpath);
+
+    /* fullpath == NULL means some directory in the path doesn't exist
+     * or is unreadable.  If allow_tabcomp is zero, then currpath is
+     * what the user typed somewhere.  We don't want to report a
+     * non-existent directory as being outside the operating directory,
+     * so we return 0.  If allow_tabcomp is nonzero, then currpath
+     * exists, but is not executable.  So we say it isn't in the
+     * operating directory. */
     if (fullpath == NULL)
-	return 1;
+	return allow_tabcomp;
 
     whereami1 = strstr(fullpath, full_operating_dir);
     if (allow_tabcomp)
 	whereami2 = strstr(full_operating_dir, fullpath);
 
-    /* if both searches failed, we're outside the operating directory */
-    /* otherwise */
-    /* check the search results; if the full operating directory path is
-       not at the beginning of the full current path (for normal usage)
-       and vice versa (for tab completion, if we're allowing it), we're
-       outside the operating directory */
+    /* If both searches failed, we're outside the operating directory.
+     * Otherwise, check the search results; if the full operating
+     * directory path is not at the beginning of the full current path
+     * (for normal usage) and vice versa (for tab completion, if we're
+     * allowing it), we're outside the operating directory. */
     if (whereami1 != fullpath && whereami2 != full_operating_dir)
 	retval = 1;
     free(fullpath);	
-    /* otherwise, we're still inside it */
+
+    /* Otherwise, we're still inside it. */
     return retval;
 }
 #endif
 
-/*
- * Write a file out.  If tmp is nonzero, we set the umask to 0600,
- * we don't set the global variable filename to its name, and don't
- * print out how many lines we wrote on the statusbar.
+/* Read from inn, write to out.  We assume inn is opened for reading,
+ * and out for writing.  We return 0 on success, -1 on read error, -2 on
+ * write error. */
+int copy_file(FILE *inn, FILE *out)
+{
+    char buf[BUFSIZ];
+    size_t charsread;
+    int retval = 0;
+
+    assert(inn != NULL && out != NULL);
+    do {
+	charsread = fread(buf, sizeof(char), BUFSIZ, inn);
+	if (charsread == 0 && ferror(inn)) {
+	    retval = -1;
+	    break;
+	}
+	if (fwrite(buf, sizeof(char), charsread, out) < charsread) {
+	    retval = -2;
+	    break;
+	}
+    } while (charsread > 0);
+    if (fclose(inn) == EOF)
+	retval = -1;
+    if (fclose(out) == EOF)
+	retval = -2;
+    return retval;
+}
+
+/* Write a file out.  If tmp is nonzero, we set the umask to disallow
+ * anyone else from accessing the file, we don't set the global variable
+ * filename to its name, and we don't print out how many lines we wrote
+ * on the statusbar.
  *
- * tmp means we are writing a tmp file in a secure fashion.  We use
- * it when spell checking or dumping the file on an error.
+ * tmp means we are writing a temporary file in a secure fashion.  We
+ * use it when spell checking or dumping the file on an error.
  *
  * append == 1 means we are appending instead of overwriting.
  * append == 2 means we are prepending instead of overwriting.
  *
  * nonamechange means don't change the current filename, it is ignored
  * if tmp is nonzero or if we're appending/prepending.
- */
+ *
+ * Return -1 on error, 1 on success. */
 int write_file(const char *name, int tmp, int append, int nonamechange)
 {
     int retval = -1;
 	/* Instead of returning in this function, you should always
-	 * merely set retval then goto cleanup_and_exit. */
-    long size;
-    int lineswritten = 0;
-    char *buf = NULL;
-    const filestruct *fileptr;
-    FILE *f;
+	 * merely set retval and then goto cleanup_and_exit. */
+    size_t lineswritten = 0;
+    const filestruct *fileptr = fileage;
     int fd;
-    int mask = 0, realexists, anyexists;
-    struct stat st, lst;
-    char *realname = NULL;
+    mode_t original_umask = 0;
+	/* Our umask, from when nano started. */
+    int realexists;
+	/* The result of stat().  True if the file exists, false
+	 * otherwise.  If name is a link that points nowhere, realexists
+	 * is false. */
+    struct stat st;
+	/* The status fields filled in by stat(). */
+    int anyexists;
+	/* Result of lstat().  Same as realexists unless name is a
+	 * link. */
+    struct stat lst;
+	/* The status fields filled in by lstat(). */
+    char *realname;
+	/* name after ~ expansion. */
+    FILE *f;
+	/* The actual file, realname, we are writing to. */
+    char *tempname = NULL;
+	/* The temp file name we write to on prepend. */
 
+    assert(name != NULL);
     if (name[0] == '\0') {
 	statusbar(_("Cancelled"));
 	return -1;
     }
     if (!tmp)
 	titlebar(NULL);
-    fileptr = fileage;
 
     realname = real_dir_from_tilde(name);
 
 #ifndef DISABLE_OPERATINGDIR
     /* If we're writing a temporary file, we're probably going outside
-       the operating directory, so skip the operating directory test. */
-    if (!tmp && operating_dir != NULL && check_operating_dir(realname, 0)) {
+     * the operating directory, so skip the operating directory test. */
+    if (!tmp && check_operating_dir(realname, 0) != 0) {
 	statusbar(_("Can't write outside of %s"), operating_dir);
 	goto cleanup_and_exit;
     }
 #endif
 
+    anyexists = lstat(realname, &lst) != -1;
+    /* New case: if the file exists, just give up. */
+    if (tmp && anyexists)
+	goto cleanup_and_exit;
+    /* If NOFOLLOW_SYMLINKS is set, it doesn't make sense to prepend or
+     * append to a symlink.  Here we warn about the contradiction. */
+    if (ISSET(NOFOLLOW_SYMLINKS) && anyexists && S_ISLNK(lst.st_mode)) {
+	statusbar(_("Cannot prepend or append to a symlink with --nofollow set."));
+	goto cleanup_and_exit;
+    }
+
     /* Save the state of file at the end of the symlink (if there is
-       one). */
-    realexists = stat(realname, &st);
+     * one). */
+    realexists = stat(realname, &st) != -1;
 
 #ifndef NANO_SMALL
     /* We backup only if the backup toggle is set, the file isn't
-       temporary, and the file already exists.  Furthermore, if we aren't
-       appending, prepending, or writing a selection, we backup only if
-       the file has not been modified by someone else since nano opened
-       it. */
-    if (ISSET(BACKUP_FILE) && !tmp && realexists == 0 &&
-	    (append != 0 || ISSET(MARK_ISSET) ||
-		originalfilestat.st_mtime == st.st_mtime)) {
+     * temporary, and the file already exists.  Furthermore, if we
+     * aren't appending, prepending, or writing a selection, we backup
+     * only if the file has not been modified by someone else since nano
+     * opened it. */
+    if (ISSET(BACKUP_FILE) && !tmp && realexists != 0 &&
+	(append != 0 || ISSET(MARK_ISSET) ||
+	originalfilestat.st_mtime == st.st_mtime)) {
+
 	FILE *backup_file;
-	char *backupname = NULL;
-	char backupbuf[COPYFILEBLOCKSIZE];
-	size_t bytesread;
+	char *backupname;
 	struct utimbuf filetime;
+	int copy_status;
 
-	/* save the original file's access and modification times */
+	/* Save the original file's access and modification times. */
 	filetime.actime = originalfilestat.st_atime;
 	filetime.modtime = originalfilestat.st_mtime;
 
-	/* open the original file to copy to the backup */
+	/* Open the original file to copy to the backup. */
 	f = fopen(realname, "rb");
 	if (f == NULL) {
-	    statusbar(_("Could not read %s for backup: %s"), realname,
+	    statusbar(_("Error reading %s: %s"), realname,
 		strerror(errno));
-	    return -1;
+	    goto cleanup_and_exit;
 	}
 
 	backupname = charalloc(strlen(realname) + 2);
 	sprintf(backupname, "%s~", realname);
 
-	/* get a file descriptor for the destination backup file */
+	/* Open the destination backup file.  Before we write to it, we
+	 * set its permissions, so no unauthorized person can read it as
+	 * we write. */
 	backup_file = fopen(backupname, "wb");
-	if (backup_file == NULL) {
-	    statusbar(_("Couldn't write backup: %s"), strerror(errno));
+	if (backup_file == NULL ||
+		chmod(backupname, originalfilestat.st_mode) == -1) {
+	    statusbar(_("Error writing %s: %s"), backupname, strerror(errno));
 	    free(backupname);
-	    return -1;
+	    if (backup_file != NULL)
+		fclose(backup_file);
+	    fclose(f);
+	    goto cleanup_and_exit;
 	}
 
 #ifdef DEBUG
 	fprintf(stderr, "Backing up %s to %s\n", realname, backupname);
 #endif
 
-	/* copy the file */
-	while ((bytesread = fread(backupbuf, sizeof(char),
-		COPYFILEBLOCKSIZE, f)) > 0)
-	    if (fwrite(backupbuf, sizeof(char), bytesread, backup_file) <= 0)
-		break;
-	fclose(backup_file);
-	fclose(f);
-
-	if (chmod(backupname, originalfilestat.st_mode) == -1)
-	    statusbar(_("Could not set permissions %o on backup %s: %s"),
-			originalfilestat.st_mode, backupname,
+	/* Copy the file. */
+	copy_status = copy_file(f, backup_file);
+	/* And set metadata. */
+	if (copy_status != 0 || chown(backupname, originalfilestat.st_uid,
+		originalfilestat.st_gid) == -1 ||
+		utime(backupname, &filetime) == -1) {
+	    free(backupname);
+	    if (copy_status == -1)
+		statusbar(_("Error reading %s: %s"), realname,
 			strerror(errno));
-
-	if (chown(backupname, originalfilestat.st_uid,
-		originalfilestat.st_gid) == -1)
-	    statusbar(_("Could not set owner %d/group %d on backup %s: %s"),
-			originalfilestat.st_uid, originalfilestat.st_gid,
-			backupname, strerror(errno));
-
-	if (utime(backupname, &filetime) == -1)
-	    statusbar(_("Could not set access/modification time on backup %s: %s"),
-			backupname, strerror(errno));
-
+	    else
+		statusbar(_("Error writing %s: %s"), backupname,
+			strerror(errno));
+	    goto cleanup_and_exit;
+	}
 	free(backupname);
     }
-#endif
-
-    /* Stat the link itself for the check... */
-    anyexists = lstat(realname, &lst);
+#endif /* !NANO_SMALL */
 
-    /* New case: if the file exists, just give up */
-    if (tmp && anyexists != -1)
+    /* If NOFOLLOW_SYMLINKS and the file is a link, we aren't doing
+     * prepend or append.  So we delete the link first, and just
+     * overwrite. */
+    if (ISSET(NOFOLLOW_SYMLINKS) && anyexists && S_ISLNK(lst.st_mode) &&
+	unlink(realname) == -1) {
+	statusbar(_("Error writing %s: %s"), realname, strerror(errno));
 	goto cleanup_and_exit;
-    /* NOTE: If you change this statement, you MUST CHANGE the if 
-       statement below (that says:
-		if (realexists == -1 || tmp || (ISSET(NOFOLLOW_SYMLINKS) &&
-		S_ISLNK(lst.st_mode))) {
-       to reflect whether or not to link/unlink/rename the file */
-    else if (append != 2 && (!ISSET(NOFOLLOW_SYMLINKS) || !S_ISLNK(lst.st_mode) 
-		|| tmp)) {
-	/* Use O_EXCL if tmp is nonzero.  This is now copied from joe,
-	   because wiggy says so *shrug*. */
-	if (append != 0)
-	    fd = open(realname, O_WRONLY | O_CREAT | O_APPEND, (S_IRUSR | S_IWUSR));
-	else if (tmp)
-	    fd = open(realname, O_WRONLY | O_CREAT | O_EXCL, (S_IRUSR | S_IWUSR));
-	else
-	    fd = open(realname, O_WRONLY | O_CREAT | O_TRUNC, (S_IRUSR | S_IWUSR));
+    }
 
-	/* First, just give up if we couldn't even open the file */
-	if (fd == -1) {
-	    if (!tmp && ISSET(TEMP_OPT)) {
-		UNSET(TEMP_OPT);
-		retval = do_writeout(filename, 1, 0);
-	    } else
-		statusbar(_("Could not open file for writing: %s"),
-			strerror(errno));
+    original_umask = umask(0);
+    umask(original_umask);
+    /* If we create a temp file, we don't let anyone else access it.  We
+     * create a temp file if tmp is nonzero or if we prepend. */
+    if (tmp || append == 2)
+	umask(S_IRWXG | S_IRWXO);
+
+    /* If we are prepending, copy the file to a temp file. */
+    if (append == 2) {
+	int fd_source;
+	FILE *f_source = NULL;
+
+	tempname = charalloc(strlen(realname) + 8);
+	strcpy(tempname, realname);
+	strcat(tempname, ".XXXXXX");
+	fd = mkstemp(tempname);
+	f = NULL;
+	if (fd != -1) {
+	    f = fdopen(fd, "wb");
+	    if (f == NULL)
+		close(fd);
+	}
+	if (f == NULL) {
+	    statusbar(_("Error writing %s: %s"), tempname, strerror(errno));
+	    unlink(tempname);
 	    goto cleanup_and_exit;
 	}
 
-    }
-    /* Don't follow symlink.  Create new file. */
-    else {
-	buf = charalloc(strlen(realname) + 8);
-	strcpy(buf, realname);
-	strcat(buf, ".XXXXXX");
-	if ((fd = mkstemp(buf)) == -1) {
-	    if (ISSET(TEMP_OPT)) {
-		UNSET(TEMP_OPT);
-		retval = do_writeout(filename, 1, 0);
-	    } else
-		statusbar(_("Could not open file for writing: %s"),
-			strerror(errno));
+	fd_source = open(realname, O_RDONLY | O_CREAT);
+	if (fd_source != -1) {
+	    f_source = fdopen(fd_source, "rb");
+	    if (f_source == NULL)
+		close(fd_source);
+	}
+	if (f_source == NULL) {
+	    statusbar(_("Error reading %s: %s"), realname, strerror(errno));
+	    fclose(f);
+	    unlink(tempname);
+	    goto cleanup_and_exit;
+	}
+
+	if (copy_file(f_source, f) != 0) {
+	    statusbar(_("Error writing %s: %s"), tempname, strerror(errno));
+	    unlink(tempname);
 	    goto cleanup_and_exit;
 	}
     }
 
-#ifdef DEBUG
-    dump_buffer(fileage);
-#endif
+    /* Now open the file in place.  Use O_EXCL if tmp is nonzero.  This
+     * is now copied from joe, because wiggy says so *shrug*. */
+    fd = open(realname, O_WRONLY | O_CREAT |
+	(append == 1 ? O_APPEND : (tmp ? O_EXCL : O_TRUNC)),
+	S_IRUSR | S_IWUSR);
+
+    /* Put the umask back to the user's original value. */
+    umask(original_umask);
+
+    /* First, just give up if we couldn't even open the file. */
+    if (fd == -1) {
+	statusbar(_("Error writing %s: %s"), realname, strerror(errno));
+	unlink(tempname);
+	goto cleanup_and_exit;
+    }
 
     f = fdopen(fd, append == 1 ? "ab" : "wb");
     if (f == NULL) {
-	statusbar(_("Could not open file for writing: %s"), strerror(errno));
+	statusbar(_("Error writing %s: %s"), realname, strerror(errno));
+	close(fd);
 	goto cleanup_and_exit;
     }
 
-    while (fileptr != NULL && fileptr->next != NULL) {
-	int data_len;
+    /* There might not be a magic line.  There won't be when writing out
+     * a selection. */
+    assert(fileage != NULL && filebot != NULL);
+    while (fileptr != filebot) {
+	size_t data_len = strlen(fileptr->data);
+	size_t size;
 
-	/* Next line is so we discount the "magic line" */
-	if (filebot == fileptr && fileptr->data[0] == '\0')
-	    break;
-
-	data_len = strlen(fileptr->data);
-
-	/* newlines to nulls, just before we write to disk */
+	/* Newlines to nulls, just before we write to disk. */
 	sunder(fileptr->data);
 
-	size = fwrite(fileptr->data, 1, data_len, f);
+	size = fwrite(fileptr->data, sizeof(char), data_len, f);
 
-	/* nulls to newlines; data_len is the string's real length here */
+	/* Nulls to newlines; data_len is the string's real length. */
 	unsunder(fileptr->data, data_len);
 
 	if (size < data_len) {
-	    statusbar(_("Could not open file for writing: %s"),
-		      strerror(errno));
+	    statusbar(_("Error writing %s: %s"), realname, strerror(errno));
 	    fclose(f);
 	    goto cleanup_and_exit;
 	}
-#ifdef DEBUG
-	else
-	    fprintf(stderr, "Wrote >%s\n", fileptr->data);
-#endif
 #ifndef NANO_SMALL
 	if (ISSET(DOS_FILE) || ISSET(MAC_FILE))
-	    putc('\r', f);
+	    if (putc('\r', f) == EOF) {
+		statusbar(_("Error writing %s: %s"), realname, strerror(errno));
+		fclose(f);
+		goto cleanup_and_exit;
+	    }
 
 	if (!ISSET(MAC_FILE))
 #endif
-	    putc('\n', f);
+	    if (putc('\n', f) == EOF) {
+		statusbar(_("Error writing %s: %s"), realname, strerror(errno));
+		fclose(f);
+		goto cleanup_and_exit;
+	    }
 
 	fileptr = fileptr->next;
 	lineswritten++;
     }
 
-    if (fileptr != NULL) {
-	int data_len = strlen(fileptr->data);
-
-	/* newlines to nulls, just before we write to disk */
-	sunder(fileptr->data);
-
-	size = fwrite(fileptr->data, 1, data_len, f);
-
-	/* nulls to newlines; data_len is the string's real length here */
-	unsunder(fileptr->data, data_len);
-
-	if (size < data_len) {
-	    statusbar(_("Could not open file for writing: %s"),
-		      strerror(errno));
-	    goto cleanup_and_exit;
-	} else if (data_len > 0) {
-#ifndef NANO_SMALL
-	    if (ISSET(DOS_FILE) || ISSET(MAC_FILE)) {
-		if (putc('\r', f) == EOF) {
-		    statusbar(_("Could not open file for writing: %s"),
-			  strerror(errno));
-		    fclose(f);
-		    goto cleanup_and_exit;
-		}
-		lineswritten++;
-	    }
-
-	    if (!ISSET(MAC_FILE))
-#endif
-	    {
-		if (putc('\n', f) == EOF) {
-		    statusbar(_("Could not open file for writing: %s"),
-			  strerror(errno));
-		    fclose(f);
-		    goto cleanup_and_exit;
-		}
-		lineswritten++;
-	    }
-	}
-    }
-
-    if (fclose(f) != 0) {
-	statusbar(_("Could not close %s: %s"), realname, strerror(errno));
-	unlink(buf);
-	goto cleanup_and_exit;
-    }
-
-    /* if we're prepending, open the real file, and append it here */
+    /* If we're prepending, open the temp file, and append it to f. */
     if (append == 2) {
-	int fd_source, fd_dest;
-	FILE *f_source, *f_dest;
-	int prechar;
-
-	if ((fd_dest = open(buf, O_WRONLY | O_APPEND, (S_IRUSR | S_IWUSR))) == -1) {
-	    statusbar(_("Could not reopen %s: %s"), buf, strerror(errno));
-	    goto cleanup_and_exit;
-	}
-	f_dest = fdopen(fd_dest, "wb");
-	if (f_dest == NULL) {
-	    statusbar(_("Could not reopen %s: %s"), buf, strerror(errno));
-	    close(fd_dest);
-	    goto cleanup_and_exit;
-	}
-	if ((fd_source = open(realname, O_RDONLY | O_CREAT)) == -1) {
-	    statusbar(_("Could not open %s for prepend: %s"), realname, strerror(errno));
-	    fclose(f_dest);
-	    goto cleanup_and_exit;
+	int fd_source;
+	FILE *f_source = NULL;
+
+	fd_source = open(tempname, O_RDONLY | O_CREAT);
+	if (fd_source != -1) {
+	    f_source = fdopen(fd_source, "rb");
+	    if (f_source == NULL)
+		close(fd_source);
 	}
-	f_source = fdopen(fd_source, "rb");
 	if (f_source == NULL) {
-	    statusbar(_("Could not open %s for prepend: %s"), realname, strerror(errno));
-	    fclose(f_dest);
-	    close(fd_source);
+	    statusbar(_("Error reading %s: %s"), tempname, strerror(errno));
+	    fclose(f);
 	    goto cleanup_and_exit;
 	}
 
-        /* Doing this in blocks is an exercise left to some other reader. */
-	while ((prechar = getc(f_source)) != EOF) {
-	    if (putc(prechar, f_dest) == EOF) {
-		statusbar(_("Could not open %s for prepend: %s"), realname, strerror(errno));
-		fclose(f_source);
-		fclose(f_dest);
-		goto cleanup_and_exit;
-	    }
-	}
-
-	if (ferror(f_source)) {
-	    statusbar(_("Could not reopen %s: %s"), buf, strerror(errno));
-	    fclose(f_source);
-	    fclose(f_dest);
-	    goto cleanup_and_exit;
-	}
-	    
-	fclose(f_source);
-	fclose(f_dest);
-    }
-
-    if (realexists == -1 || tmp ||
-	(ISSET(NOFOLLOW_SYMLINKS) && S_ISLNK(lst.st_mode))) {
-
-	/* Use default umask as file permissions if file is a new file. */
-	mask = umask(0);
-	umask(mask);
-
-	if (tmp)	/* We don't want anyone reading our temporary file! */
-	    mask = S_IRUSR | S_IWUSR;
-	else
-	    mask = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH |
-		S_IWOTH) & ~mask;
-    } else
-	/* Use permissions from file we are overwriting. */
-	mask = st.st_mode;
-
-    if (append == 2 || 
-		(!tmp && (ISSET(NOFOLLOW_SYMLINKS) && S_ISLNK(lst.st_mode)))) {
-	if (unlink(realname) == -1) {
-	    if (errno != ENOENT) {
-		statusbar(_("Could not open %s for writing: %s"),
-			  realname, strerror(errno));
-		unlink(buf);
-		goto cleanup_and_exit;
-	    }
-	}
-	if (link(buf, realname) != -1)
-	    unlink(buf);
-	else if (errno != EPERM) {
-	    statusbar(_("Could not open %s for writing: %s"),
-		      name, strerror(errno));
-	    unlink(buf);
-	    goto cleanup_and_exit;
-	} else if (rename(buf, realname) == -1) {	/* Try a rename?? */
-	    statusbar(_("Could not open %s for writing: %s"),
-		      realname, strerror(errno));
-	    unlink(buf);
+	if (copy_file(f_source, f) == -1
+		|| unlink(tempname) == -1) {
+	    statusbar(_("Error writing %s: %s"), realname, strerror(errno));
 	    goto cleanup_and_exit;
 	}
+    } else if (fclose(f) == EOF) {
+	statusbar(_("Error writing %s: %s"), realname, strerror(errno));
+	unlink(tempname);
+	goto cleanup_and_exit;
     }
-    if (chmod(realname, mask) == -1)
-	statusbar(_("Could not set permissions %o on %s: %s"),
-		  mask, realname, strerror(errno));
 
     if (!tmp && append == 0) {
 	if (!nonamechange) {
@@ -1689,8 +1655,8 @@ int write_file(const char *name, int tmp, int append, int nonamechange)
 	/* Update originalfilestat to reference the file as it is now. */
 	stat(filename, &originalfilestat);
 #endif
-	statusbar(P_("Wrote %d line", "Wrote %d lines", lineswritten),
-			lineswritten);
+	statusbar(P_("Wrote %u line", "Wrote %u lines", lineswritten),
+		lineswritten);
 	UNSET(MODIFIED);
 	titlebar(NULL);
     }
@@ -1699,7 +1665,7 @@ int write_file(const char *name, int tmp, int append, int nonamechange)
 
   cleanup_and_exit:
     free(realname);
-    free(buf);
+    free(tempname);
     return retval;
 }
 
@@ -1850,31 +1816,52 @@ int do_writeout(const char *path, int exiting, int append)
 	}
 
 #ifndef NANO_SMALL
-	/* Here's where we allow the selected text to be written to 
-	   a separate file. */
+	/* Here's where we allow the selected text to be written to
+	 * a separate file. */
 	if (ISSET(MARK_ISSET) && !exiting) {
 	    filestruct *fileagebak = fileage;
 	    filestruct *filebotbak = filebot;
-	    filestruct *cutback = cutbuffer;
 	    int oldmod = ISSET(MODIFIED);
 		/* write_file() unsets the MODIFIED flag. */
-
-	    cutbuffer = NULL;
-
-	    /* Put the marked text in the cutbuffer without changing
-	       the open file. */
-	    cut_marked_segment(current, current_x, mark_beginbuf,
-				mark_beginx, 0);
-
-	    fileage = cutbuffer;
-	    filebot = get_cutbottom();
+	    size_t topx;
+		/* The column of the beginning of the mark. */
+	    char origchar;
+		/* We replace the character at the end of the mark with
+		 * '\0'.  We save the original character, to restore
+		 * it. */
+	    char *origcharloc;
+		/* The location of the character we nulled. */
+
+	    /* Set fileage as the top of the mark, and filebot as the
+	     * bottom. */
+	    if (current->lineno > mark_beginbuf->lineno ||
+		(current->lineno == mark_beginbuf->lineno &&
+		current_x > mark_beginx)) {
+		fileage = mark_beginbuf;
+		topx = mark_beginx;
+		filebot = current;
+		origcharloc = current->data + current_x;
+	    } else {
+		fileage = current;
+		topx = current_x;
+		filebot = mark_beginbuf;
+		origcharloc = mark_beginbuf->data + mark_beginx;
+	    }
+	    origchar = *origcharloc;
+	    *origcharloc = '\0';
+	    fileage->data += topx;
+	    /* If the line at filebot is blank, treat it as the
+	     * magicline and hence the end of the file.  Otherwise,
+	     * treat the line after filebot as the end of the file. */
+	    if (filebot->data[0] != '\0' && filebot->next != NULL)
+		filebot = filebot->next;
 	    i = write_file(answer, 0, append, 1);
 
-	    /* Now restore everything */
-	    free_filestruct(cutbuffer);
+	    /* Now restore everything. */
+	    fileage->data -= topx;
+	    *origcharloc = origchar;
 	    fileage = fileagebak;
 	    filebot = filebotbak;
-	    cutbuffer = cutback;
 	    if (oldmod)
 		set_modified();
 	} else
@@ -2110,7 +2097,7 @@ char **cwd_tab_completion(char *buf, int *num_matches)
 		strcpy(tmp2, dirname);
 		strcat(tmp2, "/");
 		strcat(tmp2, next->d_name);
-		if (check_operating_dir(tmp2, 1)) {
+		if (check_operating_dir(tmp2, 1) != 0) {
 		    free(tmp2);
 		    continue;
 		}
@@ -2631,7 +2618,7 @@ char *do_browser(const char *inpath)
 	    /* Note: the selected file can be outside the operating
 	     * directory if it is .. or if it is a symlink to 
 	     * directory outside the operating directory. */
-	    if (check_operating_dir(filelist[selected], FALSE)) {
+	    if (check_operating_dir(filelist[selected], 0) != 0) {
 		statusbar(_("Can't go outside of %s in restricted mode"), operating_dir);
 		beep();
 		break;
@@ -2704,7 +2691,7 @@ char *do_browser(const char *inpath)
 	    }
 
 #ifndef DISABLE_OPERATINGDIR
-	    if (check_operating_dir(new_path, FALSE)) {
+	    if (check_operating_dir(new_path, 0) != 0) {
 		statusbar(_("Can't go outside of %s in restricted mode"), operating_dir);
 		free(new_path);
 		break;
@@ -2847,7 +2834,7 @@ char *do_browse_from(const char *inpath)
 
 #ifndef DISABLE_OPERATINGDIR
     /* If the resulting path isn't in the operating directory, use that. */
-    if (check_operating_dir(path, FALSE))
+    if (check_operating_dir(path, 0) != 0)
 	path = mallocstrcpy(path, operating_dir);
 #endif
 
diff --git a/src/global.c b/src/global.c
index 78da209c3f684581731ab6c0e1bf6276f6c44928..e2c8b11b4e92634c70884e5d07a75f2bf140e462 100644
--- a/src/global.c
+++ b/src/global.c
@@ -172,7 +172,7 @@ void sc_init_one(shortcut **shortcutage, int key, const char *desc,
 #ifndef DISABLE_HELP
 	const char *help,
 #endif
-	int alt, int func_key, int misc, int view, int (*func) (void))
+	int meta, int func_key, int misc, int view, int (*func) (void))
 {
     shortcut *s;
 
@@ -191,7 +191,7 @@ void sc_init_one(shortcut **shortcutage, int key, const char *desc,
 #ifndef DISABLE_HELP
     s->help = help;
 #endif
-    s->altval = alt;
+    s->metaval = meta;
     s->func_key = func_key;
     s->misc = misc;
     s->viewok = view;
diff --git a/src/nano.c b/src/nano.c
index cce32695386dbf4639ae321855a2a057a20b7c1b..351125ee7c810d3b0dea1df7a763b0bace7b7a4c 100644
--- a/src/nano.c
+++ b/src/nano.c
@@ -403,7 +403,7 @@ void help_init(void)
 
     /* Now add our shortcut info */
     for (s = currshortcut; s != NULL; s = s->next) {
-	/* true if the character in s->altval is shown in first column */
+	/* true if the character in s->metaval is shown in first column */
 	int meta_shortcut = 0;
 
 	if (s->val != NANO_NO_KEY) {
@@ -420,12 +420,12 @@ void help_init(void)
 		ptr += sprintf(ptr, "^%c", s->val + 64);
 	}
 #ifndef NANO_SMALL
-	else if (s->altval != NANO_NO_KEY) {
+	else if (s->metaval != NANO_NO_KEY) {
 	    meta_shortcut = 1;
-	    if (s->altval == NANO_ALT_SPACE)
+	    if (s->metaval == NANO_ALT_SPACE)
 		ptr += snprintf(ptr, 8, "M-%.5s", _("Space"));
 	    else
-		ptr += sprintf(ptr, "M-%c", toupper(s->altval));
+		ptr += sprintf(ptr, "M-%c", toupper(s->metaval));
 	}
 #endif
 
@@ -436,8 +436,8 @@ void help_init(void)
 
 	*(ptr++) = '\t';
 
-	if (!meta_shortcut && s->altval != NANO_NO_KEY)
-	    ptr += sprintf(ptr, "(M-%c)", toupper(s->altval));
+	if (!meta_shortcut && s->metaval != NANO_NO_KEY)
+	    ptr += sprintf(ptr, "(M-%c)", toupper(s->metaval));
 	else if (meta_shortcut && s->misc != NANO_NO_KEY)
 	    ptr += sprintf(ptr, "(M-%c)", toupper(s->misc));
 
@@ -3516,10 +3516,10 @@ int main(int argc, char *argv[])
 	fprintf(stderr, "AHA!  %c (%d)\n", kbinput, kbinput);
 #endif
 	if (meta == 1) {
-	    /* Check for the altkey and misc defs... */
+	    /* Check for the metaval and misc defs... */
 	    for (s = main_list; s != NULL; s = s->next)
-		if ((s->altval > 0 && kbinput == s->altval) ||
-		    (s->misc > 0 && kbinput == s->misc)) {
+		if ((s->metaval != NANO_NO_KEY && kbinput == s->metaval) ||
+		    (s->misc != NANO_NO_KEY && kbinput == s->misc)) {
 		    if (ISSET(VIEW_MODE) && !s->viewok)
 			print_view_warning();
 		    else {
diff --git a/src/nano.h b/src/nano.h
index 44c23196a1a052b8783059b9889d56fb576e75c1..41561b824fd6047ec8ed605066859d4dc35a2c91 100644
--- a/src/nano.h
+++ b/src/nano.h
@@ -46,13 +46,14 @@
 #endif
 
 #ifdef USE_SLANG
-/* Slang support enabled */
+/* Slang support enabled.  Work around Slang's not defining KEY_DC or
+ * KEY_IC. */
 #include <slcurses.h>
 #define KEY_DC SL_KEY_DELETE
 #define KEY_IC SL_KEY_IC
 #elif defined(HAVE_NCURSES_H)
 #include <ncurses.h>
-#else /* Uh oh */
+#else /* Uh oh. */
 #include <curses.h>
 #endif /* CURSES_H */
 
@@ -71,16 +72,18 @@
 #include <sys/stat.h>
 #include "config.h"
 
+/* If no snprintf()/vsnprintf(), use the versions from glib. */
 #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
 #include <glib.h>
 # ifndef HAVE_SNPRINTF
-#  define snprintf	g_snprintf
+#  define snprintf g_snprintf
 # endif
 # ifndef HAVE_VSNPRINTF
-#  define vsnprintf	g_vsnprintf
+#  define vsnprintf g_vsnprintf
 # endif
 #endif
 
+/* If no strcasecmp()/strncasecmp(), use the versions we have. */
 #ifndef HAVE_STRCASECMP
 #define strcasecmp nstricmp
 #endif
@@ -90,11 +93,11 @@
 #endif
 
 /* Assume ERR is defined as -1.  To avoid duplicate case values when
-   some key definitions are missing, we have to set all of these, and
-   all of the special sentinel values below, to different negative
-   values other than -1. */
+ * some key definitions are missing, we have to set all of these, and
+ * all of the special sentinel values below, to different negative
+ * values other than -1. */
 
-/* HP-UX 10 & 11 do not seem to support KEY_HOME and KEY_END */
+/* HP-UX 10 & 11 do not seem to support KEY_HOME and KEY_END. */
 #ifndef KEY_HOME
 #define KEY_HOME -2
 #endif
@@ -103,13 +106,13 @@
 #define KEY_END -3
 #endif
 
-/* Slang and SunOS 5.7-5.9 do not seem to support KEY_RESIZE */
+/* Slang and SunOS 5.7-5.9 do not seem to support KEY_RESIZE. */
 #ifndef KEY_RESIZE
 #define KEY_RESIZE -4
 #endif
 
 /* Slang does not seem to support KEY_SUSPEND, KEY_SLEFT, or
-   KEY_SRIGHT */
+ * KEY_SRIGHT. */
 #ifndef KEY_SUSPEND
 #define KEY_SUSPEND -5
 #endif
@@ -124,6 +127,8 @@
 
 #define VERMSG "GNU nano " VERSION
 
+/* If we aren't using ncurses, turn the mouse support off, as it's
+ * ncurses-specific. */
 #ifndef NCURSES_MOUSE_VERSION
 #define DISABLE_MOUSE 1
 #endif
@@ -132,12 +137,12 @@
 #define DISABLE_WRAPJUSTIFY 1
 #endif
 
-/* Structure types */
+/* Structure types. */
 typedef struct filestruct {
     char *data;
-    struct filestruct *next;	/* Next node */
-    struct filestruct *prev;	/* Previous node */
-    int lineno;			/* The line number */
+    struct filestruct *next;	/* Next node. */
+    struct filestruct *prev;	/* Previous node. */
+    int lineno;			/* The line number. */
 } filestruct;
 
 #ifdef ENABLE_MULTIBUFFER
@@ -146,51 +151,56 @@ typedef struct openfilestruct {
 #ifndef NANO_SMALL
     struct stat originalfilestat;
 #endif
-    struct openfilestruct *next;	/* Next node */
-    struct openfilestruct *prev;	/* Previous node */
-    struct filestruct *fileage;	/* Current file */
-    struct filestruct *filebot;	/* Current file's last line */
+    struct openfilestruct *next;	/* Next node. */
+    struct openfilestruct *prev;	/* Previous node. */
+    struct filestruct *fileage;	/* Current file. */
+    struct filestruct *filebot;	/* Current file's last line. */
 #ifndef NANO_SMALL
     struct filestruct *file_mark_beginbuf;
-				/* Current file's beginning marked line */
-    int file_mark_beginx;	/* Current file's beginning marked line's
-				   x-coordinate position */
+				/* Current file's beginning marked
+				 * line. */
+    int file_mark_beginx;	/* Current file's beginning marked
+				 * line's x-coordinate position. */
 #endif
-    int file_current_x;		/* Current file's x-coordinate position */
-    int file_current_y;		/* Current file's y-coordinate position */
+    int file_current_x;		/* Current file's x-coordinate
+				 * position. */
+    int file_current_y;		/* Current file's y-coordinate
+				 * position. */
     int file_flags;		/* Current file's flags: modification
-				   status (and marking status, if
-				   available) */
-    int file_placewewant;	/* Current file's place we want */
-    int file_totlines;		/* Current file's total number of lines */
-    long file_totsize;		/* Current file's total size */
-    int file_lineno;		/* Current file's line number */
+				 * status (and marking status, if
+				 * available). */
+    int file_placewewant;	/* Current file's place we want. */
+    int file_totlines;		/* Current file's total number of
+				 * lines. */
+    long file_totsize;		/* Current file's total size. */
+    int file_lineno;		/* Current file's line number. */
 } openfilestruct;
 #endif
 
 typedef struct shortcut {
-    /* Key values that aren't used should be set to NANO_NO_KEY */
+    /* Key values that aren't used should be set to NANO_NO_KEY. */
     int val;		/* Special sentinel key or control key we want
-			 * bound */
-    int altval;		/* Alt key we want bound */
-    int func_key;	/* Function key we want bound */
-    int misc;		/* Other Alt key we want bound */
+			 * bound. */
+    int metaval;		/* Meta key we want bound. */
+    int func_key;	/* Function key we want bound. */
+    int misc;		/* Other Meta key we want bound. */
     int viewok;		/* Is this function legal in view mode? */
-    int (*func) (void);	/* Function to call when we catch this key */
-    const char *desc;	/* Description, e.g. "Page Up" */
+    int (*func) (void);	/* Function to call when we catch this key. */
+    const char *desc;	/* Description, e.g. "Page Up". */
 #ifndef DISABLE_HELP
-    const char *help;	/* Help file entry text */
+    const char *help;	/* Help file entry text. */
 #endif
     struct shortcut *next;
 } shortcut;
 
 #ifndef NANO_SMALL
 typedef struct toggle {
-   int val;		/* Sequence to toggle the key.  Should only need 1 */
+   int val;		/* Sequence to toggle the key.  Should only need
+			 * one. */
    const char *desc;	/* Description for when toggle is, uh, toggled,
 			   e.g. "Pico Messages"; we'll append Enabled or
-			   Disabled */
-   int flag;		/* What flag actually gets toggled */
+			   Disabled. */
+   int flag;		/* What flag actually gets toggled. */
    struct toggle *next;
 } toggle;
 #endif /* !NANO_SMALL */
@@ -235,8 +245,10 @@ typedef struct historytype {
     char *data;
 } historytype;
 typedef struct historyheadtype {
-    struct historytype *next;	/* keep *next and *prev members together */
-    struct historytype *prev;	/* and in same order as in historytype */
+    struct historytype *next;	/* Keep *next and *prev members
+				 * together. */
+    struct historytype *prev;	/* And in same order as in
+				 * historytype. */
     struct historytype *tail;
     struct historytype *current;
     int count;
@@ -244,8 +256,8 @@ typedef struct historyheadtype {
 } historyheadtype;
 #endif /* !NANO_SMALL */
 
-/* Bitwise flags so we can save space (or more correctly, not waste it) */
-
+/* Bitwise flags so we can save space (or more correctly, not waste
+ * it). */
 #define MODIFIED		(1<<0)
 #define KEEP_CUTBUFFER		(1<<1)
 #define CASE_SENSITIVE		(1<<2)
@@ -267,7 +279,7 @@ typedef struct historyheadtype {
 #define DOS_FILE		(1<<18)
 #define MAC_FILE		(1<<19)
 #define SMOOTHSCROLL		(1<<20)
-#define DISABLE_CURPOS		(1<<21)	/* Damn, we still need it */
+#define DISABLE_CURPOS		(1<<21)	/* Damn, we still need it. */
 #define REBIND_DELETE		(1<<22)
 #define NO_CONVERT		(1<<23)
 #define BACKUP_FILE		(1<<24)
@@ -278,8 +290,7 @@ typedef struct historyheadtype {
 #define HISTORYLOG		(1<<29)
 #define JUSTIFY_MODE		(1<<30)
 
-/* Control key sequences, changing these would be very very bad */
-
+/* Control key sequences, changing these would be very very bad. */
 #define NANO_CONTROL_SPACE 0
 #define NANO_CONTROL_A 1
 #define NANO_CONTROL_B 2
@@ -347,13 +358,13 @@ typedef struct historyheadtype {
 #define NANO_ALT_RBRACKET ']'
 #define NANO_ALT_SPACE ' '
 
-/* Some semi-changeable keybindings; don't play with unless you're sure
-   you know what you're doing */
+/* Some semi-changeable keybindings; don't play with these unless you're
+ * sure you know what you're doing. */
 
 /* No key at all. */
 #define NANO_NO_KEY		-8
 
-/* Special sentinel key. */
+/* Special sentinel key used for search string history. */
 #define NANO_HISTORY_KEY	-9
 
 /* Normal keys. */
@@ -453,18 +464,18 @@ typedef enum {
     TOP, CENTER, NONE
 } topmidnone;
 
-/* Minimum editor window rows required for nano to work correctly */
+/* Minimum editor window rows required for nano to work correctly. */
 #define MIN_EDITOR_ROWS 3
 
-/* Minimum editor window cols required for nano to work correctly */
+/* Minimum editor window cols required for nano to work correctly. */
 #define MIN_EDITOR_COLS 10
 
 /* Default number of characters from end-of-line where text wrapping
-   occurs */
+ * occurs. */
 #define CHARS_FROM_EOL 8
 
 /* Maximum number of search history strings saved, same value used for
-   replace history */
+ * replace history. */
 #define MAX_SEARCH_HISTORY 100
 
 #endif /* !NANO_H */
diff --git a/src/proto.h b/src/proto.h
index 097588a5c0cd84e2d1cad602c0263ec4815f9afb..93accea35b450f0647ed780a0b7f6dc88f99e8ab 100644
--- a/src/proto.h
+++ b/src/proto.h
@@ -140,8 +140,7 @@ void update_color(void);
 /* Public functions in cut.c */
 filestruct *get_cutbottom(void);
 void add_to_cutbuffer(filestruct *inptr);
-void cut_marked_segment(filestruct *top, size_t top_x, filestruct *bot,
-                        size_t bot_x, int destructive);
+void cut_marked_segment(void);
 int do_cut_text(void);
 int do_uncut_text(void);
 
@@ -207,7 +206,7 @@ void sc_init_one(shortcut **shortcutage, int key, const char *desc,
 #ifndef DISABLE_HELP
 	const char *help,
 #endif
-	int alt, int func_key, int misc, int view, int (*func) (void));
+	int meta, int func_key, int misc, int view, int (*func) (void));
 #ifndef NANO_SMALL
 void toggle_init_one(int val, const char *desc, int flag);
 void toggle_init(void);
diff --git a/src/winio.c b/src/winio.c
index 24fec70c4367c5ee35f54d98e378fdc7af17b641..ec60a2fa7f51d8524fe65f275b097fbb56e8521c 100644
--- a/src/winio.c
+++ b/src/winio.c
@@ -1090,12 +1090,12 @@ int nanogetstr(int allowtabs, const char *buf, const char *def,
 		    fprintf(stderr, "Aha! \'%c\' (%d)\n", kbinput,
 			    kbinput);
 #endif
-		    if (meta == 1 && kbinput == t->altval)
-			/* We hit an Alt key.  Do like above.  We don't
-			   just ungetch() the letter and let it get
-			   caught above cause that screws the
-			   keypad... */
-			return t->altval;
+		    if (meta == 1 && (kbinput == t->metaval || kbinput == t->misc))
+			/* We hit a Meta key.  Do like above.  We don't
+			 * just ungetch() the letter and let it get
+			 * caught above cause that screws the
+			 * keypad... */
+			return kbinput;
 		}
 
 	    if (is_cntrl_char(kbinput))
@@ -1223,8 +1223,8 @@ void bottombars(const shortcut *s)
 		    strcpy(keystr, "^?");
 		else
 		    sprintf(keystr, "^%c", s->val + 64);
-	    } else if (s->altval != NANO_NO_KEY)
-		sprintf(keystr, "M-%c", toupper(s->altval));
+	    } else if (s->metaval != NANO_NO_KEY)
+		sprintf(keystr, "M-%c", toupper(s->metaval));
 
 	    onekey(keystr, s->desc, COLS / numcols);