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>
40 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
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 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
122 # if _POSIX_CPUTIME == 0
123 if (sysconf (_SC_CPUTIME
) < 0)
127 /* See whether we can use the CPU clock. */
128 use_clock
= clock_getcpuclockid (0, &cl
) == 0;
132 re_set_syntax (RE_DEBUG
);
135 /* Run the actual tests. All tests are run in a single-byte and a
136 multi-byte locale. */
137 result
= test_expr ("[äáàâéèêíìîñöóòôüúùû]", 2, 2);
138 result
|= test_expr ("G.ran", 2, 3);
139 result
|= test_expr ("G.\\{1\\}ran", 2, 3);
140 result
|= test_expr ("G.*ran", 3, 44);
141 result
|= test_expr ("[äáàâ]", 0, 0);
142 result
|= test_expr ("Uddeborg", 2, 2);
143 result
|= test_expr (".Uddeborg", 2, 2);
145 /* Free the resources. */
155 test_expr (const char *expr
, int expected
, int expectedicase
)
164 /* First test: search with an ISO-8859-1 locale. */
165 if (setlocale (LC_ALL
, "de_DE.ISO-8859-1") == NULL
)
166 error (EXIT_FAILURE
, 0, "cannot set locale de_DE.ISO-8859-1");
168 printf ("\nTest \"%s\" with 8-bit locale\n", expr
);
169 result
= run_test (expr
, mem
, memlen
, 0, expected
);
170 printf ("\nTest \"%s\" with 8-bit locale, case insensitive\n", expr
);
171 result
|= run_test (expr
, mem
, memlen
, 1, expectedicase
);
172 printf ("\nTest \"%s\" backwards with 8-bit locale\n", expr
);
173 result
|= run_test_backwards (expr
, mem
, memlen
, 0, expected
);
174 printf ("\nTest \"%s\" backwards with 8-bit locale, case insensitive\n",
176 result
|= run_test_backwards (expr
, mem
, memlen
, 1, expectedicase
);
178 /* Second test: search with an UTF-8 locale. */
179 if (setlocale (LC_ALL
, "de_DE.UTF-8") == NULL
)
180 error (EXIT_FAILURE
, 0, "cannot set locale de_DE.UTF-8");
182 inmem
= (char *) expr
;
183 inlen
= strlen (expr
);
184 outlen
= inlen
* MB_CUR_MAX
;
185 outmem
= uexpr
= alloca (outlen
+ 1);
186 memset (outmem
, '\0', outlen
+ 1);
187 iconv (cd
, &inmem
, &inlen
, &outmem
, &outlen
);
189 error (EXIT_FAILURE
, errno
, "cannot convert expression");
192 printf ("\nTest \"%s\" with multi-byte locale\n", expr
);
193 result
|= run_test (uexpr
, umem
, umemlen
, 0, expected
);
194 printf ("\nTest \"%s\" with multi-byte locale, case insensitive\n", expr
);
195 result
|= run_test (uexpr
, umem
, umemlen
, 1, expectedicase
);
196 printf ("\nTest \"%s\" backwards with multi-byte locale\n", expr
);
197 result
|= run_test_backwards (uexpr
, umem
, umemlen
, 0, expected
);
198 printf ("\nTest \"%s\" backwards with multi-byte locale, case insensitive\n",
200 result
|= run_test_backwards (uexpr
, umem
, umemlen
, 1, expectedicase
);
207 run_test (const char *expr
, const char *mem
, size_t memlen
, int icase
,
210 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
211 struct timespec start
;
212 struct timespec finish
;
219 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
220 if (use_clock
&& !timing
)
221 use_clock
= clock_gettime (cl
, &start
) == 0;
224 err
= regcomp (&re
, expr
, REG_NEWLINE
| (icase
? REG_ICASE
: 0));
225 if (err
!= REG_NOERROR
)
228 regerror (err
, &re
, buf
, sizeof buf
);
229 error (EXIT_FAILURE
, 0, "cannot compile expression: %s", buf
);
234 assert (mem
[memlen
] == '\0');
235 while (offset
< memlen
)
241 err
= regexec (&re
, mem
+ offset
, 1, ma
, 0);
242 if (err
== REG_NOMATCH
)
245 if (err
!= REG_NOERROR
)
248 regerror (err
, &re
, buf
, sizeof buf
);
249 error (EXIT_FAILURE
, 0, "cannot use expression: %s", buf
);
252 assert (ma
[0].rm_so
>= 0);
253 sp
= mem
+ offset
+ ma
[0].rm_so
;
254 while (sp
> mem
&& sp
[-1] != '\n')
257 ep
= mem
+ offset
+ ma
[0].rm_so
;
258 while (*ep
!= '\0' && *ep
!= '\n')
261 printf ("match %d: \"%.*s\"\n", ++cnt
, (int) (ep
- sp
), sp
);
263 offset
= ep
+ 1 - mem
;
268 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
269 if (use_clock
&& !timing
)
271 use_clock
= clock_gettime (cl
, &finish
) == 0;
274 if (finish
.tv_nsec
< start
.tv_nsec
)
276 finish
.tv_nsec
-= start
.tv_nsec
- 1000000000;
277 finish
.tv_sec
-= 1 + start
.tv_sec
;
281 finish
.tv_nsec
-= start
.tv_nsec
;
282 finish
.tv_sec
-= start
.tv_sec
;
285 printf ("elapsed time: %ld.%09ld sec\n",
286 finish
.tv_sec
, finish
.tv_nsec
);
290 if (use_clock
&& timing
)
292 struct timespec mintime
= { .tv_sec
= 24 * 60 * 60 };
294 for (int i
= 0; i
< 10; ++i
)
297 use_clock
= clock_gettime (cl
, &start
) == 0;
302 err
= regcomp (&re
, expr
, REG_NEWLINE
| (icase
? REG_ICASE
: 0));
303 if (err
!= REG_NOERROR
)
306 while (offset
< memlen
)
310 err
= regexec (&re
, mem
+ offset
, 1, ma
, 0);
311 if (err
!= REG_NOERROR
)
314 offset
+= ma
[0].rm_eo
;
319 use_clock
= clock_gettime (cl
, &finish
) == 0;
322 if (finish
.tv_nsec
< start
.tv_nsec
)
324 finish
.tv_nsec
-= start
.tv_nsec
- 1000000000;
325 finish
.tv_sec
-= 1 + start
.tv_sec
;
329 finish
.tv_nsec
-= start
.tv_nsec
;
330 finish
.tv_sec
-= start
.tv_sec
;
332 if (finish
.tv_sec
< mintime
.tv_sec
333 || (finish
.tv_sec
== mintime
.tv_sec
334 && finish
.tv_nsec
< mintime
.tv_nsec
))
338 printf ("elapsed time: %ld.%09ld sec\n",
339 mintime
.tv_sec
, mintime
.tv_nsec
);
343 /* Return an error if the number of matches found is not match we
345 return cnt
!= expected
;
350 run_test_backwards (const char *expr
, const char *mem
, size_t memlen
,
351 int icase
, int expected
)
353 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
354 struct timespec start
;
355 struct timespec finish
;
357 struct re_pattern_buffer re
;
362 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
363 if (use_clock
&& !timing
)
364 use_clock
= clock_gettime (cl
, &start
) == 0;
367 re_set_syntax ((RE_SYNTAX_POSIX_BASIC
& ~RE_DOT_NEWLINE
)
368 | RE_HAT_LISTS_NOT_NEWLINE
369 | (icase
? RE_ICASE
: 0));
371 memset (&re
, 0, sizeof (re
));
372 re
.fastmap
= malloc (256);
373 if (re
.fastmap
== NULL
)
374 error (EXIT_FAILURE
, errno
, "cannot allocate fastmap");
376 err
= re_compile_pattern (expr
, strlen (expr
), &re
);
378 error (EXIT_FAILURE
, 0, "cannot compile expression: %s", err
);
380 if (re_compile_fastmap (&re
))
381 error (EXIT_FAILURE
, 0, "couldn't compile fastmap");
385 assert (mem
[memlen
] == '\0');
386 while (offset
<= memlen
)
392 start
= re_search (&re
, mem
, memlen
, offset
, -offset
, NULL
);
397 error (EXIT_FAILURE
, 0, "internal error in re_search");
400 while (sp
> mem
&& sp
[-1] != '\n')
404 while (*ep
!= '\0' && *ep
!= '\n')
407 printf ("match %d: \"%.*s\"\n", ++cnt
, (int) (ep
- sp
), sp
);
409 offset
= sp
- 1 - mem
;
414 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
415 if (use_clock
&& !timing
)
417 use_clock
= clock_gettime (cl
, &finish
) == 0;
420 if (finish
.tv_nsec
< start
.tv_nsec
)
422 finish
.tv_nsec
-= start
.tv_nsec
- 1000000000;
423 finish
.tv_sec
-= 1 + start
.tv_sec
;
427 finish
.tv_nsec
-= start
.tv_nsec
;
428 finish
.tv_sec
-= start
.tv_sec
;
431 printf ("elapsed time: %ld.%09ld sec\n",
432 finish
.tv_sec
, finish
.tv_nsec
);
436 if (use_clock
&& timing
)
438 struct timespec mintime
= { .tv_sec
= 24 * 60 * 60 };
440 for (int i
= 0; i
< 10; ++i
)
443 use_clock
= clock_gettime (cl
, &start
) == 0;
448 memset (&re
, 0, sizeof (re
));
449 re
.fastmap
= malloc (256);
450 if (re
.fastmap
== NULL
)
453 err
= re_compile_pattern (expr
, strlen (expr
), &re
);
457 if (re_compile_fastmap (&re
))
463 while (offset
<= memlen
)
468 start
= re_search (&re
, mem
, memlen
, offset
, -offset
, NULL
);
473 while (sp
> mem
&& sp
[-1] != '\n')
476 offset
= sp
- 1 - mem
;
481 use_clock
= clock_gettime (cl
, &finish
) == 0;
484 if (finish
.tv_nsec
< start
.tv_nsec
)
486 finish
.tv_nsec
-= start
.tv_nsec
- 1000000000;
487 finish
.tv_sec
-= 1 + start
.tv_sec
;
491 finish
.tv_nsec
-= start
.tv_nsec
;
492 finish
.tv_sec
-= start
.tv_sec
;
494 if (finish
.tv_sec
< mintime
.tv_sec
495 || (finish
.tv_sec
== mintime
.tv_sec
496 && finish
.tv_nsec
< mintime
.tv_nsec
))
500 printf ("elapsed time: %ld.%09ld sec\n",
501 mintime
.tv_sec
, mintime
.tv_nsec
);
505 /* Return an error if the number of matches found is not match we
507 return cnt
!= expected
;