1 /* Copyright (C) 2001-2016 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/>. */
19 #include "spawn_int.h"
35 #include <sys/types.h>
39 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
47 static size_t umemlen
;
50 static int test_expr (const char *expr
, int expected
, int expectedicase
);
51 static int run_test (const char *expr
, const char *mem
, size_t memlen
,
52 int icase
, int expected
);
53 static int run_test_backwards (const char *expr
, const char *mem
,
54 size_t memlen
, int icase
, int expected
);
71 /* Make the content of the file available in memory. */
72 file
= "../ChangeLog.8";
73 fd
= open (file
, O_RDONLY
);
75 error (EXIT_FAILURE
, errno
, "cannot open %s", basename (file
));
77 if (fstat (fd
, &st
) != 0)
78 error (EXIT_FAILURE
, errno
, "cannot stat %s", basename (file
));
81 mem
= (char *) malloc (memlen
+ 1);
83 error (EXIT_FAILURE
, errno
, "while allocating buffer");
85 if ((size_t) read (fd
, mem
, memlen
) != memlen
)
86 error (EXIT_FAILURE
, 0, "cannot read entire file");
91 /* We have to convert a few things from Latin-1 to UTF-8. */
92 cd
= iconv_open ("UTF-8", "ISO-8859-1");
93 if (cd
== (iconv_t
) -1)
94 error (EXIT_FAILURE
, errno
, "cannot get conversion descriptor");
96 /* For the second test we have to convert the file content to UTF-8.
97 Since the text is mostly ASCII it should be enough to allocate
98 twice as much memory for the UTF-8 text than for the Latin-1
100 umem
= (char *) calloc (2, memlen
);
102 error (EXIT_FAILURE
, errno
, "while allocating buffer");
107 outlen
= 2 * memlen
- 1;
108 iconv (cd
, &inmem
, &inlen
, &outmem
, &outlen
);
109 umemlen
= outmem
- umem
;
111 error (EXIT_FAILURE
, errno
, "cannot convert buffer");
113 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
114 # if _POSIX_CPUTIME == 0
115 if (sysconf (_SC_CPUTIME
) < 0)
119 /* See whether we can use the CPU clock. */
120 use_clock
= clock_getcpuclockid (0, &cl
) == 0;
124 re_set_syntax (RE_DEBUG
);
127 /* Run the actual tests. All tests are run in a single-byte and a
128 multi-byte locale. */
129 result
= test_expr ("[äáàâéèêíìîñöóòôüúùû]", 2, 2);
130 result
|= test_expr ("G.ran", 2, 3);
131 result
|= test_expr ("G.\\{1\\}ran", 2, 3);
132 result
|= test_expr ("G.*ran", 3, 44);
133 result
|= test_expr ("[äáàâ]", 0, 0);
134 result
|= test_expr ("Uddeborg", 2, 2);
135 result
|= test_expr (".Uddeborg", 2, 2);
137 /* Free the resources. */
147 test_expr (const char *expr
, int expected
, int expectedicase
)
156 /* First test: search with an ISO-8859-1 locale. */
157 if (setlocale (LC_ALL
, "de_DE.ISO-8859-1") == NULL
)
158 error (EXIT_FAILURE
, 0, "cannot set locale de_DE.ISO-8859-1");
160 printf ("\nTest \"%s\" with 8-bit locale\n", expr
);
161 result
= run_test (expr
, mem
, memlen
, 0, expected
);
162 printf ("\nTest \"%s\" with 8-bit locale, case insensitive\n", expr
);
163 result
|= run_test (expr
, mem
, memlen
, 1, expectedicase
);
164 printf ("\nTest \"%s\" backwards with 8-bit locale\n", expr
);
165 result
|= run_test_backwards (expr
, mem
, memlen
, 0, expected
);
166 printf ("\nTest \"%s\" backwards with 8-bit locale, case insensitive\n",
168 result
|= run_test_backwards (expr
, mem
, memlen
, 1, expectedicase
);
170 /* Second test: search with an UTF-8 locale. */
171 if (setlocale (LC_ALL
, "de_DE.UTF-8") == NULL
)
172 error (EXIT_FAILURE
, 0, "cannot set locale de_DE.UTF-8");
174 inmem
= (char *) expr
;
175 inlen
= strlen (expr
);
176 outlen
= inlen
* MB_CUR_MAX
;
177 outmem
= uexpr
= alloca (outlen
+ 1);
178 memset (outmem
, '\0', outlen
+ 1);
179 iconv (cd
, &inmem
, &inlen
, &outmem
, &outlen
);
181 error (EXIT_FAILURE
, errno
, "cannot convert expression");
184 printf ("\nTest \"%s\" with multi-byte locale\n", expr
);
185 result
|= run_test (uexpr
, umem
, umemlen
, 0, expected
);
186 printf ("\nTest \"%s\" with multi-byte locale, case insensitive\n", expr
);
187 result
|= run_test (uexpr
, umem
, umemlen
, 1, expectedicase
);
188 printf ("\nTest \"%s\" backwards with multi-byte locale\n", expr
);
189 result
|= run_test_backwards (uexpr
, umem
, umemlen
, 0, expected
);
190 printf ("\nTest \"%s\" backwards with multi-byte locale, case insensitive\n",
192 result
|= run_test_backwards (uexpr
, umem
, umemlen
, 1, expectedicase
);
199 run_test (const char *expr
, const char *mem
, size_t memlen
, int icase
,
202 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
203 struct timespec start
;
204 struct timespec finish
;
211 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
212 if (use_clock
&& !timing
)
213 use_clock
= clock_gettime (cl
, &start
) == 0;
216 err
= regcomp (&re
, expr
, REG_NEWLINE
| (icase
? REG_ICASE
: 0));
217 if (err
!= REG_NOERROR
)
220 regerror (err
, &re
, buf
, sizeof buf
);
221 error (EXIT_FAILURE
, 0, "cannot compile expression: %s", buf
);
226 assert (mem
[memlen
] == '\0');
227 while (offset
< memlen
)
233 err
= regexec (&re
, mem
+ offset
, 1, ma
, 0);
234 if (err
== REG_NOMATCH
)
237 if (err
!= REG_NOERROR
)
240 regerror (err
, &re
, buf
, sizeof buf
);
241 error (EXIT_FAILURE
, 0, "cannot use expression: %s", buf
);
244 assert (ma
[0].rm_so
>= 0);
245 sp
= mem
+ offset
+ ma
[0].rm_so
;
246 while (sp
> mem
&& sp
[-1] != '\n')
249 ep
= mem
+ offset
+ ma
[0].rm_so
;
250 while (*ep
!= '\0' && *ep
!= '\n')
253 printf ("match %d: \"%.*s\"\n", ++cnt
, (int) (ep
- sp
), sp
);
255 offset
= ep
+ 1 - mem
;
260 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
261 if (use_clock
&& !timing
)
263 use_clock
= clock_gettime (cl
, &finish
) == 0;
266 if (finish
.tv_nsec
< start
.tv_nsec
)
268 finish
.tv_nsec
-= start
.tv_nsec
- 1000000000;
269 finish
.tv_sec
-= 1 + start
.tv_sec
;
273 finish
.tv_nsec
-= start
.tv_nsec
;
274 finish
.tv_sec
-= start
.tv_sec
;
277 printf ("elapsed time: %jd.%09jd sec\n",
278 (intmax_t) finish
.tv_sec
, (intmax_t) finish
.tv_nsec
);
282 if (use_clock
&& timing
)
284 struct timespec mintime
= { .tv_sec
= 24 * 60 * 60 };
286 for (int i
= 0; i
< 10; ++i
)
289 use_clock
= clock_gettime (cl
, &start
) == 0;
294 err
= regcomp (&re
, expr
, REG_NEWLINE
| (icase
? REG_ICASE
: 0));
295 if (err
!= REG_NOERROR
)
298 while (offset
< memlen
)
302 err
= regexec (&re
, mem
+ offset
, 1, ma
, 0);
303 if (err
!= REG_NOERROR
)
306 offset
+= ma
[0].rm_eo
;
311 use_clock
= clock_gettime (cl
, &finish
) == 0;
314 if (finish
.tv_nsec
< start
.tv_nsec
)
316 finish
.tv_nsec
-= start
.tv_nsec
- 1000000000;
317 finish
.tv_sec
-= 1 + start
.tv_sec
;
321 finish
.tv_nsec
-= start
.tv_nsec
;
322 finish
.tv_sec
-= start
.tv_sec
;
324 if (finish
.tv_sec
< mintime
.tv_sec
325 || (finish
.tv_sec
== mintime
.tv_sec
326 && finish
.tv_nsec
< mintime
.tv_nsec
))
330 printf ("elapsed time: %jd.%09jd sec\n",
331 (intmax_t) mintime
.tv_sec
, (intmax_t) mintime
.tv_nsec
);
335 /* Return an error if the number of matches found is not match we
337 return cnt
!= expected
;
342 run_test_backwards (const char *expr
, const char *mem
, size_t memlen
,
343 int icase
, int expected
)
345 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
346 struct timespec start
;
347 struct timespec finish
;
349 struct re_pattern_buffer re
;
354 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
355 if (use_clock
&& !timing
)
356 use_clock
= clock_gettime (cl
, &start
) == 0;
359 re_set_syntax ((RE_SYNTAX_POSIX_BASIC
& ~RE_DOT_NEWLINE
)
360 | RE_HAT_LISTS_NOT_NEWLINE
361 | (icase
? RE_ICASE
: 0));
363 memset (&re
, 0, sizeof (re
));
364 re
.fastmap
= malloc (256);
365 if (re
.fastmap
== NULL
)
366 error (EXIT_FAILURE
, errno
, "cannot allocate fastmap");
368 err
= re_compile_pattern (expr
, strlen (expr
), &re
);
370 error (EXIT_FAILURE
, 0, "cannot compile expression: %s", err
);
372 if (re_compile_fastmap (&re
))
373 error (EXIT_FAILURE
, 0, "couldn't compile fastmap");
377 assert (mem
[memlen
] == '\0');
378 while (offset
<= memlen
)
384 start
= re_search (&re
, mem
, memlen
, offset
, -offset
, NULL
);
389 error (EXIT_FAILURE
, 0, "internal error in re_search");
392 while (sp
> mem
&& sp
[-1] != '\n')
396 while (*ep
!= '\0' && *ep
!= '\n')
399 printf ("match %d: \"%.*s\"\n", ++cnt
, (int) (ep
- sp
), sp
);
401 offset
= sp
- 1 - mem
;
406 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
407 if (use_clock
&& !timing
)
409 use_clock
= clock_gettime (cl
, &finish
) == 0;
412 if (finish
.tv_nsec
< start
.tv_nsec
)
414 finish
.tv_nsec
-= start
.tv_nsec
- 1000000000;
415 finish
.tv_sec
-= 1 + start
.tv_sec
;
419 finish
.tv_nsec
-= start
.tv_nsec
;
420 finish
.tv_sec
-= start
.tv_sec
;
423 printf ("elapsed time: %jd.%09jd sec\n",
424 (intmax_t) finish
.tv_sec
, (intmax_t) finish
.tv_nsec
);
428 if (use_clock
&& timing
)
430 struct timespec mintime
= { .tv_sec
= 24 * 60 * 60 };
432 for (int i
= 0; i
< 10; ++i
)
435 use_clock
= clock_gettime (cl
, &start
) == 0;
440 memset (&re
, 0, sizeof (re
));
441 re
.fastmap
= malloc (256);
442 if (re
.fastmap
== NULL
)
445 err
= re_compile_pattern (expr
, strlen (expr
), &re
);
449 if (re_compile_fastmap (&re
))
455 while (offset
<= memlen
)
460 start
= re_search (&re
, mem
, memlen
, offset
, -offset
, NULL
);
465 while (sp
> mem
&& sp
[-1] != '\n')
468 offset
= sp
- 1 - mem
;
473 use_clock
= clock_gettime (cl
, &finish
) == 0;
476 if (finish
.tv_nsec
< start
.tv_nsec
)
478 finish
.tv_nsec
-= start
.tv_nsec
- 1000000000;
479 finish
.tv_sec
-= 1 + start
.tv_sec
;
483 finish
.tv_nsec
-= start
.tv_nsec
;
484 finish
.tv_sec
-= start
.tv_sec
;
486 if (finish
.tv_sec
< mintime
.tv_sec
487 || (finish
.tv_sec
== mintime
.tv_sec
488 && finish
.tv_nsec
< mintime
.tv_nsec
))
492 printf ("elapsed time: %jd.%09jd sec\n",
493 (intmax_t) mintime
.tv_sec
, (intmax_t) mintime
.tv_nsec
);
497 /* Return an error if the number of matches found is not match we
499 return cnt
!= expected
;
502 /* If --timing is used we will need a larger timout. */
504 #define CMDLINE_OPTIONS \
505 {"timing", no_argument, &timing, 1 },
506 #define TEST_FUNCTION do_test ()
507 #include "../test-skeleton.c"