mirror of git://git.sv.gnu.org/nano.git
per DB's patch, overhaul the rcfile and history file reading and writing
routines to fix a few fundamental problems and limitations; also add getline() and getdelim() equivalents adapted from GNU mailutils 0.5 (and tweaked to better integrate with nano), since the patch uses getline() git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@1900 35c25a1d-7b9e-4130-9fde-d3aeb78583b8
This commit is contained in:
parent
bb50b305d5
commit
a27bd65057
22
ChangeLog
22
ChangeLog
|
@ -92,6 +92,14 @@ CVS code -
|
|||
fill_flag_used to avoid warnings when compiling with
|
||||
--disable-wrapping, --disable-justify, or a combination of the
|
||||
two. (DLR)
|
||||
- Overhaul the routines used to read the rcfiles and history
|
||||
files for efficiency, make them work properly on lines over
|
||||
1023 characters long and on lines containing nulls, and make
|
||||
them properly handle the case where the user's home directory
|
||||
changes in the middle of a session. New functions
|
||||
histfilename() and writehist(); changes to
|
||||
thanks_for_all_the_fish(), load_history(), save_history(), and
|
||||
do_rcfile(). (David Benbennick)
|
||||
- files.c:
|
||||
get_next_filename()
|
||||
- Tweak for efficiency, and add the ".save" suffix to the file
|
||||
|
@ -112,7 +120,7 @@ CVS code -
|
|||
- global.c:
|
||||
shortcut_init()
|
||||
- Fix erroneous #ifdef so that nano compiles with
|
||||
--disable-justify again. (DLR; found by Mike Frysinger)
|
||||
--disable-justify again. (DLR, found by Mike Frysinger)
|
||||
- Change the Cancel shortcut in the file browser to an Exit
|
||||
shortcut, to be more compatible with the current version of
|
||||
Pico. (DLR)
|
||||
|
@ -186,8 +194,8 @@ CVS code -
|
|||
match their corresponding location in files.c. (DLR)
|
||||
- rcfile.c:
|
||||
rcfile_msg()
|
||||
- Removed along with the related static int errors, and replaced
|
||||
with calls to rcfile_error(). (David Benbennick)
|
||||
- Removed and replaced with calls to rcfile_error(). (David
|
||||
Benbennick)
|
||||
- Removed the reference to "starting nano" in the statusbar
|
||||
message, as it may be called when we exit if the history file
|
||||
can't be saved. (DLR)
|
||||
|
@ -225,9 +233,13 @@ CVS code -
|
|||
- Remove code chacking for n's being less than 0 that will never
|
||||
be run, since n is a size_t and is hence unsigned. (David
|
||||
Benbennick)
|
||||
ngetdelim(), ngetline()
|
||||
- New functions equivalent to getdelim() and getline(), which
|
||||
are both GNU extensions. (DLR, adapted from GNU mailutils
|
||||
0.5)
|
||||
- winio.c:
|
||||
get_kbinput()
|
||||
- Since the only valid values for escapes are 0, 1, and 2,
|
||||
- Since the only valid values for escapes are 0, 1, and 2,
|
||||
convert it to an int. (DLR)
|
||||
get_control_kbinput()
|
||||
- Fix erroneous debugging statement so that nano compiles with
|
||||
|
@ -254,6 +266,8 @@ CVS code -
|
|||
- configure.ac:
|
||||
- Add AC_PROG_LN_S, so that we can portably create symlinks.
|
||||
(DLR)
|
||||
- Check for getdelim() and getline(), which are both GNU
|
||||
extensions. (DLR)
|
||||
- nanorc.sample:
|
||||
- Add sample regexes for patch files. (Mike Frysinger)
|
||||
- Various improvements to the "c-file" regexes. Add double,
|
||||
|
|
|
@ -290,7 +290,7 @@ AC_MSG_WARN([*** Can not use slang when cross-compiling])),
|
|||
esac], [AC_MSG_RESULT(no)])
|
||||
|
||||
dnl Checks for functions
|
||||
AC_CHECK_FUNCS(snprintf vsnprintf isblank strcasecmp strncasecmp strcasestr strnlen)
|
||||
AC_CHECK_FUNCS(snprintf vsnprintf isblank strcasecmp strncasecmp strcasestr strnlen getline getdelim)
|
||||
if test "x$ac_cv_func_snprintf" = "xno" -o "xac_cv_func_vsnprintf" = "xno"
|
||||
then
|
||||
AM_PATH_GLIB_2_0(2.0.0,,
|
||||
|
|
128
src/files.c
128
src/files.c
|
@ -2914,30 +2914,30 @@ char *do_browse_from(const char *inpath)
|
|||
#endif /* !DISABLE_BROWSER */
|
||||
|
||||
#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
|
||||
/* Return $HOME/.nano_history, or NULL if we can't find the homedir.
|
||||
* The string is dynamically allocated, and should be freed. */
|
||||
char *histfilename(void)
|
||||
{
|
||||
char *nanohist = NULL;
|
||||
|
||||
if (homedir != NULL) {
|
||||
size_t homelen = strlen(homedir);
|
||||
|
||||
nanohist = charalloc(homelen + 15);
|
||||
strcpy(nanohist, homedir);
|
||||
strcpy(nanohist + homelen, "/.nano_history");
|
||||
}
|
||||
return nanohist;
|
||||
}
|
||||
|
||||
void load_history(void)
|
||||
{
|
||||
FILE *hist;
|
||||
const struct passwd *userage = NULL;
|
||||
static char *nanohist;
|
||||
char *buf, *ptr;
|
||||
char *homenv = getenv("HOME");
|
||||
historyheadtype *history = &search_history;
|
||||
|
||||
|
||||
if (homenv != NULL) {
|
||||
nanohist = charealloc(nanohist, strlen(homenv) + 15);
|
||||
sprintf(nanohist, "%s/.nano_history", homenv);
|
||||
} else {
|
||||
userage = getpwuid(geteuid());
|
||||
endpwent();
|
||||
nanohist = charealloc(nanohist, strlen(userage->pw_dir) + 15);
|
||||
sprintf(nanohist, "%s/.nano_history", userage->pw_dir);
|
||||
}
|
||||
char *nanohist = histfilename();
|
||||
|
||||
/* assume do_rcfile() has reported missing home dir */
|
||||
if (nanohist != NULL) {
|
||||
FILE *hist = fopen(nanohist, "r");
|
||||
|
||||
if (homenv != NULL || userage != NULL) {
|
||||
hist = fopen(nanohist, "r");
|
||||
if (hist == NULL) {
|
||||
if (errno != ENOENT) {
|
||||
/* Don't save history when we quit. */
|
||||
|
@ -2947,80 +2947,72 @@ void load_history(void)
|
|||
while (getchar() != '\n')
|
||||
;
|
||||
}
|
||||
free(nanohist);
|
||||
} else {
|
||||
buf = charalloc(1024);
|
||||
while (fgets(buf, 1023, hist) != 0) {
|
||||
ptr = buf;
|
||||
while (*ptr != '\n' && *ptr != '\0' && ptr < buf + 1023)
|
||||
ptr++;
|
||||
*ptr = '\0';
|
||||
if (strlen(buf))
|
||||
update_history(history, buf);
|
||||
else
|
||||
historyheadtype *history = &search_history;
|
||||
char *line = NULL;
|
||||
size_t buflen = 0;
|
||||
ssize_t read;
|
||||
|
||||
while ((read = getline(&line, &buflen, hist)) >= 0) {
|
||||
if (read > 0 && line[read - 1] == '\n') {
|
||||
read--;
|
||||
line[read] = '\0';
|
||||
}
|
||||
if (read > 0) {
|
||||
unsunder(line, read);
|
||||
update_history(history, line);
|
||||
} else
|
||||
history = &replace_history;
|
||||
}
|
||||
fclose(hist);
|
||||
free(buf);
|
||||
free(nanohist);
|
||||
free(line);
|
||||
UNSET(HISTORY_CHANGED);
|
||||
}
|
||||
free(nanohist);
|
||||
}
|
||||
}
|
||||
|
||||
bool writehist(FILE *hist, historyheadtype *histhead)
|
||||
{
|
||||
historytype *h;
|
||||
|
||||
/* write oldest first */
|
||||
for (h = histhead->tail; h->prev != NULL; h = h->prev) {
|
||||
size_t len = strlen(h->data);
|
||||
|
||||
sunder(h->data);
|
||||
if (fwrite(h->data, sizeof(char), len, hist) < len ||
|
||||
putc('\n', hist) == EOF)
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* save histories to ~/.nano_history */
|
||||
void save_history(void)
|
||||
{
|
||||
FILE *hist;
|
||||
const struct passwd *userage = NULL;
|
||||
char *nanohist = NULL;
|
||||
char *homenv = getenv("HOME");
|
||||
historytype *h;
|
||||
char *nanohist;
|
||||
|
||||
/* don't save unchanged or empty histories */
|
||||
if ((search_history.count == 0 && replace_history.count == 0) ||
|
||||
!ISSET(HISTORY_CHANGED) || ISSET(VIEW_MODE))
|
||||
return;
|
||||
|
||||
if (homenv != NULL) {
|
||||
nanohist = charealloc(nanohist, strlen(homenv) + 15);
|
||||
sprintf(nanohist, "%s/.nano_history", homenv);
|
||||
} else {
|
||||
userage = getpwuid(geteuid());
|
||||
endpwent();
|
||||
nanohist = charealloc(nanohist, strlen(userage->pw_dir) + 15);
|
||||
sprintf(nanohist, "%s/.nano_history", userage->pw_dir);
|
||||
}
|
||||
nanohist = histfilename();
|
||||
|
||||
if (nanohist != NULL) {
|
||||
FILE *hist = fopen(nanohist, "wb");
|
||||
|
||||
if (homenv != NULL || userage != NULL) {
|
||||
hist = fopen(nanohist, "wb");
|
||||
if (hist == NULL)
|
||||
rcfile_error(N_("Error writing %s: %s"), nanohist, strerror(errno));
|
||||
else {
|
||||
/* set rw only by owner for security ?? */
|
||||
chmod(nanohist, S_IRUSR | S_IWUSR);
|
||||
/* write oldest first */
|
||||
for (h = search_history.tail; h->prev; h = h->prev) {
|
||||
h->data = charealloc(h->data, strlen(h->data) + 2);
|
||||
strcat(h->data, "\n");
|
||||
if (fputs(h->data, hist) == EOF) {
|
||||
rcfile_error(N_("Error writing %s: %s"), nanohist, strerror(errno));
|
||||
goto come_from;
|
||||
}
|
||||
}
|
||||
if (fputs("\n", hist) == EOF) {
|
||||
|
||||
if (!writehist(hist, &search_history) ||
|
||||
putc('\n', hist) == EOF ||
|
||||
!writehist(hist, &replace_history))
|
||||
rcfile_error(N_("Error writing %s: %s"), nanohist, strerror(errno));
|
||||
goto come_from;
|
||||
}
|
||||
for (h = replace_history.tail; h->prev; h = h->prev) {
|
||||
h->data = charealloc(h->data, strlen(h->data) + 2);
|
||||
strcat(h->data, "\n");
|
||||
if (fputs(h->data, hist) == EOF) {
|
||||
rcfile_error(N_("Error writing %s: %s"), nanohist, strerror(errno));
|
||||
goto come_from;
|
||||
}
|
||||
}
|
||||
come_from:
|
||||
fclose(hist);
|
||||
}
|
||||
free(nanohist);
|
||||
|
|
|
@ -178,6 +178,10 @@ bool curses_ended = FALSE; /* Indicates to statusbar() to simply
|
|||
* write to stderr, since endwin() has
|
||||
* ended curses mode. */
|
||||
|
||||
#ifdef ENABLE_NANORC
|
||||
char *homedir = NULL; /* $HOME or from /etc/passwd. */
|
||||
#endif
|
||||
|
||||
size_t length_of_list(const shortcut *s)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
@ -1188,5 +1192,8 @@ void thanks_for_all_the_fish(void)
|
|||
free_history(&search_history);
|
||||
free_history(&replace_history);
|
||||
#endif
|
||||
#ifdef ENABLE_NANORC
|
||||
free(homedir);
|
||||
#endif
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
|
|
@ -3000,7 +3000,7 @@ void terminal_init(void)
|
|||
disable_flow_control();
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int optchr;
|
||||
int startline = 0; /* Line to try and start at */
|
||||
|
|
12
src/nano.h
12
src/nano.h
|
@ -95,8 +95,8 @@
|
|||
# endif
|
||||
#endif
|
||||
|
||||
/* If no isblank(), strcasecmp(), strncasecmp(), strcasestr(), or
|
||||
* strnlen(), use the versions we have. */
|
||||
/* If no isblank(), strcasecmp(), strncasecmp(), strcasestr(),
|
||||
* strnlen(), getdelim(), or getline(), use the versions we have. */
|
||||
#ifndef HAVE_ISBLANK
|
||||
#define isblank is_blank_char
|
||||
#endif
|
||||
|
@ -117,6 +117,14 @@
|
|||
#define strnlen nstrnlen
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETDELIM
|
||||
#define getdelim ngetdelim
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETLINE
|
||||
#define getline ngetline
|
||||
#endif
|
||||
|
||||
/* Assume ERR is defined as -1. To avoid duplicate case values when
|
||||
* some key definitions are missing, we have to set all of these, and
|
||||
* all of the special sentinel values below, to different negative
|
||||
|
|
12
src/proto.h
12
src/proto.h
|
@ -142,6 +142,10 @@ extern historyheadtype replace_history;
|
|||
|
||||
extern bool curses_ended;
|
||||
|
||||
#ifdef ENABLE_NANORC
|
||||
extern char *homedir;
|
||||
#endif
|
||||
|
||||
/* Functions we want available. */
|
||||
|
||||
/* Public functions in color.c */
|
||||
|
@ -224,7 +228,9 @@ char *do_browser(const char *inpath);
|
|||
char *do_browse_from(const char *inpath);
|
||||
#endif
|
||||
#if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
|
||||
char *histfilename(void);
|
||||
void load_history(void);
|
||||
bool writehist(FILE *hist, historyheadtype *histhead);
|
||||
void save_history(void);
|
||||
#endif
|
||||
|
||||
|
@ -461,6 +467,12 @@ const char *revstristr(const char *haystack, const char *needle, const
|
|||
#ifndef HAVE_STRNLEN
|
||||
size_t nstrnlen(const char *s, size_t maxlen);
|
||||
#endif
|
||||
#ifndef HAVE_GETLINE
|
||||
ssize_t ngetline(char **lineptr, size_t *n, FILE *stream);
|
||||
#endif
|
||||
#ifndef HAVE_GETDELIM
|
||||
ssize_t ngetdelim(char **lineptr, size_t *n, int delim, FILE *stream);
|
||||
#endif
|
||||
const char *strstrwrapper(const char *haystack, const char *needle,
|
||||
const char *start);
|
||||
void nperror(const char *s);
|
||||
|
|
50
src/rcfile.c
50
src/rcfile.c
|
@ -101,7 +101,7 @@ const static rcoption rcopts[] = {
|
|||
|
||||
static bool errors = FALSE;
|
||||
static int lineno = 0;
|
||||
static char *nanorc;
|
||||
static const char *nanorc;
|
||||
|
||||
/* We have an error in some part of the rcfile; put it on stderr and
|
||||
make the user hit return to continue starting up nano. */
|
||||
|
@ -648,16 +648,13 @@ void parse_rcfile(FILE *rcstream)
|
|||
void do_rcfile(void)
|
||||
{
|
||||
FILE *rcstream;
|
||||
const struct passwd *userage;
|
||||
uid_t euid = geteuid();
|
||||
char *homenv = getenv("HOME");
|
||||
|
||||
#ifdef SYSCONFDIR
|
||||
assert(sizeof(SYSCONFDIR) == strlen(SYSCONFDIR) + 1);
|
||||
nanorc = charalloc(sizeof(SYSCONFDIR) + 7);
|
||||
sprintf(nanorc, "%s/nanorc", SYSCONFDIR);
|
||||
nanorc = SYSCONFDIR "/nanorc";
|
||||
/* Try to open system nanorc */
|
||||
if ((rcstream = fopen(nanorc, "r")) != NULL) {
|
||||
rcstream = fopen(nanorc, "r");
|
||||
if (rcstream != NULL) {
|
||||
/* Parse it! */
|
||||
parse_rcfile(rcstream);
|
||||
fclose(rcstream);
|
||||
|
@ -666,33 +663,38 @@ void do_rcfile(void)
|
|||
|
||||
lineno = 0;
|
||||
|
||||
/* Rely on $HOME, fall back on getpwuid() */
|
||||
if (homenv != NULL) {
|
||||
nanorc = charealloc(nanorc, strlen(homenv) + 10);
|
||||
sprintf(nanorc, "%s/.nanorc", homenv);
|
||||
} else {
|
||||
userage = getpwuid(euid);
|
||||
endpwent();
|
||||
{
|
||||
const char *homenv = getenv("HOME");
|
||||
|
||||
if (userage == NULL) {
|
||||
rcfile_error(N_("I can't find my home directory! Wah!"));
|
||||
SET(NO_RCFILE);
|
||||
} else {
|
||||
nanorc = charealloc(nanorc, strlen(userage->pw_dir) + 9);
|
||||
sprintf(nanorc, "%s/.nanorc", userage->pw_dir);
|
||||
/* Rely on $HOME, fall back on getpwuid() */
|
||||
if (homenv == NULL) {
|
||||
const struct passwd *userage = getpwuid(geteuid());
|
||||
|
||||
if (userage != NULL)
|
||||
homenv = userage->pw_dir;
|
||||
}
|
||||
homedir = mallocstrcpy(NULL, homenv);
|
||||
}
|
||||
|
||||
if (!ISSET(NO_RCFILE)) {
|
||||
if (homedir == NULL) {
|
||||
rcfile_error(N_("I can't find my home directory! Wah!"));
|
||||
SET(NO_RCFILE);
|
||||
} else {
|
||||
size_t homelen = strlen(homedir);
|
||||
char *nanorcf = charalloc(homelen + 9);
|
||||
|
||||
nanorc = nanorcf;
|
||||
strcpy(nanorcf, homedir);
|
||||
strcpy(nanorcf + homelen, "/.nanorc");
|
||||
|
||||
#if defined(DISABLE_ROOTWRAP) && !defined(DISABLE_WRAPPING)
|
||||
/* If we've already read SYSCONFDIR/nanorc (if it's there), we're
|
||||
root, and --disable-wrapping-as-root is used, turn wrapping off */
|
||||
if (euid == NANO_ROOT_UID)
|
||||
if (geteuid() == NANO_ROOT_UID)
|
||||
SET(NO_WRAP);
|
||||
#endif
|
||||
if ((rcstream = fopen(nanorc, "r")) == NULL) {
|
||||
rcstream = fopen(nanorc, "r");
|
||||
if (rcstream == NULL) {
|
||||
/* Don't complain about the file not existing */
|
||||
if (errno != ENOENT) {
|
||||
rcfile_error(N_("Error reading %s: %s"), nanorc, strerror(errno));
|
||||
|
@ -702,10 +704,10 @@ void do_rcfile(void)
|
|||
parse_rcfile(rcstream);
|
||||
fclose(rcstream);
|
||||
}
|
||||
free(nanorcf);
|
||||
}
|
||||
lineno = 0;
|
||||
|
||||
free(nanorc);
|
||||
#ifdef ENABLE_COLOR
|
||||
set_colorpairs();
|
||||
#endif
|
||||
|
|
59
src/utils.c
59
src/utils.c
|
@ -240,6 +240,65 @@ size_t nstrnlen(const char *s, size_t maxlen)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETLINE
|
||||
/* This function is equivalent to getline(). It was adapted from
|
||||
* GNU mailutils' getline() function. */
|
||||
ssize_t ngetline(char **lineptr, size_t *n, FILE *stream)
|
||||
{
|
||||
return getdelim(lineptr, n, '\n', stream);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETDELIM
|
||||
/* This function is equivalent to getdelim(). It was adapted from
|
||||
* GNU mailutils' getdelim() function. */
|
||||
ssize_t ngetdelim(char **lineptr, size_t *n, int delim, FILE *stream)
|
||||
{
|
||||
static const int line_size = 128;
|
||||
/* Default value for line length. */
|
||||
size_t indx = 0;
|
||||
int c;
|
||||
|
||||
/* Sanity checks. */
|
||||
if (lineptr == NULL || n == NULL || stream == NULL)
|
||||
return -1;
|
||||
|
||||
/* Allocate the line the first time. */
|
||||
if (*lineptr == NULL) {
|
||||
*lineptr = charalloc(line_size);
|
||||
*n = line_size;
|
||||
}
|
||||
|
||||
while ((c = getc(stream)) != EOF) {
|
||||
/* Check if more memory is needed. */
|
||||
if (indx >= *n) {
|
||||
*lineptr = charealloc(*lineptr, *n + line_size);
|
||||
*n += line_size;
|
||||
}
|
||||
|
||||
/* Push the result in the line. */
|
||||
(*lineptr)[indx++] = (char)c;
|
||||
|
||||
/* Bail out. */
|
||||
if (c == delim)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Make room for the null character. */
|
||||
if (indx >= *n) {
|
||||
*lineptr = charealloc(*lineptr, *n + line_size);
|
||||
*n += line_size;
|
||||
}
|
||||
|
||||
/* Null terminate the buffer. */
|
||||
(*lineptr)[indx++] = '\0';
|
||||
|
||||
/* The last line may not have the delimiter, we have to return what
|
||||
* we got and the error will be seen on the next iteration. */
|
||||
return (c == EOF && (indx - 1) == 0) ? -1 : indx - 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If we are searching backwards, we will find the last match that
|
||||
* starts no later than start. Otherwise we find the first match
|
||||
* starting no earlier than start. If we are doing a regexp search, we
|
||||
|
|
Loading…
Reference in New Issue