about summary refs log tree commit diff
path: root/string
diff options
context:
space:
mode:
Diffstat (limited to 'string')
-rw-r--r--string/Makefile8
-rw-r--r--string/basename.c7
-rw-r--r--string/string.h3
-rw-r--r--string/strverscmp.c111
-rw-r--r--string/tester.c76
-rw-r--r--string/tst-strlen.c2
-rw-r--r--string/tst-svc.c45
-rw-r--r--string/tst-svc.expect26
-rw-r--r--string/tst-svc.input26
9 files changed, 300 insertions, 4 deletions
diff --git a/string/Makefile b/string/Makefile
index 8f35f207f6..6704dbf4e0 100644
--- a/string/Makefile
+++ b/string/Makefile
@@ -24,7 +24,7 @@ subdir	:= string
 headers	:= string.h strings.h memory.h endian.h bytesex.h \
 	   argz.h envz.h
 
-routines	:= strcat strchr strcmp strcoll strcpy strcspn		\
+routines	:= strcat strchr strcmp strcoll strcpy strcspn strverscmp	\
 		   strdup strndup	\
 		   strerror _strerror strerror_r strlen strnlen		\
 		   strncat strncmp strncpy				\
@@ -40,7 +40,8 @@ routines	:= strcat strchr strcmp strcoll strcpy strcspn		\
 		   envz basename					\
 		   strcoll_l strxfrm_l
 
-tests		:= tester testcopy test-ffs tst-strlen stratcliff
+tests		:= tester testcopy test-ffs tst-strlen stratcliff \
+	           tst-svc
 distribute	:= memcopy.h pagecopy.h
 
 
@@ -50,3 +51,6 @@ tester-ENV = LANGUAGE=C
 CFLAGS-tester.c = -fno-builtin
 CFLAGS-tst-strlen.c = -fno-builtin
 CFLAGS-stratcliff.c = -fno-builtin
+
+tests: $(objpfx)tst-svc.out
+	cmp tst-svc.expect $(objpfx)tst-svc.out
diff --git a/string/basename.c b/string/basename.c
index 4f06843aeb..f24e0ac1b4 100644
--- a/string/basename.c
+++ b/string/basename.c
@@ -17,10 +17,15 @@
    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
 #include <string.h>
 
 char *
