|  | #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; | 
|  | } |