1 /* Copyright (C) 2001-2017 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 The GNU C Library 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 GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <http://www.gnu.org/licenses/>. */
33 #include <sys/types.h>
37 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
45 static size_t umemlen
;
48 static int test_expr (const char *expr
, int expected
, int expectedicase
);
49 static int run_test (const char *expr
, const char *mem
, size_t memlen
,
50 int icase
, int expected
);
51 static int run_test_backwards (const char *expr
, const char *mem
,
52 size_t memlen
, int icase
, int expected
);
69 /* Make the content of the file available in memory. */
70 file
= "../ChangeLog.8";
71 fd
= open (file
, O_RDONLY
);
73 error (EXIT_FAILURE
, errno
, "cannot open %s", basename (file
));
75 if (fstat (fd
, &st
) != 0)
76 error (EXIT_FAILURE
, errno
, "cannot stat %s", basename (file
));
79 mem
= (char *) malloc (memlen
+ 1);
81 error (EXIT_FAILURE
, errno
, "while allocating buffer");
83 if ((size_t) read (fd
, mem
, memlen
) != memlen
)
84 error (EXIT_FAILURE
, 0, "cannot read entire file");
89 /* We have to convert a few things from Latin-1 to UTF-8. */
90 cd
= iconv_open ("UTF-8", "ISO-8859-1");
91 if (cd
== (iconv_t
) -1)
92 error (EXIT_FAILURE
, errno
, "cannot get conversion descriptor");
94 /* For the second test we have to convert the file content to UTF-8.
95 Since the text is mostly ASCII it should be enough to allocate
96 twice as much memory for the UTF-8 text than for the Latin-1
98 umem
= (char *) calloc (2, memlen
);
100 error (EXIT_FAILURE
, errno
, "while allocating buffer");
105 outlen
= 2 * memlen
- 1;
106 iconv (cd
, &inmem
, &inlen
, &outmem
, &outlen
);
107 umemlen
= outmem
- umem
;
109 error (EXIT_FAILURE
, errno
, "cannot convert buffer");
111 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
112 # if _POSIX_CPUTIME == 0
113 if (sysconf (_SC_CPUTIME
) < 0)
117 /* See whether we can use the CPU clock. */
118 use_clock
= clock_getcpuclockid (0, &cl
) == 0;
122 re_set_syntax (RE_DEBUG
);
125 /* Run the actual tests. All tests are run in a single-byte and a
126 multi-byte locale. */
127 result
= test_expr ("[äáàâéèêíìîñöóòôüúùû]", 2, 2);
128 result
|= test_expr ("G.ran", 2, 3);
129 result
|= test_expr ("G.\\{1\\}ran", 2, 3);
130 result
|= test_expr ("G.*ran", 3, 44);
131 result
|= test_expr ("[äáàâ]", 0, 0);
132 result
|= test_expr ("Uddeborg", 2, 2);
133 result
|= test_expr (".Uddeborg", 2, 2);
135 /* Free the resources. */
145 test_expr (const char *expr
, int expected
, int expectedicase
)
154 /* First test: search with an ISO-8859-1 locale. */
155 if (setlocale (LC_ALL
, "de_DE.ISO-8859-1") == NULL
)
156 error (EXIT_FAILURE
, 0, "cannot set locale de_DE.ISO-8859-1");
158 printf ("\nTest \"%s\" with 8-bit locale\n", expr
);
159 result
= run_test (expr
, mem
, memlen
, 0, expected
);
160 printf ("\nTest \"%s\" with 8-bit locale, case insensitive\n", expr
);
161 result
|= run_test (expr
, mem
, memlen
, 1, expectedicase
);
162 printf ("\nTest \"%s\" backwards with 8-bit locale\n", expr
);
163 result
|= run_test_backwards (expr
, mem
, memlen
, 0, expected
);
164 printf ("\nTest \"%s\" backwards with 8-bit locale, case insensitive\n",
166 result
|= run_test_backwards (expr
, mem
, memlen
, 1, expectedicase
);
168 /* Second test: search with an UTF-8 locale. */
169 if (setlocale (LC_ALL
, "de_DE.UTF-8") == NULL
)
170 error (EXIT_FAILURE
, 0, "cannot set locale de_DE.UTF-8");
172 inmem
= (char *) expr
;
173 inlen
= strlen (expr
);
174 outlen
= inlen
* MB_CUR_MAX
;
175 outmem
= uexpr
= alloca (outlen
+ 1);
176 memset (outmem
, '\0', outlen
+ 1);
177 iconv (cd
, &inmem
, &inlen
, &outmem
, &outlen
);
179 error (EXIT_FAILURE
, errno
, "cannot convert expression");
182 printf ("\nTest \"%s\" with multi-byte locale\n", expr
);
183 result
|= run_test (uexpr
, umem
, umemlen
, 0, expected
);
184 printf ("\nTest \"%s\" with multi-byte locale, case insensitive\n", expr
);
185 result
|= run_test (uexpr
, umem
, umemlen
, 1, expectedicase
);
186 printf ("\nTest \"%s\" backwards with multi-byte locale\n", expr
);
187 result
|= run_test_backwards (uexpr
, umem
, umemlen
, 0, expected
);
188 printf ("\nTest \"%s\" backwards with multi-byte locale, case insensitive\n",
190 result
|= run_test_backwards (uexpr
, umem
, umemlen
, 1, expectedicase
);
197 run_test (const char *expr
, const char *mem
, size_t memlen
, int icase
,
200 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
201 struct timespec start
;
202 struct timespec finish
;
209 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
210 if (use_clock
&& !timing
)
211 use_clock
= clock_gettime (cl
, &start
) == 0;
214 err
= regcomp (&re
, expr
, REG_NEWLINE
| (icase
? REG_ICASE
: 0));
215 if (err
!= REG_NOERROR
)
218 regerror (err
, &re
, buf
, sizeof buf
);
219 error (EXIT_FAILURE
, 0, "cannot compile expression: %s", buf
);
224 assert (mem
[memlen
] == '\0');
225 while (offset
< memlen
)
231 err
= regexec (&re
, mem
+ offset
, 1, ma
, 0);
232 if (err
== REG_NOMATCH
)
235 if (err
!= REG_NOERROR
)
238 regerror (err
, &re
, buf
, sizeof buf
);
239 error (EXIT_FAILURE
, 0, "cannot use expression: %s", buf
);
242 assert (ma
[0].rm_so
>= 0);
243 sp
= mem
+ offset
+ ma
[0].rm_so
;
244 while (sp
> mem
&& sp
[-1] != '\n')
247 ep
= mem
+ offset
+ ma
[0].rm_so
;
248 while (*ep
!= '\0' && *ep
!= '\n')
251 printf ("match %d: \"%.*s\"\n", ++cnt
, (int) (ep
- sp
), sp
);
253 offset
= ep
+ 1 - mem
;
258 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
259 if (use_clock
&& !timing
)
261 use_clock
= clock_gettime (cl
, &finish
) == 0;
264 if (finish
.tv_nsec
< start
.tv_nsec
)
266 finish
.tv_nsec
-= start
.tv_nsec
- 1000000000;
267 finish
.tv_sec
-= 1 + start
.tv_sec
;
271 finish
.tv_nsec
-= start
.tv_nsec
;
272 finish
.tv_sec
-= start
.tv_sec
;
275 printf ("elapsed time: %jd.%09jd sec\n",
276 (intmax_t) finish
.tv_sec
, (intmax_t) finish
.tv_nsec
);
280 if (use_clock
&& timing
)
282 struct timespec mintime
= { .tv_sec
= 24 * 60 * 60 };
284 for (int i
= 0; i
< 10; ++i
)
287 use_clock
= clock_gettime (cl
, &start
) == 0;
292 err
= regcomp (&re
, expr
, REG_NEWLINE
| (icase
? REG_ICASE
: 0));
293 if (err
!= REG_NOERROR
)
296 while (offset
< memlen
)
300 err
= regexec (&re
, mem
+ offset
, 1, ma
, 0);
301 if (err
!= REG_NOERROR
)
304 offset
+= ma
[0].rm_eo
;
309 use_clock
= clock_gettime (cl
, &finish
) == 0;
312 if (finish
.tv_nsec
< start
.tv_nsec
)
314 finish
.tv_nsec
-= start
.tv_nsec
- 1000000000;
315 finish
.tv_sec
-= 1 + start
.tv_sec
;
319 finish
.tv_nsec
-= start
.tv_nsec
;
320 finish
.tv_sec
-= start
.tv_sec
;
322 if (finish
.tv_sec
< mintime
.tv_sec
323 || (finish
.tv_sec
== mintime
.tv_sec
324 && finish
.tv_nsec
< mintime
.tv_nsec
))
328 printf ("elapsed time: %jd.%09jd sec\n",
329 (intmax_t) mintime
.tv_sec
, (intmax_t) mintime
.tv_nsec
);
333 /* Return an error if the number of matches found is not match we
335 return cnt
!= expected
;
340 run_test_backwards (const char *expr
, const char *mem
, size_t memlen
,
341 int icase
, int expected
)
343 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
344 struct timespec start
;
345 struct timespec finish
;
347 struct re_pattern_buffer re
;
352 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
353 if (use_clock
&& !timing
)
354 use_clock
= clock_gettime (cl
, &start
) == 0;
357 re_set_syntax ((RE_SYNTAX_POSIX_BASIC
& ~RE_DOT_NEWLINE
)
358 | RE_HAT_LISTS_NOT_NEWLINE
359 | (icase
? RE_ICASE
: 0));
361 memset (&re
, 0, sizeof (re
));
362 re
.fastmap
= malloc (256);
363 if (re
.fastmap
== NULL
)
364 error (EXIT_FAILURE
, errno
, "cannot allocate fastmap");
366 err
= re_compile_pattern (expr
, strlen (expr
), &re
);
368 error (EXIT_FAILURE
, 0, "cannot compile expression: %s", err
);
370 if (re_compile_fastmap (&re
))
371 error (EXIT_FAILURE
, 0, "couldn't compile fastmap");
375 assert (mem
[memlen
] == '\0');
376 while (offset
<= memlen
)
382 start
= re_search (&re
, mem
, memlen
, offset
, -offset
, NULL
);
387 error (EXIT_FAILURE
, 0, "internal error in re_search");
390 while (sp
> mem
&& sp
[-1] != '\n')
394 while (*ep
!= '\0' && *ep
!= '\n')
397 printf ("match %d: \"%.*s\"\n", ++cnt
, (int) (ep
- sp
), sp
);
399 offset
= sp
- 1 - mem
;
404 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
405 if (use_clock
&& !timing
)
407 use_clock
= clock_gettime (cl
, &finish
) == 0;
410 if (finish
.tv_nsec
< start
.tv_nsec
)
412 finish
.tv_nsec
-= start
.tv_nsec
- 1000000000;
413 finish
.tv_sec
-= 1 + start
.tv_sec
;
417 finish
.tv_nsec
-= start
.tv_nsec
;
418 finish
.tv_sec
-= start
.tv_sec
;
421 printf ("elapsed time: %jd.%09jd sec\n",
422 (intmax_t) finish
.tv_sec
, (intmax_t) finish
.tv_nsec
);
426 if (use_clock
&& timing
)
428 struct timespec mintime
= { .tv_sec
= 24 * 60 * 60 };
430 for (int i
= 0; i
< 10; ++i
)
433 use_clock
= clock_gettime (cl
, &start
) == 0;
438 memset (&re
, 0, sizeof (re
));
439 re
.fastmap
= malloc (256);
440 if (re
.fastmap
== NULL
)
443 err
= re_compile_pattern (expr
, strlen (expr
), &re
);
447 if (re_compile_fastmap (&re
))
453 while (offset
<= memlen
)
458 start
= re_search (&re
, mem
, memlen
, offset
, -offset
, NULL
);
463 while (sp
> mem
&& sp
[-1] != '\n')
466 offset
= sp
- 1 - mem
;
471 use_clock
= clock_gettime (cl
, &finish
) == 0;
474 if (finish
.tv_nsec
< start
.tv_nsec
)
476 finish
.tv_nsec
-= start
.tv_nsec
- 1000000000;
477 finish
.tv_sec
-= 1 + start
.tv_sec
;
481 finish
.tv_nsec
-= start
.tv_nsec
;
482 finish
.tv_sec
-= start
.tv_sec
;
484 if (finish
.tv_sec
< mintime
.tv_sec
485 || (finish
.tv_sec
== mintime
.tv_sec
486 && finish
.tv_nsec
< mintime
.tv_nsec
))
490 printf ("elapsed time: %jd.%09jd sec\n",
491 (intmax_t) mintime
.tv_sec
, (intmax_t) mintime
.tv_nsec
);
495 /* Return an error if the number of matches found is not match we
497 return cnt
!= expected
;
500 /* If --timing is used we will need a larger timout. */
502 #define CMDLINE_OPTIONS \
503 {"timing", no_argument, &timing, 1 },
504 #define TEST_FUNCTION do_test ()
505 #include "../test-skeleton.c"