futimens: fix configure check
[gnulib.git] / lib / filevercmp.c
index 856f30f..cb7c25c 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
    Copyright (C) 2001 Anthony Towns <aj@azure.humbug.org.au>
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008-2010 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
@@ -27,7 +27,7 @@
 #include <limits.h>
 
 /* Match a file suffix defined by this regular expression:
-   /(\.[A-Za-z][A-Za-z0-9]*)*$/
+   /(\.[A-Za-z~][A-Za-z0-9~]*)*$/
    Scan the string *STR and return a pointer to the matching suffix, or
    NULL if not found.  Upon return, *STR points to terminating NUL.  */
 static const char *
@@ -40,7 +40,7 @@ match_suffix (const char **str)
       if (read_alpha)
         {
           read_alpha = false;
-          if (!c_isalpha (**str))
+          if (!c_isalpha (**str) && '~' != **str)
             match = NULL;
         }
       else if ('.' == **str)
@@ -49,7 +49,7 @@ match_suffix (const char **str)
           if (!match)
             match = *str;
         }
-      else if (!c_isalnum (**str))
+      else if (!c_isalnum (**str) && '~' != **str)
         match = NULL;
       (*str)++;
     }
@@ -89,32 +89,32 @@ verrevcmp (const char *s1, size_t s1_len, const char *s2, size_t s2_len)
     {
       int first_diff = 0;
       while ((s1_pos < s1_len && !c_isdigit (s1[s1_pos]))
-            || (s2_pos < s2_len && !c_isdigit (s2[s2_pos])))
-       {
-         int s1_c = (s1_pos == s1_len) ? 0 : order (s1[s1_pos]);
-         int s2_c = (s2_pos == s2_len) ? 0 : order (s2[s2_pos]);
-         if (s1_c != s2_c)
-           return s1_c - s2_c;
-         s1_pos++;
-         s2_pos++;
-       }
+             || (s2_pos < s2_len && !c_isdigit (s2[s2_pos])))
+        {
+          int s1_c = (s1_pos == s1_len) ? 0 : order (s1[s1_pos]);
+          int s2_c = (s2_pos == s2_len) ? 0 : order (s2[s2_pos]);
+          if (s1_c != s2_c)
+            return s1_c - s2_c;
+          s1_pos++;
+          s2_pos++;
+        }
       while (s1[s1_pos] == '0')
-       s1_pos++;
+        s1_pos++;
       while (s2[s2_pos] == '0')
-       s2_pos++;
+        s2_pos++;
       while (c_isdigit (s1[s1_pos]) && c_isdigit (s2[s2_pos]))
-       {
-         if (!first_diff)
-           first_diff = s1[s1_pos] - s2[s2_pos];
-         s1_pos++;
-         s2_pos++;
-       }
+        {
+          if (!first_diff)
+            first_diff = s1[s1_pos] - s2[s2_pos];
+          s1_pos++;
+          s2_pos++;
+        }
       if (c_isdigit (s1[s1_pos]))
-       return 1;
+        return 1;
       if (c_isdigit (s2[s2_pos]))
-       return -1;
+        return -1;
       if (first_diff)
-       return first_diff;
+        return first_diff;
     }
   return 0;
 }
@@ -124,8 +124,8 @@ verrevcmp (const char *s1, size_t s1_len, const char *s2, size_t s2_len)
 int
 filevercmp (const char *s1, const char *s2)
 {
-  const char *s1_pos = s1;
-  const char *s2_pos = s2;
+  const char *s1_pos;
+  const char *s2_pos;
   const char *s1_suffix, *s2_suffix;
   size_t s1_len, s2_len;
   int result;
@@ -135,7 +135,34 @@ filevercmp (const char *s1, const char *s2)
   if (simple_cmp == 0)
     return 0;
 
+  /* special handle for "", "." and ".." */
+  if (!*s1)
+    return -1;
+  if (!*s2)
+    return 1;
+  if (0 == strcmp (".", s1))
+    return -1;
+  if (0 == strcmp (".", s2))
+    return 1;
+  if (0 == strcmp ("..", s1))
+    return -1;
+  if (0 == strcmp ("..", s2))
+    return 1;
+
+  /* special handle for other hidden files */
+  if (*s1 == '.' && *s2 != '.')
+    return -1;
+  if (*s1 != '.' && *s2 == '.')
+    return 1;
+  if (*s1 == '.' && *s2 == '.')
+    {
+      s1++;
+      s2++;
+    }
+
   /* "cut" file suffixes */
+  s1_pos = s1;
+  s2_pos = s2;
   s1_suffix = match_suffix (&s1_pos);
   s2_suffix = match_suffix (&s2_pos);
   s1_len = (s1_suffix ? s1_suffix : s1_pos) - s1;