]> git.ipfire.org Git - thirdparty/gettext.git/commitdiff
Subroutines for backing up a regular file.
authorBruno Haible <bruno@clisp.org>
Sat, 20 Oct 2001 13:13:38 +0000 (13:13 +0000)
committerBruno Haible <bruno@clisp.org>
Sat, 20 Oct 2001 13:13:38 +0000 (13:13 +0000)
ChangeLog
configure.in
lib/ChangeLog
lib/Makefile.am
lib/addext.c [new file with mode: 0644]
lib/backupfile.c [new file with mode: 0644]
lib/backupfile.h [new file with mode: 0644]
m4/ChangeLog
m4/Makefile.am
m4/backupfile.m4 [new file with mode: 0644]

index 57bff64258b52a7de19d2372c60e5bd64f4593a0..36488c44821089d96b01122a873236afbddd8f31 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2001-09-17  Bruno Haible  <haible@clisp.cons.org>
+
+       * configure.in: Call gt_PREREQ_BACKUPFILE.
+
 2001-09-17  Bruno Haible  <haible@clisp.cons.org>
 
        * configure.in: Check for utime and utimes.
index 4bb0fe5564d5b67bab3620843643c6d7ffe85bc5..55b3ec0b03c405d76cdd21874298f98bbb5ffcfb 100644 (file)
@@ -75,6 +75,7 @@ if test $am_cv_func_working_getline != yes; then
   AC_CHECK_FUNCS(getdelim)
 fi
 jm_PREREQ_MBSWIDTH
+gt_PREREQ_BACKUPFILE
 AC_FUNC_VFORK
 gt_UNION_WAIT
 gt_TMPDIR
index bab72121b60c35426941c228c200e45b7e07033c..80e56dd2a90b1c03b027c3c79918ca9d8cfa2693 100644 (file)
@@ -1,3 +1,11 @@
+2001-09-17  Bruno Haible  <haible@clisp.cons.org>
+
+       * backupfile.h: New file, from fileutils-4.1 with modifications.
+       * backupfile.c: New file, from fileutils-4.1 with modifications.
+       * addext.c: New file, from fileutils-4.1 with modifications.
+       * Makefile.am (libnlsut_a_SOURCES): Add backupfile.c, addext.c.
+       (libnlsut_a_HEADER): Add backupfile.h.
+
 2001-09-17  Bruno Haible  <haible@clisp.cons.org>
 
        * argmatch.h: New file, from fileutils-4.1 with simplifications.
index 079fa14b4156188abf0f0e8b90148f971686b90e..324a20aac12c66a18ae4f1e4bf04183b0d14ef8e 100644 (file)
@@ -23,17 +23,17 @@ noinst_LIBRARIES = libnlsut.a
 
 # Sources that are compiled on all platforms.
 
-libnlsut_a_SOURCES = argmatch.c basename.c c-ctype.c concatpath.c copy-file.c \
-execute.c findprog.c fstrcmp.c full-write.c gcd.c getopt.c getopt1.c hash.c \
-javacomp.c javaexec.c linebreak.c localcharset.c mbswidth.c obstack.c \
-pipe-bidi.c pipe-in.c pipe-out.c progname.c sh-quote.c tmpdir.c \
-wait-process.c xerror.c xgetcwd.c xmalloc.c xstrdup.c
-
-libnlsut_a_HEADER = argmatch.h basename.h c-ctype.h copy-file.h execute.h \
-findprog.h fstrcmp.h full-write.h gcd.h getopt.h hash.h javacomp.h javaexec.h \
-lbrkprop.h linebreak.h mbswidth.h obstack.h pathmax.h pipe.h progname.h \
-sh-quote.h system.h tmpdir.h utf8-ucs4.h utf16-ucs4.h wait-process.h xerror.h \
-xmalloc.h
+libnlsut_a_SOURCES = addext.c argmatch.c backupfile.c basename.c c-ctype.c \
+concatpath.c copy-file.c execute.c findprog.c fstrcmp.c full-write.c gcd.c \
+getopt.c getopt1.c hash.c javacomp.c javaexec.c linebreak.c localcharset.c \
+mbswidth.c obstack.c pipe-bidi.c pipe-in.c pipe-out.c progname.c sh-quote.c \
+tmpdir.c wait-process.c xerror.c xgetcwd.c xmalloc.c xstrdup.c
+
+libnlsut_a_HEADER = argmatch.h backupfile.h basename.h c-ctype.h copy-file.h \
+execute.h findprog.h fstrcmp.h full-write.h gcd.h getopt.h hash.h javacomp.h \
+javaexec.h lbrkprop.h linebreak.h mbswidth.h obstack.h pathmax.h pipe.h \
+progname.h sh-quote.h system.h tmpdir.h utf8-ucs4.h utf16-ucs4.h \
+wait-process.h xerror.h xmalloc.h
 
 # Sources that are compiled only on platforms that lack the functions.
 
