add DB's overhaul of the cutting code and related file-writing code, his

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
master
David Lawrence Ramsey 2003-12-24 08:03:54 +00:00
parent f427694400
commit 8213850df6
8 changed files with 541 additions and 553 deletions

View File

@ -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

317
src/cut.c
View File

@ -28,15 +28,17 @@
#include "proto.h"
#include "nano.h"
static int marked_cut; /* Is the cutbuffer from a mark? */
static int marked_cut; /* Is the cutbuffer from a mark?
* 0 means whole-line cut, 1 means mark,
* 2 means cut-from-cursor. */
#ifndef NANO_SMALL
static int concatenate_cut; /* Should we add this cut string to the
end of the last one? */
* end of the last one? */
#endif
static filestruct *cutbottom = NULL;
/* Pointer to end of cutbuffer */
/* Pointer to end of cutbuffer. */
filestruct *get_cutbottom(void)
{
@ -46,29 +48,27 @@ filestruct *get_cutbottom(void)
void add_to_cutbuffer(filestruct *inptr)
{
#ifdef DEBUG
fprintf(stderr, "add_to_cutbuffer() called with inptr->data = %s\n",
inptr->data);
fprintf(stderr, "add_to_cutbuffer(): inptr->data = %s\n", inptr->data);
#endif
if (cutbuffer == NULL) {
if (cutbuffer == NULL)
cutbuffer = inptr;
inptr->prev = NULL;
#ifndef NANO_SMALL
} else if (concatenate_cut && !ISSET(JUSTIFY_MODE)) {
else if (concatenate_cut && !ISSET(JUSTIFY_MODE)) {
/* Just tack the text in inptr onto the text in cutbottom,
unless we're backing up lines while justifying text. */
* unless we're backing up lines while justifying text. */
cutbottom->data = charealloc(cutbottom->data,
strlen(cutbottom->data) + strlen(inptr->data) + 1);
strcat(cutbottom->data, inptr->data);
return;
}
#endif
} else {
else {
cutbottom->next = inptr;
inptr->prev = cutbottom;
}
inptr->next = NULL;
cutbottom = inptr;
cutbottom->next = NULL;
}
#ifndef NANO_SMALL
@ -78,112 +78,115 @@ void add_to_cutbuffer(filestruct *inptr)
* last cut line has length bot_x. That is, if bot_x > 0 then we cut to
* bot->data[bot_x - 1].
*
* destructive is whether to actually modify the file structure, if not
* then just copy the buffer into cutbuffer and don't pull it from the
* file.
* We maintain totsize, totlines, filebot, the magicline, and line
* numbers. Also, we set current and current_x so the cursor will be on
* the first character after what was cut. We do not do any screen
* updates.
*
* If destructive, then we maintain totsize, totlines, filebot, the
* magic line, and line numbers. Also, we set current and current_x so
* the cursor will be on the first character after what was cut. We do
* not do any screen updates. */
void cut_marked_segment(filestruct *top, size_t top_x, filestruct *bot,
size_t bot_x, int destructive)
* Note cutbuffer might not be NULL if "cut to end" is used. */
void cut_marked_segment(void)
{
filestruct *tmp, *next;
filestruct *top;
filestruct *bot;
filestruct *tmp;
size_t top_x;
size_t bot_x;
size_t newsize;
if (top == bot && top_x == bot_x)
/* If the mark doesn't cover any text, get out. */
if (current == mark_beginbuf && current_x == mark_beginx)
return;
assert(top != NULL && bot != NULL);
assert(current != NULL && mark_beginbuf != NULL);
/* Make top be no later than bot. */
if (top->lineno > bot->lineno) {
filestruct *swap = top;
int swap2 = top_x;
/* 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 = bot;
bot = swap;
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;
/* 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);
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. */
tmp = copy_node(bot);
null_at(&tmp->data, bot_x);
add_to_cutbuffer(tmp);
#ifdef DEBUG
dump_buffer(cutbuffer);
#endif
null_at(&bot->data, bot_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();
}
/* 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();

View 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,410 +1272,376 @@ 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)) {
FILE *backup_file;
char *backupname = NULL;
char backupbuf[COPYFILEBLOCKSIZE];
size_t bytesread;
struct utimbuf filetime;
* 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)) {
/* save the original file's access and modification times */
FILE *backup_file;
char *backupname;
struct utimbuf filetime;
int copy_status;
/* 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
#endif /* !NANO_SMALL */
/* Stat the link itself for the check... */
anyexists = lstat(realname, &lst);
/* 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);
/* If we're prepending, open the temp file, and append it to f. */
if (append == 2) {
int fd_source;
FILE *f_source = NULL;
/* 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++;
}
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);
}
if (f_source == NULL) {
statusbar(_("Error reading %s: %s"), tempname, strerror(errno));
fclose(f);
goto cleanup_and_exit;
}
}
if (fclose(f) != 0) {
statusbar(_("Could not close %s: %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 we're prepending, open the real file, and append it here */
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;
}
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);
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);
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) {
filename = mallocstrcpy(filename, realname);
@ -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. */
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. */
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();
/* 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

View 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;

View 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 {

View File

@ -46,13 +46,14 @@
#endif
#ifdef USE_SLANG
/* Slang support enabled */
/* Slang support enabled. Work around Slang's not defining KEY_DC or
* KEY_IC. */
#include <slcurses.h>
#define KEY_DC SL_KEY_DELETE
#define KEY_IC SL_KEY_IC
#elif defined(HAVE_NCURSES_H)
#include <ncurses.h>
#else /* Uh oh */
#else /* Uh oh. */
#include <curses.h>
#endif /* CURSES_H */
@ -71,16 +72,18 @@
#include <sys/stat.h>
#include "config.h"
/* If no snprintf()/vsnprintf(), use the versions from glib. */
#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
#include <glib.h>
# ifndef HAVE_SNPRINTF
# define snprintf g_snprintf
# define snprintf g_snprintf
# endif
# ifndef HAVE_VSNPRINTF
# define vsnprintf g_vsnprintf
# define vsnprintf g_vsnprintf
# endif
#endif
/* If no strcasecmp()/strncasecmp(), use the versions we have. */
#ifndef HAVE_STRCASECMP
#define strcasecmp nstricmp
#endif
@ -90,11 +93,11 @@
#endif
/* Assume ERR is defined as -1. To avoid duplicate case values when
some key definitions are missing, we have to set all of these, and
all of the special sentinel values below, to different negative
values other than -1. */
* some key definitions are missing, we have to set all of these, and
* all of the special sentinel values below, to different negative
* values other than -1. */
/* HP-UX 10 & 11 do not seem to support KEY_HOME and KEY_END */
/* HP-UX 10 & 11 do not seem to support KEY_HOME and KEY_END. */
#ifndef KEY_HOME
#define KEY_HOME -2
#endif
@ -103,13 +106,13 @@
#define KEY_END -3
#endif
/* Slang and SunOS 5.7-5.9 do not seem to support KEY_RESIZE */
/* Slang and SunOS 5.7-5.9 do not seem to support KEY_RESIZE. */
#ifndef KEY_RESIZE
#define KEY_RESIZE -4
#endif
/* Slang does not seem to support KEY_SUSPEND, KEY_SLEFT, or
KEY_SRIGHT */
* KEY_SRIGHT. */
#ifndef KEY_SUSPEND
#define KEY_SUSPEND -5
#endif
@ -124,6 +127,8 @@
#define VERMSG "GNU nano " VERSION
/* If we aren't using ncurses, turn the mouse support off, as it's
* ncurses-specific. */
#ifndef NCURSES_MOUSE_VERSION
#define DISABLE_MOUSE 1
#endif
@ -132,12 +137,12 @@
#define DISABLE_WRAPJUSTIFY 1
#endif
/* Structure types */
/* Structure types. */
typedef struct filestruct {
char *data;
struct filestruct *next; /* Next node */
struct filestruct *prev; /* Previous node */
int lineno; /* The line number */
struct filestruct *next; /* Next node. */
struct filestruct *prev; /* Previous node. */
int lineno; /* The line number. */
} filestruct;
#ifdef ENABLE_MULTIBUFFER
@ -146,51 +151,56 @@ typedef struct openfilestruct {
#ifndef NANO_SMALL
struct stat originalfilestat;
#endif
struct openfilestruct *next; /* Next node */
struct openfilestruct *prev; /* Previous node */
struct filestruct *fileage; /* Current file */
struct filestruct *filebot; /* Current file's last line */
struct openfilestruct *next; /* Next node. */
struct openfilestruct *prev; /* Previous node. */
struct filestruct *fileage; /* Current file. */
struct filestruct *filebot; /* Current file's last line. */
#ifndef NANO_SMALL
struct filestruct *file_mark_beginbuf;
/* Current file's beginning marked line */
int file_mark_beginx; /* Current file's beginning marked line's
x-coordinate position */
/* Current file's beginning marked
* line. */
int file_mark_beginx; /* Current file's beginning marked
* line's x-coordinate position. */
#endif
int file_current_x; /* Current file's x-coordinate position */
int file_current_y; /* Current file's y-coordinate position */
int file_current_x; /* Current file's x-coordinate
* position. */
int file_current_y; /* Current file's y-coordinate
* position. */
int file_flags; /* Current file's flags: modification
status (and marking status, if
available) */
int file_placewewant; /* Current file's place we want */
int file_totlines; /* Current file's total number of lines */
long file_totsize; /* Current file's total size */
int file_lineno; /* Current file's line number */
* status (and marking status, if
* available). */
int file_placewewant; /* Current file's place we want. */
int file_totlines; /* Current file's total number of
* lines. */
long file_totsize; /* Current file's total size. */
int file_lineno; /* Current file's line number. */
} openfilestruct;
#endif
typedef struct shortcut {
/* Key values that aren't used should be set to NANO_NO_KEY */
/* Key values that aren't used should be set to NANO_NO_KEY. */
int val; /* Special sentinel key or control key we want
* bound */
int altval; /* Alt key we want bound */
int func_key; /* Function key we want bound */
int misc; /* Other Alt key we want bound */
* bound. */
int metaval; /* Meta key we want bound. */
int func_key; /* Function key we want bound. */
int misc; /* Other Meta key we want bound. */
int viewok; /* Is this function legal in view mode? */
int (*func) (void); /* Function to call when we catch this key */
const char *desc; /* Description, e.g. "Page Up" */
int (*func) (void); /* Function to call when we catch this key. */
const char *desc; /* Description, e.g. "Page Up". */
#ifndef DISABLE_HELP
const char *help; /* Help file entry text */
const char *help; /* Help file entry text. */
#endif
struct shortcut *next;
} shortcut;
#ifndef NANO_SMALL
typedef struct toggle {
int val; /* Sequence to toggle the key. Should only need 1 */
int val; /* Sequence to toggle the key. Should only need
* one. */
const char *desc; /* Description for when toggle is, uh, toggled,
e.g. "Pico Messages"; we'll append Enabled or
Disabled */
int flag; /* What flag actually gets toggled */
Disabled. */
int flag; /* What flag actually gets toggled. */
struct toggle *next;
} toggle;
#endif /* !NANO_SMALL */
@ -235,8 +245,10 @@ typedef struct historytype {
char *data;
} historytype;
typedef struct historyheadtype {
struct historytype *next; /* keep *next and *prev members together */
struct historytype *prev; /* and in same order as in historytype */
struct historytype *next; /* Keep *next and *prev members
* together. */
struct historytype *prev; /* And in same order as in
* historytype. */
struct historytype *tail;
struct historytype *current;
int count;
@ -244,8 +256,8 @@ typedef struct historyheadtype {
} historyheadtype;
#endif /* !NANO_SMALL */
/* Bitwise flags so we can save space (or more correctly, not waste it) */
/* Bitwise flags so we can save space (or more correctly, not waste
* it). */
#define MODIFIED (1<<0)
#define KEEP_CUTBUFFER (1<<1)
#define CASE_SENSITIVE (1<<2)
@ -267,7 +279,7 @@ typedef struct historyheadtype {
#define DOS_FILE (1<<18)
#define MAC_FILE (1<<19)
#define SMOOTHSCROLL (1<<20)
#define DISABLE_CURPOS (1<<21) /* Damn, we still need it */
#define DISABLE_CURPOS (1<<21) /* Damn, we still need it. */
#define REBIND_DELETE (1<<22)
#define NO_CONVERT (1<<23)
#define BACKUP_FILE (1<<24)
@ -278,8 +290,7 @@ typedef struct historyheadtype {
#define HISTORYLOG (1<<29)
#define JUSTIFY_MODE (1<<30)
/* Control key sequences, changing these would be very very bad */
/* Control key sequences, changing these would be very very bad. */
#define NANO_CONTROL_SPACE 0
#define NANO_CONTROL_A 1
#define NANO_CONTROL_B 2
@ -347,13 +358,13 @@ typedef struct historyheadtype {
#define NANO_ALT_RBRACKET ']'
#define NANO_ALT_SPACE ' '
/* Some semi-changeable keybindings; don't play with unless you're sure
you know what you're doing */
/* Some semi-changeable keybindings; don't play with these unless you're
* sure you know what you're doing. */
/* No key at all. */
#define NANO_NO_KEY -8
/* Special sentinel key. */
/* Special sentinel key used for search string history. */
#define NANO_HISTORY_KEY -9
/* Normal keys. */
@ -453,18 +464,18 @@ typedef enum {
TOP, CENTER, NONE
} topmidnone;
/* Minimum editor window rows required for nano to work correctly */
/* Minimum editor window rows required for nano to work correctly. */
#define MIN_EDITOR_ROWS 3
/* Minimum editor window cols required for nano to work correctly */
/* Minimum editor window cols required for nano to work correctly. */
#define MIN_EDITOR_COLS 10
/* Default number of characters from end-of-line where text wrapping
occurs */
* occurs. */
#define CHARS_FROM_EOL 8
/* Maximum number of search history strings saved, same value used for
replace history */
* replace history. */
#define MAX_SEARCH_HISTORY 100
#endif /* !NANO_H */

View 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);

View 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);