[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