Merge pull request #2408 from tastywheattasteslikechicken/MoreInterfaceSupport
[mono.git] / mono / utils / parse.c
1 /*
2  * parse.c: Parsing for GC options.
3  *
4  * Copyright (C) 2015 Xamarin Inc
5  *
6  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
7  */
8
9 #include <config.h>
10 #include <glib.h>
11 #include <string.h>
12 #include <errno.h>
13 #include <ctype.h>
14 #include <stdlib.h>
15
16 #include "parse.h"
17
18 /**
19  * mono_gc_parse_environment_string_extract_number:
20  *
21  * @str: points to the first digit of the number
22  * @out: pointer to the variable that will receive the value
23  *
24  * Tries to extract a number from the passed string, taking in to account m, k
25  * and g suffixes
26  *
27  * Returns true if passing was successful
28  */
29 gboolean
30 mono_gc_parse_environment_string_extract_number (const char *str, size_t *out)
31 {
32         char *endptr;
33         int len = strlen (str), shift = 0;
34         size_t val;
35         gboolean is_suffix = FALSE;
36         char suffix;
37
38         if (!len)
39                 return FALSE;
40
41         suffix = str [len - 1];
42
43         switch (suffix) {
44                 case 'g':
45                 case 'G':
46                         shift += 10;
47                 case 'm':
48                 case 'M':
49                         shift += 10;
50                 case 'k':
51                 case 'K':
52                         shift += 10;
53                         is_suffix = TRUE;
54                         break;
55                 default:
56                         if (!isdigit (suffix))
57                                 return FALSE;
58                         break;
59         }
60
61         errno = 0;
62         val = strtol (str, &endptr, 10);
63
64         if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
65                         || (errno != 0 && val == 0) || (endptr == str))
66                 return FALSE;
67
68         if (is_suffix) {
69                 size_t unshifted;
70
71                 if (*(endptr + 1)) /* Invalid string. */
72                         return FALSE;
73
74                 unshifted = (size_t)val;
75                 val <<= shift;
76                 if (((size_t)val >> shift) != unshifted) /* value too large */
77                         return FALSE;
78         }
79
80         *out = val;
81         return TRUE;
82 }