From 04e42a6bcc111d12172767c61c3b384c25f3460a Mon Sep 17 00:00:00 2001 From: David Lawrence Ramsey Date: Sat, 28 Feb 2004 16:24:31 +0000 Subject: [PATCH] Martin Ehmsen's backup directory patch, with a few minor changes git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@1674 35c25a1d-7b9e-4130-9fde-d3aeb78583b8 --- ChangeLog | 12 ++++++ doc/man/nano.1 | 4 ++ doc/man/nanorc.5 | 4 ++ doc/nanorc.sample | 3 ++ doc/texinfo/nano.texi | 4 ++ src/files.c | 92 ++++++++++++++++++++++++++++++++++--------- src/global.c | 8 ++++ src/nano.c | 28 ++++++++++++- src/proto.h | 11 +++++- src/rcfile.c | 21 +++++++--- 10 files changed, 160 insertions(+), 27 deletions(-) diff --git a/ChangeLog b/ChangeLog index df7d735d..d240b3f7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -23,6 +23,13 @@ CVS code - - Decouple the paragraph searching code and the justifying code. Removed function do_para_operation(); new function do_para_search(); changes to do_justify(). (DLR) + - Add -E/--backupdir option. When used with -B/--backup, backup + files will be saved in the specified directory with their + canonical pathnames encoded in their names (all '/'s replaced + with '!'s). Changes to write_file(). (Martin Ehmsen) DLR: + Add function init_backup_dir() to handle relative paths + correctly, use get_full_path() to get the canonical pathname, + and use tail() to get the filename if get_full_path() fails. - files.c: add_open_files() - Make the saving of marked status in open_files->file_flags @@ -199,6 +206,11 @@ CVS code - not 1.1.12. (DLR) - nano.1, nanorc.5, nano.texi - Clarify the description for -T/--tabsize a bit. (DLR) + - Add -E/--backupdir description. (Martin Ehmsen; minor cosmetic + fixes by DLR) +- nanorc.sample: + - Add backupdir description. (Martin Ehmsen; minor cosmetic + fixes by DLR) - README: - Reformat to 72 characters per line, fix wording in one spot, and fix spacing in several spots. (DLR) diff --git a/doc/man/nano.1 b/doc/man/nano.1 index a8b7e630..889732c0 100644 --- a/doc/man/nano.1 +++ b/doc/man/nano.1 @@ -42,6 +42,10 @@ filename suffixed with a ~. .B \-D (\-\-dos) Write file in DOS format. .TP +.B \-E \fIdir\fP (\-\-backupdir=\fIdir\fP) +Set the directory where \fBnano\fP puts the backup files if file backups +are enabled. +.TP .B \-F (\-\-multibuffer) Enable multiple file buffers, if available. .TP diff --git a/doc/man/nanorc.5 b/doc/man/nanorc.5 index 05873459..924da881 100644 --- a/doc/man/nanorc.5 +++ b/doc/man/nanorc.5 @@ -47,6 +47,10 @@ Use auto-indentation. Create backup files in .IR filename~ . .TP +\fBset backupdir "\fIdirectory\fP"\fP +Set the directory where \fBnano\fP puts the backup files if file backups +are enabled. +.TP \fBset/unset const\fP Constantly display the cursor position in the status bar. .TP diff --git a/doc/nanorc.sample b/doc/nanorc.sample index eee7cdb3..98bb6a8a 100644 --- a/doc/nanorc.sample +++ b/doc/nanorc.sample @@ -14,6 +14,9 @@ ## Backup files to filename~ # set backup +## The directory to put the backup files in. +# set backupdir "" + ## Constantly display the cursor position in the status bar. # set const diff --git a/doc/texinfo/nano.texi b/doc/texinfo/nano.texi index 487f555d..1158d28a 100644 --- a/doc/texinfo/nano.texi +++ b/doc/texinfo/nano.texi @@ -114,6 +114,10 @@ filename suffixed with a ~. @item -D, --dos Write file in DOS format. +@item -E, --backupdir=[dir] +Set the directory where @code{nano) puts the backup files if file +backups are enabled. + @item -F, --multibuffer Enable multiple file buffers, if available. diff --git a/src/files.c b/src/files.c index 04d043d7..d69c46b8 100644 --- a/src/files.c +++ b/src/files.c @@ -1026,7 +1026,7 @@ int close_open_file(void) } #endif /* MULTIBUFFER */ -#if !defined(DISABLE_SPELLER) || !defined(DISABLE_OPERATINGDIR) +#if !defined(DISABLE_SPELLER) || !defined(DISABLE_OPERATINGDIR) || !defined(NANO_SMALL) /* * When passed "[relative path]" or "[relative path][filename]" in * origpath, return "[full path]" or "[full path][filename]" on success, @@ -1333,6 +1333,30 @@ int check_operating_dir(const char *currpath, int allow_tabcomp) } #endif +#ifndef NANO_SMALL +void init_backup_dir(void) +{ + char *full_backup_dir; + + if (backup_dir == NULL) + return; + + full_backup_dir = get_full_path(backup_dir); + + /* If get_full_path() failed or the backup directory is + * inaccessible, unset backup_dir. */ + if (full_backup_dir == NULL || + full_backup_dir[strlen(full_backup_dir) - 1] != '/') { + free(full_backup_dir); + free(backup_dir); + backup_dir = NULL; + } else { + free(backup_dir); + backup_dir = full_backup_dir; + } +} +#endif + /* Read from inn, write to out. We assume inn is opened for reading, * and out for writing. We return 0 on success, -1 on read error, -2 on * write error. */ @@ -1465,8 +1489,38 @@ int write_file(const char *name, int tmp, int append, int nonamechange) goto cleanup_and_exit; } - backupname = charalloc(strlen(realname) + 2); - sprintf(backupname, "%s~", realname); + /* If backup_dir is set, we set backupname to + * backup_dir/backupname~, where backupnae is the canonicalized + * absolute pathname of realname with every '/' replaced with a + * '!'. This means that /home/foo/file is backed up in + * backup_dir/!home!foo!file~. */ + if (backup_dir != NULL) { + char *canon_realname = get_full_path(realname); + size_t i; + + if (canon_realname == NULL) + /* If get_full_path() failed, we don't have a + * canonicalized absolute pathname, so just use the + * filename portion of the pathname. We use tail() so + * that e.g. ../backupname will be backed up in + * backupdir/backupname~ instead of + * backupdir/../backupname~. */ + canon_realname = mallocstrcpy(NULL, tail(realname)); + else { + for (i = 0; canon_realname[i] != '\0'; i++) { + if (canon_realname[i] == '/') + canon_realname[i] = '!'; + } + } + + backupname = charalloc(strlen(backup_dir) + + strlen(canon_realname) + 2); + sprintf(backupname, "%s%s~", backup_dir, canon_realname); + free(canon_realname); + } else { + backupname = charalloc(strlen(realname) + 2); + sprintf(backupname, "%s~", realname); + } /* Open the destination backup file. Before we write to it, we * set its permissions, so no unauthorized person can read it as @@ -2370,6 +2424,23 @@ char *input_tab(char *buf, int place, int *lastwastab, int *newplace, int *list) } #endif /* !DISABLE_TABCOMP */ +#if !defined(DISABLE_BROWSER) || !defined(NANO_SMALL) +/* Only print the last part of a path; isn't there a shell + * command for this? */ +const char *tail(const char *foo) +{ + const char *tmp = foo + strlen(foo); + + while (*tmp != '/' && tmp != foo) + tmp--; + + if (*tmp == '/') + tmp++; + + return tmp; +} +#endif + #ifndef DISABLE_BROWSER /* Our sort routine for file listings -- sort directories before * files, and then alphabetically. */ @@ -2396,21 +2467,6 @@ void free_charptrarray(char **array, int len) free(array); } -/* Only print the last part of a path; isn't there a shell - * command for this? */ -const char *tail(const char *foo) -{ - const char *tmp = foo + strlen(foo); - - while (*tmp != '/' && tmp != foo) - tmp--; - - if (*tmp == '/') - tmp++; - - return tmp; -} - /* Strip one dir from the end of a string. */ void striponedir(char *foo) { diff --git a/src/global.c b/src/global.c index 4e4ec377..34d27aa0 100644 --- a/src/global.c +++ b/src/global.c @@ -72,6 +72,10 @@ char *quotestr = NULL; /* Quote string. The default value is set in main(). */ #endif +#ifndef NANO_SMALL +char *backup_dir = NULL; /* Backup directory. */ +#endif + int resetstatuspos; /* Hack for resetting the status bar cursor position */ char *answer = NULL; /* Answer str to many questions */ @@ -932,6 +936,10 @@ void thanks_for_all_the_fish(void) if (quotestr != NULL) free(quotestr); #endif +#ifndef NANO_SMALL + if (backup_dir != NULL) + free(backup_dir); +#endif #ifndef DISABLE_OPERATINGDIR if (operating_dir != NULL) free(operating_dir); diff --git a/src/nano.c b/src/nano.c index e2dc353e..15c1fe5e 100644 --- a/src/nano.c +++ b/src/nano.c @@ -629,6 +629,7 @@ void usage(void) #ifndef NANO_SMALL print1opt("-B", "--backup", _("Backup existing files on save")); print1opt("-D", "--dos", _("Write file in DOS format")); + print1opt("-E", "--backupdir=[dir]", _("Directory for writing backup files")); #endif #ifdef ENABLE_MULTIBUFFER print1opt("-F", "--multibuffer", _("Enable multiple file buffers")); @@ -3152,6 +3153,7 @@ int main(int argc, char *argv[]) #ifndef NANO_SMALL {"backup", 0, 0, 'B'}, {"dos", 0, 0, 'D'}, + {"backupdir", 1, 0, 'E'}, {"mac", 0, 0, 'M'}, {"noconvert", 0, 0, 'N'}, {"smooth", 0, 0, 'S'}, @@ -3176,11 +3178,11 @@ int main(int argc, char *argv[]) #endif #ifdef HAVE_GETOPT_LONG - while ((optchr = getopt_long(argc, argv, "h?BDFHIMNQ:RST:VY:abcdefgijklmo:pr:s:tvwxz", + while ((optchr = getopt_long(argc, argv, "h?BDE:FHIMNQ:RST:VY:abcdefgijklmo:pr:s:tvwxz", long_options, NULL)) != -1) { #else while ((optchr = - getopt(argc, argv, "h?BDFHIMNQ:RST:VY:abcdefgijklmo:pr:s:tvwxz")) != -1) { + getopt(argc, argv, "h?BDE:FHIMNQ:RST:VY:abcdefgijklmo:pr:s:tvwxz")) != -1) { #endif switch (optchr) { @@ -3200,6 +3202,9 @@ int main(int argc, char *argv[]) case 'D': SET(DOS_FILE); break; + case 'E': + backup_dir = mallocstrcpy(backup_dir, optarg); + break; #endif #ifdef ENABLE_MULTIBUFFER case 'F': @@ -3350,6 +3355,9 @@ int main(int argc, char *argv[]) #ifndef DISABLE_WRAPPING int wrap_at_cpy = wrap_at; #endif +#ifndef NANO_SMALL + char *backup_dir_cpy = backup_dir; +#endif #ifndef DISABLE_JUSTIFY char *quotestr_cpy = quotestr; #endif @@ -3362,6 +3370,9 @@ int main(int argc, char *argv[]) #ifndef DISABLE_OPERATINGDIR operating_dir = NULL; #endif +#ifndef NANO_SMALL + backup_dir = NULL; +#endif #ifndef DISABLE_JUSTIFY quotestr = NULL; #endif @@ -3381,6 +3392,12 @@ int main(int argc, char *argv[]) if (fill_flag_used) wrap_at = wrap_at_cpy; #endif +#ifndef NANO_SMALL + if (backup_dir_cpy != NULL) { + free(backup_dir); + backup_dir = backup_dir_cpy; + } +#endif #ifndef DISABLE_JUSTIFY if (quotestr_cpy != NULL) { free(quotestr); @@ -3411,6 +3428,12 @@ int main(int argc, char *argv[]) #endif #endif +#ifndef NANO_SMALL + /* Set up the backup directory. This entails making sure it exists + * and is a directory, so that backup files will be saved there. */ + init_backup_dir(); +#endif + #ifndef DISABLE_OPERATINGDIR /* Set up the operating directory. This entails chdir()ing there, so that file reads and writes will be based there. */ @@ -3425,6 +3448,7 @@ int main(int argc, char *argv[]) quotestr = mallocstrcpy(NULL, "> "); #endif #endif /* !DISABLE_JUSTIFY */ + if (tabsize == -1) tabsize = 8; diff --git a/src/proto.h b/src/proto.h index d330b7d6..83697ffc 100644 --- a/src/proto.h +++ b/src/proto.h @@ -50,6 +50,10 @@ extern int currslen; extern char *quotestr; #endif +#ifndef NANO_SMALL +extern char *backup_dir; +#endif + extern WINDOW *edit, *topwin, *bottomwin; extern char *filename; extern struct stat originalfilestat; @@ -178,6 +182,9 @@ char *safe_tempnam(const char *dirname, const char *filename_prefix); void init_operating_dir(void); int check_operating_dir(const char *currpath, int allow_tabcomp); #endif +#ifndef NANO_SMALL +void init_backup_dir(void); +#endif int write_file(const char *name, int tmp, int append, int nonamechange); #ifndef NANO_SMALL int write_marked(const char *name, int tmp, int append, int @@ -192,10 +199,12 @@ char **username_tab_completion(char *buf, int *num_matches); char **cwd_tab_completion(char *buf, int *num_matches); char *input_tab(char *buf, int place, int *lastwastab, int *newplace, int *list); #endif +#if !defined(DISABLE_BROWSER) || !defined(NANO_SMALL) +const char *tail(const char *foo); +#endif #ifndef DISABLE_BROWSER int diralphasort(const void *va, const void *vb); void free_charptrarray(char **array, int len); -const char *tail(const char *foo); void striponedir(char *foo); int readable_dir(const char *path); char **browser_init(const char *path, int *longest, int *numents); diff --git a/src/rcfile.c b/src/rcfile.c index e15379c9..dcfdb8c7 100644 --- a/src/rcfile.c +++ b/src/rcfile.c @@ -41,6 +41,7 @@ const static rcoption rcopts[] = { #ifndef NANO_SMALL {"autoindent", AUTOINDENT}, {"backup", BACKUP_FILE}, + {"backupdir", 0}, #endif {"const", CONSTUPDATE}, #ifndef NANO_SMALL @@ -145,12 +146,12 @@ char *parse_next_word(char *ptr) return ptr; } -/* The keywords operatingdir, fill, tabsize, speller, and quotestr take - * an argument when set. Among these, operatingdir, speller, and - * quotestr have to allow tabs and spaces in the argument. Thus, if the - * next word starts with a ", we say it ends with the last " of the line. - * Otherwise, the word is interpreted as usual. That is so the arguments - * can contain "s too. */ +/* The keywords operatingdir, backupdir, fill, tabsize, speller, and + * quotestr take an argument when set. Among these, operatingdir, + * backupdir, speller, and quotestr have to allow tabs and spaces in the + * argument. Thus, if the next word starts with a ", we say it ends + * with the last " of the line. Otherwise, the word is interpreted as + * usual. That is so the arguments can contain "s too. */ char *parse_argument(char *ptr) { const char *ptr_bak = ptr; @@ -540,6 +541,9 @@ void parse_rcfile(FILE *rcstream) #ifndef DISABLE_JUSTIFY || !strcasecmp(rcopts[i].name, "quotestr") #endif +#ifndef NANO_SMALL + || !strcasecmp(rcopts[i].name, "backupdir") +#endif #ifndef DISABLE_SPELLER || !strcasecmp(rcopts[i].name, "speller") #endif @@ -582,6 +586,11 @@ void parse_rcfile(FILE *rcstream) quotestr = mallocstrcpy(NULL, option); else #endif +#ifndef NANO_SMALL + if (!strcasecmp(rcopts[i].name, "backupdir")) + backup_dir = mallocstrcpy(NULL, option); + else +#endif #ifndef DISABLE_SPELLER if (!strcasecmp(rcopts[i].name, "speller")) alt_speller = mallocstrcpy(NULL, option); -- 2.39.5