示例位置: <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次。