1 /* Copyright (C) 2001, 2003 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, write to the Free
16 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 #include "spawn_int.h"
36 #include <sys/types.h>
48 static size_t umemlen
;
51 static int test_expr (const char *expr
, int expected
, int expectedicase
);
52 static int run_test (const char *expr
, const char *mem
, size_t memlen
,
53 int icase
, int expected
);
54 static int run_test_backwards (const char *expr
, const char *mem
,
55 size_t memlen
, int icase
, int expected
);
59 main (int argc
, char *argv
[])
69 static const struct option options
[] =
71 {"timing",no_argument
, &timing
, 1 },
77 while (getopt_long (argc
, argv
, "", options
, NULL
) >= 0);
79 /* Make the content of the file available in memory. */
80 file
= "../ChangeLog.8";
81 fd
= open (file
, O_RDONLY
);
83 error (EXIT_FAILURE
, errno
, "cannot open %s", basename (file
));
85 if (fstat (fd
, &st
) != 0)
86 error (EXIT_FAILURE
, errno
, "cannot stat %s", basename (file
));
89 mem
= (char *) malloc (memlen
+ 1);
91 error (EXIT_FAILURE
, errno
, "while allocating buffer");
93 if ((size_t) read (fd
, mem
, memlen
) != memlen
)
94 error (EXIT_FAILURE
, 0, "cannot read entire file");
99 /* We have to convert a few things from Latin-1 to UTF-8. */
100 cd
= iconv_open ("UTF-8", "ISO-8859-1");
101 if (cd
== (iconv_t
) -1)
102 error (EXIT_FAILURE
, errno
, "cannot get conversion descriptor");
104 /* For the second test we have to convert the file content to UTF-8.
105 Since the text is mostly ASCII it should be enough to allocate
106 twice as much memory for the UTF-8 text than for the Latin-1
108 umem
= (char *) calloc (2, memlen
);
110 error (EXIT_FAILURE
, errno
, "while allocating buffer");
115 outlen
= 2 * memlen
- 1;
116 iconv (cd
, &inmem
, &inlen
, &outmem
, &outlen
);
117 umemlen
= outmem
- umem
;
119 error (EXIT_FAILURE
, errno
, "cannot convert buffer");
121 #ifdef _POSIX_CPUTIME
122 /* See whether we can use the CPU clock. */
123 use_clock
= clock_getcpuclockid (0, &cl
) == 0;
127 re_set_syntax (RE_DEBUG
);
130 /* Run the actual tests. All tests are run in a single-byte and a
131 multi-byte locale. */
132 result
= test_expr ("[äáàâéèêíìîñöóòôüúùû]", 2, 2);
133 result
|= test_expr ("G.ran", 2, 3);
134 result
|= test_expr ("G.\\{1\\}ran", 2, 3);
135 result
|= test_expr ("G.*ran", 3, 44);
136 result
|= test_expr ("[äáàâ]", 0, 0);
137 result
|= test_expr ("Uddeborg", 2, 2);
138 result
|= test_expr (".Uddeborg", 2, 2);
140 /* Free the resources. */
150 test_expr (const char *expr
, int expected
, int expectedicase
)
159 /* First test: search with an ISO-8859-1 locale. */
160 if (setlocale (LC_ALL
, "de_DE.ISO-8859-1") == NULL
)
161 error (EXIT_FAILURE
, 0, "cannot set locale de_DE.ISO-8859-1");
163 printf ("\nTest \"%s\" with 8-bit locale\n", expr
);
164 result
= run_test (expr
, mem
, memlen
, 0, expected
);
165 printf ("\nTest \"%s\" with 8-bit locale, case insensitive\n", expr
);
166 result
|= run_test (expr
, mem
, memlen
, 1, expectedicase
);
167 printf ("\nTest \"%s\" backwards with 8-bit locale\n", expr
);
168 result
|= run_test_backwards (expr
, mem
, memlen
, 0, expected
);
169 printf ("\nTest \"%s\" backwards with 8-bit locale, case insensitive\n",
171 result
|= run_test_backwards (expr
, mem
, memlen
, 1, expectedicase
);
173 /* Second test: search with an UTF-8 locale. */
174 if (setlocale (LC_ALL
, "de_DE.UTF-8") == NULL
)
175 error (EXIT_FAILURE
, 0, "cannot set locale de_DE.UTF-8");
177 inmem
= (char *) expr
;
178 inlen
= strlen (expr
);
179 outlen
= inlen
* MB_CUR_MAX
;
180 outmem
= uexpr
= alloca (outlen
+ 1);
181 memset (outmem
, '\0', outlen
+ 1);
182 iconv (cd
, &inmem
, &inlen
, &outmem
, &outlen
);
184 error (EXIT_FAILURE
, errno
, "cannot convert expression");
187 printf ("\nTest \"%s\" with multi-byte locale\n", expr
);
188 result
|= run_test (uexpr
, umem
, umemlen
, 0, expected
);
189 printf ("\nTest \"%s\" with multi-byte locale, case insensitive\n", expr
);
190 result
|= run_test (uexpr
, umem
, umemlen
, 1, expectedicase
);
191 printf ("\nTest \"%s\" backwards with multi-byte locale\n", expr
);
192 result
|= run_test_backwards (uexpr
, umem
, umemlen
, 0, expected
);
193 printf ("\nTest \"%s\" backwards with multi-byte locale, case insensitive\n",
195 result
|= run_test_backwards (uexpr
, umem
, umemlen
, 1, expectedicase
);
202 run_test (const char *expr
, const char *mem
, size_t memlen
, int icase
,
205 #ifdef _POSIX_CPUTIME
206 struct timespec start
;
207 struct timespec finish
;
214 #ifdef _POSIX_CPUTIME
215 if (use_clock
&& !timing
)
216 use_clock
= clock_gettime (cl
, &start
) == 0;
219 err
= regcomp (&re
, expr
, REG_NEWLINE
| (icase
? REG_ICASE
: 0));
220 if (err
!= REG_NOERROR
)
223 regerror (err
, &re
, buf
, sizeof buf
);
224 error (EXIT_FAILURE
, 0, "cannot compile expression: %s", buf
);
229 assert (mem
[memlen
] == '\0');
230 while (offset
< memlen
)
236 err
= regexec (&re
, mem
+ offset
, 1, ma
, 0);
237 if (err
== REG_NOMATCH
)
240 if (err
!= REG_NOERROR
)
243 regerror (err
, &re
, buf
, sizeof buf
);
244 error (EXIT_FAILURE
, 0, "cannot use expression: %s", buf
);
247 assert (ma
[0].rm_so
>= 0);
248 sp
= mem
+ offset
+ ma
[0].rm_so
;
249 while (sp
> mem
&& sp
[-1] != '\n')
252 ep
= mem
+ offset
+ ma
[0].rm_so
;
253 while (*ep
!= '\0' && *ep
!= '\n')
256 printf ("match %d: \"%.*s\"\n", ++cnt
, (int) (ep
- sp
), sp
);
258 offset
= ep
+ 1 - mem
;
263 #ifdef _POSIX_CPUTIME
264 if (use_clock
&& !timing
)
266 use_clock
= clock_gettime (cl
, &finish
) == 0;
269 if (finish
.tv_nsec
< start
.tv_nsec
)
271 finish
.tv_nsec
-= start
.tv_nsec
- 1000000000;
272 finish
.tv_sec
-= 1 + start
.tv_sec
;
276 finish
.tv_nsec
-= start
.tv_nsec
;
277 finish
.tv_sec
-= start
.tv_sec
;
280 printf ("elapsed time: %ld.%09ld sec\n",
281 finish
.tv_sec
, finish
.tv_nsec
);
285 if (use_clock
&& timing
)
287 struct timespec mintime
= { .tv_sec
= 24 * 60 * 60 };
289 for (int i
= 0; i
< 10; ++i
)
292 use_clock
= clock_gettime (cl
, &start
) == 0;
297 err
= regcomp (&re
, expr
, REG_NEWLINE
| (icase
? REG_ICASE
: 0));
298 if (err
!= REG_NOERROR
)
301 while (offset
< memlen
)
305 err
= regexec (&re
, mem
+ offset
, 1, ma
, 0);
306 if (err
!= REG_NOERROR
)
309 offset
+= ma
[0].rm_eo
;
314 use_clock
= clock_gettime (cl
, &finish
) == 0;
317 if (finish
.tv_nsec
< start
.tv_nsec
)
319 finish
.tv_nsec
-= start
.tv_nsec
- 1000000000;
320 finish
.tv_sec
-= 1 + start
.tv_sec
;
324 finish
.tv_nsec
-= start
.tv_nsec
;
325 finish
.tv_sec
-= start
.tv_sec
;
327 if (finish
.tv_sec
< mintime
.tv_sec
328 || (finish
.tv_sec
== mintime
.tv_sec
329 && finish
.tv_nsec
< mintime
.tv_nsec
))
333 printf ("elapsed time: %ld.%09ld sec\n",
334 mintime
.tv_sec
, mintime
.tv_nsec
);
338 /* Return an error if the number of matches found is not match we
340 return cnt
!= expected
;
345 run_test_backwards (const char *expr
, const char *mem
, size_t memlen
,
346 int icase
, int expected
)
348 #ifdef _POSIX_CPUTIME
349 struct timespec start
;
350 struct timespec finish
;
352 struct re_pattern_buffer re
;
357 #ifdef _POSIX_CPUTIME
358 if (use_clock
&& !timing
)
359 use_clock
= clock_gettime (cl
, &start
) == 0;
362 re_set_syntax ((RE_SYNTAX_POSIX_BASIC
& ~RE_DOT_NEWLINE
)
363 | RE_HAT_LISTS_NOT_NEWLINE
364 | (icase
? RE_ICASE
: 0));
366 memset (&re
, 0, sizeof (re
));
367 re
.fastmap
= malloc (256);
368 if (re
.fastmap
== NULL
)
369 error (EXIT_FAILURE
, errno
, "cannot allocate fastmap");
371 err
= re_compile_pattern (expr
, strlen (expr
), &re
);
373 error (EXIT_FAILURE
, 0, "cannot compile expression: %s", err
);
375 if (re_compile_fastmap (&re
))
376 error (EXIT_FAILURE
, 0, "couldn't compile fastmap");
380 assert (mem
[memlen
] == '\0');
381 while (offset
<= memlen
)
387 start
= re_search (&re
, mem
, memlen
, offset
, -offset
, NULL
);
392 error (EXIT_FAILURE
, 0, "internal error in re_search");
395 while (sp
> mem
&& sp
[-1] != '\n')
399 while (*ep
!= '\0' && *ep
!= '\n')
402 printf ("match %d: \"%.*s\"\n", ++cnt
, (int) (ep
- sp
), sp
);
404 offset
= sp
- 1 - mem
;
409 #ifdef _POSIX_CPUTIME
410 if (use_clock
&& !timing
)
412 use_clock
= clock_gettime (cl
, &finish
) == 0;
415 if (finish
.tv_nsec
< start
.tv_nsec
)
417 finish
.tv_nsec
-= start
.tv_nsec
- 1000000000;
418 finish
.tv_sec
-= 1 + start
.tv_sec
;
422 finish
.tv_nsec
-= start
.tv_nsec
;
423 finish
.tv_sec
-= start
.tv_sec
;
426 printf ("elapsed time: %ld.%09ld sec\n",
427 finish
.tv_sec
, finish
.tv_nsec
);
431 if (use_clock
&& timing
)
433 struct timespec mintime
= { .tv_sec
= 24 * 60 * 60 };
435 for (int i
= 0; i
< 10; ++i
)
438 use_clock
= clock_gettime (cl
, &start
) == 0;
443 memset (&re
, 0, sizeof (re
));
444 re
.fastmap
= malloc (256);
445 if (re
.fastmap
== NULL
)
448 err
= re_compile_pattern (expr
, strlen (expr
), &re
);
452 if (re_compile_fastmap (&re
))
458 while (offset
<= memlen
)
463 start
= re_search (&re
, mem
, memlen
, offset
, -offset
, NULL
);
468 while (sp
> mem
&& sp
[-1] != '\n')
471 offset
= sp
- 1 - mem
;
476 use_clock
= clock_gettime (cl
, &finish
) == 0;
479 if (finish
.tv_nsec
< start
.tv_nsec
)
481 finish
.tv_nsec
-= start
.tv_nsec
- 1000000000;
482 finish
.tv_sec
-= 1 + start
.tv_sec
;
486 finish
.tv_nsec
-= start
.tv_nsec
;
487 finish
.tv_sec
-= start
.tv_sec
;
489 if (finish
.tv_sec
< mintime
.tv_sec
490 || (finish
.tv_sec
== mintime
.tv_sec
491 && finish
.tv_nsec
< mintime
.tv_nsec
))
495 printf ("elapsed time: %ld.%09ld sec\n",
496 mintime
.tv_sec
, mintime
.tv_nsec
);
500 /* Return an error if the number of matches found is not match we
502 return cnt
!= expected
;