tweaks: convert the indentation to use only tabs

Each leading tab is converted to two tabs, and any leading four spaces
is converted to one tab.  The intended tab size (for keeping most lines
within 80 columns) is now four.
master
Benno Schulenberg 2017-12-29 19:27:33 +01:00
parent b574f73e60
commit 87206c0607
19 changed files with 15755 additions and 15755 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -33,7 +33,7 @@
/* For early versions of ncurses-6.0, use an additional A_PROTECT attribute
* for all colors, in order to work around an ncurses miscoloring bug. */
#if defined(NCURSES_VERSION_MAJOR) && (NCURSES_VERSION_MAJOR == 6) && \
(NCURSES_VERSION_MINOR == 0) && (NCURSES_VERSION_PATCH < 20151017)
(NCURSES_VERSION_MINOR == 0) && (NCURSES_VERSION_PATCH < 20151017)
#define A_BANDAID A_PROTECT
#else
#define A_BANDAID A_NORMAL
@ -43,394 +43,394 @@
* for the colors in each syntax. */
void set_colorpairs(void)
{
const syntaxtype *sint;
bool using_defaults = FALSE;
short foreground, background;
size_t i;
const syntaxtype *sint;
bool using_defaults = FALSE;
short foreground, background;
size_t i;
/* Tell ncurses to enable colors. */
start_color();
/* Tell ncurses to enable colors. */
start_color();
#ifdef HAVE_USE_DEFAULT_COLORS
/* Allow using the default colors, if available. */
using_defaults = (use_default_colors() != ERR);
/* Allow using the default colors, if available. */
using_defaults = (use_default_colors() != ERR);
#endif
/* Initialize the color pairs for nano's interface elements. */
for (i = 0; i < NUMBER_OF_ELEMENTS; i++) {
bool bright = FALSE;
/* Initialize the color pairs for nano's interface elements. */
for (i = 0; i < NUMBER_OF_ELEMENTS; i++) {
bool bright = FALSE;
if (specified_color_combo[i] != NULL &&
parse_color_names(specified_color_combo[i],
&foreground, &background, &bright)) {
if (foreground == -1 && !using_defaults)
foreground = COLOR_WHITE;
if (background == -1 && !using_defaults)
background = COLOR_BLACK;
init_pair(i + 1, foreground, background);
interface_color_pair[i] = COLOR_PAIR(i + 1) | A_BANDAID |
(bright ? A_BOLD : A_NORMAL);
} else {
if (i != FUNCTION_TAG)
interface_color_pair[i] = hilite_attribute;
else
interface_color_pair[i] = A_NORMAL;
if (specified_color_combo[i] != NULL &&
parse_color_names(specified_color_combo[i],
&foreground, &background, &bright)) {
if (foreground == -1 && !using_defaults)
foreground = COLOR_WHITE;
if (background == -1 && !using_defaults)
background = COLOR_BLACK;
init_pair(i + 1, foreground, background);
interface_color_pair[i] = COLOR_PAIR(i + 1) | A_BANDAID |
(bright ? A_BOLD : A_NORMAL);
} else {
if (i != FUNCTION_TAG)
interface_color_pair[i] = hilite_attribute;
else
interface_color_pair[i] = A_NORMAL;
}
free(specified_color_combo[i]);
specified_color_combo[i] = NULL;
}
free(specified_color_combo[i]);
specified_color_combo[i] = NULL;
}
/* For each syntax, go through its list of colors and assign each
* its pair number, giving identical color pairs the same number. */
for (sint = syntaxes; sint != NULL; sint = sint->next) {
colortype *ink;
int new_number = NUMBER_OF_ELEMENTS + 1;
/* For each syntax, go through its list of colors and assign each
* its pair number, giving identical color pairs the same number. */
for (sint = syntaxes; sint != NULL; sint = sint->next) {
colortype *ink;
int new_number = NUMBER_OF_ELEMENTS + 1;
for (ink = sint->color; ink != NULL; ink = ink->next) {
const colortype *beforenow = sint->color;
for (ink = sint->color; ink != NULL; ink = ink->next) {
const colortype *beforenow = sint->color;
while (beforenow != ink && (beforenow->fg != ink->fg ||
beforenow->bg != ink->bg ||
beforenow->bright != ink->bright))
beforenow = beforenow->next;
while (beforenow != ink && (beforenow->fg != ink->fg ||
beforenow->bg != ink->bg ||
beforenow->bright != ink->bright))
beforenow = beforenow->next;
if (beforenow != ink)
ink->pairnum = beforenow->pairnum;
else
ink->pairnum = new_number++;
if (beforenow != ink)
ink->pairnum = beforenow->pairnum;
else
ink->pairnum = new_number++;
ink->attributes = COLOR_PAIR(ink->pairnum) | A_BANDAID |
(ink->bright ? A_BOLD : A_NORMAL);
ink->attributes = COLOR_PAIR(ink->pairnum) | A_BANDAID |
(ink->bright ? A_BOLD : A_NORMAL);
}
}
}
}
/* Initialize the color information. */
void color_init(void)
{
const colortype *ink;
bool using_defaults = FALSE;
short foreground, background;
const colortype *ink;
bool using_defaults = FALSE;
short foreground, background;
/* If the terminal is not capable of colors, forget it. */
if (!has_colors())
return;
/* If the terminal is not capable of colors, forget it. */
if (!has_colors())
return;
#ifdef HAVE_USE_DEFAULT_COLORS
/* Allow using the default colors, if available. */
using_defaults = (use_default_colors() != ERR);
/* Allow using the default colors, if available. */
using_defaults = (use_default_colors() != ERR);
#endif
/* For each coloring expression, initialize the color pair. */
for (ink = openfile->colorstrings; ink != NULL; ink = ink->next) {
foreground = ink->fg;
background = ink->bg;
/* For each coloring expression, initialize the color pair. */
for (ink = openfile->colorstrings; ink != NULL; ink = ink->next) {
foreground = ink->fg;
background = ink->bg;
if (foreground == -1 && !using_defaults)
foreground = COLOR_WHITE;
if (foreground == -1 && !using_defaults)
foreground = COLOR_WHITE;
if (background == -1 && !using_defaults)
background = COLOR_BLACK;
if (background == -1 && !using_defaults)
background = COLOR_BLACK;
init_pair(ink->pairnum, foreground, background);
}
init_pair(ink->pairnum, foreground, background);
}
have_palette = TRUE;
have_palette = TRUE;
}
/* Try to match the given shibboleth string with one of the regexes in
* the list starting at head. Return TRUE upon success. */
bool found_in_list(regexlisttype *head, const char *shibboleth)
{
regexlisttype *item;
regex_t rgx;
regexlisttype *item;
regex_t rgx;
for (item = head; item != NULL; item = item->next) {
regcomp(&rgx, fixbounds(item->full_regex), NANO_REG_EXTENDED);
for (item = head; item != NULL; item = item->next) {
regcomp(&rgx, fixbounds(item->full_regex), NANO_REG_EXTENDED);
if (regexec(&rgx, shibboleth, 0, NULL, 0) == 0) {
regfree(&rgx);
return TRUE;
if (regexec(&rgx, shibboleth, 0, NULL, 0) == 0) {
regfree(&rgx);
return TRUE;
}
regfree(&rgx);
}
regfree(&rgx);
}
return FALSE;
return FALSE;
}
/* Update the color information based on the current filename and content. */
void color_update(void)
{
syntaxtype *sint = NULL;
colortype *ink;
syntaxtype *sint = NULL;
colortype *ink;
/* If the rcfiles were not read, or contained no syntaxes, get out. */
if (syntaxes == NULL)
return;
/* If the rcfiles were not read, or contained no syntaxes, get out. */
if (syntaxes == NULL)
return;
/* If we specified a syntax-override string, use it. */
if (syntaxstr != NULL) {
/* An override of "none" is like having no syntax at all. */
if (strcmp(syntaxstr, "none") == 0)
return;
/* If we specified a syntax-override string, use it. */
if (syntaxstr != NULL) {
/* An override of "none" is like having no syntax at all. */
if (strcmp(syntaxstr, "none") == 0)
return;
for (sint = syntaxes; sint != NULL; sint = sint->next) {
if (strcmp(sint->name, syntaxstr) == 0)
break;
for (sint = syntaxes; sint != NULL; sint = sint->next) {
if (strcmp(sint->name, syntaxstr) == 0)
break;
}
if (sint == NULL && !inhelp)
statusline(ALERT, _("Unknown syntax name: %s"), syntaxstr);
}
if (sint == NULL && !inhelp)
statusline(ALERT, _("Unknown syntax name: %s"), syntaxstr);
}
/* If no syntax-override string was specified, or it didn't match,
* try finding a syntax based on the filename (extension). */
if (sint == NULL && !inhelp) {
char *reserved = charalloc(PATH_MAX + 1);
char *currentdir = getcwd(reserved, PATH_MAX + 1);
char *joinednames = charalloc(PATH_MAX + 1);
char *fullname = NULL;
/* If no syntax-override string was specified, or it didn't match,
* try finding a syntax based on the filename (extension). */
if (sint == NULL && !inhelp) {
char *reserved = charalloc(PATH_MAX + 1);
char *currentdir = getcwd(reserved, PATH_MAX + 1);
char *joinednames = charalloc(PATH_MAX + 1);
char *fullname = NULL;
if (currentdir == NULL)
free(reserved);
else {
/* Concatenate the current working directory with the
* specified filename, and canonicalize the result. */
sprintf(joinednames, "%s/%s", currentdir, openfile->filename);
fullname = get_full_path(joinednames);
free(currentdir);
}
if (currentdir == NULL)
free(reserved);
else {
/* Concatenate the current working directory with the
* specified filename, and canonicalize the result. */
sprintf(joinednames, "%s/%s", currentdir, openfile->filename);
fullname = get_full_path(joinednames);
free(currentdir);
if (fullname == NULL)
fullname = mallocstrcpy(fullname, openfile->filename);
for (sint = syntaxes; sint != NULL; sint = sint->next) {
if (found_in_list(sint->extensions, fullname))
break;
}
free(joinednames);
free(fullname);
}
if (fullname == NULL)
fullname = mallocstrcpy(fullname, openfile->filename);
for (sint = syntaxes; sint != NULL; sint = sint->next) {
if (found_in_list(sint->extensions, fullname))
break;
/* If the filename didn't match anything, try the first line. */
if (sint == NULL && !inhelp) {
for (sint = syntaxes; sint != NULL; sint = sint->next) {
if (found_in_list(sint->headers, openfile->fileage->data))
break;
}
}
free(joinednames);
free(fullname);
}
/* If the filename didn't match anything, try the first line. */
if (sint == NULL && !inhelp) {
for (sint = syntaxes; sint != NULL; sint = sint->next) {
if (found_in_list(sint->headers, openfile->fileage->data))
break;
}
}
#ifdef HAVE_LIBMAGIC
/* If we still don't have an answer, try using magic. */
if (sint == NULL && !inhelp) {
struct stat fileinfo;
magic_t cookie = NULL;
const char *magicstring = NULL;
/* If we still don't have an answer, try using magic. */
if (sint == NULL && !inhelp) {
struct stat fileinfo;
magic_t cookie = NULL;
const char *magicstring = NULL;
if (stat(openfile->filename, &fileinfo) == 0) {
/* Open the magic database and get a diagnosis of the file. */
cookie = magic_open(MAGIC_SYMLINK |
if (stat(openfile->filename, &fileinfo) == 0) {
/* Open the magic database and get a diagnosis of the file. */
cookie = magic_open(MAGIC_SYMLINK |
#ifdef DEBUG
MAGIC_DEBUG | MAGIC_CHECK |
MAGIC_DEBUG | MAGIC_CHECK |
#endif
MAGIC_ERROR);
if (cookie == NULL || magic_load(cookie, NULL) < 0)
statusline(ALERT, _("magic_load() failed: %s"), strerror(errno));
else {
magicstring = magic_file(cookie, openfile->filename);
if (magicstring == NULL)
statusline(ALERT, _("magic_file(%s) failed: %s"),
openfile->filename, magic_error(cookie));
}
}
MAGIC_ERROR);
if (cookie == NULL || magic_load(cookie, NULL) < 0)
statusline(ALERT, _("magic_load() failed: %s"), strerror(errno));
else {
magicstring = magic_file(cookie, openfile->filename);
if (magicstring == NULL)
statusline(ALERT, _("magic_file(%s) failed: %s"),
openfile->filename, magic_error(cookie));
}
}
/* Now try and find a syntax that matches the magic string. */
if (magicstring != NULL) {
for (sint = syntaxes; sint != NULL; sint = sint->next) {
if (found_in_list(sint->magics, magicstring))
break;
}
}
/* Now try and find a syntax that matches the magic string. */
if (magicstring != NULL) {
for (sint = syntaxes; sint != NULL; sint = sint->next) {
if (found_in_list(sint->magics, magicstring))
break;
}
}
if (stat(openfile->filename, &fileinfo) == 0)
magic_close(cookie);
}
if (stat(openfile->filename, &fileinfo) == 0)
magic_close(cookie);
}
#endif /* HAVE_LIBMAGIC */
/* If nothing at all matched, see if there is a default syntax. */
if (sint == NULL && !inhelp) {
for (sint = syntaxes; sint != NULL; sint = sint->next) {
if (strcmp(sint->name, "default") == 0)
break;
}
}
openfile->syntax = sint;
openfile->colorstrings = (sint == NULL ? NULL : sint->color);
/* If a syntax was found, compile its specified regexes (which have
* already been checked for validity when they were read in). */
for (ink = openfile->colorstrings; ink != NULL; ink = ink->next) {
if (ink->start == NULL) {
ink->start = (regex_t *)nmalloc(sizeof(regex_t));
regcomp(ink->start, fixbounds(ink->start_regex), ink->rex_flags);
/* If nothing at all matched, see if there is a default syntax. */
if (sint == NULL && !inhelp) {
for (sint = syntaxes; sint != NULL; sint = sint->next) {
if (strcmp(sint->name, "default") == 0)
break;
}
}
if (ink->end_regex != NULL && ink->end == NULL) {
ink->end = (regex_t *)nmalloc(sizeof(regex_t));
regcomp(ink->end, fixbounds(ink->end_regex), ink->rex_flags);
openfile->syntax = sint;
openfile->colorstrings = (sint == NULL ? NULL : sint->color);
/* If a syntax was found, compile its specified regexes (which have
* already been checked for validity when they were read in). */
for (ink = openfile->colorstrings; ink != NULL; ink = ink->next) {
if (ink->start == NULL) {
ink->start = (regex_t *)nmalloc(sizeof(regex_t));
regcomp(ink->start, fixbounds(ink->start_regex), ink->rex_flags);
}
if (ink->end_regex != NULL && ink->end == NULL) {
ink->end = (regex_t *)nmalloc(sizeof(regex_t));
regcomp(ink->end, fixbounds(ink->end_regex), ink->rex_flags);
}
}
}
}
/* Determine whether the matches of multiline regexes are still the same,
* and if not, schedule a screen refresh, so things will be repainted. */
void check_the_multis(filestruct *line)
{
const colortype *ink;
bool astart, anend;
regmatch_t startmatch, endmatch;
const colortype *ink;
bool astart, anend;
regmatch_t startmatch, endmatch;
/* If there is no syntax or no multiline regex, there is nothing to do. */
if (openfile->syntax == NULL || openfile->syntax->nmultis == 0)
return;
/* If there is no syntax or no multiline regex, there is nothing to do. */
if (openfile->syntax == NULL || openfile->syntax->nmultis == 0)
return;
for (ink = openfile->colorstrings; ink != NULL; ink = ink->next) {
/* If it's not a multiline regex, skip. */
if (ink->end == NULL)
continue;
for (ink = openfile->colorstrings; ink != NULL; ink = ink->next) {
/* If it's not a multiline regex, skip. */
if (ink->end == NULL)
continue;
alloc_multidata_if_needed(line);
alloc_multidata_if_needed(line);
astart = (regexec(ink->start, line->data, 1, &startmatch, 0) == 0);
anend = (regexec(ink->end, line->data, 1, &endmatch, 0) == 0);
astart = (regexec(ink->start, line->data, 1, &startmatch, 0) == 0);
anend = (regexec(ink->end, line->data, 1, &endmatch, 0) == 0);
/* Check whether the multidata still matches the current situation. */
if (line->multidata[ink->id] == CNONE ||
line->multidata[ink->id] == CWHOLELINE) {
if (!astart && !anend)
continue;
} else if (line->multidata[ink->id] == CSTARTENDHERE) {
if (astart && anend && startmatch.rm_so < endmatch.rm_so)
continue;
} else if (line->multidata[ink->id] == CBEGINBEFORE) {
if (!astart && anend)
continue;
} else if (line->multidata[ink->id] == CENDAFTER) {
if (astart && !anend)
continue;
/* Check whether the multidata still matches the current situation. */
if (line->multidata[ink->id] == CNONE ||
line->multidata[ink->id] == CWHOLELINE) {
if (!astart && !anend)
continue;
} else if (line->multidata[ink->id] == CSTARTENDHERE) {
if (astart && anend && startmatch.rm_so < endmatch.rm_so)
continue;
} else if (line->multidata[ink->id] == CBEGINBEFORE) {
if (!astart && anend)
continue;
} else if (line->multidata[ink->id] == CENDAFTER) {
if (astart && !anend)
continue;
}
/* There is a mismatch, so something changed: repaint. */
refresh_needed = TRUE;
return;
}
/* There is a mismatch, so something changed: repaint. */
refresh_needed = TRUE;
return;
}
}
/* Allocate (for one line) the cache space for multiline color regexes. */
void alloc_multidata_if_needed(filestruct *fileptr)
{
int i;
int i;
if (fileptr->multidata == NULL) {
fileptr->multidata = (short *)nmalloc(openfile->syntax->nmultis * sizeof(short));
if (fileptr->multidata == NULL) {
fileptr->multidata = (short *)nmalloc(openfile->syntax->nmultis * sizeof(short));
for (i = 0; i < openfile->syntax->nmultis; i++)
fileptr->multidata[i] = -1;
}
for (i = 0; i < openfile->syntax->nmultis; i++)
fileptr->multidata[i] = -1;
}
}
/* Precalculate the multi-line start and end regex info so we can
* speed up rendering (with any hope at all...). */
void precalc_multicolorinfo(void)
{
const colortype *ink;
regmatch_t startmatch, endmatch;
filestruct *line, *tailline;
const colortype *ink;
regmatch_t startmatch, endmatch;
filestruct *line, *tailline;
if (openfile->colorstrings == NULL || ISSET(NO_COLOR_SYNTAX))
return;
if (openfile->colorstrings == NULL || ISSET(NO_COLOR_SYNTAX))
return;
#ifdef DEBUG
fprintf(stderr, "Precalculating the multiline color info...\n");
fprintf(stderr, "Precalculating the multiline color info...\n");
#endif
for (ink = openfile->colorstrings; ink != NULL; ink = ink->next) {
/* If this is not a multi-line regex, skip it. */
if (ink->end == NULL)
continue;
for (ink = openfile->colorstrings; ink != NULL; ink = ink->next) {
/* If this is not a multi-line regex, skip it. */
if (ink->end == NULL)
continue;
for (line = openfile->fileage; line != NULL; line = line->next) {
int index = 0;
for (line = openfile->fileage; line != NULL; line = line->next) {
int index = 0;
alloc_multidata_if_needed(line);
/* Assume nothing applies until proven otherwise below. */
line->multidata[ink->id] = CNONE;
alloc_multidata_if_needed(line);
/* Assume nothing applies until proven otherwise below. */
line->multidata[ink->id] = CNONE;
/* For an unpaired start match, mark all remaining lines. */
if (line->prev && line->prev->multidata[ink->id] == CWOULDBE) {
line->multidata[ink->id] = CWOULDBE;
continue;
}
/* For an unpaired start match, mark all remaining lines. */
if (line->prev && line->prev->multidata[ink->id] == CWOULDBE) {
line->multidata[ink->id] = CWOULDBE;
continue;
}
/* When the line contains a start match, look for an end, and if
* found, mark all the lines that are affected. */
while (regexec(ink->start, line->data + index, 1,
&startmatch, (index == 0) ? 0 : REG_NOTBOL) == 0) {
/* Begin looking for an end match after the start match. */
index += startmatch.rm_eo;
/* When the line contains a start match, look for an end, and if
* found, mark all the lines that are affected. */
while (regexec(ink->start, line->data + index, 1,
&startmatch, (index == 0) ? 0 : REG_NOTBOL) == 0) {
/* Begin looking for an end match after the start match. */
index += startmatch.rm_eo;
/* If there is an end match on this line, mark the line, but
* continue looking for other starts after it. */
if (regexec(ink->end, line->data + index, 1,
&endmatch, (index == 0) ? 0 : REG_NOTBOL) == 0) {
line->multidata[ink->id] = CSTARTENDHERE;
index += endmatch.rm_eo;
/* If both start and end are mere anchors, step ahead. */
if (startmatch.rm_so == startmatch.rm_eo &&
endmatch.rm_so == endmatch.rm_eo) {
/* When at end-of-line, we're done. */
if (line->data[index] == '\0')
break;
index = move_mbright(line->data, index);
}
continue;
/* If there is an end match on this line, mark the line, but
* continue looking for other starts after it. */
if (regexec(ink->end, line->data + index, 1,
&endmatch, (index == 0) ? 0 : REG_NOTBOL) == 0) {
line->multidata[ink->id] = CSTARTENDHERE;
index += endmatch.rm_eo;
/* If both start and end are mere anchors, step ahead. */
if (startmatch.rm_so == startmatch.rm_eo &&
endmatch.rm_so == endmatch.rm_eo) {
/* When at end-of-line, we're done. */
if (line->data[index] == '\0')
break;
index = move_mbright(line->data, index);
}
continue;
}
/* Look for an end match on later lines. */
tailline = line->next;
while (tailline != NULL) {
if (regexec(ink->end, tailline->data, 1, &endmatch, 0) == 0)
break;
tailline = tailline->next;
}
if (tailline == NULL) {
line->multidata[ink->id] = CWOULDBE;
break;
}
/* We found it, we found it, la la la la la. Mark all
* the lines in between and the end properly. */
line->multidata[ink->id] = CENDAFTER;
for (line = line->next; line != tailline; line = line->next) {
alloc_multidata_if_needed(line);
line->multidata[ink->id] = CWHOLELINE;
}
alloc_multidata_if_needed(tailline);
tailline->multidata[ink->id] = CBEGINBEFORE;
/* Begin looking for a new start after the end match. */
index = endmatch.rm_eo;
}
}
/* Look for an end match on later lines. */
tailline = line->next;
while (tailline != NULL) {
if (regexec(ink->end, tailline->data, 1, &endmatch, 0) == 0)
break;
tailline = tailline->next;
}
if (tailline == NULL) {
line->multidata[ink->id] = CWOULDBE;
break;
}
/* We found it, we found it, la la la la la. Mark all
* the lines in between and the end properly. */
line->multidata[ink->id] = CENDAFTER;
for (line = line->next; line != tailline; line = line->next) {
alloc_multidata_if_needed(line);
line->multidata[ink->id] = CWHOLELINE;
}
alloc_multidata_if_needed(tailline);
tailline->multidata[ink->id] = CBEGINBEFORE;
/* Begin looking for a new start after the end match. */
index = endmatch.rm_eo;
}
}
}
}
#endif /* ENABLE_COLOR */

290
src/cut.c
View File

@ -25,18 +25,18 @@
#include <string.h>
static bool keep_cutbuffer = FALSE;
/* Should we keep the contents of the cutbuffer? */
/* Should we keep the contents of the cutbuffer? */
/* Indicate that we should no longer keep the contents of the cutbuffer. */
void cutbuffer_reset(void)
{
keep_cutbuffer = FALSE;
keep_cutbuffer = FALSE;
}
/* Return the status of cutbuffer preservation. */
inline bool keeping_cutbuffer(void)
{
return keep_cutbuffer;
return keep_cutbuffer;
}
/* If we aren't on the last line of the file, move all the text of the
@ -46,13 +46,13 @@ inline bool keeping_cutbuffer(void)
* current line. */
void cut_line(void)
{
if (openfile->current != openfile->filebot)
extract_buffer(&cutbuffer, &cutbottom, openfile->current, 0,
openfile->current->next, 0);
else
extract_buffer(&cutbuffer, &cutbottom, openfile->current, 0,
openfile->current, strlen(openfile->current->data));
openfile->placewewant = 0;
if (openfile->current != openfile->filebot)
extract_buffer(&cutbuffer, &cutbottom, openfile->current, 0,
openfile->current->next, 0);
else
extract_buffer(&cutbuffer, &cutbottom, openfile->current, 0,
openfile->current, strlen(openfile->current->data));
openfile->placewewant = 0;
}
#ifndef NANO_TINY
@ -60,14 +60,14 @@ void cut_line(void)
* current place we want to where the text used to start. */
void cut_marked(bool *right_side_up)
{
filestruct *top, *bot;
size_t top_x, bot_x;
filestruct *top, *bot;
size_t top_x, bot_x;
mark_order((const filestruct **)&top, &top_x,
(const filestruct **)&bot, &bot_x, right_side_up);
mark_order((const filestruct **)&top, &top_x,
(const filestruct **)&bot, &bot_x, right_side_up);
extract_buffer(&cutbuffer, &cutbottom, top, top_x, bot, bot_x);
openfile->placewewant = xplustabs();
extract_buffer(&cutbuffer, &cutbottom, top, top_x, bot, bot_x);
openfile->placewewant = xplustabs();
}
/* If we aren't at the end of the current line, move all the text from
@ -78,32 +78,32 @@ void cut_marked(bool *right_side_up)
* newline used to be. */
void cut_to_eol(void)
{
size_t data_len = strlen(openfile->current->data);
size_t data_len = strlen(openfile->current->data);
if (openfile->current_x < data_len)
/* If we're not at the end of the line, move all the text from
* the current position up to it, not counting the newline at
* the end, into the cutbuffer. */
extract_buffer(&cutbuffer, &cutbottom, openfile->current,
openfile->current_x, openfile->current, data_len);
else if (openfile->current != openfile->filebot) {
/* If we're at the end of the line, and it isn't the last line
* of the file, move all the text from the current position up
* to the beginning of the next line, i.e. the newline at the
* end, into the cutbuffer. */
extract_buffer(&cutbuffer, &cutbottom, openfile->current,
openfile->current_x, openfile->current->next, 0);
openfile->placewewant = xplustabs();
}
if (openfile->current_x < data_len)
/* If we're not at the end of the line, move all the text from
* the current position up to it, not counting the newline at
* the end, into the cutbuffer. */
extract_buffer(&cutbuffer, &cutbottom, openfile->current,
openfile->current_x, openfile->current, data_len);
else if (openfile->current != openfile->filebot) {
/* If we're at the end of the line, and it isn't the last line
* of the file, move all the text from the current position up
* to the beginning of the next line, i.e. the newline at the
* end, into the cutbuffer. */
extract_buffer(&cutbuffer, &cutbottom, openfile->current,
openfile->current_x, openfile->current->next, 0);
openfile->placewewant = xplustabs();
}
}
/* Move all the text from the current cursor position to the end of the
* file into the cutbuffer. */
void cut_to_eof(void)
{
extract_buffer(&cutbuffer, &cutbottom,
openfile->current, openfile->current_x,
openfile->filebot, strlen(openfile->filebot->data));
extract_buffer(&cutbuffer, &cutbottom,
openfile->current, openfile->current_x,
openfile->filebot, strlen(openfile->filebot->data));
}
#endif /* !NANO_TINY */
@ -114,86 +114,86 @@ void cut_to_eof(void)
void do_cut_text(bool copy_text, bool cut_till_eof)
{
#ifndef NANO_TINY
filestruct *cb_save = NULL;
/* The current end of the cutbuffer, before we add text to it. */
size_t cb_save_len = 0;
/* The length of the string at the current end of the cutbuffer,
* before we add text to it. */
bool old_no_newlines = ISSET(NO_NEWLINES);
bool right_side_up = TRUE;
/* There *is* no region, *or* it is marked forward. */
filestruct *cb_save = NULL;
/* The current end of the cutbuffer, before we add text to it. */
size_t cb_save_len = 0;
/* The length of the string at the current end of the cutbuffer,
* before we add text to it. */
bool old_no_newlines = ISSET(NO_NEWLINES);
bool right_side_up = TRUE;
/* There *is* no region, *or* it is marked forward. */
#endif
size_t was_totsize = openfile->totsize;
size_t was_totsize = openfile->totsize;
/* If a chain of cuts was broken, empty the cutbuffer. */
if (!keep_cutbuffer) {
free_filestruct(cutbuffer);
cutbuffer = NULL;
/* Indicate that future cuts should add to the cutbuffer. */
keep_cutbuffer = TRUE;
}
/* If a chain of cuts was broken, empty the cutbuffer. */
if (!keep_cutbuffer) {
free_filestruct(cutbuffer);
cutbuffer = NULL;
/* Indicate that future cuts should add to the cutbuffer. */
keep_cutbuffer = TRUE;
}
#ifndef NANO_TINY
if (copy_text) {
/* If the cutbuffer isn't empty, remember where it currently ends. */
if (cutbuffer != NULL) {
cb_save = cutbottom;
cb_save_len = strlen(cutbottom->data);
if (copy_text) {
/* If the cutbuffer isn't empty, remember where it currently ends. */
if (cutbuffer != NULL) {
cb_save = cutbottom;
cb_save_len = strlen(cutbottom->data);
}
/* Don't add a magicline when moving text to the cutbuffer. */
SET(NO_NEWLINES);
}
/* Don't add a magicline when moving text to the cutbuffer. */
SET(NO_NEWLINES);
}
if (cut_till_eof) {
/* Move all text up to the end of the file into the cutbuffer. */
cut_to_eof();
} else if (openfile->mark) {
/* Move the marked text to the cutbuffer, and turn the mark off. */
cut_marked(&right_side_up);
openfile->mark = NULL;
} else if (ISSET(CUT_FROM_CURSOR))
/* Move all text up to the end of the line into the cutbuffer. */
cut_to_eol();
else
if (cut_till_eof) {
/* Move all text up to the end of the file into the cutbuffer. */
cut_to_eof();
} else if (openfile->mark) {
/* Move the marked text to the cutbuffer, and turn the mark off. */
cut_marked(&right_side_up);
openfile->mark = NULL;
} else if (ISSET(CUT_FROM_CURSOR))
/* Move all text up to the end of the line into the cutbuffer. */
cut_to_eol();
else
#endif
/* Move the entire line into the cutbuffer. */
cut_line();
/* Move the entire line into the cutbuffer. */
cut_line();
#ifndef NANO_TINY
if (copy_text) {
/* Copy the text that is in the cutbuffer (starting at its saved end,
* if there is one) back into the current buffer. This effectively
* uncuts the text we just cut. */
if (cutbuffer != NULL) {
if (cb_save != NULL) {
cb_save->data += cb_save_len;
copy_from_buffer(cb_save);
cb_save->data -= cb_save_len;
} else
copy_from_buffer(cutbuffer);
if (copy_text) {
/* Copy the text that is in the cutbuffer (starting at its saved end,
* if there is one) back into the current buffer. This effectively
* uncuts the text we just cut. */
if (cutbuffer != NULL) {
if (cb_save != NULL) {
cb_save->data += cb_save_len;
copy_from_buffer(cb_save);
cb_save->data -= cb_save_len;
} else
copy_from_buffer(cutbuffer);
/* If the copied region was marked forward, put the new desired
* x position at its end; otherwise, leave it at its beginning. */
if (right_side_up)
openfile->placewewant = xplustabs();
}
/* Restore the magicline behavior now that we're done fiddling. */
if (!old_no_newlines)
UNSET(NO_NEWLINES);
} else
/* If the copied region was marked forward, put the new desired
* x position at its end; otherwise, leave it at its beginning. */
if (right_side_up)
openfile->placewewant = xplustabs();
}
/* Restore the magicline behavior now that we're done fiddling. */
if (!old_no_newlines)
UNSET(NO_NEWLINES);
} else
#endif /* !NANO_TINY */
/* Only set the modification flag if actually something was cut. */
if (openfile->totsize != was_totsize)
set_modified();
/* Only set the modification flag if actually something was cut. */
if (openfile->totsize != was_totsize)
set_modified();
refresh_needed = TRUE;
refresh_needed = TRUE;
#ifdef ENABLE_COLOR
check_the_multis(openfile->current);
check_the_multis(openfile->current);
#endif
#ifdef DEBUG
dump_filestruct(cutbuffer);
dump_filestruct(cutbuffer);
#endif
}
@ -201,11 +201,11 @@ void do_cut_text(bool copy_text, bool cut_till_eof)
void do_cut_text_void(void)
{
#ifndef NANO_TINY
add_undo(CUT);
add_undo(CUT);
#endif
do_cut_text(FALSE, FALSE);
do_cut_text(FALSE, FALSE);
#ifndef NANO_TINY
update_undo(CUT);
update_undo(CUT);
#endif
}
@ -215,79 +215,79 @@ void do_cut_text_void(void)
* was moved, blow away previous contents of the cutbuffer. */
void do_copy_text(void)
{
static struct filestruct *next_contiguous_line = NULL;
bool mark_is_set = (openfile->mark != NULL);
static struct filestruct *next_contiguous_line = NULL;
bool mark_is_set = (openfile->mark != NULL);
/* Remember the current viewport and cursor position. */
ssize_t is_edittop_lineno = openfile->edittop->lineno;
size_t is_firstcolumn = openfile->firstcolumn;
ssize_t is_current_lineno = openfile->current->lineno;
size_t is_current_x = openfile->current_x;
/* Remember the current viewport and cursor position. */
ssize_t is_edittop_lineno = openfile->edittop->lineno;
size_t is_firstcolumn = openfile->firstcolumn;
ssize_t is_current_lineno = openfile->current->lineno;
size_t is_current_x = openfile->current_x;
if (mark_is_set || openfile->current != next_contiguous_line)
cutbuffer_reset();
if (mark_is_set || openfile->current != next_contiguous_line)
cutbuffer_reset();
do_cut_text(TRUE, FALSE);
do_cut_text(TRUE, FALSE);
/* If the mark was set, blow away the cutbuffer on the next copy. */
next_contiguous_line = (mark_is_set ? NULL : openfile->current);
/* If the mark was set, blow away the cutbuffer on the next copy. */
next_contiguous_line = (mark_is_set ? NULL : openfile->current);
/* If the mark was set, restore the viewport and cursor position. */
if (mark_is_set) {
openfile->edittop = fsfromline(is_edittop_lineno);
openfile->firstcolumn = is_firstcolumn;
openfile->current = fsfromline(is_current_lineno);
openfile->current_x = is_current_x;
}
/* If the mark was set, restore the viewport and cursor position. */
if (mark_is_set) {
openfile->edittop = fsfromline(is_edittop_lineno);
openfile->firstcolumn = is_firstcolumn;
openfile->current = fsfromline(is_current_lineno);
openfile->current_x = is_current_x;
}
}
/* Cut from the current cursor position to the end of the file. */
void do_cut_till_eof(void)
{
add_undo(CUT_TO_EOF);
do_cut_text(FALSE, TRUE);
update_undo(CUT_TO_EOF);
add_undo(CUT_TO_EOF);
do_cut_text(FALSE, TRUE);
update_undo(CUT_TO_EOF);
}
#endif /* !NANO_TINY */
/* Copy text from the cutbuffer into the current buffer. */
void do_uncut_text(void)
{
ssize_t was_lineno = openfile->current->lineno;
/* The line number where we started the paste. */
size_t was_leftedge = 0;
/* The leftedge where we started the paste. */
ssize_t was_lineno = openfile->current->lineno;
/* The line number where we started the paste. */
size_t was_leftedge = 0;
/* The leftedge where we started the paste. */
/* If the cutbuffer is empty, there is nothing to do. */
if (cutbuffer == NULL)
return;
/* If the cutbuffer is empty, there is nothing to do. */
if (cutbuffer == NULL)
return;
#ifndef NANO_TINY
add_undo(PASTE);
add_undo(PASTE);
if (ISSET(SOFTWRAP))
was_leftedge = leftedge_for(xplustabs(), openfile->current);
if (ISSET(SOFTWRAP))
was_leftedge = leftedge_for(xplustabs(), openfile->current);
#endif
/* Add a copy of the text in the cutbuffer to the current buffer
* at the current cursor position. */
copy_from_buffer(cutbuffer);
/* Add a copy of the text in the cutbuffer to the current buffer
* at the current cursor position. */
copy_from_buffer(cutbuffer);
#ifndef NANO_TINY
update_undo(PASTE);
update_undo(PASTE);
#endif
/* If we pasted less than a screenful, don't center the cursor. */
if (less_than_a_screenful(was_lineno, was_leftedge))
focusing = FALSE;
/* If we pasted less than a screenful, don't center the cursor. */
if (less_than_a_screenful(was_lineno, was_leftedge))
focusing = FALSE;
/* Set the desired x position to where the pasted text ends. */
openfile->placewewant = xplustabs();
/* Set the desired x position to where the pasted text ends. */
openfile->placewewant = xplustabs();
set_modified();
refresh_needed = TRUE;
set_modified();
refresh_needed = TRUE;
#ifdef ENABLE_COLOR
check_the_multis(openfile->current);
check_the_multis(openfile->current);
#endif
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -35,146 +35,146 @@
#endif
static bool history_changed = FALSE;
/* Whether any of the history lists has changed. */
/* Whether any of the history lists has changed. */
static struct stat stat_of_positions_file;
/* The last-obtained stat information of the positions file. */
/* The last-obtained stat information of the positions file. */
static char *poshistname = NULL;
/* The name of the positions-history file. */
/* The name of the positions-history file. */
/* Initialize the lists of historical search and replace strings
* and the list of historical executed commands. */
void history_init(void)
{
search_history = make_new_node(NULL);
search_history->data = mallocstrcpy(NULL, "");
searchtop = search_history;
searchbot = search_history;
search_history = make_new_node(NULL);
search_history->data = mallocstrcpy(NULL, "");
searchtop = search_history;
searchbot = search_history;
replace_history = make_new_node(NULL);
replace_history->data = mallocstrcpy(NULL, "");
replacetop = replace_history;
replacebot = replace_history;
replace_history = make_new_node(NULL);
replace_history->data = mallocstrcpy(NULL, "");
replacetop = replace_history;
replacebot = replace_history;
execute_history = make_new_node(NULL);
execute_history->data = mallocstrcpy(NULL, "");
executetop = execute_history;
executebot = execute_history;
execute_history = make_new_node(NULL);
execute_history->data = mallocstrcpy(NULL, "");
executetop = execute_history;
executebot = execute_history;
}
/* Set the current position in the given history list to the bottom. */
void history_reset(const filestruct *list)
{
if (list == search_history)
search_history = searchbot;
else if (list == replace_history)
replace_history = replacebot;
else if (list == execute_history)
execute_history = executebot;
if (list == search_history)
search_history = searchbot;
else if (list == replace_history)
replace_history = replacebot;
else if (list == execute_history)
execute_history = executebot;
}
/* Return from the history list that starts at start and ends at end
* the first node that contains the first len characters of the given
* text, or NULL if there is no such node. */
filestruct *find_history(const filestruct *start, const filestruct *end,
const char *text, size_t len)
const char *text, size_t len)
{
const filestruct *item;
const filestruct *item;
for (item = start; item != end->prev && item != NULL; item = item->prev) {
if (strncmp(item->data, text, len) == 0)
return (filestruct *)item;
}
for (item = start; item != end->prev && item != NULL; item = item->prev) {
if (strncmp(item->data, text, len) == 0)
return (filestruct *)item;
}
return NULL;
return NULL;
}
/* Update a history list (the one in which item is the current position)
* with a fresh string text. That is: add text, or move it to the end. */
void update_history(filestruct **item, const char *text)
{
filestruct **htop = NULL, **hbot = NULL, *thesame;
filestruct **htop = NULL, **hbot = NULL, *thesame;
if (*item == search_history) {
htop = &searchtop;
hbot = &searchbot;
} else if (*item == replace_history) {
htop = &replacetop;
hbot = &replacebot;
} else if (*item == execute_history) {
htop = &executetop;
hbot = &executebot;
}
if (*item == search_history) {
htop = &searchtop;
hbot = &searchbot;
} else if (*item == replace_history) {
htop = &replacetop;
hbot = &replacebot;
} else if (*item == execute_history) {
htop = &executetop;
hbot = &executebot;
}
/* See if the string is already in the history. */
thesame = find_history(*hbot, *htop, text, HIGHEST_POSITIVE);
/* See if the string is already in the history. */
thesame = find_history(*hbot, *htop, text, HIGHEST_POSITIVE);
/* If an identical string was found, delete that item. */
if (thesame != NULL) {
filestruct *after = thesame->next;
/* If an identical string was found, delete that item. */
if (thesame != NULL) {
filestruct *after = thesame->next;
/* If the string is at the head of the list, move the head. */
if (thesame == *htop)
*htop = after;
/* If the string is at the head of the list, move the head. */
if (thesame == *htop)
*htop = after;
unlink_node(thesame);
renumber(after);
}
unlink_node(thesame);
renumber(after);
}
/* If the history is full, delete the oldest item (the one at the
* head of the list), to make room for a new item at the end. */
if ((*hbot)->lineno == MAX_SEARCH_HISTORY + 1) {
filestruct *oldest = *htop;
/* If the history is full, delete the oldest item (the one at the
* head of the list), to make room for a new item at the end. */
if ((*hbot)->lineno == MAX_SEARCH_HISTORY + 1) {
filestruct *oldest = *htop;
*htop = (*htop)->next;
unlink_node(oldest);
renumber(*htop);
}
*htop = (*htop)->next;
unlink_node(oldest);
renumber(*htop);
}
/* Store the fresh string in the last item, then create a new item. */
(*hbot)->data = mallocstrcpy((*hbot)->data, text);
splice_node(*hbot, make_new_node(*hbot));
*hbot = (*hbot)->next;
(*hbot)->data = mallocstrcpy(NULL, "");
/* Store the fresh string in the last item, then create a new item. */
(*hbot)->data = mallocstrcpy((*hbot)->data, text);
splice_node(*hbot, make_new_node(*hbot));
*hbot = (*hbot)->next;
(*hbot)->data = mallocstrcpy(NULL, "");
/* Indicate that the history needs to be saved on exit. */
history_changed = TRUE;
/* Indicate that the history needs to be saved on exit. */
history_changed = TRUE;
/* Set the current position in the list to the bottom. */
*item = *hbot;
/* Set the current position in the list to the bottom. */
*item = *hbot;
}
/* Move h to the string in the history list just before it, and return
* that string. If there isn't one, don't move h and return NULL. */
char *get_history_older(filestruct **h)
{
if ((*h)->prev == NULL)
return NULL;
if ((*h)->prev == NULL)
return NULL;
*h = (*h)->prev;
*h = (*h)->prev;
return (*h)->data;
return (*h)->data;
}
/* Move h to the string in the history list just after it, and return
* that string. If there isn't one, don't move h and return NULL. */
char *get_history_newer(filestruct **h)
{
if ((*h)->next == NULL)
return NULL;
if ((*h)->next == NULL)
return NULL;
*h = (*h)->next;
*h = (*h)->next;
return (*h)->data;
return (*h)->data;
}
/* More placeholders. */
void get_history_newer_void(void)
{
;
;
}
void get_history_older_void(void)
{
;
;
}
#ifdef ENABLE_TABCOMP
@ -184,408 +184,408 @@ void get_history_older_void(void)
* s. */
char *get_history_completion(filestruct **h, char *s, size_t len)
{
if (len > 0) {
filestruct *htop = NULL, *hbot = NULL, *p;
if (len > 0) {
filestruct *htop = NULL, *hbot = NULL, *p;
if (*h == search_history) {
htop = searchtop;
hbot = searchbot;
} else if (*h == replace_history) {
htop = replacetop;
hbot = replacebot;
} else if (*h == execute_history) {
htop = executetop;
hbot = executebot;
if (*h == search_history) {
htop = searchtop;
hbot = searchbot;
} else if (*h == replace_history) {
htop = replacetop;
hbot = replacebot;
} else if (*h == execute_history) {
htop = executetop;
hbot = executebot;
}
/* Search the history list from the current position to the top
* for a match of len characters. Skip over an exact match. */
p = find_history((*h)->prev, htop, s, len);
while (p != NULL && strcmp(p->data, s) == 0)
p = find_history(p->prev, htop, s, len);
if (p != NULL) {
*h = p;
return mallocstrcpy(s, (*h)->data);
}
/* Search the history list from the bottom to the current position
* for a match of len characters. Skip over an exact match. */
p = find_history(hbot, *h, s, len);
while (p != NULL && strcmp(p->data, s) == 0)
p = find_history(p->prev, *h, s, len);
if (p != NULL) {
*h = p;
return mallocstrcpy(s, (*h)->data);
}
}
/* Search the history list from the current position to the top
* for a match of len characters. Skip over an exact match. */
p = find_history((*h)->prev, htop, s, len);
while (p != NULL && strcmp(p->data, s) == 0)
p = find_history(p->prev, htop, s, len);
if (p != NULL) {
*h = p;
return mallocstrcpy(s, (*h)->data);
}
/* Search the history list from the bottom to the current position
* for a match of len characters. Skip over an exact match. */
p = find_history(hbot, *h, s, len);
while (p != NULL && strcmp(p->data, s) == 0)
p = find_history(p->prev, *h, s, len);
if (p != NULL) {
*h = p;
return mallocstrcpy(s, (*h)->data);
}
}
/* If we're here, we didn't find a match, we didn't find an inexact
* match, or len is 0. Return s. */
return (char *)s;
/* If we're here, we didn't find a match, we didn't find an inexact
* match, or len is 0. Return s. */
return (char *)s;
}
#endif /* ENSABLE_TABCOMP */
void history_error(const char *msg, ...)
{
va_list ap;
va_list ap;
va_start(ap, msg);
vfprintf(stderr, _(msg), ap);
va_end(ap);
va_start(ap, msg);
vfprintf(stderr, _(msg), ap);
va_end(ap);
fprintf(stderr, _("\nPress Enter to continue\n"));
while (getchar() != '\n')
;
fprintf(stderr, _("\nPress Enter to continue\n"));
while (getchar() != '\n')
;
}
/* Check whether we have or could make a directory for history files. */
bool have_statedir(void)
{
struct stat dirstat;
const char *xdgdatadir;
struct stat dirstat;
const char *xdgdatadir;
get_homedir();
get_homedir();
if (homedir != NULL) {
statedir = concatenate(homedir, "/.nano/");
if (homedir != NULL) {
statedir = concatenate(homedir, "/.nano/");
if (stat(statedir, &dirstat) == 0 && S_ISDIR(dirstat.st_mode)) {
poshistname = concatenate(statedir, POSITION_HISTORY);
return TRUE;
if (stat(statedir, &dirstat) == 0 && S_ISDIR(dirstat.st_mode)) {
poshistname = concatenate(statedir, POSITION_HISTORY);
return TRUE;
}
}
}
free(statedir);
xdgdatadir = getenv("XDG_DATA_HOME");
free(statedir);
xdgdatadir = getenv("XDG_DATA_HOME");
if (homedir == NULL && xdgdatadir == NULL)
return FALSE;
if (homedir == NULL && xdgdatadir == NULL)
return FALSE;
if (xdgdatadir != NULL)
statedir = concatenate(xdgdatadir, "/nano/");
else
statedir = concatenate(homedir, "/.local/share/nano/");
if (xdgdatadir != NULL)
statedir = concatenate(xdgdatadir, "/nano/");
else
statedir = concatenate(homedir, "/.local/share/nano/");
if (stat(statedir, &dirstat) == -1) {
if (xdgdatadir == NULL) {
char *statepath = concatenate(homedir, "/.local");
mkdir(statepath, S_IRWXU | S_IRWXG | S_IRWXO);
free(statepath);
statepath = concatenate(homedir, "/.local/share");
mkdir(statepath, S_IRWXU);
free(statepath);
if (stat(statedir, &dirstat) == -1) {
if (xdgdatadir == NULL) {
char *statepath = concatenate(homedir, "/.local");
mkdir(statepath, S_IRWXU | S_IRWXG | S_IRWXO);
free(statepath);
statepath = concatenate(homedir, "/.local/share");
mkdir(statepath, S_IRWXU);
free(statepath);
}
if (mkdir(statedir, S_IRWXU) == -1) {
history_error(N_("Unable to create directory %s: %s\n"
"It is required for saving/loading "
"search history or cursor positions.\n"),
statedir, strerror(errno));
return FALSE;
}
} else if (!S_ISDIR(dirstat.st_mode)) {
history_error(N_("Path %s is not a directory and needs to be.\n"
"Nano will be unable to load or save "
"search history or cursor positions.\n"),
statedir);
return FALSE;
}
if (mkdir(statedir, S_IRWXU) == -1) {
history_error(N_("Unable to create directory %s: %s\n"
"It is required for saving/loading "
"search history or cursor positions.\n"),
statedir, strerror(errno));
return FALSE;
}
} else if (!S_ISDIR(dirstat.st_mode)) {
history_error(N_("Path %s is not a directory and needs to be.\n"
"Nano will be unable to load or save "
"search history or cursor positions.\n"),
statedir);
return FALSE;
}
poshistname = concatenate(statedir, POSITION_HISTORY);
return TRUE;
poshistname = concatenate(statedir, POSITION_HISTORY);
return TRUE;
}
/* Load the histories for Search and Replace and Execute Command. */
void load_history(void)
{
char *histname = concatenate(statedir, SEARCH_HISTORY);
FILE *hisfile = fopen(histname, "rb");
char *histname = concatenate(statedir, SEARCH_HISTORY);
FILE *hisfile = fopen(histname, "rb");
if (hisfile == NULL) {
if (errno != ENOENT) {
/* When reading failed, don't save history when we quit. */
UNSET(HISTORYLOG);
history_error(N_("Error reading %s: %s"), histname,
strerror(errno));
}
} else {
/* Load the three history lists -- first search, then replace,
* then execute -- from oldest entry to newest. Between two
* lists there is an empty line. */
filestruct **history = &search_history;
char *line = NULL;
size_t buf_len = 0;
ssize_t read;
if (hisfile == NULL) {
if (errno != ENOENT) {
/* When reading failed, don't save history when we quit. */
UNSET(HISTORYLOG);
history_error(N_("Error reading %s: %s"), histname,
strerror(errno));
}
} else {
/* Load the three history lists -- first search, then replace,
* then execute -- from oldest entry to newest. Between two
* lists there is an empty line. */
filestruct **history = &search_history;
char *line = NULL;
size_t buf_len = 0;
ssize_t read;
while ((read = getline(&line, &buf_len, hisfile)) > 0) {
line[--read] = '\0';
if (read > 0) {
/* Encode any embedded NUL as 0x0A. */
unsunder(line, read);
update_history(history, line);
} else if (history == &search_history)
history = &replace_history;
else
history = &execute_history;
while ((read = getline(&line, &buf_len, hisfile)) > 0) {
line[--read] = '\0';
if (read > 0) {
/* Encode any embedded NUL as 0x0A. */
unsunder(line, read);
update_history(history, line);
} else if (history == &search_history)
history = &replace_history;
else
history = &execute_history;
}
fclose(hisfile);
free(line);
}
fclose(hisfile);
free(line);
}
/* After reading them in, set the status of the lists to "unchanged". */
history_changed = FALSE;
/* After reading them in, set the status of the lists to "unchanged". */
history_changed = FALSE;
free(histname);
free(histname);
}
/* Write the lines of a history list, starting at head, from oldest to newest,
* to the given file. Return TRUE if writing succeeded, and FALSE otherwise. */
bool write_list(const filestruct *head, FILE *hisfile)
{
const filestruct *item;
const filestruct *item;
for (item = head; item != NULL; item = item->next) {
size_t length = strlen(item->data);
for (item = head; item != NULL; item = item->next) {
size_t length = strlen(item->data);
/* Decode 0x0A bytes as embedded NULs. */
sunder(item->data);
/* Decode 0x0A bytes as embedded NULs. */
sunder(item->data);
if (fwrite(item->data, sizeof(char), length, hisfile) < length)
return FALSE;
if (putc('\n', hisfile) == EOF)
return FALSE;
}
if (fwrite(item->data, sizeof(char), length, hisfile) < length)
return FALSE;
if (putc('\n', hisfile) == EOF)
return FALSE;
}
return TRUE;
return TRUE;
}
/* Save the histories for Search and Replace and Execute Command. */
void save_history(void)
{
char *histname;
FILE *hisfile;
char *histname;
FILE *hisfile;
/* If the histories are unchanged, don't bother saving them. */
if (!history_changed)
return;
/* If the histories are unchanged, don't bother saving them. */
if (!history_changed)
return;
histname = concatenate(statedir, SEARCH_HISTORY);
hisfile = fopen(histname, "wb");
histname = concatenate(statedir, SEARCH_HISTORY);
hisfile = fopen(histname, "wb");
if (hisfile == NULL)
fprintf(stderr, _("Error writing %s: %s\n"), histname,
strerror(errno));
else {
/* Don't allow others to read or write the history file. */
chmod(histname, S_IRUSR | S_IWUSR);
if (hisfile == NULL)
fprintf(stderr, _("Error writing %s: %s\n"), histname,
strerror(errno));
else {
/* Don't allow others to read or write the history file. */
chmod(histname, S_IRUSR | S_IWUSR);
if (!write_list(searchtop, hisfile) ||
!write_list(replacetop, hisfile) ||
!write_list(executetop, hisfile))
fprintf(stderr, _("Error writing %s: %s\n"), histname,
strerror(errno));
if (!write_list(searchtop, hisfile) ||
!write_list(replacetop, hisfile) ||
!write_list(executetop, hisfile))
fprintf(stderr, _("Error writing %s: %s\n"), histname,
strerror(errno));
fclose(hisfile);
}
fclose(hisfile);
}
free(histname);
free(histname);
}
/* Load the recorded cursor positions for files that were edited. */
void load_poshistory(void)
{
FILE *hisfile = fopen(poshistname, "rb");
FILE *hisfile = fopen(poshistname, "rb");
if (hisfile == NULL) {
if (errno != ENOENT) {
/* When reading failed, don't save history when we quit. */
UNSET(POS_HISTORY);
history_error(N_("Error reading %s: %s"), poshistname, strerror(errno));
if (hisfile == NULL) {
if (errno != ENOENT) {
/* When reading failed, don't save history when we quit. */
UNSET(POS_HISTORY);
history_error(N_("Error reading %s: %s"), poshistname, strerror(errno));
}
} else {
char *line = NULL, *lineptr, *xptr;
size_t buf_len = 0;
ssize_t read, count = 0;
poshiststruct *record_ptr = NULL, *newrecord;
/* Read and parse each line, and store the extracted data. */
while ((read = getline(&line, &buf_len, hisfile)) > 5) {
/* Decode nulls as embedded newlines. */
unsunder(line, read);
/* Find where the x index and line number are in the line. */
xptr = revstrstr(line, " ", line + read - 3);
if (xptr == NULL)
continue;
lineptr = revstrstr(line, " ", xptr - 2);
if (lineptr == NULL)
continue;
/* Now separate the three elements of the line. */
*(xptr++) = '\0';
*(lineptr++) = '\0';
/* Create a new position record. */
newrecord = (poshiststruct *)nmalloc(sizeof(poshiststruct));
newrecord->filename = mallocstrcpy(NULL, line);
newrecord->lineno = atoi(lineptr);
newrecord->xno = atoi(xptr);
newrecord->next = NULL;
/* Add the record to the list. */
if (position_history == NULL)
position_history = newrecord;
else
record_ptr->next = newrecord;
record_ptr = newrecord;
/* Impose a limit, so the file will not grow indefinitely. */
if (++count > 200) {
poshiststruct *drop_record = position_history;
position_history = position_history->next;
free(drop_record->filename);
free(drop_record);
}
}
fclose(hisfile);
free(line);
stat(poshistname, &stat_of_positions_file);
}
} else {
char *line = NULL, *lineptr, *xptr;
size_t buf_len = 0;
ssize_t read, count = 0;
poshiststruct *record_ptr = NULL, *newrecord;
/* Read and parse each line, and store the extracted data. */
while ((read = getline(&line, &buf_len, hisfile)) > 5) {
/* Decode nulls as embedded newlines. */
unsunder(line, read);
/* Find where the x index and line number are in the line. */
xptr = revstrstr(line, " ", line + read - 3);
if (xptr == NULL)
continue;
lineptr = revstrstr(line, " ", xptr - 2);
if (lineptr == NULL)
continue;
/* Now separate the three elements of the line. */
*(xptr++) = '\0';
*(lineptr++) = '\0';
/* Create a new position record. */
newrecord = (poshiststruct *)nmalloc(sizeof(poshiststruct));
newrecord->filename = mallocstrcpy(NULL, line);
newrecord->lineno = atoi(lineptr);
newrecord->xno = atoi(xptr);
newrecord->next = NULL;
/* Add the record to the list. */
if (position_history == NULL)
position_history = newrecord;
else
record_ptr->next = newrecord;
record_ptr = newrecord;
/* Impose a limit, so the file will not grow indefinitely. */
if (++count > 200) {
poshiststruct *drop_record = position_history;
position_history = position_history->next;
free(drop_record->filename);
free(drop_record);
}
}
fclose(hisfile);
free(line);
stat(poshistname, &stat_of_positions_file);
}
}
/* Save the recorded cursor positions for files that were edited. */
void save_poshistory(void)
{
poshiststruct *posptr;
FILE *hisfile = fopen(poshistname, "wb");
poshiststruct *posptr;
FILE *hisfile = fopen(poshistname, "wb");
if (hisfile == NULL)
fprintf(stderr, _("Error writing %s: %s\n"), poshistname, strerror(errno));
else {
/* Don't allow others to read or write the history file. */
chmod(poshistname, S_IRUSR | S_IWUSR);
if (hisfile == NULL)
fprintf(stderr, _("Error writing %s: %s\n"), poshistname, strerror(errno));
else {
/* Don't allow others to read or write the history file. */
chmod(poshistname, S_IRUSR | S_IWUSR);
for (posptr = position_history; posptr != NULL; posptr = posptr->next) {
char *path_and_place;
size_t length;
for (posptr = position_history; posptr != NULL; posptr = posptr->next) {
char *path_and_place;
size_t length;
/* Assume 20 decimal positions each for line and column number,
* plus two spaces, plus the line feed, plus the null byte. */
path_and_place = charalloc(strlen(posptr->filename) + 44);
sprintf(path_and_place, "%s %zd %zd\n",
posptr->filename, posptr->lineno, posptr->xno);
length = strlen(path_and_place);
/* Assume 20 decimal positions each for line and column number,
* plus two spaces, plus the line feed, plus the null byte. */
path_and_place = charalloc(strlen(posptr->filename) + 44);
sprintf(path_and_place, "%s %zd %zd\n",
posptr->filename, posptr->lineno, posptr->xno);
length = strlen(path_and_place);
/* Encode newlines in filenames as nulls. */
sunder(path_and_place);
/* Restore the terminating newline. */
path_and_place[length - 1] = '\n';
/* Encode newlines in filenames as nulls. */
sunder(path_and_place);
/* Restore the terminating newline. */
path_and_place[length - 1] = '\n';
if (fwrite(path_and_place, sizeof(char), length, hisfile) < length)
fprintf(stderr, _("Error writing %s: %s\n"),
poshistname, strerror(errno));
free(path_and_place);
if (fwrite(path_and_place, sizeof(char), length, hisfile) < length)
fprintf(stderr, _("Error writing %s: %s\n"),
poshistname, strerror(errno));
free(path_and_place);
}
fclose(hisfile);
stat(poshistname, &stat_of_positions_file);
}
fclose(hisfile);
stat(poshistname, &stat_of_positions_file);
}
}
/* Reload the position history file if it has been modified since last load. */
void reload_positions_if_needed(void)
{
struct stat newstat;
struct stat newstat;
stat(poshistname, &newstat);
stat(poshistname, &newstat);
if (newstat.st_mtime != stat_of_positions_file.st_mtime) {
poshiststruct *ptr, *nextone;
if (newstat.st_mtime != stat_of_positions_file.st_mtime) {
poshiststruct *ptr, *nextone;
for (ptr = position_history; ptr != NULL; ptr = nextone) {
nextone = ptr->next;
free(ptr->filename);
free(ptr);
for (ptr = position_history; ptr != NULL; ptr = nextone) {
nextone = ptr->next;
free(ptr->filename);
free(ptr);
}
position_history = NULL;
load_poshistory();
}
position_history = NULL;
load_poshistory();
}
}
/* Update the recorded last file positions, given a filename, a line
* and a column. If no entry is found, add a new one at the end. */
void update_poshistory(char *filename, ssize_t lineno, ssize_t xpos)
{
poshiststruct *posptr, *theone, *posprev = NULL;
char *fullpath = get_full_path(filename);
poshiststruct *posptr, *theone, *posprev = NULL;
char *fullpath = get_full_path(filename);
if (fullpath == NULL || fullpath[strlen(fullpath) - 1] == '/' || inhelp) {
free(fullpath);
return;
}
reload_positions_if_needed();
/* Look for a matching filename in the list. */
for (posptr = position_history; posptr != NULL; posptr = posptr->next) {
if (!strcmp(posptr->filename, fullpath))
break;
posprev = posptr;
}
/* Don't record files that have the default cursor position. */
if (lineno == 1 && xpos == 1) {
if (posptr != NULL) {
if (posprev == NULL)
position_history = posptr->next;
else
posprev->next = posptr->next;
free(posptr->filename);
free(posptr);
save_poshistory();
if (fullpath == NULL || fullpath[strlen(fullpath) - 1] == '/' || inhelp) {
free(fullpath);
return;
}
reload_positions_if_needed();
/* Look for a matching filename in the list. */
for (posptr = position_history; posptr != NULL; posptr = posptr->next) {
if (!strcmp(posptr->filename, fullpath))
break;
posprev = posptr;
}
/* Don't record files that have the default cursor position. */
if (lineno == 1 && xpos == 1) {
if (posptr != NULL) {
if (posprev == NULL)
position_history = posptr->next;
else
posprev->next = posptr->next;
free(posptr->filename);
free(posptr);
save_poshistory();
}
free(fullpath);
return;
}
theone = posptr;
/* If we didn't find it, make a new node; otherwise, if we're
* not at the end, move the matching one to the end. */
if (theone == NULL) {
theone = (poshiststruct *)nmalloc(sizeof(poshiststruct));
theone->filename = mallocstrcpy(NULL, fullpath);
if (position_history == NULL)
position_history = theone;
else
posprev->next = theone;
} else if (posptr->next != NULL) {
if (posprev == NULL)
position_history = posptr->next;
else
posprev->next = posptr->next;
while (posptr->next != NULL)
posptr = posptr->next;
posptr->next = theone;
}
/* Store the last cursor position. */
theone->lineno = lineno;
theone->xno = xpos;
theone->next = NULL;
free(fullpath);
return;
}
theone = posptr;
/* If we didn't find it, make a new node; otherwise, if we're
* not at the end, move the matching one to the end. */
if (theone == NULL) {
theone = (poshiststruct *)nmalloc(sizeof(poshiststruct));
theone->filename = mallocstrcpy(NULL, fullpath);
if (position_history == NULL)
position_history = theone;
else
posprev->next = theone;
} else if (posptr->next != NULL) {
if (posprev == NULL)
position_history = posptr->next;
else
posprev->next = posptr->next;
while (posptr->next != NULL)
posptr = posptr->next;
posptr->next = theone;
}
/* Store the last cursor position. */
theone->lineno = lineno;
theone->xno = xpos;
theone->next = NULL;
free(fullpath);
save_poshistory();
save_poshistory();
}
/* Check whether the given file matches an existing entry in the recorded
@ -593,24 +593,24 @@ void update_poshistory(char *filename, ssize_t lineno, ssize_t xpos)
* set line and column to the retrieved values. */
bool has_old_position(const char *file, ssize_t *line, ssize_t *column)
{
poshiststruct *posptr = position_history;
char *fullpath = get_full_path(file);
poshiststruct *posptr = position_history;
char *fullpath = get_full_path(file);
if (fullpath == NULL)
return FALSE;
if (fullpath == NULL)
return FALSE;
reload_positions_if_needed();
reload_positions_if_needed();
while (posptr != NULL && strcmp(posptr->filename, fullpath) != 0)
posptr = posptr->next;
while (posptr != NULL && strcmp(posptr->filename, fullpath) != 0)
posptr = posptr->next;
free(fullpath);
free(fullpath);
if (posptr == NULL)
return FALSE;
if (posptr == NULL)
return FALSE;
*line = posptr->lineno;
*column = posptr->xno;
return TRUE;
*line = posptr->lineno;
*column = posptr->xno;
return TRUE;
}
#endif /* ENABLE_HISTORIES */

View File

@ -26,42 +26,42 @@
/* Move to the first line of the file. */
void to_first_line(void)
{
openfile->current = openfile->fileage;
openfile->current_x = 0;
openfile->placewewant = 0;
openfile->current = openfile->fileage;
openfile->current_x = 0;
openfile->placewewant = 0;
refresh_needed = TRUE;
refresh_needed = TRUE;
}
/* Move to the last line of the file. */
void to_last_line(void)
{
openfile->current = openfile->filebot;
openfile->current_x = strlen(openfile->filebot->data);
openfile->placewewant = xplustabs();
openfile->current = openfile->filebot;
openfile->current_x = strlen(openfile->filebot->data);
openfile->placewewant = xplustabs();
/* Set the last line of the screen as the target for the cursor. */
openfile->current_y = editwinrows - 1;
/* Set the last line of the screen as the target for the cursor. */
openfile->current_y = editwinrows - 1;
refresh_needed = TRUE;
focusing = FALSE;
refresh_needed = TRUE;
focusing = FALSE;
}
/* Determine the actual current chunk and the target column. */
void get_edge_and_target(size_t *leftedge, size_t *target_column)
{
#ifndef NANO_TINY
if (ISSET(SOFTWRAP)) {
size_t shim = editwincols * (1 + (tabsize / editwincols));
if (ISSET(SOFTWRAP)) {
size_t shim = editwincols * (1 + (tabsize / editwincols));
*leftedge = leftedge_for(xplustabs(), openfile->current);
*target_column = (openfile->placewewant + shim - *leftedge) % editwincols;
} else
*leftedge = leftedge_for(xplustabs(), openfile->current);
*target_column = (openfile->placewewant + shim - *leftedge) % editwincols;
} else
#endif
{
*leftedge = 0;
*target_column = openfile->placewewant;
}
{
*leftedge = 0;
*target_column = openfile->placewewant;
}
}
/* Return the index in line->data that corresponds to the given column on the
@ -69,104 +69,104 @@ void get_edge_and_target(size_t *leftedge, size_t *target_column)
* on a tab, prevent the cursor from falling back a row when moving forward,
* or from skipping a row when moving backward, by incrementing the index. */
size_t proper_x(filestruct *line, size_t *leftedge, bool forward,
size_t column, bool *shifted)
size_t column, bool *shifted)
{
size_t index = actual_x(line->data, column);
size_t index = actual_x(line->data, column);
#ifndef NANO_TINY
if (ISSET(SOFTWRAP) && line->data[index] == '\t' &&
((forward && strnlenpt(line->data, index) < *leftedge) ||
(!forward && column / tabsize == (*leftedge - 1) / tabsize &&
column / tabsize < (*leftedge + editwincols - 1) / tabsize))) {
index++;
if (ISSET(SOFTWRAP) && line->data[index] == '\t' &&
((forward && strnlenpt(line->data, index) < *leftedge) ||
(!forward && column / tabsize == (*leftedge - 1) / tabsize &&
column / tabsize < (*leftedge + editwincols - 1) / tabsize))) {
index++;
if (shifted != NULL)
*shifted = TRUE;
}
if (shifted != NULL)
*shifted = TRUE;
}
if (ISSET(SOFTWRAP))
*leftedge = leftedge_for(strnlenpt(line->data, index), line);
if (ISSET(SOFTWRAP))
*leftedge = leftedge_for(strnlenpt(line->data, index), line);
#endif
return index;
return index;
}
/* Adjust the values for current_x and placewewant in case we have landed in
* the middle of a tab that crosses a row boundary. */
void set_proper_index_and_pww(size_t *leftedge, size_t target, bool forward)
{
bool shifted = FALSE;
size_t was_edge = *leftedge;
bool shifted = FALSE;
size_t was_edge = *leftedge;
openfile->current_x = proper_x(openfile->current, leftedge, forward,
actual_last_column(*leftedge, target), &shifted);
/* If the index was incremented, try going to the target column. */
if (shifted || *leftedge < was_edge)
openfile->current_x = proper_x(openfile->current, leftedge, forward,
actual_last_column(*leftedge, target), &shifted);
actual_last_column(*leftedge, target), &shifted);
openfile->placewewant = *leftedge + target;
/* If the index was incremented, try going to the target column. */
if (shifted || *leftedge < was_edge)
openfile->current_x = proper_x(openfile->current, leftedge, forward,
actual_last_column(*leftedge, target), &shifted);
openfile->placewewant = *leftedge + target;
}
/* Move up nearly one screenful. */
void do_page_up(void)
{
int mustmove = (editwinrows < 3) ? 1 : editwinrows - 2;
size_t leftedge, target_column;
int mustmove = (editwinrows < 3) ? 1 : editwinrows - 2;
size_t leftedge, target_column;
/* If we're not in smooth scrolling mode, put the cursor at the
* beginning of the top line of the edit window, as Pico does. */
if (!ISSET(SMOOTH_SCROLL)) {
openfile->current = openfile->edittop;
leftedge = openfile->firstcolumn;
openfile->current_y = 0;
target_column = 0;
} else
get_edge_and_target(&leftedge, &target_column);
/* If we're not in smooth scrolling mode, put the cursor at the
* beginning of the top line of the edit window, as Pico does. */
if (!ISSET(SMOOTH_SCROLL)) {
openfile->current = openfile->edittop;
leftedge = openfile->firstcolumn;
openfile->current_y = 0;
target_column = 0;
} else
get_edge_and_target(&leftedge, &target_column);
/* Move up the required number of lines or chunks. If we can't, we're
* at the top of the file, so put the cursor there and get out. */
if (go_back_chunks(mustmove, &openfile->current, &leftedge) > 0) {
to_first_line();
return;
}
/* Move up the required number of lines or chunks. If we can't, we're
* at the top of the file, so put the cursor there and get out. */
if (go_back_chunks(mustmove, &openfile->current, &leftedge) > 0) {
to_first_line();
return;
}
set_proper_index_and_pww(&leftedge, target_column, FALSE);
set_proper_index_and_pww(&leftedge, target_column, FALSE);
/* Move the viewport so that the cursor stays immobile, if possible. */
adjust_viewport(STATIONARY);
refresh_needed = TRUE;
/* Move the viewport so that the cursor stays immobile, if possible. */
adjust_viewport(STATIONARY);
refresh_needed = TRUE;
}
/* Move down nearly one screenful. */
void do_page_down(void)
{
int mustmove = (editwinrows < 3) ? 1 : editwinrows - 2;
size_t leftedge, target_column;
int mustmove = (editwinrows < 3) ? 1 : editwinrows - 2;
size_t leftedge, target_column;
/* If we're not in smooth scrolling mode, put the cursor at the
* beginning of the top line of the edit window, as Pico does. */
if (!ISSET(SMOOTH_SCROLL)) {
openfile->current = openfile->edittop;
leftedge = openfile->firstcolumn;
openfile->current_y = 0;
target_column = 0;
} else
get_edge_and_target(&leftedge, &target_column);
/* If we're not in smooth scrolling mode, put the cursor at the
* beginning of the top line of the edit window, as Pico does. */
if (!ISSET(SMOOTH_SCROLL)) {
openfile->current = openfile->edittop;
leftedge = openfile->firstcolumn;
openfile->current_y = 0;
target_column = 0;
} else
get_edge_and_target(&leftedge, &target_column);
/* Move down the required number of lines or chunks. If we can't, we're
* at the bottom of the file, so put the cursor there and get out. */
if (go_forward_chunks(mustmove, &openfile->current, &leftedge) > 0) {
to_last_line();
return;
}
/* Move down the required number of lines or chunks. If we can't, we're
* at the bottom of the file, so put the cursor there and get out. */
if (go_forward_chunks(mustmove, &openfile->current, &leftedge) > 0) {
to_last_line();
return;
}
set_proper_index_and_pww(&leftedge, target_column, TRUE);
set_proper_index_and_pww(&leftedge, target_column, TRUE);
/* Move the viewport so that the cursor stays immobile, if possible. */
adjust_viewport(STATIONARY);
refresh_needed = TRUE;
/* Move the viewport so that the cursor stays immobile, if possible. */
adjust_viewport(STATIONARY);
refresh_needed = TRUE;
}
#ifdef ENABLE_JUSTIFY
@ -174,18 +174,18 @@ void do_page_down(void)
* current line. If update_screen is TRUE, update the screen afterwards. */
void do_para_begin(bool update_screen)
{
filestruct *was_current = openfile->current;
filestruct *was_current = openfile->current;
if (openfile->current != openfile->fileage)
openfile->current = openfile->current->prev;
if (openfile->current != openfile->fileage)
openfile->current = openfile->current->prev;
while (!begpar(openfile->current))
openfile->current = openfile->current->prev;
while (!begpar(openfile->current))
openfile->current = openfile->current->prev;
openfile->current_x = 0;
openfile->current_x = 0;
if (update_screen)
edit_redraw(was_current, CENTERING);
if (update_screen)
edit_redraw(was_current, CENTERING);
}
/* Move down to the beginning of the last line of the current paragraph.
@ -196,122 +196,122 @@ void do_para_begin(bool update_screen)
* paragraph or isn't in a paragraph. */
void do_para_end(bool update_screen)
{
filestruct *was_current = openfile->current;
filestruct *was_current = openfile->current;
while (openfile->current != openfile->filebot &&
!inpar(openfile->current))
openfile->current = openfile->current->next;
while (openfile->current != openfile->filebot &&
!inpar(openfile->current))
openfile->current = openfile->current->next;
while (openfile->current != openfile->filebot &&
inpar(openfile->current->next) &&
!begpar(openfile->current->next)) {
openfile->current = openfile->current->next;
}
while (openfile->current != openfile->filebot &&
inpar(openfile->current->next) &&
!begpar(openfile->current->next)) {
openfile->current = openfile->current->next;
}
if (openfile->current != openfile->filebot) {
openfile->current = openfile->current->next;
openfile->current_x = 0;
} else
openfile->current_x = strlen(openfile->current->data);
if (openfile->current != openfile->filebot) {
openfile->current = openfile->current->next;
openfile->current_x = 0;
} else
openfile->current_x = strlen(openfile->current->data);
if (update_screen)
edit_redraw(was_current, CENTERING);
if (update_screen)
edit_redraw(was_current, CENTERING);
}
/* Move up to first start of a paragraph before the current line. */
void do_para_begin_void(void)
{
do_para_begin(TRUE);
do_para_begin(TRUE);
}
/* Move down to just after the first end of a paragraph. */
void do_para_end_void(void)
{
do_para_end(TRUE);
do_para_end(TRUE);
}
#endif /* ENABLE_JUSTIFY */
/* Move to the preceding block of text. */
void do_prev_block(void)
{
filestruct *was_current = openfile->current;
bool is_text = FALSE, seen_text = FALSE;
filestruct *was_current = openfile->current;
bool is_text = FALSE, seen_text = FALSE;
/* Skip backward until first blank line after some nonblank line(s). */
while (openfile->current->prev != NULL && (!seen_text || is_text)) {
openfile->current = openfile->current->prev;
is_text = !white_string(openfile->current->data);
seen_text = seen_text || is_text;
}
/* Skip backward until first blank line after some nonblank line(s). */
while (openfile->current->prev != NULL && (!seen_text || is_text)) {
openfile->current = openfile->current->prev;
is_text = !white_string(openfile->current->data);
seen_text = seen_text || is_text;
}
/* Step forward one line again if this one is blank. */
if (openfile->current->next != NULL &&
white_string(openfile->current->data))
openfile->current = openfile->current->next;
/* Step forward one line again if this one is blank. */
if (openfile->current->next != NULL &&
white_string(openfile->current->data))
openfile->current = openfile->current->next;
openfile->current_x = 0;
edit_redraw(was_current, CENTERING);
openfile->current_x = 0;
edit_redraw(was_current, CENTERING);
}
/* Move to the next block of text. */
void do_next_block(void)
{
filestruct *was_current = openfile->current;
bool is_white = white_string(openfile->current->data);
bool seen_white = is_white;
filestruct *was_current = openfile->current;
bool is_white = white_string(openfile->current->data);
bool seen_white = is_white;
/* Skip forward until first nonblank line after some blank line(s). */
while (openfile->current->next != NULL && (!seen_white || is_white)) {
openfile->current = openfile->current->next;
is_white = white_string(openfile->current->data);
seen_white = seen_white || is_white;
}
/* Skip forward until first nonblank line after some blank line(s). */
while (openfile->current->next != NULL && (!seen_white || is_white)) {
openfile->current = openfile->current->next;
is_white = white_string(openfile->current->data);
seen_white = seen_white || is_white;
}
openfile->current_x = 0;
edit_redraw(was_current, CENTERING);
openfile->current_x = 0;
edit_redraw(was_current, CENTERING);
}
/* Move to the previous word. If allow_punct is TRUE, treat punctuation
* as part of a word. When requested, update the screen afterwards. */
void do_prev_word(bool allow_punct, bool update_screen)
{
filestruct *was_current = openfile->current;
bool seen_a_word = FALSE, step_forward = FALSE;
filestruct *was_current = openfile->current;
bool seen_a_word = FALSE, step_forward = FALSE;
/* Move backward until we pass over the start of a word. */
while (TRUE) {
/* If at the head of a line, move to the end of the preceding one. */
if (openfile->current_x == 0) {
if (openfile->current->prev == NULL)
break;
openfile->current = openfile->current->prev;
openfile->current_x = strlen(openfile->current->data);
/* Move backward until we pass over the start of a word. */
while (TRUE) {
/* If at the head of a line, move to the end of the preceding one. */
if (openfile->current_x == 0) {
if (openfile->current->prev == NULL)
break;
openfile->current = openfile->current->prev;
openfile->current_x = strlen(openfile->current->data);
}
/* Step back one character. */
openfile->current_x = move_mbleft(openfile->current->data,
openfile->current_x);
if (is_word_mbchar(openfile->current->data + openfile->current_x,
allow_punct)) {
seen_a_word = TRUE;
/* If at the head of a line now, this surely is a word start. */
if (openfile->current_x == 0)
break;
} else if (seen_a_word) {
/* This is space now: we've overshot the start of the word. */
step_forward = TRUE;
break;
}
}
/* Step back one character. */
openfile->current_x = move_mbleft(openfile->current->data,
openfile->current_x);
if (step_forward)
/* Move one character forward again to sit on the start of the word. */
openfile->current_x = move_mbright(openfile->current->data,
openfile->current_x);
if (is_word_mbchar(openfile->current->data + openfile->current_x,
allow_punct)) {
seen_a_word = TRUE;
/* If at the head of a line now, this surely is a word start. */
if (openfile->current_x == 0)
break;
} else if (seen_a_word) {
/* This is space now: we've overshot the start of the word. */
step_forward = TRUE;
break;
}
}
if (step_forward)
/* Move one character forward again to sit on the start of the word. */
openfile->current_x = move_mbright(openfile->current->data,
openfile->current_x);
if (update_screen)
edit_redraw(was_current, FLOWING);
if (update_screen)
edit_redraw(was_current, FLOWING);
}
/* Move to the next word. If allow_punct is TRUE, treat punctuation
@ -319,55 +319,55 @@ void do_prev_word(bool allow_punct, bool update_screen)
* Return TRUE if we started on a word, and FALSE otherwise. */
bool do_next_word(bool allow_punct, bool update_screen)
{
filestruct *was_current = openfile->current;
bool started_on_word = is_word_mbchar(openfile->current->data +
openfile->current_x, allow_punct);
bool seen_space = !started_on_word;
filestruct *was_current = openfile->current;
bool started_on_word = is_word_mbchar(openfile->current->data +
openfile->current_x, allow_punct);
bool seen_space = !started_on_word;
/* Move forward until we reach the start of a word. */
while (TRUE) {
/* If at the end of a line, move to the beginning of the next one. */
if (openfile->current->data[openfile->current_x] == '\0') {
/* When at end of file, stop. */
if (openfile->current->next == NULL)
break;
openfile->current = openfile->current->next;
openfile->current_x = 0;
seen_space = TRUE;
} else {
/* Step forward one character. */
openfile->current_x = move_mbright(openfile->current->data,
openfile->current_x);
/* Move forward until we reach the start of a word. */
while (TRUE) {
/* If at the end of a line, move to the beginning of the next one. */
if (openfile->current->data[openfile->current_x] == '\0') {
/* When at end of file, stop. */
if (openfile->current->next == NULL)
break;
openfile->current = openfile->current->next;
openfile->current_x = 0;
seen_space = TRUE;
} else {
/* Step forward one character. */
openfile->current_x = move_mbright(openfile->current->data,
openfile->current_x);
}
/* If this is not a word character, then it's a separator; else
* if we've already seen a separator, then it's a word start. */
if (!is_word_mbchar(openfile->current->data + openfile->current_x,
allow_punct))
seen_space = TRUE;
else if (seen_space)
break;
}
/* If this is not a word character, then it's a separator; else
* if we've already seen a separator, then it's a word start. */
if (!is_word_mbchar(openfile->current->data + openfile->current_x,
allow_punct))
seen_space = TRUE;
else if (seen_space)
break;
}
if (update_screen)
edit_redraw(was_current, FLOWING);
if (update_screen)
edit_redraw(was_current, FLOWING);
/* Return whether we started on a word. */
return started_on_word;
/* Return whether we started on a word. */
return started_on_word;
}
/* Move to the previous word in the file, treating punctuation as part of a
* word if the WORD_BOUNDS flag is set, and update the screen afterwards. */
void do_prev_word_void(void)
{
do_prev_word(ISSET(WORD_BOUNDS), TRUE);
do_prev_word(ISSET(WORD_BOUNDS), TRUE);
}
/* Move to the next word in the file, treating punctuation as part of a word
* if the WORD_BOUNDS flag is set, and update the screen afterwards. */
void do_next_word_void(void)
{
do_next_word(ISSET(WORD_BOUNDS), TRUE);
do_next_word(ISSET(WORD_BOUNDS), TRUE);
}
/* Move to the beginning of the current line (or softwrapped chunk).
@ -375,59 +375,59 @@ void do_next_word_void(void)
* of the full line when already at the start of a chunk. */
void do_home(void)
{
filestruct *was_current = openfile->current;
size_t was_column = xplustabs();
bool moved_off_chunk = TRUE;
filestruct *was_current = openfile->current;
size_t was_column = xplustabs();
bool moved_off_chunk = TRUE;
#ifndef NANO_TINY
bool moved = FALSE;
size_t leftedge = 0, leftedge_x = 0;
bool moved = FALSE;
size_t leftedge = 0, leftedge_x = 0;
if (ISSET(SOFTWRAP)) {
leftedge = leftedge_for(was_column, openfile->current);
leftedge_x = proper_x(openfile->current, &leftedge, FALSE, leftedge,
NULL);
}
if (ISSET(SMART_HOME)) {
size_t indent_x = indent_length(openfile->current->data);
if (openfile->current->data[indent_x] != '\0') {
/* If we're exactly on the indent, move fully home. Otherwise,
* when not softwrapping or not after the first nonblank chunk,
* move to the first nonblank character. */
if (openfile->current_x == indent_x) {
openfile->current_x = 0;
moved = TRUE;
} else if (!ISSET(SOFTWRAP) || leftedge_x <= indent_x) {
openfile->current_x = indent_x;
moved = TRUE;
}
if (ISSET(SOFTWRAP)) {
leftedge = leftedge_for(was_column, openfile->current);
leftedge_x = proper_x(openfile->current, &leftedge, FALSE, leftedge,
NULL);
}
}
if (!moved && ISSET(SOFTWRAP)) {
/* If already at the left edge of the screen, move fully home.
* Otherwise, move to the left edge. */
if (openfile->current_x == leftedge_x)
openfile->current_x = 0;
else {
openfile->current_x = leftedge_x;
openfile->placewewant = leftedge;
moved_off_chunk = FALSE;
if (ISSET(SMART_HOME)) {
size_t indent_x = indent_length(openfile->current->data);
if (openfile->current->data[indent_x] != '\0') {
/* If we're exactly on the indent, move fully home. Otherwise,
* when not softwrapping or not after the first nonblank chunk,
* move to the first nonblank character. */
if (openfile->current_x == indent_x) {
openfile->current_x = 0;
moved = TRUE;
} else if (!ISSET(SOFTWRAP) || leftedge_x <= indent_x) {
openfile->current_x = indent_x;
moved = TRUE;
}
}
}
} else if (!moved)
if (!moved && ISSET(SOFTWRAP)) {
/* If already at the left edge of the screen, move fully home.
* Otherwise, move to the left edge. */
if (openfile->current_x == leftedge_x)
openfile->current_x = 0;
else {
openfile->current_x = leftedge_x;
openfile->placewewant = leftedge;
moved_off_chunk = FALSE;
}
} else if (!moved)
#endif
openfile->current_x = 0;
openfile->current_x = 0;
if (moved_off_chunk)
openfile->placewewant = xplustabs();
if (moved_off_chunk)
openfile->placewewant = xplustabs();
/* If we changed chunk, we might be offscreen. Otherwise,
* update current if the mark is on or we changed "page". */
if (ISSET(SOFTWRAP) && moved_off_chunk)
edit_redraw(was_current, FLOWING);
else if (line_needs_update(was_column, openfile->placewewant))
update_line(openfile->current, openfile->current_x);
/* If we changed chunk, we might be offscreen. Otherwise,
* update current if the mark is on or we changed "page". */
if (ISSET(SOFTWRAP) && moved_off_chunk)
edit_redraw(was_current, FLOWING);
else if (line_needs_update(was_column, openfile->placewewant))
update_line(openfile->current, openfile->current_x);
}
/* Move to the end of the current line (or softwrapped chunk).
@ -435,159 +435,159 @@ void do_home(void)
* end of the full line. */
void do_end(void)
{
filestruct *was_current = openfile->current;
size_t was_column = xplustabs();
size_t line_len = strlen(openfile->current->data);
bool moved_off_chunk = TRUE;
filestruct *was_current = openfile->current;
size_t was_column = xplustabs();
size_t line_len = strlen(openfile->current->data);
bool moved_off_chunk = TRUE;
#ifndef NANO_TINY
if (ISSET(SOFTWRAP)) {
bool last_chunk = FALSE;
size_t leftedge = leftedge_for(was_column, openfile->current);
size_t rightedge = get_softwrap_breakpoint(openfile->current->data,
leftedge, &last_chunk);
size_t rightedge_x;
if (ISSET(SOFTWRAP)) {
bool last_chunk = FALSE;
size_t leftedge = leftedge_for(was_column, openfile->current);
size_t rightedge = get_softwrap_breakpoint(openfile->current->data,
leftedge, &last_chunk);
size_t rightedge_x;
/* If we're on the last chunk, we're already at the end of the line.
* Otherwise, we're one column past the end of the line. Shifting
* backwards one column might put us in the middle of a multi-column
* character, but actual_x() will fix that. */
if (!last_chunk)
rightedge--;
/* If we're on the last chunk, we're already at the end of the line.
* Otherwise, we're one column past the end of the line. Shifting
* backwards one column might put us in the middle of a multi-column
* character, but actual_x() will fix that. */
if (!last_chunk)
rightedge--;
rightedge_x = actual_x(openfile->current->data, rightedge);
rightedge_x = actual_x(openfile->current->data, rightedge);
/* If already at the right edge of the screen, move fully to
* the end of the line. Otherwise, move to the right edge. */
if (openfile->current_x == rightedge_x)
openfile->current_x = line_len;
else {
openfile->current_x = rightedge_x;
openfile->placewewant = rightedge;
moved_off_chunk = FALSE;
}
} else
/* If already at the right edge of the screen, move fully to
* the end of the line. Otherwise, move to the right edge. */
if (openfile->current_x == rightedge_x)
openfile->current_x = line_len;
else {
openfile->current_x = rightedge_x;
openfile->placewewant = rightedge;
moved_off_chunk = FALSE;
}
} else
#endif
openfile->current_x = line_len;
openfile->current_x = line_len;
if (moved_off_chunk)
openfile->placewewant = xplustabs();
if (moved_off_chunk)
openfile->placewewant = xplustabs();
/* If we changed chunk, we might be offscreen. Otherwise,
* update current if the mark is on or we changed "page". */
if (ISSET(SOFTWRAP) && moved_off_chunk)
edit_redraw(was_current, FLOWING);
else if (line_needs_update(was_column, openfile->placewewant))
update_line(openfile->current, openfile->current_x);
/* If we changed chunk, we might be offscreen. Otherwise,
* update current if the mark is on or we changed "page". */
if (ISSET(SOFTWRAP) && moved_off_chunk)
edit_redraw(was_current, FLOWING);
else if (line_needs_update(was_column, openfile->placewewant))
update_line(openfile->current, openfile->current_x);
}
/* Move the cursor to the preceding line or chunk. If scroll_only is TRUE,
* also scroll the screen one row, so the cursor stays in the same spot. */
void do_up(bool scroll_only)
{
filestruct *was_current = openfile->current;
size_t leftedge, target_column;
filestruct *was_current = openfile->current;
size_t leftedge, target_column;
/* When just scrolling and the top of the file is onscreen, get out. */
if (scroll_only && openfile->edittop == openfile->fileage &&
openfile->firstcolumn == 0)
return;
/* When just scrolling and the top of the file is onscreen, get out. */
if (scroll_only && openfile->edittop == openfile->fileage &&
openfile->firstcolumn == 0)
return;
get_edge_and_target(&leftedge, &target_column);
get_edge_and_target(&leftedge, &target_column);
/* If we can't move up one line or chunk, we're at top of file. */
if (go_back_chunks(1, &openfile->current, &leftedge) > 0)
return;
/* If we can't move up one line or chunk, we're at top of file. */
if (go_back_chunks(1, &openfile->current, &leftedge) > 0)
return;
set_proper_index_and_pww(&leftedge, target_column, FALSE);
set_proper_index_and_pww(&leftedge, target_column, FALSE);
if (scroll_only)
edit_scroll(BACKWARD, 1);
if (scroll_only)
edit_scroll(BACKWARD, 1);
edit_redraw(was_current, FLOWING);
edit_redraw(was_current, FLOWING);
/* <Up> should not change placewewant, so restore it. */
openfile->placewewant = leftedge + target_column;
/* <Up> should not change placewewant, so restore it. */
openfile->placewewant = leftedge + target_column;
}
/* Move the cursor to next line or chunk. If scroll_only is TRUE, also
* scroll the screen one row, so the cursor stays in the same spot. */
void do_down(bool scroll_only)
{
filestruct *was_current = openfile->current;
size_t leftedge, target_column;
filestruct *was_current = openfile->current;
size_t leftedge, target_column;
get_edge_and_target(&leftedge, &target_column);
get_edge_and_target(&leftedge, &target_column);
/* If we can't move down one line or chunk, we're at bottom of file. */
if (go_forward_chunks(1, &openfile->current, &leftedge) > 0)
return;
/* If we can't move down one line or chunk, we're at bottom of file. */
if (go_forward_chunks(1, &openfile->current, &leftedge) > 0)
return;
set_proper_index_and_pww(&leftedge, target_column, TRUE);
set_proper_index_and_pww(&leftedge, target_column, TRUE);
if (scroll_only)
edit_scroll(FORWARD, 1);
if (scroll_only)
edit_scroll(FORWARD, 1);
edit_redraw(was_current, FLOWING);
edit_redraw(was_current, FLOWING);
/* <Down> should not change placewewant, so restore it. */
openfile->placewewant = leftedge + target_column;
/* <Down> should not change placewewant, so restore it. */
openfile->placewewant = leftedge + target_column;
}
/* Move up one line or chunk. */
void do_up_void(void)
{
do_up(FALSE);
do_up(FALSE);
}
/* Move down one line or chunk. */
void do_down_void(void)
{
do_down(FALSE);
do_down(FALSE);
}
#ifndef NANO_TINY
/* Scroll up one line or chunk without scrolling the cursor. */
void do_scroll_up(void)
{
do_up(TRUE);
do_up(TRUE);
}
/* Scroll down one line or chunk without scrolling the cursor. */
void do_scroll_down(void)
{
do_down(TRUE);
do_down(TRUE);
}
#endif
/* Move left one character. */
void do_left(void)
{
filestruct *was_current = openfile->current;
filestruct *was_current = openfile->current;
if (openfile->current_x > 0)
openfile->current_x = move_mbleft(openfile->current->data,
openfile->current_x);
else if (openfile->current != openfile->fileage) {
openfile->current = openfile->current->prev;
openfile->current_x = strlen(openfile->current->data);
}
if (openfile->current_x > 0)
openfile->current_x = move_mbleft(openfile->current->data,
openfile->current_x);
else if (openfile->current != openfile->fileage) {
openfile->current = openfile->current->prev;
openfile->current_x = strlen(openfile->current->data);
}
edit_redraw(was_current, FLOWING);
edit_redraw(was_current, FLOWING);
}
/* Move right one character. */
void do_right(void)
{
filestruct *was_current = openfile->current;
filestruct *was_current = openfile->current;
if (openfile->current->data[openfile->current_x] != '\0')
openfile->current_x = move_mbright(openfile->current->data,
openfile->current_x);
else if (openfile->current != openfile->filebot) {
openfile->current = openfile->current->next;
openfile->current_x = 0;
}
if (openfile->current->data[openfile->current_x] != '\0')
openfile->current_x = move_mbright(openfile->current->data,
openfile->current_x);
else if (openfile->current != openfile->filebot) {
openfile->current = openfile->current->next;
openfile->current_x = 0;
}
edit_redraw(was_current, FLOWING);
edit_redraw(was_current, FLOWING);
}

3260
src/nano.c

File diff suppressed because it is too large Load Diff

View File

@ -111,7 +111,7 @@
#endif
#define gettext_noop(string) (string)
#define N_(string) gettext_noop(string)
/* Mark a string that will be sent to gettext() later. */
/* Mark a string that will be sent to gettext() later. */
#include <stddef.h>
#include <stdlib.h>
@ -144,393 +144,393 @@
/* Enumeration types. */
typedef enum {
NIX_FILE, DOS_FILE, MAC_FILE
NIX_FILE, DOS_FILE, MAC_FILE
} file_format;
typedef enum {
HUSH, MILD, ALERT
HUSH, MILD, ALERT
} message_type;
typedef enum {
OVERWRITE, APPEND, PREPEND
OVERWRITE, APPEND, PREPEND
} kind_of_writing_type;
typedef enum {
SOFTMARK, HARDMARK
SOFTMARK, HARDMARK
} mark_type;
typedef enum {
CENTERING, FLOWING, STATIONARY
CENTERING, FLOWING, STATIONARY
} update_type;
typedef enum {
ADD, DEL, BACK, CUT, CUT_TO_EOF, REPLACE,
ADD, DEL, BACK, CUT, CUT_TO_EOF, REPLACE,
#ifdef ENABLE_WRAPPING
SPLIT_BEGIN, SPLIT_END,
SPLIT_BEGIN, SPLIT_END,
#endif
INDENT, UNINDENT,
INDENT, UNINDENT,
#ifdef ENABLE_COMMENT
COMMENT, UNCOMMENT, PREFLIGHT,
COMMENT, UNCOMMENT, PREFLIGHT,
#endif
JOIN, PASTE, INSERT, ENTER, OTHER
JOIN, PASTE, INSERT, ENTER, OTHER
} undo_type;
/* Structure types. */
#ifdef ENABLE_COLOR
typedef struct colortype {
short fg;
/* This syntax's foreground color. */
short bg;
/* This syntax's background color. */
bool bright;
/* Is this color A_BOLD? */
int pairnum;
/* The color pair number used for this foreground color and
* background color. */
int attributes;
/* Pair number and brightness composed into ready-to-use attributes. */
int rex_flags;
/* The regex compilation flags (with or without REG_ICASE). */
char *start_regex;
/* The start (or all) of the regex string. */
regex_t *start;
/* The compiled start (or all) of the regex string. */
char *end_regex;
/* The end (if any) of the regex string. */
regex_t *end;
/* The compiled end (if any) of the regex string. */
struct colortype *next;
/* Next set of colors. */
int id;
/* Basic id for assigning to lines later. */
short fg;
/* This syntax's foreground color. */
short bg;
/* This syntax's background color. */
bool bright;
/* Is this color A_BOLD? */
int pairnum;
/* The color pair number used for this foreground color and
* background color. */
int attributes;
/* Pair number and brightness composed into ready-to-use attributes. */
int rex_flags;
/* The regex compilation flags (with or without REG_ICASE). */
char *start_regex;
/* The start (or all) of the regex string. */
regex_t *start;
/* The compiled start (or all) of the regex string. */
char *end_regex;
/* The end (if any) of the regex string. */
regex_t *end;
/* The compiled end (if any) of the regex string. */
struct colortype *next;
/* Next set of colors. */
int id;
/* Basic id for assigning to lines later. */
} colortype;
typedef struct regexlisttype {
char *full_regex;
/* A regex string to match things that imply a certain syntax. */
struct regexlisttype *next;
/* The next regex. */
char *full_regex;
/* A regex string to match things that imply a certain syntax. */
struct regexlisttype *next;
/* The next regex. */
} regexlisttype;
typedef struct syntaxtype {
char *name;
/* The name of this syntax. */
regexlisttype *extensions;
/* The list of extensions that this syntax applies to. */
regexlisttype *headers;
/* The list of headerlines that this syntax applies to. */
regexlisttype *magics;
/* The list of libmagic results that this syntax applies to. */
char *linter;
/* The command with which to lint this type of file. */
char *formatter;
/* The formatting command (for programming languages mainly). */
char *name;
/* The name of this syntax. */
regexlisttype *extensions;
/* The list of extensions that this syntax applies to. */
regexlisttype *headers;
/* The list of headerlines that this syntax applies to. */
regexlisttype *magics;
/* The list of libmagic results that this syntax applies to. */
char *linter;
/* The command with which to lint this type of file. */
char *formatter;
/* The formatting command (for programming languages mainly). */
#ifdef ENABLE_COMMENT
char *comment;
/* The line comment prefix (and postfix) for this type of file. */
char *comment;
/* The line comment prefix (and postfix) for this type of file. */
#endif
colortype *color;
/* The colors and their regexes used in this syntax. */
int nmultis;
/* How many multiline regex strings this syntax has. */
struct syntaxtype *next;
/* Next syntax. */
colortype *color;
/* The colors and their regexes used in this syntax. */
int nmultis;
/* How many multiline regex strings this syntax has. */
struct syntaxtype *next;
/* Next syntax. */
} syntaxtype;
typedef struct lintstruct {
ssize_t lineno;
/* Line number of the error. */
ssize_t colno;
/* Column # of the error. */
char *msg;
/* Error message text. */
char *filename;
/* Filename. */
struct lintstruct *next;
/* Next error. */
struct lintstruct *prev;
/* Previous error. */
ssize_t lineno;
/* Line number of the error. */
ssize_t colno;
/* Column # of the error. */
char *msg;
/* Error message text. */
char *filename;
/* Filename. */
struct lintstruct *next;
/* Next error. */
struct lintstruct *prev;
/* Previous error. */
} lintstruct;
/* Flags that indicate how a multiline regex applies to a line. */
#define CNONE (1<<1)
/* Yay, regex doesn't apply to this line at all! */
/* Yay, regex doesn't apply to this line at all! */
#define CBEGINBEFORE (1<<2)
/* Regex starts on an earlier line, ends on this one. */
/* Regex starts on an earlier line, ends on this one. */
#define CENDAFTER (1<<3)
/* Regex starts on this line and ends on a later one. */
/* Regex starts on this line and ends on a later one. */
#define CWHOLELINE (1<<4)
/* Whole line engulfed by the regex, start < me, end > me. */
/* Whole line engulfed by the regex, start < me, end > me. */
#define CSTARTENDHERE (1<<5)
/* Regex starts and ends within this line. */
/* Regex starts and ends within this line. */
#define CWOULDBE (1<<6)
/* An unpaired start match on or before this line. */
/* An unpaired start match on or before this line. */
#endif /* ENABLE_COLOR */
/* More structure types. */
typedef struct filestruct {
char *data;
/* The text of this line. */
ssize_t lineno;
/* The number of this line. */
struct filestruct *next;
/* Next node. */
struct filestruct *prev;
/* Previous node. */
char *data;
/* The text of this line. */
ssize_t lineno;
/* The number of this line. */
struct filestruct *next;
/* Next node. */
struct filestruct *prev;
/* Previous node. */
#ifdef ENABLE_COLOR
short *multidata;
/* Array of which multi-line regexes apply to this line. */
short *multidata;
/* Array of which multi-line regexes apply to this line. */
#endif
} filestruct;
typedef struct partition {
filestruct *fileage;
/* The top line of this portion of the file. */
filestruct *top_prev;
/* The line before the top line of this portion of the file. */
char *top_data;
/* The text before the beginning of the top line of this portion
* of the file. */
filestruct *filebot;
/* The bottom line of this portion of the file. */
filestruct *bot_next;
/* The line after the bottom line of this portion of the
* file. */
char *bot_data;
/* The text after the end of the bottom line of this portion of
* the file. */
filestruct *fileage;
/* The top line of this portion of the file. */
filestruct *top_prev;
/* The line before the top line of this portion of the file. */
char *top_data;
/* The text before the beginning of the top line of this portion
* of the file. */
filestruct *filebot;
/* The bottom line of this portion of the file. */
filestruct *bot_next;
/* The line after the bottom line of this portion of the
* file. */
char *bot_data;
/* The text after the end of the bottom line of this portion of
* the file. */
} partition;
#ifndef NANO_TINY
typedef struct undo_group {
ssize_t top_line;
/* First line of group. */
ssize_t bottom_line;
/* Last line of group. */
char **indentations;
/* String data used to restore the affected lines; one per line. */
struct undo_group *next;
ssize_t top_line;
/* First line of group. */
ssize_t bottom_line;
/* Last line of group. */
char **indentations;
/* String data used to restore the affected lines; one per line. */
struct undo_group *next;
} undo_group;
typedef struct undo {
ssize_t lineno;
undo_type type;
/* What type of undo this was. */
size_t begin;
/* Where did this action begin or end. */
char *strdata;
/* String type data we will use for copying the affected line back. */
size_t wassize;
/* The file size before the action. */
size_t newsize;
/* The file size after the action. */
int xflags;
/* Some flag data we need. */
undo_group *grouping;
/* Undo info specific to groups of lines. */
ssize_t lineno;
undo_type type;
/* What type of undo this was. */
size_t begin;
/* Where did this action begin or end. */
char *strdata;
/* String type data we will use for copying the affected line back. */
size_t wassize;
/* The file size before the action. */
size_t newsize;
/* The file size after the action. */
int xflags;
/* Some flag data we need. */
undo_group *grouping;
/* Undo info specific to groups of lines. */
/* Cut-specific stuff we need. */
filestruct *cutbuffer;
/* Copy of the cutbuffer. */
filestruct *cutbottom;
/* Copy of cutbottom. */
ssize_t mark_begin_lineno;
/* Mostly the line number of the current line; sometimes something else. */
size_t mark_begin_x;
/* The x position corresponding to the above line number. */
struct undo *next;
/* A pointer to the undo item of the preceding action. */
/* Cut-specific stuff we need. */
filestruct *cutbuffer;
/* Copy of the cutbuffer. */
filestruct *cutbottom;
/* Copy of cutbottom. */
ssize_t mark_begin_lineno;
/* Mostly the line number of the current line; sometimes something else. */
size_t mark_begin_x;
/* The x position corresponding to the above line number. */
struct undo *next;
/* A pointer to the undo item of the preceding action. */
} undo;
#endif /* !NANO_TINY */
#ifdef ENABLE_HISTORIES
typedef struct poshiststruct {
char *filename;
/* The file. */
ssize_t lineno;
/* Line number we left off on. */
ssize_t xno;
/* x position in the file we left off on. */
struct poshiststruct *next;
char *filename;
/* The file. */
ssize_t lineno;
/* Line number we left off on. */
ssize_t xno;
/* x position in the file we left off on. */
struct poshiststruct *next;
} poshiststruct;
#endif
typedef struct openfilestruct {
char *filename;
/* The file's name. */
filestruct *fileage;
/* The file's first line. */
filestruct *filebot;
/* The file's last line. */
filestruct *edittop;
/* The current top of the edit window for this file. */
filestruct *current;
/* The current line for this file. */
size_t totsize;
/* The file's total number of characters. */
size_t firstcolumn;
/* The starting column of the top line of the edit window.
* When not in softwrap mode, it's always zero. */
size_t current_x;
/* The file's x-coordinate position. */
size_t placewewant;
/* The file's x position we would like. */
ssize_t current_y;
/* The file's y-coordinate position. */
bool modified;
/* Whether the file has been modified. */
struct stat *current_stat;
/* The file's current stat information. */
char *filename;
/* The file's name. */
filestruct *fileage;
/* The file's first line. */
filestruct *filebot;
/* The file's last line. */
filestruct *edittop;
/* The current top of the edit window for this file. */
filestruct *current;
/* The current line for this file. */
size_t totsize;
/* The file's total number of characters. */
size_t firstcolumn;
/* The starting column of the top line of the edit window.
* When not in softwrap mode, it's always zero. */
size_t current_x;
/* The file's x-coordinate position. */
size_t placewewant;
/* The file's x position we would like. */
ssize_t current_y;
/* The file's y-coordinate position. */
bool modified;
/* Whether the file has been modified. */
struct stat *current_stat;
/* The file's current stat information. */
#ifndef NANO_TINY
filestruct *mark;
/* The line in the file where the mark is set; NULL if not set. */
size_t mark_x;
/* The mark's x position in the above line. */
mark_type kind_of_mark;
/* Whether it is a soft (with Shift) or a hard mark. */
file_format fmt;
/* The file's format -- Unix or DOS or Mac or mixed. */
undo *undotop;
/* The top of the undo list. */
undo *current_undo;
/* The current (i.e. next) level of undo. */
undo *last_saved;
/* The undo item at which the file was last saved. */
undo_type last_action;
/* The type of the last action the user performed. */
char *lock_filename;
/* The path of the lockfile, if we created one. */
filestruct *mark;
/* The line in the file where the mark is set; NULL if not set. */
size_t mark_x;
/* The mark's x position in the above line. */
mark_type kind_of_mark;
/* Whether it is a soft (with Shift) or a hard mark. */
file_format fmt;
/* The file's format -- Unix or DOS or Mac or mixed. */
undo *undotop;
/* The top of the undo list. */
undo *current_undo;
/* The current (i.e. next) level of undo. */
undo *last_saved;
/* The undo item at which the file was last saved. */
undo_type last_action;
/* The type of the last action the user performed. */
char *lock_filename;
/* The path of the lockfile, if we created one. */
#endif
#ifdef ENABLE_COLOR
syntaxtype *syntax;
/* The syntax struct for this file, if any. */
colortype *colorstrings;
/* The file's associated colors. */
syntaxtype *syntax;
/* The syntax struct for this file, if any. */
colortype *colorstrings;
/* The file's associated colors. */
#endif
struct openfilestruct *next;
/* The next open file, if any. */
struct openfilestruct *prev;
/* The preceding open file, if any. */
struct openfilestruct *next;
/* The next open file, if any. */
struct openfilestruct *prev;
/* The preceding open file, if any. */
} openfilestruct;
#ifdef ENABLE_NANORC
typedef struct rcoption {
const char *name;
/* The name of the rcfile option. */
long flag;
/* The flag associated with it, if any. */
const char *name;
/* The name of the rcfile option. */
long flag;
/* The flag associated with it, if any. */
} rcoption;
#endif
typedef struct sc {
const char *keystr;
/* The string that describes a keystroke, like "^C" or "M-R". */
bool meta;
/* Whether this is a Meta keystroke. */
int keycode;
/* The integer that, together with meta, identifies the keystroke. */
int menus;
/* Which menus this applies to. */
void (*scfunc)(void);
/* The function we're going to run. */
const char *keystr;
/* The string that describes a keystroke, like "^C" or "M-R". */
bool meta;
/* Whether this is a Meta keystroke. */
int keycode;
/* The integer that, together with meta, identifies the keystroke. */
int menus;
/* Which menus this applies to. */
void (*scfunc)(void);
/* The function we're going to run. */
#ifndef NANO_TINY
int toggle;
/* If a toggle, what we're toggling. */
int ordinal;
/* The how-manieth toggle this is, in order to be able to
* keep them in sequence. */
int toggle;
/* If a toggle, what we're toggling. */
int ordinal;
/* The how-manieth toggle this is, in order to be able to
* keep them in sequence. */
#endif
struct sc *next;
/* Next in the list. */
struct sc *next;
/* Next in the list. */
} sc;
typedef struct subnfunc {
void (*scfunc)(void);
/* The actual function to call. */
int menus;
/* In what menus this function applies. */
const char *desc;
/* The function's short description, for example "Where Is". */
void (*scfunc)(void);
/* The actual function to call. */
int menus;
/* In what menus this function applies. */
const char *desc;
/* The function's short description, for example "Where Is". */
#ifdef ENABLE_HELP
const char *help;
/* The help-screen text for this function. */
bool blank_after;
/* Whether there should be a blank line after the help text
* for this function. */
const char *help;
/* The help-screen text for this function. */
bool blank_after;
/* Whether there should be a blank line after the help text
* for this function. */
#endif
bool viewok;
/* Is this function allowed when in view mode? */
long toggle;
/* If this is a toggle, which toggle to affect. */
struct subnfunc *next;
/* Next item in the list. */
bool viewok;
/* Is this function allowed when in view mode? */
long toggle;
/* If this is a toggle, which toggle to affect. */
struct subnfunc *next;
/* Next item in the list. */
} subnfunc;
#ifdef ENABLE_WORDCOMPLETION
typedef struct completion_word {
char *word;
struct completion_word *next;
char *word;
struct completion_word *next;
} completion_word;
#endif
/* The elements of the interface that can be colored differently. */
enum
{
TITLE_BAR = 0,
LINE_NUMBER,
SELECTED_TEXT,
STATUS_BAR,
KEY_COMBO,
FUNCTION_TAG,
NUMBER_OF_ELEMENTS
TITLE_BAR = 0,
LINE_NUMBER,
SELECTED_TEXT,
STATUS_BAR,
KEY_COMBO,
FUNCTION_TAG,
NUMBER_OF_ELEMENTS
};
/* Enumeration used in the flags array. See the definition of FLAGMASK. */
enum
{
DONTUSE,
CASE_SENSITIVE,
CONSTANT_SHOW,
NO_HELP,
SUSPEND,
NO_WRAP,
AUTOINDENT,
VIEW_MODE,
USE_MOUSE,
USE_REGEXP,
TEMP_FILE,
CUT_FROM_CURSOR,
BACKWARDS_SEARCH,
MULTIBUFFER,
SMOOTH_SCROLL,
REBIND_DELETE,
REBIND_KEYPAD,
NO_CONVERT,
BACKUP_FILE,
INSECURE_BACKUP,
NO_COLOR_SYNTAX,
PRESERVE,
HISTORYLOG,
RESTRICTED,
SMART_HOME,
WHITESPACE_DISPLAY,
MORE_SPACE,
TABS_TO_SPACES,
QUICK_BLANK,
WORD_BOUNDS,
NO_NEWLINES,
BOLD_TEXT,
QUIET,
SOFTWRAP,
POS_HISTORY,
LOCKING,
NOREAD_MODE,
MAKE_IT_UNIX,
TRIM_BLANKS,
SHOW_CURSOR,
LINE_NUMBERS,
NO_PAUSES,
AT_BLANKS
DONTUSE,
CASE_SENSITIVE,
CONSTANT_SHOW,
NO_HELP,
SUSPEND,
NO_WRAP,
AUTOINDENT,
VIEW_MODE,
USE_MOUSE,
USE_REGEXP,
TEMP_FILE,
CUT_FROM_CURSOR,
BACKWARDS_SEARCH,
MULTIBUFFER,
SMOOTH_SCROLL,
REBIND_DELETE,
REBIND_KEYPAD,
NO_CONVERT,
BACKUP_FILE,
INSECURE_BACKUP,
NO_COLOR_SYNTAX,
PRESERVE,
HISTORYLOG,
RESTRICTED,
SMART_HOME,
WHITESPACE_DISPLAY,
MORE_SPACE,
TABS_TO_SPACES,
QUICK_BLANK,
WORD_BOUNDS,
NO_NEWLINES,
BOLD_TEXT,
QUIET,
SOFTWRAP,
POS_HISTORY,
LOCKING,
NOREAD_MODE,
MAKE_IT_UNIX,
TRIM_BLANKS,
SHOW_CURSOR,
LINE_NUMBERS,
NO_PAUSES,
AT_BLANKS
};
/* Flags for the menus in which a given function should be present. */
@ -552,7 +552,7 @@ enum
#define MFINDINHELP (1<<15)
/* This is an abbreviation for all menus except Help and YesNo. */
#define MMOST (MMAIN|MWHEREIS|MREPLACE|MREPLACEWITH|MGOTOLINE|MWRITEFILE|MINSERTFILE|\
MEXTCMD|MBROWSER|MWHEREISFILE|MGOTODIR|MFINDINHELP|MSPELL|MLINTER)
MEXTCMD|MBROWSER|MWHEREISFILE|MGOTODIR|MFINDINHELP|MSPELL|MLINTER)
#ifndef NANO_TINY
#define MSOME MMOST
#else

File diff suppressed because it is too large Load Diff

View File

@ -272,7 +272,7 @@ bool open_buffer(const char *filename, bool undoable);
void replace_buffer(const char *filename);
#ifndef NANO_TINY
void replace_marked_buffer(const char *filename, filestruct *top, size_t top_x,
filestruct *bot, size_t bot_x);
filestruct *bot, size_t bot_x);
#endif
#endif
void prepare_for_display(void);
@ -282,7 +282,7 @@ void switch_to_next_buffer(void);
bool close_buffer(void);
#endif
void read_file(FILE *f, int fd, const char *filename, bool undoable,
bool checkwritable);
bool checkwritable);
int open_file(const char *filename, bool newfie, bool quiet, FILE **f);
char *get_next_filename(const char *name, const char *suffix);
void do_insertfile_void(void);
@ -299,10 +299,10 @@ int write_lockfile(const char *lockfilename, const char *origfilename, bool modi
#endif
int copy_file(FILE *inn, FILE *out, bool close_out);
bool write_file(const char *name, FILE *f_open, bool tmp,
kind_of_writing_type method, bool fullbuffer);
kind_of_writing_type method, bool fullbuffer);
#ifndef NANO_TINY
bool write_marked_file(const char *name, FILE *f_open, bool tmp,
kind_of_writing_type method);
kind_of_writing_type method);
#endif
int do_writeout(bool exiting, bool withprompt);
void do_writeout_void(void);
@ -313,7 +313,7 @@ int diralphasort(const void *va, const void *vb);
#endif
#ifdef ENABLE_TABCOMP
char *input_tab(char *buf, bool allow_files, size_t *place,
bool *lastwastab, void (*refresh_func)(void), bool *listed);
bool *lastwastab, void (*refresh_func)(void), bool *listed);
#endif
/* Some functions in global.c. */
@ -406,10 +406,10 @@ filestruct *copy_filestruct(const filestruct *src);
void free_filestruct(filestruct *src);
void renumber(filestruct *fileptr);
partition *partition_filestruct(filestruct *top, size_t top_x,
filestruct *bot, size_t bot_x);
filestruct *bot, size_t bot_x);
void unpartition_filestruct(partition **p);
void extract_buffer(filestruct **file_top, filestruct **file_bot,
filestruct *top, size_t top_x, filestruct *bot, size_t bot_x);
filestruct *top, size_t top_x, filestruct *bot, size_t bot_x);
void ingraft_buffer(filestruct *somebuffer);
void copy_from_buffer(filestruct *somebuffer);
openfilestruct *make_new_opennode(void);
@ -470,8 +470,8 @@ size_t get_statusbar_page_start(size_t start_col, size_t column);
void reinit_statusbar_x(void);
void update_the_statusbar(void);
int do_prompt(bool allow_tabs, bool allow_files,
int menu, const char *curranswer, filestruct **history_list,
void (*refresh_func)(void), const char *msg, ...);
int menu, const char *curranswer, filestruct **history_list,
void (*refresh_func)(void), const char *msg, ...);
int do_yesno_prompt(bool all, const char *msg);
/* Most functions in rcfile.c. */
@ -488,7 +488,7 @@ void do_rcfiles(void);
void not_found_msg(const char *str);
void search_replace_abort(void);
int findnextstr(const char *needle, bool whole_word_only, int modus,
size_t *match_len, bool skipone, const filestruct *begin, size_t begin_x);
size_t *match_len, bool skipone, const filestruct *begin, size_t begin_x);
void do_search(void);
void do_search_forward(void);
void do_search_backward(void);
@ -499,11 +499,11 @@ void do_findnext(void);
void do_research(void);
void go_looking(void);
ssize_t do_replace_loop(const char *needle, bool whole_word_only,
const filestruct *real_current, size_t *real_current_x);
const filestruct *real_current, size_t *real_current_x);
void do_replace(void);
void goto_line_posx(ssize_t line, size_t pos_x);
void do_gotolinecolumn(ssize_t line, ssize_t column, bool use_answer,
bool interactive);
bool interactive);
void do_gotolinecolumn_void(void);
#ifndef NANO_TINY
void do_find_bracket(void);
@ -592,7 +592,7 @@ const char *fixbounds(const char *r);
bool is_separate_word(size_t position, size_t length, const char *buf);
#endif
const char *strstrwrapper(const char *haystack, const char *needle,
const char *start);
const char *start);
void nperror(const char *s);
void *nmalloc(size_t howmuch);
void *nrealloc(void *ptr, size_t howmuch);
@ -610,7 +610,7 @@ void remove_magicline(void);
#endif
#ifndef NANO_TINY
void mark_order(const filestruct **top, size_t *top_x,
const filestruct **bot, size_t *bot_x, bool *right_side_up);
const filestruct **bot, size_t *bot_x, bool *right_side_up);
void get_range(const filestruct **top, const filestruct **bot);
#endif
size_t get_totsize(const filestruct *begin, const filestruct *end);
@ -654,7 +654,7 @@ void bottombars(int menu);
void post_one_key(const char *keystroke, const char *tag, int width);
void place_the_cursor(void);
void edit_draw(filestruct *fileptr, const char *converted,
int line, size_t from_col);
int line, size_t from_col);
int update_line(filestruct *fileptr, size_t index);
#ifndef NANO_TINY
int update_softwrapped_line(filestruct *fileptr);
@ -666,7 +666,7 @@ bool less_than_a_screenful(size_t was_lineno, size_t was_leftedge);
void edit_scroll(bool direction, int nrows);
#ifndef NANO_TINY
size_t get_softwrap_breakpoint(const char *text, size_t leftedge,
bool *end_of_line);
bool *end_of_line);
size_t get_chunk_and_edge(size_t column, filestruct *line, size_t *leftedge);
size_t chunk_for(size_t column, filestruct *line);
size_t leftedge_for(size_t column, filestruct *line);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

5576
src/text.c

File diff suppressed because it is too large Load Diff

View File

@ -32,79 +32,79 @@
* we fall back on the home directory of the effective user ID. */
void get_homedir(void)
{
if (homedir == NULL) {
const char *homenv = getenv("HOME");
if (homedir == NULL) {
const char *homenv = getenv("HOME");
#ifdef HAVE_PWD_H
/* When HOME isn't set, or when we're root, get the home directory
* from the password file instead. */
if (homenv == NULL || geteuid() == 0) {
const struct passwd *userage = getpwuid(geteuid());
/* When HOME isn't set, or when we're root, get the home directory
* from the password file instead. */
if (homenv == NULL || geteuid() == 0) {
const struct passwd *userage = getpwuid(geteuid());
if (userage != NULL)
homenv = userage->pw_dir;
}
if (userage != NULL)
homenv = userage->pw_dir;
}
#endif
/* Only set homedir if some home directory could be determined,
* otherwise keep homedir NULL. */
if (homenv != NULL && strcmp(homenv, "") != 0)
homedir = mallocstrcpy(NULL, homenv);
}
/* Only set homedir if some home directory could be determined,
* otherwise keep homedir NULL. */
if (homenv != NULL && strcmp(homenv, "") != 0)
homedir = mallocstrcpy(NULL, homenv);
}
}
/* Return the filename part of the given path. */
const char *tail(const char *path)
{
const char *slash = strrchr(path, '/');
const char *slash = strrchr(path, '/');
if (slash == NULL)
return path;
else
return ++slash;
if (slash == NULL)
return path;
else
return ++slash;
}
/* Return a copy of the two given strings, welded together. */
char *concatenate(const char *path, const char *name)
{
size_t pathlen = strlen(path);
char *joined = charalloc(pathlen + strlen(name) + 1);
size_t pathlen = strlen(path);
char *joined = charalloc(pathlen + strlen(name) + 1);
strcpy(joined, path);
strcpy(joined + pathlen, name);
strcpy(joined, path);
strcpy(joined + pathlen, name);
return joined;
return joined;
}
#ifdef ENABLE_LINENUMBERS
/* Return the number of digits that the given integer n takes up. */
int digits(ssize_t n)
{
if (n < 100000) {
if (n < 1000) {
if (n < 100)
return 2;
else
return 3;
if (n < 100000) {
if (n < 1000) {
if (n < 100)
return 2;
else
return 3;
} else {
if (n < 10000)
return 4;
else
return 5;
}
} else {
if (n < 10000)
return 4;
else
return 5;
if (n < 10000000) {
if (n < 1000000)
return 6;
else
return 7;
} else {
if (n < 100000000)
return 8;
else
return 9;
}
}
} else {
if (n < 10000000) {
if (n < 1000000)
return 6;
else
return 7;
} else {
if (n < 100000000)
return 8;
else
return 9;
}
}
}
#endif
@ -112,98 +112,98 @@ int digits(ssize_t n)
* and return TRUE; otherwise, return FALSE. */
bool parse_num(const char *str, ssize_t *result)
{
char *first_error;
ssize_t value;
char *first_error;
ssize_t value;
/* The manual page for strtol() says this is required. */
errno = 0;
/* The manual page for strtol() says this is required. */
errno = 0;
value = (ssize_t)strtol(str, &first_error, 10);
value = (ssize_t)strtol(str, &first_error, 10);
if (errno == ERANGE || *str == '\0' || *first_error != '\0')
return FALSE;
if (errno == ERANGE || *str == '\0' || *first_error != '\0')
return FALSE;
*result = value;
*result = value;
return TRUE;
return TRUE;
}
/* Read two numbers, separated by a comma, from str, and store them in
* *line and *column. Return FALSE on error, and TRUE otherwise. */
bool parse_line_column(const char *str, ssize_t *line, ssize_t *column)
{
bool retval;
char *firstpart;
const char *comma;
bool retval;
char *firstpart;
const char *comma;
while (*str == ' ')
str++;
while (*str == ' ')
str++;
comma = strpbrk(str, "m,. /;");
comma = strpbrk(str, "m,. /;");
if (comma == NULL)
return parse_num(str, line);
if (comma == NULL)
return parse_num(str, line);
retval = parse_num(comma + 1, column);
retval = parse_num(comma + 1, column);
if (comma == str)
return retval;
firstpart = mallocstrcpy(NULL, str);
firstpart[comma - str] = '\0';
retval = parse_num(firstpart, line) && retval;
free(firstpart);
if (comma == str)
return retval;
firstpart = mallocstrcpy(NULL, str);
firstpart[comma - str] = '\0';
retval = parse_num(firstpart, line) && retval;
free(firstpart);
return retval;
}
/* Reduce the memory allocation of a string to what is needed. */
void snuggly_fit(char **str)
{
if (*str != NULL)
*str = charealloc(*str, strlen(*str) + 1);
if (*str != NULL)
*str = charealloc(*str, strlen(*str) + 1);
}
/* Null a string at a certain index and align it. */
void null_at(char **data, size_t index)
{
*data = charealloc(*data, index + 1);
(*data)[index] = '\0';
*data = charealloc(*data, index + 1);
(*data)[index] = '\0';
}
/* For non-null-terminated lines. A line, by definition, shouldn't
* normally have newlines in it, so encode its nulls as newlines. */
void unsunder(char *str, size_t true_len)
{
for (; true_len > 0; true_len--, str++) {
if (*str == '\0')
*str = '\n';
}
for (; true_len > 0; true_len--, str++) {
if (*str == '\0')
*str = '\n';
}
}
/* For non-null-terminated lines. A line, by definition, shouldn't
* normally have newlines in it, so decode its newlines as nulls. */
void sunder(char *str)
{
for (; *str != '\0'; str++) {
if (*str == '\n')
*str = '\0';
}
for (; *str != '\0'; str++) {
if (*str == '\n')
*str = '\0';
}
}
#if !defined(ENABLE_TINY) || defined(ENABLE_TABCOMP) || defined(ENABLE_BROWSER)
/* Free the memory of the given array, which should contain len elements. */
void free_chararray(char **array, size_t len)
{
if (array == NULL)
return;
if (array == NULL)
return;
while (len > 0)
free(array[--len]);
while (len > 0)
free(array[--len]);
free(array);
free(array);
}
#endif
@ -212,30 +212,30 @@ void free_chararray(char **array, size_t len)
const char *fixbounds(const char *r)
{
#ifndef GNU_WORDBOUNDS
int i, j = 0;
char *r2 = charalloc(strlen(r) * 5);
char *r3;
int i, j = 0;
char *r2 = charalloc(strlen(r) * 5);
char *r3;
for (i = 0; i < strlen(r); i++) {
if (r[i] != '\0' && r[i] == '\\' && (r[i + 1] == '>' || r[i + 1] == '<')) {
strcpy(&r2[j], "[[:");
r2[j + 3] = r[i + 1];
strcpy(&r2[j + 4], ":]]");
i++;
j += 6;
} else
r2[j] = r[i];
j++;
}
for (i = 0; i < strlen(r); i++) {
if (r[i] != '\0' && r[i] == '\\' && (r[i + 1] == '>' || r[i + 1] == '<')) {
strcpy(&r2[j], "[[:");
r2[j + 3] = r[i + 1];
strcpy(&r2[j + 4], ":]]");
i++;
j += 6;
} else
r2[j] = r[i];
j++;
}
r2[j] = '\0';
r3 = mallocstrcpy(NULL, r2);
free(r2);
r2[j] = '\0';
r3 = mallocstrcpy(NULL, r2);
free(r2);
return (const char *) r3;
return (const char *) r3;
#endif /* !GNU_WORDBOUNDS */
return r;
return r;
}
#ifdef ENABLE_SPELLER
@ -243,18 +243,18 @@ const char *fixbounds(const char *r)
* a separate word? That is: is it not part of a longer word?*/
bool is_separate_word(size_t position, size_t length, const char *buf)
{
char before[MAXCHARLEN], after[MAXCHARLEN];
size_t word_end = position + length;
char before[MAXCHARLEN], after[MAXCHARLEN];
size_t word_end = position + length;
/* Get the characters before and after the word, if any. */
parse_mbchar(buf + move_mbleft(buf, position), before, NULL);
parse_mbchar(buf + word_end, after, NULL);
/* Get the characters before and after the word, if any. */
parse_mbchar(buf + move_mbleft(buf, position), before, NULL);
parse_mbchar(buf + word_end, after, NULL);
/* If the word starts at the beginning of the line OR the character before
* the word isn't a letter, and if the word ends at the end of the line OR
* the character after the word isn't a letter, we have a whole word. */
return ((position == 0 || !is_alpha_mbchar(before)) &&
(buf[word_end] == '\0' || !is_alpha_mbchar(after)));
/* If the word starts at the beginning of the line OR the character before
* the word isn't a letter, and if the word ends at the end of the line OR
* the character after the word isn't a letter, we have a whole word. */
return ((position == 0 || !is_alpha_mbchar(before)) &&
(buf[word_end] == '\0' || !is_alpha_mbchar(after)));
}
#endif /* ENABLE_SPELLER */
@ -264,76 +264,76 @@ bool is_separate_word(size_t position, size_t length, const char *buf)
* than start. If we are doing a regexp search, and we find a match, we fill
* in the global variable regmatches with at most 9 subexpression matches. */
const char *strstrwrapper(const char *haystack, const char *needle,
const char *start)
const char *start)
{
if (*needle == '\0') {
if (*needle == '\0') {
#ifndef NANO_TINY
statusline(ALERT, "Searching for nothing -- please report a bug");
statusline(ALERT, "Searching for nothing -- please report a bug");
#endif
return (char *)start;
}
if (ISSET(USE_REGEXP)) {
if (ISSET(BACKWARDS_SEARCH)) {
size_t last_find, ceiling, far_end;
size_t floor = 0, next_rung = 0;
/* The start of the search range, and the next start. */
if (regexec(&search_regexp, haystack, 1, regmatches, 0) != 0)
return NULL;
far_end = strlen(haystack);
ceiling = start - haystack;
last_find = regmatches[0].rm_so;
/* A result beyond the search range also means: no match. */
if (last_find > ceiling)
return NULL;
/* Move the start-of-range forward until there is no more match;
* then the last match found is the first match backwards. */
while (regmatches[0].rm_so <= ceiling) {
floor = next_rung;
last_find = regmatches[0].rm_so;
/* If this is the last possible match, don't try to advance. */
if (last_find == ceiling)
break;
next_rung = move_mbright(haystack, last_find);
regmatches[0].rm_so = next_rung;
regmatches[0].rm_eo = far_end;
if (regexec(&search_regexp, haystack, 1, regmatches,
REG_STARTEND) != 0)
break;
}
/* Find the last match again, to get possible submatches. */
regmatches[0].rm_so = floor;
regmatches[0].rm_eo = far_end;
if (regexec(&search_regexp, haystack, 10, regmatches,
REG_STARTEND) != 0)
return NULL;
return haystack + regmatches[0].rm_so;
return (char *)start;
}
/* Do a forward regex search from the starting point. */
regmatches[0].rm_so = start - haystack;
regmatches[0].rm_eo = strlen(haystack);
if (regexec(&search_regexp, haystack, 10, regmatches,
REG_STARTEND) != 0)
return NULL;
else
return haystack + regmatches[0].rm_so;
}
if (ISSET(CASE_SENSITIVE)) {
if (ISSET(BACKWARDS_SEARCH))
return revstrstr(haystack, needle, start);
else
return strstr(start, needle);
} else if (ISSET(BACKWARDS_SEARCH))
return mbrevstrcasestr(haystack, needle, start);
if (ISSET(USE_REGEXP)) {
if (ISSET(BACKWARDS_SEARCH)) {
size_t last_find, ceiling, far_end;
size_t floor = 0, next_rung = 0;
/* The start of the search range, and the next start. */
return mbstrcasestr(start, needle);
if (regexec(&search_regexp, haystack, 1, regmatches, 0) != 0)
return NULL;
far_end = strlen(haystack);
ceiling = start - haystack;
last_find = regmatches[0].rm_so;
/* A result beyond the search range also means: no match. */
if (last_find > ceiling)
return NULL;
/* Move the start-of-range forward until there is no more match;
* then the last match found is the first match backwards. */
while (regmatches[0].rm_so <= ceiling) {
floor = next_rung;
last_find = regmatches[0].rm_so;
/* If this is the last possible match, don't try to advance. */
if (last_find == ceiling)
break;
next_rung = move_mbright(haystack, last_find);
regmatches[0].rm_so = next_rung;
regmatches[0].rm_eo = far_end;
if (regexec(&search_regexp, haystack, 1, regmatches,
REG_STARTEND) != 0)
break;
}
/* Find the last match again, to get possible submatches. */
regmatches[0].rm_so = floor;
regmatches[0].rm_eo = far_end;
if (regexec(&search_regexp, haystack, 10, regmatches,
REG_STARTEND) != 0)
return NULL;
return haystack + regmatches[0].rm_so;
}
/* Do a forward regex search from the starting point. */
regmatches[0].rm_so = start - haystack;
regmatches[0].rm_eo = strlen(haystack);
if (regexec(&search_regexp, haystack, 10, regmatches,
REG_STARTEND) != 0)
return NULL;
else
return haystack + regmatches[0].rm_so;
}
if (ISSET(CASE_SENSITIVE)) {
if (ISSET(BACKWARDS_SEARCH))
return revstrstr(haystack, needle, start);
else
return strstr(start, needle);
} else if (ISSET(BACKWARDS_SEARCH))
return mbrevstrcasestr(haystack, needle, start);
return mbstrcasestr(start, needle);
}
/* This is a wrapper for the perror() function. The wrapper temporarily
@ -342,63 +342,63 @@ const char *strstrwrapper(const char *haystack, const char *needle,
* nperror() causes the window to flicker once. */
void nperror(const char *s)
{
endwin();
perror(s);
doupdate();
endwin();
perror(s);
doupdate();
}
/* This is a wrapper for the malloc() function that properly handles
* things when we run out of memory. */
void *nmalloc(size_t howmuch)
{
void *r = malloc(howmuch);
void *r = malloc(howmuch);
if (r == NULL && howmuch != 0)
die(_("nano is out of memory!"));
if (r == NULL && howmuch != 0)
die(_("nano is out of memory!"));
return r;
return r;
}
/* This is a wrapper for the realloc() function that properly handles
* things when we run out of memory. */
void *nrealloc(void *ptr, size_t howmuch)
{
void *r = realloc(ptr, howmuch);
void *r = realloc(ptr, howmuch);
if (r == NULL && howmuch != 0)
die(_("nano is out of memory!"));
if (r == NULL && howmuch != 0)
die(_("nano is out of memory!"));
return r;
return r;
}
/* Allocate and copy the first n characters of the given src string, after
* freeing the destination. Usage: "dest = mallocstrncpy(dest, src, n);". */
char *mallocstrncpy(char *dest, const char *src, size_t n)
{
if (src == NULL)
src = "";
if (src == NULL)
src = "";
if (src != dest)
free(dest);
if (src != dest)
free(dest);
dest = charalloc(n);
strncpy(dest, src, n);
dest = charalloc(n);
strncpy(dest, src, n);
return dest;
return dest;
}
/* Free the dest string and return a malloc'ed copy of src. Should be used as:
* "dest = mallocstrcpy(dest, src);". */
char *mallocstrcpy(char *dest, const char *src)
{
return mallocstrncpy(dest, src, (src == NULL) ? 1 : strlen(src) + 1);
return mallocstrncpy(dest, src, (src == NULL) ? 1 : strlen(src) + 1);
}
/* Free the string at dest and return the string at src. */
char *free_and_assign(char *dest, char *src)
{
free(dest);
return src;
free(dest);
return src;
}
/* When not in softwrap mode, nano scrolls horizontally within a line in
@ -408,83 +408,83 @@ char *free_and_assign(char *dest, char *src)
* get_page_start(column) < COLS). */
size_t get_page_start(size_t column)
{
if (column < editwincols - 1 || ISSET(SOFTWRAP) || column == 0)
return 0;
else if (editwincols > 8)
return column - 7 - (column - 7) % (editwincols - 8);
else
return column - (editwincols - 2);
if (column < editwincols - 1 || ISSET(SOFTWRAP) || column == 0)
return 0;
else if (editwincols > 8)
return column - 7 - (column - 7) % (editwincols - 8);
else
return column - (editwincols - 2);
}
/* Return the placewewant associated with current_x, i.e. the zero-based
* column position of the cursor. */
size_t xplustabs(void)
{
return strnlenpt(openfile->current->data, openfile->current_x);
return strnlenpt(openfile->current->data, openfile->current_x);
}
/* Return the index in text of the character that (when displayed) will
* not overshoot the given column. */
size_t actual_x(const char *text, size_t column)
{
const char *start = text;
/* From where we start walking through the text. */
size_t width = 0;
/* The current accumulated span, in columns. */
const char *start = text;
/* From where we start walking through the text. */
size_t width = 0;
/* The current accumulated span, in columns. */
while (*text != '\0') {
int charlen = parse_mbchar(text, NULL, &width);
while (*text != '\0') {
int charlen = parse_mbchar(text, NULL, &width);
if (width > column)
break;
if (width > column)
break;
text += charlen;
}
text += charlen;
}
return (text - start);
return (text - start);
}
/* A strnlen() with tabs and multicolumn characters factored in:
* how many columns wide are the first maxlen bytes of text? */
size_t strnlenpt(const char *text, size_t maxlen)
{
size_t width = 0;
/* The screen display width to text[maxlen]. */
size_t width = 0;
/* The screen display width to text[maxlen]. */
if (maxlen == 0)
return 0;
if (maxlen == 0)
return 0;
while (*text != '\0') {
int charlen = parse_mbchar(text, NULL, &width);
while (*text != '\0') {
int charlen = parse_mbchar(text, NULL, &width);
if (maxlen <= charlen)
break;
if (maxlen <= charlen)
break;
maxlen -= charlen;
text += charlen;
}
maxlen -= charlen;
text += charlen;
}
return width;
return width;
}
/* Return the number of columns that the given text occupies. */
size_t strlenpt(const char *text)
{
size_t span = 0;
size_t span = 0;
while (*text != '\0')
text += parse_mbchar(text, NULL, &span);
while (*text != '\0')
text += parse_mbchar(text, NULL, &span);
return span;
return span;
}
/* Append a new magicline to the end of the buffer. */
void new_magicline(void)
{
openfile->filebot->next = make_new_node(openfile->filebot);
openfile->filebot->next->data = mallocstrcpy(NULL, "");
openfile->filebot = openfile->filebot->next;
openfile->totsize++;
openfile->filebot->next = make_new_node(openfile->filebot);
openfile->filebot->next->data = mallocstrcpy(NULL, "");
openfile->filebot = openfile->filebot->next;
openfile->totsize++;
}
#if !defined(NANO_TINY) || defined(ENABLE_HELP)
@ -492,13 +492,13 @@ void new_magicline(void)
* it isn't the only line in the file. */
void remove_magicline(void)
{
if (openfile->filebot->data[0] == '\0' &&
openfile->filebot != openfile->fileage) {
openfile->filebot = openfile->filebot->prev;
free_filestruct(openfile->filebot->next);
openfile->filebot->next = NULL;
openfile->totsize--;
}
if (openfile->filebot->data[0] == '\0' &&
openfile->filebot != openfile->fileage) {
openfile->filebot = openfile->filebot->prev;
free_filestruct(openfile->filebot->next);
openfile->filebot->next = NULL;
openfile->totsize--;
}
}
#endif
@ -507,25 +507,25 @@ void remove_magicline(void)
* the marked region. If right_side_up isn't NULL, set it to TRUE when the
* mark is at the top of the marked region, and to FALSE otherwise. */
void mark_order(const filestruct **top, size_t *top_x,
const filestruct **bot, size_t *bot_x, bool *right_side_up)
const filestruct **bot, size_t *bot_x, bool *right_side_up)
{
if ((openfile->current->lineno == openfile->mark->lineno &&
openfile->current_x > openfile->mark_x) ||
openfile->current->lineno > openfile->mark->lineno) {
*top = openfile->mark;
*top_x = openfile->mark_x;
*bot = openfile->current;
*bot_x = openfile->current_x;
if (right_side_up != NULL)
*right_side_up = TRUE;
} else {
*bot = openfile->mark;
*bot_x = openfile->mark_x;
*top = openfile->current;
*top_x = openfile->current_x;
if (right_side_up != NULL)
*right_side_up = FALSE;
}
if ((openfile->current->lineno == openfile->mark->lineno &&
openfile->current_x > openfile->mark_x) ||
openfile->current->lineno > openfile->mark->lineno) {
*top = openfile->mark;
*top_x = openfile->mark_x;
*bot = openfile->current;
*bot_x = openfile->current_x;
if (right_side_up != NULL)
*right_side_up = TRUE;
} else {
*bot = openfile->mark;
*bot_x = openfile->mark_x;
*top = openfile->current;
*top_x = openfile->current_x;
if (right_side_up != NULL)
*right_side_up = FALSE;
}
}
/* Get the set of lines to work on -- either just the current line, or the
@ -533,74 +533,74 @@ void mark_order(const filestruct **top, size_t *top_x,
* at the start of the last line of the region, exclude that line. */
void get_range(const filestruct **top, const filestruct **bot)
{
if (!openfile->mark) {
*top = openfile->current;
*bot = openfile->current;
} else {
size_t top_x, bot_x;
if (!openfile->mark) {
*top = openfile->current;
*bot = openfile->current;
} else {
size_t top_x, bot_x;
mark_order(top, &top_x, bot, &bot_x, NULL);
mark_order(top, &top_x, bot, &bot_x, NULL);
if (bot_x == 0 && *bot != *top && !also_the_last)
*bot = (*bot)->prev;
else
also_the_last = TRUE;
}
if (bot_x == 0 && *bot != *top && !also_the_last)
*bot = (*bot)->prev;
else
also_the_last = TRUE;
}
}
/* Given a line number, return a pointer to the corresponding struct. */
filestruct *fsfromline(ssize_t lineno)
{
filestruct *f = openfile->current;
filestruct *f = openfile->current;
if (lineno <= openfile->current->lineno)
while (f->lineno != lineno && f->prev != NULL)
f = f->prev;
else
while (f->lineno != lineno && f->next != NULL)
f = f->next;
if (lineno <= openfile->current->lineno)
while (f->lineno != lineno && f->prev != NULL)
f = f->prev;
else
while (f->lineno != lineno && f->next != NULL)
f = f->next;
if (f->lineno != lineno) {
statusline(ALERT, "Gone undo line -- please report a bug");
return NULL;
}
if (f->lineno != lineno) {
statusline(ALERT, "Gone undo line -- please report a bug");
return NULL;
}
return f;
return f;
}
#endif /* !NANO_TINY */
/* Count the number of characters from begin to end, and return it. */
size_t get_totsize(const filestruct *begin, const filestruct *end)
{
const filestruct *line;
size_t totsize = 0;
const filestruct *line;
size_t totsize = 0;
/* Sum the number of characters (plus a newline) in each line. */
for (line = begin; line != end->next; line = line->next)
totsize += mbstrlen(line->data) + 1;
/* Sum the number of characters (plus a newline) in each line. */
for (line = begin; line != end->next; line = line->next)
totsize += mbstrlen(line->data) + 1;
/* The last line of a file doesn't have a newline -- otherwise it
* wouldn't be the last line -- so subtract 1 when at EOF. */
if (line == NULL)
totsize--;
/* The last line of a file doesn't have a newline -- otherwise it
* wouldn't be the last line -- so subtract 1 when at EOF. */
if (line == NULL)
totsize--;
return totsize;
return totsize;
}
#ifdef DEBUG
/* Dump the given buffer to stderr. */
void dump_filestruct(const filestruct *inptr)
{
if (inptr == openfile->fileage)
fprintf(stderr, "Dumping file buffer to stderr...\n");
else if (inptr == cutbuffer)
fprintf(stderr, "Dumping cutbuffer to stderr...\n");
else
fprintf(stderr, "Dumping a buffer to stderr...\n");
if (inptr == openfile->fileage)
fprintf(stderr, "Dumping file buffer to stderr...\n");
else if (inptr == cutbuffer)
fprintf(stderr, "Dumping cutbuffer to stderr...\n");
else
fprintf(stderr, "Dumping a buffer to stderr...\n");
while (inptr != NULL) {
fprintf(stderr, "(%zd) %s\n", inptr->lineno, inptr->data);
inptr = inptr->next;
}
while (inptr != NULL) {
fprintf(stderr, "(%zd) %s\n", inptr->lineno, inptr->data);
inptr = inptr->next;
}
}
#endif /* DEBUG */

File diff suppressed because it is too large Load Diff