]>
Commit | Line | Data |
---|---|---|
22a2d3d5 UG |
1 | /* |
2 | * Copyright (C) the libgit2 contributors. All rights reserved. | |
3 | * | |
4 | * This file is part of libgit2, distributed under the GNU GPL v2 with | |
5 | * a Linking Exception. For full terms see the included COPYING file. | |
6 | */ | |
7 | ||
8 | #include "regexp.h" | |
9 | ||
10 | #if defined(GIT_REGEX_BUILTIN) || defined(GIT_REGEX_PCRE) | |
11 | ||
12 | int git_regexp_compile(git_regexp *r, const char *pattern, int flags) | |
13 | { | |
14 | int erroffset, cflags = 0; | |
15 | const char *error = NULL; | |
16 | ||
17 | if (flags & GIT_REGEXP_ICASE) | |
18 | cflags |= PCRE_CASELESS; | |
19 | ||
20 | if ((*r = pcre_compile(pattern, cflags, &error, &erroffset, NULL)) == NULL) { | |
21 | git_error_set_str(GIT_ERROR_REGEX, error); | |
22 | return GIT_EINVALIDSPEC; | |
23 | } | |
24 | ||
25 | return 0; | |
26 | } | |
27 | ||
28 | void git_regexp_dispose(git_regexp *r) | |
29 | { | |
30 | pcre_free(*r); | |
31 | *r = NULL; | |
32 | } | |
33 | ||
34 | int git_regexp_match(const git_regexp *r, const char *string) | |
35 | { | |
36 | int error; | |
37 | if ((error = pcre_exec(*r, NULL, string, (int) strlen(string), 0, 0, NULL, 0)) < 0) | |
38 | return (error == PCRE_ERROR_NOMATCH) ? GIT_ENOTFOUND : GIT_EINVALIDSPEC; | |
39 | return 0; | |
40 | } | |
41 | ||
42 | int git_regexp_search(const git_regexp *r, const char *string, size_t nmatches, git_regmatch *matches) | |
43 | { | |
44 | int static_ovec[9] = {0}, *ovec; | |
45 | int error; | |
46 | size_t i; | |
47 | ||
e579e0f7 | 48 | /* The ovec array always needs to be a multiple of three */ |
22a2d3d5 UG |
49 | if (nmatches <= ARRAY_SIZE(static_ovec) / 3) |
50 | ovec = static_ovec; | |
51 | else | |
52 | ovec = git__calloc(nmatches * 3, sizeof(*ovec)); | |
53 | GIT_ERROR_CHECK_ALLOC(ovec); | |
54 | ||
55 | if ((error = pcre_exec(*r, NULL, string, (int) strlen(string), 0, 0, ovec, (int) nmatches * 3)) < 0) | |
56 | goto out; | |
57 | ||
58 | if (error == 0) | |
59 | error = (int) nmatches; | |
60 | ||
61 | for (i = 0; i < (unsigned int) error; i++) { | |
62 | matches[i].start = (ovec[i * 2] < 0) ? -1 : ovec[i * 2]; | |
63 | matches[i].end = (ovec[i * 2 + 1] < 0) ? -1 : ovec[i * 2 + 1]; | |
64 | } | |
65 | for (i = (unsigned int) error; i < nmatches; i++) | |
66 | matches[i].start = matches[i].end = -1; | |
67 | ||
68 | out: | |
69 | if (nmatches > ARRAY_SIZE(static_ovec) / 3) | |
70 | git__free(ovec); | |
71 | if (error < 0) | |
72 | return (error == PCRE_ERROR_NOMATCH) ? GIT_ENOTFOUND : GIT_EINVALIDSPEC; | |
73 | return 0; | |
74 | } | |
75 | ||
76 | #elif defined(GIT_REGEX_PCRE2) | |
77 | ||
78 | int git_regexp_compile(git_regexp *r, const char *pattern, int flags) | |
79 | { | |
80 | unsigned char errmsg[1024]; | |
81 | PCRE2_SIZE erroff; | |
82 | int error, cflags = 0; | |
83 | ||
84 | if (flags & GIT_REGEXP_ICASE) | |
85 | cflags |= PCRE2_CASELESS; | |
86 | ||
87 | if ((*r = pcre2_compile((const unsigned char *) pattern, PCRE2_ZERO_TERMINATED, | |
88 | cflags, &error, &erroff, NULL)) == NULL) { | |
89 | pcre2_get_error_message(error, errmsg, sizeof(errmsg)); | |
90 | git_error_set_str(GIT_ERROR_REGEX, (char *) errmsg); | |
91 | return GIT_EINVALIDSPEC; | |
92 | } | |
93 | ||
94 | return 0; | |
95 | } | |
96 | ||
97 | void git_regexp_dispose(git_regexp *r) | |
98 | { | |
99 | pcre2_code_free(*r); | |
100 | *r = NULL; | |
101 | } | |
102 | ||
103 | int git_regexp_match(const git_regexp *r, const char *string) | |
104 | { | |
105 | pcre2_match_data *data; | |
106 | int error; | |
107 | ||
108 | data = pcre2_match_data_create(1, NULL); | |
109 | GIT_ERROR_CHECK_ALLOC(data); | |
110 | ||
111 | if ((error = pcre2_match(*r, (const unsigned char *) string, strlen(string), | |
112 | 0, 0, data, NULL)) < 0) | |
113 | return (error == PCRE2_ERROR_NOMATCH) ? GIT_ENOTFOUND : GIT_EINVALIDSPEC; | |
114 | ||
115 | pcre2_match_data_free(data); | |
116 | return 0; | |
117 | } | |
118 | ||
119 | int git_regexp_search(const git_regexp *r, const char *string, size_t nmatches, git_regmatch *matches) | |
120 | { | |
121 | pcre2_match_data *data = NULL; | |
122 | PCRE2_SIZE *ovec; | |
123 | int error; | |
124 | size_t i; | |
125 | ||
126 | if ((data = pcre2_match_data_create(nmatches, NULL)) == NULL) { | |
127 | git_error_set_oom(); | |
128 | goto out; | |
129 | } | |
130 | ||
131 | if ((error = pcre2_match(*r, (const unsigned char *) string, strlen(string), | |
132 | 0, 0, data, NULL)) < 0) | |
133 | goto out; | |
134 | ||
135 | if (error == 0 || (unsigned int) error > nmatches) | |
136 | error = nmatches; | |
137 | ovec = pcre2_get_ovector_pointer(data); | |
138 | ||
139 | for (i = 0; i < (unsigned int) error; i++) { | |
140 | matches[i].start = (ovec[i * 2] == PCRE2_UNSET) ? -1 : (ssize_t) ovec[i * 2]; | |
141 | matches[i].end = (ovec[i * 2 + 1] == PCRE2_UNSET) ? -1 : (ssize_t) ovec[i * 2 + 1]; | |
142 | } | |
143 | for (i = (unsigned int) error; i < nmatches; i++) | |
144 | matches[i].start = matches[i].end = -1; | |
145 | ||
146 | out: | |
147 | pcre2_match_data_free(data); | |
148 | if (error < 0) | |
149 | return (error == PCRE2_ERROR_NOMATCH) ? GIT_ENOTFOUND : GIT_EINVALIDSPEC; | |
150 | return 0; | |
151 | } | |
152 | ||
153 | #elif defined(GIT_REGEX_REGCOMP) || defined(GIT_REGEX_REGCOMP_L) | |
154 | ||
155 | #if defined(GIT_REGEX_REGCOMP_L) | |
156 | # include <xlocale.h> | |
157 | #endif | |
158 | ||
159 | int git_regexp_compile(git_regexp *r, const char *pattern, int flags) | |
160 | { | |
161 | int cflags = REG_EXTENDED, error; | |
162 | char errmsg[1024]; | |
163 | ||
164 | if (flags & GIT_REGEXP_ICASE) | |
165 | cflags |= REG_ICASE; | |
166 | ||
167 | # if defined(GIT_REGEX_REGCOMP) | |
168 | if ((error = regcomp(r, pattern, cflags)) != 0) | |
169 | # else | |
170 | if ((error = regcomp_l(r, pattern, cflags, (locale_t) 0)) != 0) | |
171 | # endif | |
172 | { | |
173 | regerror(error, r, errmsg, sizeof(errmsg)); | |
174 | git_error_set_str(GIT_ERROR_REGEX, errmsg); | |
175 | return GIT_EINVALIDSPEC; | |
176 | } | |
177 | ||
178 | return 0; | |
179 | } | |
180 | ||
181 | void git_regexp_dispose(git_regexp *r) | |
182 | { | |
183 | regfree(r); | |
184 | } | |
185 | ||
186 | int git_regexp_match(const git_regexp *r, const char *string) | |
187 | { | |
188 | int error; | |
189 | if ((error = regexec(r, string, 0, NULL, 0)) != 0) | |
190 | return (error == REG_NOMATCH) ? GIT_ENOTFOUND : GIT_EINVALIDSPEC; | |
191 | return 0; | |
192 | } | |
193 | ||
194 | int git_regexp_search(const git_regexp *r, const char *string, size_t nmatches, git_regmatch *matches) | |
195 | { | |
196 | regmatch_t static_m[3], *m; | |
197 | int error; | |
198 | size_t i; | |
199 | ||
200 | if (nmatches <= ARRAY_SIZE(static_m)) | |
201 | m = static_m; | |
202 | else | |
203 | m = git__calloc(nmatches, sizeof(*m)); | |
204 | ||
205 | if ((error = regexec(r, string, nmatches, m, 0)) != 0) | |
206 | goto out; | |
207 | ||
208 | for (i = 0; i < nmatches; i++) { | |
209 | matches[i].start = (m[i].rm_so < 0) ? -1 : m[i].rm_so; | |
210 | matches[i].end = (m[i].rm_eo < 0) ? -1 : m[i].rm_eo; | |
211 | } | |
212 | ||
213 | out: | |
214 | if (nmatches > ARRAY_SIZE(static_m)) | |
215 | git__free(m); | |
216 | if (error) | |
217 | return (error == REG_NOMATCH) ? GIT_ENOTFOUND : GIT_EINVALIDSPEC; | |
218 | return 0; | |
219 | } | |
220 | ||
221 | #endif |