57b979bc22552830e73af4381077342c2a2ff962
[NetworkManager.git] / shared / nm-shared-utils.c
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* NetworkManager -- Network link manager
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301 USA.
18  *
19  * (C) Copyright 2016 Red Hat, Inc.
20  */
21
22 #include "nm-default.h"
23
24 #include "nm-shared-utils.h"
25
26 #include <errno.h>
27
28 /*****************************************************************************/
29
30 /* _nm_utils_ascii_str_to_int64:
31  *
32  * A wrapper for g_ascii_strtoll, that checks whether the whole string
33  * can be successfully converted to a number and is within a given
34  * range. On any error, @fallback will be returned and %errno will be set
35  * to a non-zero value. On success, %errno will be set to zero, check %errno
36  * for errors. Any trailing or leading (ascii) white space is ignored and the
37  * functions is locale independent.
38  *
39  * The function is guaranteed to return a value between @min and @max
40  * (inclusive) or @fallback. Also, the parsing is rather strict, it does
41  * not allow for any unrecognized characters, except leading and trailing
42  * white space.
43  **/
44 gint64
45 _nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max, gint64 fallback)
46 {
47         gint64 v;
48         size_t len;
49         char buf[64], *s, *str_free = NULL;
50
51         if (str) {
52                 while (g_ascii_isspace (str[0]))
53                         str++;
54         }
55         if (!str || !str[0]) {
56                 errno = EINVAL;
57                 return fallback;
58         }
59
60         len = strlen (str);
61         if (g_ascii_isspace (str[--len])) {
62                 /* backward search the first non-ws character.
63                  * We already know that str[0] is non-ws. */
64                 while (g_ascii_isspace (str[--len]))
65                         ;
66
67                 /* str[len] is now the last non-ws character... */
68                 len++;
69
70                 if (len >= sizeof (buf))
71                         s = str_free = g_malloc (len + 1);
72                 else
73                         s = buf;
74
75                 memcpy (s, str, len);
76                 s[len] = 0;
77
78                 nm_assert (len > 0 && len < strlen (str) && len == strlen (s));
79                 nm_assert (!g_ascii_isspace (str[len-1]) && g_ascii_isspace (str[len]));
80                 nm_assert (strncmp (str, s, len) == 0);
81
82                 str = s;
83         }
84
85         errno = 0;
86         v = g_ascii_strtoll (str, &s, base);
87
88         if (errno != 0)
89                 v = fallback;
90         else if (s[0] != 0) {
91                 errno = EINVAL;
92                 v = fallback;
93         } else if (v > max || v < min) {
94                 errno = ERANGE;
95                 v = fallback;
96         }
97
98         if (G_UNLIKELY (str_free))
99                 g_free (str_free);
100         return v;
101 }
102
103 /*****************************************************************************/
104
105 G_DEFINE_QUARK (nm-utils-error-quark, nm_utils_error)
106
107 void
108 nm_utils_error_set_cancelled (GError **error,
109                               gboolean is_disposing,
110                               const char *instance_name)
111 {
112         if (is_disposing) {
113                 g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_CANCELLED_DISPOSING,
114                              "Disposing %s instance",
115                              instance_name && *instance_name ? instance_name : "source");
116         } else {
117                 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CANCELLED,
118                                      "Request cancelled");
119         }
120 }
121
122 gboolean
123 nm_utils_error_is_cancelled (GError *error,
124                              gboolean consider_is_disposing)
125 {
126         if (error) {
127                 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
128                         return TRUE;
129                 if (   consider_is_disposing
130                     && g_error_matches (error, NM_UTILS_ERROR, NM_UTILS_ERROR_CANCELLED_DISPOSING))
131                         return TRUE;
132         }
133         return FALSE;
134 }
135
136 /*****************************************************************************/