1 /*
2 * Copyright 2012-2016 James Geboski <jgeboski@gmail.com>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program 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
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <stdarg.h>
19 #include <string.h>
20
21 #include "steam-util.h"
22
23 void
steam_util_debug(SteamDebugLevel level,const gchar * format,...)24 steam_util_debug(SteamDebugLevel level, const gchar *format, ...)
25 {
26 va_list ap;
27
28 va_start(ap, format);
29 steam_util_vdebug(level, format, ap);
30 va_end(ap);
31 }
32
33 void
steam_util_vdebug(SteamDebugLevel level,const gchar * format,va_list ap)34 steam_util_vdebug(SteamDebugLevel level, const gchar *format, va_list ap)
35 {
36 const gchar *lstr;
37 gchar *str;
38
39 static gboolean debug = FALSE;
40 static gboolean setup = FALSE;
41
42 g_return_if_fail(format != NULL);
43
44 if (G_UNLIKELY(!setup)) {
45 debug = (g_getenv("BITLBEE_DEBUG") != NULL) ||
46 (g_getenv("BITLBEE_DEBUG_STEAM") != NULL);
47 setup = TRUE;
48 }
49
50 if (!debug) {
51 return;
52 }
53
54 switch (level) {
55 case STEAM_UTIL_DEBUG_LEVEL_MISC:
56 lstr = "MISC";
57 break;
58 case STEAM_UTIL_DEBUG_LEVEL_INFO:
59 lstr = "INFO";
60 break;
61 case STEAM_UTIL_DEBUG_LEVEL_WARN:
62 lstr = "WARN";
63 break;
64 case STEAM_UTIL_DEBUG_LEVEL_ERROR:
65 lstr = "ERROR";
66 break;
67 case STEAM_UTIL_DEBUG_LEVEL_FATAL:
68 lstr = "FATAL";
69 break;
70
71 default:
72 g_return_if_reached();
73 return;
74 }
75
76 str = g_strdup_vprintf(format, ap);
77 g_print("[%s] %s: %s\n", lstr, "steam", str);
78 g_free(str);
79 }
80
81 void
steam_util_debug_misc(const gchar * format,...)82 steam_util_debug_misc(const gchar *format, ...)
83 {
84 va_list ap;
85
86 va_start(ap, format);
87 steam_util_vdebug(STEAM_UTIL_DEBUG_LEVEL_MISC, format, ap);
88 va_end(ap);
89 }
90
91 void
steam_util_debug_info(const gchar * format,...)92 steam_util_debug_info(const gchar *format, ...)
93 {
94 va_list ap;
95
96 va_start(ap, format);
97 steam_util_vdebug(STEAM_UTIL_DEBUG_LEVEL_INFO, format, ap);
98 va_end(ap);
99 }
100
101 void
steam_util_debug_warn(const gchar * format,...)102 steam_util_debug_warn(const gchar *format, ...)
103 {
104 va_list ap;
105
106 va_start(ap, format);
107 steam_util_vdebug(STEAM_UTIL_DEBUG_LEVEL_WARN, format, ap);
108 va_end(ap);
109 }
110
111 void
steam_util_debug_error(const gchar * format,...)112 steam_util_debug_error(const gchar *format, ...)
113 {
114 va_list ap;
115
116 va_start(ap, format);
117 steam_util_vdebug(STEAM_UTIL_DEBUG_LEVEL_ERROR, format, ap);
118 va_end(ap);
119 }
120
121 void
steam_util_debug_fatal(const gchar * format,...)122 steam_util_debug_fatal(const gchar *format, ...)
123 {
124 va_list ap;
125
126 va_start(ap, format);
127 steam_util_vdebug(STEAM_UTIL_DEBUG_LEVEL_FATAL, format, ap);
128 va_end(ap);
129 }
130
131 gpointer
steam_util_enum_ptr(const SteamUtilEnum * enums,gpointer def,guint val)132 steam_util_enum_ptr(const SteamUtilEnum *enums, gpointer def, guint val)
133 {
134 guint i;
135
136 g_return_val_if_fail(enums != NULL, NULL);
137
138 for (i = 0; enums[i].ptr != NULL; i++) {
139 if (enums[i].val == val) {
140 return enums[i].ptr;
141 }
142 }
143
144 return def;
145 }
146
147 gpointer *
steam_util_enum_ptrs(const SteamUtilEnum * enums,guint vals)148 steam_util_enum_ptrs(const SteamUtilEnum *enums, guint vals)
149 {
150 gpointer *ptrs;
151 gsize size = 0;
152 guint i;
153 guint j;
154
155 g_return_val_if_fail(enums != NULL, g_new0(gpointer, 0));
156
157 for (i = 0; enums[i].ptr != NULL; i++) {
158 if (vals & enums[i].val) {
159 size++;
160 }
161 }
162
163 ptrs = g_new0(gpointer, ++size);
164
165 for (i = 0, j = 0; enums[i].ptr != NULL; i++) {
166 if (vals & enums[i].val) {
167 ptrs[j++] = enums[i].ptr;
168 }
169 }
170
171 return ptrs;
172 }
173
174 guint
steam_util_enum_val(const SteamUtilEnum * enums,guint def,gconstpointer ptr,GCompareFunc cmpfunc)175 steam_util_enum_val(const SteamUtilEnum *enums, guint def,
176 gconstpointer ptr, GCompareFunc cmpfunc)
177 {
178 guint i;
179
180 g_return_val_if_fail(enums != NULL, 0);
181 g_return_val_if_fail(ptr != NULL, 0);
182 g_return_val_if_fail(cmpfunc != NULL, 0);
183
184 for (i = 0; enums[i].ptr != NULL; i++) {
185 if (cmpfunc(ptr, enums[i].ptr) == 0) {
186 return enums[i].val;
187 }
188 }
189
190 return def;
191 }
192
193 GByteArray *
steam_util_str_hex2bytes(const gchar * str)194 steam_util_str_hex2bytes(const gchar *str)
195 {
196 gboolean hax;
197 GByteArray *ret;
198 gchar val;
199 gsize size;
200 guint d;
201 guint i;
202
203 g_return_val_if_fail(str != NULL, NULL);
204
205 size = strlen(str);
206 hax = (size % 2) != 0;
207
208 ret = g_byte_array_new();
209 g_byte_array_set_size(ret, (size + 1) / 2);
210 memset(ret->data, 0, ret->len);
211
212 for (d = i = 0; i < size; i++, hax = !hax) {
213 val = g_ascii_xdigit_value(str[i]);
214
215 if (val < 0) {
216 g_byte_array_free(ret, TRUE);
217 return NULL;
218 }
219
220 if (hax) {
221 ret->data[d++] |= val & 0x0F;
222 } else {
223 ret->data[d] |= (val << 4) & 0xF0;
224 }
225 }
226
227 return ret;
228 }
229
230 gboolean
steam_util_str_iequal(const gchar * s1,const gchar * s2)231 steam_util_str_iequal(const gchar *s1, const gchar *s2)
232 {
233 return g_ascii_strcasecmp(s1, s2) == 0;
234 }
235
236 gchar *
steam_util_time_span_str(GTimeSpan span)237 steam_util_time_span_str(GTimeSpan span)
238 {
239 gchar *str;
240 guint i;
241
242 static const SteamUtilTimeSpan spans[] = {
243 {"second", 1},
244 {"minute", 60},
245 {"hour", 60 * 60},
246 {"day", 60 * 60 * 24},
247 {"week", 60 * 60 * 24 * 7},
248 {"month", 60 * 60 * 24 * 30},
249 {"year", 60 * 60 * 24 * 365},
250 {NULL, 0}
251 };
252
253 span /= G_TIME_SPAN_SECOND;
254
255 for (i = 1; spans[i].name != NULL; i++) {
256 if (span < spans[i].span) {
257 span /= spans[--i].span;
258 break;
259 }
260
261 if (G_UNLIKELY(spans[i + 1].name == NULL)) {
262 span /= spans[i].span;
263 break;
264 }
265 }
266
267 str = g_strdup_printf("%" G_GINT64_FORMAT " %s%s", span, spans[i].name,
268 ((span > 1) ? "s" : ""));
269
270 return str;
271 }
272
273 gchar *
steam_util_time_since_utc(gint64 timestamp)274 steam_util_time_since_utc(gint64 timestamp)
275 {
276 GDateTime *beg;
277 GDateTime *end;
278 GTimeSpan spn;
279
280 beg = g_date_time_new_from_unix_utc(timestamp);
281 end = g_date_time_new_now_utc();
282 spn = g_date_time_difference(end, beg);
283
284 g_date_time_unref(beg);
285 g_date_time_unref(end);
286
287 if (G_UNLIKELY(spn < 0)) {
288 spn = -spn;
289 }
290
291 return steam_util_time_span_str(spn);
292 }
293
294 gchar *
steam_util_ustrchr(const gchar * str,gchar chr)295 steam_util_ustrchr(const gchar *str, gchar chr)
296 {
297 gchar qc;
298 gsize cs;
299 gsize i;
300 gsize ssz;
301 gssize j;
302
303 if (G_UNLIKELY(str == NULL)) {
304 return NULL;
305 }
306
307 ssz = strlen(str);
308
309 for (qc = i = 0; i < ssz; i++) {
310 if ((qc == 0) && (str[i] == chr)) {
311 return (gchar *) str + i;
312 }
313
314 if ((str[i] != '"') && (str[i] != '\'')) {
315 continue;
316 }
317
318 if ((qc != 0) && (str[i] != qc)) {
319 continue;
320 }
321
322 for (cs = 0, j = i - 1; (j >= 0) && (str[j] == '\\'); j--, cs++);
323
324 if ((cs % 2) == 0) {
325 qc = (qc == 0) ? str[i] : 0;
326 }
327 }
328
329 return NULL;
330 }
331