示例位置: <hyperscan source>/examples/simplegrep.c
参考:http://01org.github.io/hyperscan/dev-reference/api_files.htmlhtml
此示例实现一个grep的简化版本:指定一个正则表达式和文件,执行后依次输出匹配位置。c++
但这个简单示例并不支持从stdin读取数据,也不支持grep那丰富的命令行参数。git
simplegrep演示了如下hyperscan概念:github
这个示例很是简单,这里只解读表达式编译和匹配两部分的代码,读取数据文件等代码忽略。正则表达式
进行匹配以前,首先须要编译正则表达式,生成hs_database_t。express
hs_database_t *database; hs_compile_error_t *compile_err; if (hs_compile(pattern, HS_FLAG_DOTALL, HS_MODE_BLOCK, NULL, &database, &compile_err) != HS_SUCCESS) { fprintf(stderr, "ERROR: Unable to compile pattern \"%s\": %s\n", pattern, compile_err->message); hs_free_compile_error(compile_err); return -1; }
hs_compile的原型是api
hs_error_t hs_compile(const char * expression,
unsigned int flags,
unsigned int mode,
const hs_platform_info_t * platform,
hs_database_t ** db,
hs_compile_error_t ** error)
其中,expression是正则表达式字符串;flags用来控制正则的行为,好比忽略大小写,使.包含换行等;mode肯定了生成database的格式,主要有BLOCK,STREAM和VECTOR三种,每一种模式的database只能由相应的scan接口使用;platform用来指定此database的目标平台(主要是一些CPU特性),为NULL表示目标平台与当前平台一致;db用来保存编译后的database;error接收错误信息。函数
首先分配好每次匹配须要用的临时数据(scratch)。性能
hs_scratch_t *scratch = NULL; if (hs_alloc_scratch(database, &scratch) != HS_SUCCESS) { fprintf(stderr, "ERROR: Unable to allocate scratch space. Exiting.\n"); free(inputData); hs_free_database(database); return -1; }
接下来进行匹配(scan)。spa
if (hs_scan(database, inputData, length, 0, scratch, eventHandler, pattern) != HS_SUCCESS) { fprintf(stderr, "ERROR: Unable to scan input buffer. Exiting.\n"); hs_free_scratch(scratch); free(inputData); hs_free_database(database); return -1; }
hs_scan的原型是
hs_error_t hs_scan(const hs_database_t * db,
const char * data,
unsigned int length,
unsigned int flags,
hs_scratch_t * scratch,
match_event_handler onEvent,
void * context)
其中,db就是上一步编译的databas;data和length分别是要匹配的数据和数据长度;flags用来在将来版本中控制函数行为,目前未使用;scratch是匹配时要用的临时数据,以前已经分配好;onEvent很是关键,即匹配时调用的回调函数,由用户指定;context是用户自定义指针。
匹配回调函数的原型是
typedef (* match_event_handler)(unsigned int id,
unsigned long long from,
unsigned long long to,
unsigned int flags,
void *context)
其中,id是命中的正则表达式的ID,对于使用hs_compile编译的惟一表达式来讲,此值为0;若是在编译时指定了相关模式选项(hs_compile中的mode参数),则此值将会设为匹配特征的起始位置,不然会设为0;to是命中数据的下一个字节的偏移;flags目前未用;context是用户自定义指针。
返回值为非0表示中止匹配,不然继续;在匹配的过程当中,每次命中时都将同步调用匹配回调函数,直到匹配结束。
本例中的回调函数是
static int eventHandler(unsigned int id, unsigned long long from, unsigned long long to, unsigned int flags, void *ctx) { printf("Match for pattern \"%s\" at offset %llu\n", (char *)ctx, to); return 0; }
输出了正则表达式和其匹配的位置(命中数据的下一个字节在数据中的偏移值)。
程序结束后,应清理相关数据,释放内存。
hs_free_scratch(scratch); free(inputData); hs_free_database(database);
编译以前,我已经经过make install将hyperscan头文件和静态库安装在了/usr/local相关目录中。
gcc -o simplegrep simplegrep.c -lhs -lstdc++ -lm
注意连接stdc++和math库 (lstdc++ -lm)。若是是连接动态库,不须要加-lstdc++ -lm。
运行,在另外一示例代码pcapscan.cc中匹配/[f|F]ile/:
./simplegrep '[f|F]ile' pcapscan.cc Scanning 22859 bytes with Hyperscan Match for pattern "[f|F]ile" at offset 1692 .....(略,共45次匹配)
用grep命令验证结果
grep -o '[f|F]ile' pcapscan.cc | wc -l 45
OK,也是45次。