ambrop7 15 лет назад
Родитель
Сommit
309bc57291

+ 1 - 0
blog_channels.txt

@@ -12,6 +12,7 @@ ncd_concatv 4
 ncd_concatlist 4
 ncd_if 4
 ncd_strcmp 4
+ncd_regex_match 4
 ncd_logical 4
 ncd_sleep 4
 ncd_print 4

+ 4 - 0
generated/blog_channel_ncd_regex_match.h

@@ -0,0 +1,4 @@
+#ifdef BLOG_CURRENT_CHANNEL
+#undef BLOG_CURRENT_CHANNEL
+#endif
+#define BLOG_CURRENT_CHANNEL BLOG_CHANNEL_ncd_regex_match

+ 49 - 48
generated/blog_channels_defines.h

@@ -12,51 +12,52 @@
 #define BLOG_CHANNEL_ncd_concatlist 11
 #define BLOG_CHANNEL_ncd_if 12
 #define BLOG_CHANNEL_ncd_strcmp 13
-#define BLOG_CHANNEL_ncd_logical 14
-#define BLOG_CHANNEL_ncd_sleep 15
-#define BLOG_CHANNEL_ncd_print 16
-#define BLOG_CHANNEL_ncd_blocker 17
-#define BLOG_CHANNEL_ncd_ip_in_network 18
-#define BLOG_CHANNEL_ncd_run 19
-#define BLOG_CHANNEL_ncd_synchronous_process 20
-#define BLOG_CHANNEL_ncd_process_manager 21
-#define BLOG_CHANNEL_ncd_net_backend_waitdevice 22
-#define BLOG_CHANNEL_ncd_net_backend_waitlink 23
-#define BLOG_CHANNEL_ncd_net_backend_badvpn 24
-#define BLOG_CHANNEL_ncd_net_backend_wpa_supplicant 25
-#define BLOG_CHANNEL_ncd_net_backend_rfkill 26
-#define BLOG_CHANNEL_ncd_net_up 27
-#define BLOG_CHANNEL_ncd_net_dns 28
-#define BLOG_CHANNEL_ncd_net_iptables 29
-#define BLOG_CHANNEL_ncd_net_ipv4_addr 30
-#define BLOG_CHANNEL_ncd_net_ipv4_dhcp 31
-#define BLOG_CHANNEL_ncd_net_ipv4_route 32
-#define BLOG_CHANNEL_ncd_sys_evdev 33
-#define BLOG_CHANNEL_StreamPeerIO 34
-#define BLOG_CHANNEL_DatagramPeerIO 35
-#define BLOG_CHANNEL_BReactor 36
-#define BLOG_CHANNEL_BSignal 37
-#define BLOG_CHANNEL_FragmentProtoAssembler 38
-#define BLOG_CHANNEL_BPredicate 39
-#define BLOG_CHANNEL_ServerConnection 40
-#define BLOG_CHANNEL_Listener 41
-#define BLOG_CHANNEL_DataProto 42
-#define BLOG_CHANNEL_FrameDecider 43
-#define BLOG_CHANNEL_BSocksClient 44
-#define BLOG_CHANNEL_BDHCPClientCore 45
-#define BLOG_CHANNEL_BDHCPClient 46
-#define BLOG_CHANNEL_NCDIfConfig 47
-#define BLOG_CHANNEL_BUnixSignal 48
-#define BLOG_CHANNEL_BProcess 49
-#define BLOG_CHANNEL_StreamSocketSink 50
-#define BLOG_CHANNEL_StreamSocketSource 51
-#define BLOG_CHANNEL_DatagramSocketSink 52
-#define BLOG_CHANNEL_DatagramSocketSource 53
-#define BLOG_CHANNEL_PRStreamSink 54
-#define BLOG_CHANNEL_PRStreamSource 55
-#define BLOG_CHANNEL_BSocketPRFileDesc 56
-#define BLOG_CHANNEL_PacketProtoDecoder 57
-#define BLOG_CHANNEL_DPRelay 58
-#define BLOG_CHANNEL_BThreadWork 59
-#define BLOG_CHANNEL_DPReceive 60
-#define BLOG_NUM_CHANNELS 61
+#define BLOG_CHANNEL_ncd_regex_match 14
+#define BLOG_CHANNEL_ncd_logical 15
+#define BLOG_CHANNEL_ncd_sleep 16
+#define BLOG_CHANNEL_ncd_print 17
+#define BLOG_CHANNEL_ncd_blocker 18
+#define BLOG_CHANNEL_ncd_ip_in_network 19
+#define BLOG_CHANNEL_ncd_run 20
+#define BLOG_CHANNEL_ncd_synchronous_process 21
+#define BLOG_CHANNEL_ncd_process_manager 22
+#define BLOG_CHANNEL_ncd_net_backend_waitdevice 23
+#define BLOG_CHANNEL_ncd_net_backend_waitlink 24
+#define BLOG_CHANNEL_ncd_net_backend_badvpn 25
+#define BLOG_CHANNEL_ncd_net_backend_wpa_supplicant 26
+#define BLOG_CHANNEL_ncd_net_backend_rfkill 27
+#define BLOG_CHANNEL_ncd_net_up 28
+#define BLOG_CHANNEL_ncd_net_dns 29
+#define BLOG_CHANNEL_ncd_net_iptables 30
+#define BLOG_CHANNEL_ncd_net_ipv4_addr 31
+#define BLOG_CHANNEL_ncd_net_ipv4_dhcp 32
+#define BLOG_CHANNEL_ncd_net_ipv4_route 33
+#define BLOG_CHANNEL_ncd_sys_evdev 34
+#define BLOG_CHANNEL_StreamPeerIO 35
+#define BLOG_CHANNEL_DatagramPeerIO 36
+#define BLOG_CHANNEL_BReactor 37
+#define BLOG_CHANNEL_BSignal 38
+#define BLOG_CHANNEL_FragmentProtoAssembler 39
+#define BLOG_CHANNEL_BPredicate 40
+#define BLOG_CHANNEL_ServerConnection 41
+#define BLOG_CHANNEL_Listener 42
+#define BLOG_CHANNEL_DataProto 43
+#define BLOG_CHANNEL_FrameDecider 44
+#define BLOG_CHANNEL_BSocksClient 45
+#define BLOG_CHANNEL_BDHCPClientCore 46
+#define BLOG_CHANNEL_BDHCPClient 47
+#define BLOG_CHANNEL_NCDIfConfig 48
+#define BLOG_CHANNEL_BUnixSignal 49
+#define BLOG_CHANNEL_BProcess 50
+#define BLOG_CHANNEL_StreamSocketSink 51
+#define BLOG_CHANNEL_StreamSocketSource 52
+#define BLOG_CHANNEL_DatagramSocketSink 53
+#define BLOG_CHANNEL_DatagramSocketSource 54
+#define BLOG_CHANNEL_PRStreamSink 55
+#define BLOG_CHANNEL_PRStreamSource 56
+#define BLOG_CHANNEL_BSocketPRFileDesc 57
+#define BLOG_CHANNEL_PacketProtoDecoder 58
+#define BLOG_CHANNEL_DPRelay 59
+#define BLOG_CHANNEL_BThreadWork 60
+#define BLOG_CHANNEL_DPReceive 61
+#define BLOG_NUM_CHANNELS 62

