1*a5ecbe62SWolfgang Denk /* 2*a5ecbe62SWolfgang Denk * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com> 3*a5ecbe62SWolfgang Denk * All rights reserved 4*a5ecbe62SWolfgang Denk * 5*a5ecbe62SWolfgang Denk * "THE BEER-WARE LICENSE" (Revision 42): 6*a5ecbe62SWolfgang Denk * Sergey Lyubka wrote this file. As long as you retain this notice you 7*a5ecbe62SWolfgang Denk * can do whatever you want with this stuff. If we meet some day, and you think 8*a5ecbe62SWolfgang Denk * this stuff is worth it, you can buy me a beer in return. 9*a5ecbe62SWolfgang Denk */ 10*a5ecbe62SWolfgang Denk 11*a5ecbe62SWolfgang Denk /* 12*a5ecbe62SWolfgang Denk * Downloaded Sat Nov 5 17:43:06 CET 2011 at 13*a5ecbe62SWolfgang Denk * http://slre.sourceforge.net/1.0/slre.c 14*a5ecbe62SWolfgang Denk */ 15*a5ecbe62SWolfgang Denk 16*a5ecbe62SWolfgang Denk #ifdef SLRE_TEST 17*a5ecbe62SWolfgang Denk #include <stdio.h> 18*a5ecbe62SWolfgang Denk #include <assert.h> 19*a5ecbe62SWolfgang Denk #include <ctype.h> 20*a5ecbe62SWolfgang Denk #include <stdlib.h> 21*a5ecbe62SWolfgang Denk #include <string.h> 22*a5ecbe62SWolfgang Denk #else 23*a5ecbe62SWolfgang Denk #include <common.h> 24*a5ecbe62SWolfgang Denk #include <linux/ctype.h> 25*a5ecbe62SWolfgang Denk #endif /* SLRE_TEST */ 26*a5ecbe62SWolfgang Denk 27*a5ecbe62SWolfgang Denk #include <errno.h> 28*a5ecbe62SWolfgang Denk 29*a5ecbe62SWolfgang Denk #include <slre.h> 30*a5ecbe62SWolfgang Denk 31*a5ecbe62SWolfgang Denk enum {END, BRANCH, ANY, EXACT, ANYOF, ANYBUT, OPEN, CLOSE, BOL, EOL, 32*a5ecbe62SWolfgang Denk STAR, PLUS, STARQ, PLUSQ, QUEST, SPACE, NONSPACE, DIGIT}; 33*a5ecbe62SWolfgang Denk 34*a5ecbe62SWolfgang Denk #ifdef SLRE_TEST 35*a5ecbe62SWolfgang Denk static struct { 36*a5ecbe62SWolfgang Denk const char *name; 37*a5ecbe62SWolfgang Denk int narg; 38*a5ecbe62SWolfgang Denk const char *flags; 39*a5ecbe62SWolfgang Denk } opcodes[] = { 40*a5ecbe62SWolfgang Denk {"END", 0, ""}, /* End of code block or program */ 41*a5ecbe62SWolfgang Denk {"BRANCH", 2, "oo"}, /* Alternative operator, "|" */ 42*a5ecbe62SWolfgang Denk {"ANY", 0, ""}, /* Match any character, "." */ 43*a5ecbe62SWolfgang Denk {"EXACT", 2, "d"}, /* Match exact string */ 44*a5ecbe62SWolfgang Denk {"ANYOF", 2, "D"}, /* Match any from set, "[]" */ 45*a5ecbe62SWolfgang Denk {"ANYBUT", 2, "D"}, /* Match any but from set, "[^]"*/ 46*a5ecbe62SWolfgang Denk {"OPEN ", 1, "i"}, /* Capture start, "(" */ 47*a5ecbe62SWolfgang Denk {"CLOSE", 1, "i"}, /* Capture end, ")" */ 48*a5ecbe62SWolfgang Denk {"BOL", 0, ""}, /* Beginning of string, "^" */ 49*a5ecbe62SWolfgang Denk {"EOL", 0, ""}, /* End of string, "$" */ 50*a5ecbe62SWolfgang Denk {"STAR", 1, "o"}, /* Match zero or more times "*" */ 51*a5ecbe62SWolfgang Denk {"PLUS", 1, "o"}, /* Match one or more times, "+" */ 52*a5ecbe62SWolfgang Denk {"STARQ", 1, "o"}, /* Non-greedy STAR, "*?" */ 53*a5ecbe62SWolfgang Denk {"PLUSQ", 1, "o"}, /* Non-greedy PLUS, "+?" */ 54*a5ecbe62SWolfgang Denk {"QUEST", 1, "o"}, /* Match zero or one time, "?" */ 55*a5ecbe62SWolfgang Denk {"SPACE", 0, ""}, /* Match whitespace, "\s" */ 56*a5ecbe62SWolfgang Denk {"NONSPACE", 0, ""}, /* Match non-space, "\S" */ 57*a5ecbe62SWolfgang Denk {"DIGIT", 0, ""} /* Match digit, "\d" */ 58*a5ecbe62SWolfgang Denk }; 59*a5ecbe62SWolfgang Denk #endif /* SLRE_TEST */ 60*a5ecbe62SWolfgang Denk 61*a5ecbe62SWolfgang Denk /* 62*a5ecbe62SWolfgang Denk * Commands and operands are all unsigned char (1 byte long). All code offsets 63*a5ecbe62SWolfgang Denk * are relative to current address, and positive (always point forward). Data 64*a5ecbe62SWolfgang Denk * offsets are absolute. Commands with operands: 65*a5ecbe62SWolfgang Denk * 66*a5ecbe62SWolfgang Denk * BRANCH offset1 offset2 67*a5ecbe62SWolfgang Denk * Try to match the code block that follows the BRANCH instruction 68*a5ecbe62SWolfgang Denk * (code block ends with END). If no match, try to match code block that 69*a5ecbe62SWolfgang Denk * starts at offset1. If either of these match, jump to offset2. 70*a5ecbe62SWolfgang Denk * 71*a5ecbe62SWolfgang Denk * EXACT data_offset data_length 72*a5ecbe62SWolfgang Denk * Try to match exact string. String is recorded in data section from 73*a5ecbe62SWolfgang Denk * data_offset, and has length data_length. 74*a5ecbe62SWolfgang Denk * 75*a5ecbe62SWolfgang Denk * OPEN capture_number 76*a5ecbe62SWolfgang Denk * CLOSE capture_number 77*a5ecbe62SWolfgang Denk * If the user have passed 'struct cap' array for captures, OPEN 78*a5ecbe62SWolfgang Denk * records the beginning of the matched substring (cap->ptr), CLOSE 79*a5ecbe62SWolfgang Denk * sets the length (cap->len) for respective capture_number. 80*a5ecbe62SWolfgang Denk * 81*a5ecbe62SWolfgang Denk * STAR code_offset 82*a5ecbe62SWolfgang Denk * PLUS code_offset 83*a5ecbe62SWolfgang Denk * QUEST code_offset 84*a5ecbe62SWolfgang Denk * *, +, ?, respectively. Try to gobble as much as possible from the 85*a5ecbe62SWolfgang Denk * matched buffer, until code block that follows these instructions 86*a5ecbe62SWolfgang Denk * matches. When the longest possible string is matched, 87*a5ecbe62SWolfgang Denk * jump to code_offset 88*a5ecbe62SWolfgang Denk * 89*a5ecbe62SWolfgang Denk * STARQ, PLUSQ are non-greedy versions of STAR and PLUS. 90*a5ecbe62SWolfgang Denk */ 91*a5ecbe62SWolfgang Denk 92*a5ecbe62SWolfgang Denk static const char *meta_chars = "|.^$*+?()[\\"; 93*a5ecbe62SWolfgang Denk 94*a5ecbe62SWolfgang Denk #ifdef SLRE_TEST 95*a5ecbe62SWolfgang Denk 96*a5ecbe62SWolfgang Denk static void 97*a5ecbe62SWolfgang Denk print_character_set(FILE *fp, const unsigned char *p, int len) 98*a5ecbe62SWolfgang Denk { 99*a5ecbe62SWolfgang Denk int i; 100*a5ecbe62SWolfgang Denk 101*a5ecbe62SWolfgang Denk for (i = 0; i < len; i++) { 102*a5ecbe62SWolfgang Denk if (i > 0) 103*a5ecbe62SWolfgang Denk (void) fputc(',', fp); 104*a5ecbe62SWolfgang Denk if (p[i] == 0) { 105*a5ecbe62SWolfgang Denk i++; 106*a5ecbe62SWolfgang Denk if (p[i] == 0) 107*a5ecbe62SWolfgang Denk (void) fprintf(fp, "\\x%02x", p[i]); 108*a5ecbe62SWolfgang Denk else 109*a5ecbe62SWolfgang Denk (void) fprintf(fp, "%s", opcodes[p[i]].name); 110*a5ecbe62SWolfgang Denk } else if (isprint(p[i])) { 111*a5ecbe62SWolfgang Denk (void) fputc(p[i], fp); 112*a5ecbe62SWolfgang Denk } else { 113*a5ecbe62SWolfgang Denk (void) fprintf(fp, "\\x%02x", p[i]); 114*a5ecbe62SWolfgang Denk } 115*a5ecbe62SWolfgang Denk } 116*a5ecbe62SWolfgang Denk } 117*a5ecbe62SWolfgang Denk 118*a5ecbe62SWolfgang Denk void 119*a5ecbe62SWolfgang Denk slre_dump(const struct slre *r, FILE *fp) 120*a5ecbe62SWolfgang Denk { 121*a5ecbe62SWolfgang Denk int i, j, ch, op, pc; 122*a5ecbe62SWolfgang Denk 123*a5ecbe62SWolfgang Denk for (pc = 0; pc < r->code_size; pc++) { 124*a5ecbe62SWolfgang Denk 125*a5ecbe62SWolfgang Denk op = r->code[pc]; 126*a5ecbe62SWolfgang Denk (void) fprintf(fp, "%3d %s ", pc, opcodes[op].name); 127*a5ecbe62SWolfgang Denk 128*a5ecbe62SWolfgang Denk for (i = 0; opcodes[op].flags[i] != '\0'; i++) 129*a5ecbe62SWolfgang Denk switch (opcodes[op].flags[i]) { 130*a5ecbe62SWolfgang Denk case 'i': 131*a5ecbe62SWolfgang Denk (void) fprintf(fp, "%d ", r->code[pc + 1]); 132*a5ecbe62SWolfgang Denk pc++; 133*a5ecbe62SWolfgang Denk break; 134*a5ecbe62SWolfgang Denk case 'o': 135*a5ecbe62SWolfgang Denk (void) fprintf(fp, "%d ", 136*a5ecbe62SWolfgang Denk pc + r->code[pc + 1] - i); 137*a5ecbe62SWolfgang Denk pc++; 138*a5ecbe62SWolfgang Denk break; 139*a5ecbe62SWolfgang Denk case 'D': 140*a5ecbe62SWolfgang Denk print_character_set(fp, r->data + 141*a5ecbe62SWolfgang Denk r->code[pc + 1], r->code[pc + 2]); 142*a5ecbe62SWolfgang Denk pc += 2; 143*a5ecbe62SWolfgang Denk break; 144*a5ecbe62SWolfgang Denk case 'd': 145*a5ecbe62SWolfgang Denk (void) fputc('"', fp); 146*a5ecbe62SWolfgang Denk for (j = 0; j < r->code[pc + 2]; j++) { 147*a5ecbe62SWolfgang Denk ch = r->data[r->code[pc + 1] + j]; 148*a5ecbe62SWolfgang Denk if (isprint(ch)) { 149*a5ecbe62SWolfgang Denk (void) fputc(ch, fp); 150*a5ecbe62SWolfgang Denk } else { 151*a5ecbe62SWolfgang Denk (void) fprintf(fp, 152*a5ecbe62SWolfgang Denk "\\x%02x", ch); 153*a5ecbe62SWolfgang Denk } 154*a5ecbe62SWolfgang Denk } 155*a5ecbe62SWolfgang Denk (void) fputc('"', fp); 156*a5ecbe62SWolfgang Denk pc += 2; 157*a5ecbe62SWolfgang Denk break; 158*a5ecbe62SWolfgang Denk } 159*a5ecbe62SWolfgang Denk 160*a5ecbe62SWolfgang Denk (void) fputc('\n', fp); 161*a5ecbe62SWolfgang Denk } 162*a5ecbe62SWolfgang Denk } 163*a5ecbe62SWolfgang Denk #endif /* SLRE_TEST */ 164*a5ecbe62SWolfgang Denk 165*a5ecbe62SWolfgang Denk static void 166*a5ecbe62SWolfgang Denk set_jump_offset(struct slre *r, int pc, int offset) 167*a5ecbe62SWolfgang Denk { 168*a5ecbe62SWolfgang Denk assert(offset < r->code_size); 169*a5ecbe62SWolfgang Denk 170*a5ecbe62SWolfgang Denk if (r->code_size - offset > 0xff) 171*a5ecbe62SWolfgang Denk r->err_str = "Jump offset is too big"; 172*a5ecbe62SWolfgang Denk else 173*a5ecbe62SWolfgang Denk r->code[pc] = (unsigned char) (r->code_size - offset); 174*a5ecbe62SWolfgang Denk } 175*a5ecbe62SWolfgang Denk 176*a5ecbe62SWolfgang Denk static void 177*a5ecbe62SWolfgang Denk emit(struct slre *r, int code) 178*a5ecbe62SWolfgang Denk { 179*a5ecbe62SWolfgang Denk if (r->code_size >= (int) (sizeof(r->code) / sizeof(r->code[0]))) 180*a5ecbe62SWolfgang Denk r->err_str = "RE is too long (code overflow)"; 181*a5ecbe62SWolfgang Denk else 182*a5ecbe62SWolfgang Denk r->code[r->code_size++] = (unsigned char) code; 183*a5ecbe62SWolfgang Denk } 184*a5ecbe62SWolfgang Denk 185*a5ecbe62SWolfgang Denk static void 186*a5ecbe62SWolfgang Denk store_char_in_data(struct slre *r, int ch) 187*a5ecbe62SWolfgang Denk { 188*a5ecbe62SWolfgang Denk if (r->data_size >= (int) sizeof(r->data)) 189*a5ecbe62SWolfgang Denk r->err_str = "RE is too long (data overflow)"; 190*a5ecbe62SWolfgang Denk else 191*a5ecbe62SWolfgang Denk r->data[r->data_size++] = ch; 192*a5ecbe62SWolfgang Denk } 193*a5ecbe62SWolfgang Denk 194*a5ecbe62SWolfgang Denk static void 195*a5ecbe62SWolfgang Denk exact(struct slre *r, const char **re) 196*a5ecbe62SWolfgang Denk { 197*a5ecbe62SWolfgang Denk int old_data_size = r->data_size; 198*a5ecbe62SWolfgang Denk 199*a5ecbe62SWolfgang Denk while (**re != '\0' && (strchr(meta_chars, **re)) == NULL) 200*a5ecbe62SWolfgang Denk store_char_in_data(r, *(*re)++); 201*a5ecbe62SWolfgang Denk 202*a5ecbe62SWolfgang Denk emit(r, EXACT); 203*a5ecbe62SWolfgang Denk emit(r, old_data_size); 204*a5ecbe62SWolfgang Denk emit(r, r->data_size - old_data_size); 205*a5ecbe62SWolfgang Denk } 206*a5ecbe62SWolfgang Denk 207*a5ecbe62SWolfgang Denk static int 208*a5ecbe62SWolfgang Denk get_escape_char(const char **re) 209*a5ecbe62SWolfgang Denk { 210*a5ecbe62SWolfgang Denk int res; 211*a5ecbe62SWolfgang Denk 212*a5ecbe62SWolfgang Denk switch (*(*re)++) { 213*a5ecbe62SWolfgang Denk case 'n': 214*a5ecbe62SWolfgang Denk res = '\n'; 215*a5ecbe62SWolfgang Denk break; 216*a5ecbe62SWolfgang Denk case 'r': 217*a5ecbe62SWolfgang Denk res = '\r'; 218*a5ecbe62SWolfgang Denk break; 219*a5ecbe62SWolfgang Denk case 't': 220*a5ecbe62SWolfgang Denk res = '\t'; 221*a5ecbe62SWolfgang Denk break; 222*a5ecbe62SWolfgang Denk case '0': 223*a5ecbe62SWolfgang Denk res = 0; 224*a5ecbe62SWolfgang Denk break; 225*a5ecbe62SWolfgang Denk case 'S': 226*a5ecbe62SWolfgang Denk res = NONSPACE << 8; 227*a5ecbe62SWolfgang Denk break; 228*a5ecbe62SWolfgang Denk case 's': 229*a5ecbe62SWolfgang Denk res = SPACE << 8; 230*a5ecbe62SWolfgang Denk break; 231*a5ecbe62SWolfgang Denk case 'd': 232*a5ecbe62SWolfgang Denk res = DIGIT << 8; 233*a5ecbe62SWolfgang Denk break; 234*a5ecbe62SWolfgang Denk default: 235*a5ecbe62SWolfgang Denk res = (*re)[-1]; 236*a5ecbe62SWolfgang Denk break; 237*a5ecbe62SWolfgang Denk } 238*a5ecbe62SWolfgang Denk 239*a5ecbe62SWolfgang Denk return res; 240*a5ecbe62SWolfgang Denk } 241*a5ecbe62SWolfgang Denk 242*a5ecbe62SWolfgang Denk static void 243*a5ecbe62SWolfgang Denk anyof(struct slre *r, const char **re) 244*a5ecbe62SWolfgang Denk { 245*a5ecbe62SWolfgang Denk int esc, old_data_size = r->data_size, op = ANYOF; 246*a5ecbe62SWolfgang Denk 247*a5ecbe62SWolfgang Denk if (**re == '^') { 248*a5ecbe62SWolfgang Denk op = ANYBUT; 249*a5ecbe62SWolfgang Denk (*re)++; 250*a5ecbe62SWolfgang Denk } 251*a5ecbe62SWolfgang Denk 252*a5ecbe62SWolfgang Denk while (**re != '\0') 253*a5ecbe62SWolfgang Denk 254*a5ecbe62SWolfgang Denk switch (*(*re)++) { 255*a5ecbe62SWolfgang Denk case ']': 256*a5ecbe62SWolfgang Denk emit(r, op); 257*a5ecbe62SWolfgang Denk emit(r, old_data_size); 258*a5ecbe62SWolfgang Denk emit(r, r->data_size - old_data_size); 259*a5ecbe62SWolfgang Denk return; 260*a5ecbe62SWolfgang Denk /* NOTREACHED */ 261*a5ecbe62SWolfgang Denk break; 262*a5ecbe62SWolfgang Denk case '\\': 263*a5ecbe62SWolfgang Denk esc = get_escape_char(re); 264*a5ecbe62SWolfgang Denk if ((esc & 0xff) == 0) { 265*a5ecbe62SWolfgang Denk store_char_in_data(r, 0); 266*a5ecbe62SWolfgang Denk store_char_in_data(r, esc >> 8); 267*a5ecbe62SWolfgang Denk } else { 268*a5ecbe62SWolfgang Denk store_char_in_data(r, esc); 269*a5ecbe62SWolfgang Denk } 270*a5ecbe62SWolfgang Denk break; 271*a5ecbe62SWolfgang Denk default: 272*a5ecbe62SWolfgang Denk store_char_in_data(r, (*re)[-1]); 273*a5ecbe62SWolfgang Denk break; 274*a5ecbe62SWolfgang Denk } 275*a5ecbe62SWolfgang Denk 276*a5ecbe62SWolfgang Denk r->err_str = "No closing ']' bracket"; 277*a5ecbe62SWolfgang Denk } 278*a5ecbe62SWolfgang Denk 279*a5ecbe62SWolfgang Denk static void 280*a5ecbe62SWolfgang Denk relocate(struct slre *r, int begin, int shift) 281*a5ecbe62SWolfgang Denk { 282*a5ecbe62SWolfgang Denk emit(r, END); 283*a5ecbe62SWolfgang Denk memmove(r->code + begin + shift, r->code + begin, r->code_size - begin); 284*a5ecbe62SWolfgang Denk r->code_size += shift; 285*a5ecbe62SWolfgang Denk } 286*a5ecbe62SWolfgang Denk 287*a5ecbe62SWolfgang Denk static void 288*a5ecbe62SWolfgang Denk quantifier(struct slre *r, int prev, int op) 289*a5ecbe62SWolfgang Denk { 290*a5ecbe62SWolfgang Denk if (r->code[prev] == EXACT && r->code[prev + 2] > 1) { 291*a5ecbe62SWolfgang Denk r->code[prev + 2]--; 292*a5ecbe62SWolfgang Denk emit(r, EXACT); 293*a5ecbe62SWolfgang Denk emit(r, r->code[prev + 1] + r->code[prev + 2]); 294*a5ecbe62SWolfgang Denk emit(r, 1); 295*a5ecbe62SWolfgang Denk prev = r->code_size - 3; 296*a5ecbe62SWolfgang Denk } 297*a5ecbe62SWolfgang Denk relocate(r, prev, 2); 298*a5ecbe62SWolfgang Denk r->code[prev] = op; 299*a5ecbe62SWolfgang Denk set_jump_offset(r, prev + 1, prev); 300*a5ecbe62SWolfgang Denk } 301*a5ecbe62SWolfgang Denk 302*a5ecbe62SWolfgang Denk static void 303*a5ecbe62SWolfgang Denk exact_one_char(struct slre *r, int ch) 304*a5ecbe62SWolfgang Denk { 305*a5ecbe62SWolfgang Denk emit(r, EXACT); 306*a5ecbe62SWolfgang Denk emit(r, r->data_size); 307*a5ecbe62SWolfgang Denk emit(r, 1); 308*a5ecbe62SWolfgang Denk store_char_in_data(r, ch); 309*a5ecbe62SWolfgang Denk } 310*a5ecbe62SWolfgang Denk 311*a5ecbe62SWolfgang Denk static void 312*a5ecbe62SWolfgang Denk fixup_branch(struct slre *r, int fixup) 313*a5ecbe62SWolfgang Denk { 314*a5ecbe62SWolfgang Denk if (fixup > 0) { 315*a5ecbe62SWolfgang Denk emit(r, END); 316*a5ecbe62SWolfgang Denk set_jump_offset(r, fixup, fixup - 2); 317*a5ecbe62SWolfgang Denk } 318*a5ecbe62SWolfgang Denk } 319*a5ecbe62SWolfgang Denk 320*a5ecbe62SWolfgang Denk static void 321*a5ecbe62SWolfgang Denk compile(struct slre *r, const char **re) 322*a5ecbe62SWolfgang Denk { 323*a5ecbe62SWolfgang Denk int op, esc, branch_start, last_op, fixup, cap_no, level; 324*a5ecbe62SWolfgang Denk 325*a5ecbe62SWolfgang Denk fixup = 0; 326*a5ecbe62SWolfgang Denk level = r->num_caps; 327*a5ecbe62SWolfgang Denk branch_start = last_op = r->code_size; 328*a5ecbe62SWolfgang Denk 329*a5ecbe62SWolfgang Denk for (;;) 330*a5ecbe62SWolfgang Denk switch (*(*re)++) { 331*a5ecbe62SWolfgang Denk case '\0': 332*a5ecbe62SWolfgang Denk (*re)--; 333*a5ecbe62SWolfgang Denk return; 334*a5ecbe62SWolfgang Denk /* NOTREACHED */ 335*a5ecbe62SWolfgang Denk break; 336*a5ecbe62SWolfgang Denk case '^': 337*a5ecbe62SWolfgang Denk emit(r, BOL); 338*a5ecbe62SWolfgang Denk break; 339*a5ecbe62SWolfgang Denk case '$': 340*a5ecbe62SWolfgang Denk emit(r, EOL); 341*a5ecbe62SWolfgang Denk break; 342*a5ecbe62SWolfgang Denk case '.': 343*a5ecbe62SWolfgang Denk last_op = r->code_size; 344*a5ecbe62SWolfgang Denk emit(r, ANY); 345*a5ecbe62SWolfgang Denk break; 346*a5ecbe62SWolfgang Denk case '[': 347*a5ecbe62SWolfgang Denk last_op = r->code_size; 348*a5ecbe62SWolfgang Denk anyof(r, re); 349*a5ecbe62SWolfgang Denk break; 350*a5ecbe62SWolfgang Denk case '\\': 351*a5ecbe62SWolfgang Denk last_op = r->code_size; 352*a5ecbe62SWolfgang Denk esc = get_escape_char(re); 353*a5ecbe62SWolfgang Denk if (esc & 0xff00) 354*a5ecbe62SWolfgang Denk emit(r, esc >> 8); 355*a5ecbe62SWolfgang Denk else 356*a5ecbe62SWolfgang Denk exact_one_char(r, esc); 357*a5ecbe62SWolfgang Denk break; 358*a5ecbe62SWolfgang Denk case '(': 359*a5ecbe62SWolfgang Denk last_op = r->code_size; 360*a5ecbe62SWolfgang Denk cap_no = ++r->num_caps; 361*a5ecbe62SWolfgang Denk emit(r, OPEN); 362*a5ecbe62SWolfgang Denk emit(r, cap_no); 363*a5ecbe62SWolfgang Denk 364*a5ecbe62SWolfgang Denk compile(r, re); 365*a5ecbe62SWolfgang Denk if (*(*re)++ != ')') { 366*a5ecbe62SWolfgang Denk r->err_str = "No closing bracket"; 367*a5ecbe62SWolfgang Denk return; 368*a5ecbe62SWolfgang Denk } 369*a5ecbe62SWolfgang Denk 370*a5ecbe62SWolfgang Denk emit(r, CLOSE); 371*a5ecbe62SWolfgang Denk emit(r, cap_no); 372*a5ecbe62SWolfgang Denk break; 373*a5ecbe62SWolfgang Denk case ')': 374*a5ecbe62SWolfgang Denk (*re)--; 375*a5ecbe62SWolfgang Denk fixup_branch(r, fixup); 376*a5ecbe62SWolfgang Denk if (level == 0) { 377*a5ecbe62SWolfgang Denk r->err_str = "Unbalanced brackets"; 378*a5ecbe62SWolfgang Denk return; 379*a5ecbe62SWolfgang Denk } 380*a5ecbe62SWolfgang Denk return; 381*a5ecbe62SWolfgang Denk /* NOTREACHED */ 382*a5ecbe62SWolfgang Denk break; 383*a5ecbe62SWolfgang Denk case '+': 384*a5ecbe62SWolfgang Denk case '*': 385*a5ecbe62SWolfgang Denk op = (*re)[-1] == '*' ? STAR : PLUS; 386*a5ecbe62SWolfgang Denk if (**re == '?') { 387*a5ecbe62SWolfgang Denk (*re)++; 388*a5ecbe62SWolfgang Denk op = op == STAR ? STARQ : PLUSQ; 389*a5ecbe62SWolfgang Denk } 390*a5ecbe62SWolfgang Denk quantifier(r, last_op, op); 391*a5ecbe62SWolfgang Denk break; 392*a5ecbe62SWolfgang Denk case '?': 393*a5ecbe62SWolfgang Denk quantifier(r, last_op, QUEST); 394*a5ecbe62SWolfgang Denk break; 395*a5ecbe62SWolfgang Denk case '|': 396*a5ecbe62SWolfgang Denk fixup_branch(r, fixup); 397*a5ecbe62SWolfgang Denk relocate(r, branch_start, 3); 398*a5ecbe62SWolfgang Denk r->code[branch_start] = BRANCH; 399*a5ecbe62SWolfgang Denk set_jump_offset(r, branch_start + 1, branch_start); 400*a5ecbe62SWolfgang Denk fixup = branch_start + 2; 401*a5ecbe62SWolfgang Denk r->code[fixup] = 0xff; 402*a5ecbe62SWolfgang Denk break; 403*a5ecbe62SWolfgang Denk default: 404*a5ecbe62SWolfgang Denk (*re)--; 405*a5ecbe62SWolfgang Denk last_op = r->code_size; 406*a5ecbe62SWolfgang Denk exact(r, re); 407*a5ecbe62SWolfgang Denk break; 408*a5ecbe62SWolfgang Denk } 409*a5ecbe62SWolfgang Denk } 410*a5ecbe62SWolfgang Denk 411*a5ecbe62SWolfgang Denk int 412*a5ecbe62SWolfgang Denk slre_compile(struct slre *r, const char *re) 413*a5ecbe62SWolfgang Denk { 414*a5ecbe62SWolfgang Denk r->err_str = NULL; 415*a5ecbe62SWolfgang Denk r->code_size = r->data_size = r->num_caps = r->anchored = 0; 416*a5ecbe62SWolfgang Denk 417*a5ecbe62SWolfgang Denk if (*re == '^') 418*a5ecbe62SWolfgang Denk r->anchored++; 419*a5ecbe62SWolfgang Denk 420*a5ecbe62SWolfgang Denk emit(r, OPEN); /* This will capture what matches full RE */ 421*a5ecbe62SWolfgang Denk emit(r, 0); 422*a5ecbe62SWolfgang Denk 423*a5ecbe62SWolfgang Denk while (*re != '\0') 424*a5ecbe62SWolfgang Denk compile(r, &re); 425*a5ecbe62SWolfgang Denk 426*a5ecbe62SWolfgang Denk if (r->code[2] == BRANCH) 427*a5ecbe62SWolfgang Denk fixup_branch(r, 4); 428*a5ecbe62SWolfgang Denk 429*a5ecbe62SWolfgang Denk emit(r, CLOSE); 430*a5ecbe62SWolfgang Denk emit(r, 0); 431*a5ecbe62SWolfgang Denk emit(r, END); 432*a5ecbe62SWolfgang Denk 433*a5ecbe62SWolfgang Denk return (r->err_str == NULL ? 1 : 0); 434*a5ecbe62SWolfgang Denk } 435*a5ecbe62SWolfgang Denk 436*a5ecbe62SWolfgang Denk static int match(const struct slre *, int, 437*a5ecbe62SWolfgang Denk const char *, int, int *, struct cap *); 438*a5ecbe62SWolfgang Denk 439*a5ecbe62SWolfgang Denk static void 440*a5ecbe62SWolfgang Denk loop_greedy(const struct slre *r, int pc, const char *s, int len, int *ofs) 441*a5ecbe62SWolfgang Denk { 442*a5ecbe62SWolfgang Denk int saved_offset, matched_offset; 443*a5ecbe62SWolfgang Denk 444*a5ecbe62SWolfgang Denk saved_offset = matched_offset = *ofs; 445*a5ecbe62SWolfgang Denk 446*a5ecbe62SWolfgang Denk while (match(r, pc + 2, s, len, ofs, NULL)) { 447*a5ecbe62SWolfgang Denk saved_offset = *ofs; 448*a5ecbe62SWolfgang Denk if (match(r, pc + r->code[pc + 1], s, len, ofs, NULL)) 449*a5ecbe62SWolfgang Denk matched_offset = saved_offset; 450*a5ecbe62SWolfgang Denk *ofs = saved_offset; 451*a5ecbe62SWolfgang Denk } 452*a5ecbe62SWolfgang Denk 453*a5ecbe62SWolfgang Denk *ofs = matched_offset; 454*a5ecbe62SWolfgang Denk } 455*a5ecbe62SWolfgang Denk 456*a5ecbe62SWolfgang Denk static void 457*a5ecbe62SWolfgang Denk loop_non_greedy(const struct slre *r, int pc, const char *s, int len, int *ofs) 458*a5ecbe62SWolfgang Denk { 459*a5ecbe62SWolfgang Denk int saved_offset = *ofs; 460*a5ecbe62SWolfgang Denk 461*a5ecbe62SWolfgang Denk while (match(r, pc + 2, s, len, ofs, NULL)) { 462*a5ecbe62SWolfgang Denk saved_offset = *ofs; 463*a5ecbe62SWolfgang Denk if (match(r, pc + r->code[pc + 1], s, len, ofs, NULL)) 464*a5ecbe62SWolfgang Denk break; 465*a5ecbe62SWolfgang Denk } 466*a5ecbe62SWolfgang Denk 467*a5ecbe62SWolfgang Denk *ofs = saved_offset; 468*a5ecbe62SWolfgang Denk } 469*a5ecbe62SWolfgang Denk 470*a5ecbe62SWolfgang Denk static int 471*a5ecbe62SWolfgang Denk is_any_of(const unsigned char *p, int len, const char *s, int *ofs) 472*a5ecbe62SWolfgang Denk { 473*a5ecbe62SWolfgang Denk int i, ch; 474*a5ecbe62SWolfgang Denk 475*a5ecbe62SWolfgang Denk ch = s[*ofs]; 476*a5ecbe62SWolfgang Denk 477*a5ecbe62SWolfgang Denk for (i = 0; i < len; i++) 478*a5ecbe62SWolfgang Denk if (p[i] == ch) { 479*a5ecbe62SWolfgang Denk (*ofs)++; 480*a5ecbe62SWolfgang Denk return 1; 481*a5ecbe62SWolfgang Denk } 482*a5ecbe62SWolfgang Denk 483*a5ecbe62SWolfgang Denk return 0; 484*a5ecbe62SWolfgang Denk } 485*a5ecbe62SWolfgang Denk 486*a5ecbe62SWolfgang Denk static int 487*a5ecbe62SWolfgang Denk is_any_but(const unsigned char *p, int len, const char *s, int *ofs) 488*a5ecbe62SWolfgang Denk { 489*a5ecbe62SWolfgang Denk int i, ch; 490*a5ecbe62SWolfgang Denk 491*a5ecbe62SWolfgang Denk ch = s[*ofs]; 492*a5ecbe62SWolfgang Denk 493*a5ecbe62SWolfgang Denk for (i = 0; i < len; i++) { 494*a5ecbe62SWolfgang Denk if (p[i] == ch) 495*a5ecbe62SWolfgang Denk return 0; 496*a5ecbe62SWolfgang Denk } 497*a5ecbe62SWolfgang Denk 498*a5ecbe62SWolfgang Denk (*ofs)++; 499*a5ecbe62SWolfgang Denk return 1; 500*a5ecbe62SWolfgang Denk } 501*a5ecbe62SWolfgang Denk 502*a5ecbe62SWolfgang Denk static int 503*a5ecbe62SWolfgang Denk match(const struct slre *r, int pc, const char *s, int len, 504*a5ecbe62SWolfgang Denk int *ofs, struct cap *caps) 505*a5ecbe62SWolfgang Denk { 506*a5ecbe62SWolfgang Denk int n, saved_offset, res = 1; 507*a5ecbe62SWolfgang Denk 508*a5ecbe62SWolfgang Denk while (res && r->code[pc] != END) { 509*a5ecbe62SWolfgang Denk 510*a5ecbe62SWolfgang Denk assert(pc < r->code_size); 511*a5ecbe62SWolfgang Denk assert(pc < (int) (sizeof(r->code) / sizeof(r->code[0]))); 512*a5ecbe62SWolfgang Denk 513*a5ecbe62SWolfgang Denk switch (r->code[pc]) { 514*a5ecbe62SWolfgang Denk case BRANCH: 515*a5ecbe62SWolfgang Denk saved_offset = *ofs; 516*a5ecbe62SWolfgang Denk res = match(r, pc + 3, s, len, ofs, caps); 517*a5ecbe62SWolfgang Denk if (res == 0) { 518*a5ecbe62SWolfgang Denk *ofs = saved_offset; 519*a5ecbe62SWolfgang Denk res = match(r, pc + r->code[pc + 1], 520*a5ecbe62SWolfgang Denk s, len, ofs, caps); 521*a5ecbe62SWolfgang Denk } 522*a5ecbe62SWolfgang Denk pc += r->code[pc + 2]; 523*a5ecbe62SWolfgang Denk break; 524*a5ecbe62SWolfgang Denk case EXACT: 525*a5ecbe62SWolfgang Denk res = 0; 526*a5ecbe62SWolfgang Denk n = r->code[pc + 2]; /* String length */ 527*a5ecbe62SWolfgang Denk if (n <= len - *ofs && !memcmp(s + *ofs, r->data + 528*a5ecbe62SWolfgang Denk r->code[pc + 1], n)) { 529*a5ecbe62SWolfgang Denk (*ofs) += n; 530*a5ecbe62SWolfgang Denk res = 1; 531*a5ecbe62SWolfgang Denk } 532*a5ecbe62SWolfgang Denk pc += 3; 533*a5ecbe62SWolfgang Denk break; 534*a5ecbe62SWolfgang Denk case QUEST: 535*a5ecbe62SWolfgang Denk res = 1; 536*a5ecbe62SWolfgang Denk saved_offset = *ofs; 537*a5ecbe62SWolfgang Denk if (!match(r, pc + 2, s, len, ofs, caps)) 538*a5ecbe62SWolfgang Denk *ofs = saved_offset; 539*a5ecbe62SWolfgang Denk pc += r->code[pc + 1]; 540*a5ecbe62SWolfgang Denk break; 541*a5ecbe62SWolfgang Denk case STAR: 542*a5ecbe62SWolfgang Denk res = 1; 543*a5ecbe62SWolfgang Denk loop_greedy(r, pc, s, len, ofs); 544*a5ecbe62SWolfgang Denk pc += r->code[pc + 1]; 545*a5ecbe62SWolfgang Denk break; 546*a5ecbe62SWolfgang Denk case STARQ: 547*a5ecbe62SWolfgang Denk res = 1; 548*a5ecbe62SWolfgang Denk loop_non_greedy(r, pc, s, len, ofs); 549*a5ecbe62SWolfgang Denk pc += r->code[pc + 1]; 550*a5ecbe62SWolfgang Denk break; 551*a5ecbe62SWolfgang Denk case PLUS: 552*a5ecbe62SWolfgang Denk res = match(r, pc + 2, s, len, ofs, caps); 553*a5ecbe62SWolfgang Denk if (res == 0) 554*a5ecbe62SWolfgang Denk break; 555*a5ecbe62SWolfgang Denk 556*a5ecbe62SWolfgang Denk loop_greedy(r, pc, s, len, ofs); 557*a5ecbe62SWolfgang Denk pc += r->code[pc + 1]; 558*a5ecbe62SWolfgang Denk break; 559*a5ecbe62SWolfgang Denk case PLUSQ: 560*a5ecbe62SWolfgang Denk res = match(r, pc + 2, s, len, ofs, caps); 561*a5ecbe62SWolfgang Denk if (res == 0) 562*a5ecbe62SWolfgang Denk break; 563*a5ecbe62SWolfgang Denk 564*a5ecbe62SWolfgang Denk loop_non_greedy(r, pc, s, len, ofs); 565*a5ecbe62SWolfgang Denk pc += r->code[pc + 1]; 566*a5ecbe62SWolfgang Denk break; 567*a5ecbe62SWolfgang Denk case SPACE: 568*a5ecbe62SWolfgang Denk res = 0; 569*a5ecbe62SWolfgang Denk if (*ofs < len && isspace(((unsigned char *)s)[*ofs])) { 570*a5ecbe62SWolfgang Denk (*ofs)++; 571*a5ecbe62SWolfgang Denk res = 1; 572*a5ecbe62SWolfgang Denk } 573*a5ecbe62SWolfgang Denk pc++; 574*a5ecbe62SWolfgang Denk break; 575*a5ecbe62SWolfgang Denk case NONSPACE: 576*a5ecbe62SWolfgang Denk res = 0; 577*a5ecbe62SWolfgang Denk if (*ofs < len && 578*a5ecbe62SWolfgang Denk !isspace(((unsigned char *)s)[*ofs])) { 579*a5ecbe62SWolfgang Denk (*ofs)++; 580*a5ecbe62SWolfgang Denk res = 1; 581*a5ecbe62SWolfgang Denk } 582*a5ecbe62SWolfgang Denk pc++; 583*a5ecbe62SWolfgang Denk break; 584*a5ecbe62SWolfgang Denk case DIGIT: 585*a5ecbe62SWolfgang Denk res = 0; 586*a5ecbe62SWolfgang Denk if (*ofs < len && isdigit(((unsigned char *)s)[*ofs])) { 587*a5ecbe62SWolfgang Denk (*ofs)++; 588*a5ecbe62SWolfgang Denk res = 1; 589*a5ecbe62SWolfgang Denk } 590*a5ecbe62SWolfgang Denk pc++; 591*a5ecbe62SWolfgang Denk break; 592*a5ecbe62SWolfgang Denk case ANY: 593*a5ecbe62SWolfgang Denk res = 0; 594*a5ecbe62SWolfgang Denk if (*ofs < len) { 595*a5ecbe62SWolfgang Denk (*ofs)++; 596*a5ecbe62SWolfgang Denk res = 1; 597*a5ecbe62SWolfgang Denk } 598*a5ecbe62SWolfgang Denk pc++; 599*a5ecbe62SWolfgang Denk break; 600*a5ecbe62SWolfgang Denk case ANYOF: 601*a5ecbe62SWolfgang Denk res = 0; 602*a5ecbe62SWolfgang Denk if (*ofs < len) 603*a5ecbe62SWolfgang Denk res = is_any_of(r->data + r->code[pc + 1], 604*a5ecbe62SWolfgang Denk r->code[pc + 2], s, ofs); 605*a5ecbe62SWolfgang Denk pc += 3; 606*a5ecbe62SWolfgang Denk break; 607*a5ecbe62SWolfgang Denk case ANYBUT: 608*a5ecbe62SWolfgang Denk res = 0; 609*a5ecbe62SWolfgang Denk if (*ofs < len) 610*a5ecbe62SWolfgang Denk res = is_any_but(r->data + r->code[pc + 1], 611*a5ecbe62SWolfgang Denk r->code[pc + 2], s, ofs); 612*a5ecbe62SWolfgang Denk pc += 3; 613*a5ecbe62SWolfgang Denk break; 614*a5ecbe62SWolfgang Denk case BOL: 615*a5ecbe62SWolfgang Denk res = *ofs == 0 ? 1 : 0; 616*a5ecbe62SWolfgang Denk pc++; 617*a5ecbe62SWolfgang Denk break; 618*a5ecbe62SWolfgang Denk case EOL: 619*a5ecbe62SWolfgang Denk res = *ofs == len ? 1 : 0; 620*a5ecbe62SWolfgang Denk pc++; 621*a5ecbe62SWolfgang Denk break; 622*a5ecbe62SWolfgang Denk case OPEN: 623*a5ecbe62SWolfgang Denk if (caps != NULL) 624*a5ecbe62SWolfgang Denk caps[r->code[pc + 1]].ptr = s + *ofs; 625*a5ecbe62SWolfgang Denk pc += 2; 626*a5ecbe62SWolfgang Denk break; 627*a5ecbe62SWolfgang Denk case CLOSE: 628*a5ecbe62SWolfgang Denk if (caps != NULL) 629*a5ecbe62SWolfgang Denk caps[r->code[pc + 1]].len = (s + *ofs) - 630*a5ecbe62SWolfgang Denk caps[r->code[pc + 1]].ptr; 631*a5ecbe62SWolfgang Denk pc += 2; 632*a5ecbe62SWolfgang Denk break; 633*a5ecbe62SWolfgang Denk case END: 634*a5ecbe62SWolfgang Denk pc++; 635*a5ecbe62SWolfgang Denk break; 636*a5ecbe62SWolfgang Denk default: 637*a5ecbe62SWolfgang Denk printf("unknown cmd (%d) at %d\n", r->code[pc], pc); 638*a5ecbe62SWolfgang Denk assert(0); 639*a5ecbe62SWolfgang Denk break; 640*a5ecbe62SWolfgang Denk } 641*a5ecbe62SWolfgang Denk } 642*a5ecbe62SWolfgang Denk 643*a5ecbe62SWolfgang Denk return res; 644*a5ecbe62SWolfgang Denk } 645*a5ecbe62SWolfgang Denk 646*a5ecbe62SWolfgang Denk int 647*a5ecbe62SWolfgang Denk slre_match(const struct slre *r, const char *buf, int len, 648*a5ecbe62SWolfgang Denk struct cap *caps) 649*a5ecbe62SWolfgang Denk { 650*a5ecbe62SWolfgang Denk int i, ofs = 0, res = 0; 651*a5ecbe62SWolfgang Denk 652*a5ecbe62SWolfgang Denk if (r->anchored) { 653*a5ecbe62SWolfgang Denk res = match(r, 0, buf, len, &ofs, caps); 654*a5ecbe62SWolfgang Denk } else { 655*a5ecbe62SWolfgang Denk for (i = 0; i < len && res == 0; i++) { 656*a5ecbe62SWolfgang Denk ofs = i; 657*a5ecbe62SWolfgang Denk res = match(r, 0, buf, len, &ofs, caps); 658*a5ecbe62SWolfgang Denk } 659*a5ecbe62SWolfgang Denk } 660*a5ecbe62SWolfgang Denk 661*a5ecbe62SWolfgang Denk return res; 662*a5ecbe62SWolfgang Denk } 663*a5ecbe62SWolfgang Denk 664*a5ecbe62SWolfgang Denk #ifdef SLRE_TEST 665*a5ecbe62SWolfgang Denk #define N_CAPS 5 666*a5ecbe62SWolfgang Denk 667*a5ecbe62SWolfgang Denk int main(int argc, char *argv[]) 668*a5ecbe62SWolfgang Denk { 669*a5ecbe62SWolfgang Denk struct slre slre; 670*a5ecbe62SWolfgang Denk struct cap caps[N_CAPS]; 671*a5ecbe62SWolfgang Denk unsigned char data[1 * 1024 * 1024]; 672*a5ecbe62SWolfgang Denk FILE *fp; 673*a5ecbe62SWolfgang Denk int i, res, len; 674*a5ecbe62SWolfgang Denk 675*a5ecbe62SWolfgang Denk if (argc < 2) { 676*a5ecbe62SWolfgang Denk fprintf(stderr, "Usage: %s 'slre' <file>\n", argv[0]); 677*a5ecbe62SWolfgang Denk return 1; 678*a5ecbe62SWolfgang Denk } 679*a5ecbe62SWolfgang Denk 680*a5ecbe62SWolfgang Denk fp = fopen(argv[2], "rb"); 681*a5ecbe62SWolfgang Denk if (fp == NULL) { 682*a5ecbe62SWolfgang Denk fprintf(stderr, "Error: cannot open %s:%s\n", 683*a5ecbe62SWolfgang Denk argv[2], strerror(errno)); 684*a5ecbe62SWolfgang Denk return 1; 685*a5ecbe62SWolfgang Denk } 686*a5ecbe62SWolfgang Denk 687*a5ecbe62SWolfgang Denk if (!slre_compile(&slre, argv[1])) { 688*a5ecbe62SWolfgang Denk fprintf(stderr, "Error compiling slre: %s\n", slre.err_str); 689*a5ecbe62SWolfgang Denk return 1; 690*a5ecbe62SWolfgang Denk } 691*a5ecbe62SWolfgang Denk 692*a5ecbe62SWolfgang Denk slre_dump(&slre, stderr); 693*a5ecbe62SWolfgang Denk 694*a5ecbe62SWolfgang Denk while (fgets(data, sizeof(data), fp) != NULL) { 695*a5ecbe62SWolfgang Denk len = strlen(data); 696*a5ecbe62SWolfgang Denk 697*a5ecbe62SWolfgang Denk if ((len > 0) && (data[len-1] == '\n')) { 698*a5ecbe62SWolfgang Denk data[len-1] = '\0'; 699*a5ecbe62SWolfgang Denk --len; 700*a5ecbe62SWolfgang Denk } 701*a5ecbe62SWolfgang Denk 702*a5ecbe62SWolfgang Denk printf("Data = \"%s\"\n", data); 703*a5ecbe62SWolfgang Denk 704*a5ecbe62SWolfgang Denk (void) memset(caps, 0, sizeof(caps)); 705*a5ecbe62SWolfgang Denk 706*a5ecbe62SWolfgang Denk res = 0; 707*a5ecbe62SWolfgang Denk 708*a5ecbe62SWolfgang Denk res = slre_match(&slre, data, len, caps); 709*a5ecbe62SWolfgang Denk printf("Result [%d]: %d\n", i, res); 710*a5ecbe62SWolfgang Denk 711*a5ecbe62SWolfgang Denk for (i = 0; i < N_CAPS; i++) { 712*a5ecbe62SWolfgang Denk if (caps[i].len > 0) { 713*a5ecbe62SWolfgang Denk printf("Substring %d: len=%d [%.*s]\n", i, 714*a5ecbe62SWolfgang Denk caps[i].len, 715*a5ecbe62SWolfgang Denk caps[i].len, caps[i].ptr); 716*a5ecbe62SWolfgang Denk } 717*a5ecbe62SWolfgang Denk } 718*a5ecbe62SWolfgang Denk printf("----------------------------------------------------\n"); 719*a5ecbe62SWolfgang Denk } 720*a5ecbe62SWolfgang Denk (void) fclose(fp); 721*a5ecbe62SWolfgang Denk 722*a5ecbe62SWolfgang Denk return 0; 723*a5ecbe62SWolfgang Denk } 724*a5ecbe62SWolfgang Denk #endif /* SLRE_TEST */ 725