From 126b9bebac9a1ea06d3d3308ace2705f01e57769 Mon Sep 17 00:00:00 2001 From: Florian Forster Date: Sat, 23 Feb 2008 15:44:27 +0100 Subject: [PATCH] src/utils_match.[ch]: Add a module to automate regular expression matching on a string. --- src/Makefile.am | 1 + src/utils_match.c | 201 ++++++++++++++++++++++++++++++++++++++++++++++ src/utils_match.h | 133 ++++++++++++++++++++++++++++++ 3 files changed, 335 insertions(+) create mode 100644 src/utils_match.c create mode 100644 src/utils_match.h diff --git a/src/Makefile.am b/src/Makefile.am index a0b4c2df..30518b9f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -31,6 +31,7 @@ collectd_SOURCES = collectd.c collectd.h \ utils_ignorelist.c utils_ignorelist.h \ utils_llist.c utils_llist.h \ utils_logtail.c utils_logtail.h \ + utils_match.c utils_match.h \ utils_mount.c utils_mount.h \ utils_tail.c utils_tail.h \ utils_threshold.c utils_threshold.h \ diff --git a/src/utils_match.c b/src/utils_match.c new file mode 100644 index 00000000..23bedb1b --- /dev/null +++ b/src/utils_match.c @@ -0,0 +1,201 @@ +/** + * collectd - src/utils_match.c + * Copyright (C) 2008 Florian octo Forster + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: + * Florian octo Forster + **/ + +#include "collectd.h" +#include "common.h" +#include "plugin.h" + +#include "utils_match.h" + +#include + +#define UTILS_MATCH_FLAGS_FREE_USER_DATA 0x01 + +struct cu_match_s +{ + regex_t regex; + int flags; + + int (*callback) (const char *str, void *user_data); + void *user_data; +}; + +/* + * Private functions + */ +static int default_callback (const char *str, void *user_data) +{ + cu_match_value_t *data = (cu_match_value_t *) user_data; + + if (data->ds_type == UTILS_MATCH_DS_TYPE_GAUGE) + { + gauge_t value; + char *endptr = NULL; + + value = strtod (str, &endptr); + if (str == endptr) + return (-1); + + data->value.gauge = value; + } + else if ((data->ds_type == UTILS_MATCH_DS_TYPE_COUNTER_SET) + || (data->ds_type == UTILS_MATCH_DS_TYPE_COUNTER_ADD)) + { + counter_t value; + char *endptr = NULL; + + value = strtoll (str, &endptr, 0); + if (str == endptr) + return (-1); + + if (data->ds_type == UTILS_MATCH_DS_TYPE_COUNTER_SET) + data->value.counter = value; + else + data->value.counter += value; + } + else if (data->ds_type == UTILS_MATCH_DS_TYPE_COUNTER_INC) + { + data->value.counter++; + } + else + { + return (-1); + } + + return (0); +} /* int default_callback */ + +/* + * Public functions + */ +cu_match_t *match_create_callback (const char *regex, + int (*callback) (const char *str, void *user_data), + void *user_data) +{ + cu_match_t *obj; + int status; + + obj = (cu_match_t *) malloc (sizeof (cu_match_t)); + if (obj == NULL) + return (NULL); + memset (obj, '\0', sizeof (cu_match_t)); + + status = regcomp (&obj->regex, regex, REG_EXTENDED); + if (status != 0) + { + ERROR ("Compiling the regular expression \"%s\" failed.", regex); + sfree (obj); + return (NULL); + } + + obj->callback = callback; + obj->user_data = user_data; + + return (obj); +} /* cu_match_t *match_create_callback */ + +cu_match_t *match_create_default (const char *regex, int match_ds_type) +{ + cu_match_value_t *user_data; + cu_match_t *obj; + + user_data = (cu_match_value_t *) malloc (sizeof (cu_match_value_t)); + if (user_data == NULL) + return (NULL); + memset (user_data, '\0', sizeof (cu_match_value_t)); + + obj = match_create_callback (regex, default_callback, user_data); + if (obj == NULL) + { + sfree (user_data); + return (NULL); + } + + obj->flags |= UTILS_MATCH_FLAGS_FREE_USER_DATA; + + return (obj); +} /* cu_match_t *match_create_default */ + +void match_destroy (cu_match_t *obj) +{ + if (obj == NULL) + return; + + if (obj->flags & UTILS_MATCH_FLAGS_FREE_USER_DATA) + { + sfree (obj->user_data); + } + + sfree (obj); +} /* void match_destroy */ + +int match_apply (cu_match_t *obj, const char *str) +{ + int status; + regmatch_t re_match; + char *sub_match; + size_t sub_match_len; + + if ((obj == NULL) || (str == NULL)) + return (-1); + + re_match.rm_so = -1; + re_match.rm_eo = -1; + + status = regexec (&obj->regex, str, /* nmatch = */ 1, &re_match, + /* eflags = */ 0); + + /* Regex did not match */ + if (status != 0) + return (0); + + if (re_match.rm_so < 0) + { + status = obj->callback (str, obj->user_data); + return (status); + } + + assert (re_match.rm_so < re_match.rm_eo); + sub_match_len = (size_t) (re_match.rm_eo - re_match.rm_so); + sub_match = (char *) malloc (sizeof (char) * (sub_match_len + 1)); + if (sub_match == NULL) + { + ERROR ("malloc failed."); + return (-1); + } + sstrncpy (sub_match, str + re_match.rm_so, sub_match_len + 1); + + status = obj->callback (sub_match, obj->user_data); + + sfree (sub_match); + + return (status); +} /* int match_apply */ + +void *match_get_user_data (cu_match_t *obj) +{ + if (obj == NULL) + return (NULL); + return (obj->user_data); +} /* void *match_get_user_data */ + +/* vim: set sw=2 sts=2 ts=8 : */ diff --git a/src/utils_match.h b/src/utils_match.h new file mode 100644 index 00000000..5098e970 --- /dev/null +++ b/src/utils_match.h @@ -0,0 +1,133 @@ +/** + * collectd - src/utils_match.h + * Copyright (C) 2008 Florian octo Forster + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: + * Florian octo Forster + **/ + +#ifndef UTILS_MATCH_H +#define UTILS_MATCH_H 1 + +#include "plugin.h" + +/* + * Defines + */ +#define UTILS_MATCH_DS_TYPE_GAUGE 0 +#define UTILS_MATCH_DS_TYPE_COUNTER_SET 1 +#define UTILS_MATCH_DS_TYPE_COUNTER_ADD 2 +#define UTILS_MATCH_DS_TYPE_COUNTER_INC 3 + +/* + * Data types + */ +struct cu_match_s; +typedef struct cu_match_s cu_match_t; + +struct cu_match_value_s +{ + int ds_type; + value_t value; +}; +typedef struct cu_match_value_s cu_match_value_t; + +/* + * Prototypes + */ +/* + * NAME + * match_create_callback + * + * DESCRIPTION + * Creates a new `cu_match_t' object which will use the regular expression + * `regex' to match lines, see the `match_apply' method below. If the line + * matches, the callback passed in `callback' will be called along with the + * pointer `user_pointer'. + * The string that's passed to the callback depends on the regular expression: + * If the regular expression includes a sub-match, i. e. something like + * "value=([0-9][0-9]*)" + * then only the submatch (the part in the parenthesis) will be passed to the + * callback. If there is no submatch, then the entire string is passed to the + * callback. + */ +cu_match_t *match_create_callback (const char *regex, + int (*callback) (const char *str, void *user_data), + void *user_data); + +/* + * NAME + * match_create_callback + * + * DESCRIPTION + * Creates a new `cu_match_t' with a default callback. The user data for that + * default callback will be a `cu_match_value_t' structure, with + * `ds_type' copied to the structure. The default callback will handle the + * string as containing a number (see strtoll(3) and strtod(3)) and store that + * number in the `value' member. How that is done depends on `ds_type': + * + * UTILS_MATCH_DS_TYPE_GAUGE + * The function will search for a floating point number in the string and + * store it in value.gauge. + * UTILS_MATCH_DS_TYPE_COUNTER_SET + * The function will search for an integer in the string and store it in + * value.counter. + * UTILS_MATCH_DS_TYPE_COUNTER_ADD + * The function will search for an integer in the string and add it to the + * value in value.counter. + * UTILS_MATCH_DS_TYPE_COUNTER_INC + * The function will not search for anything in the string and increase + * value.counter by one. + */ +cu_match_t *match_create_default (const char *regex, int ds_type); + +/* + * NAME + * match_destroy + * + * DESCRIPTION + * Destroys the object and frees all internal resources. + */ +void match_destroy (cu_match_t *obj); + +/* + * NAME + * match_apply + * + * DESCRIPTION + * Tries to match the string `str' with the regular expression of `obj'. If + * the string matches, calls the callback in `obj' with the (sub-)match. + * + * The user_data pointer passed to `match_create_callback' is NOT freed + * automatically. The `cu_match_value_t' structure allocated by + * `match_create_callback' is freed automatically. + */ +int match_apply (cu_match_t *obj, const char *str); + +/* + * NAME + * match_get_user_data + * + * DESCRIPTION + * Returns the pointer passed to `match_create_callback' or a pointer to the + * `cu_match_value_t' structure allocated by `match_create_callback'. + */ +void *match_get_user_data (cu_match_t *obj); + +#endif /* UTILS_MATCH_H */ + +/* vim: set sw=2 sts=2 ts=8 : */ -- 2.30.2