Bug Summary

File:plugins/spell/lapiz-spell-checker-language.c
Warning:line 194, column 8
true and false branches are identical

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 lapiz-spell-checker-language.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/plugins/spell -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I ../.. -I ../.. -I /usr/include/libxml2 -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/libmount -I /usr/include/blkid -I /usr/include/ctk-3.0 -I /usr/include/pango-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -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/local/include/ctksourceview-4 -I /usr/local/include/libbean-1.0 -I /usr/include/gobject-introspection-1.0 -I /usr/include/enchant-2 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -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/13/../../../../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/plugins/spell -ferror-limit 19 -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-08-07-113623-33852-1 -x c lapiz-spell-checker-language.c
1/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2/*
3 * lapiz-spell-checker-language.c
4 * This file is part of lapiz
5 *
6 * Copyright (C) 2006 Paolo Maggi
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24/*
25 * Modified by the lapiz Team, 2006. See the AUTHORS file for a
26 * list of people on the lapiz Team.
27 * See the ChangeLog files for a list of changes.
28 */
29
30/* Part of the code taked from Epiphany.
31 *
32 * Copyright (C) 2003, 2004 Christian Persch
33 */
34
35#ifdef HAVE_CONFIG_H1
36#include <config.h>
37#endif
38
39#include <string.h>
40
41#include <enchant.h>
42
43#include <glib/gi18n.h>
44#include <libxml/xmlreader.h>
45
46#include "lapiz-spell-checker-language.h"
47
48#include <lapiz/lapiz-debug.h>
49
50#define ISO_639_DOMAIN"iso_639" "iso_639"
51#define ISO_3166_DOMAIN"iso_3166" "iso_3166"
52
53#define ISOCODESLOCALEDIR"/usr" "/share/locale" ISO_CODES_PREFIX"/usr" "/share/locale"
54
55struct _LapizSpellCheckerLanguage
56{
57 gchar *abrev;
58 gchar *name;
59};
60
61static gboolean available_languages_initialized = FALSE(0);
62static GSList *available_languages = NULL((void*)0);
63
64static GHashTable *iso_639_table = NULL((void*)0);
65static GHashTable *iso_3166_table = NULL((void*)0);
66
67static void
68bind_iso_domains (void)
69{
70 static gboolean bound = FALSE(0);
71
72 if (bound == FALSE(0))
73 {
74 bindtextdomain (ISO_639_DOMAIN"iso_639", ISOCODESLOCALEDIR"/usr" "/share/locale");
75 bind_textdomain_codeset (ISO_639_DOMAIN"iso_639", "UTF-8");
76
77 bindtextdomain(ISO_3166_DOMAIN"iso_3166", ISOCODESLOCALEDIR"/usr" "/share/locale");
78 bind_textdomain_codeset (ISO_3166_DOMAIN"iso_3166", "UTF-8");
79
80 bound = TRUE(!(0));
81 }
82}
83
84static void
85read_iso_639_entry (xmlTextReaderPtr reader,
86 GHashTable *table)
87{
88 xmlChar *code, *name;
89
90 code = xmlTextReaderGetAttribute (reader, (const xmlChar *) "iso_639_1_code");
91 name = xmlTextReaderGetAttribute (reader, (const xmlChar *) "name");
92
93 /* Get iso-639-2 code */
94 if (code == NULL((void*)0) || code[0] == '\0')
95 {
96 xmlFree (code);
97 /* FIXME: use the 2T or 2B code? */
98 code = xmlTextReaderGetAttribute (reader, (const xmlChar *) "iso_639_2T_code");
99 }
100
101 if (code != NULL((void*)0) && code[0] != '\0' && name != NULL((void*)0) && name[0] != '\0')
102 {
103 g_hash_table_insert (table, code, name);
104 }
105 else
106 {
107 xmlFree (code);
108 xmlFree (name);
109 }
110}
111
112static void
113read_iso_3166_entry (xmlTextReaderPtr reader,
114 GHashTable *table)
115{
116 xmlChar *code, *name;
117
118 code = xmlTextReaderGetAttribute (reader, (const xmlChar *) "alpha_2_code");
119 name = xmlTextReaderGetAttribute (reader, (const xmlChar *) "name");
120
121 if (code != NULL((void*)0) && code[0] != '\0' && name != NULL((void*)0) && name[0] != '\0')
122 {
123 char *lcode;
124
125 lcode = g_ascii_strdown ((char *) code, -1);
126 xmlFree (code);
127
128 /* g_print ("%s -> %s\n", lcode, name); */
129
130 g_hash_table_insert (table, lcode, name);
131 }
132 else
133 {
134 xmlFree (code);
135 xmlFree (name);
136 }
137}
138
139typedef enum
140{
141 STATE_START,
142 STATE_STOP,
143 STATE_ENTRIES,
144} ParserState;
145
146static void
147load_iso_entries (int iso,
148 GFunc read_entry_func,
149 gpointer user_data)
150{
151 xmlTextReaderPtr reader;
152 ParserState state = STATE_START;
153 xmlChar iso_entries[32], iso_entry[32];
154 char *filename;
155 int ret = -1;
156
157 lapiz_debug_message (DEBUG_PLUGINSLAPIZ_DEBUG_PLUGINS, "lapiz-spell-checker-language.c", 157, (
(const char*) (__func__))
, "Loading ISO-%d codes", iso);
158
159 filename = g_strdup_printf (ISO_CODES_PREFIX"/usr" "/share/xml/iso-codes/iso_%d.xml", iso);
160 reader = xmlNewTextReaderFilename (filename);
161 if (reader == NULL((void*)0)) goto out;
162
163 xmlStrPrintf (iso_entries, sizeof (iso_entries), (const char *)"iso_%d_entries", iso);
164 xmlStrPrintf (iso_entry, sizeof (iso_entry), (const char *)"iso_%d_entry", iso);
165
166 ret = xmlTextReaderRead (reader);
167
168 while (ret == 1)
169 {
170 const xmlChar *tag;
171 xmlReaderTypes type;
172
173 tag = xmlTextReaderConstName (reader);
174 type = xmlTextReaderNodeType (reader);
175
176 if (state == STATE_ENTRIES &&
177 type == XML_READER_TYPE_ELEMENT &&
178 xmlStrEqual (tag, iso_entry))
179 {
180 read_entry_func (reader, user_data);
181 }
182 else if (state == STATE_START &&
183 type == XML_READER_TYPE_ELEMENT &&
184 xmlStrEqual (tag, iso_entries))
185 {
186 state = STATE_ENTRIES;
187 }
188 else if (state == STATE_ENTRIES &&
189 type == XML_READER_TYPE_END_ELEMENT &&
190 xmlStrEqual (tag, iso_entries))
191 {
192 state = STATE_STOP;
193 }
194 else if (type == XML_READER_TYPE_SIGNIFICANT_WHITESPACE ||
true and false branches are identical
195 type == XML_READER_TYPE_WHITESPACE ||
196 type == XML_READER_TYPE_TEXT ||
197 type == XML_READER_TYPE_COMMENT)
198 {
199 /* eat it */
200 }
201 else
202 {
203 /* ignore it */
204 }
205
206 ret = xmlTextReaderRead (reader);
207 }
208
209 xmlFreeTextReader (reader);
210
211out:
212 if (ret < 0 || state != STATE_STOP)
213 {
214 g_warning ("Failed to load ISO-%d codes from %s!\n",
215 iso, filename);
216 }
217
218 g_free (filename);
219}
220
221static GHashTable *
222create_iso_639_table (void)
223{
224 GHashTable *table;
225
226 bind_iso_domains ();
227 table = g_hash_table_new_full (g_str_hash, g_str_equal,
228 (GDestroyNotify) xmlFree,
229 (GDestroyNotify) xmlFree);
230
231 load_iso_entries (639, (GFunc) read_iso_639_entry, table);
232
233 return table;
234}
235
236static GHashTable *
237create_iso_3166_table (void)
238{
239 GHashTable *table;
240
241 bind_iso_domains ();
242 table = g_hash_table_new_full (g_str_hash, g_str_equal,
243 (GDestroyNotify) g_free,
244 (GDestroyNotify) xmlFree);
245
246 load_iso_entries (3166, (GFunc) read_iso_3166_entry, table);
247
248 return table;
249}
250
251static char *
252create_name_for_language (const char *code)
253{
254 char **str;
255 char *name = NULL((void*)0);
256 const char *langname;
257 int len;
258
259 g_return_val_if_fail (iso_639_table != NULL, NULL)do { if ((iso_639_table != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "iso_639_table != NULL"
); return (((void*)0)); } } while (0)
;
260 g_return_val_if_fail (iso_3166_table != NULL, NULL)do { if ((iso_3166_table != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "iso_3166_table != NULL"
); return (((void*)0)); } } while (0)
;
261
262 str = g_strsplit (code, "_", -1);
263 len = g_strv_length (str);
264 g_return_val_if_fail (len != 0, NULL)do { if ((len != 0)) { } else { g_return_if_fail_warning (((gchar
*) 0), ((const char*) (__func__)), "len != 0"); return (((void
*)0)); } } while (0)
;
265
266 langname = (const char *) g_hash_table_lookup (iso_639_table, str[0]);
267
268 if (len == 1 && langname != NULL((void*)0))
269 {
270 name = g_strdup (dgettext (ISO_639_DOMAIN, langname))g_strdup_inline (dgettext ("iso_639", langname));
271 }
272 else if (len == 2 && langname != NULL((void*)0))
273 {
274 const char *localename;
275
276 gchar *locale_code = g_ascii_strdown (str[1], -1);
277
278 localename = (const char *) g_hash_table_lookup (iso_3166_table, locale_code);
279 g_free (locale_code);
280
281 if (localename != NULL((void*)0))
282 {
283 /* Translators: the first %s is the language name, and
284 * the second %s is the locale name. Example:
285 * "French (France)"
286 */
287 name = g_strdup_printf (C_("language", "%s (%s)")g_dpgettext (((void*)0), "language" "\004" "%s (%s)", strlen (
"language") + 1)
,
288 dgettext (ISO_639_DOMAIN"iso_639", langname),
289 dgettext (ISO_3166_DOMAIN"iso_3166", localename));
290 }
291 else
292 {
293 name = g_strdup_printf (C_("language", "%s (%s)")g_dpgettext (((void*)0), "language" "\004" "%s (%s)", strlen (
"language") + 1)
,
294 dgettext (ISO_639_DOMAIN"iso_639", langname), str[1]);
295 }
296 }
297 else
298 {
299 /* Translators: this refers to an unknown language code
300 * (one which isn't in our built-in list).
301 */
302 name = g_strdup_printf (C_("language", "Unknown (%s)")g_dpgettext (((void*)0), "language" "\004" "Unknown (%s)", strlen
("language") + 1)
, code);
303 }
304
305 g_strfreev (str);
306
307 return name;
308}
309
310static void
311enumerate_dicts (const char * const lang_tag,
312 const char * const provider_name G_GNUC_UNUSED__attribute__ ((__unused__)),
313 const char * const provider_desc G_GNUC_UNUSED__attribute__ ((__unused__)),
314 const char * const provider_file G_GNUC_UNUSED__attribute__ ((__unused__)),
315 void * user_data)
316{
317 gchar *lang_name;
318
319 GTree *dicts = (GTree *)user_data;
320
321 lang_name = create_name_for_language (lang_tag);
322 g_return_if_fail (lang_name != NULL)do { if ((lang_name != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "lang_name != NULL"
); return; } } while (0)
;
323
324 /* g_print ("%s - %s\n", lang_tag, lang_name); */
325
326 g_tree_replace (dicts, g_strdup (lang_tag)g_strdup_inline (lang_tag), lang_name);
327}
328
329static gint
330key_cmp (gconstpointer a,
331 gconstpointer b,
332 gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__)))
333{
334 return strcmp (a, b);
335}
336
337static gint
338lang_cmp (const LapizSpellCheckerLanguage *a,
339 const LapizSpellCheckerLanguage *b)
340{
341 return g_utf8_collate (a->name, b->name);
342}
343
344static gboolean
345build_langs_list (const gchar *key,
346 const gchar *value,
347 gpointer data G_GNUC_UNUSED__attribute__ ((__unused__)))
348{
349 LapizSpellCheckerLanguage *lang = g_new (LapizSpellCheckerLanguage, 1)((LapizSpellCheckerLanguage *) g_malloc_n ((1), sizeof (LapizSpellCheckerLanguage
)))
;
350
351 lang->abrev = g_strdup (key)g_strdup_inline (key);
352 lang->name = g_strdup (value)g_strdup_inline (value);
353
354 available_languages = g_slist_insert_sorted (available_languages,
355 lang,
356 (GCompareFunc)lang_cmp);
357
358 return FALSE(0);
359}
360
361const GSList *
362lapiz_spell_checker_get_available_languages (void)
363{
364 EnchantBroker *broker;
365 GTree *dicts;
366
367 if (available_languages_initialized)
368 return available_languages;
369
370 g_return_val_if_fail (available_languages == NULL, NULL)do { if ((available_languages == ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "available_languages == NULL"
); return (((void*)0)); } } while (0)
;
371
372 available_languages_initialized = TRUE(!(0));
373
374 broker = enchant_broker_init ();
375 g_return_val_if_fail (broker != NULL, NULL)do { if ((broker != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "broker != NULL")
; return (((void*)0)); } } while (0)
;
376
377 /* Use a GTree to efficiently remove duplicates while building the list */
378 dicts = g_tree_new_full (key_cmp,
379 NULL((void*)0),
380 (GDestroyNotify)g_free,
381 (GDestroyNotify)g_free);
382
383 iso_639_table = create_iso_639_table ();
384 iso_3166_table = create_iso_3166_table ();
385
386 enchant_broker_list_dicts (broker, enumerate_dicts, dicts);
387
388 enchant_broker_free (broker);
389
390 g_hash_table_destroy (iso_639_table);
391 g_hash_table_destroy (iso_3166_table);
392
393 iso_639_table = NULL((void*)0);
394 iso_3166_table = NULL((void*)0);
395
396 g_tree_foreach (dicts, (GTraverseFunc)build_langs_list, NULL((void*)0));
397
398 g_tree_destroy (dicts);
399
400 return available_languages;
401}
402
403const gchar *
404lapiz_spell_checker_language_to_string (const LapizSpellCheckerLanguage *lang)
405{
406 if (lang == NULL((void*)0))
407 /* Translators: this refers the Default language used by the
408 * spell checker
409 */
410 return C_("language", "Default")g_dpgettext (((void*)0), "language" "\004" "Default", strlen (
"language") + 1)
;
411
412 return lang->name;
413}
414
415const gchar *
416lapiz_spell_checker_language_to_key (const LapizSpellCheckerLanguage *lang)
417{
418 g_return_val_if_fail (lang != NULL, NULL)do { if ((lang != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "lang != NULL"); return
(((void*)0)); } } while (0)
;
419
420 return lang->abrev;
421}
422
423const LapizSpellCheckerLanguage *
424lapiz_spell_checker_language_from_key (const gchar *key)
425{
426 const GSList *langs;
427
428 g_return_val_if_fail (key != NULL, NULL)do { if ((key != ((void*)0))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "key != NULL"); return
(((void*)0)); } } while (0)
;
429
430 langs = lapiz_spell_checker_get_available_languages ();
431
432 while (langs != NULL((void*)0))
433 {
434 const LapizSpellCheckerLanguage *l = (const LapizSpellCheckerLanguage *)langs->data;
435
436 if (g_ascii_strcasecmp (key, l->abrev) == 0)
437 return l;
438
439 langs = g_slist_next (langs)((langs) ? (((GSList *)(langs))->next) : ((void*)0));
440 }
441
442 return NULL((void*)0);
443}