Branch data Line data Source code
1 : : /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
2 : : /*
3 : : * SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
4 : : * SPDX-FileCopyrightText: 2023 Philip Chimento <philip.chimento@gmail.com>
5 : : */
6 : :
7 : : #include <config.h>
8 : :
9 : : #include <stdbool.h>
10 : : #include <stddef.h> /* for NULL */
11 : : #include <stdint.h>
12 : : #include <sys/types.h> /* for ssize_t */
13 : :
14 : : #include <glib-object.h>
15 : : #include <glib.h>
16 : :
17 : : #include "libgjs-private/gjs-match-info.h"
18 : :
19 [ + + + - : 60 : G_DEFINE_BOXED_TYPE(GjsMatchInfo, gjs_match_info, gjs_match_info_ref,
+ + ]
20 : : gjs_match_info_unref)
21 : :
22 : : struct _GjsMatchInfo {
23 : : gatomicrefcount refcount;
24 : : GMatchInfo* base; /* owned */
25 : : char* str;
26 : : };
27 : :
28 : : /* Takes ownership of string */
29 : 17 : static GjsMatchInfo* new_match_info(GMatchInfo* base, char* s) {
30 : 17 : GjsMatchInfo* retval = g_new0(GjsMatchInfo, 1);
31 : 17 : g_atomic_ref_count_init(&retval->refcount);
32 : 17 : retval->base = base;
33 : 17 : retval->str = s;
34 : 17 : return retval;
35 : : }
36 : :
37 : : /**
38 : : * gjs_match_info_get_regex:
39 : : * @self: a #GjsMatchInfo
40 : : *
41 : : * Wrapper for g_match_info_get_regex().
42 : : *
43 : : * Returns: (transfer none): #GRegex object
44 : : */
45 : 0 : GRegex* gjs_match_info_get_regex(const GjsMatchInfo* self) {
46 : 0 : g_return_val_if_fail(self != NULL, NULL);
47 : 0 : return g_match_info_get_regex(self->base);
48 : : }
49 : :
50 : : /**
51 : : * gjs_match_info_get_string:
52 : : * @self: a #GjsMatchInfo
53 : : *
54 : : * Replacement for g_match_info_get_string(), but the string is owned by @self.
55 : : *
56 : : * Returns: (transfer none): the string searched with @match_info
57 : : */
58 : 4 : const char* gjs_match_info_get_string(const GjsMatchInfo* self) {
59 : 4 : g_return_val_if_fail(self != NULL, NULL);
60 : 4 : return self->str;
61 : : }
62 : :
63 : : /**
64 : : * gjs_match_info_ref:
65 : : * @self: a #GjsMatchInfo
66 : : *
67 : : * Replacement for g_match_info_ref().
68 : : *
69 : : * Returns: @self
70 : : */
71 : 17 : GjsMatchInfo* gjs_match_info_ref(GjsMatchInfo* self) {
72 : 17 : g_return_val_if_fail(self != NULL, NULL);
73 : 17 : g_atomic_ref_count_inc(&self->refcount);
74 : 17 : return self;
75 : : }
76 : :
77 : : /**
78 : : * gjs_match_info_unref:
79 : : * @self: a #GjsMatchInfo
80 : : *
81 : : * Replacement for g_match_info_unref().
82 : : */
83 : 34 : void gjs_match_info_unref(GjsMatchInfo* self) {
84 : 34 : g_return_if_fail(self != NULL);
85 [ + + ]: 34 : if (g_atomic_ref_count_dec(&self->refcount)) {
86 : 17 : g_match_info_unref(self->base);
87 : 17 : g_free(self->str);
88 : 17 : g_free(self);
89 : : }
90 : : }
91 : :
92 : : /**
93 : : * gjs_match_info_free:
94 : : * @self: (nullable): a #GjsMatchInfo, or %NULL
95 : : *
96 : : * Replacement for g_match_info_free().
97 : : */
98 : 0 : void gjs_match_info_free(GjsMatchInfo* self) {
99 : 0 : g_return_if_fail(self != NULL);
100 [ # # ]: 0 : if (self == NULL)
101 : 0 : return;
102 : :
103 : 0 : gjs_match_info_unref(self);
104 : : }
105 : :
106 : : /**
107 : : * gjs_match_info_next:
108 : : * @self: a #GjsMatchInfo
109 : : * @error: location to store the error occurring, or %NULL to ignore errors
110 : : *
111 : : * Wrapper for g_match_info_next().
112 : : *
113 : : * Returns: %TRUE or %FALSE
114 : : */
115 : 2 : gboolean gjs_match_info_next(GjsMatchInfo* self, GError** error) {
116 : 2 : g_return_val_if_fail(self != NULL, FALSE);
117 : 2 : return g_match_info_next(self->base, error);
118 : : }
119 : :
120 : : /**
121 : : * gjs_match_info_matches:
122 : : * @self: a #GjsMatchInfo
123 : : *
124 : : * Wrapper for g_match_info_matches().
125 : : *
126 : : * Returns: %TRUE or %FALSE
127 : : */
128 : 2 : gboolean gjs_match_info_matches(const GjsMatchInfo* self) {
129 : 2 : g_return_val_if_fail(self != NULL, FALSE);
130 : 2 : return g_match_info_matches(self->base);
131 : : }
132 : :
133 : : /**
134 : : * gjs_match_info_get_match_count:
135 : : * @self: a #GjsMatchInfo
136 : : *
137 : : * Wrapper for g_match_info_get_match_count().
138 : : *
139 : : * Returns: Number of matched substrings, or -1 if an error occurred
140 : : */
141 : 2 : int gjs_match_info_get_match_count(const GjsMatchInfo* self) {
142 : 2 : g_return_val_if_fail(self != NULL, -1);
143 : 2 : return g_match_info_get_match_count(self->base);
144 : : }
145 : :
146 : : /**
147 : : * gjs_match_info_is_partial_match:
148 : : * @self: a #GjsMatchInfo
149 : : *
150 : : * Wrapper for g_match_info_is_partial_match().
151 : : *
152 : : * Returns: %TRUE or %FALSE
153 : : */
154 : 2 : gboolean gjs_match_info_is_partial_match(const GjsMatchInfo* self) {
155 : 2 : g_return_val_if_fail(self != NULL, FALSE);
156 : 2 : return g_match_info_is_partial_match(self->base);
157 : : }
158 : :
159 : : /**
160 : : * gjs_match_info_expand_references:
161 : : * @self: (nullable): a #GjsMatchInfo or %NULL
162 : : * @string_to_expand: the string to expand
163 : : * @error: location to store the error occurring, or %NULL to ignore errors
164 : : *
165 : : * Wrapper for g_match_info_expand_references().
166 : : *
167 : : * Returns: (nullable): the expanded string, or %NULL if an error occurred
168 : : */
169 : 2 : char* gjs_match_info_expand_references(const GjsMatchInfo* self,
170 : : const char* string_to_expand,
171 : : GError** error) {
172 : 2 : return g_match_info_expand_references(self->base, string_to_expand, error);
173 : : }
174 : :
175 : : /**
176 : : * gjs_match_info_fetch:
177 : : * @self: a #GjsMatchInfo
178 : : * @match_num: number of the sub expression
179 : : *
180 : : * Wrapper for g_match_info_fetch().
181 : : *
182 : : * Returns: (nullable): The matched substring, or %NULL if an error occurred.
183 : : */
184 : 2 : char* gjs_match_info_fetch(const GjsMatchInfo* self, int match_num) {
185 : 2 : g_return_val_if_fail(self != NULL, NULL);
186 : 2 : return g_match_info_fetch(self->base, match_num);
187 : : }
188 : :
189 : : /**
190 : : * gjs_match_info_fetch_pos:
191 : : * @self: a #GMatchInfo
192 : : * @match_num: number of the sub expression
193 : : * @start_pos: (out) (optional): pointer to location for the start position
194 : : * @end_pos: (out) (optional): pointer to location for the end position
195 : : *
196 : : * Wrapper for g_match_info_fetch_pos().
197 : : *
198 : : * Returns: %TRUE or %FALSE
199 : : */
200 : 2 : gboolean gjs_match_info_fetch_pos(const GjsMatchInfo* self, int match_num,
201 : : int* start_pos, int* end_pos) {
202 : 2 : g_return_val_if_fail(self != NULL, FALSE);
203 : 2 : return g_match_info_fetch_pos(self->base, match_num, start_pos, end_pos);
204 : : }
205 : :
206 : : /**
207 : : * gjs_match_info_fetch_named:
208 : : * @self: a #GjsMatchInfo
209 : : * @name: name of the subexpression
210 : : *
211 : : * Wrapper for g_match_info_fetch_named().
212 : : *
213 : : * Returns: (nullable): The matched substring, or %NULL if an error occurred.
214 : : */
215 : 2 : char* gjs_match_info_fetch_named(const GjsMatchInfo* self, const char* name) {
216 : 2 : g_return_val_if_fail(self != NULL, NULL);
217 : 2 : return g_match_info_fetch_named(self->base, name);
218 : : }
219 : :
220 : : /**
221 : : * gjs_match_info_fetch_named_pos:
222 : : * @self: a #GMatchInfo
223 : : * @name: name of the subexpression
224 : : * @start_pos: (out) (optional): pointer to location for the start position
225 : : * @end_pos: (out) (optional): pointer to location for the end position
226 : : *
227 : : * Wrapper for g_match_info_fetch_named_pos().
228 : : *
229 : : * Returns: %TRUE or %FALSE
230 : : */
231 : 2 : gboolean gjs_match_info_fetch_named_pos(const GjsMatchInfo* self,
232 : : const char* name, int* start_pos,
233 : : int* end_pos) {
234 : 2 : g_return_val_if_fail(self != NULL, FALSE);
235 : 2 : return g_match_info_fetch_named_pos(self->base, name, start_pos, end_pos);
236 : : }
237 : :
238 : : /**
239 : : * gjs_match_info_fetch_all:
240 : : * @self: a #GMatchInfo
241 : : *
242 : : * Wrapper for g_match_info_fetch_all().
243 : : *
244 : : * Returns: (transfer full): a %NULL-terminated array of strings. If the
245 : : * previous match failed %NULL is returned
246 : : */
247 : 2 : char** gjs_match_info_fetch_all(const GjsMatchInfo* self) {
248 : 2 : g_return_val_if_fail(self != NULL, NULL);
249 : 2 : return g_match_info_fetch_all(self->base);
250 : : }
251 : :
252 : : /**
253 : : * gjs_regex_match:
254 : : * @regex: a #GRegex
255 : : * @s: the string to scan for matches
256 : : * @match_options: match options
257 : : * @match_info: (out) (optional): pointer to location for the #GjsMatchInfo
258 : : *
259 : : * Wrapper for g_regex_match() that doesn't require the string to be kept alive.
260 : : *
261 : : * Returns: %TRUE or %FALSE
262 : : */
263 : 13 : gboolean gjs_regex_match(const GRegex* regex, const char* s,
264 : : GRegexMatchFlags match_options,
265 : : GjsMatchInfo** match_info) {
266 : 13 : return gjs_regex_match_full(regex, (const uint8_t*)s, -1, 0, match_options,
267 : : match_info, NULL);
268 : : }
269 : :
270 : : /**
271 : : * gjs_regex_match_full:
272 : : * @regex: a #GRegex
273 : : * @bytes: (array length=len): the string to scan for matches
274 : : * @len: the length of @bytes
275 : : * @start_position: starting index of the string to match, in bytes
276 : : * @match_options: match options
277 : : * @match_info: (out) (optional): pointer to location for the #GjsMatchInfo
278 : : * @error: location to store the error occurring, or %NULL to ignore errors
279 : : *
280 : : * Wrapper for g_regex_match_full() that doesn't require the string to be kept
281 : : * alive.
282 : : *
283 : : * Returns: %TRUE or %FALSE
284 : : */
285 : 15 : gboolean gjs_regex_match_full(const GRegex* regex, const uint8_t* bytes,
286 : : ssize_t len, int start_position,
287 : : GRegexMatchFlags match_options,
288 : : GjsMatchInfo** match_info, GError** error) {
289 : 15 : const char* s = (const char*)bytes;
290 [ - + ]: 15 : if (match_info == NULL)
291 : 0 : return g_regex_match_full(regex, s, len, start_position, match_options,
292 : : NULL, error);
293 : :
294 [ + + ]: 28 : char* string_copy = len < 0 ? g_strdup(s) : g_strndup(s, len);
295 : 15 : GMatchInfo* base = NULL;
296 : 15 : bool retval = g_regex_match_full(regex, string_copy, len, start_position,
297 : : match_options, &base, error);
298 : :
299 [ + - ]: 15 : if (base)
300 : 15 : *match_info = new_match_info(base, string_copy);
301 : :
302 : 15 : return retval;
303 : : }
304 : :
305 : : /**
306 : : * gjs_regex_match_all:
307 : : * @regex: a #GRegex
308 : : * @s: the string to scan for matches
309 : : * @match_options: match options
310 : : * @match_info: (out) (optional): pointer to location for the #GjsMatchInfo
311 : : *
312 : : * Wrapper for g_regex_match_all() that doesn't require the string to be kept
313 : : * alive.
314 : : *
315 : : * Returns: %TRUE or %FALSE
316 : : */
317 : 1 : gboolean gjs_regex_match_all(const GRegex* regex, const char* s,
318 : : GRegexMatchFlags match_options,
319 : : GjsMatchInfo** match_info) {
320 : 1 : return gjs_regex_match_all_full(regex, (const uint8_t*)s, -1, 0,
321 : : match_options, match_info, NULL);
322 : : }
323 : :
324 : : /**
325 : : * gjs_regex_match_all_full:
326 : : * @regex: a #GRegex
327 : : * @bytes: (array length=len): the string to scan for matches
328 : : * @len: the length of @bytes
329 : : * @start_position: starting index of the string to match, in bytes
330 : : * @match_options: match options
331 : : * @match_info: (out) (optional): pointer to location for the #GMatchInfo
332 : : * @error: location to store the error occurring, or %NULL to ignore errors
333 : : *
334 : : * Wrapper for g_regex_match_all_full() that doesn't require the string to be
335 : : * kept alive.
336 : : *
337 : : * Returns: %TRUE or %FALSE
338 : : */
339 : 2 : gboolean gjs_regex_match_all_full(const GRegex* regex, const uint8_t* bytes,
340 : : ssize_t len, int start_position,
341 : : GRegexMatchFlags match_options,
342 : : GjsMatchInfo** match_info, GError** error) {
343 : 2 : const char* s = (const char*)bytes;
344 [ - + ]: 2 : if (match_info == NULL)
345 : 0 : return g_regex_match_all_full(regex, s, len, start_position,
346 : : match_options, NULL, error);
347 : :
348 [ + + ]: 3 : char* string_copy = len < 0 ? g_strdup(s) : g_strndup(s, len);
349 : 2 : GMatchInfo* base = NULL;
350 : 2 : bool retval = g_regex_match_all_full(
351 : : regex, string_copy, len, start_position, match_options, &base, error);
352 : :
353 [ + - ]: 2 : if (base)
354 : 2 : *match_info = new_match_info(base, string_copy);
355 : :
356 : 2 : return retval;
357 : : }
|