1 /***************************************************************************
2  *   Copyright (C) 2002~2005 by Yuking                                     *
3  *   yuking_net@sohu.com                                                   *
4  *   Copyright (C) 2011~2012 by CSSlayer                                   *
5  *   wengxt@gmail.com                                                      *
6  *   Copyright (C) 2012~2013 by Yichao Yu                                  *
7  *   yyc1992@gmail.com                                                     *
8  *                                                                         *
9  *   This program is free software; you can redistribute it and/or modify  *
10  *   it under the terms of the GNU General Public License as published by  *
11  *   the Free Software Foundation; either version 2 of the License, or     *
12  *   (at your option) any later version.                                   *
13  *                                                                         *
14  *   This program is distributed in the hope that it will be useful,       *
15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
17  *   GNU General Public License for more details.                          *
18  *                                                                         *
19  *   You should have received a copy of the GNU General Public License     *
20  *   along with this program; if not, write to the                         *
21  *   Free Software Foundation, Inc.,                                       *
22  *   51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.              *
23  ***************************************************************************/
24 /**
25  * @defgroup FcitxUtils FcitxUtils
26  *
27  * Fcitx Utils contains a bunch of functions, with extend common c library.
28  * It contains uthash/utarray as macro based hash table and dynamic array.
29  *
30  * Some Fcitx path related function, includes fcitx_utils_get_fcitx_path()
31  * and fcitx_utils_get_fcitx_path_with_filename()
32  *
33  * Some string related function, providing split, join string list.
34  *
35  * A simple memory pool, if you need to allocate many small memory block, and
36  * only need to free them at once.
37  *
38  * Some log function, which prints the current file number, with printf format.
39  *
40  * Why Fcitx does not use GLib?
41  *
42  * The answer is glib contains a lot of function that fcitx doesn't need, and
43  * in order to keep fcitx-core only depends on libc,
44  * we provide some functions that are equivalent to glib ones in fcitx-utils.
45  */
46 
47 /**
48  * @addtogroup FcitxUtils
49  * @{
50  */
51 
52 /**
53  * @file   utils.h
54  * @author CS Slayer wengxt@gmail.com
55  *
56  *  Misc function for Fcitx.
57  *
58  */
59 
60 #ifndef _FCITX_UTILS_H_
61 #define _FCITX_UTILS_H_
62 
63 #include <stdio.h>
64 #include <stdint.h>
65 #include <unistd.h>
66 #include <fcitx-utils/utarray.h>
67 #include <fcitx-utils/uthash.h>
68 #include <sys/stat.h>
69 
70 /**
71  * fcitx boolean
72  **/
73 typedef int32_t boolean;
74 #if !defined(__cplusplus) && !defined(FCITX_DONOT_DEFINE_TRUE_FALSE)
75 /**
76  * fcitx true
77  */
78 #define true (1)
79 /**
80  * fcitx false
81  */
82 #define false (0)
83 #endif
84 
85 #define FCITX_INT_LEN ((int)(sizeof(int) * 2.5) + 2)
86 #define FCITX_LONG_LEN ((int)(sizeof(long) * 2.5) + 2)
87 #define FCITX_INT32_LEN (22)
88 #define FCITX_INT64_LEN (42)
89 
90 #define fcitx_container_of(ptr, type, member)           \
91     ((type*)(((void*)(ptr)) - offsetof(type, member)))
92 
93 #if (defined(__GNUC__) && (__GNUC__ > 2))
94 #  define fcitx_expect(exp, var) __builtin_expect(exp, var)
95 #else
96 #  define fcitx_expect(exp, var) (exp)
97 #endif
98 
99 #define FCITX_ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
100 
101 #define fcitx_likely(x) fcitx_expect(!!(x), 1)
102 #define fcitx_unlikely(x) fcitx_expect(!!(x), 0)
103 
104 #ifdef __cplusplus
105 extern "C" {
106 #endif
107 
108     typedef enum _FcitxTriState {
109       Tri_False = false,
110       Tri_True = true,
111       Tri_Unknown
112     } FcitxTriState;
113 
114     extern const UT_icd *const fcitx_ptr_icd;
115     extern const UT_icd *const fcitx_str_icd;
116     extern const UT_icd *const fcitx_int_icd;
117     extern const UT_icd *const fcitx_int8_icd;
118     extern const UT_icd *const fcitx_int16_icd;
119     extern const UT_icd *const fcitx_int32_icd;
120     extern const UT_icd *const fcitx_int64_icd;
121 
122     /**
123      * Function used to free the pointer
124      **/
125     typedef void (*FcitxDestroyNotify)(void *p);
126     /**
127      * Function used to free the content of a structure,
128      * DO NOT free the pointer itself
129      **/
130     typedef void (*FcitxCallBack)();
131     /**
132      * A hash set for string
133      **/
134     typedef struct _FcitxStringHashSet {
135         /**
136          * String in Hash Set
137          **/
138         char *name;
139         /**
140          * UT Hash handle
141          **/
142         UT_hash_handle hh;
143     } FcitxStringHashSet;
144 
145 
146     /**
147      * Custom bsearch, it can search the most near value.
148      *
149      * @param key
150      * @param base
151      * @param nmemb
152      * @param size
153      * @param accurate
154      * @param compar
155      *
156      * @return
157      */
158     void *fcitx_utils_custom_bsearch(const void *key, const void *base,
159                                      size_t nmemb, size_t size, int accurate,
160                                      int (*compar)(const void *, const void *));
161 
162     /**
163      * Fork twice to run as daemon
164      *
165      * @return void
166      **/
167     void fcitx_utils_init_as_daemon(void);
168 
169     /**
170      * Count the file line count
171      *
172      * @param fpDict file pointer
173      * @return int line count
174      **/
175     int fcitx_utils_calculate_record_number(FILE* fpDict);
176 
177 
178     /**
179      * create empty string list
180      *
181      * @return UT_array*
182      **/
183     UT_array* fcitx_utils_new_string_list(void);
184 
185     /**
186      * Split a string by delm
187      *
188      * @param str input string
189      * @param delm character as delimiter
190      * @return UT_array* a new utarray for store the split string
191      **/
192     UT_array* fcitx_utils_split_string(const char *str, char delm);
193 
194     /**
195      * append a string with printf format
196      *
197      * @param list string list
198      * @param fmt printf fmt
199      * @return void
200      **/
201     void fcitx_utils_string_list_printf_append(UT_array* list, const char* fmt,...);
202 
203     /**
204      * Join string list with delm
205      *
206      * @param list string list
207      * @param delm delm
208      * @return char* return string, need to be free'd
209      **/
210     char* fcitx_utils_join_string_list(UT_array* list, char delm);
211 
212     /**
213      * check if a string list contains a specific string
214      *
215      * @param list string list
216      * @param scmp string to compare
217      *
218      * @return 1 for found, 0 for not found.
219      *
220      * @since 4.2.5
221      */
222     int fcitx_utils_string_list_contains(UT_array* list, const char* scmp);
223 
224     /**
225      * Helper function for free the SplitString Output
226      *
227      * @param list the SplitString Output
228      * @return void
229      * @see fcitx_utils_split_string
230      **/
231     void fcitx_utils_free_string_list(UT_array *list);
232 
233     /**
234      * Free String Hash Set
235      *
236      * @param sset String Hash Set
237      * @return void
238      *
239      * @since 4.2.0
240      **/
241     void fcitx_utils_free_string_hash_set(FcitxStringHashSet* sset);
242 
243     /**
244      * compare two string with strcmp
245      *
246      * @param sseta left
247      * @param ssetb right
248      * @return same as strcmp
249      *
250      * @since 4.2.8
251      **/
252     int fcitx_utils_string_hash_set_compare(FcitxStringHashSet* sseta, FcitxStringHashSet* ssetb);
253 
254     /**
255      * insert to a string hash set
256      *
257      * @param sset string hash set
258      * @param str string
259      * @return FcitxStringHashSet*
260      *
261      * @since 4.2.7
262      **/
263     FcitxStringHashSet* fcitx_utils_string_hash_set_insert(FcitxStringHashSet* sset, const char* str);
264 
265     /**
266      * insert string with specified length
267      *
268      * @param sset string hash set
269      * @param str string
270      * @param len length
271      * @return FcitxStringHashSet*
272      *
273      * @since 4.2.7
274      **/
275     FcitxStringHashSet* fcitx_utils_string_hash_set_insert_len(FcitxStringHashSet* sset, const char* str, size_t len);
276 
277     /**
278      * check a string contains in string hash set or not
279      *
280      * @param sset string hash set
281      * @param str string
282      * @return boolean
283      *
284      * @since 4.2.7
285      **/
286     boolean fcitx_utils_string_hash_set_contains(FcitxStringHashSet* sset, const char* str);
287 
288     /**
289      * remove a string from string hash set
290      *
291      * @param sset string hash set
292      * @param str string
293      * @return FcitxStringHashSet*
294      *
295      * @since 4.2.7
296      **/
297     FcitxStringHashSet* fcitx_util_string_hash_set_remove(FcitxStringHashSet* sset, const char* str);
298 
299     /**
300      * join a string hash set with delimiter
301      *
302      * @param sset string hash set
303      * @param delim delimeter
304      * @return char*
305      *
306      * @since 4.2.7
307      **/
308     char* fcitx_utils_string_hash_set_join(FcitxStringHashSet* sset, char delim);
309 
310     /**
311      * parse a string with delimiter
312      *
313      * @param str string
314      * @param delim delimiter
315      * @return FcitxStringHashSet*
316      *
317      * @since 4.2.7
318      **/
319     FcitxStringHashSet* fcitx_utils_string_hash_set_parse(const char* str, char delim);
320 
321     /**
322      * Trim the input string's white space
323      *
324      * @param s input string
325      * @return char* new malloced string, need to free'd by caller
326      **/
327     char* fcitx_utils_trim(const char *s);
328 
329     /**
330      * Malloc and memset all memory to zero
331      *
332      * @param bytes malloc size
333      * @return void* malloced pointer
334      **/
335     void* fcitx_utils_malloc0(size_t bytes);
336 
337 #define fcitx_utils_new(TYPE) ((TYPE*) fcitx_utils_malloc0(sizeof(TYPE)))
338 
339     static inline void*
_fcitx_utils_new_with_data(size_t base_size,const void * extra_data,size_t extra_size)340     _fcitx_utils_new_with_data(size_t base_size, const void *extra_data,
341                                size_t extra_size)
342     {
343         void *res = fcitx_utils_malloc0(base_size + extra_size);
344         memcpy(((char*)res) + base_size, extra_data, extra_size);
345         return res;
346     }
347     static inline void*
_fcitx_utils_new_with_str(size_t base_size,const char * extra_str)348     _fcitx_utils_new_with_str(size_t base_size, const char *extra_str)
349     {
350         return _fcitx_utils_new_with_data(base_size, (const void*)extra_str,
351                                           strlen(extra_str) + 1);
352     }
353 #define fcitx_utils_new_with_data(TYPE, data, size)                     \
354     ((TYPE*)_fcitx_utils_new_with_data(sizeof(TYPE), data, size))
355 #define fcitx_utils_new_with_str(TYPE, str)                     \
356     ((TYPE*)_fcitx_utils_new_with_str(sizeof(TYPE), str))
357 #define fcitx_utils_new_with_data_member(TYPE, member, data, size)      \
358     ((TYPE*)_fcitx_utils_new_with_data(offsetof(TYPE, member), data, size))
359 #define fcitx_utils_new_with_str_member(TYPE, member, str)              \
360     ((TYPE*)_fcitx_utils_new_with_str(offsetof(TYPE, member), str))
361 
362     /**
363      * Get Display number, Fcitx DBus and Socket are identified by display number.
364      *
365      * @return int
366      **/
367     int fcitx_utils_get_display_number(void);
368 
369     /**
370      * Get current language code, result need to be free'd
371      * It will check LC_CTYPE, LC_ALL, LANG, for current language code.
372      *
373      * @return char*
374      **/
375     char* fcitx_utils_get_current_langcode(void);
376 
377     /**
378      * check the current locale is utf8 or not
379      *
380      * @return int
381      **/
382     int fcitx_utils_current_locale_is_utf8(void);
383 
384     /**
385      * Get Current Process Name, implementation depends on OS,
386      * Always return a string need to be free'd, if cannot get
387      * current process name, it will return "".
388      *
389      * @return char*
390      **/
391     char* fcitx_utils_get_process_name(void);
392 
393 
394     /**
395      * @brief check a process is running or not
396      *
397      * @param pid pid
398      * @return 1 for exists or error, 0 for non exists
399      **/
400     int fcitx_utils_pid_exists(pid_t pid);
401 
402     /**
403      * Get Fcitx install path, need be free'd
404      * All possible type includes:
405      * datadir
406      * pkgdatadir
407      * bindir
408      * libdir
409      * localedir
410      *
411      * It's determined at compile time, and can be changed via environment variable: FCITXDIR
412      *
413      * It will only return NULL while the type is invalid.
414      *
415      * @param type path type
416      *
417      * @return char*
418      *
419      * @since 4.2.1
420      */
421     char* fcitx_utils_get_fcitx_path(const char* type);
422 
423     /**
424      * Get fcitx install path with file name, need to be free'd
425      *
426      * It's just simply return the path/filename string.
427      *
428      * It will only return NULL while the type is invalid.
429      *
430      * @param type path type
431      * @param filename filename
432      *
433      * @return char*
434      *
435      * @see fcitx_utils_get_fcitx_path
436      *
437      * @since 4.2.1
438      */
439     char* fcitx_utils_get_fcitx_path_with_filename(const char* type, const char* filename);
440 
441     /**
442      * lanunch fcitx's tool
443      *
444      * @param name tool's name
445      * @param arg single arg
446      *
447      * @return void
448      *
449      * @since 4.2.6
450      */
451     void fcitx_utils_launch_tool(const char* name, const char* arg);
452 
453     /**
454      * launch fcitx-configtool
455      *
456      * @return void
457      **/
458     void fcitx_utils_launch_configure_tool(void);
459 
460     /**
461      * launch fcitx-configtool for an addon
462      *
463      * @return void
464      **/
465     void fcitx_utils_launch_configure_tool_for_addon(const char* addon);
466 
467     /**
468      * helper function to execute fcitx -r
469      *
470      * @return void
471      **/
472     void fcitx_utils_launch_restart(void);
473 
474     /**
475      * helper function to execute in place
476      *
477      * @return void
478      **/
479     void fcitx_utils_restart_in_place(void);
480 
481     /**
482      * @brief launch a process
483      *
484      * @param args argument and command
485      * @return void
486      *
487      * @since 4.2.5
488      **/
489     void fcitx_utils_start_process(char** args);
490 
491     /**
492      * output backtrace to stderr, need to enable backtrace, this function
493      * will be signal safe since 4.2.7, if you want to use it in debug,
494      * you'd better call fflush(stderr) before call to it.
495      *
496      * @return void
497      *
498      * @since 4.2.5
499      **/
500     void fcitx_utils_backtrace();
501 
502     /**
503      * @brief get bool environment var for convenience.
504      *
505      * @param name var name
506      * @param defval default value
507      *
508      * @return value of var
509      *
510      * @since 4.2.6
511      */
512     int fcitx_utils_get_boolean_env(const char *name, int defval);
513 
514     /**
515      * if obj is null, free it, after that, if str is NULL set it with NULL,
516      * if str is not NULL, set it with strdup(str)
517      *
518      * @param obj object string
519      * @param str source string
520      * @return void
521      **/
522     void fcitx_utils_string_swap(char** obj, const char* str);
523     void fcitx_utils_string_swap_with_len(char** obj,
524                                           const char* str, size_t len);
525 
526     /**
527      * similar with strcmp, but can handle the case that a or b is null.
528      * NULL < not NULL and NULL == NULL
529      *
530      * @param a string a
531      * @param b string b
532      * @return same as rule of strcmp
533      */
534     int fcitx_utils_strcmp0(const char* a, const char* b);
535 
536     /**
537      * similar with fcitx_utils_strcmp0, but empty string will be considered
538      * equals to NULL in this case.
539      * NULL == empty, and empty < not empty
540      *
541      * @param a string a
542      * @param b string b
543      * @return same as rule of strcmp
544      */
545     int fcitx_utils_strcmp_empty(const char* a, const char* b);
546 
547     /** free a pointer if it's not NULL */
548     static inline void
fcitx_utils_free(void * ptr)549     fcitx_utils_free(void *ptr)
550     {
551         if (ptr)
552             free(ptr);
553     }
554 
555 #define fcitx_utils_read(fp, p, type)           \
556     fcitx_utils_read_ ## type(fp, p)
557 
558 #define fcitx_utils_write(fp, p, type)          \
559     fcitx_utils_write_ ## type(fp, p)
560 
561     /**
562      * read a little endian 32bit unsigned int from a file
563      *
564      * @param fp FILE* to read from
565      * @param p return the integer read
566      * @return 1 on success, 0 on error
567      * @since 4.2.6
568      **/
569     size_t fcitx_utils_read_uint32(FILE *fp, uint32_t *p);
570 
571     /**
572      * read a little endian 32bit int from a file
573      *
574      * @param fp FILE* to read from
575      * @param p return the integer read
576      * @return 1 on success, 0 on error
577      * @since 4.2.6
578      **/
579     static inline size_t
fcitx_utils_read_int32(FILE * fp,int32_t * p)580     fcitx_utils_read_int32(FILE *fp, int32_t *p)
581     {
582         return fcitx_utils_read_uint32(fp, (uint32_t*)p);
583     }
584 
585     /**
586      * write a little endian 32bit int to a file
587      *
588      * @param fp FILE* to write to
589      * @param i int to write in host endian
590      * @return 1 on success, 0 on error
591      * @since 4.2.6
592      **/
593     size_t fcitx_utils_write_uint32(FILE *fp, uint32_t i);
594 
595     /**
596      * write a little endian 32bit unsigned int to a file
597      *
598      * @param fp FILE* to write to
599      * @param i int to write in host endian
600      * @return 1 on success, 0 on error
601      * @since 4.2.6
602      **/
603     static inline size_t
fcitx_utils_write_int32(FILE * fp,int32_t i)604     fcitx_utils_write_int32(FILE *fp, int32_t i)
605     {
606         return fcitx_utils_write_uint32(fp, (uint32_t)i);
607     }
608 
609 
610     /**
611      * read a little endian 64bit unsigned int from a file
612      *
613      * @param fp FILE* to read from
614      * @param p return the integer read
615      * @return 1 on success, 0 on error
616      * @since 4.2.6
617      **/
618     size_t fcitx_utils_read_uint64(FILE *fp, uint64_t *p);
619 
620     /**
621      * read a little endian 64bit int from a file
622      *
623      * @param fp FILE* to read from
624      * @param p return the integer read
625      * @return 1 on success, 0 on error
626      * @since 4.2.6
627      **/
628     static inline size_t
fcitx_utils_read_int64(FILE * fp,int64_t * p)629     fcitx_utils_read_int64(FILE *fp, int64_t *p)
630     {
631         return fcitx_utils_read_uint64(fp, (uint64_t*)p);
632     }
633 
634     /**
635      * write a little endian 64bit int to a file
636      *
637      * @param fp FILE* to write
638      * @param i int to write in host endian
639      * @return 1 on success, 0 on error
640      * @since 4.2.6
641      **/
642     size_t fcitx_utils_write_uint64(FILE *fp, uint64_t i);
643 
644     /**
645      * write a little endian 64bit unsigned int to a file
646      *
647      * @param fp FILE* to write to
648      * @param i int to write in host endian
649      * @return 1 on success, 0 on error
650      * @since 4.2.6
651      **/
652     static inline size_t
fcitx_utils_write_int64(FILE * fp,int64_t i)653     fcitx_utils_write_int64(FILE *fp, int64_t i)
654     {
655         return fcitx_utils_write_uint64(fp, (uint64_t)i);
656     }
657 
658 
659     /**
660      * read a little endian 16bit unsigned int from a file
661      *
662      * @param fp FILE* to read from
663      * @param p return the integer read
664      * @return 1 on success, 0 on error
665      * @since 4.2.6
666      **/
667     size_t fcitx_utils_read_uint16(FILE *fp, uint16_t *p);
668 
669     /**
670      * read a little endian 16bit int from a file
671      *
672      * @param fp FILE* to read from
673      * @param p return the integer read
674      * @return 1 on success, 0 on error
675      * @since 4.2.6
676      **/
677     static inline size_t
fcitx_utils_read_int16(FILE * fp,int16_t * p)678     fcitx_utils_read_int16(FILE *fp, int16_t *p)
679     {
680         return fcitx_utils_read_uint16(fp, (uint16_t*)p);
681     }
682 
683     /**
684      * write a little endian 16bit int to a file
685      *
686      * @param fp FILE* to write to
687      * @param i int to write in host endian
688      * @return 1 on success, 0 on error
689      * @since 4.2.6
690      **/
691     size_t fcitx_utils_write_uint16(FILE *fp, uint16_t i);
692 
693     /**
694      * write a little endian 16bit unsigned int to a file
695      *
696      * @param fp FILE* to write to
697      * @param i int to write in host endian
698      * @return 1 on success, 0 on error
699      * @since 4.2.6
700      **/
701     static inline size_t
fcitx_utils_write_int16(FILE * fp,int16_t i)702     fcitx_utils_write_int16(FILE *fp, int16_t i)
703     {
704         return fcitx_utils_write_uint16(fp, (uint16_t)i);
705     }
706 
707     size_t fcitx_utils_str_lens(size_t n, const char **str_list,
708                                 size_t *size_list);
709     void fcitx_utils_cat_str(char *out, size_t n, const char **str_list,
710                              const size_t *size_list);
711     void fcitx_utils_cat_str_with_len(char *out, size_t len, size_t n,
712                                       const char **str_list,
713                                       const size_t *size_list);
714 #define fcitx_utils_cat_str_simple(out, n, str_list) do {       \
715         size_t __tmp_size_list[n];                              \
716         fcitx_utils_str_lens(n, str_list, __tmp_size_list);     \
717         fcitx_utils_cat_str(out, n, str_list, __tmp_size_list); \
718     } while (0)
719 
720 #define fcitx_utils_cat_str_simple_with_len(out, len, n, str_list) do { \
721         size_t __tmp_size_list[n];                                      \
722         fcitx_utils_str_lens(n, str_list, __tmp_size_list);             \
723         fcitx_utils_cat_str_with_len(out, len, n, str_list, __tmp_size_list); \
724     } while (0)
725 
726 #define fcitx_utils_local_cat_str(dest, len, strs...)                   \
727     const char *__str_list_##dest[] = {strs};                           \
728     size_t __size_list_##dest[sizeof((const char*[]){strs}) / sizeof(char*)]; \
729     fcitx_utils_str_lens(sizeof((const char*[]){strs}) / sizeof(char*), \
730                          __str_list_##dest, __size_list_##dest);        \
731     char dest[len];                                                     \
732     fcitx_utils_cat_str_with_len(dest, len,                             \
733                                  sizeof((const char*[]){strs}) / sizeof(char*), \
734                                  __str_list_##dest, __size_list_##dest)
735 
736 #define fcitx_utils_alloc_cat_str(dest, strs...) do {                   \
737         const char *__str_list[] = {strs};                              \
738         size_t __cat_str_n = sizeof(__str_list) / sizeof(char*);        \
739         size_t __size_list[sizeof(__str_list) / sizeof(char*)];         \
740         size_t __total_size = fcitx_utils_str_lens(__cat_str_n,         \
741                                                    __str_list, __size_list); \
742         dest = malloc(__total_size);                                    \
743         fcitx_utils_cat_str(dest, __cat_str_n,                          \
744                             __str_list, __size_list);                   \
745     } while (0)
746 
747 #define fcitx_utils_set_cat_str(dest, strs...) do {                     \
748         const char *__str_list[] = {strs};                              \
749         size_t __cat_str_n = sizeof(__str_list) / sizeof(char*);        \
750         size_t __size_list[sizeof(__str_list) / sizeof(char*)];         \
751         size_t __total_size = fcitx_utils_str_lens(__cat_str_n,         \
752                                                    __str_list, __size_list); \
753         dest = realloc(dest, __total_size);                             \
754         fcitx_utils_cat_str(dest, __cat_str_n,                          \
755                             __str_list, __size_list);                   \
756     } while (0)
757 
fcitx_utils_isdir(const char * path)758     static inline int fcitx_utils_isdir(const char *path)
759     {
760         struct stat stats;
761         return (stat(path, &stats) == 0 && S_ISDIR(stats.st_mode) &&
762                 access(path, R_OK | X_OK) == 0);
763     }
764 
fcitx_utils_isreg(const char * path)765     static inline int fcitx_utils_isreg(const char *path)
766     {
767         struct stat stats;
768         return (stat(path, &stats) == 0 && S_ISREG(stats.st_mode) &&
769                 access(path, R_OK) == 0);
770     }
771 
fcitx_utils_islnk(const char * path)772     static inline int fcitx_utils_islnk(const char *path)
773     {
774         struct stat stats;
775         return stat(path, &stats) == 0 && S_ISLNK(stats.st_mode);
776     }
777     char *fcitx_utils_set_str_with_len(char *res, const char *str, size_t len);
778     static inline char*
fcitx_utils_set_str(char * res,const char * str)779     fcitx_utils_set_str(char *res, const char *str)
780     {
781         return fcitx_utils_set_str_with_len(res, str, strlen(str));
782     }
783     char fcitx_utils_unescape_char(char c);
784     char *fcitx_utils_unescape_str_inplace(char *str);
785     char *fcitx_utils_set_unescape_str(char *res, const char *str);
786 #define FCITX_CHAR_NEED_ESCAPE "\a\b\f\n\r\t\e\v\'\"\\"
787     char fcitx_utils_escape_char(char c);
788     char *fcitx_utils_set_escape_str_with_set(char *res, const char *str,
789                                               const char *set);
790     static inline char*
fcitx_utils_set_escape_str(char * res,const char * str)791     fcitx_utils_set_escape_str(char *res, const char *str)
792     {
793         return fcitx_utils_set_escape_str_with_set(res, str, NULL);
794     }
795     UT_array *fcitx_utils_append_split_string(UT_array *list, const char* str,
796                                               const char *delm);
797     static inline UT_array*
fcitx_utils_append_lines(UT_array * list,const char * str)798     fcitx_utils_append_lines(UT_array *list, const char* str)
799     {
800         return fcitx_utils_append_split_string(list, str, "\n");
801     }
802     UT_array *fcitx_utils_string_list_append_no_copy(UT_array *list, char *str);
803     UT_array *fcitx_utils_string_list_append_len(UT_array *list,
804                                                  const char *str, size_t len);
805 
806     static inline uintptr_t
fcitx_utils_align_to(uintptr_t len,uintptr_t align)807     fcitx_utils_align_to(uintptr_t len, uintptr_t align)
808     {
809         uintptr_t left;
810         if ((left = len % align))
811             return len + align - left;
812         return len;
813     }
814 
815 #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
816 #define __FCITX_ATOMIC_USE_SYNC_FETCH
817 #elif defined __has_builtin
818 #if __has_builtin(__sync_fetch_and_add) &&      \
819     __has_builtin(__sync_fetch_and_and) &&      \
820     __has_builtin(__sync_fetch_and_xor) &&      \
821     __has_builtin(__sync_fetch_and_or)
822 #define __FCITX_ATOMIC_USE_SYNC_FETCH
823 #endif
824 #endif
825 
826 #ifdef __FCITX_ATOMIC_USE_SYNC_FETCH
827 #define FCITX_UTIL_DECLARE_ATOMIC(name, type)                           \
828     type (fcitx_utils_atomic_##name)(volatile type *atomic, type val);  \
829     static inline type                                                  \
830     __fcitx_utils_atomic_##name(volatile type *atomic, type val)        \
831     {                                                                   \
832         return __sync_fetch_and_##name(atomic, val);                    \
833     }
834 #else
835 #define FCITX_UTIL_DECLARE_ATOMIC(name, type)                           \
836     type (fcitx_utils_atomic_##name)(volatile type *atomic, type val);  \
837     static inline type                                                  \
838     __fcitx_utils_atomic_##name(volatile type *atomic, type val)        \
839     {                                                                   \
840         return (fcitx_utils_atomic_##name)(atomic, val);                \
841     }
842 #endif
843 
FCITX_UTIL_DECLARE_ATOMIC(add,int32_t)844     FCITX_UTIL_DECLARE_ATOMIC(add, int32_t)
845     FCITX_UTIL_DECLARE_ATOMIC(and, uint32_t)
846     FCITX_UTIL_DECLARE_ATOMIC(or, uint32_t)
847     FCITX_UTIL_DECLARE_ATOMIC(xor, uint32_t)
848 
849 #define fcitx_utils_atomic_add(atomic, val)     \
850     __fcitx_utils_atomic_add(atomic, val)
851 #define fcitx_utils_atomic_and(atomic, val)     \
852     __fcitx_utils_atomic_and(atomic, val)
853 #define fcitx_utils_atomic_or(atomic, val)      \
854     __fcitx_utils_atomic_or(atomic, val)
855 #define fcitx_utils_atomic_xor(atomic, val)     \
856     __fcitx_utils_atomic_xor(atomic, val)
857 
858 #undef FCITX_UTIL_DECLARE_ATOMIC
859 
860     static inline void*
861     fcitx_array_eltptr(UT_array *ary, int i)
862     {
863         if (fcitx_unlikely(i < 0))
864             return NULL;
865         return (void*)utarray_eltptr(ary, (unsigned)i);
866     }
867 
868     static inline void
fcitx_array_insert(UT_array * ary,void * p,int i)869     fcitx_array_insert(UT_array *ary, void *p, int i)
870     {
871         if (fcitx_unlikely(i < 0))
872             return;
873         utarray_insert(ary, p, (unsigned)i);
874     }
875 
876     static inline void
fcitx_array_inserta(UT_array * ary,UT_array * ary2,int i)877     fcitx_array_inserta(UT_array *ary, UT_array *ary2, int i)
878     {
879         if (fcitx_unlikely(i < 0))
880             return;
881         utarray_inserta(ary, ary2, (unsigned)i);
882     }
883 
884     static inline void
fcitx_array_move(UT_array * ary,int from,int to)885     fcitx_array_move(UT_array *ary, int from, int to)
886     {
887         if (fcitx_unlikely(from < 0 || to < 0))
888             return;
889         utarray_move(ary, (unsigned)from, (unsigned)to);
890     }
891 
892     static inline void
fcitx_array_erase(UT_array * ary,int pos,int len)893     fcitx_array_erase(UT_array *ary, int pos, int len)
894     {
895         if (fcitx_unlikely(pos < 0 || len < 0))
896             return;
897         utarray_erase(ary, (unsigned)pos, (unsigned)len);
898     }
899 
900     static inline void
fcitx_array_resize(UT_array * ary,int len)901     fcitx_array_resize(UT_array *ary, int len)
902     {
903         if (fcitx_unlikely(len < 0))
904             return;
905         utarray_resize(ary, (unsigned)len);
906     }
907 
908     /**
909      * rely on compiler to optimize out unnecessary memcpy's and branches here
910      * (and both gcc and clang can do it very well).
911      **/
912 #define __FCITX_BYTE_CAST(new_val, old_type, old_val) do {      \
913         old_type __fx_byte_cast_old = (old_val);                \
914         memset(&new_val, 0, sizeof(new_val));                   \
915         memcpy(&new_val, &__fx_byte_cast_old,                   \
916                sizeof(old_type) < sizeof(new_val) ?             \
917                sizeof(old_type) : sizeof(new_val));             \
918     } while (0)
919 
920     /**
921      * cast a arbitrary type to integer. for pointers and integers types,
922      * this is compatible with normal type casting for other types
923      * (especially float), this will not loss any information
924      * as long as the size of the types is not larger than the integer type
925      **/
926 #define _FCITX_CAST_TO_INT(new_type, new_val, old_type, old_val) do {   \
927         if (sizeof(old_type) <= 1) {                                    \
928             int8_t __fx_cast_to_int_tmp;                                \
929             __FCITX_BYTE_CAST(__fx_cast_to_int_tmp, old_type, old_val); \
930             new_val = (new_type)__fx_cast_to_int_tmp;                   \
931         } else if (sizeof(old_type) <= 2) {                             \
932             int16_t __fx_cast_to_int_tmp;                               \
933             __FCITX_BYTE_CAST(__fx_cast_to_int_tmp, old_type, old_val); \
934             new_val = (new_type)__fx_cast_to_int_tmp;                   \
935         } else if (sizeof(old_type) <= 4) {                             \
936             int32_t __fx_cast_to_int_tmp;                               \
937             __FCITX_BYTE_CAST(__fx_cast_to_int_tmp, old_type, old_val); \
938             new_val = (new_type)__fx_cast_to_int_tmp;                   \
939         } else {                                                        \
940             int64_t __fx_cast_to_int_tmp;                               \
941             __FCITX_BYTE_CAST(__fx_cast_to_int_tmp, old_type, old_val); \
942             new_val = (new_type)__fx_cast_to_int_tmp;                   \
943         }                                                               \
944     } while (0)
945 
946 #define _FCITX_CAST_TO_PTR(new_val, old_type, old_val) do {     \
947         intptr_t __fx_cast_to_ptr_tmp;                          \
948         _FCITX_CAST_TO_INT(intptr_t, __fx_cast_to_ptr_tmp,      \
949                            old_type, old_val);                  \
950         new_val = (void*)__fx_cast_to_ptr_tmp;                  \
951     } while (0)
952 
953 #define FCITX_DEF_CAST_TO_INT(new_type, new_val, old_type, old_val)     \
954     new_type new_val;                                                   \
955     _FCITX_CAST_TO_INT(new_type, new_val, old_type, old_val)
956 
957 #define FCITX_DEF_CAST_TO_PTR(new_val, old_type, old_val)       \
958     void *new_val;                                              \
959     _FCITX_CAST_TO_PTR(new_val, old_type, old_val)
960 
961 #define FCITX_RETURN_AS_INT(new_type, old_type, old_val) do {   \
962         FCITX_DEF_CAST_TO_INT(new_type, __fx_return_as_int_tmp, \
963                               old_type, old_val);               \
964         return __fx_return_as_int_tmp;                          \
965     } while (0)
966 
967 #define FCITX_RETURN_AS_PTR(old_type, old_val) do {     \
968         FCITX_DEF_CAST_TO_PTR(__fx_return_as_ptr_tmp,   \
969                               old_type, old_val);       \
970         return __fx_return_as_ptr_tmp;                  \
971     } while (0)
972 
973 #define __FCITX_DEF_CAST_TO_PTR_FUNC(name, type)        \
974     static inline void*                                 \
975     fcitx_utils_##name##_to_ptr(type value)             \
976     {                                                   \
977         FCITX_RETURN_AS_PTR(type, value);               \
978     }
979 
980     __FCITX_DEF_CAST_TO_PTR_FUNC(float, float)
981     __FCITX_DEF_CAST_TO_PTR_FUNC(int, int)
982     __FCITX_DEF_CAST_TO_PTR_FUNC(intptr, intptr_t)
983     __FCITX_DEF_CAST_TO_PTR_FUNC(int8, int8_t)
984     __FCITX_DEF_CAST_TO_PTR_FUNC(int16, int16_t)
985     __FCITX_DEF_CAST_TO_PTR_FUNC(int32, int32_t)
986     __FCITX_DEF_CAST_TO_PTR_FUNC(ssize, ssize_t)
987     __FCITX_DEF_CAST_TO_PTR_FUNC(uint, unsigned int)
988     __FCITX_DEF_CAST_TO_PTR_FUNC(uintptr, uintptr_t)
989     __FCITX_DEF_CAST_TO_PTR_FUNC(uint8, uint8_t)
990     __FCITX_DEF_CAST_TO_PTR_FUNC(uint16, uint16_t)
991     __FCITX_DEF_CAST_TO_PTR_FUNC(uint32, uint32_t)
992     __FCITX_DEF_CAST_TO_PTR_FUNC(size, size_t)
993     __FCITX_DEF_CAST_TO_PTR_FUNC(constptr, const void*)
994 
995 #define _FCITX_CAST_FROM_INT(new_type, new_val, old_type, old_val) do { \
996         if (sizeof(new_type) <= 1) {                                    \
997             int8_t __fx_cast_from_int_tmp = (int8_t)(old_val);          \
998             __FCITX_BYTE_CAST(new_val, int8_t, __fx_cast_from_int_tmp); \
999         } else if (sizeof(new_type) <= 2) {                             \
1000             int16_t __fx_cast_from_int_tmp = (int16_t)(old_val);        \
1001             __FCITX_BYTE_CAST(new_val, int16_t, __fx_cast_from_int_tmp); \
1002         } else if (sizeof(new_type) <= 4) {                             \
1003             int32_t __fx_cast_from_int_tmp = (int32_t)(old_val);        \
1004             __FCITX_BYTE_CAST(new_val, uint32_t, __fx_cast_from_int_tmp); \
1005         } else {                                                        \
1006             int64_t __fx_cast_from_int_tmp = (int64_t)(old_val);        \
1007             __FCITX_BYTE_CAST(new_val, int64_t, __fx_cast_from_int_tmp); \
1008         }                                                               \
1009     } while (0)
1010 
1011 #define _FCITX_CAST_FROM_PTR(new_type, new_val, p)                      \
1012     _FCITX_CAST_FROM_INT(new_type, new_val, intptr_t, (intptr_t)p)
1013 
1014 #define FCITX_DEF_CAST_FROM_INT(new_type, new_val, old_type, old_val)   \
1015     new_type new_val;                                                   \
1016     _FCITX_CAST_FROM_INT(new_type, new_val, old_type, old_val)
1017 
1018 #define FCITX_DEF_CAST_FROM_PTR(new_type, new_val, p)                   \
1019     FCITX_DEF_CAST_FROM_INT(new_type, new_val, intptr_t, (intptr_t)p)
1020 
1021 #define FCITX_RETURN_FROM_INT(new_type, old_type, old_val) do {         \
1022         FCITX_DEF_CAST_FROM_INT(new_type, __fx_return_from_int_tmp,     \
1023                                 old_type, old_val);                     \
1024         return __fx_return_from_int_tmp;                                \
1025     } while (0)
1026 
1027 #define FCITX_RETURN_FROM_PTR(new_type, old_val) do {                   \
1028         FCITX_DEF_CAST_FROM_PTR(new_type, __fx_return_from_ptr_tmp,     \
1029                                 old_val);                               \
1030         return __fx_return_from_ptr_tmp;                                \
1031     } while (0)
1032 
1033 #define __FCITX_DEF_CAST_FROM_PTR_FUNC(name, type)      \
1034     static inline type                                  \
1035     fcitx_utils_ptr_to_##name(void *value)              \
1036     {                                                   \
1037         FCITX_RETURN_FROM_PTR(type, value);             \
1038     }
1039 
1040     __FCITX_DEF_CAST_FROM_PTR_FUNC(float, float)
1041     __FCITX_DEF_CAST_FROM_PTR_FUNC(int, int)
1042     __FCITX_DEF_CAST_FROM_PTR_FUNC(intptr, intptr_t)
1043     __FCITX_DEF_CAST_FROM_PTR_FUNC(int8, int8_t)
1044     __FCITX_DEF_CAST_FROM_PTR_FUNC(int16, int16_t)
1045     __FCITX_DEF_CAST_FROM_PTR_FUNC(int32, int32_t)
1046     __FCITX_DEF_CAST_FROM_PTR_FUNC(ssize, ssize_t)
1047     __FCITX_DEF_CAST_FROM_PTR_FUNC(uint, unsigned int)
1048     __FCITX_DEF_CAST_FROM_PTR_FUNC(uintptr, uintptr_t)
1049     __FCITX_DEF_CAST_FROM_PTR_FUNC(uint8, uint8_t)
1050     __FCITX_DEF_CAST_FROM_PTR_FUNC(uint16, uint16_t)
1051     __FCITX_DEF_CAST_FROM_PTR_FUNC(uint32, uint32_t)
1052     __FCITX_DEF_CAST_FROM_PTR_FUNC(size, size_t)
1053 
1054 #ifdef __cplusplus
1055 }
1056 #endif
1057 
1058 #endif
1059 
1060 /**
1061  * @}
1062  */
1063 
1064 // kate: indent-mode cstyle; space-indent on; indent-width 0;
1065