-basename (const char *filename)
+basename (filename)
+     const char *filename;
 {
   char *p = strrchr (filename, '/');
   return p ? p + 1 : (char *) filename;
diff --git a/string/string.h b/string/string.h
index 7a6ad1235f..4a79dcecc2 100644
--- a/string/string.h
+++ b/string/string.h
@@ -241,6 +241,9 @@ extern char *strsep __P ((char **__stringp, __const char *__delim));
 #endif
 
 #ifdef	__USE_GNU
+/* Compare S1 and S2 as strings holding name & indices/version numbers.  */
+extern int strverscmp __P ((__const char *__s1, __const char *__s2));
+
 /* Return a string describing the meaning of the signal number in SIG.  */
 extern char *strsignal __P ((int __sig));
 
diff --git a/string/strverscmp.c b/string/strverscmp.c
new file mode 100644
index 0000000000..388df75dfd
--- /dev/null
+++ b/string/strverscmp.c
@@ -0,0 +1,111 @@
+/* Compare strings while treating digits characters numerically.
+   Copyright (C) 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jean-François Bignolles <bignolle@ecoledoc.ibp.fr>, 1997.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <string.h>
+#include <ctype.h>
+
+/* states: S_N: normal, S_I: comparing integral part, S_F: comparing
+           Fractionnal parts, S_Z: idem but with leading Zeroes only */
+#define  S_N    0x0
+#define  S_I    0x4
+#define  S_F    0x8
+#define  S_Z    0xC
+
+/* result_type: CMP: return diff; LEN: compare using len_diff/diff */
+#define  CMP    2
+#define  LEN    3
+
+
+/* Compare S1 and S2 as strings holding indices/version numbers,
+   returning less than, equal to or greater than zero if S1 is less than,
+   equal to or greater than S2 (for more info, see the texinfo doc).
+*/
+
+int
+strverscmp (s1, s2)
+     const char *s1;
+     const char *s2;
+{
+  const unsigned char *p1 = (const unsigned char *) s1;
+  const unsigned char *p2 = (const unsigned char *) s2;
+  unsigned char c1, c2;
+  int state;
+  int diff;
+
+  /* Symbol(s)    0       [1-9]   others  (padding)
+     Transition   (10) 0  (01) d  (00) x  (11) -   */
+  static const unsigned int next_state[] =
+  {
+      /* state    x    d    0    - */
+      /* S_N */  S_N, S_I, S_Z, S_N,
+      /* S_I */  S_N, S_I, S_I, S_I,
+      /* S_F */  S_N, S_F, S_F, S_F,
+      /* S_Z */  S_N, S_F, S_Z, S_Z
+  };
+
+  static const int result_type[] =
+  {
+      /* state   x/x  x/d  x/0  x/-  d/x  d/d  d/0  d/-
+                 0/x  0/d  0/0  0/-  -/x  -/d  -/0  -/- */
+
+      /* S_N */  CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP,
+                 CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP,
+      /* S_I */  CMP, -1,  -1,  CMP, +1,  LEN, LEN, CMP,
+                 +1,  LEN, LEN, CMP, CMP, CMP, CMP, CMP,
+      /* S_F */  CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP,
+                 CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP,
+      /* S_Z */  CMP, +1,  +1,  CMP, -1,  CMP, CMP, CMP,
+                 -1,  CMP, CMP, CMP
+  };
+
+  if (p1 == p2)
+    return 0;
+
+  c1 = *p1++;
+  c2 = *p2++;
+  /* Hint: '0' is a digit too.  */
+  state = S_N | (c1 == '0') + (isdigit (c1) != 0);
+
+  while ((diff = c1 - c2) == 0 && c1 != '\0')
+    {
+      state = next_state[state];
+      c1 = *p1++;
+      c2 = *p2++;
+      state |= (c1 == '0') + (isdigit (c1) != 0);
+    }
+
+  state = result_type[state << 2 | ((c2 == '0') + (isdigit (c2) != 0))];
+
+  switch (state)
+  {
+    case CMP:
+      return diff;
+
+    case LEN:
+      while (isdigit (*p1++))
+	if (!isdigit (*p2++))
+	  return 1;
+
+      return isdigit (*p2) ? -1 : diff;
+
+    default:
+      return state;
+  }
+}
diff --git a/string/tester.c b/string/tester.c
index b815539737..dcd7342ba3 100644
--- a/string/tester.c
+++ b/string/tester.c
@@ -1,3 +1,6 @@
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
 #include <ansidecl.h>
 #include <errno.h>
 #include <stdio.h>
@@ -28,6 +31,7 @@ DEFUN(check, (thing, number), int thing AND int number)
 }
 
 /* Complain if first two args don't strcmp as equal.  */
+void equal(CONST char *a, CONST char *b, int number);
 void
 DEFUN(equal, (a, b, number), CONST char *a AND CONST char *b AND int number)
 {
@@ -54,6 +58,41 @@ DEFUN(main, (argc, argv), int argc AND char **argv)
   check(strcmp("a\203", "a") > 0, 8);		/* Tricky if char signed. */
   check(strcmp("a\203", "a\003") > 0, 9);
 
+  {
+    char buf1[0x40], buf2[0x40];
+    int i, j;
+    for (i=0; i < 0x10; i++)
+      for (j = 0; j < 0x10; j++)
+      {
+	int k;
+	for (k = 0; k < 0x3f; k++)
+	  {
+	    buf1[j] = '0' ^ (k & 4);
+	    buf2[j] = '4' ^ (k & 4);
+	  }
+	buf1[i] = buf1[0x3f] = 0;
+	buf2[j] = buf2[0x3f] = 0;
+	for (k = 0; k < 0xf; k++)
+	  {
+	    int cnum = 0x10+0x10*k+0x100*j+0x1000*i;
+	    check(strcmp(buf1+i,buf2+j) == 0, cnum);
+	    buf1[i+k] = 'A' + i + k;
+	    buf1[i+k+1] = 0;
+	    check(strcmp(buf1+i,buf2+j) > 0, cnum+1);
+	    check(strcmp(buf2+j,buf1+i) < 0, cnum+2);
+	    buf2[j+k] = 'B' + i + k;
+	    buf2[j+k+1] = 0;
+	    check(strcmp(buf1+i,buf2+j) < 0, cnum+3);
+	    check(strcmp(buf2+j,buf1+i) > 0, cnum+4);
+	    buf2[j+k] = 'A' + i + k;
+	    buf1[i] = 'A' + i + 0x80;
+	    check(strcmp(buf1+i,buf2+j) > 0, cnum+5);
+	    check(strcmp(buf2+j,buf1+i) < 0, cnum+6);
+	    buf1[i] = 'A' + i;
+	  }
+      }
+   }
+
   /* Test strcpy next because we need it to set up other tests.  */
   it = "strcpy";
   check(strcpy(one, "abcd") == one, 1);	/* Returned value. */
@@ -672,6 +711,43 @@ DEFUN(main, (argc, argv), int argc AND char **argv)
   (void) memset(one+2, 010045, 1);
   equal(one, "ax\045xe", 6);		/* Unsigned char convert. */
 
+  /* Test for more complex versions of memset, for all alignments and
+     lengths up to 256. This test takes a little while, perhaps it should
+     be made weaker? */
+  {
+    char data[512];
+    int i;
+    int j;
+    int k;
+    int c;
+    
+    for (i = 0; i < 512; i++)
+      data[i] = 'x';
+    for (c = 0; c <= 'y'; c += 'y')  /* check for memset(,0,) and
+					memset(,'y',) */
+      for (j = 0; j < 256; j++)
+	for (i = 0; i < 256; i++)
+	  {
+	    memset(data+i,c,j);
+	    for (k = 0; k < i; k++)
+	      if (data[k] != 'x')
+		goto fail;
+	    for (k = i; k < i+j; k++)
+	      {
+		if (data[k] != c)
+		  goto fail;
+		data[k] = 'x';
+	      }
+	    for (k = i+j; k < 512; k++)
+	      if (data[k] != 'x')
+		goto fail;
+	    continue;
+
+	  fail:
+	    check(0,7+i+j*256+(c != 0)*256*256); 
+	  }
+  }
+
   /* bcopy - much like memcpy.
      Berklix manual is silent about overlap, so don't test it.  */
   it = "bcopy";
diff --git a/string/tst-strlen.c b/string/tst-strlen.c
index b9efe1da29..4acd4045f5 100644
--- a/string/tst-strlen.c
+++ b/string/tst-strlen.c
@@ -34,7 +34,7 @@ main(int argc, char *argv[])
 		  return 1;
 		}
 	    }
