Guard inclusion of stdlib.h with `#if HAVE_STDLIB_H', not `#if STDC_HEADERS'.
[gnulib.git] / lib / backupfile.c
1 /* backupfile.c -- make Emacs style backup file names
2    Copyright (C) 1990-1997, 1998, 1999, 2000 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 HAVE_STDLIB_H
62 # include <stdlib.h>
63 #endif
64
65 #ifndef HAVE_DECL_GETENV
66 "this configure-time declaration test was not run"
67 #endif
68 #if !HAVE_DECL_GETENV
69 char *getenv ();
70 #endif
71
72 #ifndef HAVE_DECL_MALLOC
73 "this configure-time declaration test was not run"
74 #endif
75 #if !HAVE_DECL_MALLOC
76 char *malloc ();
77 #endif
78
79 char *base_name PARAMS ((char const *));
80
81 #if HAVE_DIRENT_H || HAVE_NDIR_H || HAVE_SYS_DIR_H || HAVE_SYS_NDIR_H
82 # define HAVE_DIR 1
83 #else
84 # define HAVE_DIR 0
85 #endif
86
87 #if HAVE_LIMITS_H
88 # include <limits.h>
89 #endif
90 #ifndef CHAR_BIT
91 # define CHAR_BIT 8
92 #endif
93 /* Upper bound on the string length of an integer converted to string.
94    302 / 1000 is ceil (log10 (2.0)).  Subtract 1 for the sign bit;
95    add 1 for integer division truncation; add 1 more for a minus sign.  */
96 #define INT_STRLEN_BOUND(t) ((sizeof (t) * CHAR_BIT - 1) * 302 / 1000 + 2)
97
98 /* ISDIGIT differs from isdigit, as follows:
99    - Its arg may be any int or unsigned int; it need not be an unsigned char.
100    - It's guaranteed to evaluate its argument exactly once.
101    - It's typically faster.
102    Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that
103    only '0' through '9' are digits.  Prefer ISDIGIT to isdigit unless
104    it's important to use the locale's definition of `digit' even when the
105    host does not conform to Posix.  */
106 #define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
107
108 #if D_INO_IN_DIRENT
109 # define REAL_DIR_ENTRY(dp) ((dp)->d_ino != 0)
110 #else
111 # define REAL_DIR_ENTRY(dp) 1
112 #endif
113
114 /* The extension added to file names to produce a simple (as opposed
115    to numbered) backup file name. */
116 const char *simple_backup_suffix = "~";
117
118 static int max_backup_version PARAMS ((const char *, const char *));
119 static int version_number PARAMS ((const char *, const char *, size_t));
120
121 /* Return the name of the new backup file for file FILE,
122    allocated with malloc.  Return 0 if out of memory.
123    FILE must not end with a '/' unless it is the root directory.
124    Do not call this function if backup_type == none. */
125
126 char *
127 find_backup_file_name (const char *file, enum backup_type backup_type)
128 {
129   size_t backup_suffix_size_max;
130   size_t file_len = strlen (file);
131   size_t numbered_suffix_size_max = INT_STRLEN_BOUND (int) + 4;
132   char *s;
133   const char *suffix = simple_backup_suffix;
134
135   /* Allow room for simple or `.~N~' backups.  */
136   backup_suffix_size_max = strlen (simple_backup_suffix) + 1;
137   if (HAVE_DIR && backup_suffix_size_max < numbered_suffix_size_max)
138     backup_suffix_size_max = numbered_suffix_size_max;
139
140   s = malloc (file_len + backup_suffix_size_max + numbered_suffix_size_max);
141   if (s)
142     {
143       strcpy (s, file);
144
145 #if HAVE_DIR
146       if (backup_type != simple)
147         {
148           int highest_backup;
149           size_t dir_len = base_name (s) - s;
150
151           strcpy (s + dir_len, ".");
152           highest_backup = max_backup_version (file + dir_len, s);
153           if (! (backup_type == numbered_existing && highest_backup == 0))
154             {
155               char *numbered_suffix = s + (file_len + backup_suffix_size_max);
156               sprintf (numbered_suffix, ".~%d~", highest_backup + 1);
157               suffix = numbered_suffix;
158             }
159           strcpy (s, file);
160         }
161 #endif /* HAVE_DIR */
162
163       addext (s, suffix, '~');
164     }
165   return s;
166 }
167
168 #if HAVE_DIR
169
170 /* Return the number of the highest-numbered backup file for file
171    FILE in directory DIR.  If there are no numbered backups
172    of FILE in DIR, or an error occurs reading DIR, return 0.
173    */
174
175 static int
176 max_backup_version (const char *file, const char *dir)
177 {
178   DIR *dirp;
179   struct dirent *dp;
180   int highest_version;
181   int this_version;
182   size_t file_name_length;
183
184   dirp = opendir (dir);
185   if (!dirp)
186     return 0;
187
188   highest_version = 0;
189   file_name_length = strlen (file);
190
191   while ((dp = readdir (dirp)) != 0)
192     {
193       if (!REAL_DIR_ENTRY (dp) || NLENGTH (dp) < file_name_length + 4)
194         continue;
195
196       this_version = version_number (file, dp->d_name, file_name_length);
197       if (this_version > highest_version)
198         highest_version = this_version;
199     }
200   if (CLOSEDIR (dirp))
201     return 0;
202   return highest_version;
203 }
204
205 /* If BACKUP is a numbered backup of BASE, return its version number;
206    otherwise return 0.  BASE_LENGTH is the length of BASE.
207    */
208
209 static int
210 version_number (const char *base, const char *backup, size_t base_length)
211 {
212   int version;
213   const char *p;
214
215   version = 0;
216   if (strncmp (base, backup, base_length) == 0
217       && backup[base_length] == '.'
218       && backup[base_length + 1] == '~')
219     {
220       for (p = &backup[base_length + 2]; ISDIGIT (*p); ++p)
221         version = version * 10 + *p - '0';
222       if (p[0] != '~' || p[1])
223         version = 0;
224     }
225   return version;
226 }
227 #endif /* HAVE_DIR */
228
229 static const char * const backup_args[] =
230 {
231   /* In a series of synonyms, present the most meaning full first, so
232      that argmatch_valid be more readable. */
233   "none", "off",
234   "simple", "never",
235   "existing", "nil",
236   "numbered", "t",
237   0
238 };
239
240 static const enum backup_type backup_types[] =
241 {
242   none, none,
243   simple, simple,
244   numbered_existing, numbered_existing,
245   numbered, numbered
246 };
247
248 /* Return the type of backup specified by VERSION.
249    If VERSION is NULL or the empty string, return numbered_existing.
250    If VERSION is invalid or ambiguous, fail with a diagnostic appropriate
251    for the specified CONTEXT.  Unambiguous abbreviations are accepted.  */
252
253 enum backup_type
254 get_version (const char *context, const char *version)
255 {
256   if (version == 0 || *version == 0)
257     return numbered_existing;
258   else
259     return XARGMATCH (context, version, backup_args, backup_types);
260 }
261
262
263 /* Return the type of backup specified by VERSION.
264    If VERSION is NULL, use the value of the envvar VERSION_CONTROL.
265    If the specified string is invalid or ambiguous, fail with a diagnostic
266    appropriate for the specified CONTEXT.
267    Unambiguous abbreviations are accepted.  */
268
269 enum backup_type
270 xget_version (const char *context, const char *version)
271 {
272   if (version && *version)
273     return get_version (context, version);
274   else
275     return get_version ("$VERSION_CONTROL", getenv ("VERSION_CONTROL"));
276 }