+ 1 - 0
generated/blog_channels_list.h

@@ -12,6 +12,7 @@
 {.name = "ncd_concatlist", .loglevel = 4},
 {.name = "ncd_if", .loglevel = 4},
 {.name = "ncd_strcmp", .loglevel = 4},
+{.name = "ncd_regex_match", .loglevel = 4},
 {.name = "ncd_logical", .loglevel = 4},
 {.name = "ncd_sleep", .loglevel = 4},
 {.name = "ncd_print", .loglevel = 4},

+ 1 - 0
ncd/CMakeLists.txt

@@ -31,6 +31,7 @@ add_executable(badvpn-ncd
     modules/concatlist.c
     modules/if.c
     modules/strcmp.c
+    modules/regex_match.c
     modules/logical.c
     modules/sleep.c
     modules/print.c

+ 2 - 0
ncd/modules/modules.h

@@ -36,6 +36,7 @@ extern const struct NCDModuleGroup ncdmodule_concatv;
 extern const struct NCDModuleGroup ncdmodule_concatlist;
 extern const struct NCDModuleGroup ncdmodule_if;
 extern const struct NCDModuleGroup ncdmodule_strcmp;
+extern const struct NCDModuleGroup ncdmodule_regex_match;
 extern const struct NCDModuleGroup ncdmodule_logical;
 extern const struct NCDModuleGroup ncdmodule_sleep;
 extern const struct NCDModuleGroup ncdmodule_print;
@@ -71,6 +72,7 @@ static const struct NCDModuleGroup *ncd_modules[] = {
     &ncdmodule_concatlist,
     &ncdmodule_if,
     &ncdmodule_strcmp,
+    &ncdmodule_regex_match,
     &ncdmodule_logical,
     &ncdmodule_sleep,
     &ncdmodule_print,

+ 181 - 0
ncd/modules/regex_match.c

@@ -0,0 +1,181 @@
+/**
+ * @file regex_match.c
+ * @author Ambroz Bizjak <ambrop7@gmail.com>
+ * 
+ * @section LICENSE
+ * 
+ * This file is part of BadVPN.
+ * 
+ * BadVPN is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ * 
+ * BadVPN is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * @section DESCRIPTION
+ * 
+ * Regular expression matching module.
+ * 
+ * Synopsis: regex_match(string input, string regex)
+ * Variables:
+ *   succeeded - "true" or "false", indicating whether input matched regex
+ *   matchN - for N=0,1,2,..., the matching data for the N-th subexpression
+ *     (match0 = whole match)
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <regex.h>
+
+#include <misc/string_begins_with.h>
+#include <misc/parse_number.h>
+#include <ncd/NCDModule.h>
+
+#include <generated/blog_channel_ncd_regex_match.h>
+
+#define ModuleLog(i, ...) NCDModuleInst_Backend_Log((i), BLOG_CURRENT_CHANNEL, __VA_ARGS__)
+
+#define MAX_MATCHES 64
+
+struct instance {
+    NCDModuleInst *i;
+    char *input;
+    int succeeded;
+    int num_matches;
+    regmatch_t matches[MAX_MATCHES];
+};
+
+static void func_new (NCDModuleInst *i)
+{
+    // allocate instance
+    struct instance *o = malloc(sizeof(*o));
+    if (!o) {
+        ModuleLog(i, BLOG_ERROR, "failed to allocate instance");
+        goto fail0;
+    }
+    NCDModuleInst_Backend_SetUser(i, o);
+    
+    // init arguments
+    o->i = i;
+    
+    // read arguments
+    NCDValue *input_arg;
+    NCDValue *regex_arg;
+    if (!NCDValue_ListRead(o->i->args, 2, &input_arg, &regex_arg)) {
+        ModuleLog(o->i, BLOG_ERROR, "wrong arity");
+        goto fail1;
+    }
+    if (NCDValue_Type(input_arg) != NCDVALUE_STRING || NCDValue_Type(regex_arg) != NCDVALUE_STRING) {
+        ModuleLog(o->i, BLOG_ERROR, "wrong type");
+        goto fail1;
+    }
+    o->input = NCDValue_StringValue(input_arg);
+    char *regex = NCDValue_StringValue(regex_arg);
+    
+    // compile regex
+    regex_t preg;
+    int ret;
+    if ((ret = regcomp(&preg, regex, REG_EXTENDED)) != 0) {
+        ModuleLog(o->i, BLOG_ERROR, "regcomp failed (error=%d)", ret);
+        goto fail1;
+    }
+    
+    // execute match
+    o->succeeded = (regexec(&preg, o->input, MAX_MATCHES, o->matches, 0) == 0);
+    
+    // free regex
+    regfree(&preg);
+    
+    // signal up
+    NCDModuleInst_Backend_Event(o->i, NCDMODULE_EVENT_UP);
+    
+    return;
+    
+fail1:
+    free(o);
+fail0:
+    NCDModuleInst_Backend_SetError(i);
+    NCDModuleInst_Backend_Event(i, NCDMODULE_EVENT_DEAD);
+}
+
+static void func_die (void *vo)
+{
+    struct instance *o = vo;
+    NCDModuleInst *i = o->i;
+    
+    // free instance
+    free(o);
+    
+    NCDModuleInst_Backend_Event(i, NCDMODULE_EVENT_DEAD);
+}
+
+static int func_getvar (void *vo, const char *name, NCDValue *out)
+{
+    struct instance *o = vo;
+    
+    if (!strcmp(name, "succeeded")) {
+        if (!NCDValue_InitString(out, (o->succeeded ? "true" : "false"))) {
+            ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
+            return 0;
+        }
+        
+        return 1;
+    }
+    
+    size_t pos;
+    uintmax_t n;
+    if ((pos = string_begins_with(name, "match")) && parse_unsigned_integer(name + pos, &n)) {
+        if (o->succeeded && n < MAX_MATCHES && o->matches[n].rm_so >= 0) {
+            regmatch_t *m = &o->matches[n];
+            
+            ASSERT(m->rm_so <= strlen(o->input))
+            ASSERT(m->rm_eo >= m->rm_so)
+            ASSERT(m->rm_eo <= strlen(o->input))
+            
+            size_t len = m->rm_eo - m->rm_so;
+            
+            char *str = malloc(len + 1);
+            if (!str) {
+                ModuleLog(o->i, BLOG_ERROR, "malloc failed");
+                return 0;
+            }
+            
+            memcpy(str, o->input + m->rm_so, len);
+            str[len] = '\0';
+            
+            if (!NCDValue_InitString(out, str)) {
+                ModuleLog(o->i, BLOG_ERROR, "NCDValue_InitCopy failed");
+                free(str);
+                return 0;
+            }
+            
+            free(str);
+            
+            return 1;
+        }
+    }
+    
+    return 0;
+}
+
+static const struct NCDModule modules[] = {
+    {
+        .type = "regex_match",
+        .func_new = func_new,
+        .func_die = func_die,
+        .func_getvar = func_getvar
+    }, {
+        .type = NULL
+    }
+};
+
+const struct NCDModuleGroup ncdmodule_regex_match = {
+    .modules = modules
+};