diff options
Diffstat (limited to 'lib/perfdata.c')
-rw-r--r-- | lib/perfdata.c | 605 |
1 files changed, 605 insertions, 0 deletions
diff --git a/lib/perfdata.c b/lib/perfdata.c new file mode 100644 index 00000000..b87de7e0 --- /dev/null +++ b/lib/perfdata.c | |||
@@ -0,0 +1,605 @@ | |||
1 | #include "./perfdata.h" | ||
2 | #include "../plugins/common.h" | ||
3 | #include "../plugins/utils.h" | ||
4 | #include "utils_base.h" | ||
5 | |||
6 | #include <assert.h> | ||
7 | #include <limits.h> | ||
8 | #include <stdlib.h> | ||
9 | |||
10 | char *pd_value_to_string(const mp_perfdata_value pd) { | ||
11 | char *result = NULL; | ||
12 | |||
13 | assert(pd.type != PD_TYPE_NONE); | ||
14 | |||
15 | switch (pd.type) { | ||
16 | case PD_TYPE_INT: | ||
17 | asprintf(&result, "%lli", pd.pd_int); | ||
18 | break; | ||
19 | case PD_TYPE_UINT: | ||
20 | asprintf(&result, "%llu", pd.pd_int); | ||
21 | break; | ||
22 | case PD_TYPE_DOUBLE: | ||
23 | asprintf(&result, "%f", pd.pd_double); | ||
24 | break; | ||
25 | default: | ||
26 | // die here | ||
27 | die(STATE_UNKNOWN, "Invalid mp_perfdata mode\n"); | ||
28 | } | ||
29 | |||
30 | return result; | ||
31 | } | ||
32 | |||
33 | char *pd_to_string(mp_perfdata pd) { | ||
34 | assert(pd.label != NULL); | ||
35 | char *result = NULL; | ||
36 | asprintf(&result, "'%s'=", pd.label); | ||
37 | |||
38 | asprintf(&result, "%s%s", result, pd_value_to_string(pd.value)); | ||
39 | |||
40 | if (pd.uom != NULL) { | ||
41 | asprintf(&result, "%s%s", result, pd.uom); | ||
42 | } | ||
43 | |||
44 | if (pd.warn_present) { | ||
45 | asprintf(&result, "%s;%s", result, mp_range_to_string(pd.warn)); | ||
46 | } else { | ||
47 | asprintf(&result, "%s;", result); | ||
48 | } | ||
49 | |||
50 | if (pd.crit_present) { | ||
51 | asprintf(&result, "%s;%s", result, mp_range_to_string(pd.crit)); | ||
52 | } else { | ||
53 | asprintf(&result, "%s;", result); | ||
54 | } | ||
55 | if (pd.min_present) { | ||
56 | asprintf(&result, "%s;%s", result, pd_value_to_string(pd.min)); | ||
57 | } else { | ||
58 | asprintf(&result, "%s;", result); | ||
59 | } | ||
60 | |||
61 | if (pd.max_present) { | ||
62 | asprintf(&result, "%s;%s", result, pd_value_to_string(pd.max)); | ||
63 | } | ||
64 | |||
65 | /*printf("pd_to_string: %s\n", result); */ | ||
66 | |||
67 | return result; | ||
68 | } | ||
69 | |||
70 | char *pd_list_to_string(const pd_list pd) { | ||
71 | char *result = pd_to_string(pd.data); | ||
72 | |||
73 | for (pd_list *elem = pd.next; elem != NULL; elem = elem->next) { | ||
74 | asprintf(&result, "%s %s", result, pd_to_string(elem->data)); | ||
75 | } | ||
76 | |||
77 | return result; | ||
78 | } | ||
79 | |||
80 | mp_perfdata perfdata_init() { | ||
81 | mp_perfdata pd = {}; | ||
82 | return pd; | ||
83 | } | ||
84 | |||
85 | pd_list *pd_list_init() { | ||
86 | pd_list *tmp = (pd_list *)calloc(1, sizeof(pd_list)); | ||
87 | if (tmp == NULL) { | ||
88 | die(STATE_UNKNOWN, "calloc failed\n"); | ||
89 | } | ||
90 | tmp->next = NULL; | ||
91 | return tmp; | ||
92 | } | ||
93 | |||
94 | mp_range mp_range_init() { | ||
95 | mp_range result = { | ||
96 | .alert_on_inside_range = OUTSIDE, | ||
97 | .start = {}, | ||
98 | .start_infinity = true, | ||
99 | .end = {}, | ||
100 | .end_infinity = true, | ||
101 | }; | ||
102 | |||
103 | return result; | ||
104 | } | ||
105 | |||
106 | mp_range mp_range_set_start(mp_range input, mp_perfdata_value perf_val) { | ||
107 | input.start = perf_val; | ||
108 | input.start_infinity = false; | ||
109 | return input; | ||
110 | } | ||
111 | |||
112 | mp_range mp_range_set_end(mp_range input, mp_perfdata_value perf_val) { | ||
113 | input.end = perf_val; | ||
114 | input.end_infinity = false; | ||
115 | return input; | ||
116 | } | ||
117 | |||
118 | void pd_list_append(pd_list pdl[1], const mp_perfdata pd) { | ||
119 | assert(pdl != NULL); | ||
120 | |||
121 | if (pdl->data.value.type == PD_TYPE_NONE) { | ||
122 | // first entry is still empty | ||
123 | pdl->data = pd; | ||
124 | } else { | ||
125 | // find last element in the list | ||
126 | pd_list *curr = pdl; | ||
127 | pd_list *next = pdl->next; | ||
128 | |||
129 | while (next != NULL) { | ||
130 | curr = next; | ||
131 | next = next->next; | ||
132 | } | ||
133 | |||
134 | if (curr->data.value.type == PD_TYPE_NONE) { | ||
135 | // still empty | ||
136 | curr->data = pd; | ||
137 | } else { | ||
138 | // new a new one | ||
139 | curr->next = pd_list_init(); | ||
140 | curr->next->data = pd; | ||
141 | } | ||
142 | } | ||
143 | } | ||
144 | |||
145 | void pd_list_free(pd_list pdl[1]) { | ||
146 | while (pdl != NULL) { | ||
147 | pd_list *old = pdl; | ||
148 | pdl = pdl->next; | ||
149 | free(old); | ||
150 | } | ||
151 | } | ||
152 | |||
153 | /* | ||
154 | * returns -1 if a < b, 0 if a == b, 1 if a > b | ||
155 | */ | ||
156 | int cmp_perfdata_value(const mp_perfdata_value a, const mp_perfdata_value b) { | ||
157 | // Test if types are different | ||
158 | if (a.type == b.type) { | ||
159 | |||
160 | switch (a.type) { | ||
161 | case PD_TYPE_UINT: | ||
162 | if (a.pd_uint < b.pd_uint) { | ||
163 | return -1; | ||
164 | } else if (a.pd_uint == b.pd_uint) { | ||
165 | return 0; | ||
166 | } else { | ||
167 | return 1; | ||
168 | } | ||
169 | break; | ||
170 | case PD_TYPE_INT: | ||
171 | if (a.pd_int < b.pd_int) { | ||
172 | return -1; | ||
173 | } else if (a.pd_int == b.pd_int) { | ||
174 | return 0; | ||
175 | } else { | ||
176 | return 1; | ||
177 | } | ||
178 | break; | ||
179 | case PD_TYPE_DOUBLE: | ||
180 | if (a.pd_int < b.pd_int) { | ||
181 | return -1; | ||
182 | } else if (a.pd_int == b.pd_int) { | ||
183 | return 0; | ||
184 | } else { | ||
185 | return 1; | ||
186 | } | ||
187 | break; | ||
188 | default: | ||
189 | die(STATE_UNKNOWN, "Error in %s line: %d!", __FILE__, __LINE__); | ||
190 | } | ||
191 | } | ||
192 | |||
193 | // Get dirty here | ||
194 | long double floating_a = 0; | ||
195 | |||
196 | switch (a.type) { | ||
197 | case PD_TYPE_UINT: | ||
198 | floating_a = a.pd_uint; | ||
199 | break; | ||
200 | case PD_TYPE_INT: | ||
201 | floating_a = a.pd_int; | ||
202 | break; | ||
203 | case PD_TYPE_DOUBLE: | ||
204 | floating_a = a.pd_double; | ||
205 | break; | ||
206 | default: | ||
207 | die(STATE_UNKNOWN, "Error in %s line: %d!", __FILE__, __LINE__); | ||
208 | } | ||
209 | |||
210 | long double floating_b = 0; | ||
211 | switch (b.type) { | ||
212 | case PD_TYPE_UINT: | ||
213 | floating_b = b.pd_uint; | ||
214 | break; | ||
215 | case PD_TYPE_INT: | ||
216 | floating_b = b.pd_int; | ||
217 | break; | ||
218 | case PD_TYPE_DOUBLE: | ||
219 | floating_b = b.pd_double; | ||
220 | break; | ||
221 | default: | ||
222 | die(STATE_UNKNOWN, "Error in %s line: %d!", __FILE__, __LINE__); | ||
223 | } | ||
224 | |||
225 | if (floating_a < floating_b) { | ||
226 | return -1; | ||
227 | } | ||
228 | if (floating_a == floating_b) { | ||
229 | return 0; | ||
230 | } | ||
231 | return 1; | ||
232 | } | ||
233 | |||
234 | char *mp_range_to_string(const mp_range input) { | ||
235 | char *result = ""; | ||
236 | if (input.alert_on_inside_range == INSIDE) { | ||
237 | asprintf(&result, "@"); | ||
238 | } | ||
239 | |||
240 | if (input.start_infinity) { | ||
241 | asprintf(&result, "%s~:", result); | ||
242 | } else { | ||
243 | asprintf(&result, "%s%s:", result, pd_value_to_string(input.start)); | ||
244 | } | ||
245 | |||
246 | if (!input.end_infinity) { | ||
247 | asprintf(&result, "%s%s", result, pd_value_to_string(input.end)); | ||
248 | } | ||
249 | return result; | ||
250 | } | ||
251 | |||
252 | mp_perfdata mp_set_pd_value_float(mp_perfdata pd, float value) { return mp_set_pd_value_double(pd, value); } | ||
253 | |||
254 | mp_perfdata mp_set_pd_value_double(mp_perfdata pd, double value) { | ||
255 | pd.value.pd_double = value; | ||
256 | pd.value.type = PD_TYPE_DOUBLE; | ||
257 | return pd; | ||
258 | } | ||
259 | |||
260 | mp_perfdata mp_set_pd_value_char(mp_perfdata pd, char value) { return mp_set_pd_value_long_long(pd, (long long)value); } | ||
261 | |||
262 | mp_perfdata mp_set_pd_value_u_char(mp_perfdata pd, unsigned char value) { return mp_set_pd_value_u_long_long(pd, (unsigned long long)value); } | ||
263 | |||
264 | mp_perfdata mp_set_pd_value_int(mp_perfdata pd, int value) { return mp_set_pd_value_long_long(pd, (long long)value); } | ||
265 | |||
266 | mp_perfdata mp_set_pd_value_u_int(mp_perfdata pd, unsigned int value) { return mp_set_pd_value_u_long_long(pd, (unsigned long long)value); } | ||
267 | |||
268 | mp_perfdata mp_set_pd_value_long(mp_perfdata pd, long value) { return mp_set_pd_value_long_long(pd, (long long)value); } | ||
269 | |||
270 | mp_perfdata mp_set_pd_value_u_long(mp_perfdata pd, unsigned long value) { | ||
271 | return mp_set_pd_value_u_long_long(pd, (unsigned long long)value); | ||
272 | } | ||
273 | |||
274 | mp_perfdata mp_set_pd_value_long_long(mp_perfdata pd, long long value) { | ||
275 | pd.value.pd_int = value; | ||
276 | pd.value.type = PD_TYPE_INT; | ||
277 | return pd; | ||
278 | } | ||
279 | |||
280 | mp_perfdata mp_set_pd_value_u_long_long(mp_perfdata pd, unsigned long long value) { | ||
281 | pd.value.pd_uint = value; | ||
282 | pd.value.type = PD_TYPE_UINT; | ||
283 | return pd; | ||
284 | } | ||
285 | |||
286 | mp_perfdata_value mp_create_pd_value_double(double value) { | ||
287 | mp_perfdata_value res = {0}; | ||
288 | res.type = PD_TYPE_DOUBLE; | ||
289 | res.pd_double = value; | ||
290 | return res; | ||
291 | } | ||
292 | |||
293 | mp_perfdata_value mp_create_pd_value_float(float value) { return mp_create_pd_value_double((double)value); } | ||
294 | |||
295 | mp_perfdata_value mp_create_pd_value_char(char value) { return mp_create_pd_value_long_long((long long)value); } | ||
296 | |||
297 | mp_perfdata_value mp_create_pd_value_u_char(unsigned char value) { return mp_create_pd_value_u_long_long((unsigned long long)value); } | ||
298 | |||
299 | mp_perfdata_value mp_create_pd_value_int(int value) { return mp_create_pd_value_long_long((long long)value); } | ||
300 | |||
301 | mp_perfdata_value mp_create_pd_value_u_int(unsigned int value) { return mp_create_pd_value_u_long_long((unsigned long long)value); } | ||
302 | |||
303 | mp_perfdata_value mp_create_pd_value_long(long value) { return mp_create_pd_value_long_long((long long)value); } | ||
304 | |||
305 | mp_perfdata_value mp_create_pd_value_u_long(unsigned long value) { return mp_create_pd_value_u_long_long((unsigned long long)value); } | ||
306 | |||
307 | mp_perfdata_value mp_create_pd_value_long_long(long long value) { | ||
308 | mp_perfdata_value res = {0}; | ||
309 | res.type = PD_TYPE_INT; | ||
310 | res.pd_int = value; | ||
311 | return res; | ||
312 | } | ||
313 | |||
314 | mp_perfdata_value mp_create_pd_value_u_long_long(unsigned long long value) { | ||
315 | mp_perfdata_value res = {0}; | ||
316 | res.type = PD_TYPE_UINT; | ||
317 | res.pd_uint = value; | ||
318 | return res; | ||
319 | } | ||
320 | |||
321 | char *fmt_range(range foo) { return foo.text; } | ||
322 | |||
323 | typedef struct integer_parser_wrapper { | ||
324 | int error; | ||
325 | mp_perfdata_value value; | ||
326 | } integer_parser_wrapper; | ||
327 | |||
328 | typedef struct double_parser_wrapper { | ||
329 | int error; | ||
330 | mp_perfdata_value value; | ||
331 | } double_parser_wrapper; | ||
332 | |||
333 | typedef struct perfdata_value_parser_wrapper { | ||
334 | int error; | ||
335 | mp_perfdata_value value; | ||
336 | } perfdata_value_parser_wrapper; | ||
337 | |||
338 | double_parser_wrapper parse_double(const char *input); | ||
339 | integer_parser_wrapper parse_integer(const char *input); | ||
340 | perfdata_value_parser_wrapper parse_pd_value(const char *input); | ||
341 | |||
342 | mp_range_parsed mp_parse_range_string(const char *input) { | ||
343 | if (input == NULL) { | ||
344 | mp_range_parsed result = { | ||
345 | .error = MP_RANGE_PARSING_FAILURE, | ||
346 | }; | ||
347 | return result; | ||
348 | } | ||
349 | |||
350 | if (strlen(input) == 0) { | ||
351 | mp_range_parsed result = { | ||
352 | .error = MP_RANGE_PARSING_FAILURE, | ||
353 | }; | ||
354 | return result; | ||
355 | } | ||
356 | |||
357 | mp_range_parsed result = { | ||
358 | .range = mp_range_init(), | ||
359 | .error = MP_PARSING_SUCCES, | ||
360 | }; | ||
361 | |||
362 | if (input[0] == '@') { | ||
363 | // found an '@' at beginning, so invert the range logic | ||
364 | result.range.alert_on_inside_range = INSIDE; | ||
365 | |||
366 | // advance the pointer one symbol | ||
367 | input++; | ||
368 | } | ||
369 | |||
370 | char *working_copy = strdup(input); | ||
371 | input = working_copy; | ||
372 | |||
373 | char *separator = index(working_copy, ':'); | ||
374 | if (separator != NULL) { | ||
375 | // Found a separator | ||
376 | // set the separator to 0, so we have two different strings | ||
377 | *separator = '\0'; | ||
378 | |||
379 | if (input[0] == '~') { | ||
380 | // the beginning starts with '~', so it might be infinity | ||
381 | if (&input[1] != separator) { | ||
382 | // the next symbol after '~' is not the separator! | ||
383 | // so input is probably wrong | ||
384 | result.error = MP_RANGE_PARSING_FAILURE; | ||
385 | free(working_copy); | ||
386 | return result; | ||
387 | } | ||
388 | |||
389 | result.range.start_infinity = true; | ||
390 | } else { | ||
391 | // No '~' at the beginning, so this should be a number | ||
392 | result.range.start_infinity = false; | ||
393 | perfdata_value_parser_wrapper parsed_pd = parse_pd_value(input); | ||
394 | |||
395 | if (parsed_pd.error != MP_PARSING_SUCCES) { | ||
396 | result.error = parsed_pd.error; | ||
397 | free(working_copy); | ||
398 | return result; | ||
399 | } | ||
400 | |||
401 | result.range.start = parsed_pd.value; | ||
402 | result.range.start_infinity = false; | ||
403 | } | ||
404 | // got the first part now | ||
405 | // advance the pointer | ||
406 | input = separator + 1; | ||
407 | } | ||
408 | |||
409 | // End part or no separator | ||
410 | if (input[0] == '\0') { | ||
411 | // the end is infinite | ||
412 | result.range.end_infinity = true; | ||
413 | } else { | ||
414 | perfdata_value_parser_wrapper parsed_pd = parse_pd_value(input); | ||
415 | |||
416 | if (parsed_pd.error != MP_PARSING_SUCCES) { | ||
417 | result.error = parsed_pd.error; | ||
418 | return result; | ||
419 | } | ||
420 | result.range.end = parsed_pd.value; | ||
421 | result.range.end_infinity = false; | ||
422 | } | ||
423 | free(working_copy); | ||
424 | return result; | ||
425 | } | ||
426 | |||
427 | double_parser_wrapper parse_double(const char *input) { | ||
428 | double_parser_wrapper result = { | ||
429 | .error = MP_PARSING_SUCCES, | ||
430 | }; | ||
431 | |||
432 | if (input == NULL) { | ||
433 | result.error = MP_PARSING_FAILURE; | ||
434 | return result; | ||
435 | } | ||
436 | |||
437 | char *endptr = NULL; | ||
438 | errno = 0; | ||
439 | double tmp = strtod(input, &endptr); | ||
440 | |||
441 | if (input == endptr) { | ||
442 | // man 3 strtod says, no conversion performed | ||
443 | result.error = MP_PARSING_FAILURE; | ||
444 | return result; | ||
445 | } | ||
446 | |||
447 | if (errno) { | ||
448 | // some other error | ||
449 | // TODO maybe differentiate a little bit | ||
450 | result.error = MP_PARSING_FAILURE; | ||
451 | return result; | ||
452 | } | ||
453 | |||
454 | result.value = mp_create_pd_value(tmp); | ||
455 | return result; | ||
456 | } | ||
457 | |||
458 | integer_parser_wrapper parse_integer(const char *input) { | ||
459 | integer_parser_wrapper result = { | ||
460 | .error = MP_PARSING_SUCCES, | ||
461 | }; | ||
462 | |||
463 | if (input == NULL) { | ||
464 | result.error = MP_PARSING_FAILURE; | ||
465 | return result; | ||
466 | } | ||
467 | |||
468 | char *endptr = NULL; | ||
469 | errno = 0; | ||
470 | long long tmp = strtoll(input, &endptr, 0); | ||
471 | |||
472 | // validating *sigh* | ||
473 | if (*endptr != '\0') { | ||
474 | // something went wrong in strtoll | ||
475 | if (tmp == LLONG_MIN) { | ||
476 | // underflow | ||
477 | result.error = MP_RANGE_PARSING_UNDERFLOW; | ||
478 | return result; | ||
479 | } | ||
480 | |||
481 | if (tmp == LLONG_MAX) { | ||
482 | // overflow | ||
483 | result.error = MP_RANGE_PARSING_OVERFLOW; | ||
484 | return result; | ||
485 | } | ||
486 | |||
487 | // still wrong, but not sure why, probably invalid characters | ||
488 | if (errno == EINVAL) { | ||
489 | result.error = MP_RANGE_PARSING_INVALID_CHAR; | ||
490 | return result; | ||
491 | } | ||
492 | |||
493 | // some other error, do catch all here | ||
494 | result.error = MP_RANGE_PARSING_FAILURE; | ||
495 | return result; | ||
496 | } | ||
497 | |||
498 | // no error, should be fine | ||
499 | result.value = mp_create_pd_value(tmp); | ||
500 | return result; | ||
501 | } | ||
502 | |||
503 | perfdata_value_parser_wrapper parse_pd_value(const char *input) { | ||
504 | // try integer first | ||
505 | integer_parser_wrapper tmp_int = parse_integer(input); | ||
506 | |||
507 | if (tmp_int.error == MP_PARSING_SUCCES) { | ||
508 | perfdata_value_parser_wrapper result = { | ||
509 | .error = tmp_int.error, | ||
510 | .value = tmp_int.value, | ||
511 | }; | ||
512 | return result; | ||
513 | } | ||
514 | |||
515 | double_parser_wrapper tmp_double = parse_double(input); | ||
516 | perfdata_value_parser_wrapper result = {}; | ||
517 | if (tmp_double.error == MP_PARSING_SUCCES) { | ||
518 | result.error = tmp_double.error; | ||
519 | result.value = tmp_double.value; | ||
520 | } else { | ||
521 | result.error = tmp_double.error; | ||
522 | } | ||
523 | return result; | ||
524 | } | ||
525 | |||
526 | mp_perfdata mp_set_pd_max_value(mp_perfdata perfdata, mp_perfdata_value value) { | ||
527 | perfdata.max = value; | ||
528 | perfdata.max_present = true; | ||
529 | return perfdata; | ||
530 | } | ||
531 | |||
532 | mp_perfdata mp_set_pd_min_value(mp_perfdata perfdata, mp_perfdata_value value) { | ||
533 | perfdata.min = value; | ||
534 | perfdata.min_present = true; | ||
535 | return perfdata; | ||
536 | } | ||
537 | |||
538 | double mp_get_pd_value(mp_perfdata_value value) { | ||
539 | assert(value.type != PD_TYPE_NONE); | ||
540 | switch (value.type) { | ||
541 | case PD_TYPE_DOUBLE: | ||
542 | return value.pd_double; | ||
543 | case PD_TYPE_INT: | ||
544 | return (double)value.pd_int; | ||
545 | case PD_TYPE_UINT: | ||
546 | return (double)value.pd_uint; | ||
547 | default: | ||
548 | return 0; // just to make the compiler happy | ||
549 | } | ||
550 | } | ||
551 | |||
552 | mp_perfdata_value mp_pd_value_multiply(mp_perfdata_value left, mp_perfdata_value right) { | ||
553 | if (left.type == right.type) { | ||
554 | switch (left.type) { | ||
555 | case PD_TYPE_DOUBLE: | ||
556 | left.pd_double *= right.pd_double; | ||
557 | return left; | ||
558 | case PD_TYPE_INT: | ||
559 | left.pd_int *= right.pd_int; | ||
560 | return left; | ||
561 | case PD_TYPE_UINT: | ||
562 | left.pd_uint *= right.pd_uint; | ||
563 | return left; | ||
564 | default: | ||
565 | // what to here? | ||
566 | return left; | ||
567 | } | ||
568 | } | ||
569 | |||
570 | // Different types, oh boy, just do the lazy thing for now and switch to double | ||
571 | switch (left.type) { | ||
572 | case PD_TYPE_INT: | ||
573 | left.pd_double = (double)left.pd_int; | ||
574 | left.type = PD_TYPE_DOUBLE; | ||
575 | break; | ||
576 | case PD_TYPE_UINT: | ||
577 | left.pd_double = (double)left.pd_uint; | ||
578 | left.type = PD_TYPE_DOUBLE; | ||
579 | break; | ||
580 | } | ||
581 | |||
582 | switch (right.type) { | ||
583 | case PD_TYPE_INT: | ||
584 | right.pd_double = (double)right.pd_int; | ||
585 | right.type = PD_TYPE_DOUBLE; | ||
586 | break; | ||
587 | case PD_TYPE_UINT: | ||
588 | right.pd_double = (double)right.pd_uint; | ||
589 | right.type = PD_TYPE_DOUBLE; | ||
590 | break; | ||
591 | } | ||
592 | |||
593 | left.pd_double *= right.pd_double; | ||
594 | return left; | ||
595 | } | ||
596 | |||
597 | mp_range mp_range_multiply(mp_range range, mp_perfdata_value factor) { | ||
598 | if (!range.end_infinity) { | ||
599 | range.end = mp_pd_value_multiply(range.end, factor); | ||
600 | } | ||
601 | if (!range.start_infinity) { | ||
602 | range.start = mp_pd_value_multiply(range.start, factor); | ||
603 | } | ||
604 | return range; | ||
605 | } | ||