}
#if !defined(NANO_TINY) && defined(ENABLE_NANORC)
-/* Return $HOME/.nano_history, or NULL if we can't find the home
+/* Return the constructed dorfile path, or NULL if we can't find the home
* directory. The string is dynamically allocated, and should be
* freed. */
-char *histfilename(void)
+char *construct_filename(char *str)
{
- char *nanohist = NULL;
+ char *newstr = NULL;
if (homedir != NULL) {
size_t homelen = strlen(homedir);
- nanohist = charalloc(homelen + 15);
- strcpy(nanohist, homedir);
- strcpy(nanohist + homelen, "/.nano_history");
+ newstr = charalloc(homelen + strlen(str) + 1);
+ strcpy(newstr, homedir);
+ strcpy(newstr + homelen, str);
}
- return nanohist;
+ return newstr;
+
+}
+
+char *histfilename(void)
+{
+ return construct_filename( "/.nano/search_history");
+}
+
+/* Construct the legacy history filename
+ * (Deprecate in 2.5, delete later
+ */
+char *legacyhistfilename(void)
+{
+ return construct_filename("/.nano_history");
+}
+
+char *poshistfilename(void)
+{
+ return construct_filename( "/.nano/filepos_history");
+}
+
+
+
+void history_error(const char *msg, ...)
+{
+ va_list ap;
+
+ va_start(ap, msg);
+ vfprintf(stderr, _(msg), ap);
+ va_end(ap);
+
+ fprintf(stderr, _("\nPress Enter to continue\n"));
+ while (getchar() != '\n')
+ ;
+
+}
+
+/* Now that we have more than one history file, let's just rely
+ on a .nano dir for this stuff. Return 1 if the dir exists
+ or was successfully created, and return 0 otherwise.
+ */
+int check_dotnano(void)
+{
+ struct stat dirstat;
+ char *nanodir = construct_filename("/.nano");
+
+ if (stat(nanodir, &dirstat) == -1) {
+ if (mkdir(nanodir, S_IRWXU | S_IRWXG | S_IRWXO) == -1) {
+ history_error(N_("Unable to create directory %s: %s\nIt is required for saving/loading search history or cursor position\n"),
+ nanodir, strerror(errno));
+ return 0;
+ }
+ } else if (!S_ISDIR(dirstat.st_mode)) {
+ history_error(N_("Path %s is not a directory and needs to be.\nNano will be unable to load or save search or cursor position history\n"));
+ return 0;
+ }
+ return 1;
}
/* Load histories from ~/.nano_history. */
void load_history(void)
{
char *nanohist = histfilename();
+ char *legacyhist = legacyhistfilename();
+ struct stat hstat;
+
+
+ if (histfilename && stat(legacyhist, &hstat) != -1
+ && stat(nanohist, &hstat) == -1) {
+ if (rename(legacyhist, nanohist) == -1)
+ history_error(N_("Detected a legacy nano history file (%s) which I tried to move\nto the preferred location (%s) but encountered an error: %s"),
+ legacyhist, nanohist, strerror(errno));
+ else
+ history_error(N_("Detected a legacy nano history file (%s) which I moved\nto the preferred location (%s)\n(see the nano FAQ about this change)"),
+ legacyhist, nanohist);
+ }
+
+
/* Assume do_rcfile() has reported a missing home directory. */
if (nanohist != NULL) {
if (errno != ENOENT) {
/* Don't save history when we quit. */
UNSET(HISTORYLOG);
- rcfile_error(N_("Error reading %s: %s"), nanohist,
+ history_error(N_("Error reading %s: %s"), nanohist,
strerror(errno));
- fprintf(stderr,
- _("\nPress Enter to continue starting nano.\n"));
- while (getchar() != '\n')
- ;
}
} else {
/* Load a history list (first the search history, then the
free(line);
}
free(nanohist);
+ free(legacyhist);
}
}
return TRUE;
}
-/* Save histories to ~/.nano_history. */
+/* Save histories to ~/.nano/search_history. */
void save_history(void)
{
char *nanohist;
FILE *hist = fopen(nanohist, "wb");
if (hist == NULL)
- rcfile_error(N_("Error writing %s: %s"), nanohist,
+ history_error(N_("Error writing %s: %s"), nanohist,
strerror(errno));
else {
/* Make sure no one else can read from or write to the
if (!writehist(hist, searchage) || !writehist(hist,
replaceage))
- rcfile_error(N_("Error writing %s: %s"), nanohist,
+ history_error(N_("Error writing %s: %s"), nanohist,
strerror(errno));
fclose(hist);
free(nanohist);
}
}
+
+
+/* Analogs for the POS history */
+void save_poshistory(void)
+{
+ char *poshist;
+ char *statusstr;
+ openfilestruct *ofptr = openfile;
+
+ poshist = poshistfilename();
+
+ if (poshist != NULL) {
+ FILE *hist = fopen(poshist, "wb");
+
+ if (hist == NULL)
+ history_error(N_("Error writing %s: %s"), poshist,
+ strerror(errno));
+ else {
+ /* Make sure no one else can read from or write to the
+ * history file. */
+ chmod(poshist, S_IRUSR | S_IWUSR);
+
+ while (1) {
+ char *name = get_full_path(ofptr->filename);
+ statusstr = charalloc(strlen(name) + 2 * sizeof(ssize_t) + 4);
+ sprintf(statusstr, "%s %d %d\n", name, (int) ofptr->current->lineno,
+ (int) strnlenpt(openfile->current->data, openfile->current_x) + 1);
+ if (fwrite(statusstr, sizeof(char), strlen(statusstr), hist) < strlen(statusstr))
+ history_error(N_("Error writing %s: %s"), poshist,
+ strerror(errno));
+ free(name);
+ if (ofptr->next == ofptr)
+ break;
+ ofptr = ofptr->next;
+ }
+ fclose(hist);
+ }
+ free(poshist);
+ }
+}
+
+/* Check the POS history to see if file matches
+ * an existing entry. If so return 1 and set line and column
+ * to the right values Otherwise return 0
+ */
+int check_poshistory(const char *file, ssize_t *line, ssize_t *column)
+{
+ poshiststruct *posptr;
+ char *fullpath = get_full_path(file);
+
+ if (fullpath == NULL)
+ return 0;
+
+ for (posptr = poshistory; posptr != NULL; posptr = posptr->next) {
+ if (!strcmp(posptr->filename, fullpath)) {
+ *line = posptr->lineno;
+ *column = posptr->xno;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+/* Load histories from ~/.nano_history. */
+void load_poshistory(void)
+{
+ char *nanohist = poshistfilename();
+
+
+ /* Assume do_rcfile() has reported a missing home directory. */
+ if (nanohist != NULL) {
+ FILE *hist = fopen(nanohist, "rb");
+
+ if (hist == NULL) {
+ if (errno != ENOENT) {
+ /* Don't save history when we quit. */
+ UNSET(HISTORYLOG);
+ history_error(N_("Error reading %s: %s"), nanohist,
+ strerror(errno));
+ }
+ } else {
+ char *line = NULL, *lineptr, *xptr;
+ size_t buf_len = 0;
+ ssize_t read, lineno, xno;
+ poshiststruct *posptr;
+
+ /* See if we can find the file we're currently editing */
+ while ((read = getline(&line, &buf_len, hist)) >= 0) {
+ if (read > 0 && line[read - 1] == '\n') {
+ read--;
+ line[read] = '\0';
+ }
+ if (read > 0) {
+ unsunder(line, read);
+ }
+ lineptr = parse_next_word(line);
+ xptr = parse_next_word(lineptr);
+ lineno = atoi(lineptr);
+ xno = atoi(xptr);
+ fprintf(stderr, "Read data: file %s, line %d, xpos %d\n", line, lineno, xno);
+ if (poshistory == NULL) {
+ poshistory = nmalloc(sizeof(poshiststruct));
+ poshistory->filename = mallocstrcpy(NULL, line);
+ poshistory->lineno = lineno;
+ poshistory->xno = xno;
+ poshistory->next = NULL;
+ } else {
+ for (posptr = poshistory; posptr != NULL; posptr = posptr->next)
+ ;
+ posptr->next = nmalloc(sizeof(poshiststruct));
+ posptr->next->filename = mallocstrcpy(NULL, line);
+ posptr->next->lineno = lineno;
+ posptr->next->xno = xno;
+ posptr->next->next = NULL;
+ }
+
+ }
+
+ fclose(hist);
+ free(line);
+ }
+ free(nanohist);
+ }
+}
+
#endif /* !NANO_TINY && ENABLE_NANORC */
#if !defined(NANO_TINY) && defined(ENABLE_NANORC)
if (!no_rcfiles && ISSET(HISTORYLOG))
save_history();
+ if (!no_rcfiles && ISSET(POS_HISTORY))
+ save_poshistory();
#endif
#ifdef DEBUG
N_("Don't convert files from DOS/Mac format"));
#endif
print_opt("-O", "--morespace", N_("Use one more line for editing"));
+#ifndef NANO_TINY
+ print_opt("-P", "--poshistory",
+ N_("Save and load history of cursor position"));
+#endif
#ifndef DISABLE_JUSTIFY
print_opt(_("-Q <str>"), _("--quotestr=<str>"),
N_("Quoting string"));
{"tabstospaces", 0, NULL, 'E'},
{"historylog", 0, NULL, 'H'},
{"noconvert", 0, NULL, 'N'},
+ {"poshistory", 0, NULL, 'P'},
{"smooth", 0, NULL, 'S'},
{"quickblank", 0, NULL, 'U'},
{"undo", 0, NULL, 'u'},
while ((optchr =
#ifdef HAVE_GETOPT_LONG
getopt_long(argc, argv,
- "h?ABC:DEFHIKLNOQ:RST:UVWY:abcdefgijklmo:pqr:s:tuvwxz$",
+ "h?ABC:DEFHIKLNOPQ:RST:UVWY:abcdefgijklmo:pqr:s:tuvwxz$",
long_options, NULL)
#else
getopt(argc, argv,
- "h?ABC:DEFHIKLNOQ:RST:UVWY:abcdefgijklmo:pqr:s:tuvwxz$")
+ "h?ABC:DEFHIKLNOPQ:RST:UVWY:abcdefgijklmo:pqr:s:tuvwxz$")
#endif
) != -1) {
switch (optchr) {
case 'O':
SET(MORE_SPACE);
break;
+#ifndef NANO_TINY
+ case 'P':
+ SET(POS_HISTORY);
+ break;
+#endif
#ifndef DISABLE_JUSTIFY
case 'Q':
quotestr = mallocstrcpy(quotestr, optarg);
/* Set up the search/replace history. */
history_init();
#ifdef ENABLE_NANORC
- if (!no_rcfiles && ISSET(HISTORYLOG))
- load_history();
-#endif
-#endif
+ if (!no_rcfiles) {
+ if (ISSET(HISTORYLOG) || ISSET(POS_HISTORY)) {
+ if (check_dotnano() == 0) {
+ UNSET(HISTORYLOG);
+ UNSET(POS_HISTORY);
+ }
+ }
+ if (ISSET(HISTORYLOG))
+ load_history();
+ if (ISSET(POS_HISTORY))
+ load_poshistory();
+ }
+#endif /* ENABLE_NANORC */
+#endif /* NANO_TINY */
#ifndef NANO_TINY
/* Set up the backup directory (unless we're using restricted mode,
iline = 1;
icol = 1;
}
+#ifndef NANO_TINY
+ else {
+ /* See if we have a POS history to use if we haven't overridden it */
+ ssize_t savedposline, savedposcol;
+ if (check_poshistory(argv[i], &savedposline, &savedposcol))
+ do_gotolinecolumn(savedposline, savedposcol, FALSE, FALSE, FALSE,
+ FALSE);
+ }
+#endif /* NANO_TINY */
}
}
}
if (startline > 1 || startcol > 1)
do_gotolinecolumn(startline, startcol, FALSE, FALSE, FALSE,
FALSE);
+# ifndef NANO_TINY
+ else {
+ /* See if we have a POS history to use if we haven't overridden it */
+ ssize_t savedposline, savedposcol;
+ if (check_poshistory(argv[optind], &savedposline, &savedposcol))
+ do_gotolinecolumn(savedposline, savedposcol, FALSE, FALSE, FALSE, FALSE);
+ }
+#endif /* NANO_TINY */
display_main_list();