725 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			725 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
/*
 | 
						|
 * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com>
 | 
						|
 * All rights reserved
 | 
						|
 *
 | 
						|
 * "THE BEER-WARE LICENSE" (Revision 42):
 | 
						|
 * Sergey Lyubka wrote this file.  As long as you retain this notice you
 | 
						|
 * can do whatever you want with this stuff. If we meet some day, and you think
 | 
						|
 * this stuff is worth it, you can buy me a beer in return.
 | 
						|
 */
 | 
						|
 | 
						|
/*
 | 
						|
 * Downloaded Sat Nov  5 17:43:06 CET 2011 at
 | 
						|
 * http://slre.sourceforge.net/1.0/slre.c
 | 
						|
 */
 | 
						|
 | 
						|
#ifdef SLRE_TEST
 | 
						|
#include <stdio.h>
 | 
						|
#include <assert.h>
 | 
						|
#include <ctype.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <string.h>
 | 
						|
#else
 | 
						|
#include <common.h>
 | 
						|
#include <linux/ctype.h>
 | 
						|
#endif /* SLRE_TEST */
 | 
						|
 | 
						|
#include <errno.h>
 | 
						|
 | 
						|
#include <slre.h>
 | 
						|
 | 
						|
enum {END, BRANCH, ANY, EXACT, ANYOF, ANYBUT, OPEN, CLOSE, BOL, EOL,
 | 
						|
	STAR, PLUS, STARQ, PLUSQ, QUEST, SPACE, NONSPACE, DIGIT};
 | 
						|
 | 
						|
#ifdef SLRE_TEST
 | 
						|
static struct {
 | 
						|
	const char	*name;
 | 
						|
	int		narg;
 | 
						|
	const char	*flags;
 | 
						|
} opcodes[] = {
 | 
						|
	{"END",		0, ""},		/* End of code block or program	*/
 | 
						|
	{"BRANCH",	2, "oo"},	/* Alternative operator, "|"	*/
 | 
						|
	{"ANY",		0, ""},		/* Match any character, "."	*/
 | 
						|
	{"EXACT",	2, "d"},	/* Match exact string		*/
 | 
						|
	{"ANYOF",	2, "D"},	/* Match any from set, "[]"	*/
 | 
						|
	{"ANYBUT",	2, "D"},	/* Match any but from set, "[^]"*/
 | 
						|
	{"OPEN ",	1, "i"},	/* Capture start, "("		*/
 | 
						|
	{"CLOSE",	1, "i"},	/* Capture end, ")"		*/
 | 
						|
	{"BOL",		0, ""},		/* Beginning of string, "^"	*/
 | 
						|
	{"EOL",		0, ""},		/* End of string, "$"		*/
 | 
						|
	{"STAR",	1, "o"},	/* Match zero or more times "*"	*/
 | 
						|
	{"PLUS",	1, "o"},	/* Match one or more times, "+"	*/
 | 
						|
	{"STARQ",	1, "o"},	/* Non-greedy STAR,  "*?"	*/
 | 
						|
	{"PLUSQ",	1, "o"},	/* Non-greedy PLUS, "+?"	*/
 | 
						|
	{"QUEST",	1, "o"},	/* Match zero or one time, "?"	*/
 | 
						|
	{"SPACE",	0, ""},		/* Match whitespace, "\s"	*/
 | 
						|
	{"NONSPACE",	0, ""},		/* Match non-space, "\S"	*/
 | 
						|
	{"DIGIT",	0, ""}		/* Match digit, "\d"		*/
 | 
						|
};
 | 
						|
#endif /* SLRE_TEST */
 | 
						|
 | 
						|
