cis_config
regex_posix.h
1 
2 #ifndef REGEX_POSIX_H_
3 #define REGEX_POSIX_H_
4 
5 #include <regex.h>
6 #include <stdint.h>
7 
8 #ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
9 extern "C" {
10 #endif
11 
20 static inline
21 int compile_regex (regex_t * r, const char * regex_text)
22 {
23  int status = regcomp (r, regex_text, REG_EXTENDED);//|REG_NEWLINE);
24  if (status != 0) {
25  char error_message[2048];
26  regerror (status, r, error_message, 2048);
27  printf ("Regex error compiling '%s': %s\n",
28  regex_text, error_message);
29  return 1;
30  }
31  return 0;
32 };
33 
43 static inline
44 int count_matches(const char *regex_text, const char *to_match) {
45  int ret;
46  int n_match = 0;
47  regex_t r;
48  // Compile
49  ret = compile_regex(&r, regex_text);
50  if (ret)
51  return -1;
52  // Loop until string done
53  const char * p = to_match;
54  const size_t n_sub_matches = 10;
55  regmatch_t m[n_sub_matches];
56  while (1) {
57  int nomatch = regexec(&r, p, n_sub_matches, m, 0);
58  if (nomatch)
59  break;
60  n_match++;
61  p += m[0].rm_eo;
62  }
63  regfree(&r);
64  return n_match;
65 };
66 
67 
79 static inline
80 int find_match(const char *regex_text, const char *to_match,
81  size_t *sind, size_t *eind) {
82  int ret;
83  int n_match = 0;
84  regex_t r;
85  // Compile
86  ret = compile_regex(&r, regex_text);
87  if (ret)
88  return -1;
89  // Loop until string done
90  const char * p = to_match;
91  const size_t n_sub_matches = 10;
92  regmatch_t m[n_sub_matches];
93  int nomatch = regexec(&r, p, n_sub_matches, m, 0);
94  if (!(nomatch)) {
95  *sind = m[0].rm_so;
96  *eind = m[0].rm_eo;
97  n_match++;
98  }
99  regfree(&r);
100  return n_match;
101 };
102 
103 
115 static inline
116 int find_matches(const char *regex_text, const char *to_match,
117  size_t **sind, size_t **eind) {
118  int ret;
119  int n_match = 0;
120  regex_t r;
121  // Compile
122  ret = compile_regex(&r, regex_text);
123  if (ret)
124  return -1;
125  // Loop until string done
126  const size_t n_sub_matches = 50;
127  regmatch_t m[n_sub_matches];
128  int nomatch = regexec(&r, to_match, n_sub_matches, m, 0);
129  if (!(nomatch)) {
130  // Count
131  while (n_match < n_sub_matches) {
132  if ((m[n_match].rm_so == -1) && (m[n_match].rm_eo == -1)) {
133  break;
134  }
135  n_match++;
136  }
137  // Realloc
138  *sind = (size_t*)realloc(*sind, n_match*sizeof(size_t));
139  *eind = (size_t*)realloc(*eind, n_match*sizeof(size_t));
140  // Record
141  int i;
142  for (i = 0; i < n_match; i++) {
143  (*sind)[i] = m[i].rm_so;
144  (*eind)[i] = m[i].rm_eo;
145  }
146  }
147  regfree(&r);
148  return n_match;
149 };
150 
151 
165 static inline
166 int regex_replace_nosub(char *buf, const size_t len_buf,
167  const char *re, const char *rp,
168  const size_t nreplace) {
169  /* printf("regex_replace_nosub(%s, %s, %s)\n", buf, re, rp); */
170  // Compile
171  regex_t r;
172  int ret = compile_regex(&r, re);
173  if (ret)
174  return -1;
175  // Loop making replacements
176  size_t len_rp = strlen(rp);
177  char * p = buf;
178  const size_t ngroups = r.re_nsub + 1;
179  regmatch_t *m = (regmatch_t*)malloc(ngroups * sizeof(regmatch_t));
180  size_t len_m, rem_s, rem_l, delta_siz;
181  size_t cur_pos = 0;
182  size_t cur_siz = strlen(buf);
183  size_t creplace = 0;
184  while (1) {
185  if ((nreplace > 0) && (creplace >= nreplace)) {
186  printf("regex_replace_nosub: Maximum of %d replacements reached\n",
187  (int)creplace);
188  break;
189  }
190  int nomatch = regexec(&r, p, ngroups, m, 0);
191  if (nomatch) {
192  /* printf("regex_replace_nosub: nomatch for %s in %s\n", re, p); */
193  break;
194  }
195  // Ensure replacement will not exceed buffer
196  len_m = m[0].rm_eo - m[0].rm_so;
197  delta_siz = len_rp - len_m;
198  if ((cur_siz + delta_siz + 1) > len_buf) {
199  printf("regex_replace_nosub: Relacement will exceed buffer.\n");
200  cur_siz = -1;
201  break;
202  }
203  // Move trailing
204  rem_l = cur_siz - (cur_pos + m[0].rm_eo);
205  rem_s = m[0].rm_so + len_rp;
206  memmove(p + rem_s, p + m[0].rm_eo, rem_l + 1);
207  // Copy replacement
208  strncpy(p + m[0].rm_so, rp, len_rp);
209  // Advance
210  p += rem_s;
211  cur_pos += rem_s;
212  cur_siz += delta_siz;
213  creplace += 1;
214  }
215  /* printf("regex_replace_nosub() = %s\n", buf); */
216  free(m);
217  regfree(&r);
218  return cur_siz;
219 };
220 
221 
231 static inline
232 int get_subrefs(const char *buf, size_t **refs) {
233  // Compile
234  regex_t r;
235  int ret = compile_regex(&r, "\\$([[:digit:]])");
236  if (ret)
237  return -1;
238  // Allocate;
239  const size_t ngroups = r.re_nsub + 1;
240  if (ngroups != 2) {
241  printf("ERROR: regex could not find subgroup\n");
242  regfree(&r);
243  return -1;
244  }
245  regmatch_t *m = (regmatch_t*)malloc(ngroups * sizeof(regmatch_t));
246  // Prepare "bitmap"
247  const size_t max_ref = 10; //99;
248  size_t i;
249  uint8_t *ref_bytes = (uint8_t*)malloc((max_ref + 1)*sizeof(uint8_t));
250  for (i = 0; i <= max_ref; i++)
251  ref_bytes[i] = 0;
252  // Locate matches
253  const char *p = buf;
254  const size_t max_grp = 2; // Digits in max_ref
255  size_t igrp_len;
256  char igrp[max_grp];
257  size_t iref;
258  while (1) {
259  int nomatch = regexec(&r, p, ngroups, m, 0);
260  if (nomatch) {
261  break;
262  }
263  // Lone $ without digit
264  /* printf("so = %d, eo = %d\n", m[1].rm_so, m[1].rm_eo); */
265  if ((m[1].rm_so == -1) && (m[1].rm_eo == -1)) {
266  p += m[0].rm_eo;
267  continue;
268  }
269  // Substring
270  igrp_len = m[1].rm_eo - m[1].rm_so;
271  if (igrp_len > max_grp) {
272  printf("Number longer than %d digits unlikely.\n", (int)max_grp);
273  free(m);
274  free(ref_bytes);
275  regfree(&r);
276  return -1;
277  }
278  strncpy(igrp, p + m[1].rm_so, igrp_len);
279  igrp[igrp_len] = 0;
280  // Extract ref number
281  iref = atoi(igrp);
282  if (iref > max_ref) {
283  printf("Reference to substr %d exceeds limit (%d)\n",
284  (int)iref, (int)max_ref);
285  free(m);
286  free(ref_bytes);
287  regfree(&r);
288  return -1;
289  }
290  ref_bytes[iref] = 1;
291  p += m[0].rm_eo;
292  }
293  // Get unique refs
294  int nref = 0;
295  for (i = 0; i <= max_ref; i++) {
296  if (ref_bytes[i])
297  nref++;
298  }
299  *refs = (size_t*)realloc(*refs, nref*sizeof(size_t));
300  size_t ir;
301  for (i = 0, ir = 0; i <= max_ref; i++) {
302  if (ref_bytes[i]) {
303  (*refs)[ir] = i;
304  ir++;
305  }
306  }
307  free(m);
308  free(ref_bytes);
309  regfree(&r);
310  // printf("%d refs in %s\n", nref, buf);
311  return nref;
312 };
313 
314 
328 static inline
329 int regex_replace_sub(char *buf, const size_t len_buf,
330  const char *re, const char *rp,
331  const size_t nreplace) {
332  // Compile
333  regex_t r;
334  int ret = compile_regex(&r, re);
335  if (ret)
336  return -1;
337  // Loop making replacements
338  char * p = buf;
339  const size_t ngroups = r.re_nsub + 1;
340  regmatch_t *m = (regmatch_t*)malloc(ngroups * sizeof(regmatch_t));
341  char rp_sub[2*len_buf];
342  char re_sub[len_buf];
343  char igrp[len_buf];
344  size_t len_m, rem_s, rem_l, delta_siz, len_rp;
345  size_t cur_pos = 0;
346  size_t cur_siz = strlen(buf);
347  size_t creplace = 0;
348  size_t i;
349  int j;
350  while (1) {
351  if ((nreplace > 0) && (creplace >= nreplace)) {
352  printf("regex_replace_nosub: Maximum of %d replacements reached\n",
353  (int)creplace);
354  break;
355  }
356  int nomatch = regexec(&r, p, ngroups, m, 0);
357  if (nomatch) {
358  /* printf("regex_replace_sub: nomatch for %s in %s\n", re, p); */
359  break;
360  }
361  // Get list of subrefs
362  size_t *refs = NULL;
363  int nref = get_subrefs(rp, &refs);
364  if (nref < 0) {
365  printf("Error gettings subrefs\n");
366  free(m);
367  regfree(&r);
368  return -1;
369  }
370  // For each subref complete replacements
371  strcpy(rp_sub, rp);
372  for (j = 0; j < nref; j++) {
373  i = refs[j];
374  strcpy(igrp, p + m[i].rm_so);
375  igrp[m[i].rm_eo - m[i].rm_so] = 0; // terminate
376  sprintf(re_sub, "\\$%d", (int)i);
377  ret = regex_replace_nosub(rp_sub, 2*len_buf, re_sub, igrp, 0);
378  if (ret < 0) {
379  printf("regex_replace_sub: Error replacing substring $%d.\n", (int)i);
380  free(m);
381  regfree(&r);
382  return -1;
383  }
384  }
385  // Ensure replacement will not exceed buffer
386  len_rp = ret;
387  len_m = m[0].rm_eo - m[0].rm_so;
388  delta_siz = len_rp - len_m;
389  if ((cur_siz + delta_siz + 1) > len_buf) {
390  printf("regex_replace_sub: Relacement will exceed buffer.\n");
391  free(m);
392  regfree(&r);
393  return -1;
394  }
395  // Move trailing
396  rem_l = cur_siz - (cur_pos + m[0].rm_eo);
397  rem_s = m[0].rm_so + len_rp;
398  memmove(p + rem_s, p + m[0].rm_eo, rem_l + 1);
399  // Copy replacement
400  strncpy(p + m[0].rm_so, rp_sub, len_rp);
401  // Advance
402  p += m[0].rm_so + len_rp;
403  cur_pos += m[0].rm_so + len_rp;
404  cur_siz += delta_siz;
405  creplace += 1;
406  }
407  free(m);
408  regfree(&r);
409  return (int)cur_siz;
410 };
411 
412 #ifdef __cplusplus /* If this is a C++ compiler, end C linkage */
413 }
414 #endif
415 
416 #endif /*REGEX_POSIX_H_*/