1 /*
2  * Copyright (c) 2008-2010 Lu, Chao-Ming (Tetralet).  All rights reserved.
3  *
4  * This file is part of LilyTerm.
5  *
6  * LilyTerm is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * LilyTerm is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with LilyTerm.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "misc.h"
21 extern gboolean proc_exist;
22 
23 // The returned string should be freed when no longer needed.
convert_array_to_string(gchar ** array,gchar separator)24 gchar *convert_array_to_string(gchar **array, gchar separator)
25 {
26 #ifdef DETAIL
27 	g_debug("! Launch convert_array_to_string()");
28 #endif
29 #ifdef SAFEMODE
30 	if (array==NULL) return NULL;
31 #endif
32 	GString *array_str = g_string_new (NULL);
33 	gint i=0;
34 
35 	while (array[i]!=NULL)
36 	{
37 		// g_debug("%d: %s", i, array[i]);
38 		if (array_str->len && (separator!='\0'))
39 			g_string_append_printf(array_str, "%c%s", separator, array[i]);
40 		else
41 			g_string_append_printf(array_str, "%s", array[i]);
42 		i++;
43 	}
44 	// g_debug ("Got array_str = %s", array_str->str);
45 	return g_string_free(array_str, FALSE);
46 }
47 
48 // return FALSE if the strings are the same.
compare_strings(const gchar * string_a,const gchar * string_b,gboolean case_sensitive)49 gboolean compare_strings(const gchar *string_a, const gchar *string_b, gboolean case_sensitive)
50 {
51 #ifdef FULL
52 	g_debug("! Launch compare_strings()! with string_a = %s, string_b = %s", string_a, string_b);
53 #endif
54 	if ((string_a == NULL) && (string_b == NULL)) return FALSE;
55 	if ((string_a == NULL) || (string_b == NULL)) return TRUE;
56 	if (case_sensitive)
57 	{
58 		if (strcmp(string_a, string_b)) return TRUE;
59 	}
60 	else
61 	{
62 		if (strcasecmp(string_a, string_b)) return TRUE;
63 	}
64 	return FALSE;
65 }
66 
67 // The returned string should be freed when no longer needed.
convert_str_to_utf8(gchar * string,gchar * encoding_str)68 gchar *convert_str_to_utf8(gchar *string, gchar *encoding_str)
69 {
70 #ifdef DETAIL
71 	g_debug("! Launch convert_str_to_utf8() with string = %s, encoding_str = %s", string, encoding_str);
72 #endif
73 	if (string==NULL) return NULL;
74 
75 	gchar *local_string = NULL;
76 	if (encoding_str)
77 	{
78 		//g_debug("string = %s", string);
79 		//g_debug("encoding_str = %s", encoding_str);
80 		local_string = g_convert_with_fallback (string,
81 							-1,
82 							"UTF-8",
83 							encoding_str,
84 							"_",
85 							NULL,
86 							NULL,
87 							NULL);
88 		// g_debug("Get local_string = %s", local_string);
89 
90 		if ((local_string == NULL ) || (local_string[0]=='\0'))
91 		{
92 			g_free(local_string);
93 			local_string = g_strdup(string);
94 			gint i = 0;
95 			while (local_string[i])
96 			{
97 				if (local_string[i] < 32 || local_string[i]>126)
98 					local_string[i] = '?';
99 				i++;
100 			}
101 		}
102 
103 		// g_debug("FINAL: local_string = %s", local_string);
104 		return local_string;
105 	}
106 	else
107 		return g_strdup(string);
108 }
109 
set_VTE_CJK_WIDTH_environ(gint VTE_CJK_WIDTH)110 void set_VTE_CJK_WIDTH_environ(gint VTE_CJK_WIDTH)
111 {
112 #ifdef DETAIL
113 	g_debug("! Launch set_VTE_CJK_WIDTH_environ() with VTE_CJK_WIDTH = %d", VTE_CJK_WIDTH);
114 #endif
115 	// Set the VTE_CJK_WIDTH environment
116 	switch (VTE_CJK_WIDTH)
117 	{
118 		case 0:
119 			// Don't touch VTE_CJK_WIDTH
120 			break;
121 		//case 1:
122 		//	// The VTE_CJK_WIDTH will be setted depend on the LC environ in newer libvte version.
123 		//	unsetenv("VTE_CJK_WIDTH");
124 		//	break;
125 		case 1:
126 			// VTE_CJK_WIDTH=narrow only work for vte >= 0.16.14
127 			setenv("VTE_CJK_WIDTH", "narrow", TRUE);
128 			break;
129 		case 2:
130 			setenv("VTE_CJK_WIDTH", "wide", TRUE);
131 			break;
132 		default:
133 #ifdef FATAL
134 			print_switch_out_of_range_error_dialog("set_VTE_CJK_WIDTH_environ",
135 							       "VTE_CJK_WIDTH",
136 							       VTE_CJK_WIDTH);
137 #endif
138 			break;
139 
140 	}
141 }
142 
get_VTE_CJK_WIDTH_str(gint VTE_CJK_WIDTH)143 gchar *get_VTE_CJK_WIDTH_str(gint VTE_CJK_WIDTH)
144 {
145 #ifdef DETAIL
146 	g_debug("! Launch get_VTE_CJK_WIDTH_str() with VTE_CJK_WIDTH = %d", VTE_CJK_WIDTH);
147 #endif
148 	switch (VTE_CJK_WIDTH)
149 	{
150 		case 0:
151 			return NULL;
152 		case 1:
153 			return "narrow";
154 		case 2:
155 			return "wide";
156 		default:
157 #ifdef FATAL
158 			print_switch_out_of_range_error_dialog("get_VTE_CJK_WIDTH_str",
159 							       "VTE_CJK_WIDTH",
160 							       VTE_CJK_WIDTH);
161 #endif
162 			break;
163 	}
164 	return NULL;
165 }
166 
get_default_VTE_CJK_WIDTH()167 gint get_default_VTE_CJK_WIDTH()
168 {
169 #ifdef DETAIL
170 	g_debug("! Launch get_default_VTE_CJK_WIDTH()");
171 #endif
172 	const gchar *VTE_CJK_WIDTH = g_getenv("VTE_CJK_WIDTH");
173 	if (VTE_CJK_WIDTH==NULL)
174 		return 0;
175 	else
176 	{
177 		// VTE_CJK_WIDTH only work under UTF-8
178 		if ((compare_strings (VTE_CJK_WIDTH, "wide", FALSE)==FALSE) ||
179 		    (compare_strings (VTE_CJK_WIDTH, "1", FALSE)==FALSE))
180 			return 2;
181 		else if ((compare_strings (VTE_CJK_WIDTH, "narrow", FALSE)==FALSE) ||
182 			 (compare_strings (VTE_CJK_WIDTH, "0", FALSE)==FALSE))
183 			return 1;
184 		else
185 			return 0;
186 	}
187 }
188 
restore_SYSTEM_VTE_CJK_WIDTH_STR()189 void restore_SYSTEM_VTE_CJK_WIDTH_STR()
190 {
191 #ifdef DETAIL
192 	g_debug("! Launch restore_SYSTEM_VTE_CJK_WIDTH_STR()");
193 #endif
194 	extern gchar *SYSTEM_VTE_CJK_WIDTH_STR;
195 	if (SYSTEM_VTE_CJK_WIDTH_STR)
196 		g_setenv("VTE_CJK_WIDTH", SYSTEM_VTE_CJK_WIDTH_STR, TRUE);
197 	else
198 		g_unsetenv("VTE_CJK_WIDTH");
199 }
200 
set_env(const gchar * variable,const gchar * value,gboolean overwrite)201 void set_env(const gchar *variable, const gchar *value, gboolean overwrite)
202 {
203 #ifdef DETAIL
204 	g_debug("! Launch set_env() with variable = %s, value = %s, overwrite = %d", variable, value, overwrite);
205 #endif
206 #ifdef SAFEMODE
207 	if ((variable==NULL) || (variable[0]=='\0')) return;
208 #endif
209 	if (value)
210 		g_setenv(variable, value, overwrite);
211 	else
212 		g_unsetenv(variable);
213 }
214 
215 // get default locale from environ
216 // The returned string CAN NOT be free()!
get_default_lc_data(gint lc_type)217 const gchar *get_default_lc_data(gint lc_type)
218 {
219 #ifdef DETAIL
220 	g_debug("! Launch get_default_lc_data() with lc_type= %d", lc_type);
221 #endif
222 	const char *lc_data;
223 	switch (lc_type)
224 	{
225 		case LC_CTYPE:
226 			lc_data = g_getenv("LC_CTYPE");
227 			break;
228 		case LC_MESSAGES:
229 			lc_data = g_getenv("LC_MESSAGES");
230 			break;
231 		default:
232 #ifdef FATAL
233 			print_switch_out_of_range_error_dialog("get_default_lc_data", "lc_type", lc_type);
234 #endif
235 			return "";
236 	}
237 	const char *lc_all = g_getenv("LC_ALL");
238 	const char *lang = g_getenv("LANG");
239 
240 	if ( (!lc_data) && lang)
241 		lc_data = lang;
242 
243 	if (lc_all)
244 		lc_data = lc_all;
245 
246 //	g_debug("Get lc_data = %s", lc_data);
247 	if (lc_data)
248 		return lc_data;
249 	else
250 		return "";
251 }
252 
253 // The returned string should be freed when no longer needed.
get_encoding_from_locale(const gchar * locale)254 gchar *get_encoding_from_locale(const gchar *locale)
255 {
256 #ifdef DETAIL
257 	g_debug("! Launch get_encoding_from_locale() with locale = %s", locale);
258 #endif
259 #ifdef OUT_OF_MEMORY
260 #  undef g_strdup
261 #endif
262 	// locale==NULL: get the init encoding.
263 
264 	G_CONST_RETURN char *locale_encoding = NULL;
265 	if (setlocale(LC_CTYPE, locale)) g_get_charset(&locale_encoding);
266 	return g_strdup(locale_encoding);
267 
268 #ifdef OUT_OF_MEMORY
269 	#define g_strdup fake_g_strdup
270 #endif
271 }
272 
check_string_in_array(gchar * str,gchar ** lists)273 gboolean check_string_in_array(gchar *str, gchar **lists)
274 {
275 #ifdef DETAIL
276 	g_debug("! Launch check_string_in_array() with str = %s", str);
277 #endif
278 #ifdef SAFEMODE
279 	if ((str==NULL) || (lists==NULL)) return FALSE;
280 #endif
281 	gint i=-1;
282 
283 	while (lists[++i])
284 	{
285 		// g_debug("Checking %s and %s...", str, lists[i]);
286 		if (strcmp(str, lists[i])==0) return TRUE;
287 	}
288 	// g_debug("No, Can not find '%s' in the array!!", str);
289 	return FALSE;
290 }
291 
292 //gchar *get_proc_data(pid_t pid, gchar *file, gsize *length)
293 //{
294 //#ifdef FULL
295 //	g_debug("! Launch get_proc_data() with pid = %d, file = %s", pid, file);
296 //#endif
297 //
298 //	if (! proc_exist) return NULL;
299 //	if (pid<1) return NULL;
300 //
301 //	*length=0;
302 //	gchar *contents=NULL;
303 //	gchar *file_path = g_strdup_printf("/proc/%d/%s", (gint)pid, file);
304 //	// g_debug("file_path = %s", file_path);
305 //
306 //	if (file_path && (g_file_test(file_path, G_FILE_TEST_EXISTS)))
307 //		g_file_get_contents (file_path, &contents, length, NULL);
308 //	g_free(file_path);
309 //	// g_debug("contents = %s", contents);
310 //	return contents;
311 //}
312 
get_proc_data(pid_t pid,gchar * file,gsize * length)313 gchar *get_proc_data(pid_t pid, gchar *file, gsize *length)
314 {
315 #ifdef FULL
316 	g_debug("! Launch get_proc_data() with pid = %d, file = %s", pid, file);
317 #endif
318 	// g_debug("proc_exist = %d", proc_exist);
319 	if (! proc_exist) return NULL;
320 	if (pid<1) return NULL;
321 #ifdef UNIT_TEST
322 	if (file==NULL) return NULL;
323 #endif
324 	gchar *contents=NULL;
325 	gint timeout=0;
326 	gchar *proc_path = g_strdup_printf("/proc/%d", (gint)pid);
327 	// g_debug("proc_path = %s", proc_path);
328 	gchar *file_path = g_strdup_printf("%s/%s", proc_path, file);
329 	// g_debug("file_path = %s", file_path);
330 
331 #if defined(OUT_OF_MEMORY) || defined(UNIT_TEST)
332 	if (proc_path && file_path)
333 	{
334 #endif
335 		while (g_file_test(proc_path, G_FILE_TEST_EXISTS) &&
336 		       g_file_get_contents (file_path, &contents, length, NULL))
337 		{
338 			// g_debug("Got the contents length is %d for %s", *length, file_path);
339 			if (*length==0)
340 			{
341 				// gsize len = 0;
342 				// gchar *stat = NULL;
343 				// gchar *stat_path = g_strdup_printf("/proc/%d/stat", (gint)pid);
344 				// if (g_file_get_contents (stat_path, &contents, &len, NULL))
345 				// {
346 				//	g_debug("Got len = %d, stat = %s", len, stat);
347 				//	if (len && stat)
348 				//	{
349 				//		gchar **stats = split_string(stat, " ()", 6);
350 				//		if (stats && stats[4][0]=='Z')
351 				//		{
352 				//			g_warning("The child process \"(%s) %s\" has died. Abort.",
353 				//				  stats[0], stats[2]);
354 				//			g_free(stat);
355 				//			g_strfreev(stats);
356 				//
357 				//			g_free(contents);
358 				//			contents = NULL;
359 				//			break;
360 				//		}
361 				//		g_strfreev(stats);
362 				//	}
363 				// }
364 				// g_free(stat);
365 				g_message("Waiting for /proc/%d/%s...", (gint)pid, file);
366 				// we should wait until "/proc/%d/file" is not empty
367 				usleep(100000);
368 				timeout++;
369 				// contents = "" here
370 				g_free(contents);
371 				contents = NULL;
372 			}
373 			else
374 				break;
375 
376 			// we only try for 3 times
377 			if (timeout>2)
378 			{
379 #ifdef FATAL
380 				g_message("Failed when waiting for /proc/%d/%s. Abort.", (gint)pid, file);
381 #else
382 				g_warning("Failed when waiting for /proc/%d/%s. Abort.", (gint)pid, file);
383 #endif
384 				break;
385 			}
386 		}
387 #if defined(OUT_OF_MEMORY) || defined(UNIT_TEST)
388 	}
389 #endif
390 	g_free(file_path);
391 	g_free(proc_path);
392 	// g_debug("contents = %s", contents);
393 	return contents;
394 }
395 
396 // it will check if the count of returned string array is < max_tokens
split_string(const gchar * str,const gchar * split,gint max_tokens)397 gchar **split_string(const gchar *str, const gchar *split, gint max_tokens)
398 {
399 #ifdef FULL
400 	g_debug("! Launch split_string with str = %s, split = %s, max_tokens = %d", str, split, max_tokens);
401 #endif
402 #ifdef SAFEMODE
403 	if ((str==NULL) || (split==NULL) || (split[0]=='\0')) return NULL;
404 #endif
405 	// g_debug("contents = %s", contents);
406 	gchar **datas = g_strsplit_set(str, split, max_tokens);
407 	gint i = -1;
408 
409 	// while (datas[++i])
410 	//	g_debug("Got data[%d] = %s", i, datas[i]);
411 	// g_debug("Got i = %d in split_string()", i);
412 	// i = -1;
413 #ifdef SAFEMODE
414 	if ( datas && (max_tokens>0))
415 #else
416 	if (max_tokens>0)
417 #endif
418 	{
419 		while (datas[++i]);
420 		if (i<max_tokens)
421 		{
422 			g_strfreev(datas);
423 			datas = NULL;
424 		}
425 	}
426 	return datas;
427 }
428 
count_char_in_string(const gchar * str,const gchar split)429 gint count_char_in_string(const gchar *str, const gchar split)
430 {
431 #ifdef FULL
432 	g_debug("! Launch count_char_in_string with str = %s, split = %c", str, split);
433 #endif
434 	if (str==NULL) return -1;
435 
436 	gint i = -1, count = 0;
437 	while (str[++i])
438 		if (str[i]==split) count++;
439 
440 	return count;
441 }
442 
get_pid_stat(pid_t pid,gint max_tokens)443 gchar **get_pid_stat(pid_t pid, gint max_tokens)
444 {
445 #ifdef FULL
446 	g_debug("! Launch get_pid_stat with pid = %d, max_tokens = %d", pid, max_tokens);
447 #endif
448 	if (pid<1) return NULL;
449 
450 	gsize length=0;
451 	gchar *stat = get_proc_data(pid, "stat", &length);
452 	gchar **stats = NULL;
453 	if (stat) stats = split_string(stat, " ()", max_tokens);
454 	g_free(stat);
455 	return stats;
456 }
457 
458 // The returned string should be freed when no longer needed.
convert_text_to_html(StrAddr ** text,gboolean free_text,gchar * color,StrLists * tag,...)459 gchar *convert_text_to_html(StrAddr **text, gboolean free_text, gchar *color, StrLists *tag, ...)
460 {
461 #ifdef DETAIL
462 	g_debug("! Launch convert_text_to_html() with text = %s, color = %s, tag = %s",
463 		*text, color, tag);
464 #endif
465 #ifdef SAFEMODE
466 	if ((text==NULL) || (*text==NULL)) return NULL;
467 #endif
468 	gchar *markup_escape_text = g_markup_escape_text(*text, -1);
469 
470 	if (color)
471 	{
472 		gchar *color_profile = g_strdup_printf ("<span foreground=\"%s\">%s</span>",
473 							color, markup_escape_text);
474 		g_free(markup_escape_text);
475 		markup_escape_text = color_profile;
476 	}
477 
478 	va_list arg_ptr;
479 	va_start(arg_ptr, tag);
480 	while (tag)
481 	{
482 		gchar *new_html_string = g_strdup_printf("<%s>%s</%s>",
483 							 tag, markup_escape_text, tag);
484 		g_free(markup_escape_text);
485 		markup_escape_text = new_html_string;
486 		tag = va_arg(arg_ptr, char *);
487 	}
488 	va_end(arg_ptr);
489 
490 	if (free_text)
491 	{
492 		g_free(*text);
493 #ifdef SAFEMODE
494 		*text = NULL;
495 #endif
496 	}
497 	return markup_escape_text;
498 }
499 
500 // The returned string should be freed when no longer needed.
join_strings_to_string(const gchar separator,const gint total,const StrLists * string,...)501 gchar *join_strings_to_string(const gchar separator, const gint total, const StrLists *string, ...)
502 {
503 #ifdef DETAIL
504 	g_debug("! Launch join_strings_to_string() with separator = '%c', total = %d",
505 		separator, total);
506 #endif
507 #ifdef SAFEMODE
508 	if (separator=='\0') return NULL;
509 #endif
510 	GString *strings = g_string_new ("");
511 	gint i;
512 	va_list arg_ptr;
513 	va_start(arg_ptr, string);
514 	for (i=0; i<total; i++)
515 	{
516 		if (string && string[0]!='\0')
517 		{
518 			if (strings->len)
519 				g_string_append_printf(strings, "%c%s", separator, string);
520 			else
521 				g_string_append_printf(strings, "%s", string);
522 		}
523 		// g_debug("[%2d] convert_strings_to_string(): strings = %s", i, strings->str);
524 		string = va_arg(arg_ptr, char *);
525 	}
526 	va_end(arg_ptr);
527 	// g_debug("convert_strings_to_string(): strings = %s", strings->str);
528 
529 	return g_string_free(strings, FALSE);
530 }
531 
532 // return NULL: No, it is less than MAX
533 // return String: Yes, It is more then MAX, and have been cut short to OUTPUT_LINE lines.
colorful_max_new_lines(gchar * string,gint max,gint output_line)534 gchar *colorful_max_new_lines(gchar *string, gint max, gint output_line)
535 {
536 #ifdef DETAIL
537 	g_debug("! Launch count_max_new_lines() with string = '%s', max = %d",
538 		string, max);
539 #endif
540 	if (string==NULL) return NULL;
541 
542 	gint i = 0;
543 	gint total = 0;
544 	gchar *color_str = g_strdup("");
545 	gint star_start = 0;
546 
547 	while (string[i])
548 	{
549 		char separate;
550 
551 		if ((string[i]=='\n') || (string[i]=='\r') || (string[i+1]=='\0'))
552 		{
553 			if ((string[i]=='\n') || (string[i]=='\r'))
554 				total++;
555 
556 			if (total < output_line)
557 			{
558 				separate = string[i];
559 				if ((string[i]=='\n') || (string[i]=='\r'))
560 					string[i] = 0;
561 				gchar *str = &(string[star_start]);
562 				gchar *markup_str;
563 				if ((str==NULL) || (str[0] == '\0'))
564 					markup_str = g_strdup("");
565 				else
566 				{
567 					gchar *tmp_str = g_markup_escape_text(str, -1);
568 					markup_str = g_strconcat("<b><span foreground=\"blue\">",
569 								 tmp_str, "</span></b>", NULL);
570 					g_free(tmp_str);
571 				}
572 				gchar *new_str = NULL;
573 				if ((separate=='\n') || (separate=='\r'))
574 				{
575 					// TRANSLATE NOTE: The "↲" is a replace character for <Enter> (<CR>, or <New Line>).
576 					// TRANSLATE NOTE: You may translate it into something like "¶", "↵" or "↩".
577 					gchar *markup_enter = g_markup_escape_text(_("↲"), -1);
578 					if (string[i+1])
579 						new_str = g_strconcat(color_str,
580 								      markup_str,
581 								      "<small><span foreground=\"darkgray\">",
582 								      markup_enter,
583 								      "</span></small>\n", NULL);
584 					else
585 						new_str = g_strconcat(color_str,
586 								      markup_str,
587 								      "<small><span foreground=\"darkgray\">",
588 								      markup_enter,
589 								      "</span></small>", NULL);
590 					g_free(markup_enter);
591 				}
592 				else
593 					new_str = g_strconcat(color_str, markup_str, NULL);
594 				g_free(markup_str);
595 				g_free(color_str);
596 				color_str = new_str;
597 				string[i] = separate;
598 				star_start = i+1;
599 
600 				// g_debug("colorful_max_new_lines(): color_str = %s", color_str);
601 			}
602 		}
603 		if (total>=output_line)
604 		{
605 			separate = string[i];
606 			string[i] = 0;
607 			gchar *output_str = g_strdup_printf("<tt>%s%s</tt>",
608 							    color_str, "<b>...</b>");
609 			g_free(color_str);
610 			string[i] = separate;
611 			return output_str;
612 		}
613 		i++;
614 	}
615 	// g_debug("colorful_max_new_lines(FINAL): color_str = %s", color_str);
616 	// g_debug("colorful_max_new_lines(): total = %d", total);
617 	if (total > max)
618 	{
619 		gchar *output_str = g_strdup_printf("<tt>%s</tt>", color_str);
620 		g_free(color_str);
621 		return output_str;
622 	}
623 	g_free(color_str);
624 	return NULL;
625 }
626 
dirty_gdk_color_parse(const gchar * spec,GdkColor * color)627 gboolean dirty_gdk_color_parse(const gchar *spec, GdkColor *color)
628 {
629 #ifdef DETAIL
630 	g_debug("! Launch dirty_gdk_color_parse() with spec = %s", spec);
631 #endif
632 	if (spec==NULL) return FALSE;
633 
634 	gchar *new_spec = g_strdup(spec);
635 #ifdef OUT_OF_MEMORY
636 	if (new_spec==NULL) return FALSE;
637 #endif
638 	new_spec = g_strstrip(new_spec);
639 	gboolean response = gdk_color_parse(new_spec, color);
640 	g_free(new_spec);
641 	return response;
642 }
643 
644 #if defined(OUT_OF_MEMORY) || defined(UNIT_TEST)
fake_g_strdup(const gchar * str)645 gchar *fake_g_strdup(const gchar *str)
646 {
647 #  ifdef DETAIL
648 	g_debug("! fake_g_strdup(): Trying to strdup(%s)...", str);
649 #  endif
650 
651 #  undef g_strdup
652 #  undef g_strsplit
653 	if (str==NULL) return NULL;
654 
655 	gchar *return_str = NULL;
656 	gchar **strs = g_strsplit(str, " ", 2);
657 	if (strs)
658 	{
659 		if ((! compare_strings(strs[0], "Alt", FALSE)) ||
660 		    (! compare_strings(strs[0], "Shift", FALSE)) ||
661 		    (! compare_strings(strs[0], "Ctrl", FALSE)))
662 		{
663 			return_str = g_strdup(str);
664 			// g_debug("fake_g_strdup(): strdup(%s) succeed!!", str);
665 		}
666 	}
667 	g_strfreev (strs);
668 	return return_str;
669 #  define g_strdup fake_g_strdup
670 #  define g_strsplit fake_g_strsplit
671 }
672 
fake_g_strdup_printf(const StrLists * format,...)673 gchar *fake_g_strdup_printf(const StrLists *format, ...)
674 {
675 #  ifdef DETAIL
676 	g_debug("! Trying to strdup_printf(%s)...", format);
677 #  endif
678 	return NULL;
679 }
680 
681 
fake_g_strsplit(const gchar * string,const gchar * delimiter,gint max_tokens)682 gchar** fake_g_strsplit(const gchar *string, const gchar *delimiter, gint max_tokens)
683 {
684 #  ifdef DETAIL
685 	g_debug("! fake_g_strsplit(): Trying to strsplit('%s', '%s', %d)...", string, delimiter, max_tokens);
686 #  endif
687 
688 	if ((string==NULL) || (delimiter==NULL) || (delimiter[0]=='\0')) return NULL;
689 
690 #  undef g_strsplit
691 
692 	gchar **return_array = NULL;
693 	gchar **strs = g_strsplit(string, " ", 2);
694 	if (strs)
695 	{
696 		if ((strs[0]=='\0') ||
697 		    (! compare_strings(strs[0], "Alt", FALSE)) ||
698 		    (! compare_strings(strs[0], "Shift", FALSE)) ||
699 		    (! compare_strings(strs[0], "Ctrl", FALSE)))
700 		{
701 			return_array = g_strsplit (string, delimiter, max_tokens);
702 			// g_debug("fake_g_strsplit(): strsplit('%s', '%s', %d) succeed!!",
703 			//	string, delimiter, max_tokens);
704 		}
705 	}
706 	g_strfreev (strs);
707 
708 	if (! return_array)
709 	{
710 		if (! compare_strings(delimiter, "+", TRUE))
711 		{
712 			return_array = g_strsplit (string, delimiter, max_tokens);
713 			// g_debug("fake_g_strsplit(): strsplit('%s', '%s', %d) succeed!!",
714 			//	string, delimiter, max_tokens);
715 		}
716 	}
717 
718 	return return_array;
719 
720 #  define g_strsplit fake_g_strsplit
721 }
722 
723 // A very dirty fix for unit test error.
g_listenv(void)724 gchar **g_listenv (void) { return NULL; }
725 
726 #endif
727