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
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  <[EMAIL PROTECTED]>
+
+       * 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);

Reply via email to