Smack: add the execute lable to ldconfig
[platform/upstream/glibc.git] / posix / tst-regex.c
1 /* Copyright (C) 2001-2015 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
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.
8
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.
13
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/>.  */
17
18 #include <spawn.h>
19 #include "spawn_int.h"
20
21 #include <assert.h>
22 #include <errno.h>
23 #include <error.h>
24 #include <fcntl.h>
25 #include <getopt.h>
26 #include <iconv.h>
27 #include <locale.h>
28 #include <mcheck.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <time.h>
33 #include <unistd.h>
34 #include <sys/stat.h>
35 #include <sys/types.h>
36 #include <regex.h>
37
38
39 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
40 static clockid_t cl;
41 static int use_clock;
42 #endif
43 static iconv_t cd;
44 static char *mem;
45 static char *umem;
46 static size_t memlen;
47 static size_t umemlen;
48 static int timing;
49
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);
55
56
57 static int
58 do_test (void)
59 {
60   const char *file;
61   int fd;
62   struct stat st;
63   int result;
64   char *inmem;
65   char *outmem;
66   size_t inlen;
67   size_t outlen;
68
69   mtrace ();
70
71   /* Make the content of the file available in memory.  */
72   file = "../ChangeLog.8";
73   fd = open (file, O_RDONLY);
74   if (fd == -1)
75     error (EXIT_FAILURE, errno, "cannot open %s", basename (file));
76
77   if (fstat (fd, &st) != 0)
78     error (EXIT_FAILURE, errno, "cannot stat %s", basename (file));
79   memlen = st.st_size;
80
81   mem = (char *) malloc (memlen + 1);
82   if (mem == NULL)
83     error (EXIT_FAILURE, errno, "while allocating buffer");
84
85   if ((size_t) read (fd, mem, memlen) != memlen)
86     error (EXIT_FAILURE, 0, "cannot read entire file");
87   mem[memlen] = '\0';
88
89   close (fd);
90
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");
95
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
99      text.  */
100   umem = (char *) calloc (2, memlen);
101   if (umem == NULL)
102     error (EXIT_FAILURE, errno, "while allocating buffer");
103
104   inmem = mem;
105   inlen = memlen;
106   outmem = umem;
107   outlen = 2 * memlen - 1;
108   iconv (cd, &inmem, &inlen, &outmem, &outlen);
109   umemlen = outmem - umem;
110   if (inlen != 0)
111     error (EXIT_FAILURE, errno, "cannot convert buffer");
112
113 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
114 # if _POSIX_CPUTIME == 0
115   if (sysconf (_SC_CPUTIME) < 0)
116     use_clock = 0;
117   else
118 # endif
119     /* See whether we can use the CPU clock.  */
120     use_clock = clock_getcpuclockid (0, &cl) == 0;
121 #endif
122
123 #ifdef DEBUG
124   re_set_syntax (RE_DEBUG);
125 #endif
126
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);
136
137   /* Free the resources.  */
138   free (umem);
139   iconv_close (cd);
140   free (mem);
141
142   return result;
143 }
144
145
146 static int
147 test_expr (const char *expr, int expected, int expectedicase)
148 {
149   int result;
150   char *inmem;
151   char *outmem;
152   size_t inlen;
153   size_t outlen;
154   char *uexpr;
155
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");
159
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",
167           expr);
168   result |= run_test_backwards (expr, mem, memlen, 1, expectedicase);
169
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");
173
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);
180   if (inlen != 0)
181     error (EXIT_FAILURE, errno, "cannot convert expression");
182
183   /* Run the tests.  */
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",
191           expr);
192   result |= run_test_backwards (uexpr, umem, umemlen, 1, expectedicase);
193
194   return result;
195 }
196
197
198 static int
199 run_test (const char *expr, const char *mem, size_t memlen, int icase,
200           int expected)
201 {
202 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
203   struct timespec start;
204   struct timespec finish;
205 #endif
206   regex_t re;
207   int err;
208   size_t offset;
209   int cnt;
210
211 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
212   if (use_clock && !timing)
213     use_clock = clock_gettime (cl, &start) == 0;
214 #endif
215
216   err = regcomp (&re, expr, REG_NEWLINE | (icase ? REG_ICASE : 0));
217   if (err != REG_NOERROR)
218     {
219       char buf[200];
220       regerror (err, &re, buf, sizeof buf);
221       error (EXIT_FAILURE, 0, "cannot compile expression: %s", buf);
222     }
223
224   cnt = 0;
225   offset = 0;
226   assert (mem[memlen] == '\0');
227   while (offset < memlen)
228     {
229       regmatch_t ma[1];
230       const char *sp;
231       const char *ep;
232
233       err = regexec (&re, mem + offset, 1, ma, 0);
234       if (err == REG_NOMATCH)
235         break;
236
237       if (err != REG_NOERROR)
238         {
239           char buf[200];
240           regerror (err, &re, buf, sizeof buf);
241           error (EXIT_FAILURE, 0, "cannot use expression: %s", buf);
242         }
243
244       assert (ma[0].rm_so >= 0);
245       sp = mem + offset + ma[0].rm_so;
246       while (sp > mem && sp[-1] != '\n')
247         --sp;
248
249       ep = mem + offset + ma[0].rm_so;
250       while (*ep != '\0' && *ep != '\n')
251         ++ep;
252
253       printf ("match %d: \"%.*s\"\n", ++cnt, (int) (ep - sp), sp);
254
255       offset = ep + 1 - mem;
256     }
257
258   regfree (&re);
259
260 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
261   if (use_clock && !timing)
262     {
263       use_clock = clock_gettime (cl, &finish) == 0;
264       if (use_clock)
265         {
266           if (finish.tv_nsec < start.tv_nsec)
267             {
268               finish.tv_nsec -= start.tv_nsec - 1000000000;
269               finish.tv_sec -= 1 + start.tv_sec;
270             }
271           else
272             {
273               finish.tv_nsec -= start.tv_nsec;
274               finish.tv_sec -= start.tv_sec;
275             }
276
277           printf ("elapsed time: %jd.%09jd sec\n",
278                   (intmax_t) finish.tv_sec, (intmax_t) finish.tv_nsec);
279         }
280     }
281
282   if (use_clock && timing)
283     {
284       struct timespec mintime = { .tv_sec = 24 * 60 * 60 };
285
286       for (int i = 0; i < 10; ++i)
287         {
288           offset = 0;
289           use_clock = clock_gettime (cl, &start) == 0;
290
291           if (!use_clock)
292             continue;
293
294           err = regcomp (&re, expr, REG_NEWLINE | (icase ? REG_ICASE : 0));
295           if (err != REG_NOERROR)
296             continue;
297
298           while (offset < memlen)
299             {
300               regmatch_t ma[1];
301
302               err = regexec (&re, mem + offset, 1, ma, 0);
303               if (err != REG_NOERROR)
304                 break;
305
306               offset += ma[0].rm_eo;
307             }
308
309           regfree (&re);
310
311           use_clock = clock_gettime (cl, &finish) == 0;
312           if (use_clock)
313             {
314               if (finish.tv_nsec < start.tv_nsec)
315                 {
316                   finish.tv_nsec -= start.tv_nsec - 1000000000;
317                   finish.tv_sec -= 1 + start.tv_sec;
318                 }
319               else
320                 {
321                   finish.tv_nsec -= start.tv_nsec;
322                   finish.tv_sec -= start.tv_sec;
323                 }
324               if (finish.tv_sec < mintime.tv_sec
325                   || (finish.tv_sec == mintime.tv_sec
326                       && finish.tv_nsec < mintime.tv_nsec))
327                 mintime = finish;
328             }
329         }
330       printf ("elapsed time: %jd.%09jd sec\n",
331               (intmax_t) mintime.tv_sec, (intmax_t) mintime.tv_nsec);
332     }
333 #endif
334
335   /* Return an error if the number of matches found is not match we
336      expect.  */
337   return cnt != expected;
338 }
339
340
341 static int
342 run_test_backwards (const char *expr, const char *mem, size_t memlen,
343                     int icase, int expected)
344 {
345 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
346   struct timespec start;
347   struct timespec finish;
348 #endif
349   struct re_pattern_buffer re;
350   const char *err;
351   size_t offset;
352   int cnt;
353
354 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
355   if (use_clock && !timing)
356     use_clock = clock_gettime (cl, &start) == 0;
357 #endif
358
359   re_set_syntax ((RE_SYNTAX_POSIX_BASIC & ~RE_DOT_NEWLINE)
360                  | RE_HAT_LISTS_NOT_NEWLINE
361                  | (icase ? RE_ICASE : 0));
362
363   memset (&re, 0, sizeof (re));
364   re.fastmap = malloc (256);
365   if (re.fastmap == NULL)
366     error (EXIT_FAILURE, errno, "cannot allocate fastmap");
367
368   err = re_compile_pattern (expr, strlen (expr), &re);
369   if (err != NULL)
370     error (EXIT_FAILURE, 0, "cannot compile expression: %s", err);
371
372   if (re_compile_fastmap (&re))
373     error (EXIT_FAILURE, 0, "couldn't compile fastmap");
374
375   cnt = 0;
376   offset = memlen;
377   assert (mem[memlen] == '\0');
378   while (offset <= memlen)
379     {
380       int start;
381       const char *sp;
382       const char *ep;
383
384       start = re_search (&re, mem, memlen, offset, -offset, NULL);
385       if (start == -1)
386         break;
387
388       if (start == -2)
389         error (EXIT_FAILURE, 0, "internal error in re_search");
390
391       sp = mem + start;
392       while (sp > mem && sp[-1] != '\n')
393         --sp;
394
395       ep = mem + start;
396       while (*ep != '\0' && *ep != '\n')
397         ++ep;
398
399       printf ("match %d: \"%.*s\"\n", ++cnt, (int) (ep - sp), sp);
400
401       offset = sp - 1 - mem;
402     }
403
404   regfree (&re);
405
406 #if defined _POSIX_CPUTIME && _POSIX_CPUTIME >= 0
407   if (use_clock && !timing)
408     {
409       use_clock = clock_gettime (cl, &finish) == 0;
410       if (use_clock)
411         {
412           if (finish.tv_nsec < start.tv_nsec)
413             {
414               finish.tv_nsec -= start.tv_nsec - 1000000000;
415               finish.tv_sec -= 1 + start.tv_sec;
416             }
417           else
418             {
419               finish.tv_nsec -= start.tv_nsec;
420               finish.tv_sec -= start.tv_sec;
421             }
422
423           printf ("elapsed time: %jd.%09jd sec\n",
424                   (intmax_t) finish.tv_sec, (intmax_t) finish.tv_nsec);
425         }
426     }
427
428   if (use_clock && timing)
429     {
430       struct timespec mintime = { .tv_sec = 24 * 60 * 60 };
431
432       for (int i = 0; i < 10; ++i)
433         {
434           offset = memlen;
435           use_clock = clock_gettime (cl, &start) == 0;
436
437           if (!use_clock)
438             continue;
439
440           memset (&re, 0, sizeof (re));
441           re.fastmap = malloc (256);
442           if (re.fastmap == NULL)
443             continue;
444
445           err = re_compile_pattern (expr, strlen (expr), &re);
446           if (err != NULL)
447             continue;
448
449           if (re_compile_fastmap (&re))
450             {
451               regfree (&re);
452               continue;
453             }
454
455           while (offset <= memlen)
456             {
457               int start;
458               const char *sp;
459
460               start = re_search (&re, mem, memlen, offset, -offset, NULL);
461               if (start < -1)
462                 break;
463
464               sp = mem + start;
465               while (sp > mem && sp[-1] != '\n')
466                 --sp;
467
468               offset = sp - 1 - mem;
469             }
470
471           regfree (&re);
472
473           use_clock = clock_gettime (cl, &finish) == 0;
474           if (use_clock)
475             {
476               if (finish.tv_nsec < start.tv_nsec)
477                 {
478                   finish.tv_nsec -= start.tv_nsec - 1000000000;
479                   finish.tv_sec -= 1 + start.tv_sec;
480                 }
481               else
482                 {
483                   finish.tv_nsec -= start.tv_nsec;
484                   finish.tv_sec -= start.tv_sec;
485                 }
486               if (finish.tv_sec < mintime.tv_sec
487                   || (finish.tv_sec == mintime.tv_sec
488                       && finish.tv_nsec < mintime.tv_nsec))
489                 mintime = finish;
490             }
491         }
492       printf ("elapsed time: %jd.%09jd sec\n",
493               (intmax_t) mintime.tv_sec, (intmax_t) mintime.tv_nsec);
494     }
495 #endif
496
497   /* Return an error if the number of matches found is not match we
498      expect.  */
499   return cnt != expected;
500 }
501
502 /* If --timing is used we will need a larger timout.  */
503 #define TIMEOUT 50
504 #define CMDLINE_OPTIONS \
505    {"timing", no_argument, &timing, 1 },
506 #define TEST_FUNCTION do_test ()
507 #include "../test-skeleton.c"