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
Этот коммит содержится в:
родитель
f427694400
Коммит
8213850df6
22
ChangeLog
22
ChangeLog
@ -29,13 +29,26 @@ CVS code -
|
||||
shortcut display routines to handle them. Also modify the
|
||||
shortcut list code to not treat non-control character values
|
||||
of val as Meta-sequences, and fix dependencies on that
|
||||
behavior. (DLR)
|
||||
behavior. Also rename several variables: "alt" -> "meta",
|
||||
"altval" -> "metaval". (DLR)
|
||||
- Hook up the verbatim input functions so that verbatim input
|
||||
can be used in the edit window. New function
|
||||
do_verbatim_input(); changes to do_char(). (DLR) Additional
|
||||
minor tweaks to do_char() by David Benbennick.
|
||||
- Clarify the description of the --rebinddelete option. (DLR)
|
||||
- cut.c:
|
||||
- Overhaul to increase efficiency and add various cleanups.
|
||||
Changes to add_to_cutbuffer(), cut_marked_segment(), and
|
||||
do_uncut_text(). (David Benbennick)
|
||||
- files.c:
|
||||
check_operating_dir()
|
||||
- Add an assert to ensure that full_operatingdir isn't NULL,
|
||||
a fix for reporting nonexistent (incomplete) directory names
|
||||
as being outside the operating directory when tab completion
|
||||
is being used, and cosmetic cleanups. (David Benbennick)
|
||||
copy_file()
|
||||
- New function containing part of the functionality formerly in
|
||||
do_writeout. (David Benbennick)
|
||||
do_writeout()
|
||||
- Prompt the user if we're trying to save an existing file (and
|
||||
not just a selection of it) under a different name. (DLR;
|
||||
@ -56,6 +69,10 @@ CVS code -
|
||||
- Convert to use the new low-level input functions. (DLR)
|
||||
main()
|
||||
- Remove unused variable option_index. (DLR)
|
||||
- Fix omission of NANO_NO_KEY in the shortcut list scanning
|
||||
code. (DLR)
|
||||
- nano.h:
|
||||
- Comment additions and cosmetic tweaks. (DLR)
|
||||
- search.c:
|
||||
findnextstr(), do_replace_loop()
|
||||
- Fix potential infinite loops and other misbehavior when doing
|
||||
@ -95,6 +112,9 @@ CVS code -
|
||||
- Modify to take an extra parameter indicating if we should
|
||||
ungetch() the key equivalents of shortcuts we click on or not.
|
||||
(DLR)
|
||||
nanogetstr()
|
||||
- Properly interpret the Meta key value in misc if we hit it at
|
||||
the statusbar prompt. (DLR)
|
||||
do_yesno()
|
||||
- Add a few efficiency/extensibility tweaks. (David Benbennick)
|
||||
- Convert to use the new low-level input functions, and remove
|
||||
|
317
src/cut.c
317
src/cut.c
@ -28,15 +28,17 @@
|
||||
#include "proto.h"
|
||||
#include "nano.h"
|
||||
|
||||
static int marked_cut; /* Is the cutbuffer from a mark? */
|
||||
static int marked_cut; /* Is the cutbuffer from a mark?
|
||||
* 0 means whole-line cut, 1 means mark,
|
||||
* 2 means cut-from-cursor. */
|
||||
|
||||
#ifndef NANO_SMALL
|
||||
static int concatenate_cut; /* Should we add this cut string to the
|
||||
end of the last one? */
|
||||
* end of the last one? */
|
||||
#endif
|
||||
|
||||
static filestruct *cutbottom = NULL;
|
||||
/* Pointer to end of cutbuffer */
|
||||
/* Pointer to end of cutbuffer. */
|
||||
|
||||
filestruct *get_cutbottom(void)
|
||||
{
|
||||
@ -46,29 +48,27 @@ filestruct *get_cutbottom(void)
|
||||
void add_to_cutbuffer(filestruct *inptr)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "add_to_cutbuffer() called with inptr->data = %s\n",
|
||||
inptr->data);
|
||||
fprintf(stderr, "add_to_cutbuffer(): inptr->data = %s\n", inptr->data);
|
||||
#endif
|
||||
|
||||
if (cutbuffer == NULL) {
|
||||
if (cutbuffer == NULL)
|
||||
cutbuffer = inptr;
|
||||
inptr->prev = NULL;
|
||||
#ifndef NANO_SMALL
|
||||
} else if (concatenate_cut && !ISSET(JUSTIFY_MODE)) {
|
||||
else if (concatenate_cut && !ISSET(JUSTIFY_MODE)) {
|
||||
/* Just tack the text in inptr onto the text in cutbottom,
|
||||
unless we're backing up lines while justifying text. */
|
||||
* unless we're backing up lines while justifying text. */
|
||||
cutbottom->data = charealloc(cutbottom->data,
|
||||
strlen(cutbottom->data) + strlen(inptr->data) + 1);
|
||||
strcat(cutbottom->data, inptr->data);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
else {
|
||||
cutbottom->next = inptr;
|
||||
inptr->prev = cutbottom;
|
||||
}
|
||||
|
||||
inptr->next = NULL;
|
||||
cutbottom = inptr;
|
||||
cutbottom->next = NULL;
|
||||
}
|
||||
|
||||
#ifndef NANO_SMALL
|
||||
@ -78,112 +78,115 @@ void add_to_cutbuffer(filestruct *inptr)
|
||||
* last cut line has length bot_x. That is, if bot_x > 0 then we cut to
|
||||
* bot->data[bot_x - 1].
|
||||
*
|
||||
* destructive is whether to actually modify the file structure, if not
|
||||
* then just copy the buffer into cutbuffer and don't pull it from the
|
||||
* file.
|
||||
* We maintain totsize, totlines, filebot, the magicline, and line
|
||||
* numbers. Also, we set current and current_x so the cursor will be on
|
||||
* the first character after what was cut. We do not do any screen
|
||||
* updates.
|
||||
*
|
||||
* If destructive, then we maintain totsize, totlines, filebot, the
|
||||
* magic line, and line numbers. Also, we set current and current_x so
|
||||
* the cursor will be on the first character after what was cut. We do
|
||||
* not do any screen updates. */
|
||||
void cut_marked_segment(filestruct *top, size_t top_x, filestruct *bot,
|
||||
size_t bot_x, int destructive)
|
||||
* Note cutbuffer might not be NULL if "cut to end" is used. */
|
||||
void cut_marked_segment(void)
|
||||
{
|
||||
filestruct *tmp, *next;
|
||||
filestruct *top;
|
||||
filestruct *bot;
|
||||
filestruct *tmp;
|
||||
size_t top_x;
|
||||
size_t bot_x;
|
||||
size_t newsize;
|
||||
|
||||
if (top == bot && top_x == bot_x)
|
||||
/* If the mark doesn't cover any text, get out. */
|
||||
if (current == mark_beginbuf && current_x == mark_beginx)
|
||||
return;
|
||||
assert(top != NULL && bot != NULL);
|
||||
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(¤t->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();
|
||||
|
593
src/files.c
593
src/files.c
@ -522,7 +522,7 @@ int do_insertfile(int loading_file)
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_OPERATINGDIR
|
||||
if (i != NANO_EXTCMD_KEY && check_operating_dir(answer, FALSE)) {
|
||||
if (i != NANO_EXTCMD_KEY && check_operating_dir(answer, 0) != 0) {
|
||||
statusbar(_("Can't insert file from outside of %s"),
|
||||
operating_dir);
|
||||
return 0;
|
||||
@ -1272,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
|
||||
|
||||
|
@ -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;
|
||||
|
18
src/nano.c
18
src/nano.c
@ -403,7 +403,7 @@ void help_init(void)
|
||||
|
||||
/* Now add our shortcut info */
|
||||
for (s = currshortcut; s != NULL; s = s->next) {
|
||||
/* true if the character in s->altval is shown in first column */
|
||||
/* true if the character in s->metaval is shown in first column */
|
||||
int meta_shortcut = 0;
|
||||
|
||||
if (s->val != NANO_NO_KEY) {
|
||||
@ -420,12 +420,12 @@ void help_init(void)
|
||||
ptr += sprintf(ptr, "^%c", s->val + 64);
|
||||
}
|
||||
#ifndef NANO_SMALL
|
||||
else if (s->altval != NANO_NO_KEY) {
|
||||
else if (s->metaval != NANO_NO_KEY) {
|
||||
meta_shortcut = 1;
|
||||
if (s->altval == NANO_ALT_SPACE)
|
||||
if (s->metaval == NANO_ALT_SPACE)
|
||||
ptr += snprintf(ptr, 8, "M-%.5s", _("Space"));
|
||||
else
|
||||
ptr += sprintf(ptr, "M-%c", toupper(s->altval));
|
||||
ptr += sprintf(ptr, "M-%c", toupper(s->metaval));
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -436,8 +436,8 @@ void help_init(void)
|
||||
|
||||
*(ptr++) = '\t';
|
||||
|
||||
if (!meta_shortcut && s->altval != NANO_NO_KEY)
|
||||
ptr += sprintf(ptr, "(M-%c)", toupper(s->altval));
|
||||
if (!meta_shortcut && s->metaval != NANO_NO_KEY)
|
||||
ptr += sprintf(ptr, "(M-%c)", toupper(s->metaval));
|
||||
else if (meta_shortcut && s->misc != NANO_NO_KEY)
|
||||
ptr += sprintf(ptr, "(M-%c)", toupper(s->misc));
|
||||
|
||||
@ -3516,10 +3516,10 @@ int main(int argc, char *argv[])
|
||||
fprintf(stderr, "AHA! %c (%d)\n", kbinput, kbinput);
|
||||
#endif
|
||||
if (meta == 1) {
|
||||
/* Check for the altkey and misc defs... */
|
||||
/* Check for the metaval and misc defs... */
|
||||
for (s = main_list; s != NULL; s = s->next)
|
||||
if ((s->altval > 0 && kbinput == s->altval) ||
|
||||
(s->misc > 0 && kbinput == s->misc)) {
|
||||
if ((s->metaval != NANO_NO_KEY && kbinput == s->metaval) ||
|
||||
(s->misc != NANO_NO_KEY && kbinput == s->misc)) {
|
||||
if (ISSET(VIEW_MODE) && !s->viewok)
|
||||
print_view_warning();
|
||||
else {
|
||||
|
119
src/nano.h
119
src/nano.h
@ -46,13 +46,14 @@
|
||||
#endif
|
||||
|
||||
#ifdef USE_SLANG
|
||||
/* Slang support enabled */
|
||||
/* Slang support enabled. Work around Slang's not defining KEY_DC or
|
||||
* KEY_IC. */
|
||||
#include <slcurses.h>
|
||||
#define KEY_DC SL_KEY_DELETE
|
||||
#define KEY_IC SL_KEY_IC
|
||||
#elif defined(HAVE_NCURSES_H)
|
||||
#include <ncurses.h>
|
||||
#else /* Uh oh */
|
||||
#else /* Uh oh. */
|
||||
#include <curses.h>
|
||||
#endif /* CURSES_H */
|
||||
|
||||
@ -71,16 +72,18 @@
|
||||
#include <sys/stat.h>
|
||||
#include "config.h"
|
||||
|
||||
/* If no snprintf()/vsnprintf(), use the versions from glib. */
|
||||
#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
|
||||
#include <glib.h>
|
||||
# ifndef HAVE_SNPRINTF
|
||||
# define snprintf g_snprintf
|
||||
# define snprintf g_snprintf
|
||||
# endif
|
||||
# ifndef HAVE_VSNPRINTF
|
||||
# define vsnprintf g_vsnprintf
|
||||
# define vsnprintf g_vsnprintf
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* If no strcasecmp()/strncasecmp(), use the versions we have. */
|
||||
#ifndef HAVE_STRCASECMP
|
||||
#define strcasecmp nstricmp
|
||||
#endif
|
||||
@ -90,11 +93,11 @@
|
||||
#endif
|
||||
|
||||
/* Assume ERR is defined as -1. To avoid duplicate case values when
|
||||
some key definitions are missing, we have to set all of these, and
|
||||
all of the special sentinel values below, to different negative
|
||||
values other than -1. */
|
||||
* some key definitions are missing, we have to set all of these, and
|
||||
* all of the special sentinel values below, to different negative
|
||||
* values other than -1. */
|
||||
|
||||
/* HP-UX 10 & 11 do not seem to support KEY_HOME and KEY_END */
|
||||
/* HP-UX 10 & 11 do not seem to support KEY_HOME and KEY_END. */
|
||||
#ifndef KEY_HOME
|
||||
#define KEY_HOME -2
|
||||
#endif
|
||||
@ -103,13 +106,13 @@
|
||||
#define KEY_END -3
|
||||
#endif
|
||||
|
||||
/* Slang and SunOS 5.7-5.9 do not seem to support KEY_RESIZE */
|
||||
/* Slang and SunOS 5.7-5.9 do not seem to support KEY_RESIZE. */
|
||||
#ifndef KEY_RESIZE
|
||||
#define KEY_RESIZE -4
|
||||
#endif
|
||||
|
||||
/* Slang does not seem to support KEY_SUSPEND, KEY_SLEFT, or
|
||||
KEY_SRIGHT */
|
||||
* KEY_SRIGHT. */
|
||||
#ifndef KEY_SUSPEND
|
||||
#define KEY_SUSPEND -5
|
||||
#endif
|
||||
@ -124,6 +127,8 @@
|
||||
|
||||
#define VERMSG "GNU nano " VERSION
|
||||
|
||||
/* If we aren't using ncurses, turn the mouse support off, as it's
|
||||
* ncurses-specific. */
|
||||
#ifndef NCURSES_MOUSE_VERSION
|
||||
#define DISABLE_MOUSE 1
|
||||
#endif
|
||||
@ -132,12 +137,12 @@
|
||||
#define DISABLE_WRAPJUSTIFY 1
|
||||
#endif
|
||||
|
||||
/* Structure types */
|
||||
/* Structure types. */
|
||||
typedef struct filestruct {
|
||||
char *data;
|
||||
struct filestruct *next; /* Next node */
|
||||
struct filestruct *prev; /* Previous node */
|
||||
int lineno; /* The line number */
|
||||
struct filestruct *next; /* Next node. */
|
||||
struct filestruct *prev; /* Previous node. */
|
||||
int lineno; /* The line number. */
|
||||
} filestruct;
|
||||
|
||||
#ifdef ENABLE_MULTIBUFFER
|
||||
@ -146,51 +151,56 @@ typedef struct openfilestruct {
|
||||
#ifndef NANO_SMALL
|
||||
struct stat originalfilestat;
|
||||
#endif
|
||||
struct openfilestruct *next; /* Next node */
|
||||
struct openfilestruct *prev; /* Previous node */
|
||||
struct filestruct *fileage; /* Current file */
|
||||
struct filestruct *filebot; /* Current file's last line */
|
||||
struct openfilestruct *next; /* Next node. */
|
||||
struct openfilestruct *prev; /* Previous node. */
|
||||
struct filestruct *fileage; /* Current file. */
|
||||
struct filestruct *filebot; /* Current file's last line. */
|
||||
#ifndef NANO_SMALL
|
||||
struct filestruct *file_mark_beginbuf;
|
||||
/* Current file's beginning marked line */
|
||||
int file_mark_beginx; /* Current file's beginning marked line's
|
||||
x-coordinate position */
|
||||
/* Current file's beginning marked
|
||||
* line. */
|
||||
int file_mark_beginx; /* Current file's beginning marked
|
||||
* line's x-coordinate position. */
|
||||
#endif
|
||||
int file_current_x; /* Current file's x-coordinate position */
|
||||
int file_current_y; /* Current file's y-coordinate position */
|
||||
int file_current_x; /* Current file's x-coordinate
|
||||
* position. */
|
||||
int file_current_y; /* Current file's y-coordinate
|
||||
* position. */
|
||||
int file_flags; /* Current file's flags: modification
|
||||
status (and marking status, if
|
||||
available) */
|
||||
int file_placewewant; /* Current file's place we want */
|
||||
int file_totlines; /* Current file's total number of lines */
|
||||
long file_totsize; /* Current file's total size */
|
||||
int file_lineno; /* Current file's line number */
|
||||
* status (and marking status, if
|
||||
* available). */
|
||||
int file_placewewant; /* Current file's place we want. */
|
||||
int file_totlines; /* Current file's total number of
|
||||
* lines. */
|
||||
long file_totsize; /* Current file's total size. */
|
||||
int file_lineno; /* Current file's line number. */
|
||||
} openfilestruct;
|
||||
#endif
|
||||
|
||||
typedef struct shortcut {
|
||||
/* Key values that aren't used should be set to NANO_NO_KEY */
|
||||
/* Key values that aren't used should be set to NANO_NO_KEY. */
|
||||
int val; /* Special sentinel key or control key we want
|
||||
* bound */
|
||||
int altval; /* Alt key we want bound */
|
||||
int func_key; /* Function key we want bound */
|
||||
int misc; /* Other Alt key we want bound */
|
||||
* bound. */
|
||||
int metaval; /* Meta key we want bound. */
|
||||
int func_key; /* Function key we want bound. */
|
||||
int misc; /* Other Meta key we want bound. */
|
||||
int viewok; /* Is this function legal in view mode? */
|
||||
int (*func) (void); /* Function to call when we catch this key */
|
||||
const char *desc; /* Description, e.g. "Page Up" */
|
||||
int (*func) (void); /* Function to call when we catch this key. */
|
||||
const char *desc; /* Description, e.g. "Page Up". */
|
||||
#ifndef DISABLE_HELP
|
||||
const char *help; /* Help file entry text */
|
||||
const char *help; /* Help file entry text. */
|
||||
#endif
|
||||
struct shortcut *next;
|
||||
} shortcut;
|
||||
|
||||
#ifndef NANO_SMALL
|
||||
typedef struct toggle {
|
||||
int val; /* Sequence to toggle the key. Should only need 1 */
|
||||
int val; /* Sequence to toggle the key. Should only need
|
||||
* one. */
|
||||
const char *desc; /* Description for when toggle is, uh, toggled,
|
||||
e.g. "Pico Messages"; we'll append Enabled or
|
||||
Disabled */
|
||||
int flag; /* What flag actually gets toggled */
|
||||
Disabled. */
|
||||
int flag; /* What flag actually gets toggled. */
|
||||
struct toggle *next;
|
||||
} toggle;
|
||||
#endif /* !NANO_SMALL */
|
||||
@ -235,8 +245,10 @@ typedef struct historytype {
|
||||
char *data;
|
||||
} historytype;
|
||||
typedef struct historyheadtype {
|
||||
struct historytype *next; /* keep *next and *prev members together */
|
||||
struct historytype *prev; /* and in same order as in historytype */
|
||||
struct historytype *next; /* Keep *next and *prev members
|
||||
* together. */
|
||||
struct historytype *prev; /* And in same order as in
|
||||
* historytype. */
|
||||
struct historytype *tail;
|
||||
struct historytype *current;
|
||||
int count;
|
||||
@ -244,8 +256,8 @@ typedef struct historyheadtype {
|
||||
} historyheadtype;
|
||||
#endif /* !NANO_SMALL */
|
||||
|
||||
/* Bitwise flags so we can save space (or more correctly, not waste it) */
|
||||
|
||||
/* Bitwise flags so we can save space (or more correctly, not waste
|
||||
* it). */
|
||||
#define MODIFIED (1<<0)
|
||||
#define KEEP_CUTBUFFER (1<<1)
|
||||
#define CASE_SENSITIVE (1<<2)
|
||||
@ -267,7 +279,7 @@ typedef struct historyheadtype {
|
||||
#define DOS_FILE (1<<18)
|
||||
#define MAC_FILE (1<<19)
|
||||
#define SMOOTHSCROLL (1<<20)
|
||||
#define DISABLE_CURPOS (1<<21) /* Damn, we still need it */
|
||||
#define DISABLE_CURPOS (1<<21) /* Damn, we still need it. */
|
||||
#define REBIND_DELETE (1<<22)
|
||||
#define NO_CONVERT (1<<23)
|
||||
#define BACKUP_FILE (1<<24)
|
||||
@ -278,8 +290,7 @@ typedef struct historyheadtype {
|
||||
#define HISTORYLOG (1<<29)
|
||||
#define JUSTIFY_MODE (1<<30)
|
||||
|
||||
/* Control key sequences, changing these would be very very bad */
|
||||
|
||||
/* Control key sequences, changing these would be very very bad. */
|
||||
#define NANO_CONTROL_SPACE 0
|
||||
#define NANO_CONTROL_A 1
|
||||
#define NANO_CONTROL_B 2
|
||||
@ -347,13 +358,13 @@ typedef struct historyheadtype {
|
||||
#define NANO_ALT_RBRACKET ']'
|
||||
#define NANO_ALT_SPACE ' '
|
||||
|
||||
/* Some semi-changeable keybindings; don't play with unless you're sure
|
||||
you know what you're doing */
|
||||
/* Some semi-changeable keybindings; don't play with these unless you're
|
||||
* sure you know what you're doing. */
|
||||
|
||||
/* No key at all. */
|
||||
#define NANO_NO_KEY -8
|
||||
|
||||
/* Special sentinel key. */
|
||||
/* Special sentinel key used for search string history. */
|
||||
#define NANO_HISTORY_KEY -9
|
||||
|
||||
/* Normal keys. */
|
||||
@ -453,18 +464,18 @@ typedef enum {
|
||||
TOP, CENTER, NONE
|
||||
} topmidnone;
|
||||
|
||||
/* Minimum editor window rows required for nano to work correctly */
|
||||
/* Minimum editor window rows required for nano to work correctly. */
|
||||
#define MIN_EDITOR_ROWS 3
|
||||
|
||||
/* Minimum editor window cols required for nano to work correctly */
|
||||
/* Minimum editor window cols required for nano to work correctly. */
|
||||
#define MIN_EDITOR_COLS 10
|
||||
|
||||
/* Default number of characters from end-of-line where text wrapping
|
||||
occurs */
|
||||
* occurs. */
|
||||
#define CHARS_FROM_EOL 8
|
||||
|
||||
/* Maximum number of search history strings saved, same value used for
|
||||
replace history */
|
||||
* replace history. */
|
||||
#define MAX_SEARCH_HISTORY 100
|
||||
|
||||
#endif /* !NANO_H */
|
||||
|
@ -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);
|
||||
|
16
src/winio.c
16
src/winio.c
@ -1090,12 +1090,12 @@ int nanogetstr(int allowtabs, const char *buf, const char *def,
|
||||
fprintf(stderr, "Aha! \'%c\' (%d)\n", kbinput,
|
||||
kbinput);
|
||||
#endif
|
||||
if (meta == 1 && kbinput == t->altval)
|
||||
/* We hit an Alt key. Do like above. We don't
|
||||
just ungetch() the letter and let it get
|
||||
caught above cause that screws the
|
||||
keypad... */
|
||||
return t->altval;
|
||||
if (meta == 1 && (kbinput == t->metaval || kbinput == t->misc))
|
||||
/* We hit a Meta key. Do like above. We don't
|
||||
* just ungetch() the letter and let it get
|
||||
* caught above cause that screws the
|
||||
* keypad... */
|
||||
return kbinput;
|
||||
}
|
||||
|
||||
if (is_cntrl_char(kbinput))
|
||||
@ -1223,8 +1223,8 @@ void bottombars(const shortcut *s)
|
||||
strcpy(keystr, "^?");
|
||||
else
|
||||
sprintf(keystr, "^%c", s->val + 64);
|
||||
} else if (s->altval != NANO_NO_KEY)
|
||||
sprintf(keystr, "M-%c", toupper(s->altval));
|
||||
} else if (s->metaval != NANO_NO_KEY)
|
||||
sprintf(keystr, "M-%c", toupper(s->metaval));
|
||||
|
||||
onekey(keystr, s->desc, COLS / numcols);
|
||||
|
||||
|
Загрузка…
x
Ссылка в новой задаче
Block a user