Bug Summary

File:ctk/ctkimmodule.c
Warning:line 499, column 4
Potential leak of memory pointed to by 'info'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ctkimmodule.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/ctk -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I .. -D G_LOG_DOMAIN="Ctk" -D G_LOG_USE_STRUCTURED=1 -D CTK_VERSION="3.25.5" -D CTK_BINARY_VERSION="3.0.0" -D CTK_COMPILATION -D CTK_PRINT_BACKEND_ENABLE_UNSUPPORTED -D CTK_LIBDIR="/usr/lib" -D CTK_LOCALEDIR="/usr/share/locale" -D CTK_DATADIR="/usr/share" -D CTK_DATA_PREFIX="/usr" -D CTK_SYSCONFDIR="/usr/etc" -D CTK_HOST="x86_64-pc-linux-gnu" -D CTK_PRINT_BACKENDS="file,cups" -D X11_DATA_PREFIX="/usr" -D ISO_CODES_PREFIX="" -I .. -I ../ctk -I .. -I ../cdk -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -D G_ENABLE_DEBUG -D G_ENABLE_CONSISTENCY_CHECKS -D GLIB_MIN_REQUIRED_VERSION=GLIB_VERSION_2_66 -D GLIB_MAX_ALLOWED_VERSION=GLIB_VERSION_2_66 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/atk-1.0 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/gio-unix-2.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/pango-1.0 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -D PIC -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/ctk -ferror-limit 19 -fvisibility=hidden -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-09-19-172131-43638-1 -x c ctkimmodule.c
1/* CTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.Free
16 */
17
18/*
19 * Modified by the CTK+ Team and others 1997-2000. See the AUTHORS
20 * file for a list of people on the CTK+ Team. See the ChangeLog
21 * files for a list of changes. These files are distributed with
22 * CTK+ at ftp://ftp.ctk.org/pub/ctk/.
23 */
24
25#include "config.h"
26
27#include <errno(*__errno_location ()).h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31
32#include <glib/gstdio.h>
33#include <gmodule.h>
34#include "ctkimmoduleprivate.h"
35#include "ctkimcontextsimple.h"
36#include "ctksettings.h"
37#include "ctkprivate.h"
38#include "ctkutilsprivate.h"
39#include "ctkintl.h"
40
41#ifdef CDK_WINDOWING_X11
42#include "x11/cdkx.h"
43#endif
44
45#ifdef CDK_WINDOWING_WAYLAND
46#include "wayland/cdkwayland.h"
47#endif
48
49#ifdef CDK_WINDOWING_BROADWAY
50#include "broadway/cdkbroadway.h"
51#endif
52
53#ifdef CDK_WINDOWING_WIN32
54#include "win32/cdkwin32.h"
55#endif
56
57#ifdef G_OS_WIN32
58#include <windows.h>
59#endif
60
61#undef CDK_DEPRECATED
62#undef CDK_DEPRECATED_FOR
63#define CDK_DEPRECATED
64#define CDK_DEPRECATED_FOR(f)
65
66#include "ctkrc.h"
67
68/* We need to call getc() a lot in a loop. This is suboptimal,
69 * as getc() does thread locking on the FILE it is given.
70 * To optimize that, lock the file first, then call getc(),
71 * then unlock.
72 * If locking functions are not present in libc, fall back
73 * to the suboptimal getc().
74 */
75#if !defined(HAVE_FLOCKFILE1) && !defined(HAVE__LOCK_FILE)
76# define flockfile(f) (void)1
77# define funlockfile(f) (void)1
78# define getc_unlocked(f) getc(f)
79#elif !defined(HAVE_FLOCKFILE1) && defined(HAVE__LOCK_FILE)
80# define flockfile(f) _lock_file(f)
81# define funlockfile(f) _unlock_file(f)
82# define getc_unlocked(f) _getc_nolock(f)
83#endif
84
85#define SIMPLE_ID"ctk-im-context-simple" "ctk-im-context-simple"
86#define NONE_ID"ctk-im-context-none" "ctk-im-context-none"
87
88/**
89 * CtkIMContextInfo:
90 * @context_id: The unique identification string of the input method.
91 * @context_name: The human-readable name of the input method.
92 * @domain: Translation domain to be used with dgettext()
93 * @domain_dirname: Name of locale directory for use with bindtextdomain()
94 * @default_locales: A colon-separated list of locales where this input method
95 * should be the default. The asterisk “*” sets the default for all locales.
96 *
97 * Bookkeeping information about a loadable input method.
98 */
99
100typedef struct _CtkIMModule CtkIMModule;
101typedef struct _CtkIMModuleClass CtkIMModuleClass;
102
103#define CTK_TYPE_IM_MODULE(ctk_im_module_get_type ()) (ctk_im_module_get_type ())
104#define CTK_IM_MODULE(im_module)((((CtkIMModule*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((im_module)), ((ctk_im_module_get_type ()))))))
(G_TYPE_CHECK_INSTANCE_CAST ((im_module), CTK_TYPE_IM_MODULE, CtkIMModule)(((CtkIMModule*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((im_module)), ((ctk_im_module_get_type ())))))
)
105#define CTK_IS_IM_MODULE(im_module)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(im_module)); GType __t = ((ctk_im_module_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
(G_TYPE_CHECK_INSTANCE_TYPE ((im_module), CTK_TYPE_IM_MODULE)((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(im_module)); GType __t = ((ctk_im_module_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))
)
106
107struct _CtkIMModule
108{
109 GTypeModule parent_instance;
110
111 gboolean builtin;
112
113 GModule *library;
114
115 void (*list) (const CtkIMContextInfo ***contexts,
116 guint *n_contexts);
117 void (*init) (GTypeModule *module);
118 void (*exit) (void);
119 CtkIMContext *(*create) (const gchar *context_id);
120
121 CtkIMContextInfo **contexts;
122 guint n_contexts;
123
124 gchar *path;
125};
126
127struct _CtkIMModuleClass
128{
129 GTypeModuleClass parent_class;
130};
131
132static GType ctk_im_module_get_type (void);
133
134static gint n_loaded_contexts = 0;
135static GHashTable *contexts_hash = NULL((void*)0);
136static GSList *modules_list = NULL((void*)0);
137
138static gboolean
139ctk_im_module_load (GTypeModule *module)
140{
141 CtkIMModule *im_module = CTK_IM_MODULE (module)((((CtkIMModule*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((module)), ((ctk_im_module_get_type ()))))))
;
142
143 if (!im_module->builtin)
144 {
145 im_module->library = g_module_open (im_module->path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
146 if (!im_module->library)
147 {
148 g_warning ("%s", g_module_error());
149 return FALSE(0);
150 }
151
152 /* extract symbols from the lib */
153 if (!g_module_symbol (im_module->library, "im_module_init",
154 (gpointer *)&im_module->init) ||
155 !g_module_symbol (im_module->library, "im_module_exit",
156 (gpointer *)&im_module->exit) ||
157 !g_module_symbol (im_module->library, "im_module_list",
158 (gpointer *)&im_module->list) ||
159 !g_module_symbol (im_module->library, "im_module_create",
160 (gpointer *)&im_module->create))
161 {
162 g_warning ("%s", g_module_error());
163 g_module_close (im_module->library);
164
165 return FALSE(0);
166 }
167 }
168
169 /* call the module's init function to let it */
170 /* setup anything it needs to set up. */
171 im_module->init (module);
172
173 return TRUE(!(0));
174}
175
176static void
177ctk_im_module_unload (GTypeModule *module)
178{
179 CtkIMModule *im_module = CTK_IM_MODULE (module)((((CtkIMModule*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((module)), ((ctk_im_module_get_type ()))))))
;
180
181 im_module->exit();
182
183 if (!im_module->builtin)
184 {
185 g_module_close (im_module->library);
186 im_module->library = NULL((void*)0);
187
188 im_module->init = NULL((void*)0);
189 im_module->exit = NULL((void*)0);
190 im_module->list = NULL((void*)0);
191 im_module->create = NULL((void*)0);
192 }
193}
194
195G_DEFINE_TYPE (CtkIMModule, ctk_im_module, G_TYPE_TYPE_MODULE)static void ctk_im_module_init (CtkIMModule *self); static void
ctk_im_module_class_init (CtkIMModuleClass *klass); static GType
ctk_im_module_get_type_once (void); static gpointer ctk_im_module_parent_class
= ((void*)0); static gint CtkIMModule_private_offset; static
void ctk_im_module_class_intern_init (gpointer klass) { ctk_im_module_parent_class
= g_type_class_peek_parent (klass); if (CtkIMModule_private_offset
!= 0) g_type_class_adjust_private_offset (klass, &CtkIMModule_private_offset
); ctk_im_module_class_init ((CtkIMModuleClass*) klass); } __attribute__
((__unused__)) static inline gpointer ctk_im_module_get_instance_private
(CtkIMModule *self) { return (((gpointer) ((guint8*) (self) +
(glong) (CtkIMModule_private_offset)))); } GType ctk_im_module_get_type
(void) { static GType static_g_define_type_id = 0; if ((__extension__
({ _Static_assert (sizeof *(&static_g_define_type_id) ==
sizeof (gpointer), "Expression evaluates to false"); (void) (
0 ? (gpointer) * (&static_g_define_type_id) : ((void*)0))
; (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter_pointer (
&static_g_define_type_id)); })) ) { GType g_define_type_id
= ctk_im_module_get_type_once (); (__extension__ ({ _Static_assert
(sizeof *(&static_g_define_type_id) == sizeof (gpointer)
, "Expression evaluates to false"); 0 ? (void) (*(&static_g_define_type_id
) = (g_define_type_id)) : (void) 0; g_once_init_leave_pointer
((&static_g_define_type_id), (gpointer) (guintptr) (g_define_type_id
)); })) ; } return static_g_define_type_id; } __attribute__ (
(__noinline__)) static GType ctk_im_module_get_type_once (void
) { GType g_define_type_id = g_type_register_static_simple ((
g_type_module_get_type ()), g_intern_static_string ("CtkIMModule"
), sizeof (CtkIMModuleClass), (GClassInitFunc)(void (*)(void)
) ctk_im_module_class_intern_init, sizeof (CtkIMModule), (GInstanceInitFunc
)(void (*)(void)) ctk_im_module_init, (GTypeFlags) 0); { {{};
} } return g_define_type_id; }
196
197/* This only will ever be called if an error occurs during
198 * initialization
199 */
200static void
201ctk_im_module_finalize (GObject *object)
202{
203 CtkIMModule *module = CTK_IM_MODULE (object)((((CtkIMModule*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((ctk_im_module_get_type ()))))))
;
204
205 g_free (module->path);
206
207 G_OBJECT_CLASS (ctk_im_module_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_im_module_parent_class)), (((GType) ((20) << (
2))))))))
->finalize (object);
208}
209
210static void
211ctk_im_module_class_init (CtkIMModuleClass *class)
212{
213 GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (class)((((GTypeModuleClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((class)), ((g_type_module_get_type ()))))))
;
214 GObjectClass *gobject_class = G_OBJECT_CLASS (class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((class)), (((GType) ((20) << (2))))))))
;
215
216 module_class->load = ctk_im_module_load;
217 module_class->unload = ctk_im_module_unload;
218
219 gobject_class->finalize = ctk_im_module_finalize;
220}
221
222static void
223ctk_im_module_init (CtkIMModule* object G_GNUC_UNUSED__attribute__ ((__unused__)))
224{
225}
226
227static void
228free_info (CtkIMContextInfo *info)
229{
230 g_free ((char *)info->context_id);
231 g_free ((char *)info->context_name);
232 g_free ((char *)info->domain);
233 g_free ((char *)info->domain_dirname);
234 g_free ((char *)info->default_locales);
235 g_free (info);
236}
237
238static void
239add_module (CtkIMModule *module, GSList *infos)
240{
241 GSList *tmp_list = infos;
242 gint i = 0;
243 gint n = g_slist_length (infos);
244 module->contexts = g_new (CtkIMContextInfo *, n)((CtkIMContextInfo * *) g_malloc_n ((n), sizeof (CtkIMContextInfo
*)))
;
245
246 while (tmp_list)
247 {
248 CtkIMContextInfo *info = tmp_list->data;
249
250 if (g_hash_table_lookup (contexts_hash, info->context_id))
251 {
252 free_info (info); /* Duplicate */
253 }
254 else
255 {
256 g_hash_table_insert (contexts_hash, (char *)info->context_id, module);
257 module->contexts[i++] = tmp_list->data;
258 n_loaded_contexts++;
259 }
260
261 tmp_list = tmp_list->next;
262 }
263 g_slist_free (infos);
264 module->n_contexts = i;
265
266 modules_list = g_slist_prepend (modules_list, module);
267}
268
269#ifdef G_OS_WIN32
270
271static void
272correct_libdir_prefix (gchar **path)
273{
274 /* CTK_LIBDIR is the build-time libdir */
275 if (strncmp (*path, CTK_LIBDIR"/usr/lib", strlen (CTK_LIBDIR"/usr/lib")) == 0)
276 {
277 /* This is an entry put there by make install on the
278 * packager's system. On Windows a prebuilt CTK+
279 * package can be installed in a random
280 * location. The ctk.immodules file distributed in
281 * such a package contains paths from the package
282 * builder's machine. Replace the path with the real
283 * one on this machine.
284 */
285 gchar *tem = *path;
286 *path = g_strconcat (_ctk_get_libdir (), tem + strlen (CTK_LIBDIR"/usr/lib"), NULL((void*)0));
287 g_free (tem);
288 }
289}
290
291static void
292correct_localedir_prefix (gchar **path)
293{
294 /* See above */
295 if (strncmp (*path, CTK_LOCALEDIR"/usr/share/locale", strlen (CTK_LOCALEDIR"/usr/share/locale")) == 0)
296 {
297 gchar *tem = *path;
298 *path = g_strconcat (_ctk_get_localedir (), tem + strlen (CTK_LOCALEDIR"/usr/share/locale"), NULL((void*)0));
299 g_free (tem);
300 }
301}
302#endif
303
304
305G_GNUC_UNUSED__attribute__ ((__unused__)) static CtkIMModule *
306add_builtin_module (const gchar *module_name,
307 const CtkIMContextInfo **contexts,
308 int n_contexts)
309{
310 CtkIMModule *module = g_object_new (CTK_TYPE_IM_MODULE(ctk_im_module_get_type ()), NULL((void*)0));
311 GSList *infos = NULL((void*)0);
312 int i;
313
314 for (i = 0; i < n_contexts; i++)
315 {
316 CtkIMContextInfo *info = g_new (CtkIMContextInfo, 1)((CtkIMContextInfo *) g_malloc_n ((1), sizeof (CtkIMContextInfo
)))
;
317 info->context_id = g_strdup (contexts[i]->context_id)g_strdup_inline (contexts[i]->context_id);
318 info->context_name = g_strdup (contexts[i]->context_name)g_strdup_inline (contexts[i]->context_name);
319 info->domain = g_strdup (contexts[i]->domain)g_strdup_inline (contexts[i]->domain);
320 info->domain_dirname = g_strdup (contexts[i]->domain_dirname)g_strdup_inline (contexts[i]->domain_dirname);
321#ifdef G_OS_WIN32
322 correct_localedir_prefix ((char **) &info->domain_dirname);
323#endif
324 info->default_locales = g_strdup (contexts[i]->default_locales)g_strdup_inline (contexts[i]->default_locales);
325 infos = g_slist_prepend (infos, info);
326 }
327
328 module->builtin = TRUE(!(0));
329 g_type_module_set_name (G_TYPE_MODULE (module)((((GTypeModule*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((module)), ((g_type_module_get_type ()))))))
, module_name);
330 add_module (module, infos);
331
332 return module;
333}
334
335static void
336ctk_im_module_initialize (void)
337{
338 GString *line_buf = g_string_new (NULL((void*)0));
339 GString *tmp_buf = g_string_new (NULL((void*)0));
340 gchar *filename = ctk_rc_get_im_module_file();
341 FILE *file;
342 gboolean have_error = FALSE(0);
343
344 CtkIMModule *module = NULL((void*)0);
345 GSList *infos = NULL((void*)0);
346
347 contexts_hash = g_hash_table_new (g_str_hash, g_str_equal);
348
349#define do_builtin(m) \
350 { \
351 const CtkIMContextInfo **contexts; \
352 int n_contexts; \
353 extern void _ctk_immodule_ ## m ## _list (const CtkIMContextInfo ***contexts, \
354 int *n_contexts); \
355 extern void _ctk_immodule_ ## m ## _init (GTypeModule *module); \
356 extern void _ctk_immodule_ ## m ## _exit (void); \
357 extern CtkIMContext *_ctk_immodule_ ## m ## _create (const gchar *context_id); \
358 \
359 _ctk_immodule_ ## m ## _list (&contexts, &n_contexts); \
360 module = add_builtin_module (#m, contexts, n_contexts); \
361 module->init = _ctk_immodule_ ## m ## _init; \
362 module->exit = _ctk_immodule_ ## m ## _exit; \
363 module->create = _ctk_immodule_ ## m ## _create; \
364 module = NULL((void*)0); \
365 }
366
367#ifdef INCLUDE_IM_am_et
368 do_builtin (am_et);
369#endif
370#ifdef INCLUDE_IM_cedilla
371 do_builtin (cedilla);
372#endif
373#ifdef INCLUDE_IM_cyrillic_translit
374 do_builtin (cyrillic_translit);
375#endif
376#ifdef INCLUDE_IM_ime
377 do_builtin (ime);
378#endif
379#ifdef INCLUDE_IM_inuktitut
380 do_builtin (inuktitut);
381#endif
382#ifdef INCLUDE_IM_ipa
383 do_builtin (ipa);
384#endif
385#ifdef INCLUDE_IM_multipress
386 do_builtin (multipress);
387#endif
388#ifdef INCLUDE_IM_thai
389 do_builtin (thai);
390#endif
391#ifdef INCLUDE_IM_ti_er
392 do_builtin (ti_er);
393#endif
394#ifdef INCLUDE_IM_ti_et
395 do_builtin (ti_et);
396#endif
397#ifdef INCLUDE_IM_viqr
398 do_builtin (viqr);
399#endif
400#ifdef INCLUDE_IM_xim
401 do_builtin (xim);
402#endif
403#ifdef INCLUDE_IM_broadway
404 do_builtin (broadway);
405#endif
406#ifdef INCLUDE_IM_wayland
407 do_builtin (wayland);
408#endif
409
410#undef do_builtin
411
412 file = g_fopenfopen (filename, "r");
413 if (!file)
4
Assuming 'file' is non-null
414 {
415 /* In case someone wants only the default input method,
416 * we allow no file at all.
417 */
418 g_string_free (line_buf, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(line_buf), ((!(0)))) : g_string_free_and_steal (line_buf)) :
(g_string_free) ((line_buf), ((!(0)))))
;
419 g_string_free (tmp_buf, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(tmp_buf), ((!(0)))) : g_string_free_and_steal (tmp_buf)) : (
g_string_free) ((tmp_buf), ((!(0)))))
;
420 g_free (filename);
421 return;
422 }
423
424 while (!have_error
4.1
'have_error' is 0
11.1
'have_error' is 0
&& ctk_read_line (file, line_buf))
5
Loop condition is true. Entering loop body
12
Loop condition is true. Entering loop body
425 {
426 const char *p;
427
428 p = line_buf->str;
429
430 if (!ctk_skip_space (&p))
6
Assuming the condition is false
7
Taking false branch
13
Assuming the condition is false
14
Taking false branch
431 {
432 /* Blank line marking the end of a module
433 */
434 if (module && *p != '#')
435 {
436 add_module (module, infos);
437 module = NULL((void*)0);
438 infos = NULL((void*)0);
439 }
440
441 continue;
442 }
443
444 if (!module
7.1
'module' is null
14.1
'module' is non-null
)
8
Taking true branch
15
Taking false branch
445 {
446 /* Read a module location
447 */
448 module = g_object_new (CTK_TYPE_IM_MODULE(ctk_im_module_get_type ()), NULL((void*)0));
449
450 if (!ctk_scan_string (&p, tmp_buf) || ctk_skip_space (&p))
9
Assuming the condition is false
10
Assuming the condition is false
11
Taking false branch
451 {
452 g_warning ("Error parsing context info in '%s'\n %s", filename, line_buf->str);
453 have_error = TRUE(!(0));
454 }
455
456 module->path = g_strdup (tmp_buf->str)g_strdup_inline (tmp_buf->str);
457#ifdef G_OS_WIN32
458 correct_libdir_prefix (&module->path);
459#endif
460 g_type_module_set_name (G_TYPE_MODULE (module)((((GTypeModule*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((module)), ((g_type_module_get_type ()))))))
, module->path);
461 }
462 else
463 {
464 CtkIMContextInfo *info = g_new0 (CtkIMContextInfo, 1)((CtkIMContextInfo *) g_malloc0_n ((1), sizeof (CtkIMContextInfo
)))
;
16
Memory is allocated
465
466 /* Read information about a context type
467 */
468 if (!ctk_scan_string (&p, tmp_buf))
17
Assuming the condition is true
18
Taking true branch
469 goto context_error;
19
Control jumps to line 499
470 info->context_id = g_strdup (tmp_buf->str)g_strdup_inline (tmp_buf->str);
471
472 if (!ctk_scan_string (&p, tmp_buf))
473 goto context_error;
474 info->context_name = g_strdup (tmp_buf->str)g_strdup_inline (tmp_buf->str);
475
476 if (!ctk_scan_string (&p, tmp_buf))
477 goto context_error;
478 info->domain = g_strdup (tmp_buf->str)g_strdup_inline (tmp_buf->str);
479
480 if (!ctk_scan_string (&p, tmp_buf))
481 goto context_error;
482
483 info->domain_dirname = g_strdup (tmp_buf->str)g_strdup_inline (tmp_buf->str);
484#ifdef G_OS_WIN32
485 correct_localedir_prefix ((char **) &info->domain_dirname);
486#endif
487
488 if (!ctk_scan_string (&p, tmp_buf))
489 goto context_error;
490 info->default_locales = g_strdup (tmp_buf->str)g_strdup_inline (tmp_buf->str);
491
492 if (ctk_skip_space (&p))
493 goto context_error;
494
495 infos = g_slist_prepend (infos, info);
496 continue;
497
498 context_error:
499 g_warning ("Error parsing context info in '%s'\n %s", filename, line_buf->str);
20
Potential leak of memory pointed to by 'info'
500 have_error = TRUE(!(0));
501 }
502 }
503
504 if (have_error)
505 {
506 g_slist_free_full (infos, (GDestroyNotify)free_info);
507 g_object_unref (module);
508 }
509 else if (module)
510 add_module (module, infos);
511
512 fclose (file);
513 g_string_free (line_buf, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(line_buf), ((!(0)))) : g_string_free_and_steal (line_buf)) :
(g_string_free) ((line_buf), ((!(0)))))
;
514 g_string_free (tmp_buf, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(tmp_buf), ((!(0)))) : g_string_free_and_steal (tmp_buf)) : (
g_string_free) ((tmp_buf), ((!(0)))))
;
515 g_free (filename);
516}
517
518static gint
519compare_ctkimcontextinfo_name (const CtkIMContextInfo **a,
520 const CtkIMContextInfo **b)
521{
522 return g_utf8_collate ((*a)->context_name, (*b)->context_name);
523}
524
525/**
526 * _ctk_im_module_list:
527 * @contexts: location to store an array of pointers to #CtkIMContextInfo
528 * this array should be freed with g_free() when you are finished.
529 * The structures it points are statically allocated and should
530 * not be modified or freed.
531 * @n_contexts: the length of the array stored in @contexts
532 *
533 * List all available types of input method context
534 */
535void
536_ctk_im_module_list (const CtkIMContextInfo ***contexts,
537 guint *n_contexts)
538{
539 int n = 0;
540
541 static
542#ifndef G_OS_WIN32
543 const
544#endif
545 CtkIMContextInfo simple_context_info = {
546 SIMPLE_ID"ctk-im-context-simple",
547 NC_("input method menu", "Simple")("Simple"),
548 GETTEXT_PACKAGE"ctk30",
549#ifdef CTK_LOCALEDIR"/usr/share/locale"
550 CTK_LOCALEDIR"/usr/share/locale",
551#else
552 "",
553#endif
554 ""
555 };
556
557 static
558#ifndef G_OS_WIN32
559 const
560#endif
561 CtkIMContextInfo none_context_info = {
562 NONE_ID"ctk-im-context-none",
563 NC_("input method menu", "None")("None"),
564 GETTEXT_PACKAGE"ctk30",
565#ifdef CTK_LOCALEDIR"/usr/share/locale"
566 CTK_LOCALEDIR"/usr/share/locale",
567#else
568 "",
569#endif
570 ""
571 };
572
573#ifdef G_OS_WIN32
574 static gboolean beenhere = FALSE(0);
575#endif
576
577 if (!contexts_hash)
578 ctk_im_module_initialize ();
579
580#ifdef G_OS_WIN32
581 if (!beenhere)
582 {
583 beenhere = TRUE(!(0));
584 /* correct_localedir_prefix() requires its parameter to be a
585 * malloced string
586 */
587 simple_context_info.domain_dirname = g_strdup (simple_context_info.domain_dirname)g_strdup_inline (simple_context_info.domain_dirname);
588 correct_localedir_prefix ((char **) &simple_context_info.domain_dirname);
589 none_context_info.domain_dirname = g_strdup (none_context_info.domain_dirname)g_strdup_inline (none_context_info.domain_dirname);
590 correct_localedir_prefix ((char **) &none_context_info.domain_dirname);
591 }
592#endif
593
594 if (n_contexts)
595 *n_contexts = n_loaded_contexts + 2;
596
597 if (contexts)
598 {
599 GSList *tmp_list;
600 int i;
601
602 *contexts = g_new (const CtkIMContextInfo *, n_loaded_contexts + 2)((const CtkIMContextInfo * *) g_malloc_n ((n_loaded_contexts +
2), sizeof (const CtkIMContextInfo *)))
;
603
604 (*contexts)[n++] = &none_context_info;
605 (*contexts)[n++] = &simple_context_info;
606
607 tmp_list = modules_list;
608 while (tmp_list)
609 {
610 CtkIMModule *module = tmp_list->data;
611
612 for (i=0; i<module->n_contexts; i++)
613 (*contexts)[n++] = module->contexts[i];
614
615 tmp_list = tmp_list->next;
616 }
617
618 /* first elements (Simple and None) should always be at top */
619 qsort ((*contexts)+2, n-2, sizeof (CtkIMContextInfo *), (GCompareFunc)compare_ctkimcontextinfo_name);
620 }
621}
622
623/**
624 * _ctk_im_module_create:
625 * @context_id: the context ID for the context type to create
626 *
627 * Create an IM context of a type specified by the string
628 * ID @context_id.
629 *
630 * Returns: a newly created input context of or @context_id, or
631 * if that could not be created, a newly created CtkIMContextSimple.
632 */
633CtkIMContext *
634_ctk_im_module_create (const gchar *context_id)
635{
636 CtkIMModule *im_module;
637 CtkIMContext *context = NULL((void*)0);
638
639 if (strcmp (context_id, NONE_ID"ctk-im-context-none") == 0)
640 return NULL((void*)0);
641
642 if (!contexts_hash)
643 ctk_im_module_initialize ();
644
645 if (strcmp (context_id, SIMPLE_ID"ctk-im-context-simple") != 0)
646 {
647 im_module = g_hash_table_lookup (contexts_hash, context_id);
648 if (!im_module)
649 {
650 g_warning ("Attempt to load unknown IM context type '%s'", context_id);
651 }
652 else
653 {
654 if (g_type_module_use (G_TYPE_MODULE (im_module)((((GTypeModule*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((im_module)), ((g_type_module_get_type ()))))))
))
655 {
656 context = im_module->create (context_id);
657 g_type_module_unuse (G_TYPE_MODULE (im_module)((((GTypeModule*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((im_module)), ((g_type_module_get_type ()))))))
);
658 }
659
660 if (!context)
661 g_warning ("Loading IM context type '%s' failed", context_id);
662 }
663 }
664
665 if (!context)
666 return ctk_im_context_simple_new ();
667 else
668 return context;
669}
670
671/* Match @locale against @against.
672 *
673 * 'en_US' against “en_US” => 4
674 * 'en_US' against “en” => 3
675 * 'en', “en_UK” against “en_US” => 2
676 * all locales, against “*” => 1
677 */
678static gint
679match_locale (const gchar *locale,
680 const gchar *against,
681 gint against_len)
682{
683 if (strcmp (against, "*") == 0)
684 return 1;
685
686 if (g_ascii_strcasecmp (locale, against) == 0)
687 return 4;
688
689 if (g_ascii_strncasecmp (locale, against, 2) == 0)
690 return (against_len == 2) ? 3 : 2;
691
692 return 0;
693}
694
695static gboolean
696match_backend (CtkIMContextInfo *context)
697{
698#ifdef CDK_WINDOWING_WAYLAND
699 if (g_strcmp0 (context->context_id, "wayland") == 0)
700 {
701 CdkDisplay *display = cdk_display_get_default ();
702
703 return CDK_IS_WAYLAND_DISPLAY (display)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(display)); GType __t = ((cdk_wayland_display_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
&&
704 cdk_wayland_display_query_registry (display,
705 "zwp_text_input_manager_v3");
706 }
707 if (g_strcmp0 (context->context_id, "waylandctk") == 0)
708 {
709 CdkDisplay *display = cdk_display_get_default ();
710
711 return CDK_IS_WAYLAND_DISPLAY (display)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(display)); GType __t = ((cdk_wayland_display_get_type())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
&&
712 cdk_wayland_display_query_registry (display,
713 "ctk_text_input_manager");
714 }
715#endif
716
717#ifdef CDK_WINDOWING_BROADWAY
718 if (g_strcmp0 (context->context_id, "broadway") == 0)
719 return CDK_IS_BROADWAY_DISPLAY (cdk_display_get_default ())(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(cdk_display_get_default ())); GType __t = ((cdk_broadway_display_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
;
720#endif
721
722#ifdef CDK_WINDOWING_X11
723 if (g_strcmp0 (context->context_id, "xim") == 0)
724 return CDK_IS_X11_DISPLAY (cdk_display_get_default ())(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(cdk_display_get_default ())); GType __t = ((cdk_x11_display_get_type
())); gboolean __r; if (!__inst) __r = (0); else if (__inst->
g_class && __inst->g_class->g_type == __t) __r =
(!(0)); else __r = g_type_check_instance_is_a (__inst, __t);
__r; }))))
;
725#endif
726
727#ifdef CDK_WINDOWING_WIN32
728 if (g_strcmp0 (context->context_id, "ime") == 0)
729 return CDK_IS_WIN32_DISPLAY (cdk_display_get_default ());
730#endif
731
732 return TRUE(!(0));
733}
734
735static const gchar *
736lookup_immodule (gchar **immodules_list)
737{
738 while (immodules_list && *immodules_list)
739 {
740 if (g_strcmp0 (*immodules_list, SIMPLE_ID"ctk-im-context-simple") == 0)
741 return SIMPLE_ID"ctk-im-context-simple";
742 else if (g_strcmp0 (*immodules_list, NONE_ID"ctk-im-context-none") == 0)
743 return NONE_ID"ctk-im-context-none";
744 else
745 {
746 gboolean found;
747 gchar *context_id;
748 found = g_hash_table_lookup_extended (contexts_hash, *immodules_list,
749 (gpointer *) &context_id, NULL((void*)0));
750 if (found)
751 return context_id;
752 }
753 immodules_list++;
754 }
755
756 return NULL((void*)0);
757}
758
759#ifdef G_OS_WIN32
760
761/* max size for LOCALE_SISO639LANGNAME and LOCALE_SISO3166CTRYNAME is 9 */
762#define MAX_NAME_SIZE 9
763
764static gchar *
765get_current_input_language (void)
766{
767 LCID lcid;
768 LANGID langid;
769 HKL kblayout;
770 int name_size;
771 wchar_t name[MAX_NAME_SIZE];
772 gchar *language;
773 gchar *country;
774 gchar *full;
775
776 /* Current thread's keyboard layout */
777 kblayout = GetKeyboardLayout(0);
778 /* lowest word in the HKL is the LANGID */
779 langid = LOWORD (kblayout);
780 /* LCID is the LANGID without order */
781 lcid = langid;
782
783 /* Get Language ID */
784 name_size = GetLocaleInfoW (lcid, LOCALE_SISO639LANGNAME, NULL((void*)0), 0);
785 if (name_size <= 1)
786 return NULL((void*)0);
787
788 g_assert (name_size <= MAX_NAME_SIZE)do { if (name_size <= MAX_NAME_SIZE) ; else g_assertion_message_expr
("Ctk", "ctkimmodule.c", 788, ((const char*) (__func__)), "name_size <= MAX_NAME_SIZE"
); } while (0)
;
789 GetLocaleInfoW (lcid, LOCALE_SISO639LANGNAME, name, name_size);
790
791 language = g_utf16_to_utf8 (name, name_size, NULL((void*)0), NULL((void*)0), NULL((void*)0));
792 if (!language)
793 return NULL((void*)0);
794
795 if (SUBLANGID (langid) == SUBLANG_NEUTRAL)
796 return language;
797
798 /* Get Country ID */
799 name_size = GetLocaleInfoW (lcid, LOCALE_SISO3166CTRYNAME, NULL((void*)0), 0);
800 if (name_size <= 1)
801 return language;
802
803 g_assert (name_size <= MAX_NAME_SIZE)do { if (name_size <= MAX_NAME_SIZE) ; else g_assertion_message_expr
("Ctk", "ctkimmodule.c", 803, ((const char*) (__func__)), "name_size <= MAX_NAME_SIZE"
); } while (0)
;
804 GetLocaleInfoW (lcid, LOCALE_SISO3166CTRYNAME, name, name_size);
805
806 country = g_utf16_to_utf8 (name, name_size, NULL((void*)0), NULL((void*)0), NULL((void*)0));
807 if (!country)
808 return language;
809
810 full = g_strdup_printf ("%s_%s", language, country);
811
812 g_free (language);
813 g_free (country);
814
815 return full;
816}
817
818#endif
819
820/**
821 * _ctk_im_module_get_default_context_id:
822 *
823 * Return the context_id of the best IM context type
824 * for the given window.
825 *
826 * Returns: the context ID (will never be %NULL)
827 */
828const gchar *
829_ctk_im_module_get_default_context_id (void)
830{
831 GSList *tmp_list;
832 const gchar *context_id = NULL((void*)0);
833 gint best_goodness = 0;
834 gint i;
835 gchar *tmp_locale, *tmp, **immodules;
836 const gchar *envvar;
837 CdkScreen *screen;
838 CtkSettings *settings;
839
840 if (!contexts_hash)
1
Assuming 'contexts_hash' is null
2
Taking true branch
841 ctk_im_module_initialize ();
3
Calling 'ctk_im_module_initialize'
842
843 envvar = g_getenv ("CTK_IM_MODULE");
844 if (envvar)
845 {
846 immodules = g_strsplit (envvar, ":", 0);
847 context_id = lookup_immodule (immodules);
848 g_strfreev (immodules);
849
850 if (context_id)
851 return context_id;
852 }
853
854 /* Check if the certain immodule is set in XSETTINGS.
855 */
856 screen = cdk_screen_get_default ();
857 settings = ctk_settings_get_for_screen (screen);
858 g_object_get (G_OBJECT (settings)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((settings)), (((GType) ((20) << (2))))))))
, "ctk-im-module", &tmp, NULL((void*)0));
859 if (tmp)
860 {
861 immodules = g_strsplit (tmp, ":", 0);
862 context_id = lookup_immodule (immodules);
863 g_strfreev (immodules);
864 g_free (tmp);
865
866 if (context_id)
867 return context_id;
868 }
869
870#ifdef G_OS_WIN32
871 /* Read current input locale from the current keyboard info */
872 tmp_locale = get_current_input_language ();
873 if (!tmp_locale)
874 /* Default to system locale when input language is unknown */
875 tmp_locale = _ctk_get_lc_ctype ();
876#else
877 tmp_locale = _ctk_get_lc_ctype ();
878#endif
879
880 /* Strip the locale code down to the essentials
881 */
882 tmp = strchr (tmp_locale, '.');
883 if (tmp)
884 *tmp = '\0';
885 tmp = strchr (tmp_locale, '@');
886 if (tmp)
887 *tmp = '\0';
888
889 tmp_list = modules_list;
890 while (tmp_list)
891 {
892 CtkIMModule *module = tmp_list->data;
893
894 for (i = 0; i < module->n_contexts; i++)
895 {
896 const gchar *p;
897
898 if (!match_backend (module->contexts[i]))
899 continue;
900
901 p = module->contexts[i]->default_locales;
902 while (p)
903 {
904 const gchar *q = strchr (p, ':');
905 gint goodness = match_locale (tmp_locale, p, q ? q - p : strlen (p));
906
907 if (goodness > best_goodness)
908 {
909 context_id = module->contexts[i]->context_id;
910 best_goodness = goodness;
911 }
912
913 p = q ? q + 1 : NULL((void*)0);
914 }
915 }
916
917 tmp_list = tmp_list->next;
918 }
919
920 g_free (tmp_locale);
921
922 return context_id ? context_id : SIMPLE_ID"ctk-im-context-simple";
923}