]> git.wh0rd.org Git - nano.git/commitdiff
add DB's overhaul of the cutting code and related file-writing code, his
authorDavid Lawrence Ramsey <pooka109@gmail.com>
Wed, 24 Dec 2003 08:03:54 +0000 (08:03 +0000)
committerDavid Lawrence Ramsey <pooka109@gmail.com>
Wed, 24 Dec 2003 08:03:54 +0000 (08:03 +0000)
fixes to check_operating_dir(), and a few minor cleanups and fixes of
mine

git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@1600 35c25a1d-7b9e-4130-9fde-d3aeb78583b8

ChangeLog
src/cut.c
src/files.c
src/global.c
src/nano.c
src/nano.h
src/proto.h
src/winio.c

index a9eb0e12174af5c7b22a40925f5a37eff8da1bab..98192dcb74ff3e7057502da1fe54ac41c3878c80 100644 (file)
--- 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
index 61d88bf982e99d5f0b3b81959e5a3fe06a92033f..7652c17f304f4bdaaefdd7cd981b30c4f3389811 100644 (file)
--- a/src/cut.c
+++ b/src/cut.c
 #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();
index 46422a105cfee771864fc581ae56f5f627ca45c3..3fc823327052c20dcb2b77e3a293e9d59b3741ae 100644 (file)
@@ -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
 
index 78da209c3f684581731ab6c0e1bf6276f6c44928..e2c8b11b4e92634c70884e5d07a75f2bf140e462 100644 (file)
@@ -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;
index cce32695386dbf4639ae321855a2a057a20b7c1b..351125ee7c810d3b0dea1df7a763b0bace7b7a4c 100644 (file)
@@ -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 {
index 44c23196a1a052b8783059b9889d56fb576e75c1..41561b824fd6047ec8ed605066859d4dc35a2c91 100644 (file)
 #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 */
 
 #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
 #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
 #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
 
 #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
 #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 */
index 097588a5c0cd84e2d1cad602c0263ec4815f9afb..93accea35b450f0647ed780a0b7f6dc88f99e8ab 100644 (file)
@@ -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);
index 24fec70c4367c5ee35f54d98e378fdc7af17b641..ec60a2fa7f51d8524fe65f275b097fbb56e8521c 100644 (file)
@@ -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);