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