Code

Fix build on Solaris 10 i386 part 2
[collectd.git] / src / utils_match.c
1 /**
2  * collectd - src/utils_match.c
3  * Copyright (C) 2008-2014  Florian octo Forster
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; either version 2 of the License, or (at your
8  * option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
18  *
19  * Authors:
20  *   Florian octo Forster <octo at verplant.org>
21  **/
23 #include "collectd.h"
24 #include "common.h"
25 #include "plugin.h"
27 #include "utils_match.h"
29 #include <regex.h>
31 #define UTILS_MATCH_FLAGS_FREE_USER_DATA 0x01
32 #define UTILS_MATCH_FLAGS_EXCLUDE_REGEX 0x02
34 struct cu_match_s
35 {
36   regex_t regex;
37   regex_t excluderegex;
38   int flags;
40   int (*callback) (const char *str, char * const *matches, size_t matches_num,
41       void *user_data);
42   void *user_data;
43 };
45 /*
46  * Private functions
47  */
48 static char *match_substr (const char *str, int begin, int end)
49 {
50   char *ret;
51   size_t ret_len;
53   if ((begin < 0) || (end < 0) || (begin >= end))
54     return (NULL);
55   if ((size_t) end > (strlen (str) + 1))
56   {
57     ERROR ("utils_match: match_substr: `end' points after end of string.");
58     return (NULL);
59   }
61   ret_len = end - begin;
62   ret = (char *) malloc (sizeof (char) * (ret_len + 1));
63   if (ret == NULL)
64   {
65     ERROR ("utils_match: match_substr: malloc failed.");
66     return (NULL);
67   }
69   sstrncpy (ret, str + begin, ret_len + 1);
70   return (ret);
71 } /* char *match_substr */
73 static int default_callback (const char __attribute__((unused)) *str,
74     char * const *matches, size_t matches_num, void *user_data)
75 {
76   cu_match_value_t *data = (cu_match_value_t *) user_data;
78   if (data->ds_type & UTILS_MATCH_DS_TYPE_GAUGE)
79   {
80     gauge_t value;
81     char *endptr = NULL;
83     if (matches_num < 2)
84       return (-1);
86     value = (gauge_t) strtod (matches[1], &endptr);
87     if (matches[1] == endptr)
88       return (-1);
90     if ((data->values_num == 0)
91         || (data->ds_type & UTILS_MATCH_CF_GAUGE_LAST))
92     {
93       data->value.gauge = value;
94     }
95     else if (data->ds_type & UTILS_MATCH_CF_GAUGE_AVERAGE)
96     {
97       double f = ((double) data->values_num)
98         / ((double) (data->values_num + 1));
99       data->value.gauge = (data->value.gauge * f) + (value * (1.0 - f));
100     }
101     else if (data->ds_type & UTILS_MATCH_CF_GAUGE_MIN)
102     {
103       if (data->value.gauge > value)
104         data->value.gauge = value;
105     }
106     else if (data->ds_type & UTILS_MATCH_CF_GAUGE_MAX)
107     {
108       if (data->value.gauge < value)
109         data->value.gauge = value;
110     }
111     else
112     {
113       ERROR ("utils_match: default_callback: obj->ds_type is invalid!");
114       return (-1);
115     }
117     data->values_num++;
118   }
119   else if (data->ds_type & UTILS_MATCH_DS_TYPE_COUNTER)
120   {
121     counter_t value;
122     char *endptr = NULL;
124     if (data->ds_type & UTILS_MATCH_CF_COUNTER_INC)
125     {
126       data->value.counter++;
127       data->values_num++;
128       return (0);
129     }
131     if (matches_num < 2)
132       return (-1);
134     value = (counter_t) strtoull (matches[1], &endptr, 0);
135     if (matches[1] == endptr)
136       return (-1);
138     if (data->ds_type & UTILS_MATCH_CF_COUNTER_SET)
139       data->value.counter = value;
140     else if (data->ds_type & UTILS_MATCH_CF_COUNTER_ADD)
141       data->value.counter += value;
142     else
143     {
144       ERROR ("utils_match: default_callback: obj->ds_type is invalid!");
145       return (-1);
146     }
148     data->values_num++;
149   }
150   else if (data->ds_type & UTILS_MATCH_DS_TYPE_DERIVE)
151   {
152     derive_t value;
153     char *endptr = NULL;
155     if (data->ds_type & UTILS_MATCH_CF_DERIVE_INC)
156     {
157       data->value.counter++;
158       data->values_num++;
159       return (0);
160     }
162     if (matches_num < 2)
163       return (-1);
165     value = (derive_t) strtoll (matches[1], &endptr, 0);
166     if (matches[1] == endptr)
167       return (-1);
169     if (data->ds_type & UTILS_MATCH_CF_DERIVE_SET)
170       data->value.derive = value;
171     else if (data->ds_type & UTILS_MATCH_CF_DERIVE_ADD)
172       data->value.derive += value;
173     else
174     {
175       ERROR ("utils_match: default_callback: obj->ds_type is invalid!");
176       return (-1);
177     }
179     data->values_num++;
180   }
181   else if (data->ds_type & UTILS_MATCH_DS_TYPE_ABSOLUTE)
182   {
183     absolute_t value;
184     char *endptr = NULL;
186     if (matches_num < 2)
187       return (-1);
189     value = (absolute_t) strtoull (matches[1], &endptr, 0);
190     if (matches[1] == endptr)
191       return (-1);
193     if (data->ds_type & UTILS_MATCH_CF_ABSOLUTE_SET)
194       data->value.absolute = value;
195     else
196     {
197       ERROR ("utils_match: default_callback: obj->ds_type is invalid!");
198       return (-1);
199     }
201     data->values_num++;
202   }
203   else
204   {
205     ERROR ("utils_match: default_callback: obj->ds_type is invalid!");
206     return (-1);
207   }
209   return (0);
210 } /* int default_callback */
212 /*
213  * Public functions
214  */
215 cu_match_t *match_create_callback (const char *regex, const char *excluderegex,
216                 int (*callback) (const char *str,
217                   char * const *matches, size_t matches_num, void *user_data),
218                 void *user_data)
220   cu_match_t *obj;
221   int status;
223   DEBUG ("utils_match: match_create_callback: regex = %s, excluderegex = %s",
224          regex, excluderegex);
226   obj = (cu_match_t *) malloc (sizeof (cu_match_t));
227   if (obj == NULL)
228     return (NULL);
229   memset (obj, '\0', sizeof (cu_match_t));
231   status = regcomp (&obj->regex, regex, REG_EXTENDED | REG_NEWLINE);
232   if (status != 0)
233   {
234     ERROR ("Compiling the regular expression \"%s\" failed.", regex);
235     sfree (obj);
236     return (NULL);
237   }
239   if (excluderegex && strcmp(excluderegex, "") != 0) {
240     status = regcomp (&obj->excluderegex, excluderegex, REG_EXTENDED);
241     if (status != 0)
242     {
243         ERROR ("Compiling the excluding regular expression \"%s\" failed.",
244                excluderegex);
245         sfree (obj);
246         return (NULL);
247     }
248     obj->flags |= UTILS_MATCH_FLAGS_EXCLUDE_REGEX;
249   }
251   obj->callback = callback;
252   obj->user_data = user_data;
254   return (obj);
255 } /* cu_match_t *match_create_callback */
257 cu_match_t *match_create_simple (const char *regex,
258                                  const char *excluderegex, int match_ds_type)
260   cu_match_value_t *user_data;
261   cu_match_t *obj;
263   user_data = (cu_match_value_t *) malloc (sizeof (cu_match_value_t));
264   if (user_data == NULL)
265     return (NULL);
266   memset (user_data, '\0', sizeof (cu_match_value_t));
267   user_data->ds_type = match_ds_type;
269   obj = match_create_callback (regex, excluderegex,
270                                default_callback, user_data);
271   if (obj == NULL)
272   {
273     sfree (user_data);
274     return (NULL);
275   }
277   obj->flags |= UTILS_MATCH_FLAGS_FREE_USER_DATA;
279   return (obj);
280 } /* cu_match_t *match_create_simple */
282 void match_value_reset (cu_match_value_t *mv)
284   if (mv == NULL)
285     return;
287   if (mv->ds_type & UTILS_MATCH_DS_TYPE_GAUGE)
288   {
289     mv->value.gauge = NAN;
290     mv->values_num = 0;
291   }
292 } /* }}} void match_value_reset */
294 void match_destroy (cu_match_t *obj)
296   if (obj == NULL)
297     return;
299   if (obj->flags & UTILS_MATCH_FLAGS_FREE_USER_DATA)
300   {
301     sfree (obj->user_data);
302   }
304   sfree (obj);
305 } /* void match_destroy */
307 int match_apply (cu_match_t *obj, const char *str)
309   int status;
310   regmatch_t re_match[32];
311   char *matches[32];
312   size_t matches_num;
313   size_t i;
315   if ((obj == NULL) || (str == NULL))
316     return (-1);
318   if (obj->flags & UTILS_MATCH_FLAGS_EXCLUDE_REGEX) {
319     status = regexec (&obj->excluderegex, str,
320                       STATIC_ARRAY_SIZE (re_match), re_match,
321                       /* eflags = */ 0);
322     /* Regex did match, so exclude this line */
323     if (status == 0) {
324       DEBUG("ExludeRegex matched, don't count that line\n");
325       return (0);
326     }
327   }
329   status = regexec (&obj->regex, str,
330       STATIC_ARRAY_SIZE (re_match), re_match,
331       /* eflags = */ 0);
333   /* Regex did not match */
334   if (status != 0)
335     return (0);
337   memset (matches, '\0', sizeof (matches));
338   for (matches_num = 0; matches_num < STATIC_ARRAY_SIZE (matches); matches_num++)
339   {
340     if ((re_match[matches_num].rm_so < 0)
341         || (re_match[matches_num].rm_eo < 0))
342       break;
344     matches[matches_num] = match_substr (str,
345         re_match[matches_num].rm_so, re_match[matches_num].rm_eo);
346     if (matches[matches_num] == NULL)
347     {
348       status = -1;
349       break;
350     }
351   }
353   if (status != 0)
354   {
355     ERROR ("utils_match: match_apply: match_substr failed.");
356   }
357   else
358   {
359     status = obj->callback (str, matches, matches_num, obj->user_data);
360     if (status != 0)
361     {
362       ERROR ("utils_match: match_apply: callback failed.");
363     }
364   }
366   for (i = 0; i < matches_num; i++)
367   {
368     sfree (matches[i]);
369   }
371   return (status);
372 } /* int match_apply */
374 void *match_get_user_data (cu_match_t *obj)
376   if (obj == NULL)
377     return (NULL);
378   return (obj->user_data);
379 } /* void *match_get_user_data */
381 /* vim: set sw=2 sts=2 ts=8 : */