Merge branch 'ds/sparse-index-protections'
[git] / t / helper / test-regex.c
1 #include "test-tool.h"
2 #include "gettext.h"
3
4 struct reg_flag {
5         const char *name;
6         int flag;
7 };
8
9 static struct reg_flag reg_flags[] = {
10         { "EXTENDED",   REG_EXTENDED    },
11         { "NEWLINE",    REG_NEWLINE     },
12         { "ICASE",      REG_ICASE       },
13         { "NOTBOL",     REG_NOTBOL      },
14         { "NOTEOL",     REG_NOTEOL      },
15 #ifdef REG_STARTEND
16         { "STARTEND",   REG_STARTEND    },
17 #endif
18         { NULL, 0 }
19 };
20
21 static int test_regex_bug(void)
22 {
23         char *pat = "[^={} \t]+";
24         char *str = "={}\nfred";
25         regex_t r;
26         regmatch_t m[1];
27
28         if (regcomp(&r, pat, REG_EXTENDED | REG_NEWLINE))
29                 die("failed regcomp() for pattern '%s'", pat);
30         if (regexec(&r, str, 1, m, 0))
31                 die("no match of pattern '%s' to string '%s'", pat, str);
32
33         /* http://sourceware.org/bugzilla/show_bug.cgi?id=3957  */
34         if (m[0].rm_so == 3) /* matches '\n' when it should not */
35                 die("regex bug confirmed: re-build git with NO_REGEX=1");
36
37         return 0;
38 }
39
40 int cmd__regex(int argc, const char **argv)
41 {
42         const char *pat;
43         const char *str;
44         int ret, silent = 0, flags = 0;
45         regex_t r;
46         regmatch_t m[1];
47         char errbuf[64];
48
49         argv++;
50         argc--;
51
52         if (!argc)
53                 goto usage;
54
55         if (!strcmp(*argv, "--bug")) {
56                 if (argc == 1)
57                         return test_regex_bug();
58                 else
59                         goto usage;
60         }
61         if (!strcmp(*argv, "--silent")) {
62                 silent = 1;
63                 argv++;
64                 argc--;
65         }
66         if (!argc)
67                 goto usage;
68
69         pat = *argv++;
70         if (argc == 1)
71                 str = NULL;
72         else {
73                 str = *argv++;
74                 while (*argv) {
75                         struct reg_flag *rf;
76                         for (rf = reg_flags; rf->name; rf++)
77                                 if (!strcmp(*argv, rf->name)) {
78                                         flags |= rf->flag;
79                                         break;
80                                 }
81                         if (!rf->name)
82                                 die("do not recognize flag %s", *argv);
83                         argv++;
84                 }
85         }
86         git_setup_gettext();
87
88         ret = regcomp(&r, pat, flags);
89         if (ret) {
90                 if (silent)
91                         return ret;
92
93                 regerror(ret, &r, errbuf, sizeof(errbuf));
94                 die("failed regcomp() for pattern '%s' (%s)", pat, errbuf);
95         }
96         if (!str)
97                 return 0;
98
99         ret = regexec(&r, str, 1, m, 0);
100         if (ret) {
101                 if (silent || ret == REG_NOMATCH)
102                         return ret;
103
104                 regerror(ret, &r, errbuf, sizeof(errbuf));
105                 die("failed regexec() for subject '%s' (%s)", str, errbuf);
106         }
107
108         return 0;
109 usage:
110         usage("\ttest-tool regex --bug\n"
111               "\ttest-tool regex [--silent] <pattern>\n"
112               "\ttest-tool regex [--silent] <pattern> <string> [<options>]");
113         return -1;
114 }