[PATCH] convert C literals in File Find
David Sterba
dave at jikos.cz
Thu Jul 3 00:45:01 UTC 2003
Hi,
I'm sending a patch which adds a checkbox to File Find dialog,
wich determines whether to convert C literals in the content-search
pattern.
I came across some things that should be discussed.
Let's now describe what it does:
- basic "one-letter" escapes: \a \b \e \f \n \r \t
- \ooo - octal number, 0 <= o <= 7, at most 3 digits
- \xHH - hexa number, 0 <= H <= f, a-f, A-F, at most 2 digits
- lets untouched these regex escapes \( \) \[ \] \{ \} \$ \^ \* \.
and now what it does not
- convert double-backslash to single-backslash
if it would then any backslash should be escaped twice,
one for C conversion and once for regex
As regexps are matched on 1 line only, there is no reason to type
"\n" to pattern.
David
-------------- next part --------------
diff -X .diffignore -urNp mc/src/ChangeLog mc-clit/src/ChangeLog
--- mc/src/ChangeLog Thu Jul 3 01:35:21 CEST 2003
+++ mc-clit/src/ChangeLog Thu Jul 3 01:35:21 CEST 2003
@@ -0,0 +1,10 @@
+2003-07-03 David Sterba <dave at jikos.cz>
+
+ * find.c: Add a 'convert C literals' checkbox to Find File dialog.
+ (convert_x_digit): New func.
+ (translate_c_literals): New func. Converts all C escape sequences
+ to chars. Lets escaped regex symbols untouched. See comment for
+ further details.
+ (find_parm_callback): If set, convert literals before regex search.
+ (find_parameters): Add checkbox, lower the buttons.
+
diff -X .diffignore -urNp mc/src/find.c mc-clit/src/find.c
--- mc/src/find.c Wed Apr 16 17:26:29 2003
+++ mc-clit/src/find.c Thu Jul 3 01:28:10 2003
@@ -46,7 +46,7 @@
#include "../vfs/vfs.h"
/* Size of the find parameters window */
-#define FIND_Y 14
+#define FIND_Y 15
static int FIND_X = 50;
/* Size of the find window */
@@ -71,6 +71,7 @@ static WInput *in_start; /* Start path *
static WInput *in_name; /* Pattern to search */
static WInput *in_with; /* Text inside filename */
static WCheck *case_sense; /* "case sensitive" checkbox */
+static WCheck *conv_literals; /* "convert C literals" checkbox */
static int running = 0; /* nice flag */
static char *find_pattern; /* Pattern to search */
@@ -118,6 +119,122 @@ static void get_list_info (char **file,
static regex_t *r; /* Pointer to compiled content_pattern */
static int case_sensitive = 1;
+static int convert_literals = 0;
+
+static int convert_x_digit (const char c);
+
+/* Translates C escape sequences to chars,
+ * result is allocated and should be freed.
+ *
+ * Notes:
+ * - "\\" is *not* translated to "\"
+ * - hexa constant is limited to 2 digits
+ * - octal constant is limited to 3 digits
+ * - the regex escapes go through: ()[]{}$^*.
+ * - "\n" has no sense because regexps are matched only on 1 line
+ */
+static char*
+translate_c_literals (const char *str)
+{
+ char *result, *p;
+ int val;
+
+ /* Translation won't be longer than original */
+ p = result = g_malloc (strlen (str) + 1);
+
+ while (*str) {
+ if (*str != '\\') {
+ *p++ = *str++;
+ continue;
+ }
+
+ str++;
+ if (!*str) {
+ /* Malformed literal */
+ g_free (result);
+ return NULL;
+ }
+
+ /* Ocal number */
+ if ('0' <= *str && *str <= '7') {
+ val = *str++ - '0';
+
+ /* Second digit */
+ if ('0' <= *str && *str <= '7')
+ val = val * 8 + *str++ - '0';
+ else {
+ *p++ = val;
+ continue;
+ }
+
+ /* Last digit */
+ if ('0' <= *str && *str <= '7')
+ val = val * 8 + *str++ - '0';
+
+ *p++ = val;
+ continue;
+ }
+
+ switch (*str) {
+ case 'a': *p++ = '\a'; str++; break;
+ case 'b': *p++ = '\b'; str++; break;
+ case 'e': *p++ = '\e'; str++; break;
+ case 'f': *p++ = '\f'; str++; break;
+ case 'n': *p++ = '\n'; str++; break;
+ case 'r': *p++ = '\r'; str++; break;
+ case 't': *p++ = '\t'; str++; break;
+ case 'x':
+ /* Hexa number */
+ str++;
+ if (!*str || !isxdigit (*str)) {
+ g_free (result);
+ return NULL;
+ }
+
+ val = convert_x_digit (*str++);
+
+ /* Second digit */
+ if (isxdigit (*str))
+ val = val * 16 + convert_x_digit (*str++);
+
+ *p++ = val;
+ break;
+
+ /* Possible regexp */
+ case '(':
+ case ')':
+ case '[':
+ case ']':
+ case '{':
+ case '}':
+ case '*':
+ case '^':
+ case '$':
+ case '\\':
+ case '.': *p++ = '\\'; *p++ = *str++; break;
+
+ /* Invalid */
+ default:
+ g_free (result);
+ return NULL;
+ }
+ }
+ *p = 0;
+
+ return result;
+}
+
+static int
+convert_x_digit (const char c) {
+ if ('0' <= c && c <= '9')
+ return c - '0';
+ if ('a' <= c && c <= 'f')
+ return c - 'a' + 10;
+ if ('A' <= c && c <= 'F')
+ return c - 'A' + 10;
+
+ return 0;
+}
/*
* Callback for the parameter dialog.
@@ -127,6 +244,7 @@ static int
find_parm_callback (struct Dlg_head *h, int id, int Msg)
{
int flags;
+ char *str = NULL;
switch (Msg) {
case DLG_VALIDATE:
@@ -138,11 +256,26 @@ find_parm_callback (struct Dlg_head *h,
if (!(case_sense->state & C_BOOL))
flags |= REG_ICASE;
- if (regcomp (r, in_with->buffer, flags)) {
+ str = in_with->buffer;
+ if (conv_literals->state & C_BOOL) {
+ str = translate_c_literals (in_with->buffer);
+
+ if (!str) {
+ message (1, MSG_ERROR, _(" Malformed C literal "));
+ dlg_select_widget (h, in_with);
+ h->running = 1; /* Don't stop the dialog */
+ return MSG_HANDLED;
+ }
+ }
+
+ if (regcomp (r, str, flags)) {
message (1, MSG_ERROR, _(" Malformed regular expression "));
dlg_select_widget (h, in_with);
h->running = 1; /* Don't stop the dialog */
}
+ if (conv_literals->state & C_BOOL)
+ g_free (str);
+
return MSG_HANDLED;
}
return default_dlg_callback (h, id, Msg);
@@ -167,6 +300,7 @@ find_parameters (char **start_dir, char
int return_value;
char *temp_dir;
static char *case_label = N_("case &Sensitive");
+ static char *conv_label = N_("con&Vert C literals");
static char *in_contents = NULL;
static char *in_start_dir = NULL;
@@ -209,6 +343,7 @@ find_parameters (char **start_dir, char
i18n_flag = 1;
case_label = _(case_label);
+ conv_label = _(conv_label);
}
#endif /* ENABLE_NLS */
@@ -226,15 +361,19 @@ find_parameters (char **start_dir, char
DLG_CENTER);
add_widget (find_dlg,
- button_new (11, b2, B_CANCEL, NORMAL_BUTTON, buts[2], 0, 0,
+ button_new (12, b2, B_CANCEL, NORMAL_BUTTON, buts[2], 0, 0,
"cancel"));
add_widget (find_dlg,
- button_new (11, b1, B_TREE, NORMAL_BUTTON, buts[1], 0, 0,
+ button_new (12, b1, B_TREE, NORMAL_BUTTON, buts[1], 0, 0,
"tree"));
add_widget (find_dlg,
- button_new (11, b0, B_ENTER, DEFPUSH_BUTTON, buts[0], 0, 0,
+ button_new (12, b0, B_ENTER, DEFPUSH_BUTTON, buts[0], 0, 0,
"ok"));
+ conv_literals =
+ check_new (10, 3, convert_literals, conv_label, "find-conv-c-lit");
+ add_widget (find_dlg, conv_literals);
+
case_sense =
check_new (9, 3, case_sensitive, case_label, "find-case-check");
add_widget (find_dlg, case_sense);
@@ -265,6 +404,7 @@ find_parameters (char **start_dir, char
case B_TREE:
temp_dir = g_strdup (in_start->buffer);
case_sensitive = case_sense->state & C_BOOL;
+ convert_literals = conv_literals->state & C_BOOL;
destroy_dlg (find_dlg);
g_free (in_start_dir);
if (strcmp (temp_dir, ".") == 0) {
@@ -291,6 +431,7 @@ find_parameters (char **start_dir, char
}
case_sensitive = case_sense->state & C_BOOL;
+ convert_literals = conv_literals->state & C_BOOL;
return_value = 1;
*start_dir = g_strdup (in_start->buffer);
*pattern = g_strdup (in_name->buffer);
More information about the mc-devel
mailing list