mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-08-01 15:09:33 +08:00
303 lines
5.4 KiB
C
303 lines
5.4 KiB
C
#include <linux/init.h>
|
|
#include <linux/module.h>
|
|
#include <linux/types.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/slab.h>
|
|
//#include "regexp.h"
|
|
|
|
typedef enum{CHAR, DOT, BEGIN, END, STAR, PLUS, QUES, LIST, TYPENUM}TYPE;
|
|
|
|
typedef struct RE{
|
|
TYPE type;
|
|
int ch;
|
|
char *ccl;
|
|
int nccl;
|
|
struct RE *next;
|
|
}RE;
|
|
|
|
int match_longest = 0;
|
|
char *match_first = NULL;
|
|
|
|
|
|
static void * getmem(size_t size)
|
|
{
|
|
void *tmp;
|
|
if((tmp = kmalloc(size, GFP_ATOMIC))==NULL)
|
|
{
|
|
printk("malloc failed");
|
|
return NULL;
|
|
}
|
|
return tmp;
|
|
}
|
|
|
|
static size_t creat_list(char *str, int start, int end)
|
|
{
|
|
size_t cnt = end - start + 1;
|
|
for(; start <= end ;start++)
|
|
*str++ = start;
|
|
return (cnt > 0)?cnt:0;
|
|
}
|
|
|
|
static int in_list(char ch, RE *regexp)
|
|
{
|
|
char *str = regexp->ccl;
|
|
if(regexp->type != LIST)
|
|
return 0;
|
|
for(; *str && ch != *str; str++)
|
|
;
|
|
return (*str != '\0') ^ regexp->nccl;
|
|
}
|
|
|
|
static void regexp_free(RE *regexp)
|
|
{
|
|
RE *tmp;
|
|
for(; regexp; regexp = tmp)
|
|
{
|
|
tmp = regexp->next;
|
|
kfree(regexp);
|
|
}
|
|
}
|
|
|
|
static RE* compile(char *regexp)
|
|
{
|
|
RE head, *tail, *tmp;
|
|
char *pstr;
|
|
int err_flag = 0;
|
|
|
|
for(tail = &head; *regexp != '\0' && err_flag == 0; regexp++)
|
|
{
|
|
tmp = getmem(sizeof(RE));
|
|
switch(*regexp){
|
|
case '\\':
|
|
regexp++;
|
|
if(*regexp == 'd')
|
|
{
|
|
tmp->type = LIST;
|
|
tmp->nccl = 0;
|
|
tmp->ccl = getmem(11);
|
|
creat_list(tmp->ccl, '0','9');
|
|
tmp->ccl[11] = '\0';
|
|
}else if(*regexp == 'D')
|
|
{
|
|
tmp->type = LIST;
|
|
tmp->nccl = 1;
|
|
tmp->ccl = getmem(11);
|
|
creat_list(tmp->ccl, '0','9');
|
|
tmp->ccl[11] = '\0';
|
|
}else
|
|
{
|
|
tmp->type = CHAR;
|
|
tmp->ch = *regexp;
|
|
}
|
|
break;
|
|
case '.':
|
|
tmp->type = DOT;
|
|
break;
|
|
case '^':
|
|
tmp->type = BEGIN;
|
|
tmp->ch = '^';
|
|
break;
|
|
case '$':
|
|
tmp->type = END;
|
|
tmp->ch = '$';
|
|
break;
|
|
case '*':
|
|
tmp->type = STAR;
|
|
break;
|
|
case '+':
|
|
tmp->type = PLUS;
|
|
break;
|
|
case '?':
|
|
tmp->type = QUES;
|
|
break;
|
|
case '[':
|
|
pstr = tmp->ccl = getmem(256);
|
|
tmp->nccl = 0;
|
|
if(*++regexp == '^')
|
|
{
|
|
tmp->nccl = 1;
|
|
regexp++;
|
|
}
|
|
while(*regexp != '\0' && *regexp != ']')
|
|
{
|
|
if(*regexp != '-')
|
|
{
|
|
*pstr++ = *regexp++;
|
|
continue;
|
|
}
|
|
if(pstr == tmp->ccl || *(regexp + 1) == ']')
|
|
{
|
|
err_flag = 1;
|
|
break;
|
|
}
|
|
pstr += creat_list(pstr, *(regexp - 1) + 1, *(regexp + 1));
|
|
regexp += 2;
|
|
}
|
|
*pstr = '\0';
|
|
if(*regexp == '\0')
|
|
err_flag = 1;
|
|
tmp->type = LIST;
|
|
break;
|
|
default:
|
|
tmp->type = CHAR;
|
|
tmp->ch = *regexp;
|
|
}
|
|
|
|
tail->next = tmp;
|
|
tail = tmp;
|
|
}
|
|
|
|
tail->next = NULL;
|
|
if(err_flag)
|
|
{
|
|
regexp_free(head.next);
|
|
return NULL;
|
|
}
|
|
return head.next;
|
|
}
|
|
|
|
#define MATCH_ONE(reg, text) \
|
|
(reg->type == DOT || in_list(*text, reg) || *text == reg->ch)
|
|
#define MATCH_ONE_P(reg, text) \
|
|
(in_list(*text++, reg) || *(text - 1) == reg->ch || reg->type == DOT)
|
|
|
|
static int matchhere(RE *regexp, char *text);
|
|
|
|
static int matchstar(RE *cur, RE *regexp, char *text)
|
|
{
|
|
do{
|
|
if(matchhere(regexp, text))
|
|
return 1;
|
|
}while(*text != '\0' && MATCH_ONE_P(cur, text));
|
|
return 0;
|
|
}
|
|
|
|
static int matchstar_l(RE *cur, RE *regexp, char *text)
|
|
{
|
|
char *t;
|
|
for(t = text; *t != '\0' && MATCH_ONE(cur, t); t++)
|
|
;
|
|
do{
|
|
if(matchhere(regexp, t))
|
|
return 1;
|
|
}while(t-- > text);
|
|
return 0;
|
|
}
|
|
|
|
static int matchplus(RE *cur, RE *regexp, char *text)
|
|
{
|
|
while(*text != '\0' && MATCH_ONE_P(cur, text))
|
|
{
|
|
if(matchhere(regexp, text))
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int matchplus_l(RE *cur, RE *regexp, char *text)
|
|
{
|
|
char *t;
|
|
for(t = text; *t != '\0' && MATCH_ONE(cur, t); t++)
|
|
;
|
|
for(; t > text; t--)
|
|
{
|
|
if(matchhere(regexp, t))
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int matchques(RE *cur, RE *regexp, char *text)
|
|
{
|
|
int cnt = 1;
|
|
char *t = text;
|
|
if(*t != '\0' && cnt-- && MATCH_ONE(cur, t))
|
|
t++;
|
|
do{
|
|
if(matchhere(regexp, t))
|
|
return 1;
|
|
}while(t-- > text);
|
|
return 0;
|
|
}
|
|
|
|
static int (*matchfun[TYPENUM][2])(RE *, RE *, char *) = {
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
matchstar, matchstar_l,
|
|
matchplus, matchplus_l,
|
|
matchques, matchques,
|
|
};
|
|
|
|
static int matchhere(RE *regexp, char *text)
|
|
{
|
|
if(regexp == NULL)
|
|
return 1;
|
|
if(regexp->type == END && regexp->next == NULL)
|
|
return *text == '\0';
|
|
if(regexp->next && matchfun[regexp->next->type][match_longest])
|
|
return matchfun[regexp->next->type][match_longest](regexp, regexp->next->next, text);
|
|
|
|
if(*text != '\0' && MATCH_ONE(regexp, text))
|
|
return matchhere(regexp->next, text + 1);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* return value:
|
|
* -1 error
|
|
* 0 not match
|
|
* 1 matched
|
|
*/
|
|
int regexp_match(char *reg, char *text)
|
|
{
|
|
int ret;
|
|
RE *regexp = compile(reg);
|
|
if(regexp == NULL)
|
|
return -1;
|
|
|
|
if(regexp->type == BEGIN)
|
|
{
|
|
ret = matchhere(regexp->next, text);
|
|
goto out;
|
|
}
|
|
|
|
do{
|
|
if(ret = matchhere(regexp, text))
|
|
{
|
|
goto out;
|
|
}
|
|
}while(*text++ != '\0');
|
|
|
|
out:
|
|
regexp_free(regexp);
|
|
return ret;
|
|
}
|
|
|
|
|
|
void TEST_reg_func(char *reg, char * str, int ret)
|
|
{
|
|
|
|
if (ret != regexp_match(reg, str)) {
|
|
if (reg)
|
|
printk("reg = %s,", reg);
|
|
else
|
|
printk("reg = null");
|
|
if (str)
|
|
printk("str = %s ", str);
|
|
else
|
|
printk("str= null");
|
|
printk("error, unit test.... failed, ret = %d\n",ret);
|
|
}
|
|
else {
|
|
if (reg && str)
|
|
printk("[unit test] %s %s......ok,ret = %d\n", reg, str, ret);
|
|
}
|
|
}
|
|
|
|
void TEST_regexp(void)
|
|
{
|
|
TEST_reg_func(".*baidu.com$", "www.baidu.com", 1);
|
|
TEST_reg_func("^sina.com", "www.sina.com.cn", 0);
|
|
TEST_reg_func("^sina.com", "sina.com.cn", 1);
|
|
TEST_reg_func(".*baidu.com$", "www.baidu.com223", 0);
|
|
}
|