1 /*
2
3 Copyright (c) 2003-2013 uim Project https://github.com/uim/uim
4
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10
11 1. Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13 2. Redistributions in binary form must reproduce the above copyright
14 notice, this list of conditions and the following disclaimer in the
15 documentation and/or other materials provided with the distribution.
16 3. Neither the name of authors nor the names of its contributors
17 may be used to endorse or promote products derived from this software
18 without specific prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
21 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
24 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 SUCH DAMAGE.
31
32 */
33
34 /*
35 static functions that have uim_custom_ prefix could be exported as API
36 function if needed. -- YamaKen 2004-12-30
37 */
38
39 /*
40 Don't insert NULL checks for free(3). free(3) accepts NULL as proper
41 argument that causes no action. -- YamaKen 2004-12-17
42 */
43
44 #include <config.h>
45
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <unistd.h>
49 #include <stdlib.h>
50 #include <stdio.h>
51 #include <string.h>
52 #include <stdarg.h>
53 #include "gettext.h"
54
55 #include "uim-scm.h"
56 #include "uim-custom.h"
57 #include "uim-internal.h"
58 #include "uim-helper.h"
59
60 #if 0
61 /*
62 * The UIM_CUSTOM_EXPERIMENTAL_MTIME_SENSING is disabled since:
63 *
64 * - file_content_is_same() has a bug which may return invalid result
65 * when the file size is greater than 4095 bytes
66 *
67 * - The codes aim to save custom-groups that some changes are
68 * applied, but it should not be achieved by such violent method
69 * (comparing entire content of saved files). Observing updated
70 * group in uim-custom client program is recommended way
71 *
72 * - It breaks original behavior. See the comment of
73 * custom-reload-user-configs in custom-rt.scm
74 *
75 * -- YamaKen 2005-09-12
76 */
77 #define UIM_CUSTOM_EXPERIMENTAL_MTIME_SENSING
78 #endif
79
80 #define MAX_LENGTH_OF_INT_AS_STR (((sizeof(int) == 4) ? sizeof("-2147483648") : sizeof("-9223372036854775808")) - sizeof((char)'\0'))
81
82 #define UGETTEXT(str) (dgettext(GETTEXT_PACKAGE, (str)))
83
84 /* we cannot use the variadic macro (i.e. __VA_ARGS__) because we
85 should also support C89 compilers
86 */
87 #define UIM_EVAL_STRING_INTERNAL(uc, sexp_str) \
88 (uim_scm_last_val = uim_scm_eval_c_string(sexp_str))
89
90 #define UIM_EVAL_STRING(uc, sexp_str) \
91 { \
92 UIM_EVAL_STRING_INTERNAL(uc, sexp_str); \
93 }
94
95 #define UIM_EVAL_FSTRING1(uc, sexp_tmpl, arg1) \
96 { \
97 int form_size; \
98 char *buf; \
99 form_size = uim_sizeof_sexp_str(sexp_tmpl, arg1); \
100 if (form_size != -1) { \
101 uim_asprintf(&buf, sexp_tmpl, arg1); \
102 UIM_EVAL_STRING_INTERNAL(uc, buf); \
103 free(buf); \
104 } \
105 }
106
107 #define UIM_EVAL_FSTRING2(uc, sexp_tmpl, arg1, arg2) \
108 { \
109 int form_size; \
110 char *buf; \
111 form_size = uim_sizeof_sexp_str(sexp_tmpl, arg1, arg2); \
112 if (form_size != -1) { \
113 uim_asprintf(&buf, sexp_tmpl, arg1, arg2); \
114 UIM_EVAL_STRING_INTERNAL(uc, buf); \
115 free(buf); \
116 } \
117 }
118
119 #define UIM_EVAL_FSTRING3(uc, sexp_tmpl, arg1, arg2, arg3) \
120 { \
121 int form_size; \
122 char *buf; \
123 form_size = uim_sizeof_sexp_str(sexp_tmpl, arg1, arg2, arg3); \
124 if (form_size != -1) { \
125 uim_asprintf(&buf, sexp_tmpl, arg1, arg2, arg3); \
126 UIM_EVAL_STRING_INTERNAL(uc, buf); \
127 free(buf); \
128 } \
129 }
130
131 #define UIM_EVAL_FSTRING4(uc, sexp_tmpl, arg1, arg2, arg3, arg4) \
132 { \
133 int form_size; \
134 char *buf; \
135 form_size = uim_sizeof_sexp_str(sexp_tmpl, arg1, arg2, arg3, arg4); \
136 if (form_size != -1) { \
137 uim_asprintf(&buf, sexp_tmpl, arg1, arg2, arg3, arg4); \
138 UIM_EVAL_STRING_INTERNAL(uc, buf); \
139 free(buf); \
140 } \
141 }
142
143 #define UIM_EVAL_FSTRING5(uc, sexp_tmpl, arg1, arg2, arg3, arg4, arg5) \
144 { \
145 int form_size; \
146 char *buf; \
147 form_size = uim_sizeof_sexp_str(sexp_tmpl, arg1, arg2, arg3, arg4, arg5); \
148 if (form_size != -1) { \
149 uim_asprintf(&buf, sexp_tmpl, arg1, arg2, arg3, arg4, arg5); \
150 UIM_EVAL_STRING_INTERNAL(uc, buf); \
151 free(buf); \
152 } \
153 }
154
155 typedef void (*uim_custom_cb_update_cb_t)(void *ptr, const char *custom_sym);
156 typedef void (*uim_custom_global_cb_update_cb_t)(void *ptr);
157
158 typedef void *(*uim_scm_c_list_conv_func)(uim_lisp elem);
159 typedef void (*uim_scm_c_list_free_func)(void *elem);
160
161 /* exported for internal use */
162 uim_bool uim_custom_init(void);
163 uim_bool uim_custom_quit(void);
164
165 /* uim_scm_return_value() can only be used to retrieve result of
166 * UIM_EVAL_FSTRINGn() or UIM_EVAL_STRING(). */
167 static uim_lisp uim_scm_return_value(void);
168 static int uim_sizeof_sexp_str(const char *tmpl, ...);
169
170 static void **uim_scm_c_list(const char *list_repl, const char *mapper_proc,
171 uim_scm_c_list_conv_func conv_func);
172 static char *uim_scm_c_str_failsafe(uim_lisp str);
173 static char **uim_scm_c_str_list(const char *list_repl,
174 const char *mapper_proc);
175 static void uim_scm_c_list_free(void **list,
176 uim_scm_c_list_free_func free_func);
177
178 static char *literalize_string(const char *str);
179 static char *literalize_string_internal(const char *str);
180
181 static char *c_list_to_str(const void *const *list, char *(*mapper)(const void *elem), const char *sep);
182
183 static int uim_custom_type_eq(const char *custom_sym, const char *custom_type);
184 static int uim_custom_type(const char *custom_sym);
185 static int uim_custom_is_active(const char *custom_sym);
186 static const char *uim_custom_get_str(const char *custom_sym,
187 const char *proc);
188 static char *uim_custom_label(const char *custom_sym);
189 static char *uim_custom_desc(const char *custom_sym);
190
191 static struct uim_custom_pathname *uim_custom_pathname_get(const char *custom_sym, const char *getter_proc);
192 static struct uim_custom_pathname *uim_custom_pathname_new(char *str, int type);
193 static void uim_custom_pathname_free(struct uim_custom_pathname *custom_pathname);
194 static struct uim_custom_choice *uim_custom_choice_get(const char *custom_sym, const char *choice_sym);
195 static char *extract_choice_symbol(const struct uim_custom_choice *custom_choice);
196 static char *choice_list_to_str(const struct uim_custom_choice *const *list, const char *sep);
197 static void uim_custom_choice_free(struct uim_custom_choice *custom_choice);
198 static struct uim_custom_choice **extract_choice_list(const char *list_repl, const char *custom_sym);
199 static struct uim_custom_choice **uim_custom_choice_item_list(const char *custom_sym);
200
201 static struct uim_custom_choice **uim_custom_olist_get(const char *custom_sym, const char *getter_proc);
202 static struct uim_custom_choice **uim_custom_olist_item_list(const char *custom_sym);
203
204 static struct uim_custom_key **uim_custom_key_get(const char *custom_sym, const char *getter_proc);
205 static void uim_custom_key_free(struct uim_custom_key *custom_key);
206 static char *extract_key_literal(const struct uim_custom_key *custom_key);
207 static char *key_list_to_str(const struct uim_custom_key *const *list, const char *sep);
208
209 static char ***uim_custom_table_get(const char *custom_sym, const char *getter_proc);
210 static char *literalized_strdup(const char *str);
211 static char *row_list_to_str(const char *const *list);
212 static char *table_to_str(const char** const *list, const char *sep);
213 static struct uim_custom_choice **uim_custom_table_header_item_list(const char *custom_sym);
214
215
216 static union uim_custom_value *uim_custom_value_internal(const char *custom_sym, const char *getter_proc);
217 static union uim_custom_value *uim_custom_value(const char *custom_sym);
218 static union uim_custom_value *uim_custom_default_value(const char *custom_sym);
219 static void uim_custom_value_free(int custom_type, union uim_custom_value *custom_value);
220 static uim_lisp uim_custom_range_elem(const char *custom_sym, const char *accessor_proc);
221 static union uim_custom_range *uim_custom_range_get(const char *custom_sym);
222 static void uim_custom_range_free(int custom_type, union uim_custom_range *custom_range);
223 static uim_lisp uim_custom_cb_update_cb_gate(uim_lisp cb, uim_lisp ptr, uim_lisp custom_sym);
224 static uim_lisp uim_custom_global_cb_update_cb_gate(uim_lisp cb, uim_lisp ptr);
225 static uim_bool custom_cb_remove(const char *key_sym, const char *hook);
226 static uim_bool custom_cb_add(const char *hook, const char *validator,
227 const char *custom_sym, void *ptr,
228 const char *gate_func, void (*cb)(void));
229 struct custom_cb_add_args {
230 const char *hook;
231 const char *validator;
232 const char *custom_sym;
233 void *ptr;
234 const char *gate_func;
235 void (*cb)(void);
236 };
237 static void *custom_cb_add_internal(struct custom_cb_add_args *args);
238
239 static void helper_disconnect_cb(void);
240 static char *uim_conf_path(const char *subpath);
241 static char *custom_file_path(const char *group, pid_t pid);
242 static uim_bool prepare_dir(const char *dir);
243 static uim_bool uim_conf_prepare_dir(const char *subdir);
244 static uim_bool for_each_primary_groups(uim_bool (*func)(const char *));
245 static uim_bool uim_custom_load_group(const char *group);
246 static uim_bool uim_custom_save_group(const char *group);
247 static const char *uim_custom_get_primary_group_by_custom(const char *custom_sym);
248
249 static const char str_list_arg[] = "uim-custom-c-str-list-arg";
250 static const char custom_subdir[] = "customs";
251 static const char custom_msg_tmpl[] = "prop_update_custom\n%s\n%s\n";
252 static int helper_fd = -1;
253 static uim_lisp return_val;
254 static uim_lisp uim_scm_last_val;
255
256
257 static uim_lisp
uim_scm_return_value(void)258 uim_scm_return_value(void)
259 {
260 return uim_scm_last_val;
261 }
262
263 /** Calculate actual sexp string size from printf-style args.
264 * This function calculates actual sexp string size from printf-style
265 * args. Format string \a sexp_tmpl only accepts %d and %s.
266 */
267 int
uim_sizeof_sexp_str(const char * sexp_tmpl,...)268 uim_sizeof_sexp_str(const char *sexp_tmpl, ...)
269 {
270 va_list ap;
271 int len, size;
272 int tmp;
273 const char *sexp_tmpl_end, *escp = sexp_tmpl, *strarg;
274 char fmtchr;
275
276 va_start(ap, sexp_tmpl);
277 len = strlen(sexp_tmpl);
278 sexp_tmpl_end = sexp_tmpl + len - 1;
279 while ((escp = strchr(escp, '%'))) {
280 if (escp < sexp_tmpl_end) {
281 escp += sizeof((char)'%');
282 fmtchr = *escp++;
283 switch (fmtchr) {
284 case 'd':
285 tmp = va_arg(ap, int);
286 len += MAX_LENGTH_OF_INT_AS_STR;
287 break;
288 case 's':
289 strarg = va_arg(ap, const char *);
290 len += strlen(strarg);
291 break;
292 default:
293 /* unexpected format string */
294 size = -1;
295 goto end;
296 }
297 } else {
298 /* invalid format string */
299 size = -1;
300 goto end;
301 }
302 }
303 size = len + sizeof((char)'\0');
304
305 end:
306 va_end(ap);
307
308 return size;
309 }
310
311 /*
312 - list_repl must always returns same list for each evaluation
313 - returns NULL terminated array. NULL will not appeared except terminator
314 - non-string element such as #f is converted to ""
315 */
316 static void **
uim_scm_c_list(const char * list_repl,const char * mapper_proc,uim_scm_c_list_conv_func conv_func)317 uim_scm_c_list(const char *list_repl, const char *mapper_proc,
318 uim_scm_c_list_conv_func conv_func)
319 {
320 int list_len, i;
321 void **result;
322
323 UIM_EVAL_FSTRING1(NULL, "(length %s)", list_repl);
324 list_len = uim_scm_c_int(uim_scm_return_value());
325
326 result = (void **)malloc(sizeof(void *) * (list_len + 1));
327 if (!result)
328 return NULL;
329
330 result[list_len] = NULL;
331 for (i = 0; i < list_len; i++) {
332 UIM_EVAL_FSTRING3(NULL, "(%s (nth %d %s))", mapper_proc, i, list_repl);
333 result[i] = (*conv_func)(uim_scm_return_value());
334 }
335
336 return result;
337 }
338
339 static char *
uim_scm_c_str_failsafe(uim_lisp str)340 uim_scm_c_str_failsafe(uim_lisp str)
341 {
342 return (uim_scm_truep(str)) ? uim_scm_c_str(str) : strdup("");
343 }
344
345 static char **
uim_scm_c_str_list(const char * list_repl,const char * mapper_proc)346 uim_scm_c_str_list(const char *list_repl, const char *mapper_proc)
347 {
348 void **list;
349
350 list = uim_scm_c_list(list_repl, mapper_proc,
351 (uim_scm_c_list_conv_func)uim_scm_c_str_failsafe);
352
353 return (char **)list;
354 }
355
356 static void
uim_scm_c_list_free(void ** list,uim_scm_c_list_free_func free_func)357 uim_scm_c_list_free(void **list, uim_scm_c_list_free_func free_func)
358 {
359 void *elem;
360 void **p;
361
362 if (!list)
363 return;
364
365 for (p = list; *p; p++) {
366 elem = *p;
367 free_func(elem);
368 }
369 free(list);
370 }
371
372 static char *
literalize_string(const char * str)373 literalize_string(const char *str)
374 {
375 return uim_scm_call_with_gc_ready_stack((uim_gc_gate_func_ptr)literalize_string_internal, (void *)str);
376 }
377
378 static char *
literalize_string_internal(const char * str)379 literalize_string_internal(const char *str)
380 {
381 uim_lisp form;
382 char *escaped;
383
384 form = uim_scm_list2(uim_scm_make_symbol("string-escape"),
385 uim_scm_make_str(str));
386 escaped = uim_scm_c_str(uim_scm_eval(form));
387
388 return escaped;
389 }
390
391 static char *
c_list_to_str(const void * const * list,char * (* mapper)(const void * elem),const char * sep)392 c_list_to_str(const void *const *list, char *(*mapper)(const void *elem), const char *sep)
393 {
394 size_t buf_size;
395 char *buf, *bufp, *str;
396 const void *const *elem;
397
398 buf_size = sizeof(char);
399 for (elem = list; *elem; elem++) {
400 if (elem != list)
401 buf_size += strlen(sep);
402 str = (*mapper)(*elem);
403 buf_size += strlen(str);
404 free(str);
405 }
406 buf = (char *)malloc(buf_size);
407 buf[0] = '\0';
408
409 for (bufp = buf, elem = list; *elem; elem++) {
410 if (elem != list) {
411 strlcat(buf, sep, buf_size);
412 bufp += strlen(sep);
413 }
414 str = (*mapper)(*elem);
415 strlcat(buf, str, buf_size);
416 bufp += strlen(str);
417 free(str);
418 }
419
420 return buf;
421 }
422
423 static int
uim_custom_type_eq(const char * custom_sym,const char * custom_type)424 uim_custom_type_eq(const char *custom_sym, const char *custom_type)
425 {
426 UIM_EVAL_FSTRING2(NULL, "(eq? (custom-type '%s) '%s)",
427 custom_sym, custom_type);
428
429 return uim_scm_c_bool(uim_scm_return_value());
430 }
431
432 static int
uim_custom_type(const char * custom_sym)433 uim_custom_type(const char *custom_sym)
434 {
435 if (uim_custom_type_eq(custom_sym, "boolean")) {
436 return UCustom_Bool;
437 } else if (uim_custom_type_eq(custom_sym, "integer")) {
438 return UCustom_Int;
439 } else if (uim_custom_type_eq(custom_sym, "string")) {
440 return UCustom_Str;
441 } else if (uim_custom_type_eq(custom_sym, "pathname")) {
442 return UCustom_Pathname;
443 } else if (uim_custom_type_eq(custom_sym, "choice")) {
444 return UCustom_Choice;
445 } else if (uim_custom_type_eq(custom_sym, "ordered-list")) {
446 return UCustom_OrderedList;
447 } else if (uim_custom_type_eq(custom_sym, "key")) {
448 return UCustom_Key;
449 } else if (uim_custom_type_eq(custom_sym, "table")) {
450 return UCustom_Table;
451 } else {
452 return UCustom_Bool;
453 }
454 }
455
456 static int
uim_custom_is_active(const char * custom_sym)457 uim_custom_is_active(const char *custom_sym)
458 {
459 UIM_EVAL_FSTRING1(NULL, "(custom-active? '%s)", custom_sym);
460 return_val = uim_scm_return_value();
461
462 return uim_scm_c_bool(return_val);
463 }
464
465 static const char *
uim_custom_get_str(const char * custom_sym,const char * proc)466 uim_custom_get_str(const char *custom_sym, const char *proc)
467 {
468 UIM_EVAL_FSTRING2(NULL, "(%s '%s)", proc, custom_sym);
469 return_val = uim_scm_return_value();
470
471 return uim_scm_refer_c_str(return_val);
472 }
473
474 static char *
uim_custom_label(const char * custom_sym)475 uim_custom_label(const char *custom_sym)
476 {
477 const char *str;
478
479 str = uim_custom_get_str(custom_sym, "custom-label");
480 return strdup(UGETTEXT(str));
481 }
482
483 static char *
uim_custom_desc(const char * custom_sym)484 uim_custom_desc(const char *custom_sym)
485 {
486 const char *str;
487
488 str = uim_custom_get_str(custom_sym, "custom-desc");
489 return strdup(UGETTEXT(str));
490 }
491
492 /* pathname */
493 static struct uim_custom_pathname *
uim_custom_pathname_get(const char * custom_sym,const char * getter_proc)494 uim_custom_pathname_get(const char *custom_sym, const char *getter_proc)
495 {
496 struct uim_custom_pathname *custom_pathname;
497 char *str, *type_sym;
498 int type;
499
500 UIM_EVAL_FSTRING2(NULL, "(%s '%s)", getter_proc, custom_sym);
501 return_val = uim_scm_return_value();
502 str = uim_scm_c_str(return_val);
503
504 UIM_EVAL_FSTRING1(NULL, "(custom-pathname-type '%s)", custom_sym);
505 return_val = uim_scm_return_value();
506 type_sym = uim_scm_c_symbol(return_val);
507 if (strcmp(type_sym, "directory") == 0)
508 type = UCustomPathnameType_Directory;
509 else
510 type = UCustomPathnameType_RegularFile;
511 free(type_sym);
512
513 custom_pathname = uim_custom_pathname_new(str, type);
514 if (!custom_pathname)
515 return NULL;
516
517 return custom_pathname;
518 }
519
520 static struct uim_custom_pathname *
uim_custom_pathname_new(char * str,int type)521 uim_custom_pathname_new(char *str, int type)
522 {
523 struct uim_custom_pathname *custom_pathname;
524
525 custom_pathname = malloc(sizeof(struct uim_custom_pathname));
526 if (!custom_pathname)
527 return NULL;
528
529 custom_pathname->str = str;
530 custom_pathname->type = type;
531
532 return custom_pathname;
533 }
534
535 static void
uim_custom_pathname_free(struct uim_custom_pathname * custom_pathname)536 uim_custom_pathname_free(struct uim_custom_pathname *custom_pathname)
537 {
538 if (!custom_pathname)
539 return;
540
541 free(custom_pathname->str);
542 }
543
544 /* choice */
545 static struct uim_custom_choice *
uim_custom_choice_get(const char * custom_sym,const char * choice_sym)546 uim_custom_choice_get(const char *custom_sym, const char *choice_sym)
547 {
548 struct uim_custom_choice *c_choice;
549
550 c_choice = uim_custom_choice_new(NULL, NULL, NULL);
551 if (!c_choice)
552 return NULL;
553
554 c_choice->symbol = strdup(choice_sym);
555
556 UIM_EVAL_FSTRING2(NULL, "(custom-choice-label '%s '%s)",
557 custom_sym, choice_sym);
558 return_val = uim_scm_return_value();
559 c_choice->label = strdup(UGETTEXT(uim_scm_refer_c_str(return_val)));
560
561 UIM_EVAL_FSTRING2(NULL, "(custom-choice-desc '%s '%s)",
562 custom_sym, choice_sym);
563 return_val = uim_scm_return_value();
564 c_choice->desc = strdup(UGETTEXT(uim_scm_refer_c_str(return_val)));
565
566 return c_choice;
567 }
568
569 /**
570 * TODO
571 */
572 struct uim_custom_choice *
uim_custom_choice_new(char * symbol,char * label,char * desc)573 uim_custom_choice_new(char *symbol, char *label, char *desc)
574 {
575 struct uim_custom_choice *custom_choice;
576
577 custom_choice = (struct uim_custom_choice *)malloc(sizeof(struct uim_custom_choice));
578 if (!custom_choice)
579 return NULL;
580
581 custom_choice->symbol = symbol;
582 custom_choice->label = label;
583 custom_choice->desc = desc;
584
585 return custom_choice;
586 }
587
588 static void
uim_custom_choice_free(struct uim_custom_choice * custom_choice)589 uim_custom_choice_free(struct uim_custom_choice *custom_choice)
590 {
591 if (!custom_choice)
592 return;
593
594 free(custom_choice->symbol);
595 free(custom_choice->label);
596 free(custom_choice->desc);
597 free(custom_choice);
598 }
599
600 static struct uim_custom_choice **
extract_choice_list(const char * list_repl,const char * custom_sym)601 extract_choice_list(const char *list_repl, const char *custom_sym)
602 {
603 char *choice_sym, **choice_sym_list, **p;
604 struct uim_custom_choice *custom_choice, **custom_choice_list;
605
606 choice_sym_list =
607 (char **)uim_scm_c_list(list_repl, "symbol->string",
608 (uim_scm_c_list_conv_func)uim_scm_c_str);
609 if (!choice_sym_list)
610 return NULL;
611
612 for (p = choice_sym_list; *p; p++) {
613 choice_sym = *p;
614 custom_choice = uim_custom_choice_get(custom_sym, choice_sym);
615 free(choice_sym); /* free the old contents */
616 *p = (char *)custom_choice; /* intentionally overwrite */
617 }
618
619 /* reuse the list structure */
620 custom_choice_list = (struct uim_custom_choice **)choice_sym_list;
621
622 return custom_choice_list;
623 }
624
625 static struct uim_custom_choice **
uim_custom_choice_item_list(const char * custom_sym)626 uim_custom_choice_item_list(const char *custom_sym)
627 {
628 UIM_EVAL_FSTRING2(NULL, "(define %s (custom-range '%s))",
629 str_list_arg, custom_sym);
630 return extract_choice_list(str_list_arg, custom_sym);
631 }
632
633 static char *
extract_choice_symbol(const struct uim_custom_choice * custom_choice)634 extract_choice_symbol(const struct uim_custom_choice *custom_choice)
635 {
636 return strdup(custom_choice->symbol);
637 }
638
639 static char *
choice_list_to_str(const struct uim_custom_choice * const * list,const char * sep)640 choice_list_to_str(const struct uim_custom_choice *const *list, const char *sep)
641 {
642 return c_list_to_str((const void *const *)list,
643 (char *(*)(const void *))extract_choice_symbol, sep);
644 }
645
646 /**
647 * TODO
648 */
649 void
uim_custom_choice_list_free(struct uim_custom_choice ** list)650 uim_custom_choice_list_free(struct uim_custom_choice **list)
651 {
652 uim_scm_c_list_free((void **)list,
653 (uim_scm_c_list_free_func)uim_custom_choice_free);
654 }
655
656 /* ordered list */
657 static struct uim_custom_choice **
uim_custom_olist_get(const char * custom_sym,const char * getter_proc)658 uim_custom_olist_get(const char *custom_sym, const char *getter_proc)
659 {
660 UIM_EVAL_FSTRING3(NULL, "(define %s (%s '%s))",
661 str_list_arg, getter_proc, custom_sym);
662 return extract_choice_list(str_list_arg, custom_sym);
663 }
664
665 static struct uim_custom_choice **
uim_custom_olist_item_list(const char * custom_sym)666 uim_custom_olist_item_list(const char *custom_sym)
667 {
668 return uim_custom_choice_item_list(custom_sym);
669 }
670
671 /* key */
672 static struct uim_custom_key **
uim_custom_key_get(const char * custom_sym,const char * getter_proc)673 uim_custom_key_get(const char *custom_sym, const char *getter_proc)
674 {
675 char **key_literal_list, **key_label_list, **key_desc_list;
676 int *key_type_list, editor_type, list_len, i;
677 struct uim_custom_key *custom_key, **custom_key_list;
678
679 UIM_EVAL_FSTRING3(NULL, "(define %s ((if uim-custom-expand-key? custom-expand-key-references (lambda (l) l)) (%s '%s)))",
680 str_list_arg, getter_proc, custom_sym);
681 key_literal_list =
682 (char **)uim_scm_c_list(str_list_arg,
683 "(lambda (key) (if (symbol? key) (symbol->string key) key))",
684 (uim_scm_c_list_conv_func)uim_scm_c_str);
685 key_type_list =
686 (int *)uim_scm_c_list(str_list_arg,
687 "(lambda (key) (if (symbol? key) 1 0))",
688 (uim_scm_c_list_conv_func)uim_scm_c_int);
689 key_label_list =
690 (char **)uim_scm_c_list(str_list_arg,
691 "(lambda (key) (if (symbol? key) (custom-label key) #f))",
692 (uim_scm_c_list_conv_func)uim_scm_c_str_failsafe);
693 key_desc_list =
694 (char **)uim_scm_c_list(str_list_arg,
695 "(lambda (key) (if (symbol? key) (custom-desc key) #f))",
696 (uim_scm_c_list_conv_func)uim_scm_c_str_failsafe);
697 if (!key_type_list || !key_literal_list || !key_label_list || !key_desc_list)
698 {
699 free(key_type_list);
700 uim_custom_symbol_list_free(key_literal_list);
701 uim_custom_symbol_list_free(key_label_list);
702 uim_custom_symbol_list_free(key_desc_list);
703 return NULL;
704 }
705
706 UIM_EVAL_FSTRING1(NULL, "(custom-key-advanced-editor? '%s)", custom_sym);
707 return_val = uim_scm_return_value();
708 editor_type = uim_scm_c_bool(return_val) ? UCustomKeyEditor_Advanced : UCustomKeyEditor_Basic;
709
710 UIM_EVAL_FSTRING1(NULL, "(length %s)", str_list_arg);
711 return_val = uim_scm_return_value();
712 list_len = uim_scm_c_int(return_val);
713
714 for (i = 0; i < list_len; i++) {
715 char *literal, *label, *desc;
716 int type;
717 type = (key_type_list[i] == 1) ? UCustomKey_Reference : UCustomKey_Regular;
718 literal = key_literal_list[i];
719 label = key_label_list[i];
720 desc = key_desc_list[i];
721 custom_key = uim_custom_key_new(type, editor_type, literal, label, desc);
722 key_literal_list[i] = (char *)custom_key; /* intentionally overwrite */
723 }
724 /* reuse the list structure */
725 custom_key_list = (struct uim_custom_key **)key_literal_list;
726
727 /* ownership of elements had been transferred to custom_key_list */
728 free(key_type_list);
729 free(key_label_list);
730 free(key_desc_list);
731
732 return custom_key_list;
733 }
734
735 /**
736 * TODO
737 */
738 struct uim_custom_key *
uim_custom_key_new(int type,int editor_type,char * literal,char * label,char * desc)739 uim_custom_key_new(int type, int editor_type,
740 char *literal, char *label, char *desc)
741 {
742 struct uim_custom_key *custom_key;
743
744 custom_key = (struct uim_custom_key *)malloc(sizeof(struct uim_custom_key));
745 if (!custom_key)
746 return NULL;
747
748 custom_key->type = type;
749 custom_key->editor_type = editor_type;
750 custom_key->literal = literal;
751 custom_key->label = label;
752 custom_key->desc = desc;
753
754 return custom_key;
755 }
756
757 static void
uim_custom_key_free(struct uim_custom_key * custom_key)758 uim_custom_key_free(struct uim_custom_key *custom_key)
759 {
760 if (!custom_key)
761 return;
762
763 free(custom_key->literal);
764 free(custom_key->label);
765 free(custom_key->desc);
766 free(custom_key);
767 }
768
769 static char *
extract_key_literal(const struct uim_custom_key * custom_key)770 extract_key_literal(const struct uim_custom_key *custom_key)
771 {
772 char *literal;
773
774 switch (custom_key->type) {
775 case UCustomKey_Regular:
776 literal = literalize_string(custom_key->literal);
777 break;
778 case UCustomKey_Reference:
779 literal = strdup(custom_key->literal);
780 break;
781 default:
782 literal = strdup("\"\"");
783 }
784
785 return literal;
786 }
787
788 static char *
key_list_to_str(const struct uim_custom_key * const * list,const char * sep)789 key_list_to_str(const struct uim_custom_key *const *list, const char *sep)
790 {
791 return c_list_to_str((const void *const *)list,
792 (char *(*)(const void *))extract_key_literal, sep);
793 }
794
795 /**
796 * TODO
797 */
798 void
uim_custom_key_list_free(struct uim_custom_key ** list)799 uim_custom_key_list_free(struct uim_custom_key **list)
800 {
801 uim_scm_c_list_free((void **)list,
802 (uim_scm_c_list_free_func)uim_custom_key_free);
803 }
804
805 /* table */
806 static char ***
uim_custom_table_get(const char * custom_sym,const char * getter_proc)807 uim_custom_table_get(const char *custom_sym, const char *getter_proc)
808 {
809 char ***custom_table;
810 int row_count;
811 int row;
812
813 UIM_EVAL_FSTRING1(NULL, "(length %s)", custom_sym);
814 row_count = uim_scm_c_int(uim_scm_return_value());
815
816 custom_table = (char ***)malloc(sizeof(char **) * (row_count + 1));
817 if (!custom_table)
818 return NULL;
819
820 custom_table[row_count] = NULL;
821 for (row = 0; row < row_count; row++) {
822 int column_count;
823 int column;
824 UIM_EVAL_FSTRING2(NULL, "(length (nth %d %s))", row, custom_sym);
825 column_count = uim_scm_c_int(uim_scm_return_value());
826
827 custom_table[row] = (char **)malloc(sizeof(char *) * (column_count + 1));
828 if (!custom_table[row])
829 return NULL;
830 custom_table[row][column_count] = NULL;
831 for (column = 0; column < column_count; column++) {
832 char *str;
833 UIM_EVAL_FSTRING3(NULL, "(nth %d (nth %d %s))", column, row, custom_sym);
834 str = uim_scm_c_str(uim_scm_return_value());
835 if (!str)
836 return NULL;
837 custom_table[row][column] = malloc(sizeof(char) * (strlen(str) + 1));
838 if (!custom_table[row][column])
839 return NULL;
840 custom_table[row][column] = str;
841 }
842 }
843
844 return custom_table;
845 }
846
847 static char *
literalized_strdup(const char * str)848 literalized_strdup(const char *str)
849 {
850 return strdup(literalize_string(str));
851 }
852
853 static char *
row_list_to_str(const char * const * list)854 row_list_to_str(const char *const *list)
855 {
856 return c_list_to_str((const void *const *)list,
857 (char *(*)(const void *))literalized_strdup, " ");
858 }
859
860 static char *
table_to_str(const char ** const * list,const char * sep)861 table_to_str(const char** const *list, const char *sep)
862 {
863 return c_list_to_str((const void *const *)list,
864 (char *(*)(const void *))row_list_to_str, sep);
865 }
866
867 static struct uim_custom_choice **
uim_custom_table_header_item_list(const char * custom_sym)868 uim_custom_table_header_item_list(const char *custom_sym)
869 {
870 return uim_custom_choice_item_list(custom_sym);
871 }
872
873 static union uim_custom_value *
uim_custom_value_internal(const char * custom_sym,const char * getter_proc)874 uim_custom_value_internal(const char *custom_sym, const char *getter_proc)
875 {
876 int type;
877 union uim_custom_value *value;
878 char *custom_value_symbol;
879
880 if (!custom_sym || !getter_proc)
881 return NULL;
882
883 value = (union uim_custom_value *)malloc(sizeof(union uim_custom_value));
884 if (!value)
885 return NULL;
886
887 type = uim_custom_type(custom_sym);
888 UIM_EVAL_FSTRING2(NULL, "(%s '%s)", getter_proc, custom_sym);
889 return_val = uim_scm_return_value();
890 switch (type) {
891 case UCustom_Bool:
892 value->as_bool = uim_scm_c_bool(return_val);
893 break;
894 case UCustom_Int:
895 value->as_int = uim_scm_c_int(return_val);
896 break;
897 case UCustom_Str:
898 value->as_str = uim_scm_c_str(return_val);
899 break;
900 case UCustom_Pathname:
901 value->as_pathname = uim_custom_pathname_get(custom_sym, getter_proc);
902 break;
903 case UCustom_Choice:
904 custom_value_symbol = uim_scm_c_symbol(return_val);
905 value->as_choice = uim_custom_choice_get(custom_sym, custom_value_symbol);
906 free(custom_value_symbol);
907 break;
908 case UCustom_OrderedList:
909 value->as_olist = uim_custom_olist_get(custom_sym, getter_proc);
910 break;
911 case UCustom_Key:
912 value->as_key = uim_custom_key_get(custom_sym, getter_proc);
913 break;
914 case UCustom_Table:
915 value->as_table = uim_custom_table_get(custom_sym, getter_proc);
916 break;
917 default:
918 free(value);
919 value = NULL;
920 }
921
922 return value;
923 }
924
925 static union uim_custom_value *
uim_custom_value(const char * custom_sym)926 uim_custom_value(const char *custom_sym)
927 {
928 return uim_custom_value_internal(custom_sym, "custom-value");
929 }
930
931 static union uim_custom_value *
uim_custom_default_value(const char * custom_sym)932 uim_custom_default_value(const char *custom_sym)
933 {
934 return uim_custom_value_internal(custom_sym, "custom-default-value");
935 }
936
937 static void
uim_custom_value_free(int custom_type,union uim_custom_value * custom_value)938 uim_custom_value_free(int custom_type, union uim_custom_value *custom_value)
939 {
940 if (!custom_value)
941 return;
942
943 switch (custom_type) {
944 case UCustom_Str:
945 free(custom_value->as_str);
946 break;
947 case UCustom_Pathname:
948 uim_custom_pathname_free(custom_value->as_pathname);
949 break;
950 case UCustom_Choice:
951 uim_custom_choice_free(custom_value->as_choice);
952 break;
953 case UCustom_OrderedList:
954 uim_custom_choice_list_free(custom_value->as_olist);
955 break;
956 case UCustom_Key:
957 uim_custom_key_list_free(custom_value->as_key);
958 break;
959 }
960 free(custom_value);
961 }
962
963 /*
964 The arg must be assigned to return_val by caller to be proteced
965 from GC while subsequent evaluation
966 */
967 static uim_lisp
uim_custom_range_elem(const char * custom_sym,const char * accessor_proc)968 uim_custom_range_elem(const char *custom_sym, const char *accessor_proc)
969 {
970 UIM_EVAL_FSTRING2(NULL, "(%s (custom-range '%s))",
971 accessor_proc, custom_sym);
972
973 return uim_scm_return_value();
974 }
975
976 static union uim_custom_range *
uim_custom_range_get(const char * custom_sym)977 uim_custom_range_get(const char *custom_sym)
978 {
979 int type;
980 union uim_custom_range *range;
981
982 range = (union uim_custom_range *)malloc(sizeof(union uim_custom_range));
983 if (!range)
984 return NULL;
985
986 type = uim_custom_type(custom_sym);
987 switch (type) {
988 case UCustom_Int:
989 return_val = uim_custom_range_elem(custom_sym, "car");
990 range->as_int.min = uim_scm_c_int(return_val);
991 return_val = uim_custom_range_elem(custom_sym, "cadr");
992 range->as_int.max = uim_scm_c_int(return_val);
993 break;
994 case UCustom_Str:
995 return_val = uim_custom_range_elem(custom_sym, "car");
996 range->as_str.regex = uim_scm_c_str(return_val);
997 break;
998 case UCustom_Choice:
999 range->as_choice.valid_items = uim_custom_choice_item_list(custom_sym);
1000 break;
1001 case UCustom_OrderedList:
1002 range->as_olist.valid_items = uim_custom_olist_item_list(custom_sym);
1003 break;
1004 case UCustom_Table:
1005 range->as_table_header.valid_items
1006 = uim_custom_table_header_item_list(custom_sym);
1007 break;
1008 }
1009
1010 return range;
1011 }
1012
1013 static void
uim_custom_range_free(int custom_type,union uim_custom_range * custom_range)1014 uim_custom_range_free(int custom_type, union uim_custom_range *custom_range)
1015 {
1016 if (!custom_range)
1017 return;
1018
1019 switch (custom_type) {
1020 case UCustom_Str:
1021 free(custom_range->as_str.regex);
1022 break;
1023 case UCustom_Choice:
1024 uim_custom_choice_list_free(custom_range->as_choice.valid_items);
1025 break;
1026 case UCustom_OrderedList:
1027 uim_custom_choice_list_free(custom_range->as_olist.valid_items);
1028 break;
1029 }
1030 free(custom_range);
1031 }
1032
1033 static void
helper_disconnect_cb(void)1034 helper_disconnect_cb(void)
1035 {
1036 helper_fd = -1;
1037 }
1038
1039 /**
1040 * Enables use of custom API. This function must be called before
1041 * uim_custom_*() functions are called. uim_init() must be called before this
1042 * function.
1043 *
1044 * @see uim_init()
1045 * @retval UIM_TRUE succeeded
1046 * @retval UIM_FALSE failed
1047 */
1048 uim_bool
uim_custom_enable(void)1049 uim_custom_enable(void)
1050 {
1051 UIM_EVAL_STRING(NULL, "(require-dynlib \"custom-enabler\")");
1052 return uim_scm_c_bool(uim_scm_return_value());
1053 }
1054
1055 /*
1056 * This function is exported as internal use. Intentionally disdocumented.
1057 *
1058 * Initializes custom API. This function must be called before uim_custom_*()
1059 * functions are called. uim_init() must be called before this function.
1060 *
1061 * @see uim_init()
1062 * @retval UIM_TRUE succeeded
1063 * @retval UIM_FALSE failed
1064 */
1065 uim_bool
uim_custom_init(void)1066 uim_custom_init(void)
1067 {
1068 const char *client_codeset;
1069
1070 return_val = uim_scm_f();
1071 uim_scm_last_val = uim_scm_f();
1072 uim_scm_gc_protect(&return_val);
1073 uim_scm_gc_protect(&uim_scm_last_val);
1074
1075 uim_scm_init_proc3("custom-update-cb-gate", uim_custom_cb_update_cb_gate);
1076 uim_scm_init_proc2("custom-global-update-cb-gate",
1077 uim_custom_global_cb_update_cb_gate);
1078
1079 uim_scm_require_file("custom.scm");
1080
1081 /* temporary solution to control key definition expantion */
1082 UIM_EVAL_STRING(NULL, "(define uim-custom-expand-key? #t)");
1083
1084 /* Assumes that bind_textdomain_codeset() is already called in client
1085 * program. */
1086 client_codeset = bind_textdomain_codeset(textdomain(NULL), NULL);
1087 bind_textdomain_codeset(GETTEXT_PACKAGE, client_codeset);
1088
1089 return UIM_TRUE;
1090 }
1091
1092 /*
1093 * This function is exported as internal use. Intentionally disdocumented.
1094 *
1095 * Finalizes custom API. This function must be called before uim_quit().
1096 *
1097 * @see uim_quit()
1098 * @retval UIM_TRUE succeeded
1099 * @retval UIM_FALSE failed
1100 */
1101 uim_bool
uim_custom_quit(void)1102 uim_custom_quit(void)
1103 {
1104 uim_custom_cb_remove(NULL);
1105 uim_custom_group_cb_remove(NULL);
1106 uim_custom_global_cb_remove();
1107
1108 return UIM_TRUE;
1109 }
1110
1111 static char *
uim_conf_path(const char * subpath)1112 uim_conf_path(const char *subpath)
1113 {
1114 char *dir;
1115
1116 UIM_EVAL_STRING(NULL, "(string-append (or (home-directory (user-name)) \"\") \"/.uim.d\")");
1117 dir = uim_scm_c_str(uim_scm_return_value());
1118 if (subpath) {
1119 UIM_EVAL_FSTRING2(NULL, "\"%s/%s\"", dir, subpath);
1120 free(dir);
1121 dir = uim_scm_c_str(uim_scm_return_value());
1122 }
1123
1124 return dir;
1125 }
1126
1127 static char *
custom_file_path(const char * group,pid_t pid)1128 custom_file_path(const char *group, pid_t pid)
1129 {
1130 char *custom_dir, *file_path;
1131
1132 custom_dir = uim_conf_path(custom_subdir);
1133 if (pid) {
1134 UIM_EVAL_FSTRING3(NULL, "\"%s/.custom-%s.scm.%d\"", custom_dir, group, (int)pid);
1135 } else {
1136 UIM_EVAL_FSTRING2(NULL, "\"%s/custom-%s.scm\"", custom_dir, group);
1137 }
1138 file_path = uim_scm_c_str(uim_scm_return_value());
1139 free(custom_dir);
1140
1141 return file_path;
1142 }
1143
1144 static uim_bool
prepare_dir(const char * dir)1145 prepare_dir(const char *dir)
1146 {
1147 struct stat st;
1148
1149 if (stat(dir, &st) < 0) {
1150 return (mkdir(dir, 0700) < 0) ? UIM_FALSE : UIM_TRUE;
1151 } else {
1152 mode_t mode = S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR;
1153
1154 return ((st.st_mode & mode) == mode) ? UIM_TRUE : UIM_FALSE;
1155 }
1156 }
1157
1158 static uim_bool
uim_conf_prepare_dir(const char * subdir)1159 uim_conf_prepare_dir(const char *subdir)
1160 {
1161 uim_bool succeeded;
1162 char *dir;
1163
1164 dir = uim_conf_path(NULL);
1165 succeeded = prepare_dir(dir);
1166 free(dir);
1167 if (!succeeded)
1168 return UIM_FALSE;
1169
1170 if (subdir) {
1171 dir = uim_conf_path(subdir);
1172 succeeded = prepare_dir(dir);
1173 free(dir);
1174 if (!succeeded)
1175 return UIM_FALSE;
1176 }
1177
1178 return UIM_TRUE;
1179 }
1180
1181 static uim_bool
for_each_primary_groups(uim_bool (* func)(const char *))1182 for_each_primary_groups(uim_bool (*func)(const char *))
1183 {
1184 uim_bool succeeded = UIM_TRUE;
1185 char **primary_groups, **grp;
1186
1187 primary_groups = uim_custom_primary_groups();
1188 for (grp = primary_groups; *grp; grp++) {
1189 succeeded = (*func)(*grp) && succeeded;
1190 }
1191 uim_custom_symbol_list_free(primary_groups);
1192
1193 return succeeded;
1194 }
1195
1196 static uim_bool
uim_custom_load_group(const char * group)1197 uim_custom_load_group(const char *group)
1198 {
1199 char *file_path;
1200 uim_bool succeeded;
1201
1202 file_path = custom_file_path(group, 0);
1203 succeeded = uim_scm_load_file(file_path);
1204 free(file_path);
1205
1206 return succeeded;
1207 }
1208
1209 /**
1210 * Loads per-user custom variable configurations. This function loads per-user
1211 * custom variable values from ~/.uim.d/customs/custom-*.scm previously saved
1212 * by uim_custom_save().
1213 *
1214 * @see uim_custom_save()
1215 * @retval UIM_TRUE succeeded
1216 * @retval UIM_FALSE failed
1217 */
1218 uim_bool
uim_custom_load(void)1219 uim_custom_load(void)
1220 {
1221 if(uim_helper_is_setugid() ==UIM_FALSE) {
1222 return for_each_primary_groups(uim_custom_load_group);
1223 } else {
1224 return UIM_FALSE;
1225 }
1226 }
1227
1228 #ifdef UIM_CUSTOM_EXPERIMENTAL_MTIME_SENSING
1229 static uim_bool
file_content_is_same(const char * a_path,const char * b_path)1230 file_content_is_same(const char *a_path, const char *b_path)
1231 {
1232 uim_bool ret;
1233 FILE *a, *b;
1234 char a_buf[4096], b_buf[4096];
1235
1236 a = fopen(a_path, "r");
1237 b = fopen(b_path, "r");
1238
1239 while(1) {
1240 char *a_eof, *b_eof;
1241
1242 if (!a || !b) {
1243 ret = UIM_FALSE;
1244 break;
1245 }
1246
1247 a_eof = fgets(a_buf, sizeof(a_buf), a);
1248 b_eof = fgets(b_buf, sizeof(b_buf), b);
1249
1250 if (!a_eof && !b_eof) {
1251 ret = UIM_TRUE;
1252 break;
1253 }
1254
1255 if ((!a_eof && b_eof) || (a_eof && !b_eof)) {
1256 ret = UIM_FALSE;
1257 break;
1258 }
1259
1260 if (strcmp(a_buf, b_buf) != 0) {
1261 ret = UIM_FALSE;
1262 break;
1263 }
1264 }
1265
1266 if (a)
1267 fclose(a);
1268 if (b)
1269 fclose(b);
1270 return ret;
1271 }
1272 #endif
1273
1274 static uim_bool
uim_custom_save_group(const char * group)1275 uim_custom_save_group(const char *group)
1276 {
1277 uim_bool succeeded = UIM_FALSE;
1278 char **custom_syms, **sym;
1279 char *def_literal;
1280 pid_t pid;
1281 char *tmp_file_path, *file_path;
1282 FILE *file;
1283
1284 if (!uim_conf_prepare_dir(custom_subdir))
1285 return UIM_FALSE;
1286
1287 /*
1288 to avoid write conflict and broken by accident, we write customs
1289 to temporary file first
1290 */
1291 pid = getpid();
1292 tmp_file_path = custom_file_path(group, pid);
1293 file = fopen(tmp_file_path, "w");
1294 if (!file)
1295 goto error;
1296
1297 custom_syms = uim_custom_collect_by_group(group);
1298 if (!custom_syms) {
1299 fclose(file);
1300 goto error;
1301 }
1302
1303 for (sym = custom_syms; *sym; sym++) {
1304 def_literal = uim_custom_definition_as_literal(*sym);
1305 if (def_literal) {
1306 fputs(def_literal, file);
1307 fprintf(file, "\n");
1308 free(def_literal);
1309 }
1310 }
1311 uim_custom_symbol_list_free(custom_syms);
1312
1313 if (fclose(file) < 0)
1314 goto error;
1315
1316 /* rename prepared temporary file to proper name */
1317 file_path = custom_file_path(group, 0);
1318 #ifdef UIM_CUSTOM_EXPERIMENTAL_MTIME_SENSING
1319 /*
1320 * Avoiding a file saving at here by such method is a layer
1321 * violation. Observing updated group is recommended way.
1322 * -- YamaKen 2005-08-09
1323 */
1324 if (file_content_is_same(tmp_file_path, file_path)) {
1325 succeeded = UIM_TRUE;
1326 remove(tmp_file_path);
1327 } else {
1328 succeeded = (rename(tmp_file_path, file_path) == 0);
1329 }
1330 #else
1331 succeeded = (rename(tmp_file_path, file_path) == 0);
1332 #endif
1333 free(file_path);
1334
1335 error:
1336 free(tmp_file_path);
1337
1338 return succeeded;
1339 }
1340
1341 /**
1342 * Saves per-user custom variable configurations. This function saves current
1343 * custom variable values into ~/.uim.d/customs/custom-*.scm. The directory
1344 * will be made if not exist. The saved values will be implicitly loaded at
1345 * uim_init() or can explicitly be loaded by uim_custom_load().
1346 *
1347 * @see uim_init()
1348 * @see uim_custom_load()
1349 * @retval UIM_TRUE succeeded
1350 * @retval UIM_FALSE failed
1351 */
1352 uim_bool
uim_custom_save(void)1353 uim_custom_save(void)
1354 {
1355 if(uim_helper_is_setugid() == UIM_FALSE) {
1356 return for_each_primary_groups(uim_custom_save_group);
1357 } else {
1358 return UIM_FALSE;
1359 }
1360 }
1361
1362 /**
1363 * Saves a per-user custom variable configuration. This function saves a
1364 * primary custom group values which contains the specified custom variable as
1365 * ~/.uim.d/customs/custom-primary-group-file-containing-the-variable.scm. The
1366 * directory will be made if not exist. The saved values will be implicitly
1367 * loaded at uim_init() or can explicitly be loaded by uim_custom_load().
1368 *
1369 * @see uim_init()
1370 * @see uim_custom_load()
1371 * @retval UIM_TRUE succeeded
1372 * @retval UIM_FALSE failed
1373 */
1374 uim_bool
uim_custom_save_custom(const char * custom_sym)1375 uim_custom_save_custom(const char *custom_sym)
1376 {
1377 if(uim_helper_is_setugid() == UIM_FALSE) {
1378 const char *group_sym = uim_custom_get_primary_group_by_custom(custom_sym);
1379 return uim_custom_save_group(group_sym);
1380 } else {
1381 return UIM_FALSE;
1382 }
1383 }
1384
1385 /**
1386 * Broadcasts custom variable configurations to other uim-enabled application
1387 * processes via uim-helper-server. This function broadcasts current custom
1388 * variable values to other uim-enabled application processes via
1389 * uim-helper-server. The received processes updates custom variables
1390 * dynamically. This enables dynamic re-configuration of input methods.
1391 *
1392 * @retval UIM_TRUE succeeded
1393 * @retval UIM_FALSE failed
1394 */
1395 uim_bool
uim_custom_broadcast(void)1396 uim_custom_broadcast(void)
1397 {
1398 char **custom_syms, **sym;
1399 char *value, *msg;
1400
1401 if (helper_fd < 0) {
1402 helper_fd = uim_helper_init_client_fd(helper_disconnect_cb);
1403 }
1404
1405 custom_syms = uim_custom_collect_by_group(NULL);
1406 for (sym = custom_syms; *sym; sym++) {
1407 value = uim_custom_value_as_literal(*sym);
1408 if (value) {
1409 #if 1
1410 uim_asprintf(&msg, custom_msg_tmpl, *sym, value);
1411 #else
1412 /* old behavior: useless since other memory exhaustions disable uim */
1413 if (asprintf(&msg, custom_msg_tmpl, *sym, value) < 0 || !msg) {
1414 free(msg);
1415 free(value);
1416 uim_custom_symbol_list_free(custom_syms);
1417 return UIM_FALSE;
1418 }
1419 #endif
1420 uim_helper_send_message(helper_fd, msg);
1421 free(msg);
1422 free(value);
1423 }
1424 }
1425 uim_custom_symbol_list_free(custom_syms);
1426
1427 if (helper_fd != -1) {
1428 uim_helper_close_client_fd(helper_fd);
1429 }
1430
1431 return UIM_TRUE;
1432 }
1433
1434 /**
1435 * Broadcasts a request to reload custom files to other uim-enabled
1436 * application processes via uim-helper-server.
1437 *
1438 * @retval UIM_TRUE succeeded
1439 * @retval UIM_FALSE failed
1440 */
1441 uim_bool
uim_custom_broadcast_reload_request(void)1442 uim_custom_broadcast_reload_request(void)
1443 {
1444 if (helper_fd < 0) {
1445 helper_fd = uim_helper_init_client_fd(helper_disconnect_cb);
1446 }
1447
1448 uim_helper_send_message(helper_fd, "custom_reload_notify\n");
1449
1450 if (helper_fd != -1) {
1451 uim_helper_close_client_fd(helper_fd);
1452 }
1453
1454 return UIM_TRUE;
1455 }
1456
1457 /**
1458 * Returns attributes and current value of a custom variable. Returned value
1459 * must be freed by uim_custom_free().
1460 *
1461 * @see uim_custom_free()
1462 * @return custom variable attributes and current value
1463 * @param custom_sym custom variable name
1464 */
1465 struct uim_custom *
uim_custom_get(const char * custom_sym)1466 uim_custom_get(const char *custom_sym)
1467 {
1468 struct uim_custom *custom;
1469
1470 if (!custom_sym)
1471 return UIM_FALSE;
1472
1473 custom = (struct uim_custom *)malloc(sizeof(struct uim_custom));
1474 if (!custom)
1475 return UIM_FALSE;
1476
1477 custom->type = uim_custom_type(custom_sym);
1478 custom->is_active = uim_custom_is_active(custom_sym);
1479 custom->symbol = strdup(custom_sym);
1480 custom->label = uim_custom_label(custom_sym);
1481 custom->desc = uim_custom_desc(custom_sym);
1482 custom->value = uim_custom_value(custom_sym);
1483 custom->default_value = uim_custom_default_value(custom_sym);
1484 custom->range = uim_custom_range_get(custom_sym);
1485
1486 return custom;
1487 }
1488
1489 /**
1490 * Updates value of a custom variable. This function tries that an update of
1491 * the custom variable specified by symbol and value of contained in @a
1492 * custom. Update failes when passed value is invalid for the custom
1493 * variable. Previous value is kept in real custom variable when the
1494 * failure. @a custom should be created by uim_custom_get() and then user of
1495 * uim-custom API can modify value of the @custom before passing to this
1496 * function.
1497 *
1498 * If you want to set null list as value for ordered-list or key,
1499 * allocate an array contains 1 NULL element and set it into
1500 * custom->value->as_foo.
1501 *
1502 * @see uim_custom_get()
1503 * @param custom custom variable symbol and value
1504 * @retval UIM_TRUE succeeded
1505 * @retval UIM_FALSE failed
1506 */
1507 uim_bool
uim_custom_set(const struct uim_custom * custom)1508 uim_custom_set(const struct uim_custom *custom)
1509 {
1510 char *literal;
1511
1512 if (!custom)
1513 return UIM_FALSE;
1514
1515 switch (custom->type) {
1516 case UCustom_Bool:
1517 UIM_EVAL_FSTRING2(NULL, "(custom-set-value! '%s #%s)",
1518 custom->symbol, (custom->value->as_bool) ? "t" : "f");
1519 break;
1520 case UCustom_Int:
1521 UIM_EVAL_FSTRING2(NULL, "(custom-set-value! '%s %d)",
1522 custom->symbol, custom->value->as_int);
1523 break;
1524 case UCustom_Str:
1525 literal = literalize_string(custom->value->as_str);
1526 UIM_EVAL_FSTRING2(NULL, "(custom-set-value! '%s %s)",
1527 custom->symbol, literal);
1528 free(literal);
1529 break;
1530 case UCustom_Pathname:
1531 literal = literalize_string(custom->value->as_pathname->str);
1532 UIM_EVAL_FSTRING2(NULL, "(custom-set-value! '%s %s)",
1533 custom->symbol, literal);
1534 free(literal);
1535 break;
1536 case UCustom_Choice:
1537 UIM_EVAL_FSTRING2(NULL, "(custom-set-value! '%s '%s)",
1538 custom->symbol, custom->value->as_choice->symbol);
1539 break;
1540 case UCustom_OrderedList:
1541 {
1542 char *val;
1543 val = choice_list_to_str((const struct uim_custom_choice *const *)custom->value->as_olist, " ");
1544 UIM_EVAL_FSTRING2(NULL, "(custom-set-value! '%s '(%s))", custom->symbol, val);
1545 free(val);
1546 }
1547 break;
1548 case UCustom_Key:
1549 {
1550 char *val;
1551 val = key_list_to_str((const struct uim_custom_key *const *)custom->value->as_key, " ");
1552 UIM_EVAL_FSTRING2(NULL, "(custom-set-value! '%s (map gui-key-str->key-str '(%s)))", custom->symbol, val);
1553 free(val);
1554 }
1555 break;
1556 case UCustom_Table:
1557 {
1558 char *val
1559 = table_to_str((const char ** const *)custom->value->as_table, ") (");
1560 UIM_EVAL_FSTRING2(NULL, "(custom-set-value! '%s '((%s)))",
1561 custom->symbol, val);
1562 free(val);
1563 }
1564 break;
1565 default:
1566 return UIM_FALSE;
1567 }
1568 return uim_scm_c_bool(uim_scm_return_value());
1569 }
1570
1571 /**
1572 * Frees pre-allocated C representation of a custom variable. All C
1573 * representation of a custom variable allocated by uim_custom_get() must be
1574 * freed by this function.
1575 *
1576 * @see uim_custom_get()
1577 * @param custom C representation of a custom variable
1578 */
1579 void
uim_custom_free(struct uim_custom * custom)1580 uim_custom_free(struct uim_custom *custom)
1581 {
1582 if (!custom)
1583 return;
1584
1585 free(custom->symbol);
1586 free(custom->label);
1587 free(custom->desc);
1588 uim_custom_value_free(custom->type, custom->value);
1589 uim_custom_value_free(custom->type, custom->default_value);
1590 uim_custom_range_free(custom->type, custom->range);
1591 free(custom);
1592 }
1593
1594 /**
1595 * Returns Scheme literal of a custom variable value. Returned string must be
1596 * free() by caller.
1597 *
1598 * @return the literal
1599 * @param custom_sym custom variable name
1600 */
1601 char *
uim_custom_value_as_literal(const char * custom_sym)1602 uim_custom_value_as_literal(const char *custom_sym)
1603 {
1604 return strdup(uim_custom_get_str(custom_sym, "custom-value-as-literal"));
1605 }
1606
1607 /**
1608 * Returns Scheme literal of a custom variable definition. Returned string
1609 * must be free() by caller.
1610 *
1611 * @return the literal
1612 * @param custom_sym custom variable name
1613 */
1614 char *
uim_custom_definition_as_literal(const char * custom_sym)1615 uim_custom_definition_as_literal(const char *custom_sym)
1616 {
1617 return strdup(uim_custom_get_str(custom_sym, "custom-definition-as-literal"));
1618 }
1619
1620 /**
1621 * Returns attributes of a custom group.and current value of a custom
1622 * variable. Returned value must be freed by uim_custom_group_free().
1623 *
1624 * @see uim_custom_group_free()
1625 * @return attributes of custom group
1626 * @param group_sym custom group name
1627 */
1628 struct uim_custom_group *
uim_custom_group_get(const char * group_sym)1629 uim_custom_group_get(const char *group_sym)
1630 {
1631 struct uim_custom_group *custom_group;
1632 const char *label, *desc;
1633
1634 custom_group = (struct uim_custom_group *)malloc(sizeof(struct uim_custom_group));
1635 if (!custom_group)
1636 return NULL;
1637
1638 label = uim_custom_get_str(group_sym, "custom-group-label");
1639 desc = uim_custom_get_str(group_sym, "custom-group-desc");
1640
1641 custom_group->symbol = strdup(group_sym);
1642 custom_group->label = strdup(UGETTEXT(label));
1643 custom_group->desc = strdup(UGETTEXT(desc));
1644
1645 return custom_group;
1646 }
1647
1648 /**
1649 * Frees C representation of a custom group.
1650 *
1651 * @see uim_custom_group_get()
1652 * @param custom_group C representation of custom group
1653 */
1654 void
uim_custom_group_free(struct uim_custom_group * custom_group)1655 uim_custom_group_free(struct uim_custom_group *custom_group)
1656 {
1657 if (!custom_group)
1658 return;
1659
1660 free(custom_group->symbol);
1661 free(custom_group->label);
1662 free(custom_group->desc);
1663 free(custom_group);
1664 }
1665
1666 /**
1667 * Returns custom variable symbols that belongs to @a group_sym. The symbols
1668 * consist of NULL-terminated array of C string and must be freed by
1669 * uim_custom_symbol_list_free().
1670 *
1671 * @see uim_custom_symbol_list_free()
1672 * @return custom variable symbols
1673 * @param group_sym custom group name. NULL means 'any group'
1674 */
1675 char **
uim_custom_collect_by_group(const char * group_sym)1676 uim_custom_collect_by_group(const char *group_sym)
1677 {
1678 char **custom_list;
1679
1680 UIM_EVAL_FSTRING2(NULL, "(define %s (custom-collect-by-group '%s))",
1681 str_list_arg, (group_sym) ? group_sym : "#f");
1682 custom_list = uim_scm_c_str_list(str_list_arg, "symbol->string");
1683
1684 return custom_list;
1685 }
1686
1687 /**
1688 * Returns all existing custom group symbols. The symbols consist of
1689 * NULL-terminated array of C string and must be freed by
1690 * uim_custom_symbol_list_free().
1691 *
1692 * @see uim_custom_symbol_list_free()
1693 * @return custom variable symbols
1694 */
1695 char **
uim_custom_groups(void)1696 uim_custom_groups(void)
1697 {
1698 char **group_list;
1699
1700 UIM_EVAL_FSTRING1(NULL, "(define %s (custom-list-groups))", str_list_arg);
1701 group_list = uim_scm_c_str_list(str_list_arg, "symbol->string");
1702
1703 return group_list;
1704 }
1705
1706 /**
1707 * Returns all existing primary custom group symbols. Subgroups are not
1708 * returned. The symbols consist of NULL-terminated array of C string and must
1709 * be freed by uim_custom_symbol_list_free().
1710 *
1711 * @see uim_custom_symbol_list_free()
1712 * @return custom variable symbols
1713 */
1714 char **
uim_custom_primary_groups(void)1715 uim_custom_primary_groups(void)
1716 {
1717 char **group_list;
1718
1719 UIM_EVAL_FSTRING1(NULL, "(define %s (custom-list-primary-groups))",
1720 str_list_arg);
1721 group_list = uim_scm_c_str_list(str_list_arg, "symbol->string");
1722
1723 return group_list;
1724 }
1725
1726 /**
1727 * Returns subgroup symbols of @a group_sym. The symbols consist of
1728 * NULL-terminated array of C string and must be freed by
1729 * uim_custom_symbol_list_free().
1730 *
1731 * @see uim_custom_symbol_list_free()
1732 * @return custom subgroup symbols
1733 * @param group_sym custom group name
1734 */
1735 char **
uim_custom_group_subgroups(const char * group_sym)1736 uim_custom_group_subgroups(const char *group_sym)
1737 {
1738 char **group_list;
1739
1740 UIM_EVAL_FSTRING2(NULL, "(define %s (custom-group-subgroups '%s))",
1741 str_list_arg, group_sym);
1742 group_list = uim_scm_c_str_list(str_list_arg, "symbol->string");
1743
1744 return group_list;
1745 }
1746
1747 /**
1748 * Frees a symbol list allocated by uim_custom_*() functions. The term 'list'
1749 * does not mean linked list. Actually NULL-terminated array.
1750 *
1751 * @see uim_custom_collect_by_group()
1752 * @see uim_custom_groups()
1753 * @see uim_custom_primary_groups()
1754 * @see uim_custom_group_subgroups()
1755 * @param symbol_list pre-allocated symbol list
1756 */
1757 void
uim_custom_symbol_list_free(char ** symbol_list)1758 uim_custom_symbol_list_free(char **symbol_list)
1759 {
1760 uim_scm_c_list_free((void **)symbol_list, (uim_scm_c_list_free_func)free);
1761 }
1762
1763 static const char *
uim_custom_get_primary_group_by_custom(const char * custom_sym)1764 uim_custom_get_primary_group_by_custom(const char *custom_sym)
1765 {
1766 uim_lisp groups;
1767 groups = uim_scm_callf("custom-groups", "y", custom_sym);
1768
1769 return uim_scm_refer_c_str(uim_scm_car(groups));
1770 }
1771
1772 static uim_lisp
uim_custom_cb_update_cb_gate(uim_lisp cb,uim_lisp ptr,uim_lisp custom_sym)1773 uim_custom_cb_update_cb_gate(uim_lisp cb, uim_lisp ptr, uim_lisp custom_sym)
1774 {
1775 uim_custom_cb_update_cb_t update_cb;
1776 void *c_ptr;
1777 char *c_custom_sym;
1778
1779 update_cb = (uim_custom_cb_update_cb_t)uim_scm_c_func_ptr(cb);
1780 c_ptr = uim_scm_c_ptr(ptr);
1781 c_custom_sym = uim_scm_c_symbol(custom_sym);
1782 (*update_cb)(c_ptr, c_custom_sym);
1783 free(c_custom_sym);
1784
1785 return uim_scm_f();
1786 }
1787
1788 static uim_lisp
uim_custom_global_cb_update_cb_gate(uim_lisp cb,uim_lisp ptr)1789 uim_custom_global_cb_update_cb_gate(uim_lisp cb, uim_lisp ptr)
1790 {
1791 uim_custom_global_cb_update_cb_t update_cb;
1792 void *c_ptr;
1793
1794 update_cb = (uim_custom_global_cb_update_cb_t)uim_scm_c_func_ptr(cb);
1795 c_ptr = uim_scm_c_ptr(ptr);
1796 (*update_cb)(c_ptr);
1797
1798 return uim_scm_f();
1799 }
1800
1801 static uim_bool
custom_cb_add(const char * hook,const char * validator,const char * custom_sym,void * ptr,const char * gate_func,void (* cb)(void))1802 custom_cb_add(const char *hook, const char *validator,
1803 const char *custom_sym, void *ptr,
1804 const char *gate_func, void (*cb)(void))
1805 {
1806 struct custom_cb_add_args args;
1807
1808 args.hook = hook;
1809 args.validator = validator;
1810 args.custom_sym = custom_sym;
1811 args.ptr = ptr;
1812 args.gate_func = gate_func;
1813 args.cb = cb;
1814 return (uim_bool)(uintptr_t)uim_scm_call_with_gc_ready_stack((uim_gc_gate_func_ptr)custom_cb_add_internal, &args);
1815 }
1816
1817 static void *
custom_cb_add_internal(struct custom_cb_add_args * args)1818 custom_cb_add_internal(struct custom_cb_add_args *args)
1819 {
1820 uim_bool succeeded;
1821 const char *hook;
1822 const char *validator;
1823 const char *custom_sym;
1824 void *ptr;
1825 const char *gate_func;
1826 void (*cb)(void);
1827 uim_lisp form;
1828
1829 hook = args->hook;
1830 validator = args->validator;
1831 custom_sym = args->custom_sym;
1832 ptr = args->ptr;
1833 gate_func = args->gate_func;
1834 cb = args->cb;
1835
1836 form = uim_scm_list5(uim_scm_make_symbol(validator),
1837 uim_scm_quote(uim_scm_make_symbol(custom_sym)),
1838 uim_scm_make_ptr(ptr),
1839 uim_scm_make_symbol(gate_func),
1840 uim_scm_make_func_ptr(cb));
1841 form = uim_scm_cons(uim_scm_quote(uim_scm_make_symbol(hook)), form);
1842 form = uim_scm_cons(uim_scm_make_symbol("custom-register-cb"), form);
1843 succeeded = uim_scm_c_bool(uim_scm_eval(form));
1844
1845 return (void *)(uintptr_t)succeeded;
1846 }
1847
1848 static uim_bool
custom_cb_remove(const char * key_sym,const char * hook)1849 custom_cb_remove(const char *key_sym, const char *hook)
1850 {
1851 uim_bool removed;
1852
1853 UIM_EVAL_FSTRING2(NULL, "(custom-remove-hook '%s '%s)",
1854 (key_sym) ? key_sym : "#f", hook);
1855 removed = uim_scm_c_bool(uim_scm_return_value());
1856
1857 return removed;
1858 }
1859
1860 /**
1861 * Set a callback function in a custom variable. The @a update_cb is called
1862 * back when the custom variable specified by @a custom_sym is
1863 * updated. Multiple callbacks for one custom variable is allowed.
1864 *
1865 * @retval UIM_TRUE succeeded
1866 * @retval UIM_FALSE failed
1867 * @param custom_sym custom variable name
1868 * @param ptr an opaque value passed back to client at callback
1869 * @param update_cb function pointer called back when the custom variable is
1870 * updated
1871 */
1872 uim_bool
uim_custom_cb_add(const char * custom_sym,void * ptr,void (* update_cb)(void * ptr,const char * custom_sym))1873 uim_custom_cb_add(const char *custom_sym, void *ptr,
1874 void (*update_cb)(void *ptr, const char *custom_sym))
1875 {
1876 return custom_cb_add("custom-update-hooks", "custom-rec",
1877 custom_sym, ptr,
1878 "custom-update-cb-gate", (void (*)(void))update_cb);
1879 }
1880
1881 /**
1882 * Remove the callback functions in a custom variable. All functions set for @a
1883 * custom_sym will be removed.
1884 *
1885 * @retval UIM_TRUE some functions are removed
1886 * @retval UIM_FALSE no functions are removed
1887 * @param custom_sym custom variable name. NULL instructs 'all callbacks'
1888 */
1889 uim_bool
uim_custom_cb_remove(const char * custom_sym)1890 uim_custom_cb_remove(const char *custom_sym)
1891 {
1892 return custom_cb_remove(custom_sym, "custom-update-hooks");
1893 }
1894
1895 /**
1896 * Set a callback function in a custom group. The @a update_cb is
1897 * called back when the custom group specified by @a group_sym is
1898 * updated (i.e. new custom variable has been defined in the group or
1899 * a custom variable is removed from the group). Multiple callbacks
1900 * for one custom variable is allowed.
1901 *
1902 * @retval UIM_TRUE succeeded
1903 * @retval UIM_FALSE failed
1904 * @param group_sym custom group name
1905 * @param ptr an opaque value passed back to client at callback
1906 * @param update_cb function pointer called back when the custom group is
1907 * updated
1908 */
1909 uim_bool
uim_custom_group_cb_add(const char * group_sym,void * ptr,void (* update_cb)(void * ptr,const char * group_sym))1910 uim_custom_group_cb_add(const char *group_sym, void *ptr,
1911 void (*update_cb)(void *ptr, const char *group_sym))
1912 {
1913 return custom_cb_add("custom-group-update-hooks", "custom-group-rec",
1914 group_sym, ptr,
1915 "custom-update-cb-gate", (void (*)(void))update_cb);
1916 }
1917
1918 /**
1919 * Remove the callback functions in a custom group. All functions set for @a
1920 * group_sym will be removed.
1921 *
1922 * @retval UIM_TRUE some functions are removed
1923 * @retval UIM_FALSE no functions are removed
1924 * @param group_sym custom group name. NULL instructs 'all callbacks'
1925 */
1926 uim_bool
uim_custom_group_cb_remove(const char * group_sym)1927 uim_custom_group_cb_remove(const char *group_sym)
1928 {
1929 return custom_cb_remove(group_sym, "custom-group-update-hooks");
1930 }
1931
1932 /**
1933 * Set a callback function for global events. The @a
1934 * group_list_update_cb is called back when group list is updated
1935 * (i.e. new custom group has been defined or a custom group is
1936 * undefined). Multiple callbacks is allowed.
1937 *
1938 * @retval UIM_TRUE succeeded
1939 * @retval UIM_FALSE failed
1940 * @param ptr an opaque value passed back to client at callback
1941 * @param group_list_update_cb function pointer called back when
1942 * custom group list is updated
1943 */
1944 uim_bool
uim_custom_global_cb_add(void * ptr,void (* group_list_update_cb)(void * ptr))1945 uim_custom_global_cb_add(void *ptr, void (*group_list_update_cb)(void *ptr))
1946 {
1947 return custom_cb_add("custom-group-update-hooks", "(lambda (dummy) #t)",
1948 "global", ptr,
1949 "custom-global-update-cb-gate",
1950 (void (*)(void))group_list_update_cb);
1951 }
1952
1953 /**
1954 * Remove all callback functions for global events.
1955 *
1956 * @retval UIM_TRUE some functions are removed
1957 * @retval UIM_FALSE no functions are removed
1958 */
uim_custom_global_cb_remove(void)1959 uim_bool uim_custom_global_cb_remove(void)
1960 {
1961 return custom_cb_remove("global", "custom-group-list-update-hooks");
1962 }
1963