/* * $(grep [opts] filter $nv1 $n2 ...) * * Options: * --max-count or -m The maximum number of matches, 0 for unlimited */ void tf_grep_call(LogTemplateFunction *self, gpointer s, const LogTemplateInvokeArgs *args, GString *result) { gint i, msg_ndx; gboolean first = TRUE; TFCondState *state = (TFCondState *) s; gint count = 0; for (msg_ndx = 0; msg_ndx < args->num_messages; msg_ndx++) { LogMessage *msg = args->messages[msg_ndx]; if (filter_expr_eval(state->filter, msg)) { count++; for (i = 0; i < state->super.argc; i++) { if (!first) g_string_append_c(result, ','); /* NOTE: not recursive, as the message context is just one message */ log_template_append_format(state->super.argv[i], msg, args->opts, args->tz, args->seq_num, args->context_id, result); first = FALSE; } if (state->grep_max_count && count >= state->grep_max_count) break; } } }
void tf_grep_call(LogTemplateFunction *self, gpointer state, GPtrArray *arg_bufs, LogMessage **messages, gint num_messages, LogTemplateOptions *opts, gint tz, gint seq_num, const gchar *context_id, GString *result) { gint i, msg_ndx; gboolean first = TRUE; TFCondState *args = (TFCondState *) state; for (msg_ndx = 0; msg_ndx < num_messages; msg_ndx++) { LogMessage *msg = messages[msg_ndx]; if (filter_expr_eval(args->filter, msg)) { for (i = 0; i < args->argc; i++) { if (!first) g_string_append_c(result, ','); log_template_append_format(args->argv[i], msg, opts, tz, seq_num, context_id, result); first = FALSE; } } } }
static gchar * log_matcher_pcre_re_replace(LogMatcher *s, LogMessage *msg, gint value_handle, const gchar *value, gssize value_len, LogTemplate *replacement, gssize *new_length) { LogMatcherPcreRe *self = (LogMatcherPcreRe *) s; GString *new_value = NULL; gint *matches; gsize matches_size; gint num_matches; gint rc; gint start_offset, last_offset; gint options; gboolean last_match_was_empty; if (pcre_fullinfo(self->pattern, self->extra, PCRE_INFO_CAPTURECOUNT, &num_matches) < 0) g_assert_not_reached(); if (num_matches > RE_MAX_MATCHES) num_matches = RE_MAX_MATCHES; matches_size = 3 * (num_matches + 1); matches = g_alloca(matches_size * sizeof(gint)); /* we need zero initialized offsets for the last match as the * algorithm tries uses that as the base position */ matches[0] = matches[1] = matches[2] = 0; if (value_len == -1) value_len = strlen(value); last_offset = start_offset = 0; last_match_was_empty = FALSE; do { /* loop over the string, replacing one occurence at a time. */ /* NOTE: zero length matches need special care, as we could spin * forever otherwise (since the current position wouldn't be * advanced). * * A zero-length match can be as simple as "a*" which will be * returned unless PCRE_NOTEMPTY is specified. * * By supporting zero-length matches, we basically make it * possible to insert replacement between each incoming * character. * * For example: * pattern: a* * replacement: # * input: message * result: #m#e#s#s#a#g#e# * * This mimics Perl behaviour. */ if (last_match_was_empty) { /* Otherwise, arrange to run another match at the same point * to see if a non-empty match can be found. */ options = PCRE_NOTEMPTY | PCRE_ANCHORED; } else { options = 0; } rc = pcre_exec(self->pattern, self->extra, value, value_len, start_offset, (self->match_options | options), matches, matches_size); if (rc < 0 && rc != PCRE_ERROR_NOMATCH) { msg_error("Error while matching regexp", evt_tag_int("error_code", rc), NULL); break; } else if (rc < 0) { if ((options & PCRE_NOTEMPTY) == 0) { /* we didn't match, even when we permitted to match the * empty string. Nothing to find here, bail out */ break; } /* we didn't match, quite possibly because the empty match * was not permitted. Skip one character in order to avoid * infinite loop over the same zero-length match. */ start_offset = start_offset + 1; /* FIXME: handle complex sequences like utf8 and newline characters */ last_match_was_empty = FALSE; continue; } else { /* if the output array was too small, truncate the number of captures to RE_MAX_MATCHES */ if (rc == 0) rc = matches_size / 3; log_matcher_pcre_re_feed_backrefs(s, msg, value_handle, matches, rc, value); log_matcher_pcre_re_feed_named_substrings(s, msg, matches, value); if (!new_value) new_value = g_string_sized_new(value_len); /* append non-matching portion */ g_string_append_len(new_value, &value[last_offset], matches[0] - last_offset); /* replacement */ log_template_append_format(replacement, msg, NULL, LTZ_LOCAL, 0, NULL, new_value); last_match_was_empty = (matches[0] == matches[1]); start_offset = last_offset = matches[1]; } } while (self->super.flags & LMF_GLOBAL && start_offset < value_len); if (new_value) { /* append the last literal */ g_string_append_len(new_value, &value[last_offset], value_len - last_offset); if (new_length) *new_length = new_value->len; return g_string_free(new_value, FALSE); } return NULL; }
static gchar * log_matcher_string_replace(LogMatcher *s, LogMessage *msg, gint value_handle, const gchar *value, gssize value_len, LogTemplate *replacement, gssize *new_length) { LogMatcherString *self = (LogMatcherString *) s; GString *new_value = NULL; gsize current_ofs = 0; gboolean first_round = TRUE; if (value_len < 0) value_len = strlen(value); const gchar *match; do { if (current_ofs == value_len) break; match = log_matcher_string_match_string(self, value + current_ofs, value_len - current_ofs); if (match != NULL) { /* start_ofs & end_ofs are relative to the original string */ gsize start_ofs = match - value; gsize end_ofs = start_ofs + self->pattern_len; if (start_ofs == end_ofs && !first_round) { start_ofs++; end_ofs++; } if ((s->flags & LMF_STORE_MATCHES)) log_msg_clear_matches(msg); if (!new_value) new_value = g_string_sized_new(value_len); g_string_append_len(new_value, value + current_ofs, start_ofs - current_ofs); log_template_append_format(replacement, msg, NULL, LTZ_LOCAL, 0, NULL, new_value); current_ofs = end_ofs; if ((self->super.flags & LMF_GLOBAL) == 0) { g_string_append_len(new_value, value + current_ofs, value_len - current_ofs); break; } } else { if (new_value) { /* no more matches, append the end of the string */ g_string_append_len(new_value, value + current_ofs, value_len - current_ofs); } } first_round = FALSE; } while (match && (self->super.flags & LMF_GLOBAL)); if (new_value) { if (new_length) *new_length = new_value->len; return g_string_free(new_value, FALSE); } return NULL; }
static gchar * log_matcher_posix_re_replace(LogMatcher *s, LogMessage *msg, gint value_handle, const gchar *value, gssize value_len, LogTemplate *replacement, gssize *new_length) { LogMatcherPosixRe *self = (LogMatcherPosixRe *) s; regmatch_t matches[RE_MAX_MATCHES]; gboolean rc; GString *new_value = NULL; gsize current_ofs = 0; gboolean first_round = TRUE; gchar *buf; APPEND_ZERO(buf, value, value_len); do { if (current_ofs == value_len) break; rc = !regexec(&self->pattern, buf + current_ofs, RE_MAX_MATCHES, matches, current_ofs > 0 ? REG_NOTBOL : 0); if (rc) { /* start_ofs & end_ofs are relative to the original string */ gsize start_ofs = matches[0].rm_so + current_ofs; gsize end_ofs = matches[0].rm_eo + current_ofs; if (start_ofs == end_ofs && !first_round) { start_ofs++; end_ofs++; } log_matcher_posix_re_feed_backrefs(s, msg, value_handle, matches, buf + current_ofs); if (!new_value) new_value = g_string_sized_new(value_len); g_string_append_len(new_value, buf + current_ofs, start_ofs - current_ofs); log_template_append_format(replacement, msg, NULL, LTZ_LOCAL, 0, NULL, new_value); current_ofs = end_ofs; if ((self->super.flags & LMF_GLOBAL) == 0) { g_string_append_len(new_value, buf + current_ofs, value_len - current_ofs); break; } } else { if (new_value) { /* no more matches, append the end of the string */ g_string_append_len(new_value, buf + current_ofs, value_len - current_ofs); } } first_round = FALSE; } while (rc && (self->super.flags & LMF_GLOBAL)); if (new_value) { if (new_length) *new_length = new_value->len; return g_string_free(new_value, FALSE); } return NULL; }