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