コード例 #1
0
/**
 * <p>
 * The given string contains a list of substrings separated by the
 * specified delimiter characters. The substrings may contain quoted
 * strings and/or contain backslash-escaped characters. The common
 * backslash escape sequences are supported and return their ASCII
 * values.
 * </p>
 *
 * @param string
 *	A list represented as a string.
 *
 * @param delims
 *	A set of delimiter characters.
 *
 * @param flags
 *
 *	TOKEN_KEEP_EMPTY
 *
 *	If false, then a run of one or more delimeters is treated as a
 *	single delimeter separating tokens. Otherwise each delimeter
 *	separates a token that may be empty.
 *
 *	string		true		false
 *	-------------------------------------------
 *	[a,b,c]		[a] [b] [c]	[a] [b] [c]
 *	[a,,c]		[a] [] [c]	[a] [c]
 *	[a,,]		[a] [] [] 	[a]
 *	[,,]		[] [] []	(null)
 *	[]		[]		(null)
 *
 *	TOKEN_KEEP_BACKSLASH
 *
 *	The token might have backslash escapes that are suppose to be
 *	part of the token, like a regex string /RE/ where you need to
 *	keep any "\/" between the open and closing slashes. We still
 *	need to recognise escapes and not convert them to a literal.
 *
 *	TOKEN_IGNORE_QUOTES
 *
 *	Disable any special processing of quoted substrings; quotes
 *	are treated as literals.
 *
 *	TOKEN_KEEP_ASIS
 *
 *	Shorthand for TOKEN_KEEP_BACKSLASH | TOKEN_IGNORE_QUOTES.
 *
 *	TOKEN_KEEP_BRACKETS
 *
 *	Split strings with brackets, keeping the open and close:
 *	parenthesis, "(" and ")"; angle brackets, "<" and ">"; square
 *	brackets, "[" and "]"; and/or braces, "{" and "}" grouped
 *	together. Both open and close brackets must in the set of
 *	delimiters. For example:
 *
 *	string		delims	vector
 *	-------------------------------------------
 *	"a{b}c"		"{}"	"a", "{b}", "c"
 *	"a{{b}}c"	"{}"	"a", "{{b}}", "c"
 *	"a{{b\{c}}d"	"{}"	"a", "{{b{c}}", "d"
 *	"a{{b[(<c}}d"	"{}"	"a", "{{b[(<c}}", "d"
 *	"a{b{c}{d}e}f"	"{}"	"a", "{b{c}{d}e}", "f"
 *	"<>a{b<c>d}<e>"	"{}<>"	"<>", "a", "{b<c>d}", "<e>", ""
 *
 * @return
 *	A vector of C strings.
 */
Vector
TextSplit(const char *string, const char *delims, int flags)
{
	char *token;
	Vector list;

	if ((list = VectorCreate(5)) == NULL)
		return NULL;

	VectorSetDestroyEntry(list, free);

	while ((token = TokenNext(string, &string, delims, flags)) != NULL)
		(void) VectorAdd(list, token);

	return list;
}
コード例 #2
0
static void
do_command(struct pattern_rule *rule, const char *command, const char *line, regmatch_t *parens)
{
	int err;
	char *cmd, *expand;

	/* Parse field="..." */
	cmd = TokenNext(strchr(command, '=')+1, NULL, "\n", TOKEN_KEEP_ASIS);

	/* Replace #n matched sub-expressions. */
	expand = replace_references('#', cmd, line, parens, rule->re.re_nsub);

	if (expand != NULL) {
		if ((err = system(expand)) < 0)
			(void) fprintf(stderr, "%s\n\t%s (%d)\n", expand, strerror(errno), errno);
		else if (0 < err)
			(void) fprintf(stderr, "%s\n\tcommand error %d\n", expand, err);
		free(expand);
	}
	free(cmd);
}
コード例 #3
0
/*
 * Pattern Rule Grammar
 * --------------------
 *
 * line := blank | "#" comment | rule
 *
 * rule := pattern *[ whitespace ] actions
 *
 * whitespace := SPACE | TAB
 *
 * pattern := "/" extended_regex "/"
 *
 * actions := action [ ";" actions ]
 *
 * action := thread | limit | report | on_exceed | on_expire
 *
 * quote := "'" | '"'
 *
 * index := number | quote text quote
 *
 * indices := index [ "," index ]
 *
 * thread := "t=" indices
 *
 * limit := "l=" indices "," max "/" period [ unit ]
 *
 * report := "r=" mail *[ "," mail ]
 *
 * on_exceed := "c=" quoted_shell_command
 *
 * on_expire := "C=" quoted_shell_command
 *
 * quoted_shell_command := quote text quote
 */