/*
 | 
						|
 * Commands and operands are all unsigned char (1 byte long). All code offsets
 | 
						|
 * are relative to current address, and positive (always point forward). Data
 | 
						|
 * offsets are absolute. Commands with operands:
 | 
						|
 *
 | 
						|
 * BRANCH offset1 offset2
 | 
						|
 *	Try to match the code block that follows the BRANCH instruction
 | 
						|
 *	(code block ends with END). If no match, try to match code block that
 | 
						|
 *	starts at offset1. If either of these match, jump to offset2.
 | 
						|
 *
 | 
						|
 * EXACT data_offset data_length
 | 
						|
 *	Try to match exact string. String is recorded in data section from
 | 
						|
 *	data_offset, and has length data_length.
 | 
						|
 *
 | 
						|
 * OPEN capture_number
 | 
						|
 * CLOSE capture_number
 | 
						|
 *	If the user have passed 'struct cap' array for captures, OPEN
 | 
						|
 *	records the beginning of the matched substring (cap->ptr), CLOSE
 | 
						|
 *	sets the length (cap->len) for respective capture_number.
 | 
						|
 *
 | 
						|
 * STAR code_offset
 | 
						|
 * PLUS code_offset
 | 
						|
 * QUEST code_offset
 | 
						|
 *	*, +, ?, respectively. Try to gobble as much as possible from the
 | 
						|
 *	matched buffer, until code block that follows these instructions
 | 
						|
 *	matches. When the longest possible string is matched,
 | 
						|
 *	jump to code_offset
 | 
						|
 *
 | 
						|
 * STARQ, PLUSQ are non-greedy versions of STAR and PLUS.
 | 
						|
 */
 | 
						|
 | 
						|
static const char *meta_chars = "|.^$*+?()[\\";
 | 
						|
 | 
						|
#ifdef SLRE_TEST
 | 
						|
 | 
						|
static void
 | 
						|
