op-packages/oaf/src/regexp.c
github-actions[bot] 32600acc60 🌴 Sync 2026-03-05 23:51:42
2026-03-05 23:51:42 +08:00

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);
}