diff --git a/lib/addext.c b/lib/addext.c
new file mode 100644 (file)
index 0000000..9e601bd
--- /dev/null
@@ -0,0 +1,108 @@
+/* addext.c -- add an extension to a file name
+   Copyright (C) 1990, 1997-1999, 2001 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; see the file COPYING.
+   If not, write to the Free Software Foundation,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+/* Written by David MacKenzie <djm@gnu.ai.mit.edu> and Paul Eggert */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifndef HAVE_DOS_FILE_NAMES
+# define HAVE_DOS_FILE_NAMES 0
+#endif
+#ifndef HAVE_LONG_FILE_NAMES
+# define HAVE_LONG_FILE_NAMES 0
+#endif
+
+#include "backupfile.h"
+
+#if HAVE_LIMITS_H
+# include <limits.h>
+#endif
+#ifndef _POSIX_NAME_MAX
+# define _POSIX_NAME_MAX 14
+#endif
+
+#include <sys/types.h>
+#if HAVE_STRING_H
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "basename.h"
+
+/* Append to FILENAME the extension EXT, unless the result would be too long,
+   in which case just append the character E.  */
+
+void
+addext (filename, ext, e)
+     char *filename;
+     char const *ext;
+     int e;
+{
+  char *s = basename (filename);
+  size_t slen = strlen (s), extlen = strlen (ext);
+  long slen_max = -1;
+
+#if HAVE_PATHCONF && defined _PC_NAME_MAX
+  if (slen + extlen <= _POSIX_NAME_MAX && ! HAVE_DOS_FILE_NAMES)
+    /* The file name is so short there's no need to call pathconf.  */
+    slen_max = _POSIX_NAME_MAX;
+  else if (s == filename)
+    slen_max = pathconf (".", _PC_NAME_MAX);
+  else
+    {
+      char c = *s;
+      *s = 0;
+      slen_max = pathconf (filename, _PC_NAME_MAX);
+      *s = c;
+    }
+#endif
+  if (slen_max < 0)
+    slen_max = HAVE_LONG_FILE_NAMES ? 255 : 14;
+
+  if (HAVE_DOS_FILE_NAMES && slen_max <= 12)
+    {
+      /* Live within DOS's 8.3 limit.  */
+      char *dot = strchr (s, '.');
+      if (dot)
+       {
+         slen -= dot + 1 - s;
+         s = dot + 1;
+         slen_max = 3;
+       }
+      else
+       slen_max = 8;
+      extlen = 9; /* Don't use EXT.  */
+    }
+
+  if (slen + extlen <= slen_max)
+    strcpy (s + slen, ext);
+  else
+    {
+      if (slen_max <= slen)
+       slen = slen_max - 1;
+      s[slen] = e;
+      s[slen + 1] = 0;
+    }
+}
diff --git a/lib/backupfile.c b/lib/backupfile.c
new file mode 100644 (file)
index 0000000..78f2ad0
--- /dev/null
@@ -0,0 +1,273 @@
+/* backupfile.c -- make Emacs style backup file names
+   Copyright (C) 1990-1999, 2000, 2001 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; see the file COPYING.
+   If not, write to the Free Software Foundation,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+/* Written by David MacKenzie <djm@gnu.ai.mit.edu>.
+   Some algorithms adapted from GNU Emacs. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "argmatch.h"
+#include "backupfile.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#if HAVE_STRING_H
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+
+#if HAVE_DIRENT_H
+# include <dirent.h>
+# define NLENGTH(direct) strlen ((direct)->d_name)
+#else
+# define dirent direct
+# define NLENGTH(direct) ((size_t) (direct)->d_namlen)
+# if HAVE_SYS_NDIR_H
+#  include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+#  include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+#  include <ndir.h>
+# endif
+#endif
+
+#if CLOSEDIR_VOID
+/* Fake a return value. */
+# define CLOSEDIR(d) (closedir (d), 0)
+#else
+# define CLOSEDIR(d) closedir (d)
+#endif
+
+#include <stdlib.h>
+
+#include "basename.h"
+
+#if HAVE_DIRENT_H || HAVE_NDIR_H || HAVE_SYS_DIR_H || HAVE_SYS_NDIR_H
+# define HAVE_DIR 1
+#else
+# define HAVE_DIR 0
+#endif
+
+#if HAVE_LIMITS_H
+# include <limits.h>
+#endif
+#ifndef CHAR_BIT
+# define CHAR_BIT 8
+#endif
+/* Upper bound on the string length of an integer converted to string.
+   302 / 1000 is ceil (log10 (2.0)).  Subtract 1 for the sign bit;
+   add 1 for integer division truncation; add 1 more for a minus sign.  */
+#define INT_STRLEN_BOUND(t) ((sizeof (t) * CHAR_BIT - 1) * 302 / 1000 + 2)
+
+/* ISDIGIT differs from isdigit, as follows:
+   - Its arg may be any int or unsigned int; it need not be an unsigned char.
+   - It's guaranteed to evaluate its argument exactly once.
+   - It's typically faster.
+   Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that
+   only '0' through '9' are digits.  Prefer ISDIGIT to isdigit unless
+   it's important to use the locale's definition of `digit' even when the
+   host does not conform to Posix.  */
+#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
+
+#if D_INO_IN_DIRENT
+# define REAL_DIR_ENTRY(dp) ((dp)->d_ino != 0)
+#else
+# define REAL_DIR_ENTRY(dp) 1
+#endif
+
+/* The extension added to file names to produce a simple (as opposed
+   to numbered) backup file name. */
+const char *simple_backup_suffix = "~";
+
+#if HAVE_DIR
+static int max_backup_version PARAMS ((const char *, const char *));
+static int version_number PARAMS ((const char *, const char *, size_t));
+#endif
+
+/* Return the name of the new backup file for file FILE,
+   allocated with malloc.  Return 0 if out of memory.
+   FILE must not end with a '/' unless it is the root directory.
+   Do not call this function if backup_type == none. */
+
+char *
+find_backup_file_name (file, backup_type)
+     const char *file;
+     enum backup_type backup_type;
+{
+  size_t backup_suffix_size_max;
+  size_t file_len = strlen (file);
+  size_t numbered_suffix_size_max = INT_STRLEN_BOUND (int) + 4;
+  char *s;
+  const char *suffix = simple_backup_suffix;
+
+  /* Allow room for simple or `.~N~' backups.  */
+  backup_suffix_size_max = strlen (simple_backup_suffix) + 1;
+  if (HAVE_DIR && backup_suffix_size_max < numbered_suffix_size_max)
+    backup_suffix_size_max = numbered_suffix_size_max;
+
+  s = malloc (file_len + backup_suffix_size_max + numbered_suffix_size_max);
+  if (s)
+    {
+      strcpy (s, file);
+
+#if HAVE_DIR
+      if (backup_type != simple)
+       {
+         int highest_backup;
+         size_t dir_len = basename (s) - s;
+
+         strcpy (s + dir_len, ".");
+         highest_backup = max_backup_version (file + dir_len, s);
+         if (! (backup_type == numbered_existing && highest_backup == 0))
+           {
+             char *numbered_suffix = s + (file_len + backup_suffix_size_max);
+             sprintf (numbered_suffix, ".~%d~", highest_backup + 1);
+             suffix = numbered_suffix;
+           }
+         strcpy (s, file);
+       }
+#endif /* HAVE_DIR */
+
+      addext (s, suffix, '~');
+    }
+  return s;
+}
+
+#if HAVE_DIR
+
+/* Return the number of the highest-numbered backup file for file
+   FILE in directory DIR.  If there are no numbered backups
+   of FILE in DIR, or an error occurs reading DIR, return 0.
+   */
+
+static int
+max_backup_version (file, dir)
+     const char *file;
+     const char *dir;
+{
+  DIR *dirp;
+  struct dirent *dp;
+  int highest_version;
+  int this_version;
+  size_t file_name_length;
+
+  dirp = opendir (dir);
+  if (!dirp)
+    return 0;
+
+  highest_version = 0;
+  file_name_length = strlen (file);
+
+  while ((dp = readdir (dirp)) != 0)
+    {
+      if (!REAL_DIR_ENTRY (dp) || NLENGTH (dp) < file_name_length + 4)
+       continue;
+
+      this_version = version_number (file, dp->d_name, file_name_length);
+      if (this_version > highest_version)
+       highest_version = this_version;
+    }
+  if (CLOSEDIR (dirp))
+    return 0;
+  return highest_version;
+}
+
+/* If BACKUP is a numbered backup of BASE, return its version number;
+   otherwise return 0.  BASE_LENGTH is the length of BASE.
+   */
+
+static int
+version_number (base, backup, base_length)
+     const char *base;
+     const char *backup;
+     size_t base_length;
+{
+  int version;
+  const char *p;
+
+  version = 0;
+  if (strncmp (base, backup, base_length) == 0
+      && backup[base_length] == '.'
+      && backup[base_length + 1] == '~')
+    {
+      for (p = &backup[base_length + 2]; ISDIGIT (*p); ++p)
+       version = version * 10 + *p - '0';
+      if (p[0] != '~' || p[1])
+       version = 0;
+    }
+  return version;
+}
+#endif /* HAVE_DIR */
+
+static const char * const backup_args[] =
+{
+  /* In a series of synonyms, present the most meaning full first, so
+     that argmatch_valid be more readable. */
+  "none", "off",
+  "simple", "never",
+  "existing", "nil",
+  "numbered", "t",
+  0
+};
+
+static const enum backup_type backup_types[] =
+{
+  none, none,
+  simple, simple,
+  numbered_existing, numbered_existing,
+  numbered, numbered
+};
+
+/* Return the type of backup specified by VERSION.
+   If VERSION is NULL or the empty string, return numbered_existing.
+   If VERSION is invalid or ambiguous, fail with a diagnostic appropriate
+   for the specified CONTEXT.  Unambiguous abbreviations are accepted.  */
+
+enum backup_type
+get_version (context, version)
+     const char *context;
+     const char *version;
+{
+  if (version == 0 || *version == 0)
+    return numbered_existing;
+  else
+    return XARGMATCH (context, version, backup_args, backup_types);
+}
+
+
+/* Return the type of backup specified by VERSION.
+   If VERSION is NULL, use the value of the envvar VERSION_CONTROL.
+   If the specified string is invalid or ambiguous, fail with a diagnostic
+   appropriate for the specified CONTEXT.
+   Unambiguous abbreviations are accepted.  */
+
+enum backup_type
+xget_version (context, version)
+      const char *context;
+      const char *version;
+{
+  if (version && *version)
+    return get_version (context, version);
+  else
+    return get_version ("$VERSION_CONTROL", getenv ("VERSION_CONTROL"));
+}
diff --git a/lib/backupfile.h b/lib/backupfile.h
new file mode 100644 (file)
index 0000000..b061161
--- /dev/null
@@ -0,0 +1,63 @@
+/* backupfile.h -- declarations for making Emacs style backup file names
+   Copyright (C) 1990-1992, 1997-1999, 2001 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; see the file COPYING.
+   If not, write to the Free Software Foundation,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifndef BACKUPFILE_H_
+# define BACKUPFILE_H_
+
+/* When to make backup files. */
+enum backup_type
+{
+  /* Never make backups. */
+  none,
+
+  /* Make simple backups of every file. */
+  simple,
+
+  /* Make numbered backups of files that already have numbered backups,
+     and simple backups of the others. */
+  numbered_existing,
+
+  /* Make numbered backups of every file. */
+  numbered
+};
+
+# define VALID_BACKUP_TYPE(Type)       \
+  ((Type) == none                      \
+   || (Type) == simple                 \
+   || (Type) == numbered_existing      \
+   || (Type) == numbered)
+
+extern char const *simple_backup_suffix;
+
+# ifndef PARAMS
+#  if defined PROTOTYPES || (defined __STDC__ && __STDC__)
+#   define PARAMS(Args) Args
+#  else
+#   define PARAMS(Args) ()
+#  endif
+# endif
+
+extern char *find_backup_file_name PARAMS ((char const *file,
+                                           enum backup_type backup_type));
+extern enum backup_type get_version PARAMS ((char const *context,
+                                            char const *arg));
+extern enum backup_type xget_version PARAMS ((char const *context,
+                                             char const *arg));
+extern void addext PARAMS ((char *, char const *, int));
+
+#endif /* ! BACKUPFILE_H_ */
index 4639ec26912f83de551ce5fd0339a926ff455e8a..c687e6386c371da0bface0e97d3a32b53dd77c1e 100644 (file)
@@ -1,3 +1,8 @@
+2001-09-17  Bruno Haible  <haible@clisp.cons.org>
+
+       * backupfile.m4: New file.
+       * Makefile.am (EXTRA_DIST): Add it.
+
 2001-09-25  Bruno Haible  <haible@clisp.cons.org>
 
        * javacomp.m4: Recognize javac exit code 2.