print_character_set(FILE *fp, const unsigned char *p, int len)
 | 
						|
{
 | 
						|
	int	i;
 | 
						|
 | 
						|
	for (i = 0; i < len; i++) {
 | 
						|
		if (i > 0)
 | 
						|
			(void) fputc(',', fp);
 | 
						|
		if (p[i] == 0) {
 | 
						|
			i++;
 | 
						|
			if (p[i] == 0)
 | 
						|
				(void) fprintf(fp, "\\x%02x", p[i]);
 | 
						|
			else
 | 
						|
				(void) fprintf(fp, "%s", opcodes[p[i]].name);
 | 
						|
		} else if (isprint(p[i])) {
 | 
						|
			(void) fputc(p[i], fp);
 | 
						|
		} else {
 | 
						|
			(void) fprintf(fp, "\\x%02x", p[i]);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
slre_dump(const struct slre *r, FILE *fp)
 | 
						|
{
 | 
						|
	int	i, j, ch, op, pc;
 | 
						|
 | 
						|
	for (pc = 0; pc < r->code_size; pc++) {
 | 
						|
 | 
						|
		op = r->code[pc];
 | 
						|
		(void) fprintf(fp, "%3d %s ", pc, opcodes[op].name);
 | 
						|
 | 
						|
		for (i = 0; opcodes[op].flags[i] != '\0'; i++)
 | 
						|
			switch (opcodes[op].flags[i]) {
 | 
						|
			case 'i':
 | 
						|
				(void) fprintf(fp, "%d ", r->code[pc + 1]);
 | 
						|
				pc++;
 | 
						|
				break;
 | 
						|
			case 'o':
 | 
						|
				(void) fprintf(fp, "%d ",
 | 
						|
				    pc + r->code[pc + 1] - i);
 | 
						|
				pc++;
 | 
						|
				break;
 | 
						|
			case 'D':
 | 
						|
				print_character_set(fp, r->data +
 | 
						|
				    r->code[pc + 1], r->code[pc + 2]);
 | 
						|
				pc += 2;
 | 
						|
				break;
 | 
						|
			case 'd':
 | 
						|
				(void) fputc('"', fp);
 | 
						|
				for (j = 0; j < r->code[pc + 2]; j++) {
 | 
						|
					ch = r->data[r->code[pc + 1] + j];
 | 
						|
					if (isprint(ch)) {
 | 
						|
						(void) fputc(ch, fp);
 | 
						|
					} else {
 | 
						|
						(void) fprintf(fp,
 | 
						|
							"\\x%02x", ch);
 | 
						|
					}
 | 
						|
				}
 | 
						|
				(void) fputc('"', fp);
 | 
						|
				pc += 2;
 | 
						|
				break;
 | 
						|
			}
 | 
						|
 | 
						|
		(void) fputc('\n', fp);
 | 
						|
	}
 | 
						|
}
 | 
						|
#endif /* SLRE_TEST */
 | 
						|
 | 
						|
static void
 | 
						|
set_jump_offset(struct slre *r, int pc, int offset)
 | 
						|
{
 | 
						|
	assert(offset < r->code_size);
 | 
						|
 | 
						|
	if (r->code_size - offset > 0xff)
 | 
						|
		r->err_str = "Jump offset is too big";
 | 
						|
	else
 | 
						|
		r->code[pc] = (unsigned char) (r->code_size - offset);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
emit(struct slre *r, int code)
 | 
						|
{
 | 
						|
	if (r->code_size >= (int) (sizeof(r->code) / sizeof(r->code[0])))
 | 
						|
		r->err_str = "RE is too long (code overflow)";
 | 
						|
	else
 | 
						|
		r->code[r->code_size++] = (unsigned char) code;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
store_char_in_data(struct slre *r, int ch)
 | 
						|
{
 | 
						|
	if (r->data_size >= (int) sizeof(r->data))
 | 
						|
		r->err_str = "RE is too long (data overflow)";
 | 
						|
	else
 | 
						|
		r->data[r->data_size++] = ch;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
exact(struct slre *r, const char **re)
 | 
						|
{
 | 
						|
	int	old_data_size = r->data_size;
 | 
						|
 | 
						|
	while (**re != '\0' && (strchr(meta_chars, **re)) == NULL)
 | 
						|
		store_char_in_data(r, *(*re)++);
 | 
						|
 | 
						|
	emit(r, EXACT);
 | 
						|
	emit(r, old_data_size);
 | 
						|
	emit(r, r->data_size - old_data_size);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
get_escape_char(const char **re)
 | 
						|
{
 | 
						|
	int	res;
 | 
						|
 | 
						|
	switch (*(*re)++) {
 | 
						|
	case 'n':
 | 
						|
		res = '\n';
 | 
						|
		break;
 | 
						|
	case 'r':
 | 
						|
		res = '\r';
 | 
						|
		break;
 | 
						|
	case 't':
 | 
						|
		res = '\t';
 | 
						|
		break;
 | 
						|
	case '0':
 | 
						|
		res = 0;
 | 
						|
		break;
 | 
						|
	case 'S':
 | 
						|
		res = NONSPACE << 8;
 | 
						|
		break;
 | 
						|
	case 's':
 | 
						|
		res = SPACE << 8;
 | 
						|
		break;
 | 
						|
	case 'd':
 | 
						|
		res = DIGIT << 8;
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		res = (*re)[-1];
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
	return res;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
anyof(struct slre *r, const char **re)
 | 
						|
{
 | 
						|
	int	esc, old_data_size = r->data_size, op = ANYOF;
 | 
						|
 | 
						|
	if (**re == '^') {
 | 
						|
		op = ANYBUT;
 | 
						|
		(*re)++;
 | 
						|
	}
 | 
						|
 | 
						|
	while (**re != '\0')
 | 
						|
 | 
						|
		switch (*(*re)++) {
 | 
						|
		case ']':
 | 
						|
			emit(r, op);
 | 
						|
			emit(r, old_data_size);
 | 
						|
			emit(r, r->data_size - old_data_size);
 | 
						|
			return;
 | 
						|
			/* NOTREACHED */
 | 
						|
			break;
 | 
						|
		case '\\':
 | 
						|
			esc = get_escape_char(re);
 | 
						|
			if ((esc & 0xff) == 0) {
 | 
						|
				store_char_in_data(r, 0);
 | 
						|
				store_char_in_data(r, esc >> 8);
 | 
						|
			} else {
 | 
						|
				store_char_in_data(r, esc);
 | 
						|
			}
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			store_char_in_data(r, (*re)[-1]);
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
	r->err_str = "No closing ']' bracket";
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
relocate(struct slre *r, int begin, int shift)
 | 
						|
{
 | 
						|
	emit(r, END);
 | 
						|
	memmove(r->code + begin + shift, r->code + begin, r->code_size - begin);
 | 
						|
	r->code_size += shift;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
quantifier(struct slre *r, int prev, int op)
 | 
						|
{
 | 
						|
	if (r->code[prev] == EXACT && r->code[prev + 2] > 1) {
 | 
						|
		r->code[prev + 2]--;
 | 
						|
		emit(r, EXACT);
 | 
						|
		emit(r, r->code[prev + 1] + r->code[prev + 2]);
 | 
						|
		emit(r, 1);
 | 
						|
		prev = r->code_size - 3;
 | 
						|
	}
 | 
						|
	relocate(r, prev, 2);
 | 
						|
	r->code[prev] = op;
 | 
						|
	set_jump_offset(r, prev + 1, prev);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
exact_one_char(struct slre *r, int ch)
 | 
						|
{
 | 
						|
	emit(r, EXACT);
 | 
						|
	emit(r, r->data_size);
 | 
						|
	emit(r, 1);
 | 
						|
	store_char_in_data(r, ch);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
fixup_branch(struct slre *r, int fixup)
 | 
						|
{
 | 
						|
	if (fixup > 0) {
 | 
						|
		emit(r, END);
 | 
						|
		set_jump_offset(r, fixup, fixup - 2);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
compile(struct slre *r, const char **re)
 | 
						|
{
 | 
						|
	int	op, esc, branch_start, last_op, fixup, cap_no, level;
 | 
						|
 | 
						|
	fixup = 0;
 | 
						|
	level = r->num_caps;
 | 
						|
	branch_start = last_op = r->code_size;
 | 
						|
 | 
						|
	for (;;)
 | 
						|
		switch (*(*re)++) {
 | 
						|
		case '\0':
 | 
						|
			(*re)--;
 | 
						|
			return;
 | 
						|
			/* NOTREACHED */
 | 
						|
			break;
 | 
						|
		case '^':
 | 
						|
			emit(r, BOL);
 | 
						|
			break;
 | 
						|
		case '$':
 | 
						|
			emit(r, EOL);
 | 
						|
			break;
 | 
						|
		case '.':
 | 
						|
			last_op = r->code_size;
 | 
						|
			emit(r, ANY);
 | 
						|
			break;
 | 
						|
		case '[':
 | 
						|
			last_op = r->code_size;
 | 
						|
			anyof(r, re);
 | 
						|
			break;
 | 
						|
		case '\\':
 | 
						|
			last_op = r->code_size;
 | 
						|
			esc = get_escape_char(re);
 | 
						|
			if (esc & 0xff00)
 | 
						|
				emit(r, esc >> 8);
 | 
						|
			else
 | 
						|
				exact_one_char(r, esc);
 | 
						|
			break;
 | 
						|
		case '(':
 | 
						|
			last_op = r->code_size;
 | 
						|
			cap_no = ++r->num_caps;
 | 
						|
			emit(r, OPEN);
 | 
						|
			emit(r, cap_no);
 | 
						|
 | 
						|
			compile(r, re);
 | 
						|
			if (*(*re)++ != ')') {
 | 
						|
				r->err_str = "No closing bracket";
 | 
						|
				return;
 | 
						|
			}
 | 
						|
 | 
						|
			emit(r, CLOSE);
 | 
						|
			emit(r, cap_no);
 | 
						|
			break;
 | 
						|
		case ')':
 | 
						|
			(*re)--;
 | 
						|
			fixup_branch(r, fixup);
 | 
						|
			if (level == 0) {
 | 
						|
				r->err_str = "Unbalanced brackets";
 | 
						|
				return;
 | 
						|
			}
 | 
						|
			return;
 | 
						|
			/* NOTREACHED */
 | 
						|
			break;
 | 
						|
		case '+':
 | 
						|
		case '*':
 | 
						|
			op = (*re)[-1] == '*' ? STAR : PLUS;
 | 
						|
			if (**re == '?') {
 | 
						|
				(*re)++;
 | 
						|
				op = op == STAR ? STARQ : PLUSQ;
 | 
						|
			}
 | 
						|
			quantifier(r, last_op, op);
 | 
						|
			break;
 | 
						|
		case '?':
 | 
						|
			quantifier(r, last_op, QUEST);
 | 
						|
			break;
 | 
						|
		case '|':
 | 
						|
			fixup_branch(r, fixup);
 | 
						|
			relocate(r, branch_start, 3);
 | 
						|
			r->code[branch_start] = BRANCH;
 | 
						|
			set_jump_offset(r, branch_start + 1, branch_start);
 | 
						|
			fixup = branch_start + 2;
 | 
						|
			r->code[fixup] = 0xff;
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			(*re)--;
 | 
						|
			last_op = r->code_size;
 | 
						|
			exact(r, re);
 | 
						|
			break;
 | 
						|
		}
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
slre_compile(struct slre *r, const char *re)
 | 
						|
{
 | 
						|
	r->err_str = NULL;
 | 
						|
	r->code_size = r->data_size = r->num_caps = r->anchored = 0;
 | 
						|
 | 
						|
	if (*re == '^')
 | 
						|
		r->anchored++;
 | 
						|
 | 
						|
	emit(r, OPEN);	/* This will capture what matches full RE */
 | 
						|
	emit(r, 0);
 | 
						|
 | 
						|
	while (*re != '\0')
 | 
						|
		compile(r, &re);
 | 
						|
 | 
						|
	if (r->code[2] == BRANCH)
 | 
						|
		fixup_branch(r, 4);
 | 
						|
 | 
						|
	emit(r, CLOSE);
 | 
						|
	emit(r, 0);
 | 
						|
	emit(r, END);
 | 
						|
 | 
						|
	return (r->err_str == NULL ? 1 : 0);
 | 
						|
}
 | 
						|
 | 
						|
static int match(const struct slre *, int,
 | 
						|
		const char *, int, int *, struct cap *);
 | 
						|
 | 
						|
static void
 | 
						|
loop_greedy(const struct slre *r, int pc, const char *s, int len, int *ofs)
 | 
						|
{
 | 
						|
	int	saved_offset, matched_offset;
 | 
						|
 | 
						|
	saved_offset = matched_offset = *ofs;
 | 
						|
 | 
						|
	while (match(r, pc + 2, s, len, ofs, NULL)) {
 | 
						|
		saved_offset = *ofs;
 | 
						|
		if (match(r, pc + r->code[pc + 1], s, len, ofs, NULL))
 | 
						|
			matched_offset = saved_offset;
 | 
						|
		*ofs = saved_offset;
 | 
						|
	}
 | 
						|
 | 
						|
	*ofs = matched_offset;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
loop_non_greedy(const struct slre *r, int pc, const char *s, int len, int *ofs)
 | 
						|
{
 | 
						|
	int	saved_offset = *ofs;
 | 
						|
 | 
						|
	while (match(r, pc + 2, s, len, ofs, NULL)) {
 | 
						|
		saved_offset = *ofs;
 | 
						|
		if (match(r, pc + r->code[pc + 1], s, len, ofs, NULL))
 | 
						|
			break;
 | 
						|
	}
 | 
						|
 | 
						|
	*ofs = saved_offset;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
is_any_of(const unsigned char *p, int len, const char *s, int *ofs)
 | 
						|
{
 | 
						|
	int	i, ch;
 | 
						|
 | 
						|
	ch = s[*ofs];
 | 
						|
 | 
						|
	for (i = 0; i < len; i++)
 | 
						|
		if (p[i] == ch) {
 | 
						|
			(*ofs)++;
 | 
						|
			return 1;
 | 
						|
		}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
is_any_but(const unsigned char *p, int len, const char *s, int *ofs)
 | 
						|
{
 | 
						|
	int	i, ch;
 | 
						|
 | 
						|
	ch = s[*ofs];
 | 
						|
 | 
						|
	for (i = 0; i < len; i++) {
 | 
						|
		if (p[i] == ch)
 | 
						|
			return 0;
 | 
						|
	}
 | 
						|
 | 
						|
	(*ofs)++;
 | 
						|
	return 1;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
match(const struct slre *r, int pc, const char *s, int len,
 | 
						|
		int *ofs, struct cap *caps)
 | 
						|
{
 | 
						|
	int	n, saved_offset, res = 1;
 | 
						|
 | 
						|
	while (res && r->code[pc] != END) {
 | 
						|
 | 
						|
		assert(pc < r->code_size);
 | 
						|
		assert(pc < (int) (sizeof(r->code) / sizeof(r->code[0])));
 | 
						|
 | 
						|
		switch (r->code[pc]) {
 | 
						|
		case BRANCH:
 | 
						|
			saved_offset = *ofs;
 | 
						|
			res = match(r, pc + 3, s, len, ofs, caps);
 | 
						|
			if (res == 0) {
 | 
						|
				*ofs = saved_offset;
 | 
						|
				res = match(r, pc + r->code[pc + 1],
 | 
						|
				    s, len, ofs, caps);
 | 
						|
			}
 | 
						|
			pc += r->code[pc + 2];
 | 
						|
			break;
 | 
						|
		case EXACT:
 | 
						|
			res = 0;
 | 
						|
			n = r->code[pc + 2];	/* String length */
 | 
						|
			if (n <= len - *ofs && !memcmp(s + *ofs, r->data +
 | 
						|
			    r->code[pc + 1], n)) {
 | 
						|
				(*ofs) += n;
 | 
						|
				res = 1;
 | 
						|
			}
 | 
						|
			pc += 3;
 | 
						|
			break;
 | 
						|
		case QUEST:
 | 
						|
			res = 1;
 | 
						|
			saved_offset = *ofs;
 | 
						|
			if (!match(r, pc + 2, s, len, ofs, caps))
 | 
						|
				*ofs = saved_offset;
 | 
						|
			pc += r->code[pc + 1];
 | 
						|
			break;
 | 
						|
		case STAR:
 | 
						|
			res = 1;
 | 
						|
			loop_greedy(r, pc, s, len, ofs);
 | 
						|
			pc += r->code[pc + 1];
 | 
						|
			break;
 | 
						|
		case STARQ:
 | 
						|
			res = 1;
 | 
						|
			loop_non_greedy(r, pc, s, len, ofs);
 | 
						|
			pc += r->code[pc + 1];
 | 
						|
			break;
 | 
						|
		case PLUS:
 | 
						|
			res = match(r, pc + 2, s, len, ofs, caps);
 | 
						|
			if (res == 0)
 | 
						|
				break;
 | 
						|
 | 
						|
			loop_greedy(r, pc, s, len, ofs);
 | 
						|
			pc += r->code[pc + 1];
 | 
						|
			break;
 | 
						|
		case PLUSQ:
 | 
						|
			res = match(r, pc + 2, s, len, ofs, caps);
 | 
						|
			if (res == 0)
 | 
						|
				break;
 | 
						|
 | 
						|
			loop_non_greedy(r, pc, s, len, ofs);
 | 
						|
			pc += r->code[pc + 1];
 | 
						|
			break;
 | 
						|
		case SPACE:
 | 
						|
			res = 0;
 | 
						|
			if (*ofs < len && isspace(((unsigned char *)s)[*ofs])) {
 | 
						|
				(*ofs)++;
 | 
						|
				res = 1;
 | 
						|
			}
 | 
						|
			pc++;
 | 
						|
			break;
 | 
						|
		case NONSPACE:
 | 
						|
			res = 0;
 | 
						|
			if (*ofs < len &&
 | 
						|
					!isspace(((unsigned char *)s)[*ofs])) {
 | 
						|
				(*ofs)++;
 | 
						|
				res = 1;
 | 
						|
			}
 | 
						|
			pc++;
 | 
						|
			break;
 | 
						|
		case DIGIT:
 | 
						|
			res = 0;
 | 
						|
			if (*ofs < len && isdigit(((unsigned char *)s)[*ofs])) {
 | 
						|
				(*ofs)++;
 | 
						|
				res = 1;
 | 
						|
			}
 | 
						|
			pc++;
 | 
						|
			break;
 | 
						|
		case ANY:
 | 
						|
			res = 0;
 | 
						|
			if (*ofs < len) {
 | 
						|
				(*ofs)++;
 | 
						|
				res = 1;
 | 
						|
			}
 | 
						|
			pc++;
 | 
						|
			break;
 | 
						|
		case ANYOF:
 | 
						|
			res = 0;
 | 
						|
			if (*ofs < len)
 | 
						|
				res = is_any_of(r->data + r->code[pc + 1],
 | 
						|
					r->code[pc + 2], s, ofs);
 | 
						|
			pc += 3;
 | 
						|
			break;
 | 
						|
		case ANYBUT:
 | 
						|
			res = 0;
 | 
						|
			if (*ofs < len)
 | 
						|
				res = is_any_but(r->data + r->code[pc + 1],
 | 
						|
					r->code[pc + 2], s, ofs);
 | 
						|
			pc += 3;
 | 
						|
			break;
 | 
						|
		case BOL:
 | 
						|
			res = *ofs == 0 ? 1 : 0;
 | 
						|
			pc++;
 | 
						|
			break;
 | 
						|
		case EOL:
 | 
						|
			res = *ofs == len ? 1 : 0;
 | 
						|
			pc++;
 | 
						|
			break;
 | 
						|
		case OPEN:
 | 
						|
			if (caps != NULL)
 | 
						|
				caps[r->code[pc + 1]].ptr = s + *ofs;
 | 
						|
			pc += 2;
 | 
						|
			break;
 | 
						|
		case CLOSE:
 | 
						|
			if (caps != NULL)
 | 
						|
				caps[r->code[pc + 1]].len = (s + *ofs) -
 | 
						|
				    caps[r->code[pc + 1]].ptr;
 | 
						|
			pc += 2;
 | 
						|
			break;
 | 
						|
		case END:
 | 
						|
			pc++;
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			printf("unknown cmd (%d) at %d\n", r->code[pc], pc);
 | 
						|
			assert(0);
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return res;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
slre_match(const struct slre *r, const char *buf, int len,
 | 
						|
		struct cap *caps)
 | 
						|
{
 | 
						|
	int	i, ofs = 0, res = 0;
 | 
						|
 | 
						|
	if (r->anchored) {
 | 
						|
		res = match(r, 0, buf, len, &ofs, caps);
 | 
						|
	} else {
 | 
						|
		for (i = 0; i < len && res == 0; i++) {
 | 
						|
			ofs = i;
 | 
						|
			res = match(r, 0, buf, len, &ofs, caps);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return res;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef SLRE_TEST
 | 
						|
#define N_CAPS	5
 | 
						|
 | 
						|
int main(int argc, char *argv[])
 | 
						|
{
 | 
						|
	struct slre	slre;
 | 
						|
	struct cap	caps[N_CAPS];
 | 
						|
	unsigned char	data[1 * 1024 * 1024];
 | 
						|
	FILE		*fp;
 | 
						|
	int		i, res, len;
 | 
						|
 | 
						|
	if (argc < 2) {
 | 
						|
		fprintf(stderr, "Usage: %s 'slre' <file>\n", argv[0]);
 | 
						|
		return 1;
 | 
						|
	}
 | 
						|
 | 
						|
	fp = fopen(argv[2], "rb");
 | 
						|
	if (fp == NULL) {
 | 
						|
		fprintf(stderr, "Error: cannot open %s:%s\n",
 | 
						|
			argv[2], strerror(errno));
 | 
						|
		return 1;
 | 
						|
	}
 | 
						|
 | 
						|
	if (!slre_compile(&slre, argv[1])) {
 | 
						|
		fprintf(stderr, "Error compiling slre: %s\n", slre.err_str);
 | 
						|
		return 1;
 | 
						|
	}
 | 
						|
 | 
						|
	slre_dump(&slre, stderr);
 | 
						|
 | 
						|
	while (fgets(data, sizeof(data), fp) != NULL) {
 | 
						|
		len = strlen(data);
 | 
						|
 | 
						|
		if ((len > 0) && (data[len-1] == '\n')) {
 | 
						|
			data[len-1] = '\0';
 | 
						|
			--len;
 | 
						|
		}
 | 
						|
 | 
						|
		printf("Data = \"%s\"\n", data);
 | 
						|
 | 
						|
		(void) memset(caps, 0, sizeof(caps));
 | 
						|
 | 
						|
		res = 0;
 | 
						|
 | 
						|
		res = slre_match(&slre, data, len, caps);
 | 
						|
		printf("Result [%d]: %d\n", i, res);
 | 
						|
 | 
						|
		for (i = 0; i < N_CAPS; i++) {
 | 
						|
			if (caps[i].len > 0) {
 | 
						|
				printf("Substring %d: len=%d  [%.*s]\n", i,
 | 
						|
					caps[i].len,
 | 
						|
					caps[i].len, caps[i].ptr);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		printf("----------------------------------------------------\n");
 | 
						|
	}
 | 
						|
	(void) fclose(fp);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
#endif /* SLRE_TEST */
 |