summaryrefslogtreecommitdiffstats
path: root/t/helper/test-regex.c
blob: bd871a735b4fbb19ed99e9bfab56f13d138a0567 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include "test-tool.h"
#include "gettext.h"

struct reg_flag {
	const char *name;
	int flag;
};

static struct reg_flag reg_flags[] = {
	{ "EXTENDED",	REG_EXTENDED	},
	{ "NEWLINE",	REG_NEWLINE	},
	{ "ICASE",	REG_ICASE	},
	{ "NOTBOL",	REG_NOTBOL	},
	{ "NOTEOL",	REG_NOTEOL	},
#ifdef REG_STARTEND
	{ "STARTEND",	REG_STARTEND	},
#endif
	{ NULL, 0 }
};

static int test_regex_bug(void)
{
	char *pat = "[^={} \t]+";
	char *str = "={}\nfred";
	regex_t r;
	regmatch_t m[1];

	if (regcomp(&r, pat, REG_EXTENDED | REG_NEWLINE))
		die("failed regcomp() for pattern '%s'", pat);
	if (regexec(&r, str, 1, m, 0))
		die("no match of pattern '%s' to string '%s'", pat, str);

	/* http://sourceware.org/bugzilla/show_bug.cgi?id=3957  */
	if (m[0].rm_so == 3) /* matches '\n' when it should not */
		die("regex bug confirmed: re-build git with NO_REGEX=1");

	regfree(&r);
	return 0;
}

int cmd__regex(int argc, const char **argv)
{
	const char *pat;
	const char *str;
	int ret, silent = 0, flags = 0;
	regex_t r;
	regmatch_t m[1];
	char errbuf[64];

	argv++;
	argc--;

	if (!argc)
		goto usage;

	if (!strcmp(*argv, "--bug")) {
		if (argc == 1)
			return test_regex_bug();
		else
			goto usage;
	}
	if (!strcmp(*argv, "--silent")) {
		silent = 1;
		argv++;
		argc--;
	}
	if (!argc)
		goto usage;

	pat = *argv++;
	if (argc == 1)
		str = NULL;
	else {
		str = *argv++;
		while (*argv) {
			struct reg_flag *rf;
			for (rf = reg_flags; rf->name; rf++)
				if (!strcmp(*argv, rf->name)) {
					flags |= rf->flag;
					break;
				}
			if (!rf->name)
				die("do not recognize flag %s", *argv);
			argv++;
		}
	}
	git_setup_gettext();

	ret = regcomp(&r, pat, flags);
	if (ret) {
		if (silent)
			return ret;

		regerror(ret, &r, errbuf, sizeof(errbuf));
		die("failed regcomp() for pattern '%s' (%s)", pat, errbuf);
	}
	if (!str)
		goto cleanup;

	ret = regexec(&r, str, 1, m, 0);
	if (ret) {
		if (silent || ret == REG_NOMATCH)
			goto cleanup;

		regerror(ret, &r, errbuf, sizeof(errbuf));
		die("failed regexec() for subject '%s' (%s)", str, errbuf);
	}

cleanup:
	regfree(&r);
	return ret;
usage:
	usage("\ttest-tool regex --bug\n"
	      "\ttest-tool regex [--silent] <pattern>\n"
	      "\ttest-tool regex [--silent] <pattern> <string> [<options>]");
	return -1;
}