static int
init_rule(char *line)
{
	Vector fields;
	const char *next;
	struct pattern_rule *rule;
	int i, rc = -1, err;
	char *field, error[128];

	if (*line != '/')
		goto error0;
	if ((rule = calloc(1, sizeof (*rule))) == NULL)
		goto error0;
	if ((rule->pattern = TokenNext(line, &next, "/", TOKEN_KEEP_ASIS)) == NULL)
		goto error1;
	if ((fields = TextSplit(next, ";", TOKEN_KEEP_ASIS)) == NULL)
		goto error1;

	if ((err = regcomp(&rule->re, rule->pattern, REG_EXTENDED|REG_NEWLINE)) != 0) {
		(void) regerror(err, &rule->re, error, sizeof (error));
		(void) fprintf(stderr, "pattern /%s/: %s (%d)\n", rule->pattern, error, err);
		goto error2;
	}

	/* Assume new previously unknown pattern. */
	if ((err = sqlite3_bind_text(ctx.insert_pattern, 1, rule->pattern, -1, SQLITE_STATIC)) != SQLITE_OK) {
		sql_error(__FILE__, __LINE__, ctx.insert_pattern);
		goto error2;
	}
	if ((err = sql_step(ctx.db, ctx.insert_pattern)) != SQLITE_DONE) {
		sql_error(__FILE__, __LINE__, ctx.insert_pattern);
		goto error2;
	}

	rule->id_pattern = sqlite3_last_insert_rowid(ctx.db);
	(void) sqlite3_clear_bindings(ctx.insert_pattern);
	sqlite3_reset(ctx.insert_pattern);

	/* Last insert rowid is zero if no row was inserted, thus it
	 * already exists and we need to find the pattern number (OID).
	 */
	if (rule->id_pattern == 0) {
		if ((err = sqlite3_bind_text(ctx.find_pattern, 1, rule->pattern, -1, SQLITE_STATIC)) != SQLITE_OK) {
			sql_error(__FILE__, __LINE__, ctx.find_pattern);
			goto error2;
		}
		if ((err = sql_step(ctx.db, ctx.find_pattern)) != SQLITE_ROW) {
			sql_error(__FILE__, __LINE__, ctx.find_pattern);
			goto error2;
		}
		if ((rule->id_pattern = sqlite3_column_int64(ctx.find_pattern, 0)) == 0) {
			sql_error(__FILE__, __LINE__, ctx.find_pattern);
			goto error2;
		}
		(void) sqlite3_clear_bindings(ctx.find_pattern);
                sqlite3_reset(ctx.find_pattern);
	}

	for (i = 0; i < VectorLength(fields); i++) {
		field = VectorGet(fields, i);
		field += strspn(field, " \t");

		switch (*field) {
		case 'c':
			if (field[1] == '=') {
				free(rule->on_exceed);
				rule->on_exceed = VectorReplace(fields, i, NULL);
			}
			break;
		case 'C':
			if (field[1] == '=') {
				free(rule->on_expire);
				rule->on_expire = VectorReplace(fields, i, NULL);
			}
			break;
		case 'r':
			if (field[1] == '=') {
				free(rule->report);
				rule->report = VectorReplace(fields, i, NULL);
			}
			break;
		case 't':
			if (field[1] == '=')
				rule->thread = strtol(field+2, NULL, 10);
			break;
		case 'l':
			if (field[1] == '=')
				continue;
		}

		(void) VectorRemove(fields, i--);
	}

	field[strcspn(field, "\r\n")] = '\0';

	/* What remains of fields should be an empty vector or an array of l= actions. */
	rule->limits = (char **) VectorBase(fields);
	fields = NULL;

	rule->node.data = rule;
	rule->node.free = free_rule;
	listInsertAfter(&pattern_rules, NULL, &rule->node);

	rc = 0;
error2:
	VectorDestroy(fields);
error1:
	if (rc != 0)
		free_rule(rule);
error0:
	return rc;
}