Remove unnecessary definitions for r?index.
[gnulib.git] / lib / backupfile.c
1 /* backupfile.c -- make Emacs style backup file names
2    Copyright (C) 1990 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; if not, write to the Free Software
16    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
17
18 /* David MacKenzie <djm@gnu.ai.mit.edu>.
19    Some algorithms adapted from GNU Emacs. */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <stdio.h>
26 #include <ctype.h>
27 #include <sys/types.h>
28 #include "backupfile.h"
29 #ifdef HAVE_STRING_H
30 #include <string.h>
31 #else
32 #include <strings.h>
33 #endif
34
35 #ifdef HAVE_DIRENT_H
36 #include <dirent.h>
37 #define NLENGTH(direct) (strlen((direct)->d_name))
38 #else /* not HAVE_DIRENT_H */
39 #define dirent direct
40 #define NLENGTH(direct) ((direct)->d_namlen)
41 #ifdef HAVE_SYS_NDIR_H
42 #include <sys/ndir.h>
43 #endif /* HAVE_SYS_NDIR_H */
44 #ifdef HAVE_SYS_DIR_H
45 #include <sys/dir.h>
46 #endif /* HAVE_SYS_DIR_H */
47 #ifdef HAVE_NDIR_H
48 #include <ndir.h>
49 #endif /* HAVE_NDIR_H */
50 #endif /* HAVE_DIRENT_H */
51
52 #ifdef CLOSEDIR_VOID
53 /* Fake a return value. */
54 #define CLOSEDIR(d) (closedir (d), 0)
55 #else
56 #define CLOSEDIR(d) closedir (d)
57 #endif
58
59 #ifdef STDC_HEADERS
60 #include <stdlib.h>
61 #else
62 char *malloc ();
63 #endif
64
65 #if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
66 #define ISASCII(c) 1
67 #else
68 #define ISASCII(c) isascii(c)
69 #endif
70
71 #define ISDIGIT(c) (ISASCII ((unsigned char) (c)) \
72                     && isdigit ((unsigned char) (c)))
73
74 #if defined (HAVE_UNISTD_H)
75 #include <unistd.h>
76 #endif
77
78 #if defined (_POSIX_VERSION)
79 /* POSIX does not require that the d_ino field be present, and some
80    systems do not provide it. */
81 #define REAL_DIR_ENTRY(dp) 1
82 #else
83 #define REAL_DIR_ENTRY(dp) ((dp)->d_ino != 0)
84 #endif
85
86 /* Which type of backup file names are generated. */
87 enum backup_type backup_type = none;
88
89 /* The extension added to file names to produce a simple (as opposed
90    to numbered) backup file name. */
91 char *simple_backup_suffix = "~";
92
93 char *basename ();
94 char *dirname ();
95 static char *concat ();
96 char *find_backup_file_name ();
97 static char *make_version_name ();
98 static int max_backup_version ();
99 static int version_number ();
100
101 /* Return the name of the new backup file for file FILE,
102    allocated with malloc.  Return 0 if out of memory.
103    FILE must not end with a '/' unless it is the root directory.
104    Do not call this function if backup_type == none. */
105
106 char *
107 find_backup_file_name (file)
108      char *file;
109 {
110   char *dir;
111   char *base_versions;
112   int highest_backup;
113
114   if (backup_type == simple)
115     return concat (file, simple_backup_suffix);
116   base_versions = concat (basename (file), ".~");
117   if (base_versions == 0)
118     return 0;
119   dir = dirname (file);
120   if (dir == 0)
121     {
122       free (base_versions);
123       return 0;
124     }
125   highest_backup = max_backup_version (base_versions, dir);
126   free (base_versions);
127   free (dir);
128   if (backup_type == numbered_existing && highest_backup == 0)
129     return concat (file, simple_backup_suffix);
130   return make_version_name (file, highest_backup + 1);
131 }
132
133 /* Return the number of the highest-numbered backup file for file
134    FILE in directory DIR.  If there are no numbered backups
135    of FILE in DIR, or an error occurs reading DIR, return 0.
136    FILE should already have ".~" appended to it. */
137
138 static int
139 max_backup_version (file, dir)
140      char *file, *dir;
141 {
142   DIR *dirp;
143   struct dirent *dp;
144   int highest_version;
145   int this_version;
146   int file_name_length;
147
148   dirp = opendir (dir);
149   if (!dirp)
150     return 0;
151
152   highest_version = 0;
153   file_name_length = strlen (file);
154
155   while ((dp = readdir (dirp)) != 0)
156     {
157       if (!REAL_DIR_ENTRY (dp) || NLENGTH (dp) <= file_name_length)
158         continue;
159
160       this_version = version_number (file, dp->d_name, file_name_length);
161       if (this_version > highest_version)
162         highest_version = this_version;
163     }
164   if (CLOSEDIR (dirp))
165     return 0;
166   return highest_version;
167 }
168
169 /* Return a string, allocated with malloc, containing
170    "FILE.~VERSION~".  Return 0 if out of memory. */
171
172 static char *
173 make_version_name (file, version)
174      char *file;
175      int version;
176 {
177   char *backup_name;
178
179   backup_name = malloc (strlen (file) + 16);
180   if (backup_name == 0)
181     return 0;
182   sprintf (backup_name, "%s.~%d~", file, version);
183   return backup_name;
184 }
185
186 /* If BACKUP is a numbered backup of BASE, return its version number;
187    otherwise return 0.  BASE_LENGTH is the length of BASE.
188    BASE should already have ".~" appended to it. */
189
190 static int
191 version_number (base, backup, base_length)
192      char *base;
193      char *backup;
194      int base_length;
195 {
196   int version;
197   char *p;
198
199   version = 0;
200   if (!strncmp (base, backup, base_length) && ISDIGIT (backup[base_length]))
201     {
202       for (p = &backup[base_length]; ISDIGIT (*p); ++p)
203         version = version * 10 + *p - '0';
204       if (p[0] != '~' || p[1])
205         version = 0;
206     }
207   return version;
208 }
209
210 /* Return the newly-allocated concatenation of STR1 and STR2.
211    If out of memory, return 0. */
212
213 static char *
214 concat (str1, str2)
215      char *str1, *str2;
216 {
217   char *newstr;
218   int str1_length = strlen (str1);
219
220   newstr = malloc (str1_length + strlen (str2) + 1);
221   if (newstr == 0)
222     return 0;
223   strcpy (newstr, str1);
224   strcpy (newstr + str1_length, str2);
225   return newstr;
226 }