source: trunk/third/patch/backupfile.c @ 11119

Revision 11119, 6.6 KB checked in by ghudson, 27 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r11118, which included commits to RCS files with non-trunk default branches.
Line 
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
64char *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. */
101enum 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. */
105const char *simple_backup_suffix = ".orig";
106
107static int max_backup_version __BACKUPFILE_P ((const char *, const char *));
108static 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
115char *
116find_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
165static int
166max_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
201static int
202version_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
224static const char * const backup_args[] =
225{
226  "never", "simple", "nil", "existing", "t", "numbered", 0
227};
228
229static 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
237enum backup_type
238get_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}
Note: See TracBrowser for help on using the repository browser.