Visibility: split graph API into public and private interfaces
[babeltrace.git] / plugins / utils / trimmer / trimmer.c
CommitLineData
cab3f160
JG
1/*
2 * trimmer.c
3 *
4 * Babeltrace Trace Trimmer
5 *
6 * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
7 *
8 * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
27 */
28
33b34c43
PP
29#include <babeltrace/plugin/plugin-dev.h>
30#include <babeltrace/component/component.h>
890882ef 31#include <babeltrace/component/private-component.h>
d71dcf2c 32#include <babeltrace/component/component-filter.h>
33b34c43
PP
33#include <babeltrace/component/notification/notification.h>
34#include <babeltrace/component/notification/iterator.h>
890882ef 35#include <babeltrace/component/notification/private-iterator.h>
33b34c43 36#include <babeltrace/component/notification/event.h>
7d61fa8e 37#include <plugins-common.h>
cab3f160
JG
38#include "trimmer.h"
39#include "iterator.h"
44d3cbf0 40#include <assert.h>
cab3f160
JG
41
42static
43void destroy_trimmer_data(struct trimmer *trimmer)
44{
45 g_free(trimmer);
46}
47
48static
49struct trimmer *create_trimmer_data(void)
50{
51 struct trimmer *trimmer;
52
53 trimmer = g_new0(struct trimmer, 1);
54 if (!trimmer) {
55 goto end;
56 }
57end:
58 return trimmer;
59}
60
890882ef 61void destroy_trimmer(struct bt_private_component *component)
cab3f160 62{
890882ef 63 void *data = bt_private_component_get_user_data(component);
cab3f160
JG
64
65 destroy_trimmer_data(data);
66}
67
528debdf
MD
68/*
69 * Parses a timestamp, figuring out its format.
70 *
71 * Returns a negative value if anything goes wrong.
72 *
73 * Expected formats:
74 *
75 * YYYY-MM-DD hh:mm:ss.ns
76 * hh:mm:ss.ns
77 * -ss.ns
78 * ss.ns
79 * YYYY-MM-DD hh:mm:ss
80 * hh:mm:ss
81 * -ss
82 * ss
83 */
44d3cbf0 84static
c6dedfd4 85int timestamp_from_arg(const char *arg, struct trimmer *trimmer,
528debdf
MD
86 struct trimmer_bound *result_bound, bool gmt)
87{
88 int ret;
89 int64_t value;
90 unsigned int year, month, day, hh, mm, ss, ns;
91
92 /* YYYY-MM-DD hh:mm:ss.ns */
93 ret = sscanf(arg, "%u-%u-%u %u:%u:%u.%u",
94 &year, &month, &day, &hh, &mm, &ss, &ns);
95 if (ret == 7) {
96 struct tm tm = {
97 .tm_sec = ss,
98 .tm_min = mm,
99 .tm_hour = hh,
100 .tm_mday = day,
101 .tm_mon = month - 1,
102 .tm_year = year - 1900,
103 .tm_isdst = -1,
104 };
105 time_t result;
106
107 if (gmt) {
108 result = timegm(&tm);
109 if (result < 0) {
110 return -1;
111 }
112 } else {
113 result = mktime(&tm);
114 if (result < 0) {
115 return -1;
116 }
117 }
118 value = (int64_t) result;
119 value *= NSEC_PER_SEC;
120 value += ns;
c6dedfd4
MD
121 if (!trimmer->date) {
122 trimmer->year = year;
123 trimmer->month = month;
124 trimmer->day = day;
125 trimmer->date = true;
126 }
528debdf
MD
127 goto set;
128 }
129 /* hh:mm:ss.ns */
130 ret = sscanf(arg, "%u:%u:%u.%u",
131 &hh, &mm, &ss, &ns);
132 if (ret == 4) {
c6dedfd4
MD
133 if (!trimmer->date) {
134 /* We don't know which day until we get an event. */
135 result_bound->lazy_values.hh = hh;
136 result_bound->lazy_values.mm = mm;
137 result_bound->lazy_values.ss = ss;
138 result_bound->lazy_values.ns = ns;
139 result_bound->lazy_values.gmt = gmt;
140 goto lazy;
141 } else {
142 struct tm tm = {
143 .tm_sec = ss,
144 .tm_min = mm,
145 .tm_hour = hh,
146 .tm_mday = trimmer->day,
147 .tm_mon = trimmer->month - 1,
148 .tm_year = trimmer->year - 1900,
149 .tm_isdst = -1,
150 };
151 time_t result;
152
153 if (gmt) {
154 result = timegm(&tm);
155 if (result < 0) {
156 return -1;
157 }
158 } else {
159 result = mktime(&tm);
160 if (result < 0) {
161 return -1;
162 }
163 }
164 value = (int64_t) result;
165 value *= NSEC_PER_SEC;
166 value += ns;
167 goto set;
168 }
528debdf
MD
169 }
170 /* -ss.ns */
171 ret = sscanf(arg, "-%u.%u",
172 &ss, &ns);
173 if (ret == 2) {
174 value = -ss * NSEC_PER_SEC;
175 value -= ns;
176 goto set;
177 }
178 /* ss.ns */
179 ret = sscanf(arg, "%u.%u",
180 &ss, &ns);
181 if (ret == 2) {
182 value = ss * NSEC_PER_SEC;
183 value += ns;
184 goto set;
185 }
186
187 /* YYYY-MM-DD hh:mm:ss */
188 ret = sscanf(arg, "%u-%u-%u %u:%u:%u",
189 &year, &month, &day, &hh, &mm, &ss);
190 if (ret == 6) {
191 struct tm tm = {
192 .tm_sec = ss,
193 .tm_min = mm,
194 .tm_hour = hh,
195 .tm_mday = day,
196 .tm_mon = month - 1,
197 .tm_year = year - 1900,
198 .tm_isdst = -1,
199 };
200
201 if (gmt) {
202 value = timegm(&tm);
203 if (value < 0) {
204 return -1;
205 }
206 } else {
207 value = mktime(&tm);
208 if (value < 0) {
209 return -1;
210 }
211 }
212 value *= NSEC_PER_SEC;
c6dedfd4
MD
213 if (!trimmer->date) {
214 trimmer->year = year;
215 trimmer->month = month;
216 trimmer->day = day;
217 trimmer->date = true;
218 }
528debdf
MD
219 goto set;
220 }
221 /* hh:mm:ss */
222 ret = sscanf(arg, "%u:%u:%u",
223 &hh, &mm, &ss);
224 if (ret == 3) {
c6dedfd4
MD
225 if (!trimmer->date) {
226 /* We don't know which day until we get an event. */
227 result_bound->lazy_values.hh = hh;
228 result_bound->lazy_values.mm = mm;
229 result_bound->lazy_values.ss = ss;
230 result_bound->lazy_values.ns = 0;
231 result_bound->lazy_values.gmt = gmt;
232 goto lazy;
233 } else {
234 struct tm tm = {
235 .tm_sec = ss,
236 .tm_min = mm,
237 .tm_hour = hh,
238 .tm_mday = trimmer->day,
239 .tm_mon = trimmer->month - 1,
240 .tm_year = trimmer->year - 1900,
241 .tm_isdst = -1,
242 };
243 time_t result;
244
245 if (gmt) {
246 result = timegm(&tm);
247 if (result < 0) {
248 return -1;
249 }
250 } else {
251 result = mktime(&tm);
252 if (result < 0) {
253 return -1;
254 }
255 }
256 value = (int64_t) result;
257 value *= NSEC_PER_SEC;
258 goto set;
259 }
528debdf
MD
260 }
261 /* -ss */
262 ret = sscanf(arg, "-%u",
263 &ss);
264 if (ret == 1) {
265 value = -ss * NSEC_PER_SEC;
266 goto set;
267 }
268 /* ss */
269 ret = sscanf(arg, "%u",
270 &ss);
271 if (ret == 1) {
272 value = ss * NSEC_PER_SEC;
273 goto set;
274 }
275
276 /* Not found. */
277 return -1;
278
279set:
280 result_bound->value = value;
281 result_bound->set = true;
282 return 0;
283
284lazy:
285 result_bound->lazy = true;
286 return 0;
287}
288
289static
890882ef
PP
290enum bt_component_status init_from_params(struct trimmer *trimmer,
291 struct bt_value *params)
44d3cbf0
JG
292{
293 struct bt_value *value = NULL;
528debdf
MD
294 bool gmt = false;
295 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
44d3cbf0
JG
296
297 assert(params);
298
528debdf
MD
299 value = bt_value_map_get(params, "clock-gmt");
300 if (value) {
44d3cbf0
JG
301 enum bt_value_status value_ret;
302
528debdf
MD
303 value_ret = bt_value_bool_get(value, &gmt);
304 if (value_ret) {
305 ret = BT_COMPONENT_STATUS_INVALID;
55595636 306 printf_error("Failed to retrieve clock-gmt value. Expecting a boolean");
44d3cbf0
JG
307 }
308 }
309 bt_put(value);
528debdf
MD
310 if (ret != BT_COMPONENT_STATUS_OK) {
311 goto end;
312 }
313
314 value = bt_value_map_get(params, "begin");
315 if (value) {
44d3cbf0 316 enum bt_value_status value_ret;
528debdf 317 const char *str;
44d3cbf0 318
528debdf
MD
319 value_ret = bt_value_string_get(value, &str);
320 if (value_ret || timestamp_from_arg(str,
c6dedfd4 321 trimmer, &trimmer->begin, gmt)) {
528debdf 322 ret = BT_COMPONENT_STATUS_INVALID;
55595636 323 printf_error("Failed to retrieve begin value. Expecting a timestamp string");
44d3cbf0
JG
324 }
325 }
326 bt_put(value);
528debdf
MD
327 if (ret != BT_COMPONENT_STATUS_OK) {
328 goto end;
329 }
330
331 value = bt_value_map_get(params, "end");
332 if (value) {
333 enum bt_value_status value_ret;
334 const char *str;
335
336 value_ret = bt_value_string_get(value, &str);
337 if (value_ret || timestamp_from_arg(str,
c6dedfd4 338 trimmer, &trimmer->end, gmt)) {
528debdf 339 ret = BT_COMPONENT_STATUS_INVALID;
55595636 340 printf_error("Failed to retrieve end value. Expecting a timestamp string");
528debdf
MD
341 }
342 }
343 bt_put(value);
344end:
55595636
MD
345 if (trimmer->begin.set && trimmer->end.set) {
346 if (trimmer->begin.value > trimmer->end.value) {
347 printf_error("Unexpected: time range begin value is above end value");
348 ret = BT_COMPONENT_STATUS_INVALID;
349 }
350 }
528debdf 351 return ret;
44d3cbf0
JG
352}
353
cab3f160 354enum bt_component_status trimmer_component_init(
890882ef 355 struct bt_private_component *component, struct bt_value *params,
7d61fa8e 356 UNUSED_VAR void *init_method_data)
cab3f160
JG
357{
358 enum bt_component_status ret;
359 struct trimmer *trimmer = create_trimmer_data();
360
361 if (!trimmer) {
362 ret = BT_COMPONENT_STATUS_NOMEM;
363 goto end;
364 }
365
890882ef 366 ret = bt_private_component_set_user_data(component, trimmer);
cab3f160
JG
367 if (ret != BT_COMPONENT_STATUS_OK) {
368 goto error;
369 }
370
528debdf 371 ret = init_from_params(trimmer, params);
cab3f160
JG
372end:
373 return ret;
374error:
375 destroy_trimmer_data(trimmer);
376 return ret;
377}
This page took 0.040189 seconds and 4 git commands to generate.