Coverage Report

Created: 2026-10-17 07:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rtpproxy/external/libre/src/fmt/regex.c
Line
Count
Source
1
/**
2
 * @file regex.c Implements basic regular expressions
3
 *
4
 * Copyright (C) 2010 Creytiv.com
5
 */
6
#include <ctype.h>
7
#include <re_types.h>
8
#include <re_fmt.h>
9
10
11
/** Defines a character range */
12
struct chr {
13
  uint8_t min;  /**< Minimum value */
14
  uint8_t max;  /**< Maximum value */
15
};
16
17
18
static bool expr_match(const struct chr *chrv, uint32_t n, uint8_t c,
19
           bool neg)
20
0
{
21
0
  uint32_t i;
22
23
0
  for (i=0; i<n; i++) {
24
25
0
    if (c < chrv[i].min)
26
0
      continue;
27
28
0
    if (c > chrv[i].max)
29
0
      continue;
30
31
0
    break;
32
0
  }
33
34
0
  return neg ? (i == n) : (i != n);
35
0
}
36
37
38
/**
39
 * Parse a string using basic regular expressions. Any number of matching
40
 * expressions can be given, and each match will be stored in a "struct pl"
41
 * pointer-length type.
42
 *
43
 * @param ptr  String to parse
44
 * @param len  Length of string
45
 * @param expr Regular expressions string
46
 *
47
 * @return 0 if success, otherwise errorcode
48
 *
49
 * Example:
50
 *
51
 *   We parse the buffer for any numerical values, to get a match we must have
52
 *   1 or more occurences of the digits 0-9. The result is stored in 'num',
53
 *   which is of pointer-length type and will point to the first location in
54
 *   the buffer that contains "42".
55
 *
56
 * <pre>
57
 const char buf[] = "foo 42 bar";
58
 struct pl num;
59
 int err = re_regex(buf, strlen(buf), "[0-9]+", &num);
60
61
 here num contains a pointer to '42'
62
 * </pre>
63
 */
64
int re_regex(const char *ptr, size_t len, const char *expr, ...)
65
0
{
66
0
  struct chr chrv[64];
67
0
  const char *p, *ep;
68
0
  bool fm, range = false, ec = false, neg = false, qesc = false;
69
0
  uint32_t n = 0;
70
0
  va_list ap;
71
0
  bool eesc;
72
0
  size_t l;
73
74
0
  if (!ptr || !expr)
75
0
    return EINVAL;
76
77
0
 again:
78
0
  eesc = false;
79
0
  fm = false;
80
0
  l  = len--;
81
0
  p  = ptr++;
82
0
  ep = expr;
83
84
0
  va_start(ap, expr);
85
86
0
  if (!l)
87
0
    goto out;
88
89
0
  for (; *ep; ep++) {
90
91
0
    if ('\\' == *ep && !eesc) {
92
0
      eesc = true;
93
0
      continue;
94
0
    }
95
96
0
    if (!fm) {
97
98
      /* Start of character class */
99
0
      if ('[' == *ep && !eesc) {
100
0
        n     = 0;
101
0
        fm    = true;
102
0
        ec    = false;
103
0
        neg   = false;
104
0
        range = false;
105
0
        qesc  = false;
106
0
        continue;
107
0
      }
108
109
0
      if (!l)
110
0
        break;
111
112
0
      if (tolower(*ep) != tolower(*p)) {
113
0
        va_end(ap);
114
0
        goto again;
115
0
      }
116
117
0
      eesc = false;
118
0
      ++p;
119
0
      --l;
120
0
      continue;
121
0
    }
122
    /* End of character class */
123
0
    else if (ec) {
124
125
0
      uint32_t nm, nmin, nmax;
126
0
      struct pl lpl, *pl = va_arg(ap, struct pl *);
127
0
      bool quote = false, esc = false;
128
129
      /* Match 0 or more times */
130
0
      if ('*' == *ep) {
131
0
        nmin = 0;
132
0
        nmax = -1;
133
0
      }
134
      /* Match 1 or more times */
135
0
      else if ('+' == *ep) {
136
0
        nmin = 1;
137
0
        nmax = -1;
138
0
      }
139
      /* Match exactly n times */
140
0
      else if ('1' <= *ep && *ep <= '9') {
141
0
        nmin = *ep - '0';
142
0
        nmax = *ep - '0';
143
0
      }
144
0
      else
145
0
        break;
146
147
0
      fm = false;
148
149
0
      lpl.p = p;
150
0
      lpl.l = 0;
151
152
0
      for (nm = 0; l && nm < nmax; nm++, p++, l--, lpl.l++) {
153
154
0
        if (qesc) {
155
156
0
          if (esc) {
157
0
            esc = false;
158
0
            continue;
159
0
          }
160
161
0
          switch (*p) {
162
163
0
          case '\\':
164
0
            esc = true;
165
0
            continue;
166
167
0
          case '"':
168
0
            quote = !quote;
169
0
            continue;
170
0
          }
171
172
0
          if (quote)
173
0
            continue;
174
0
        }
175
176
0
        if (!expr_match(chrv, n, tolower(*p), neg))
177
0
          break;
178
0
      }
179
180
      /* Strip quotes */
181
0
      if (qesc && lpl.l > 1 &&
182
0
          lpl.p[0] == '"' && lpl.p[lpl.l - 1] == '"') {
183
184
0
        lpl.p += 1;
185
0
        lpl.l -= 2;
186
0
        nm    -= 2;
187
0
      }
188
189
0
      if ((nm < nmin) || (nm > nmax)) {
190
0
        va_end(ap);
191
0
        goto again;
192
0
      }
193
194
0
      if (pl)
195
0
        *pl = lpl;
196
197
0
      eesc = false;
198
0
      continue;
199
0
    }
200
201
0
    if (eesc) {
202
0
      eesc = false;
203
0
      goto chr;
204
0
    }
205
206
0
    switch (*ep) {
207
208
      /* End of character class */
209
0
    case ']':
210
0
      ec = true;
211
0
      continue;
212
213
      /* Negate with quote escape */
214
0
    case '~':
215
0
      if (n)
216
0
        break;
217
218
0
      qesc = true;
219
0
      neg  = true;
220
0
      continue;
221
222
      /* Negate */
223
0
    case '^':
224
0
      if (n)
225
0
        break;
226
227
0
      neg = true;
228
0
      continue;
229
230
      /* Range */
231
0
    case '-':
232
0
      if (!n || range)
233
0
        break;
234
235
0
      range = true;
236
0
      --n;
237
0
      continue;
238
0
    }
239
240
0
  chr:
241
0
    if (n >= ARRAY_SIZE(chrv))
242
0
      break;
243
244
0
    chrv[n].max = tolower(*ep);
245
246
0
    if (range)
247
0
      range = false;
248
0
    else
249
0
      chrv[n].min = tolower(*ep);
250
251
0
    ++n;
252
0
  }
253
0
 out:
254
0
  va_end(ap);
255
256
0
  if (fm)
257
0
    return EINVAL;
258
259
0
  return *ep ? ENOENT : 0;
260
0
}