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;
- 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
- 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
#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)
{
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
* 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);
int do_cut_text(void)
{
filestruct *fileptr;
-#ifndef NANO_SMALL
- int dontupdate = 0;
-#endif
assert(current != NULL && current->data != NULL);
#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)
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
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;
#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;
}
/* 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);
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(¤t->data[current_x]) + 1);
strcpy(tmpstr2, newend->data);
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);
current_x = 0;
placewewant = 0;
- /* Extra line added, update stuff */
+ /* Extra line added; update stuff. */
totlines++;
totsize++;
}
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();
#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;
}
}
-/*
- * 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) {
/* 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);
}
cleanup_and_exit:
free(realname);
- free(buf);
+ free(tempname);
return retval;
}
}
#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
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;
}
/* 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;
}
#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;
#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
#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;
#ifndef DISABLE_HELP
s->help = help;
#endif
- s->altval = alt;
+ s->metaval = meta;
s->func_key = func_key;
s->misc = misc;
s->viewok = view;
/* 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) {
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
*(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));
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 {
#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
#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 */
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;
} 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)
#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)
#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
#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. */
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 */
/* 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);
#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);
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))
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);