man1: Add input.txt
[quvi-tool.git] / src / util / regex.c
bloba4c98f84867bc14c8744bcbeb97d8f5183f9e1d5
1 /* quvi
2 * Copyright (C) 2012 Toni Gundogdu <legatvs@gmail.com>
4 * This file is part of quvi <http://quvi.sourceforge.net/>.
6 * This program is free software: you can redistribute it and/or
7 * modify it under the terms of the GNU Affero General Public
8 * License as published by the Free Software Foundation, either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
16 * You should have received a copy of the GNU Affero General
17 * Public License along with this program. If not, see
18 * <http://www.gnu.org/licenses/>.
22 * Supports Perl-like syntax. Supports the 'i' modifier.
23 * m// - match operation ('m' is optional)
24 * s/// - substitution operation
26 * NOTES:
27 * - Matches/replaces all occurences (similar to 'g' modifier of Perl)
28 * - Similar to Perl-syntax; with the exception of the "property
29 * sequence" -prefix being mandatory (e.g. "%t:s/foo/bar/i")
32 #include "config.h"
34 #include <string.h>
35 #include <glib/gi18n.h>
37 #include "lutil.h"
39 /* Check if the pattern is a s/// operation. */
40 static gboolean _chk_opmode_s(const gchar *p, lutil_regex_op_t *op)
42 static const gchar *op_s = "^(%\\w):s/(.*?)/(.*?)/(.*?)$";
44 GMatchInfo *m;
45 GRegex *re;
46 gboolean r;
47 GError *e;
49 *op = NULL;
50 r = FALSE;
51 m = NULL;
52 e = NULL;
54 re = g_regex_new(op_s, 0, 0, &e);
55 if (e != NULL)
57 g_printerr(_("error: %s: while creating the s/// "
58 "operation mode regex: %s\n"), op_s, e->message);
59 g_error_free(e);
60 return (FALSE);
63 r = g_regex_match(re, p, 0, &m);
64 if (r == TRUE)
66 *op = g_new0(struct _lutil_regex_op_s, 1);
67 (*op)->sequence = g_match_info_fetch(m, 1);
68 (*op)->mode = g_strdup("s");
69 (*op)->regex = g_match_info_fetch(m, 2);
70 (*op)->subst.replacement = g_match_info_fetch(m, 3);
71 (*op)->modifiers = g_match_info_fetch(m, 4);
73 g_match_info_free(m);
74 g_regex_unref(re);
75 return (r);
78 /* Check if the pattern is a m// operation. */
79 static gboolean _chk_opmode_m(const gchar *p, lutil_regex_op_t *op)
81 static const gchar *op_m = "^(%\\w):(.*?)/(.*?)/(.*?)$";
83 GMatchInfo *m;
84 GRegex *re;
85 gboolean r;
86 GError *e;
88 *op = NULL;
89 r = FALSE;
90 m = NULL;
91 e = NULL;
93 re = g_regex_new(op_m, 0, 0, &e);
94 if (e != NULL)
96 g_printerr(_("error: %s: while creating the m// "
97 "operation mode regex: %s\n"), op_m, e->message);
98 g_error_free(e);
99 return (FALSE);
102 r = g_regex_match(re, p, 0, &m);
103 if (r == TRUE)
105 *op = g_new0(struct _lutil_regex_op_s, 1);
106 (*op)->sequence = g_match_info_fetch(m, 1);
107 (*op)->mode = g_match_info_fetch(m, 2);
108 if (strlen((*op)->mode) ==0)
110 g_free((*op)->mode);
111 (*op)->mode = g_strdup("m");
113 (*op)->regex = g_match_info_fetch(m, 3);
114 (*op)->modifiers = g_match_info_fetch(m, 4);
116 g_match_info_free(m);
117 g_regex_unref(re);
118 return (r);
121 #ifdef _1
122 static void _dump(lutil_regex_op_t op)
124 g_message("[%s] op->modifiers=%s", __func__, op->modifiers);
125 g_message("[%s] op->sequence=%s", __func__, op->sequence);
126 g_message("[%s] op->regex=%s", __func__, op->regex);
127 g_message("[%s] op->mode=%s", __func__, op->mode);
128 g_message("[%s] op->subst.replacement=%s", __func__, op->subst.replacement);
130 #endif
132 static const gchar *_EINVSYN =
133 N_("error: %s: invalid syntax: must be either "
134 "m// or s/// operation\n");
136 /* If is_valid is set, then validate the pattern only (and return NULL). */
137 lutil_regex_op_t lutil_regex_op_new(const gchar *p, gboolean *is_valid)
139 lutil_regex_op_t op = NULL;
141 if (is_valid != NULL)
142 *is_valid = FALSE;
144 if (_chk_opmode_s(p, &op) == FALSE)
146 if (_chk_opmode_m(p, &op) == FALSE)
148 g_printerr(g_dgettext(GETTEXT_PACKAGE, _EINVSYN), p);
149 return (NULL);
153 if (g_strcmp0(op->mode,"s") ==0)
155 /* For lack of a better regex, check this the hard way. */
156 if (op->subst.replacement ==NULL)
158 g_printerr(_("error: %s: invalid s/// operation syntax\n"), p);
159 return (NULL);
161 else
163 if (is_valid != NULL)
164 *is_valid = TRUE;
167 else if (g_strcmp0(op->mode, "m") ==0)
169 if (is_valid != NULL)
170 *is_valid = TRUE;
172 else
173 g_printerr(g_dgettext(GETTEXT_PACKAGE, _EINVSYN), p);
175 #ifdef _1
176 _dump(op);
177 #endif
179 if (is_valid != NULL)
181 lutil_regex_op_free(op);
182 op = NULL;
184 return (op);
187 void lutil_regex_op_free(lutil_regex_op_t op)
189 if (op == NULL)
190 return;
192 g_free(op->subst.replacement);
193 g_free(op->modifiers);
194 g_free(op->sequence);
195 g_free(op->regex);
196 g_free(op->mode);
197 g_free(op);
199 memset(op, 0, sizeof(struct _lutil_regex_op_s));
202 static gchar *_op_m(lutil_regex_op_t op, const gchar *s)
204 GRegexCompileFlags flags;
205 GMatchInfo *m;
206 GRegex *re;
207 GError *e;
208 gchar *r;
210 g_assert(op != NULL);
212 flags = (g_strrstr(op->modifiers, "i") != NULL) ? G_REGEX_CASELESS:0;
213 e = NULL;
214 r = NULL;
216 re = g_regex_new(op->regex, flags, 0, &e);
217 if (e != NULL)
219 g_printerr(_("error: %s: while creating m// "
220 "operation mode regex: %s\n"), op->regex, e->message);
221 g_error_free(e);
222 return (NULL);
225 g_regex_match_full(re, s, -1, 0, 0, &m, &e);
226 if (e != NULL)
228 g_printerr(_("error: %s: while matching: %s\n"), op->regex, e->message);
229 g_error_free(e);
231 else
233 GString *t = g_string_new(NULL);
234 while (g_match_info_matches(m) == TRUE)
236 gchar *v = g_match_info_fetch(m, 0);
237 g_string_append(t, v);
238 g_free(v);
239 g_match_info_next(m, &e);
240 if (e != NULL)
242 g_printerr(_("error: while retrieving match info: %s\n"),
243 e->message);
244 g_error_free(e);
245 break;
248 g_match_info_free(m);
249 r = g_strdup(t->str);
250 g_string_free(t, TRUE);
252 g_regex_unref(re);
253 return (r);
256 static gchar *_op_s(lutil_regex_op_t op, const gchar *s)
258 GRegexCompileFlags flags;
259 GRegex *re;
260 GError *e;
261 gchar *r;
263 flags = (g_strrstr(op->modifiers, "i") != NULL) ? G_REGEX_CASELESS:0;
264 e = NULL;
265 r = NULL;
267 re = g_regex_new(op->regex, flags, 0, &e);
268 if (e != NULL)
270 g_printerr(_("error: %s: while creating s/// "
271 "operation mode regex: %s\n"), op->regex, e->message);
272 g_error_free(e);
274 else
276 r = g_regex_replace(re, s, -1, 0, op->subst.replacement, 0, &e);
277 if (e != NULL)
279 g_printerr(_("error: %s: while substituting: %s\n"),
280 op->regex, e->message);
281 g_error_free(e);
284 g_regex_unref(re);
285 return (r);
288 /* g_free the returned string. */
289 gchar *lutil_regex_op_apply(lutil_regex_op_t op, const gchar *s)
291 gchar *r = NULL;
293 g_assert(op != NULL);
294 g_assert(s != NULL);
296 if (g_strcmp0(op->mode,"s") ==0)
297 r = _op_s(op, s);
298 else if (g_strcmp0(op->mode,"m") ==0)
299 r = _op_m(op, s);
301 return (r);
304 /* vim: set ts=2 sw=2 tw=72 expandtab: */