Coverage Report

Created: 2025-12-14 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libgit2/src/util/regexp.c
Line
Count
Source
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
0
{
14
0
  int erroffset, cflags = 0;
15
0
  const char *error = NULL;
16
17
0
  if (flags & GIT_REGEXP_ICASE)
18
0
    cflags |= PCRE_CASELESS;
19
20
0
  if ((*r = pcre_compile(pattern, cflags, &error, &erroffset, NULL)) == NULL) {
21
0
    git_error_set_str(GIT_ERROR_REGEX, error);
22
0
    return GIT_EINVALIDSPEC;
23
0
  }
24
25
0
  return 0;
26
0
}
27
28
void git_regexp_dispose(git_regexp *r)
29
0
{
30
0
  pcre_free(*r);
31
0
  *r = NULL;
32
0
}
33
34
int git_regexp_match(const git_regexp *r, const char *string)
35
0
{
36
0
  int error;
37
0
  if ((error = pcre_exec(*r, NULL, string, (int) strlen(string), 0, 0, NULL, 0)) < 0)
38
0
    return (error == PCRE_ERROR_NOMATCH) ? GIT_ENOTFOUND : GIT_EINVALIDSPEC;
39
0
  return 0;
40
0
}
41
42
int git_regexp_search(const git_regexp *r, const char *string, size_t nmatches, git_regmatch *matches)
43
0
{
44
0
  int static_ovec[9] = {0}, *ovec;
45
0
  int error;
46
0
  size_t i;
47
48
  /* The ovec array always needs to be a multiple of three */
49
0
  if (nmatches <= ARRAY_SIZE(static_ovec) / 3)
50
0
    ovec = static_ovec;
51
0
  else
52
0
    ovec = git__calloc(nmatches * 3, sizeof(*ovec));
53
0
  GIT_ERROR_CHECK_ALLOC(ovec);
54
55
0
  if ((error = pcre_exec(*r, NULL, string, (int) strlen(string), 0, 0, ovec, (int) nmatches * 3)) < 0)
56
0
    goto out;
57
58
0
  if (error == 0)
59
0
    error = (int) nmatches;
60
61
0
  for (i = 0; i < (unsigned int) error; i++) {
62
0
    matches[i].start = (ovec[i * 2] < 0) ? -1 : ovec[i * 2];
63
0
    matches[i].end = (ovec[i * 2 + 1] < 0) ? -1 : ovec[i * 2 + 1];
64
0
  }
65
0
  for (i = (unsigned int) error; i < nmatches; i++)
66
0
    matches[i].start = matches[i].end = -1;
67
68
0
out:
69
0
  if (nmatches > ARRAY_SIZE(static_ovec) / 3)
70
0
    git__free(ovec);
71
0
  if (error < 0)
72
0
    return (error == PCRE_ERROR_NOMATCH) ? GIT_ENOTFOUND : GIT_EINVALIDSPEC;
73
0
  return 0;
74
0
}
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
  error = pcre2_match(*r, (const unsigned char *) string, strlen(string), 0, 0, data, NULL);
112
  pcre2_match_data_free(data);
113
  if (error < 0)
114
    return (error == PCRE2_ERROR_NOMATCH) ? GIT_ENOTFOUND : GIT_EINVALIDSPEC;
115
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
    return -1;
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