1 /***************************************************************************
2 * Copyright (C) 2002~2005 by Yuking *
3 * yuking_net@sohu.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
20 /**
21 * @file utils.c
22 * @author Yuking yuking_net@sohu.com
23 * @date 2008-1-16
24 *
25 * misc util function
26 *
27 */
28
29 #define FCITX_USE_INTERNAL_PATH
30
31 #include "config.h"
32
33 #include <pthread.h>
34 #include <stdio.h>
35 #include <signal.h>
36 #include <unistd.h>
37 #include <sys/wait.h>
38 #include <sys/stat.h>
39 #include <limits.h>
40 #include <libgen.h>
41 #include <ctype.h>
42 #include <stdarg.h>
43 #include <errno.h>
44
45 #if defined(ENABLE_BACKTRACE)
46 #include <execinfo.h>
47 #endif
48
49 #include "fcitx/fcitx.h"
50 #include "utils.h"
51 #include "utf8.h"
52 #include "log.h"
53
54 #if defined(LIBKVM_FOUND)
55 #include <kvm.h>
56 #include <fcntl.h>
57 #include <sys/param.h>
58 #include <sys/sysctl.h>
59 #include <sys/user.h>
60 #endif
61
62 #if defined(__linux__)
63 #include <sys/prctl.h>
64 #endif
65
66 #if defined(__linux__) || defined(__GLIBC__)
67 #include <endian.h>
68 #else
69 #include <sys/endian.h>
70 #endif
71
72 #define DEFINE_SIMPLE_UT_ICD(type, name) \
73 static const UT_icd __fcitx_##name##_icd = { \
74 sizeof(type), NULL, NULL, NULL \
75 }; \
76 FCITX_EXPORT_API const UT_icd *const fcitx_##name##_icd = \
77 &__fcitx_##name##_icd;
78
79 DEFINE_SIMPLE_UT_ICD(void*, ptr)
80 DEFINE_SIMPLE_UT_ICD(int8_t, int8)
81 DEFINE_SIMPLE_UT_ICD(int16_t, int16)
82 DEFINE_SIMPLE_UT_ICD(int32_t, int32)
83 DEFINE_SIMPLE_UT_ICD(int64_t, int64)
84
85 FCITX_EXPORT_API const UT_icd *const fcitx_str_icd = &ut_str_icd;
86 FCITX_EXPORT_API const UT_icd *const fcitx_int_icd = &ut_int_icd;
87
88 FCITX_EXPORT_API UT_array*
fcitx_utils_string_list_append_no_copy(UT_array * list,char * str)89 fcitx_utils_string_list_append_no_copy(UT_array *list, char *str)
90 {
91 utarray_extend_back(list);
92 *(char**)utarray_back(list) = str;
93 return list;
94 }
95
96 FCITX_EXPORT_API UT_array*
fcitx_utils_string_list_append_len(UT_array * list,const char * str,size_t len)97 fcitx_utils_string_list_append_len(UT_array *list, const char *str, size_t len)
98 {
99 char *buff = fcitx_utils_set_str_with_len(NULL, str, len);
100 fcitx_utils_string_list_append_no_copy(list, buff);
101 return list;
102 }
103
104 FCITX_EXPORT_API
fcitx_utils_calculate_record_number(FILE * fpDict)105 int fcitx_utils_calculate_record_number(FILE* fpDict)
106 {
107 char *strBuf = NULL;
108 size_t bufLen = 0;
109 int nNumber = 0;
110
111 while (getline(&strBuf, &bufLen, fpDict) != -1) {
112 nNumber++;
113 }
114 rewind(fpDict);
115
116 fcitx_utils_free(strBuf);
117
118 return nNumber;
119 }
120
121 FCITX_EXPORT_API
fcitx_utils_custom_bsearch(const void * key,const void * base,size_t nmemb,size_t size,int accurate,int (* compar)(const void *,const void *))122 void *fcitx_utils_custom_bsearch(const void *key, const void *base,
123 size_t nmemb, size_t size, int accurate,
124 int (*compar)(const void *, const void *))
125 {
126 if (accurate)
127 return bsearch(key, base, nmemb, size, compar);
128 else {
129 size_t l, u, idx;
130 const void *p;
131 int comparison;
132
133 l = 0;
134 u = nmemb;
135 while (l < u) {
136 idx = (l + u) / 2;
137 p = (void *)(((const char *) base) + (idx * size));
138 comparison = (*compar)(key, p);
139 if (comparison <= 0)
140 u = idx;
141 else if (comparison > 0)
142 l = idx + 1;
143 }
144
145 if (u >= nmemb)
146 return NULL;
147 else
148 return (void *)(((const char *) base) + (l * size));
149 }
150 }
151
152 typedef void (*_fcitx_sighandler_t) (int);
153
154 FCITX_EXPORT_API
fcitx_utils_init_as_daemon()155 void fcitx_utils_init_as_daemon()
156 {
157 pid_t pid;
158 if ((pid = fork()) > 0) {
159 waitpid(pid, NULL, 0);
160 exit(0);
161 }
162 setsid();
163 _fcitx_sighandler_t oldint = signal(SIGINT, SIG_IGN);
164 _fcitx_sighandler_t oldhup =signal(SIGHUP, SIG_IGN);
165 _fcitx_sighandler_t oldquit = signal(SIGQUIT, SIG_IGN);
166 _fcitx_sighandler_t oldpipe = signal(SIGPIPE, SIG_IGN);
167 _fcitx_sighandler_t oldttou = signal(SIGTTOU, SIG_IGN);
168 _fcitx_sighandler_t oldttin = signal(SIGTTIN, SIG_IGN);
169 _fcitx_sighandler_t oldchld = signal(SIGCHLD, SIG_IGN);
170 if (fork() > 0)
171 exit(0);
172 chdir("/");
173
174 signal(SIGINT, oldint);
175 signal(SIGHUP, oldhup);
176 signal(SIGQUIT, oldquit);
177 signal(SIGPIPE, oldpipe);
178 signal(SIGTTOU, oldttou);
179 signal(SIGTTIN, oldttin);
180 signal(SIGCHLD, oldchld);
181 }
182
183 FCITX_EXPORT_API UT_array*
fcitx_utils_new_string_list()184 fcitx_utils_new_string_list()
185 {
186 UT_array *array;
187 utarray_new(array, fcitx_str_icd);
188 return array;
189 }
190
191 FCITX_EXPORT_API UT_array*
fcitx_utils_append_split_string(UT_array * list,const char * str,const char * delm)192 fcitx_utils_append_split_string(UT_array *list,
193 const char* str, const char *delm)
194 {
195 const char *src = str;
196 const char *pos;
197 size_t len;
198 while ((len = strcspn(src, delm)), *(pos = src + len)) {
199 fcitx_utils_string_list_append_len(list, src, len);
200 src = pos + 1;
201 }
202 if (len)
203 fcitx_utils_string_list_append_len(list, src, len);
204 return list;
205 }
206
207 FCITX_EXPORT_API
fcitx_utils_split_string(const char * str,char delm)208 UT_array* fcitx_utils_split_string(const char* str, char delm)
209 {
210 UT_array* array;
211 char delm_s[2] = {delm, '\0'};
212 utarray_new(array, fcitx_str_icd);
213 return fcitx_utils_append_split_string(array, str, delm_s);
214 }
215
216 FCITX_EXPORT_API
fcitx_utils_string_list_printf_append(UT_array * list,const char * fmt,...)217 void fcitx_utils_string_list_printf_append(UT_array* list, const char* fmt,...)
218 {
219 char* buffer;
220 va_list ap;
221 va_start(ap, fmt);
222 vasprintf(&buffer, fmt, ap);
223 va_end(ap);
224 fcitx_utils_string_list_append_no_copy(list, buffer);
225 }
226
227 FCITX_EXPORT_API
fcitx_utils_join_string_list(UT_array * list,char delm)228 char* fcitx_utils_join_string_list(UT_array* list, char delm)
229 {
230 if (!list)
231 return NULL;
232
233 if (utarray_len(list) == 0)
234 return strdup("");
235
236 size_t len = 0;
237 char** str;
238 for (str = (char**) utarray_front(list);
239 str != NULL;
240 str = (char**) utarray_next(list, str))
241 {
242 len += strlen(*str) + 1;
243 }
244
245 char* result = (char*)malloc(sizeof(char) * len);
246 char* p = result;
247 for (str = (char**) utarray_front(list);
248 str != NULL;
249 str = (char**) utarray_next(list, str))
250 {
251 size_t strl = strlen(*str);
252 memcpy(p, *str, strl);
253 p += strl;
254 *p = delm;
255 p++;
256 }
257 result[len - 1] = '\0';
258
259 return result;
260 }
261
262 FCITX_EXPORT_API
fcitx_utils_string_list_contains(UT_array * list,const char * scmp)263 int fcitx_utils_string_list_contains(UT_array* list, const char* scmp)
264 {
265 char** str;
266 for (str = (char**) utarray_front(list);
267 str != NULL;
268 str = (char**) utarray_next(list, str))
269 {
270 if (strcmp(scmp, *str) == 0)
271 return 1;
272 }
273 return 0;
274 }
275
276 FCITX_EXPORT_API
fcitx_utils_free_string_list(UT_array * list)277 void fcitx_utils_free_string_list(UT_array* list)
278 {
279 utarray_free(list);
280 }
281
282 FCITX_EXPORT_API
fcitx_utils_string_hash_set_join(FcitxStringHashSet * sset,char delim)283 char* fcitx_utils_string_hash_set_join(FcitxStringHashSet* sset, char delim)
284 {
285 if (!sset)
286 return NULL;
287
288 if (HASH_COUNT(sset) == 0)
289 return strdup("");
290
291 size_t len = 0;
292 HASH_FOREACH(string, sset, FcitxStringHashSet) {
293 len += strlen(string->name) + 1;
294 }
295
296 char* result = (char*)malloc(sizeof(char) * len);
297 char* p = result;
298 HASH_FOREACH(string2, sset, FcitxStringHashSet) {
299 size_t strl = strlen(string2->name);
300 memcpy(p, string2->name, strl);
301 p += strl;
302 *p = delim;
303 p++;
304 }
305 result[len - 1] = '\0';
306
307 return result;
308 }
309
310 FCITX_EXPORT_API
fcitx_utils_string_hash_set_parse(const char * str,char delim)311 FcitxStringHashSet* fcitx_utils_string_hash_set_parse(const char* str, char delim)
312 {
313 FcitxStringHashSet* sset = NULL;
314 const char *src = str;
315 const char *pos;
316 size_t len;
317
318 char delim_s[2] = {delim, '\0'};
319 while ((len = strcspn(src, delim_s)), *(pos = src + len)) {
320 sset = fcitx_utils_string_hash_set_insert_len(sset, src, len);
321 src = pos + 1;
322 }
323 if (len)
324 sset = fcitx_utils_string_hash_set_insert_len(sset, src, len);
325 return sset;
326 }
327
328 FCITX_EXPORT_API
fcitx_utils_string_hash_set_insert(FcitxStringHashSet * sset,const char * str)329 FcitxStringHashSet* fcitx_utils_string_hash_set_insert(FcitxStringHashSet* sset, const char* str)
330 {
331 FcitxStringHashSet* string = fcitx_utils_new(FcitxStringHashSet);
332 string->name = strdup(str);
333 HASH_ADD_KEYPTR(hh, sset, string->name, strlen(string->name), string);
334 return sset;
335 }
336
337 FCITX_EXPORT_API
fcitx_utils_string_hash_set_insert_len(FcitxStringHashSet * sset,const char * str,size_t len)338 FcitxStringHashSet* fcitx_utils_string_hash_set_insert_len(FcitxStringHashSet* sset, const char* str, size_t len)
339 {
340 FcitxStringHashSet* string = fcitx_utils_new(FcitxStringHashSet);
341 string->name = strndup(str, len);
342 HASH_ADD_KEYPTR(hh, sset, string->name, strlen(string->name), string);
343 return sset;
344 }
345
346 FCITX_EXPORT_API
fcitx_utils_string_hash_set_contains(FcitxStringHashSet * sset,const char * str)347 boolean fcitx_utils_string_hash_set_contains(FcitxStringHashSet* sset, const char* str)
348 {
349 FcitxStringHashSet* string = NULL;
350 HASH_FIND_STR(sset, str, string);
351 return (string != NULL);
352 }
353
354 FCITX_EXPORT_API
fcitx_util_string_hash_set_remove(FcitxStringHashSet * sset,const char * str)355 FcitxStringHashSet* fcitx_util_string_hash_set_remove(FcitxStringHashSet* sset, const char* str)
356 {
357 FcitxStringHashSet* string = NULL;
358 HASH_FIND_STR(sset, str, string);
359 if (string) {
360 HASH_DEL(sset, string);
361 free(string->name);
362 free(string);
363 }
364 return sset;
365 }
366
367 FCITX_EXPORT_API
fcitx_utils_free_string_hash_set(FcitxStringHashSet * sset)368 void fcitx_utils_free_string_hash_set(FcitxStringHashSet* sset)
369 {
370 FcitxStringHashSet *curStr;
371 while (sset) {
372 curStr = sset;
373 HASH_DEL(sset, curStr);
374 free(curStr->name);
375 free(curStr);
376 }
377 }
378
379 FCITX_EXPORT_API
fcitx_utils_string_hash_set_compare(FcitxStringHashSet * sseta,FcitxStringHashSet * ssetb)380 int fcitx_utils_string_hash_set_compare(FcitxStringHashSet* sseta, FcitxStringHashSet* ssetb)
381 {
382 return strcmp(sseta->name, ssetb->name);
383 }
384
385 FCITX_EXPORT_API
fcitx_utils_malloc0(size_t bytes)386 void* fcitx_utils_malloc0(size_t bytes)
387 {
388 void *p = malloc(bytes);
389 if (!p)
390 return NULL;
391
392 memset(p, 0, bytes);
393 return p;
394 }
395
396 FCITX_EXPORT_API
fcitx_utils_trim(const char * s)397 char* fcitx_utils_trim(const char* s)
398 {
399 register const char *end;
400
401 s += strspn(s, "\f\n\r\t\v ");
402 end = s + (strlen(s) - 1);
403 while (end >= s && isspace(*end)) /* skip trailing space */
404 --end;
405
406 end++;
407
408 size_t len = end - s;
409
410 char* result = malloc(len + 1);
411 memcpy(result, s, len);
412 result[len] = '\0';
413 return result;
414 }
415
416 FCITX_EXPORT_API int
fcitx_utils_get_display_number()417 fcitx_utils_get_display_number()
418 {
419 const char *display = getenv("DISPLAY");
420 if (!display)
421 return 0;
422 size_t len;
423 const char *p = display + strcspn(display, ":");
424 if (*p != ':')
425 return 0;
426 p++;
427 len = strcspn(p, ".");
428 char *str_disp_num = fcitx_utils_set_str_with_len(NULL, p, len);
429 int displayNumber = atoi(str_disp_num);
430 free(str_disp_num);
431 return displayNumber;
432 }
433
434 FCITX_EXPORT_API
fcitx_utils_current_locale_is_utf8()435 int fcitx_utils_current_locale_is_utf8()
436 {
437 const char* p;
438 p = getenv("LC_CTYPE");
439 if (!p) {
440 p = getenv("LC_ALL");
441 if (!p)
442 p = getenv("LANG");
443 }
444 if (p) {
445 if (strcasestr(p, "utf8") || strcasestr(p, "utf-8"))
446 return 1;
447 }
448 return 0;
449 }
450
451 FCITX_EXPORT_API
fcitx_utils_get_current_langcode()452 char* fcitx_utils_get_current_langcode()
453 {
454 /* language[_territory][.codeset][@modifier]" or "C" */
455 const char* p;
456 p = getenv("LC_CTYPE");
457 if (!p) {
458 p = getenv("LC_ALL");
459 if (!p)
460 p = getenv("LANG");
461 }
462 if (p)
463 return fcitx_utils_set_str_with_len(NULL, p, strcspn(p, ".@"));
464 return strdup("C");
465 }
466
467 FCITX_EXPORT_API
fcitx_utils_pid_exists(pid_t pid)468 int fcitx_utils_pid_exists(pid_t pid)
469 {
470 if (pid <= 0)
471 return 0;
472 return !(kill(pid, 0) && (errno == ESRCH));
473 }
474
475 FCITX_EXPORT_API
fcitx_utils_get_process_name()476 char* fcitx_utils_get_process_name()
477 {
478 #if defined(__linux__)
479 #define _PR_GET_NAME_MAX 16
480 char name[_PR_GET_NAME_MAX + 1];
481 if (prctl(PR_GET_NAME, (unsigned long)name, 0, 0, 0))
482 return strdup("");
483 name[_PR_GET_NAME_MAX] = '\0';
484 return strdup(name);
485 /**
486 * Keep the old code here in case we want to get the name of
487 * another process with known pid sometime.
488 **/
489 /* do { */
490 /* FILE* fp = fopen("/proc/self/stat", "r"); */
491 /* if (!fp) */
492 /* break; */
493
494 /* const size_t bufsize = 1024; */
495 /* char buf[bufsize]; */
496 /* fgets(buf, bufsize, fp); */
497 /* fclose(fp); */
498
499 /* char* S = strchr(buf, '('); */
500 /* if (!S) */
501 /* break; */
502 /* char* E = strchr(S, ')'); */
503 /* if (!E) */
504 /* break; */
505
506 /* return strndup(S+1, E-S-1); */
507 /* } while(0); */
508 /* return strdup(""); */
509 #elif defined(LIBKVM_FOUND)
510 #if defined(__NetBSD__) || defined(__OpenBSD__)
511 kvm_t *vm = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, NULL);
512 #else
513 kvm_t *vm = kvm_open(0, "/dev/null", 0, O_RDONLY, NULL);
514 #endif
515 if (vm == 0)
516 return strdup("");
517
518 char* result = NULL;
519 do {
520 int cnt;
521 int mypid = getpid();
522 #ifdef __NetBSD__
523 struct kinfo_proc2 * kp = kvm_getproc2(vm, KERN_PROC_PID, mypid, sizeof(struct kinfo_proc2), &cnt);
524 #else
525 struct kinfo_proc * kp = kvm_getprocs(vm, KERN_PROC_PID, mypid, &cnt);
526 #endif
527 if ((cnt != 1) || (kp == 0)) {
528 break;
529 }
530 int i;
531 for (i = 0; i < cnt; i++)
532 #if defined(__NetBSD__) || defined(__OpenBSD__)
533 if (kp->p_pid == mypid)
534 #else
535 if (kp->ki_pid == mypid)
536 #endif
537 break;
538 if (i != cnt)
539 #if defined(__NetBSD__) || defined(__OpenBSD__)
540 result = strdup(kp->p_comm);
541 #else
542 result = strdup(kp->ki_comm);
543 #endif
544 } while (0);
545 kvm_close(vm);
546 if (result == NULL)
547 result = strdup("");
548 return result;
549 #else
550 return strdup("");
551 #endif
552 }
553
554 FCITX_EXPORT_API
fcitx_utils_get_fcitx_path(const char * type)555 char* fcitx_utils_get_fcitx_path(const char* type)
556 {
557 char* fcitxdir = getenv("FCITXDIR");
558 char* result = NULL;
559 if (strcmp(type, "datadir") == 0) {
560 if (fcitxdir) {
561 fcitx_utils_alloc_cat_str(result, fcitxdir, "/share");
562 } else {
563 result = strdup(DATADIR);
564 }
565 }
566 else if (strcmp(type, "pkgdatadir") == 0) {
567 if (fcitxdir) {
568 fcitx_utils_alloc_cat_str(result, fcitxdir, "/share/"PACKAGE);
569 } else {
570 result = strdup(PKGDATADIR);
571 }
572 }
573 else if (strcmp(type, "bindir") == 0) {
574 if (fcitxdir) {
575 fcitx_utils_alloc_cat_str(result, fcitxdir, "/bin");
576 }
577 else
578 result = strdup(BINDIR);
579 }
580 else if (strcmp(type, "libdir") == 0) {
581 if (fcitxdir) {
582 fcitx_utils_alloc_cat_str(result, fcitxdir, "/lib");
583 }
584 else
585 result = strdup(LIBDIR);
586 }
587 else if (strcmp(type, "localedir") == 0) {
588 if (fcitxdir) {
589 fcitx_utils_alloc_cat_str(result, fcitxdir, "/share/locale");
590 }
591 else
592 result = strdup(LOCALEDIR);
593 }
594 return result;
595 }
596
597 FCITX_EXPORT_API
fcitx_utils_get_fcitx_path_with_filename(const char * type,const char * filename)598 char* fcitx_utils_get_fcitx_path_with_filename(const char* type, const char* filename)
599 {
600 char* path = fcitx_utils_get_fcitx_path(type);
601 if (path == NULL)
602 return NULL;
603 char *result;
604 fcitx_utils_alloc_cat_str(result, path, "/", filename);
605 free(path);
606 return result;
607 }
608
609 FCITX_EXPORT_API
fcitx_utils_string_swap(char ** obj,const char * str)610 void fcitx_utils_string_swap(char** obj, const char* str)
611 {
612 if (str) {
613 *obj = fcitx_utils_set_str(*obj, str);
614 } else if (*obj) {
615 free(*obj);
616 *obj = NULL;
617 }
618 }
619
620 FCITX_EXPORT_API
fcitx_utils_string_swap_with_len(char ** obj,const char * str,size_t len)621 void fcitx_utils_string_swap_with_len(char** obj, const char* str, size_t len)
622 {
623 if (str) {
624 *obj = fcitx_utils_set_str_with_len(*obj, str, len);
625 } else if (*obj) {
626 free(*obj);
627 *obj = NULL;
628 }
629 }
630
631 FCITX_EXPORT_API void
fcitx_utils_launch_tool(const char * name,const char * arg)632 fcitx_utils_launch_tool(const char* name, const char* arg)
633 {
634 char* command = fcitx_utils_get_fcitx_path_with_filename("bindir", name);
635 char* args[] = {
636 command,
637 (char*)(intptr_t)arg, /* parent process haven't even touched this... */
638 NULL
639 };
640 fcitx_utils_start_process(args);
641 free(command);
642 }
643
644 FCITX_EXPORT_API
fcitx_utils_launch_configure_tool()645 void fcitx_utils_launch_configure_tool()
646 {
647 fcitx_utils_launch_tool("fcitx-configtool", NULL);
648 }
649
650 FCITX_EXPORT_API
fcitx_utils_launch_configure_tool_for_addon(const char * imaddon)651 void fcitx_utils_launch_configure_tool_for_addon(const char* imaddon)
652 {
653 fcitx_utils_launch_tool("fcitx-configtool", imaddon);
654 }
655
656 FCITX_EXPORT_API
fcitx_utils_launch_restart()657 void fcitx_utils_launch_restart()
658 {
659 fcitx_utils_launch_tool("fcitx", "-r");
660 }
661
662 FCITX_EXPORT_API
fcitx_utils_restart_in_place(void)663 void fcitx_utils_restart_in_place(void)
664 {
665 char* command = fcitx_utils_get_fcitx_path_with_filename("bindir", "fcitx");
666 char* const argv[] = {
667 command,
668 "-D", /* Don't start as daemon */
669 NULL
670 };
671 execv(argv[0], argv);
672 perror("Restart failed: execvp:");
673 _exit(1);
674 }
675
676 FCITX_EXPORT_API
fcitx_utils_start_process(char ** args)677 void fcitx_utils_start_process(char** args)
678 {
679 /* exec command */
680 pid_t child_pid;
681
682 child_pid = fork();
683 if (child_pid < 0) {
684 perror("fork");
685 } else if (child_pid == 0) { /* child process */
686 setsid();
687 pid_t grandchild_pid;
688
689 grandchild_pid = fork();
690 if (grandchild_pid < 0) {
691 perror("fork");
692 _exit(1);
693 } else if (grandchild_pid == 0) { /* grandchild process */
694 execvp(args[0], args);
695 perror("execvp");
696 _exit(1);
697 } else {
698 _exit(0);
699 }
700 } else { /* parent process */
701 int status;
702 waitpid(child_pid, &status, 0);
703 }
704 }
705
706 FCITX_EXPORT_API
707 void
fcitx_utils_backtrace()708 fcitx_utils_backtrace()
709 {
710 #if defined(ENABLE_BACKTRACE)
711 void *array[32];
712
713 size_t size;
714
715 size = backtrace(array, 32);
716 backtrace_symbols_fd(array, size, STDERR_FILENO);
717 #endif
718 }
719
720 FCITX_EXPORT_API
721 int
fcitx_utils_get_boolean_env(const char * name,int defval)722 fcitx_utils_get_boolean_env(const char *name,
723 int defval)
724 {
725 const char *value = getenv(name);
726
727 if (value == NULL)
728 return defval;
729
730 if ((!*value) ||
731 strcmp(value, "0") == 0 ||
732 strcasecmp(value, "false") == 0)
733 return 0;
734
735 return 1;
736 }
737
738 FCITX_EXPORT_API
739 size_t
fcitx_utils_read_uint32(FILE * fp,uint32_t * p)740 fcitx_utils_read_uint32(FILE *fp, uint32_t *p)
741 {
742 uint32_t res = 0;
743 size_t size;
744 size = fread(&res, sizeof(uint32_t), 1, fp);
745 *p = le32toh(res);
746 return size;
747 }
748
749 FCITX_EXPORT_API
750 size_t
fcitx_utils_write_uint32(FILE * fp,uint32_t i)751 fcitx_utils_write_uint32(FILE *fp, uint32_t i)
752 {
753 i = htole32(i);
754 return fwrite(&i, sizeof(uint32_t), 1, fp);
755 }
756
757 FCITX_EXPORT_API
758 size_t
fcitx_utils_read_uint16(FILE * fp,uint16_t * p)759 fcitx_utils_read_uint16(FILE *fp, uint16_t *p)
760 {
761 uint16_t res = 0;
762 size_t size;
763 size = fread(&res, sizeof(uint16_t), 1, fp);
764 *p = le16toh(res);
765 return size;
766 }
767
768 FCITX_EXPORT_API
769 size_t
fcitx_utils_write_uint16(FILE * fp,uint16_t i)770 fcitx_utils_write_uint16(FILE *fp, uint16_t i)
771 {
772 i = htole16(i);
773 return fwrite(&i, sizeof(uint16_t), 1, fp);
774 }
775
776 FCITX_EXPORT_API
777 size_t
fcitx_utils_read_uint64(FILE * fp,uint64_t * p)778 fcitx_utils_read_uint64(FILE *fp, uint64_t *p)
779 {
780 uint64_t res = 0;
781 size_t size;
782 size = fread(&res, sizeof(uint64_t), 1, fp);
783 *p = le64toh(res);
784 return size;
785 }
786
787 FCITX_EXPORT_API
788 size_t
fcitx_utils_write_uint64(FILE * fp,uint64_t i)789 fcitx_utils_write_uint64(FILE *fp, uint64_t i)
790 {
791 i = htole64(i);
792 return fwrite(&i, sizeof(uint64_t), 1, fp);
793 }
794
795 FCITX_EXPORT_API size_t
fcitx_utils_str_lens(size_t n,const char ** str_list,size_t * size_list)796 fcitx_utils_str_lens(size_t n, const char **str_list, size_t *size_list)
797 {
798 size_t i;
799 size_t total = 0;
800 for (i = 0;i < n;i++) {
801 total += (size_list[i] = str_list[i] ? strlen(str_list[i]) : 0);
802 }
803 return total + 1;
804 }
805
806 FCITX_EXPORT_API void
fcitx_utils_cat_str(char * out,size_t n,const char ** str_list,const size_t * size_list)807 fcitx_utils_cat_str(char *out, size_t n, const char **str_list,
808 const size_t *size_list)
809 {
810 size_t i = 0;
811 for (i = 0;i < n;i++) {
812 if (!size_list[i])
813 continue;
814 memcpy(out, str_list[i], size_list[i]);
815 out += size_list[i];
816 }
817 *out = '\0';
818 }
819
820 FCITX_EXPORT_API void
fcitx_utils_cat_str_with_len(char * out,size_t len,size_t n,const char ** str_list,const size_t * size_list)821 fcitx_utils_cat_str_with_len(char *out, size_t len, size_t n,
822 const char **str_list, const size_t *size_list)
823 {
824 char *limit = out + len - 1;
825 char *tmp = out;
826 size_t i = 0;
827 for (i = 0;i < n;i++) {
828 if (!size_list[i])
829 continue;
830 tmp += size_list[i];
831 if (tmp > limit) {
832 memcpy(out, str_list[i], limit - out);
833 out = limit;
834 break;
835 }
836 memcpy(out, str_list[i], size_list[i]);
837 out = tmp;
838 }
839 *out = '\0';
840 }
841
842 FCITX_EXPORT_API int
fcitx_utils_strcmp0(const char * a,const char * b)843 fcitx_utils_strcmp0(const char *a, const char *b)
844 {
845 if (!a) {
846 if (!b)
847 return 0;
848 return -1;
849 } else if (!b) {
850 return 1;
851 }
852 return strcmp(a, b);
853
854 }
855
856 FCITX_EXPORT_API
857 int
fcitx_utils_strcmp_empty(const char * a,const char * b)858 fcitx_utils_strcmp_empty(const char* a, const char* b)
859 {
860 int isemptya = (a == NULL || (*a) == 0);
861 int isemptyb = (b == NULL || (*b) == 0);
862 if (isemptya && isemptyb)
863 return 0;
864 if (isemptya && !isemptyb)
865 return -1;
866 if (!isemptya && isemptyb)
867 return 1;
868 return strcmp(a, b);
869 }
870
871 FCITX_EXPORT_API char*
fcitx_utils_set_str_with_len(char * res,const char * str,size_t len)872 fcitx_utils_set_str_with_len(char *res, const char *str, size_t len)
873 {
874 if (res) {
875 res = realloc(res, len + 1);
876 } else {
877 res = malloc(len + 1);
878 }
879 memcpy(res, str, len);
880 res[len] = '\0';
881 return res;
882 }
883
884 FCITX_EXPORT_API char
fcitx_utils_unescape_char(char c)885 fcitx_utils_unescape_char(char c)
886 {
887 switch (c) {
888 #define CASE_UNESCAPE(from, to) case from: return to
889 CASE_UNESCAPE('a', '\a');
890 CASE_UNESCAPE('b', '\b');
891 CASE_UNESCAPE('f', '\f');
892 CASE_UNESCAPE('n', '\n');
893 CASE_UNESCAPE('r', '\r');
894 CASE_UNESCAPE('t', '\t');
895 CASE_UNESCAPE('e', '\e');
896 CASE_UNESCAPE('v', '\v');
897 #undef CASE_UNESCAPE
898 }
899 return c;
900 }
901
902 FCITX_EXPORT_API char*
fcitx_utils_unescape_str_inplace(char * str)903 fcitx_utils_unescape_str_inplace(char *str)
904 {
905 char *dest = str;
906 char *src = str;
907 char *pos;
908 size_t len;
909 while ((len = strcspn(src, "\\")), *(pos = src + len)) {
910 if (dest != src && len)
911 memmove(dest, src, len);
912 dest += len;
913 src = pos + 1;
914 *dest = fcitx_utils_unescape_char(*src);
915 dest++;
916 src++;
917 }
918 if (dest != src && len)
919 memmove(dest, src, len);
920 dest[len] = '\0';
921 return str;
922 }
923
924 FCITX_EXPORT_API char*
fcitx_utils_set_unescape_str(char * res,const char * str)925 fcitx_utils_set_unescape_str(char *res, const char *str)
926 {
927 size_t len = strlen(str) + 1;
928 if (res) {
929 res = realloc(res, len);
930 } else {
931 res = malloc(len);
932 }
933 char *dest = res;
934 const char *src = str;
935 const char *pos;
936 while ((len = strcspn(src, "\\")), *(pos = src + len)) {
937 memcpy(dest, src, len);
938 dest += len;
939 src = pos + 1;
940 *dest = fcitx_utils_unescape_char(*src);
941 dest++;
942 src++;
943 }
944 if (len)
945 memcpy(dest, src, len);
946 dest[len] = '\0';
947 return res;
948 }
949
950 FCITX_EXPORT_API char
fcitx_utils_escape_char(char c)951 fcitx_utils_escape_char(char c)
952 {
953 switch (c) {
954 #define CASE_ESCAPE(to, from) case from: return to
955 CASE_ESCAPE('a', '\a');
956 CASE_ESCAPE('b', '\b');
957 CASE_ESCAPE('f', '\f');
958 CASE_ESCAPE('n', '\n');
959 CASE_ESCAPE('r', '\r');
960 CASE_ESCAPE('t', '\t');
961 CASE_ESCAPE('e', '\e');
962 CASE_ESCAPE('v', '\v');
963 #undef CASE_ESCAPE
964 }
965 return c;
966 }
967
968 FCITX_EXPORT_API char*
fcitx_utils_set_escape_str_with_set(char * res,const char * str,const char * set)969 fcitx_utils_set_escape_str_with_set(char *res, const char *str, const char *set)
970 {
971 if (!set)
972 set = FCITX_CHAR_NEED_ESCAPE;
973 size_t len = strlen(str) * 2 + 1;
974 if (res) {
975 res = realloc(res, len);
976 } else {
977 res = malloc(len);
978 }
979 char *dest = res;
980 const char *src = str;
981 const char *pos;
982 while ((len = strcspn(src, set)), *(pos = src + len)) {
983 memcpy(dest, src, len);
984 dest += len;
985 *dest = '\\';
986 dest++;
987 *dest = fcitx_utils_escape_char(*pos);
988 dest++;
989 src = pos + 1;
990 }
991 if (len)
992 memcpy(dest, src, len);
993 dest += len;
994 *dest = '\0';
995 res = realloc(res, dest - res + 1);
996 return res;
997 }
998
999 #ifdef __FCITX_ATOMIC_USE_SYNC_FETCH
1000 /**
1001 * Also define lib function when there is builtin function for
1002 * atomic operation in case the function address is needed or the builtin
1003 * is not available when compiling other modules.
1004 **/
1005 #define FCITX_UTIL_DEFINE_ATOMIC(name, op, type) \
1006 FCITX_EXPORT_API type \
1007 (fcitx_utils_atomic_##name)(volatile type *atomic, type val) \
1008 { \
1009 return __sync_fetch_and_##name(atomic, val); \
1010 }
1011 #else
1012 static pthread_mutex_t __fcitx_utils_atomic_lock = PTHREAD_MUTEX_INITIALIZER;
1013 #define FCITX_UTIL_DEFINE_ATOMIC(name, op, type) \
1014 FCITX_EXPORT_API type \
1015 (fcitx_utils_atomic_##name)(volatile type *atomic, type val) \
1016 { \
1017 type oldval; \
1018 pthread_mutex_lock(&__fcitx_utils_atomic_lock); \
1019 oldval = *atomic; \
1020 *atomic = oldval op val; \
1021 pthread_mutex_unlock(&__fcitx_utils_atomic_lock); \
1022 return oldval; \
1023 }
1024 #endif
1025
1026 FCITX_UTIL_DEFINE_ATOMIC(add, +, int32_t)
1027 FCITX_UTIL_DEFINE_ATOMIC(and, &, uint32_t)
1028 FCITX_UTIL_DEFINE_ATOMIC(or, |, uint32_t)
1029 FCITX_UTIL_DEFINE_ATOMIC(xor, ^, uint32_t)
1030
1031 #undef FCITX_UTIL_DEFINE_ATOMIC
1032
1033 // kate: indent-mode cstyle; space-indent on; indent-width 0;
1034