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