1 /* Copyright (C) 2001-2021 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 <https://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
= "./tst-regex.input";
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 UTF-8 to Latin-1. */
90 cd
= iconv_open ("ISO-8859-1", "UTF-8");
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 Latin-1.
95 This cannot grow the data. */
96 umem
= (char *) malloc (memlen
+ 1);
98 error (EXIT_FAILURE
, errno
, "while allocating buffer");
104 iconv (cd
, &inmem
, &inlen
, &outmem
, &outlen
);
105 umemlen
= outmem
- umem
;
107 error (EXIT_FAILURE
, errno
, "cannot convert buffer");
108 umem
[umemlen
] = '\0';
110 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
111 # if _POSIX_CPUTIME == 0
112 if (sysconf (_SC_CPUTIME
) < 0)
116 /* See whether we can use the CPU clock. */
117 use_clock
= clock_getcpuclockid (0, &cl
) == 0;
121 re_set_syntax (RE_DEBUG
);
124 /* Run the actual tests. All tests are run in a single-byte and a
125 multi-byte locale. */
126 result
= test_expr ("[äáàâéèêíìîñöóòôüúùû]", 4, 4);
127 result
|= test_expr ("G.ran", 2, 3);
128 result
|= test_expr ("G.\\{1\\}ran", 2, 3);
129 result
|= test_expr ("G.*ran", 3, 44);
130 result
|= test_expr ("[äáàâ]", 0, 0);
131 result
|= test_expr ("Uddeborg", 2, 2);
132 result
|= test_expr (".Uddeborg", 2, 2);
134 /* Free the resources. */
144 test_expr (const char *expr
, int expected
, int expectedicase
)
153 /* First test: search with an UTF-8 locale. */
154 if (setlocale (LC_ALL
, "de_DE.UTF-8") == NULL
)
155 error (EXIT_FAILURE
, 0, "cannot set locale de_DE.UTF-8");
157 printf ("\nTest \"%s\" with multi-byte locale\n", expr
);
158 result
= run_test (expr
, mem
, memlen
, 0, expected
);
159 printf ("\nTest \"%s\" with multi-byte locale, case insensitive\n", expr
);
160 result
|= run_test (expr
, mem
, memlen
, 1, expectedicase
);
161 printf ("\nTest \"%s\" backwards with multi-byte locale\n", expr
);
162 result
|= run_test_backwards (expr
, mem
, memlen
, 0, expected
);
163 printf ("\nTest \"%s\" backwards with multi-byte locale, case insensitive\n",
165 result
|= run_test_backwards (expr
, mem
, memlen
, 1, expectedicase
);
167 /* Second test: search with an ISO-8859-1 locale. */
168 if (setlocale (LC_ALL
, "de_DE.ISO-8859-1") == NULL
)
169 error (EXIT_FAILURE
, 0, "cannot set locale de_DE.ISO-8859-1");
171 inmem
= (char *) expr
;
172 inlen
= strlen (expr
);
174 outmem
= uexpr
= alloca (outlen
+ 1);
175 memset (outmem
, '\0', outlen
+ 1);
176 iconv (cd
, &inmem
, &inlen
, &outmem
, &outlen
);
178 error (EXIT_FAILURE
, errno
, "cannot convert expression");
181 printf ("\nTest \"%s\" with 8-bit locale\n", expr
);
182 result
|= run_test (uexpr
, umem
, umemlen
, 0, expected
);
183 printf ("\nTest \"%s\" with 8-bit locale, case insensitive\n", expr
);
184 result
|= run_test (uexpr
, umem
, umemlen
, 1, expectedicase
);
185 printf ("\nTest \"%s\" backwards with 8-bit locale\n", expr
);
186 result
|= run_test_backwards (uexpr
, umem
, umemlen
, 0, expected
);
187 printf ("\nTest \"%s\" backwards with 8-bit locale, case insensitive\n",
189 result
|= run_test_backwards (uexpr
, umem
, umemlen
, 1, expectedicase
);
196 run_test (const char *expr
, const char *mem
, size_t memlen
, int icase
,
199 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
200 struct timespec start
;
201 struct timespec finish
;
208 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
209 if (use_clock
&& !timing
)
210 use_clock
= clock_gettime (cl
, &start
) == 0;
213 err
= regcomp (&re
, expr
, REG_NEWLINE
| (icase
? REG_ICASE
: 0));
214 if (err
!= REG_NOERROR
)
217 regerror (err
, &re
, buf
, sizeof buf
);
218 error (EXIT_FAILURE
, 0, "cannot compile expression: %s", buf
);
223 assert (mem
[memlen
] == '\0');
224 while (offset
< memlen
)
230 err
= regexec (&re
, mem
+ offset
, 1, ma
, 0);
231 if (err
== REG_NOMATCH
)
234 if (err
!= REG_NOERROR
)
237 regerror (err
, &re
, buf
, sizeof buf
);
238 error (EXIT_FAILURE
, 0, "cannot use expression: %s", buf
);
241 assert (ma
[0].rm_so
>= 0);
242 sp
= mem
+ offset
+ ma
[0].rm_so
;
243 while (sp
> mem
&& sp
[-1] != '\n')
246 ep
= mem
+ offset
+ ma
[0].rm_so
;
247 while (*ep
!= '\0' && *ep
!= '\n')
250 printf ("match %d: \"%.*s\"\n", ++cnt
, (int) (ep
- sp
), sp
);
252 offset
= ep
+ 1 - mem
;
257 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
258 if (use_clock
&& !timing
)
260 use_clock
= clock_gettime (cl
, &finish
) == 0;
263 if (finish
.tv_nsec
< start
.tv_nsec
)
265 finish
.tv_nsec
-= start
.tv_nsec
- 1000000000;
266 finish
.tv_sec
-= 1 + start
.tv_sec
;
270 finish
.tv_nsec
-= start
.tv_nsec
;
271 finish
.tv_sec
-= start
.tv_sec
;
274 printf ("elapsed time: %jd.%09jd sec\n",
275 (intmax_t) finish
.tv_sec
, (intmax_t) finish
.tv_nsec
);
279 if (use_clock
&& timing
)
281 struct timespec mintime
= { .tv_sec
= 24 * 60 * 60 };
283 for (int i
= 0; i
< 10; ++i
)
286 use_clock
= clock_gettime (cl
, &start
) == 0;
291 err
= regcomp (&re
, expr
, REG_NEWLINE
| (icase
? REG_ICASE
: 0));
292 if (err
!= REG_NOERROR
)
295 while (offset
< memlen
)
299 err
= regexec (&re
, mem
+ offset
, 1, ma
, 0);
300 if (err
!= REG_NOERROR
)
303 offset
+= ma
[0].rm_eo
;
308 use_clock
= clock_gettime (cl
, &finish
) == 0;
311 if (finish
.tv_nsec
< start
.tv_nsec
)
313 finish
.tv_nsec
-= start
.tv_nsec
- 1000000000;
314 finish
.tv_sec
-= 1 + start
.tv_sec
;
318 finish
.tv_nsec
-= start
.tv_nsec
;
319 finish
.tv_sec
-= start
.tv_sec
;
321 if (finish
.tv_sec
< mintime
.tv_sec
322 || (finish
.tv_sec
== mintime
.tv_sec
323 && finish
.tv_nsec
< mintime
.tv_nsec
))
327 printf ("elapsed time: %jd.%09jd sec\n",
328 (intmax_t) mintime
.tv_sec
, (intmax_t) mintime
.tv_nsec
);
332 /* Return an error if the number of matches found is not match we
334 return cnt
!= expected
;
339 run_test_backwards (const char *expr
, const char *mem
, size_t memlen
,
340 int icase
, int expected
)
342 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
343 struct timespec start
;
344 struct timespec finish
;
346 struct re_pattern_buffer re
;
351 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
352 if (use_clock
&& !timing
)
353 use_clock
= clock_gettime (cl
, &start
) == 0;
356 re_set_syntax ((RE_SYNTAX_POSIX_BASIC
& ~RE_DOT_NEWLINE
)
357 | RE_HAT_LISTS_NOT_NEWLINE
358 | (icase
? RE_ICASE
: 0));
360 memset (&re
, 0, sizeof (re
));
361 re
.fastmap
= malloc (256);
362 if (re
.fastmap
== NULL
)
363 error (EXIT_FAILURE
, errno
, "cannot allocate fastmap");
365 err
= re_compile_pattern (expr
, strlen (expr
), &re
);
367 error (EXIT_FAILURE
, 0, "cannot compile expression: %s", err
);
369 if (re_compile_fastmap (&re
))
370 error (EXIT_FAILURE
, 0, "couldn't compile fastmap");
374 assert (mem
[memlen
] == '\0');
375 while (offset
<= memlen
)
381 start
= re_search (&re
, mem
, memlen
, offset
, -offset
, NULL
);
386 error (EXIT_FAILURE
, 0, "internal error in re_search");
389 while (sp
> mem
&& sp
[-1] != '\n')
393 while (*ep
!= '\0' && *ep
!= '\n')
396 printf ("match %d: \"%.*s\"\n", ++cnt
, (int) (ep
- sp
), sp
);
398 offset
= sp
- 1 - mem
;
403 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
404 if (use_clock
&& !timing
)
406 use_clock
= clock_gettime (cl
, &finish
) == 0;
409 if (finish
.tv_nsec
< start
.tv_nsec
)
411 finish
.tv_nsec
-= start
.tv_nsec
- 1000000000;
412 finish
.tv_sec
-= 1 + start
.tv_sec
;
416 finish
.tv_nsec
-= start
.tv_nsec
;
417 finish
.tv_sec
-= start
.tv_sec
;
420 printf ("elapsed time: %jd.%09jd sec\n",
421 (intmax_t) finish
.tv_sec
, (intmax_t) finish
.tv_nsec
);
425 if (use_clock
&& timing
)
427 struct timespec mintime
= { .tv_sec
= 24 * 60 * 60 };
429 for (int i
= 0; i
< 10; ++i
)
432 use_clock
= clock_gettime (cl
, &start
) == 0;
437 memset (&re
, 0, sizeof (re
));
438 re
.fastmap
= malloc (256);
439 if (re
.fastmap
== NULL
)
442 err
= re_compile_pattern (expr
, strlen (expr
), &re
);
446 if (re_compile_fastmap (&re
))
452 while (offset
<= memlen
)
457 start
= re_search (&re
, mem
, memlen
, offset
, -offset
, NULL
);
462 while (sp
> mem
&& sp
[-1] != '\n')
465 offset
= sp
- 1 - mem
;
470 use_clock
= clock_gettime (cl
, &finish
) == 0;
473 if (finish
.tv_nsec
< start
.tv_nsec
)
475 finish
.tv_nsec
-= start
.tv_nsec
- 1000000000;
476 finish
.tv_sec
-= 1 + start
.tv_sec
;
480 finish
.tv_nsec
-= start
.tv_nsec
;
481 finish
.tv_sec
-= start
.tv_sec
;
483 if (finish
.tv_sec
< mintime
.tv_sec
484 || (finish
.tv_sec
== mintime
.tv_sec
485 && finish
.tv_nsec
< mintime
.tv_nsec
))
489 printf ("elapsed time: %jd.%09jd sec\n",
490 (intmax_t) mintime
.tv_sec
, (intmax_t) mintime
.tv_nsec
);
494 /* Return an error if the number of matches found is not match we
496 return cnt
!= expected
;
499 /* If --timing is used we will need a larger timout. */
501 #define CMDLINE_OPTIONS \
502 {"timing", no_argument, &timing, 1 },
503 #define TEST_FUNCTION do_test ()
504 #include "../test-skeleton.c"