1 /* GKrellM
2 | Copyright (C) 1999-2019 Bill Wilson
3 |
4 | Author: Bill Wilson billw@gkrellm.net
5 | Latest versions might be found at: http://gkrellm.net
6 |
7 |
8 | GKrellM is free software: you can redistribute it and/or modify it
9 | under the terms of the GNU General Public License as published by
10 | the Free Software Foundation, either version 3 of the License, or
11 | (at your option) any later version.
12 |
13 | GKrellM is distributed in the hope that it will be useful, but WITHOUT
14 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 | License for more details.
17 |
18 | You should have received a copy of the GNU General Public License
19 | along with this program. If not, see http://www.gnu.org/licenses/
20 |
21 |
22 | Additional permission under GNU GPL version 3 section 7
23 |
24 | If you modify this program, or any covered work, by linking or
25 | combining it with the OpenSSL project's OpenSSL library (or a
26 | modified version of that library), containing parts covered by
27 | the terms of the OpenSSL or SSLeay licenses, you are granted
28 | additional permission to convey the resulting work.
29 | Corresponding Source for a non-source form of such a combination
30 | shall include the source code for the parts of OpenSSL used as well
31 | as that of the covered work.
32 */
33
34 #include "gkrellm.h"
35 #include "gkrellm-private.h"
36
37 /* =============== string utility functions ================= */
38
39
40 gboolean
gkrellm_dup_string(gchar ** dst,gchar * src)41 gkrellm_dup_string(gchar **dst, gchar *src)
42 {
43 if (!dst || (!*dst && !src))
44 return FALSE;
45 if (*dst)
46 {
47 if (src && !strcmp(*dst, src))
48 return FALSE;
49 g_free(*dst);
50 }
51 *dst = g_strdup(src);
52 return TRUE;
53 }
54
55 static gboolean
any(gchar c,gchar * s)56 any(gchar c, gchar *s)
57 {
58 while (*s)
59 if (c == *s++)
60 return TRUE;
61 return FALSE;
62 }
63
64 /* Return a duplicated token from a string. "*string" points to the source
65 | string and is updated to point to the string remaining after the
66 | found token. If there is no next token, return an empty dupped string
67 | (not a NULL pointer) and leave *string unchanged.
68 | Unlike strtok(): args are not modified, gkrellm_token() can be used on
69 | constant strings, delimeter identity is not lost, and it's thread safe.
70 | Only the caller's initial string pointer is modified.
71 */
72 gchar *
gkrellm_dup_token(gchar ** string,gchar * delimeters)73 gkrellm_dup_token(gchar **string, gchar *delimeters)
74 {
75 gchar *str, *s, *delims;
76 gboolean quoted = FALSE;
77
78 if (!string || !*string)
79 return g_strdup("");
80
81 str = *string;
82 delims = delimeters ? delimeters : " \t\n";
83 while (any(*str, delims))
84 ++str;
85
86 if (*str == '"')
87 {
88 quoted = TRUE;
89 ++str;
90 for (s = str; *s && *s != '"'; ++s)
91 ;
92 }
93 else
94 for (s = str; *s && !any(*s, delims); ++s)
95 ;
96
97 *string = (quoted && *s) ? s + 1 : s;
98 return g_strndup(str, s - str);
99 }
100
101 /* Cut out an optionally quoted string. This is destructive to the src.
102 */
103 gchar *
gkrellm_cut_quoted_string(gchar * src,gchar ** endptr)104 gkrellm_cut_quoted_string(gchar *src, gchar **endptr)
105 {
106 gchar *s;
107
108 while (*src == ' ' || *src == '\t')
109 ++src;
110 if (*src == '"')
111 {
112 s = strchr(++src, '"');
113 if (s == NULL)
114 {
115 if (endptr)
116 *endptr = src;
117 g_warning(_("Unterminated quote\n"));
118 return NULL;
119 }
120 *s = '\0';
121 if (endptr)
122 *endptr = s + 1;
123 }
124 else
125 {
126 for (s = src; *s != '\0' && *s != ' ' && *s != '\t'; ++s)
127 ;
128 if (endptr)
129 *endptr = *s ? s + 1 : s;
130 *s = '\0';
131 }
132 return src;
133 }
134
135 /* If there is a line in the gstring ('\n' delimited) copy it to the
136 | line buffer including the newline and erase it from the gstring.
137 */
138 gboolean
gkrellm_getline_from_gstring(GString ** gstring,gchar * line,gint size)139 gkrellm_getline_from_gstring(GString **gstring, gchar *line, gint size)
140 {
141 GString *gstr = *gstring;
142 gchar *s;
143 gint len, n;
144
145 if (gstr && gstr->str && (s = strchr(gstr->str, '\n')) != NULL)
146 {
147 n = len = s - gstr->str + 1;
148 if (n >= size)
149 n = size - 1; /* Truncate the line to fit */
150 strncpy(line, gstr->str, n);
151 line[n] = '\0';
152 *gstring = g_string_erase(gstr, 0, len);
153 return TRUE;
154 }
155 return FALSE;
156 }
157
158 /* =============== list utility functions ================= */
159
160 void
gkrellm_free_glist_and_data(GList ** list_head)161 gkrellm_free_glist_and_data(GList **list_head)
162 {
163 GList *list;
164
165 if (*list_head == NULL)
166 return;
167
168 /* could use g_list_foreach(*list_head, (G_FUNC)g_free, NULL);
169 */
170 for (list = *list_head; list; list = list->next)
171 if (list->data)
172 g_free(list->data);
173 g_list_free(*list_head);
174 *list_head = NULL;
175 }
176
177
178 GList *
gkrellm_string_in_list(GList * list,gchar * s)179 gkrellm_string_in_list(GList *list, gchar *s)
180 {
181 if (!s)
182 return NULL;
183 for ( ; list; list = list->next)
184 {
185 if (!strcmp((gchar *) list->data, s))
186 return list;
187 }
188 return NULL;
189 }
190
191 gint
gkrellm_string_position_in_list(GList * list,gchar * s)192 gkrellm_string_position_in_list(GList *list, gchar *s)
193 {
194 gint i, n = -1;
195
196 if (!s)
197 return -1;
198 for (i = 0 ; list; list = list->next, ++i)
199 {
200 if (!strcmp((gchar *) list->data, s))
201 {
202 n = i;
203 break;
204 }
205 }
206 return n;
207 }
208
209
210
211 /* =============== file utility functions ================= */
212 gchar *
gkrellm_homedir(void)213 gkrellm_homedir(void)
214 {
215 gchar *homedir;
216
217 homedir = (gchar *) g_get_home_dir();
218 if (!homedir)
219 homedir = ".";
220 return homedir;
221 }
222
223 gboolean
gkrellm_make_home_subdir(gchar * subdir,gchar ** path)224 gkrellm_make_home_subdir(gchar *subdir, gchar **path)
225 {
226 gchar *dir;
227 gint result = FALSE;
228
229 dir = g_build_path(G_DIR_SEPARATOR_S, gkrellm_homedir(), subdir, NULL);
230 if (!g_file_test(dir, G_FILE_TEST_IS_DIR))
231 {
232 if (g_mkdir(dir, 0755) < 0)
233 g_warning(_("Cannot create directory: %s\n"), dir);
234 else
235 result = TRUE;
236 }
237 if (path)
238 *path = dir;
239 else
240 g_free(dir);
241 return result;
242 }
243
244
245 /* =============== GtkWidget utility functions ================= */
246
247 gchar *
gkrellm_gtk_entry_get_text(GtkWidget ** entry)248 gkrellm_gtk_entry_get_text(GtkWidget **entry)
249 {
250 static /*const*/ gchar *def_s = "";
251 gchar *s = def_s;
252
253 if (*entry)
254 {
255 s = (gchar *)gtk_entry_get_text(GTK_ENTRY(*entry));
256 while (*s == ' ' || *s == '\t')
257 ++s;
258 }
259 return s;
260 }
261
262
263 /* =============== Miscellaneous utility functions ================= */
264
265 /* Print a size, abbreviating it to kilo, mega, or giga units depending
266 | on its magnitude.
267 | An aside: Memory capacities are traditionally reported in binary
268 | units (Kib, Mib, etc) while just about everything else should be
269 | reported in decimal units (KB, MB, etc). This includes transfer
270 | rates, and disk capacities, contrary to what many people think.
271 | Take a look at http://www.pcguide.com/intro/fun/bindec.htm
272 */
273 gint
gkrellm_format_size_abbrev(gchar * buf,size_t buflen,gfloat size,GkrellmSizeAbbrev * tbl,size_t tbl_size)274 gkrellm_format_size_abbrev(gchar *buf, size_t buflen, gfloat size,
275 GkrellmSizeAbbrev *tbl, size_t tbl_size)
276 {
277 gfloat abs_size;
278 gint i;
279 int ret;
280
281 abs_size = (size < 0.0) ? -size : size;
282
283 for (i = 0; i < tbl_size - 1; ++i)
284 if (abs_size < tbl[i].limit)
285 break;
286 ret = snprintf(buf, buflen, tbl[i].format, size / tbl[i].divisor);
287 if (ret < 0 || ret >= buflen)
288 return 0;
289 return ret;
290 }
291
292
293 /* Next three calls return string extent info. Width extents are logical
294 | so that spaces will be counted while height extent is ink so that gkrellm
295 | can optimize vertical space utilization.
296 */
297 gint
gkrellm_gdk_text_width(PangoFontDescription * font_desc,const gchar * string,gint len)298 gkrellm_gdk_text_width(PangoFontDescription *font_desc,
299 const gchar *string, gint len)
300 {
301 PangoLayout *layout;
302 gint w, h;
303
304 layout = gtk_widget_create_pango_layout(gkrellm_get_top_window(), NULL);
305 pango_layout_set_font_description(layout, font_desc);
306 pango_layout_set_text(layout, string, len);
307 pango_layout_get_pixel_size(layout, &w, &h);
308 g_object_unref(layout);
309 return w;
310 }
311
312 gint
gkrellm_gdk_text_markup_width(PangoFontDescription * font_desc,const gchar * string,gint len)313 gkrellm_gdk_text_markup_width(PangoFontDescription *font_desc,
314 const gchar *string, gint len)
315 {
316 PangoLayout *layout;
317 gint w, h;
318
319 layout = gtk_widget_create_pango_layout(gkrellm_get_top_window(), NULL);
320 pango_layout_set_font_description(layout, font_desc);
321 pango_layout_set_markup(layout, string, len);
322 pango_layout_get_pixel_size(layout, &w, &h);
323 g_object_unref(layout);
324 return w;
325 }
326
327 gint
gkrellm_gdk_string_width(PangoFontDescription * font_desc,gchar * string)328 gkrellm_gdk_string_width(PangoFontDescription *font_desc, gchar *string)
329 {
330 PangoLayout *layout;
331 gint w, h;
332
333 layout = gtk_widget_create_pango_layout(gkrellm_get_top_window(), NULL);
334 pango_layout_set_font_description(layout, font_desc);
335 pango_layout_set_text(layout, string, strlen(string));
336 pango_layout_get_pixel_size(layout, &w, &h);
337 g_object_unref(layout);
338 return w;
339 }
340
341 gint
gkrellm_gdk_string_markup_width(PangoFontDescription * font_desc,gchar * string)342 gkrellm_gdk_string_markup_width(PangoFontDescription *font_desc, gchar *string)
343 {
344 PangoLayout *layout;
345 gint w, h;
346
347 layout = gtk_widget_create_pango_layout(gkrellm_get_top_window(), NULL);
348 pango_layout_set_font_description(layout, font_desc);
349 pango_layout_set_markup(layout, string, strlen(string));
350 pango_layout_get_pixel_size(layout, &w, &h);
351 g_object_unref(layout);
352 return w;
353 }
354
355
356 void
gkrellm_text_extents(PangoFontDescription * font_desc,gchar * text,gint len,gint * width,gint * height,gint * baseline,gint * y_ink)357 gkrellm_text_extents(PangoFontDescription *font_desc, gchar *text,
358 gint len, gint *width, gint *height, gint *baseline, gint *y_ink)
359 {
360 PangoLayout *layout;
361 PangoLayoutIter *iter;
362 PangoRectangle ink, logical;
363 gchar *utf8;
364 gint base;
365
366 layout = gtk_widget_create_pango_layout(gkrellm_get_top_window(), NULL);
367 pango_layout_set_font_description(layout, font_desc);
368 if (g_utf8_validate(text, -1, NULL))
369 pango_layout_set_text(layout, text, len);
370 else
371 {
372 utf8 = g_locale_to_utf8(text, -1, NULL, NULL, NULL);
373 if (utf8)
374 pango_layout_set_text(layout, utf8, len);
375 g_free(utf8);
376 }
377 iter = pango_layout_get_iter(layout);
378 base = pango_layout_iter_get_baseline(iter) / PANGO_SCALE;
379 pango_layout_get_pixel_extents(layout, &ink, &logical);
380 pango_layout_iter_free(iter);
381 g_object_unref(layout);
382
383 if (width)
384 *width = logical.width;
385 if (height)
386 *height = ink.height;
387 if (baseline)
388 *baseline = base;
389 if (y_ink)
390 *y_ink = ink.y - logical.y;
391 }
392
393 void
gkrellm_text_markup_extents(PangoFontDescription * font_desc,gchar * text,gint len,gint * width,gint * height,gint * baseline,gint * y_ink)394 gkrellm_text_markup_extents(PangoFontDescription *font_desc, gchar *text,
395 gint len, gint *width, gint *height, gint *baseline, gint *y_ink)
396 {
397 PangoLayout *layout;
398 PangoLayoutIter *iter;
399 PangoRectangle ink, logical;
400 gchar *utf8;
401 gint base;
402
403 layout = gtk_widget_create_pango_layout(gkrellm_get_top_window(), NULL);
404 pango_layout_set_font_description(layout, font_desc);
405 if (g_utf8_validate(text, -1, NULL))
406 pango_layout_set_markup(layout, text, len);
407 else
408 {
409 utf8 = g_locale_to_utf8(text, -1, NULL, NULL, NULL);
410 pango_layout_set_markup(layout, utf8, len);
411 g_free(utf8);
412 }
413 iter = pango_layout_get_iter(layout);
414 base = pango_layout_iter_get_baseline(iter) / PANGO_SCALE;
415 pango_layout_get_pixel_extents(layout, &ink, &logical);
416 pango_layout_iter_free(iter);
417 g_object_unref(layout);
418
419 if (width)
420 *width = logical.width;
421 if (height)
422 *height = ink.height;
423 if (baseline)
424 *baseline = base;
425 if (y_ink)
426 *y_ink = ink.y - logical.y;
427 }
428
429 void
gkrellm_gdk_draw_string(GdkDrawable * drawable,PangoFontDescription * font_desc,GdkGC * gc,gint x,gint y,gchar * string)430 gkrellm_gdk_draw_string(GdkDrawable *drawable, PangoFontDescription *font_desc,
431 GdkGC *gc, gint x, gint y, gchar *string)
432 {
433 PangoLayout *layout;
434
435 layout = gtk_widget_create_pango_layout(gkrellm_get_top_window(), NULL);
436 pango_layout_set_font_description(layout, font_desc);
437 pango_layout_set_text(layout, string, strlen(string));
438 gdk_draw_layout(drawable, gc, x, y, layout);
439 g_object_unref(layout);
440 }
441
442 void
gkrellm_gdk_draw_string_markup(GdkDrawable * drawable,PangoFontDescription * font_desc,GdkGC * gc,gint x,gint y,gchar * string)443 gkrellm_gdk_draw_string_markup(GdkDrawable *drawable,
444 PangoFontDescription *font_desc,
445 GdkGC *gc, gint x, gint y, gchar *string)
446 {
447 PangoLayout *layout;
448
449 layout = gtk_widget_create_pango_layout(gkrellm_get_top_window(), NULL);
450 pango_layout_set_font_description(layout, font_desc);
451 pango_layout_set_markup(layout, string, strlen(string));
452 gdk_draw_layout(drawable, gc, x, y, layout);
453 g_object_unref(layout);
454 }
455
456 void
gkrellm_gdk_draw_text(GdkDrawable * drawable,PangoFontDescription * font_desc,GdkGC * gc,gint x,gint y,gchar * string,gint len)457 gkrellm_gdk_draw_text(GdkDrawable *drawable, PangoFontDescription *font_desc,
458 GdkGC *gc, gint x, gint y, gchar *string, gint len)
459 {
460 PangoLayout *layout;
461
462 layout = gtk_widget_create_pango_layout(gkrellm_get_top_window(), NULL);
463 pango_layout_set_font_description(layout, font_desc);
464 if (g_utf8_validate(string, -1, NULL))
465 pango_layout_set_text(layout, string, len);
466 gdk_draw_layout(drawable, gc, x, y, layout);
467 g_object_unref(layout);
468 }
469
470 void
gkrellm_gdk_draw_text_markup(GdkDrawable * drawable,PangoFontDescription * font_desc,GdkGC * gc,gint x,gint y,gchar * string,gint len)471 gkrellm_gdk_draw_text_markup(GdkDrawable *drawable,
472 PangoFontDescription *font_desc,
473 GdkGC *gc, gint x, gint y, gchar *string, gint len)
474 {
475 PangoLayout *layout;
476
477 layout = gtk_widget_create_pango_layout(gkrellm_get_top_window(), NULL);
478 pango_layout_set_font_description(layout, font_desc);
479 pango_layout_set_markup(layout, string, len);
480 gdk_draw_layout(drawable, gc, x, y, layout);
481 g_object_unref(layout);
482 }
483
484 /* Gtk config widgets work with utf8, so as long as I'm using gdk_draw
485 | functions, both utf8 and current locale versions of strings drawn on
486 | GKrellM must be maintained. If src is not utf8, *dst is converted
487 | to utf8 and this should fix 1.2 -> 2.0 user_config conversions
488 | (This function will usually be called from config loading).
489 | dst_locale is piggy backing so when gdk_draw is replaced by Pango
490 | equivalents, usage of this function can be replaced with a simple
491 | gkrellm_dup_string().
492 | 2.2.0 converts to using Pango. Before replacing with gkrellm_dup_string,
493 | temporarily just treat dst_locale as a direct copy of dst_utf8.
494 */
495 gboolean
gkrellm_locale_dup_string(gchar ** dst_utf8,gchar * src,gchar ** dst_locale)496 gkrellm_locale_dup_string(gchar **dst_utf8, gchar *src, gchar **dst_locale)
497 {
498 if (!dst_utf8 || (!*dst_utf8 && !src))
499 return FALSE;
500 if (*dst_utf8)
501 {
502 if (src && !strcmp(*dst_utf8, src))
503 return FALSE;
504 g_free(*dst_utf8);
505 g_free(*dst_locale);
506 }
507 if (src)
508 {
509 if (g_utf8_validate(src, -1, NULL))
510 {
511 *dst_utf8 = g_strdup(src);
512
513 *dst_locale = g_strdup(src);
514 // *dst_locale = g_locale_from_utf8(src, -1, NULL, NULL, NULL);
515 // if (!*dst_locale)
516 // *dst_locale = g_strdup(src);
517 }
518 else
519 {
520 *dst_utf8 = g_locale_to_utf8(src, -1, NULL, NULL, NULL);
521 if (!*dst_utf8)
522 *dst_utf8 = g_strdup(src);
523
524 *dst_locale = g_strdup(*dst_utf8);
525 // *dst_locale = g_strdup(src);
526 }
527 }
528 else
529 {
530 *dst_utf8 = NULL;
531 *dst_locale = NULL;
532 }
533 return TRUE;
534 }
535
536 guint
big_endian_uint(guint8 * b)537 big_endian_uint(guint8 *b)
538 {
539 return ((b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]);
540 }
541