-        }
+	}
     }
   return 0;
 }
diff --git a/string/tst-svc.c b/string/tst-svc.c
new file mode 100644
index 0000000000..c6add5b4b1
--- /dev/null
+++ b/string/tst-svc.c
@@ -0,0 +1,45 @@
+/* Test for strverscmp() */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define  MAX_STRINGS      256
+#define  MAX_LINE_SIZE    32
+
+int
+compare (const void *p1, const void *p2)
+{
+  return strverscmp (*((char **) p1), *((char **) p2));
+}
+
+int
+main (int argc, char *argv[])
+{
+  char line[MAX_LINE_SIZE + 1];
+  char *str[MAX_STRINGS];
+  int  count = 0;
+  int  i, n;
+
+  while (count < MAX_STRINGS && fgets (line, MAX_LINE_SIZE, stdin) != NULL)
+    {
+      n = strlen (line) - 1;
+
+      if (line[n] == '\n')
+        line[n] = '\0';
+
+      str[count] = strdup (line);
+
+      if (str[count] == NULL)
+        exit (EXIT_FAILURE);
+
+      ++count;
+    }
+
+  qsort (str, count, sizeof (char *), compare);
+
+  for (i = 0; i < count; ++i)
+    puts (str[i]);
+
+  exit (EXIT_SUCCESS);
+}
diff --git a/string/tst-svc.expect b/string/tst-svc.expect
new file mode 100644
index 0000000000..f906c4fc0b
--- /dev/null
+++ b/string/tst-svc.expect
@@ -0,0 +1,26 @@
+000
+001
+00
+00a
+01
+01a
+0
+0a
+20
+21
+22
+212
+foo
+foo-0.4
+foo-0.4a
+foo-0.4b
+foo-0.5
+foo-0.10.5
+foo-3.01
+foo-3.0
+foo-3.0.0
+foo-3.0.1
+foo-3.2
+foo-3.10
+foo00
+foo0
diff --git a/string/tst-svc.input b/string/tst-svc.input
new file mode 100644
index 0000000000..b80ee82b07
--- /dev/null
+++ b/string/tst-svc.input
@@ -0,0 +1,26 @@
+0a
+00
+0
+01
+001
+01a
+00a
+000
+20
+212
+21
+22
+foo0
+foo00
+foo-0.4
+foo-3.0
+foo
+foo-3.0.0
+foo-3.0.1
+foo-0.5
+foo-0.4b
+foo-3.10
+foo-3.2
+foo-3.01
+foo-0.4a
+foo-0.10.5