summaryrefslogtreecommitdiff
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