src/utils_match.c: Actually set `ds_type' in the object.
[collectd.git] / src / utils_match.c
1 /**
2  * collectd - src/utils_match.c
3  * Copyright (C) 2008  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  **/
22
23 #include "collectd.h"
24 #include "common.h"
25 #include "plugin.h"
26
27 #include "utils_match.h"
28
29 #include <regex.h>
30
31 #define UTILS_MATCH_FLAGS_FREE_USER_DATA 0x01
32
33 struct cu_match_s
34 {
35   regex_t regex;
36   int flags;
37
38   int (*callback) (const char *str, void *user_data);
39   void *user_data;
40 };
41
42 /*
43  * Private functions
44  */
45 static int default_callback (const char *str, void *user_data)
46 {
47   cu_match_value_t *data = (cu_match_value_t *) user_data;
48
49   if (data->ds_type == UTILS_MATCH_DS_TYPE_GAUGE)
50   {
51     gauge_t value;
52     char *endptr = NULL;
53
54     value = strtod (str, &endptr);
55     if (str == endptr)
56       return (-1);
57
58     data->value.gauge = value;
59   }
60   else if ((data->ds_type == UTILS_MATCH_DS_TYPE_COUNTER_SET)
61       || (data->ds_type == UTILS_MATCH_DS_TYPE_COUNTER_ADD))
62   {
63     counter_t value;
64     char *endptr = NULL;
65
66     value = strtoll (str, &endptr, 0);
67     if (str == endptr)
68       return (-1);
69
70     if (data->ds_type == UTILS_MATCH_DS_TYPE_COUNTER_SET)
71       data->value.counter = value;
72     else
73       data->value.counter += value;
74   }
75   else if (data->ds_type == UTILS_MATCH_DS_TYPE_COUNTER_INC)
76   {
77     data->value.counter++;
78   }
79   else
80   {
81     return (-1);
82   }
83
84   return (0);
85 } /* int default_callback */
86
87 /*
88  * Public functions
89  */
90 cu_match_t *match_create_callback (const char *regex,
91                 int (*callback) (const char *str, void *user_data),
92                 void *user_data)
93 {
94   cu_match_t *obj;
95   int status;
96
97   obj = (cu_match_t *) malloc (sizeof (cu_match_t));
98   if (obj == NULL)
99     return (NULL);
100   memset (obj, '\0', sizeof (cu_match_t));
101
102   status = regcomp (&obj->regex, regex, REG_EXTENDED);
103   if (status != 0)
104   {
105     ERROR ("Compiling the regular expression \"%s\" failed.", regex);
106     sfree (obj);
107     return (NULL);
108   }
109
110   obj->callback = callback;
111   obj->user_data = user_data;
112
113   return (obj);
114 } /* cu_match_t *match_create_callback */
115
116 cu_match_t *match_create_simple (const char *regex, int match_ds_type)
117 {
118   cu_match_value_t *user_data;
119   cu_match_t *obj;
120
121   user_data = (cu_match_value_t *) malloc (sizeof (cu_match_value_t));
122   if (user_data == NULL)
123     return (NULL);
124   memset (user_data, '\0', sizeof (cu_match_value_t));
125   user_data->ds_type = match_ds_type;
126
127   obj = match_create_callback (regex, default_callback, user_data);
128   if (obj == NULL)
129   {
130     sfree (user_data);
131     return (NULL);
132   }
133
134   obj->flags |= UTILS_MATCH_FLAGS_FREE_USER_DATA;
135
136   return (obj);
137 } /* cu_match_t *match_create_simple */
138
139 void match_destroy (cu_match_t *obj)
140 {
141   if (obj == NULL)
142     return;
143
144   if (obj->flags & UTILS_MATCH_FLAGS_FREE_USER_DATA)
145   {
146     sfree (obj->user_data);
147   }
148
149   sfree (obj);
150 } /* void match_destroy */
151
152 int match_apply (cu_match_t *obj, const char *str)
153 {
154   int status;
155   regmatch_t re_match[2];
156   char *sub_match;
157   size_t sub_match_len;
158
159   if ((obj == NULL) || (str == NULL))
160     return (-1);
161
162   re_match[0].rm_so = -1;
163   re_match[0].rm_eo = -1;
164   re_match[1].rm_so = -1;
165   re_match[1].rm_eo = -1;
166   status = regexec (&obj->regex, str, /* nmatch = */ 2, re_match,
167       /* eflags = */ 0);
168
169   /* Regex did not match */
170   if (status != 0)
171     return (0);
172
173   /* re_match[0] is the location of the entire match.
174    * re_match[1] is the location of the sub-match. */
175   if (re_match[1].rm_so < 0)
176   {
177     status = obj->callback (str, obj->user_data);
178     return (status);
179   }
180
181   assert (re_match[1].rm_so < re_match[1].rm_eo);
182   sub_match_len = (size_t) (re_match[1].rm_eo - re_match[1].rm_so);
183   sub_match = (char *) malloc (sizeof (char) * (sub_match_len + 1));
184   if (sub_match == NULL)
185   {
186     ERROR ("malloc failed.");
187     return (-1);
188   }
189   sstrncpy (sub_match, str + re_match[1].rm_so, sub_match_len + 1);
190
191   DEBUG ("utils_match: match_apply: Dispatching substring \"%s\" to "
192       "callback.", sub_match);
193   status = obj->callback (sub_match, obj->user_data);
194
195   sfree (sub_match);
196
197   return (status);
198 } /* int match_apply */
199
200 void *match_get_user_data (cu_match_t *obj)
201 {
202   if (obj == NULL)
203     return (NULL);
204   return (obj->user_data);
205 } /* void *match_get_user_data */
206
207 /* vim: set sw=2 sts=2 ts=8 : */