index 8c0edc9f6ea33256a86c16106a37354ee1005176..340702aacc140f69579a4a15b827dbda7988e130 100644 (file)
@@ -7,8 +7,8 @@ aclocal_DATA = codeset.m4 gettext.m4 glibc21.m4 iconv.m4 isc-posix.m4 lcmessage.
 # find . -type f -name '*.m4' -printf '%f\n'|sort |fmt |tr '\012' @ \
 #   |sed 's/@$/%/;s/@/ \\@/g' |tr @% '\012\012'
 EXTRA_DIST = README \
-c-bs-a.m4 codeset.m4 flex.m4 getline.m4 gettext.m4 glibc21.m4 iconv.m4 \
-inttypes_h.m4 isc-posix.m4 javacomp.m4 javaexec.m4 lcmessage.m4 libtool.m4 \
-mbrtowc.m4 mbstate_t.m4 mbswidth.m4 mkdtemp.m4 progtest.m4 setenv.m4 \
-setlocale.m4 signalblocking.m4 signed.m4 ssize_t.m4 stdbool.m4 tmpdir.m4 \
-uintmax_t.m4 ulonglong.m4 unionwait.m4
+backupfile.m4 c-bs-a.m4 codeset.m4 flex.m4 getline.m4 gettext.m4 \
+glibc21.m4 iconv.m4 inttypes_h.m4 isc-posix.m4 javacomp.m4 javaexec.m4 \
+lcmessage.m4 libtool.m4 mbrtowc.m4 mbstate_t.m4 mbswidth.m4 mkdtemp.m4 \
+progtest.m4 setenv.m4 setlocale.m4 signalblocking.m4 signed.m4 ssize_t.m4 \
+stdbool.m4 tmpdir.m4 uintmax_t.m4 ulonglong.m4 unionwait.m4
diff --git a/m4/backupfile.m4 b/m4/backupfile.m4
new file mode 100644 (file)
index 0000000..2434edc
--- /dev/null
@@ -0,0 +1,15 @@
+#serial 1
+
+# Prerequisites of lib/backupfile.h
+
+AC_DEFUN([gt_PREREQ_BACKUPFILE],
+[
+  dnl For backupfile.c.
+  AC_REQUIRE([AC_HEADER_DIRENT])
+  AC_FUNC_CLOSEDIR_VOID
+  AC_CHECK_HEADERS(limits.h string.h)
+  dnl For addext.c.
+  AC_SYS_LONG_FILE_NAMES
+  AC_CHECK_FUNCS(pathconf)
+  AC_CHECK_HEADERS(limits.h string.h unistd.h)
+])