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