]> git.wh0rd.org Git - nano.git/commitdiff
per DB's patch, overhaul the rcfile and history file reading and writing
authorDavid Lawrence Ramsey <pooka109@gmail.com>
Tue, 17 Aug 2004 05:23:38 +0000 (05:23 +0000)
committerDavid Lawrence Ramsey <pooka109@gmail.com>
Tue, 17 Aug 2004 05:23:38 +0000 (05:23 +0000)
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

ChangeLog
configure.ac
src/files.c
src/global.c
src/nano.c
src/nano.h
src/proto.h
src/rcfile.c
src/utils.c

index e01a4fed5091cfcc976a61f770bad3f0c16ece91..700f5108b69183d72bacd7b83fcdf48a43940325 100644 (file)
--- a/ChangeLog
+++ b/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,
index 196c4febbc0e72169e1fa9ca9ec1c030688ee518..3e3d87926f3cde136d7e43c74fb5d9dfdbc76f96 100644 (file)
@@ -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,,
index bddfba91608aab2af98fa38db423bcfe646885ec..36e642ee911de117167590251b1bebed2f0b5322 100644 (file)
@@ -2914,30 +2914,30 @@ char *do_browse_from(const char *inpath)
 #endif /* !DISABLE_BROWSER */
 
 #if !defined(NANO_SMALL) && defined(ENABLE_NANORC)
-void load_history(void)
+/* 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)
 {
-    FILE *hist;
-    const struct passwd *userage = NULL;
-    static char *nanohist;
-    char *buf, *ptr;
-    char *homenv = getenv("HOME");
-    historyheadtype *history = &search_history;
+    char *nanohist = NULL;
 
+    if (homedir != NULL) {
+       size_t homelen = strlen(homedir);
 
-    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 = charalloc(homelen + 15);
+       strcpy(nanohist, homedir);
+       strcpy(nanohist + homelen, "/.nano_history");
     }
+    return nanohist;
+}
+
+void load_history(void)
+{
+    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);
index 79f817652a67920d7e0181436af5253d78f33d15..f2a947edc8b3f3b722221cd7637f82872c48b73c 100644 (file)
@@ -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 */
index 07ca0c16c211e219037f9e23dcd67c6b89bf3429..3826ef263a84800d02208b706dbd634ed69bd921 100644 (file)
@@ -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 */
index be0a7af78f1bd861f8c241d5d7e1debc9341801c..b145022f278d247f174b498dd6857c2d07ecce0a 100644 (file)
@@ -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
 #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
index 3ec5e3d9c2f0995c04d2ca9075359c35e7e1a7ad..6f03d74f4eeae344ae8f96cb69e59f4201ff038e 100644 (file)
@@ -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);
index 579bf6c47626732f4495357cab9ffcfb55bb953d..20b9de255bec336ddda464b722ac4416b9590400 100644 (file)
@@ -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
index 4e6b5880fbdfe7c4348a2f3fc8303ba8ac196e76..5619f936362b90db9355d19e2ff24481a847ebc5 100644 (file)
@@ -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