#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)
{
	const char *pat = "[^={} \t]+";
	const 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);

	/* https://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;
}
