1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 
3 /*  Fluent Bit
4  *  ==========
5  *  Copyright (C) 2019-2021 The Fluent Bit Authors
6  *  Copyright (C) 2015-2018 Treasure Data Inc.
7  *
8  *  Licensed under the Apache License, Version 2.0 (the "License");
9  *  you may not use this file except in compliance with the License.
10  *  You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  *  Unless required by applicable law or agreed to in writing, software
15  *  distributed under the License is distributed on an "AS IS" BASIS,
16  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  *  See the License for the specific language governing permissions and
18  *  limitations under the License.
19  */
20 
21 #include <fluent-bit/flb_info.h>
22 #include <fluent-bit/flb_regex.h>
23 #include <fluent-bit/flb_log.h>
24 #include <fluent-bit/flb_mem.h>
25 
26 #include <string.h>
27 #include <onigmo.h>
28 
29 static int
cb_onig_named(const UChar * name,const UChar * name_end,int ngroup_num,int * group_nums,regex_t * reg,void * data)30 cb_onig_named(const UChar *name, const UChar *name_end,
31               int ngroup_num, int *group_nums,
32               regex_t *reg, void *data)
33 {
34     int i;
35     int gn;
36     struct flb_regex_search *s;
37     OnigRegion *region;
38 
39     s = (struct flb_regex_search *) data;
40     region = s->region;
41 
42     for (i = 0; i < ngroup_num; i++) {
43         gn = group_nums[i];
44         onig_name_to_backref_number(reg, name, name_end, region);
45 
46         if (s->cb_match) {
47             s->cb_match((const char *)name,
48                         s->str + region->beg[gn],
49                         region->end[gn] - region->beg[gn],
50                         s->data);
51         }
52 
53         if (region->end[gn] >= 0) {
54             s->last_pos = region->end[gn];
55         }
56     }
57 
58     return 0;
59 }
60 
str_to_regex(const char * pattern,OnigRegex * reg)61 static int str_to_regex(const char *pattern, OnigRegex *reg)
62 {
63     int ret;
64     int len;
65     const char *start;
66     const char *end;
67     OnigErrorInfo einfo;
68 
69     len = strlen(pattern);
70     start = pattern;
71     end = pattern + len;
72 
73     if (pattern[0] == '/' && pattern[len - 1] == '/') {
74         start++;
75         end--;
76     }
77 
78     ret = onig_new(reg,
79                    (const unsigned char *)start, (const unsigned char *)end,
80                    ONIG_OPTION_DEFAULT,
81                    ONIG_ENCODING_UTF8, ONIG_SYNTAX_RUBY, &einfo);
82 
83     if (ret != ONIG_NORMAL) {
84         return -1;
85     }
86     return 0;
87 }
88 
89 /* Initialize backend library */
flb_regex_init()90 int flb_regex_init()
91 {
92     return onig_init();
93 }
94 
flb_regex_create(const char * pattern)95 struct flb_regex *flb_regex_create(const char *pattern)
96 {
97     int ret;
98     struct flb_regex *r;
99 
100     /* Create context */
101     r = flb_malloc(sizeof(struct flb_regex));
102     if (!r) {
103         flb_errno();
104         return NULL;
105     }
106 
107     /* Compile pattern */
108     ret = str_to_regex(pattern, (OnigRegex *) &r->regex);
109     if (ret == -1) {
110         flb_free(r);
111         return NULL;
112     }
113 
114     return r;
115 }
116 
flb_regex_do(struct flb_regex * r,const char * str,size_t slen,struct flb_regex_search * result)117 ssize_t flb_regex_do(struct flb_regex *r, const char *str, size_t slen,
118                      struct flb_regex_search *result)
119 {
120     int ret;
121     const char *start;
122     const char *end;
123     const char *range;
124     OnigRegion *region;
125 
126     region = onig_region_new();
127     if (!region) {
128         result->region = NULL;
129         return -1;
130     }
131 
132     /* Search scope */
133     start = str;
134     end   = start + slen;
135     range = end;
136 
137     ret = onig_search(r->regex,
138                       (const unsigned char *)str,
139                       (const unsigned char *)end,
140                       (const unsigned char *)start,
141                       (const unsigned char *)range,
142                       region, ONIG_OPTION_NONE);
143     if (ret == ONIG_MISMATCH) {
144         result->region = NULL;
145         onig_region_free(region, 1);
146         return -1;
147     }
148     else if (ret < 0) {
149         result->region = NULL;
150         onig_region_free(region, 1);
151         return -1;
152     }
153 
154     result->region   = region;
155     result->str      = str;
156 
157     ret = region->num_regs - 1;
158 
159     if (ret == 0) {
160         result->region = NULL;
161         onig_region_free(region, 1);
162     }
163 
164     return ret;
165 }
166 
flb_regex_results_get(struct flb_regex_search * result,int i,ptrdiff_t * start,ptrdiff_t * end)167 int flb_regex_results_get(struct flb_regex_search *result, int i,
168                           ptrdiff_t *start, ptrdiff_t *end)
169 {
170     OnigRegion *region;
171 
172     region = (OnigRegion *) result->region;
173     if (!region) {
174         return -1;
175     }
176 
177     if (i >= region->num_regs) {
178         return -1;
179     }
180 
181     *start = region->beg[i];
182     *end = region->end[i];
183 
184     return 0;
185 }
186 
flb_regex_results_release(struct flb_regex_search * result)187 void flb_regex_results_release(struct flb_regex_search *result)
188 {
189     onig_region_free(result->region, 1);
190 }
191 
flb_regex_results_size(struct flb_regex_search * result)192 int flb_regex_results_size(struct flb_regex_search *result)
193 {
194     OnigRegion *region;
195 
196     region = (OnigRegion *) result->region;
197     if (!region) {
198         return -1;
199     }
200 
201     return region->num_regs;
202 }
203 
flb_regex_match(struct flb_regex * r,unsigned char * str,size_t slen)204 int flb_regex_match(struct flb_regex *r, unsigned char *str, size_t slen)
205 {
206     int ret;
207     unsigned char *start;
208     unsigned char *end;
209     unsigned char *range;
210 
211     /* Search scope */
212     start = (unsigned char *) str;
213     end   = start + slen;
214     range = end;
215 
216     ret = onig_search(r->regex, str, end, start, range, NULL, ONIG_OPTION_NONE);
217 
218     if (ret == ONIG_MISMATCH) {
219         return 0;
220     }
221     else if (ret < 0) {
222         return ret;
223     }
224     return 1;
225 }
226 
227 
flb_regex_parse(struct flb_regex * r,struct flb_regex_search * result,void (* cb_match)(const char *,const char *,size_t,void *),void * data)228 int flb_regex_parse(struct flb_regex *r, struct flb_regex_search *result,
229                     void (*cb_match) (const char *,          /* name  */
230                                       const char *, size_t,  /* value */
231                                       void *),                  /* caller data */
232                     void *data)
233 {
234     int ret;
235 
236     result->data = data;
237     result->cb_match = cb_match;
238     result->last_pos = -1;
239 
240     ret = onig_foreach_name(r->regex, cb_onig_named, result);
241     onig_region_free(result->region, 1);
242 
243     if (ret == 0) {
244         return result->last_pos;
245     }
246     return -1;
247 }
248 
flb_regex_destroy(struct flb_regex * r)249 int flb_regex_destroy(struct flb_regex *r)
250 {
251     onig_free(r->regex);
252     flb_free(r);
253     return 0;
254 }
255 
flb_regex_exit()256 void flb_regex_exit()
257 {
258     onig_end();
259 }
260