replace SPDX identifier GPL-2.0+ with GPL-2.0-or-later.
[metze/wireshark/wip.git] / wsutil / str_util.c
1 /* str_util.c
2  * String utility routines
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
6  * Copyright 1998 Gerald Combs
7  *
8  * SPDX-License-Identifier: GPL-2.0-or-later
9  */
10
11 #include <config.h>
12
13 #include "str_util.h"
14
15 int
16 ws_xton(char ch)
17 {
18         switch (ch) {
19                 case '0': return 0;
20                 case '1': return 1;
21                 case '2': return 2;
22                 case '3': return 3;
23                 case '4': return 4;
24                 case '5': return 5;
25                 case '6': return 6;
26                 case '7': return 7;
27                 case '8': return 8;
28                 case '9': return 9;
29                 case 'a':  case 'A': return 10;
30                 case 'b':  case 'B': return 11;
31                 case 'c':  case 'C': return 12;
32                 case 'd':  case 'D': return 13;
33                 case 'e':  case 'E': return 14;
34                 case 'f':  case 'F': return 15;
35                 default: return -1;
36         }
37 }
38
39 /* Convert all ASCII letters to lower case, in place. */
40 gchar *
41 ascii_strdown_inplace(gchar *str)
42 {
43         gchar *s;
44
45         for (s = str; *s; s++)
46                 /* What 'g_ascii_tolower (gchar c)' does, this should be slightly more efficient */
47                 *s = g_ascii_isupper (*s) ? *s - 'A' + 'a' : *s;
48
49         return (str);
50 }
51
52 /* Convert all ASCII letters to upper case, in place. */
53 gchar *
54 ascii_strup_inplace(gchar *str)
55 {
56         gchar *s;
57
58         for (s = str; *s; s++)
59                 /* What 'g_ascii_toupper (gchar c)' does, this should be slightly more efficient */
60                 *s = g_ascii_islower (*s) ? *s - 'a' + 'A' : *s;
61
62         return (str);
63 }
64
65 /* Check if an entire string is printable. */
66 gboolean
67 isprint_string(const gchar *str)
68 {
69         guint pos;
70
71         /* Loop until we reach the end of the string (a null) */
72         for(pos = 0; str[pos] != '\0'; pos++){
73                 if(!g_ascii_isprint(str[pos])){
74                         /* The string contains a non-printable character */
75                         return FALSE;
76                 }
77         }
78
79         /* The string contains only printable characters */
80         return TRUE;
81 }
82
83 /* Check if an entire string is digits. */
84 gboolean
85 isdigit_string(guchar *str)
86 {
87         guint pos;
88
89         /* Loop until we reach the end of the string (a null) */
90         for(pos = 0; str[pos] != '\0'; pos++){
91                 if(!g_ascii_isdigit(str[pos])){
92                         /* The string contains a non-digit character */
93                         return FALSE;
94                 }
95         }
96
97         /* The string contains only digits */
98         return TRUE;
99 }
100
101 #define FORMAT_SIZE_UNIT_MASK 0x00ff
102 #define FORMAT_SIZE_PFX_MASK 0xff00
103
104 static const char *thousands_grouping_fmt = NULL;
105
106 DIAG_OFF(format)
107 static void test_printf_thousands_grouping(void) {
108         /* test whether g_printf works with "'" flag character */
109         gchar *str = g_strdup_printf("%'d", 22);
110         if (g_strcmp0(str, "22") == 0) {
111                 thousands_grouping_fmt = "%'"G_GINT64_MODIFIER"d";
112         } else {
113                 /* Don't use */
114                 thousands_grouping_fmt = "%"G_GINT64_MODIFIER"d";
115         }
116         g_free(str);
117 }
118 DIAG_ON(format)
119
120 /* Given a size, return its value in a human-readable format */
121 /* This doesn't handle fractional values. We might want to make size a double. */
122 gchar *
123 format_size(gint64 size, format_size_flags_e flags)
124 {
125         GString *human_str = g_string_new("");
126         int power = 1000;
127         int pfx_off = 0;
128         gboolean is_small = FALSE;
129         static const gchar *prefix[] = {" T", " G", " M", " k", " Ti", " Gi", " Mi", " Ki"};
130         gchar *ret_val;
131
132         if (thousands_grouping_fmt == NULL)
133                 test_printf_thousands_grouping();
134
135         if ((flags & FORMAT_SIZE_PFX_MASK) == format_size_prefix_iec) {
136                 pfx_off = 4;
137                 power = 1024;
138         }
139
140         if (size / power / power / power / power >= 10) {
141                 g_string_printf(human_str, thousands_grouping_fmt, size / power / power / power / power);
142                 g_string_append(human_str, prefix[pfx_off]);
143         } else if (size / power / power / power >= 10) {
144                 g_string_printf(human_str, thousands_grouping_fmt, size / power / power / power);
145                 g_string_append(human_str, prefix[pfx_off+1]);
146         } else if (size / power / power >= 10) {
147                 g_string_printf(human_str, thousands_grouping_fmt, size / power / power);
148                 g_string_append(human_str, prefix[pfx_off+2]);
149         } else if (size / power >= 10) {
150                 g_string_printf(human_str, thousands_grouping_fmt, size / power);
151                 g_string_append(human_str, prefix[pfx_off+3]);
152         } else {
153                 g_string_printf(human_str, thousands_grouping_fmt, size);
154                 is_small = TRUE;
155         }
156
157
158         switch (flags & FORMAT_SIZE_UNIT_MASK) {
159                 case format_size_unit_none:
160                         break;
161                 case format_size_unit_bytes:
162                         g_string_append(human_str, is_small ? " bytes" : "B");
163                         break;
164                 case format_size_unit_bits:
165                         g_string_append(human_str, is_small ? " bits" : "b");
166                         break;
167                 case format_size_unit_bits_s:
168                         g_string_append(human_str, is_small ? " bits/s" : "bps");
169                         break;
170                 case format_size_unit_bytes_s:
171                         g_string_append(human_str, is_small ? " bytes/s" : "Bps");
172                         break;
173                 case format_size_unit_packets:
174                         g_string_append(human_str, is_small ? " packets" : "packets");
175                         break;
176                 case format_size_unit_packets_s:
177                         g_string_append(human_str, is_small ? " packets/s" : "packets/s");
178                         break;
179                 default:
180                         g_assert_not_reached();
181         }
182
183         ret_val = g_string_free(human_str, FALSE);
184         return g_strchomp(ret_val);
185 }
186
187 gchar
188 printable_char_or_period(gchar c)
189 {
190         return g_ascii_isprint(c) ? c : '.';
191 }
192
193 /*
194  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
195  *
196  * Local variables:
197  * c-basic-offset: 8
198  * tab-width: 8
199  * indent-tabs-mode: t
200  * End:
201  *
202  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
203  * :indentSize=8:tabSize=8:noTabs=false:
204  */