1 /* backupfile.c -- make Emacs style backup file names 2 Copyright (C) 1990,1991,1992,1993,1995,1997 Free Software Foundation, Inc. 3 4 This program is free software; you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation; either version 2, or (at your option) 7 any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program; see the file COPYING. 16 If not, write to the Free Software Foundation, 17 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 18 19 /* Written by David MacKenzie <djm@gnu.ai.mit.edu>. 20 Some algorithms adapted from GNU Emacs. */ 21 22 #if HAVE_CONFIG_H 23 # include <config.h> 24 #endif 25 26 #include <argmatch.h> 27 #include <backupfile.h> 28 29 #include <stdio.h> 30 #include <sys/types.h> 31 #if HAVE_STRING_H 32 # include <string.h> 33 #else 34 # include <strings.h> 35 #endif 36 37 #if HAVE_DIRENT_H 38 # include <dirent.h> 39 # define NLENGTH(direct) strlen ((direct)->d_name) 40 #else 41 # define dirent direct 42 # define NLENGTH(direct) ((size_t) (direct)->d_namlen) 43 # if HAVE_SYS_NDIR_H 44 # include <sys/ndir.h> 45 # endif 46 # if HAVE_SYS_DIR_H 47 # include <sys/dir.h> 48 # endif 49 # if HAVE_NDIR_H 50 # include <ndir.h> 51 # endif 52 #endif 53 54 #if CLOSEDIR_VOID 55 /* Fake a return value. */ 56 # define CLOSEDIR(d) (closedir (d), 0) 57 #else 58 # define CLOSEDIR(d) closedir (d) 59 #endif 60 61 #if STDC_HEADERS 62 # include <stdlib.h> 63 #else 64 char *malloc (); 65 #endif 66 67 #if HAVE_DIRENT_H || HAVE_NDIR_H || HAVE_SYS_DIR_H || HAVE_SYS_NDIR_H 68 # define HAVE_DIR 1 69 #else 70 # define HAVE_DIR 0 71 #endif 72 73 #if HAVE_LIMITS_H 74 # include <limits.h> 75 #endif 76 #ifndef CHAR_BIT 77 #define CHAR_BIT 8 78 #endif 79 /* Upper bound on the string length of an integer converted to string. 80 302 / 1000 is ceil (log10 (2.0)). Subtract 1 for the sign bit; 81 add 1 for integer division truncation; add 1 more for a minus sign. */ 82 #define INT_STRLEN_BOUND(t) ((sizeof (t) * CHAR_BIT - 1) * 302 / 1000 + 2) 83 84 /* ISDIGIT differs from isdigit, as follows: 85 - Its arg may be any int or unsigned int; it need not be an unsigned char. 86 - It's guaranteed to evaluate its argument exactly once. 87 - It's typically faster. 88 Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that 89 only '0' through '9' are digits. Prefer ISDIGIT to isdigit unless 90 it's important to use the locale's definition of `digit' even when the 91 host does not conform to Posix. */ 92 #define ISDIGIT(c) ((unsigned) (c) - '0' <= 9) 93 94 #if D_INO_IN_DIRENT 95 # define REAL_DIR_ENTRY(dp) ((dp)->d_ino != 0) 96 #else 97 # define REAL_DIR_ENTRY(dp) 1 98 #endif 99 100 /* Which type of backup file names are generated. */ 101 enum backup_type backup_type = none; 102 103 /* The extension added to file names to produce a simple (as opposed 104 to numbered) backup file name. */ 105 const char *simple_backup_suffix = ".orig"; 106 107 static int max_backup_version __BACKUPFILE_P ((const char *, const char *)); 108 static int version_number __BACKUPFILE_P ((const char *, const char *, size_t)); 109 110 /* Return the name of the new backup file for file FILE, 111 allocated with malloc. Return 0 if out of memory. 112 FILE must not end with a '/' unless it is the root directory. 113 Do not call this function if backup_type == none. */ 114 115 char * 116 find_backup_file_name (file) 117 const char *file; 118 { 119 size_t backup_suffix_size_max; 120 size_t file_len = strlen (file); 121 size_t numbered_suffix_size_max = INT_STRLEN_BOUND (int) + 4; 122 char *s; 123 const char *suffix = simple_backup_suffix; 124 125 /* Allow room for simple or `.~N~' backups. */ 126 backup_suffix_size_max = strlen (simple_backup_suffix) + 1; 127 if (HAVE_DIR && backup_suffix_size_max < numbered_suffix_size_max) 128 backup_suffix_size_max = numbered_suffix_size_max; 129 130 s = malloc (file_len + backup_suffix_size_max + numbered_suffix_size_max); 131 if (s) 132 { 133 strcpy (s, file); 134 135 #if HAVE_DIR 136 if (backup_type != simple) 137 { 138 int highest_backup; 139 size_t dir_len = base_name (s) - s; 140 141 strcpy (s + dir_len, "."); 142 highest_backup = max_backup_version (file + dir_len, s); 143 if (! (backup_type == numbered_existing && highest_backup == 0)) 144 { 145 char *numbered_suffix = s + (file_len + backup_suffix_size_max); 146 sprintf (numbered_suffix, ".~%d~", highest_backup + 1); 147 suffix = numbered_suffix; 148 } 149 strcpy (s, file); 150 } 151 #endif /* HAVE_DIR */ 152 153 addext (s, suffix, '~'); 154 } 155 return s; 156 } 157 158 #if HAVE_DIR 159 160 /* Return the number of the highest-numbered backup file for file 161 FILE in directory DIR. If there are no numbered backups 162 of FILE in DIR, or an error occurs reading DIR, return 0. 163 */ 164 165 static int 166 max_backup_version (file, dir) 167 const char *file; 168 const char *dir; 169 { 170 DIR *dirp; 171 struct dirent *dp; 172 int highest_version; 173 int this_version; 174 size_t file_name_length; 175 176 dirp = opendir (dir); 177 if (!dirp) 178 return 0; 179 180 highest_version = 0; 181 file_name_length = strlen (file); 182 183 while ((dp = readdir (dirp)) != 0) 184 { 185 if (!REAL_DIR_ENTRY (dp) || NLENGTH (dp) < file_name_length + 4) 186 continue; 187 188 this_version = version_number (file, dp->d_name, file_name_length); 189 if (this_version > highest_version) 190 highest_version = this_version; 191 } 192 if (CLOSEDIR (dirp)) 193 return 0; 194 return highest_version; 195 } 196 197 /* If BACKUP is a numbered backup of BASE, return its version number; 198 otherwise return 0. BASE_LENGTH is the length of BASE. 199 */ 200 201 static int 202 version_number (base, backup, base_length) 203 const char *base; 204 const char *backup; 205 size_t base_length; 206 { 207 int version; 208 const char *p; 209 210 version = 0; 211 if (strncmp (base, backup, base_length) == 0 212 && backup[base_length] == '.' 213 && backup[base_length + 1] == '~') 214 { 215 for (p = &backup[base_length + 2]; ISDIGIT (*p); ++p) 216 version = version * 10 + *p - '0'; 217 if (p[0] != '~' || p[1]) 218 version = 0; 219 } 220 return version; 221 } 222 #endif /* HAVE_DIR */ 223 224 static const char * const backup_args[] = 225 { 226 "never", "simple", "nil", "existing", "t", "numbered", 0 227 }; 228 229 static const enum backup_type backup_types[] = 230 { 231 simple, simple, numbered_existing, numbered_existing, numbered, numbered 232 }; 233 234 /* Return the type of backup indicated by VERSION. 235 Unique abbreviations are accepted. */ 236 237 enum backup_type 238 get_version (version) 239 const char *version; 240 { 241 int i; 242 243 if (version == 0 || *version == 0) 244 return numbered_existing; 245 i = argmatch (version, backup_args); 246 if (i < 0) 247 { 248 invalid_arg ("version control type", version, i); 249 exit (2); 250 } 251 return backup_types[i]; 252 } 253