Bug Summary

File:_build/../ctksourceview/ctksourceutils.c
Warning:line 727, column 3
Value stored to 'scroll_dest' is never read

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 ctksourceutils.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=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/rootdir/_build -fcoverage-compilation-dir=/rootdir/_build -resource-dir /usr/lib/llvm-19/lib/clang/19 -I ctksourceview/libctksourceview-4core.a.p -I ctksourceview -I ../ctksourceview -I . -I .. -I /usr/include/fribidi -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/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/include/libxml2 -D _FILE_OFFSET_BITS=64 -D G_DISABLE_DEPRECATED -D CDK_DISABLE_DEPRECATED -D CTK_DISABLE_DEPRECATED -D GDK_PIXBUF_DISABLE_DEPRECATED -D CDK_VERSION_MIN_REQUIRED=CDK_VERSION_3_24 -D CDK_VERSION_MAX_ALLOWED=CDK_VERSION_3_24 -D GLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_48 -D GLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_48 -D HAVE_CONFIG_H -D CTK_SOURCE_COMPILATION -D G_LOG_DOMAIN="CtkSourceView" -internal-isystem /usr/lib/llvm-19/lib/clang/19/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 -O2 -Wno-cast-function-type -Wno-missing-field-initializers -Wno-sign-compare -Wno-unused-parameter -std=gnu99 -ferror-limit 19 -stack-protector 2 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcolor-diagnostics -vectorize-loops -vectorize-slp -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.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/2025-07-20-153142-14238-1 -x c ../ctksourceview/ctksourceutils.c
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*- */
2/*
3 * This file is part of CtkSourceView
4 *
5 * Copyright (C) 2005 - Paolo Borelli
6 * Copyright (C) 2007 - Gustavo Giráldez
7 * Copyright (C) 2007 - Paolo Maggi
8 * Copyright (C) 2013, 2017 - Sébastien Wilmet <swilmet@gnome.org>
9 *
10 * CtkSourceView is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * CtkSourceView is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this library; if not, see <http://www.gnu.org/licenses/>.
22 */
23
24/**
25 * SECTION:utils
26 * @title: CtkSourceUtils
27 * @short_description: Utility functions
28 *
29 * Utility functions.
30 */
31
32#ifdef HAVE_CONFIG_H1
33#include <config.h>
34#endif
35
36#include "ctksourceutils.h"
37#include "ctksourceutils-private.h"
38#include <string.h>
39#include <errno(*__errno_location ()).h>
40#include <math.h>
41#include <glib/gi18n-lib.h>
42
43/**
44 * ctk_source_utils_unescape_search_text:
45 * @text: the text to unescape.
46 *
47 * Use this function before ctk_source_search_settings_set_search_text(), to
48 * unescape the following sequences of characters: `\n`, `\r`, `\t` and `\\`.
49 * The purpose is to easily write those characters in a search entry.
50 *
51 * Note that unescaping the search text is not needed for regular expression
52 * searches.
53 *
54 * See also: ctk_source_utils_escape_search_text().
55 *
56 * Returns: the unescaped @text.
57 * Since: 3.10
58 */
59gchar *
60ctk_source_utils_unescape_search_text (const gchar *text)
61{
62 GString *str;
63 gint length;
64 gboolean drop_prev = FALSE(0);
65 const gchar *cur;
66 const gchar *end;
67 const gchar *prev;
68
69 if (text == NULL((void*)0))
70 {
71 return NULL((void*)0);
72 }
73
74 length = strlen (text);
75
76 str = g_string_new ("");
77
78 cur = text;
79 end = text + length;
80 prev = NULL((void*)0);
81
82 while (cur != end)
83 {
84 const gchar *next;
85 next = g_utf8_next_char (cur)((cur) + g_utf8_skip[*(const guchar *)(cur)]);
86
87 if (prev && (*prev == '\\'))
88 {
89 switch (*cur)
90 {
91 case 'n':
92 str = g_string_append (str, "\n")(__builtin_constant_p ("\n") ? __extension__ ({ const char * const
__val = ("\n"); g_string_append_len_inline (str, __val, (__builtin_expect
(__extension__ ({ int _g_boolean_var_51 = 0; if (__val != ((
void*)0)) _g_boolean_var_51 = 1; _g_boolean_var_51; }), 1)) ?
(gssize) strlen (((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(str, "\n", (gssize) -1))
;
93 break;
94 case 'r':
95 str = g_string_append (str, "\r")(__builtin_constant_p ("\r") ? __extension__ ({ const char * const
__val = ("\r"); g_string_append_len_inline (str, __val, (__builtin_expect
(__extension__ ({ int _g_boolean_var_52 = 0; if (__val != ((
void*)0)) _g_boolean_var_52 = 1; _g_boolean_var_52; }), 1)) ?
(gssize) strlen (((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(str, "\r", (gssize) -1))
;
96 break;
97 case 't':
98 str = g_string_append (str, "\t")(__builtin_constant_p ("\t") ? __extension__ ({ const char * const
__val = ("\t"); g_string_append_len_inline (str, __val, (__builtin_expect
(__extension__ ({ int _g_boolean_var_53 = 0; if (__val != ((
void*)0)) _g_boolean_var_53 = 1; _g_boolean_var_53; }), 1)) ?
(gssize) strlen (((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(str, "\t", (gssize) -1))
;
99 break;
100 case '\\':
101 str = g_string_append (str, "\\")(__builtin_constant_p ("\\") ? __extension__ ({ const char * const
__val = ("\\"); g_string_append_len_inline (str, __val, (__builtin_expect
(__extension__ ({ int _g_boolean_var_54 = 0; if (__val != ((
void*)0)) _g_boolean_var_54 = 1; _g_boolean_var_54; }), 1)) ?
(gssize) strlen (((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(str, "\\", (gssize) -1))
;
102 drop_prev = TRUE(!(0));
103 break;
104 default:
105 str = g_string_append (str, "\\")(__builtin_constant_p ("\\") ? __extension__ ({ const char * const
__val = ("\\"); g_string_append_len_inline (str, __val, (__builtin_expect
(__extension__ ({ int _g_boolean_var_55 = 0; if (__val != ((
void*)0)) _g_boolean_var_55 = 1; _g_boolean_var_55; }), 1)) ?
(gssize) strlen (((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(str, "\\", (gssize) -1))
;
106 str = g_string_append_len (str, cur, next - cur)g_string_append_len_inline (str, cur, next - cur);
107 break;
108 }
109 }
110 else if (*cur != '\\')
111 {
112 str = g_string_append_len (str, cur, next - cur)g_string_append_len_inline (str, cur, next - cur);
113 }
114 else if ((next == end) && (*cur == '\\'))
115 {
116 str = g_string_append (str, "\\")(__builtin_constant_p ("\\") ? __extension__ ({ const char * const
__val = ("\\"); g_string_append_len_inline (str, __val, (__builtin_expect
(__extension__ ({ int _g_boolean_var_56 = 0; if (__val != ((
void*)0)) _g_boolean_var_56 = 1; _g_boolean_var_56; }), 1)) ?
(gssize) strlen (((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline
(str, "\\", (gssize) -1))
;
117 }
118
119 if (!drop_prev)
120 {
121 prev = cur;
122 }
123 else
124 {
125 prev = NULL((void*)0);
126 drop_prev = FALSE(0);
127 }
128
129 cur = next;
130 }
131
132 return g_string_free (str, FALSE(0));
133}
134
135/**
136 * ctk_source_utils_escape_search_text:
137 * @text: the text to escape.
138 *
139 * Use this function to escape the following characters: `\n`, `\r`, `\t` and `\`.
140 *
141 * For a regular expression search, use g_regex_escape_string() instead.
142 *
143 * One possible use case is to take the #CtkTextBuffer's selection and put it in a
144 * search entry. The selection can contain tabulations, newlines, etc. So it's
145 * better to escape those special characters to better fit in the search entry.
146 *
147 * See also: ctk_source_utils_unescape_search_text().
148 *
149 * <warning>
150 * Warning: the escape and unescape functions are not reciprocal! For example,
151 * escape (unescape (\)) = \\. So avoid cycles such as: search entry -> unescape
152 * -> search settings -> escape -> search entry. The original search entry text
153 * may be modified.
154 * </warning>
155 *
156 * Returns: the escaped @text.
157 * Since: 3.10
158 */
159gchar *
160ctk_source_utils_escape_search_text (const gchar* text)
161{
162 GString *str;
163 gint length;
164 const gchar *p;
165 const gchar *end;
166
167 if (text == NULL((void*)0))
168 {
169 return NULL((void*)0);
170 }
171
172 length = strlen (text);
173
174 str = g_string_new ("");
175
176 p = text;
177 end = text + length;
178
179 while (p != end)
180 {
181 const gchar *next = g_utf8_next_char (p)((p) + g_utf8_skip[*(const guchar *)(p)]);
182
183 switch (*p)
184 {
185 case '\n':
186 g_string_append (str, "\\n")(__builtin_constant_p ("\\n") ? __extension__ ({ const char *
const __val = ("\\n"); g_string_append_len_inline (str, __val
, (__builtin_expect (__extension__ ({ int _g_boolean_var_57 =
0; if (__val != ((void*)0)) _g_boolean_var_57 = 1; _g_boolean_var_57
; }), 1)) ? (gssize) strlen (((__val) + !(__val))) : (gssize)
-1); }) : g_string_append_len_inline (str, "\\n", (gssize) -
1))
;
187 break;
188 case '\r':
189 g_string_append (str, "\\r")(__builtin_constant_p ("\\r") ? __extension__ ({ const char *
const __val = ("\\r"); g_string_append_len_inline (str, __val
, (__builtin_expect (__extension__ ({ int _g_boolean_var_58 =
0; if (__val != ((void*)0)) _g_boolean_var_58 = 1; _g_boolean_var_58
; }), 1)) ? (gssize) strlen (((__val) + !(__val))) : (gssize)
-1); }) : g_string_append_len_inline (str, "\\r", (gssize) -
1))
;
190 break;
191 case '\t':
192 g_string_append (str, "\\t")(__builtin_constant_p ("\\t") ? __extension__ ({ const char *
const __val = ("\\t"); g_string_append_len_inline (str, __val
, (__builtin_expect (__extension__ ({ int _g_boolean_var_59 =
0; if (__val != ((void*)0)) _g_boolean_var_59 = 1; _g_boolean_var_59
; }), 1)) ? (gssize) strlen (((__val) + !(__val))) : (gssize)
-1); }) : g_string_append_len_inline (str, "\\t", (gssize) -
1))
;
193 break;
194 case '\\':
195 g_string_append (str, "\\\\")(__builtin_constant_p ("\\\\") ? __extension__ ({ const char *
const __val = ("\\\\"); g_string_append_len_inline (str, __val
, (__builtin_expect (__extension__ ({ int _g_boolean_var_60 =
0; if (__val != ((void*)0)) _g_boolean_var_60 = 1; _g_boolean_var_60
; }), 1)) ? (gssize) strlen (((__val) + !(__val))) : (gssize)
-1); }) : g_string_append_len_inline (str, "\\\\", (gssize) -
1))
;
196 break;
197 default:
198 g_string_append_len (str, p, next - p)g_string_append_len_inline (str, p, next - p);
199 break;
200 }
201
202 p = next;
203 }
204
205 return g_string_free (str, FALSE(0));
206}
207
208#define GSV_DATA_SUBDIR"ctksourceview-" "4" "ctksourceview-" GSV_API_VERSION_S"4"
209
210gchar **
211_ctk_source_utils_get_default_dirs (const gchar *basename)
212{
213 const gchar * const *system_dirs;
214 GPtrArray *dirs;
215
216 dirs = g_ptr_array_new ();
217
218 /* User dir */
219 g_ptr_array_add (dirs, g_build_filename (g_get_user_data_dir (),
220 GSV_DATA_SUBDIR"ctksourceview-" "4",
221 basename,
222 NULL((void*)0)));
223
224 /* System dirs */
225 for (system_dirs = g_get_system_data_dirs ();
226 system_dirs != NULL((void*)0) && *system_dirs != NULL((void*)0);
227 system_dirs++)
228 {
229 g_ptr_array_add (dirs, g_build_filename (*system_dirs,
230 GSV_DATA_SUBDIR"ctksourceview-" "4",
231 basename,
232 NULL((void*)0)));
233 }
234
235 g_ptr_array_add (dirs, NULL((void*)0));
236
237 return (gchar **) g_ptr_array_free (dirs, FALSE(0));
238}
239
240static GSList *
241build_file_listing (const gchar *item,
242 GSList *filenames,
243 const gchar *suffix,
244 gboolean only_dirs)
245{
246 GDir *dir;
247 const gchar *name;
248
249 if (!only_dirs && g_file_test (item, G_FILE_TEST_IS_REGULAR))
250 {
251 filenames = g_slist_prepend (filenames, g_strdup(item)g_strdup_inline (item));
252 return filenames;
253
254 }
255 dir = g_dir_open (item, 0, NULL((void*)0));
256
257 if (dir == NULL((void*)0))
258 {
259 return filenames;
260 }
261
262 while ((name = g_dir_read_name (dir)) != NULL((void*)0))
263 {
264 gchar *full_path = g_build_filename (item, name, NULL((void*)0));
265
266 if (!g_file_test (full_path, G_FILE_TEST_IS_DIR) &&
267 g_str_has_suffix (name, suffix)(__builtin_constant_p (suffix)? __extension__ ({ const char *
const __str = (name); const char * const __suffix = (suffix)
; gboolean __result = (0); if (__builtin_expect (__extension__
({ int _g_boolean_var_61 = 0; if (__str == ((void*)0) || __suffix
== ((void*)0)) _g_boolean_var_61 = 1; _g_boolean_var_61; }),
0)) __result = (g_str_has_suffix) (__str, __suffix); else { const
size_t __str_len = strlen (((__str) + !(__str))); const size_t
__suffix_len = strlen (((__suffix) + !(__suffix))); if (__str_len
>= __suffix_len) __result = memcmp (__str + __str_len - __suffix_len
, ((__suffix) + !(__suffix)), __suffix_len) == 0; } __result;
}) : (g_str_has_suffix) (name, suffix) )
)
268 {
269 filenames = g_slist_prepend (filenames, full_path);
270 }
271 else
272 {
273 g_free (full_path);
274 }
275 }
276
277 g_dir_close (dir);
278
279 return filenames;
280}
281
282GSList *
283_ctk_source_utils_get_file_list (gchar **path,
284 const gchar *suffix,
285 gboolean only_dirs)
286{
287 GSList *files = NULL((void*)0);
288
289 for ( ; path && *path; ++path)
290 {
291 files = build_file_listing (*path, files, suffix, only_dirs);
292 }
293
294 return g_slist_reverse (files);
295}
296
297/* Wrapper around strtoull for easier use: tries
298 * to convert @str to a number and return -1 if it is not.
299 * Used to check if references in subpattern contexts
300 * (e.g. \%{1@start} or \%{blah@start}) are named or numbers.
301 */
302gint
303_ctk_source_utils_string_to_int (const gchar *str)
304{
305 guint64 number;
306 gchar *end_str;
307
308 if (str == NULL((void*)0) || *str == '\0')
309 {
310 return -1;
311 }
312
313 errno(*__errno_location ()) = 0;
314 number = g_ascii_strtoull (str, &end_str, 10);
315
316 if (errno(*__errno_location ()) != 0 || number > G_MAXINT2147483647 || *end_str != '\0')
317 {
318 return -1;
319 }
320
321 return number;
322}
323
324#define FONT_FAMILY"font-family" "font-family"
325#define FONT_VARIANT"font-variant" "font-variant"
326#define FONT_STRETCH"font-stretch" "font-stretch"
327#define FONT_WEIGHT"font-weight" "font-weight"
328#define FONT_STYLE"font-style" "font-style"
329#define FONT_SIZE"font-size" "font-size"
330
331gchar *
332_ctk_source_utils_pango_font_description_to_css (const PangoFontDescription *font_desc)
333{
334 PangoFontMask mask;
335 GString *str;
336
337#define ADD_KEYVAL(key,fmt) \
338 g_string_append(str,key":"fmt";")(__builtin_constant_p (key":"fmt";") ? __extension__ ({ const
char * const __val = (key":"fmt";"); g_string_append_len_inline
(str, __val, (__builtin_expect (__extension__ ({ int _g_boolean_var_62
= 0; if (__val != ((void*)0)) _g_boolean_var_62 = 1; _g_boolean_var_62
; }), 1)) ? (gssize) strlen (((__val) + !(__val))) : (gssize)
-1); }) : g_string_append_len_inline (str, key":"fmt";", (gssize
) -1))
339#define ADD_KEYVAL_PRINTF(key,fmt,...) \
340 g_string_append_printf(str,key":"fmt";", __VA_ARGS__)
341
342 g_return_val_if_fail (font_desc, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_63
= 0; if (font_desc) _g_boolean_var_63 = 1; _g_boolean_var_63
; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView"
, ((const char*) (__func__)), "font_desc"); return (((void*)0
)); } } while (0)
;
343
344 str = g_string_new (NULL((void*)0));
345
346 mask = pango_font_description_get_set_fields (font_desc);
347
348 if ((mask & PANGO_FONT_MASK_FAMILY) != 0)
349 {
350 const gchar *family;
351
352 family = pango_font_description_get_family (font_desc);
353 ADD_KEYVAL_PRINTF (FONT_FAMILY"font-family", "\"%s\"", family);
354 }
355
356 if ((mask & PANGO_FONT_MASK_STYLE) != 0)
357 {
358 PangoStyle style;
359
360 style = pango_font_description_get_style (font_desc);
361
362 switch (style)
363 {
364 case PANGO_STYLE_NORMAL:
365 ADD_KEYVAL (FONT_STYLE"font-style", "normal");
366 break;
367
368 case PANGO_STYLE_OBLIQUE:
369 ADD_KEYVAL (FONT_STYLE"font-style", "oblique");
370 break;
371
372 case PANGO_STYLE_ITALIC:
373 ADD_KEYVAL (FONT_STYLE"font-style", "italic");
374 break;
375
376 default:
377 break;
378 }
379 }
380
381 if ((mask & PANGO_FONT_MASK_VARIANT) != 0)
382 {
383 PangoVariant variant;
384
385 variant = pango_font_description_get_variant (font_desc);
386
387 switch (variant)
388 {
389 case PANGO_VARIANT_NORMAL:
390 ADD_KEYVAL (FONT_VARIANT"font-variant", "normal");
391 break;
392
393 case PANGO_VARIANT_SMALL_CAPS:
394 ADD_KEYVAL (FONT_VARIANT"font-variant", "small-caps");
395 break;
396
397#if PANGO_VERSION_CHECK(1, 49, 3)(( ((1) * 10000) + ((56) * 100) + ((3) * 1)) >= ( ((1) * 10000
) + ((49) * 100) + ((3) * 1)))
398 case PANGO_VARIANT_ALL_SMALL_CAPS:
399 ADD_KEYVAL (FONT_VARIANT"font-variant", "all-small-caps");
400 break;
401
402 case PANGO_VARIANT_PETITE_CAPS:
403 ADD_KEYVAL (FONT_VARIANT"font-variant", "petite-caps");
404 break;
405
406 case PANGO_VARIANT_ALL_PETITE_CAPS:
407 ADD_KEYVAL (FONT_VARIANT"font-variant", "all-petite-caps");
408 break;
409
410 case PANGO_VARIANT_UNICASE:
411 ADD_KEYVAL (FONT_VARIANT"font-variant", "unicase");
412 break;
413
414 case PANGO_VARIANT_TITLE_CAPS:
415 ADD_KEYVAL (FONT_VARIANT"font-variant", "titling-caps");
416 break;
417#endif
418
419 default:
420 break;
421 }
422 }
423
424 if ((mask & PANGO_FONT_MASK_WEIGHT))
425 {
426 gint weight;
427
428 weight = pango_font_description_get_weight (font_desc);
429
430 /*
431 * WORKAROUND:
432 *
433 * font-weight with numbers does not appear to be working as expected
434 * right now. So for the common (bold/normal), let's just use the string
435 * and let ctk warn for the other values, which shouldn't really be
436 * used for this.
437 */
438
439 switch (weight)
440 {
441 case PANGO_WEIGHT_SEMILIGHT:
442 /*
443 * 350 is not actually a valid css font-weight, so we will just round
444 * up to 400.
445 */
446 case PANGO_WEIGHT_NORMAL:
447 ADD_KEYVAL (FONT_WEIGHT"font-weight", "normal");
448 break;
449
450 case PANGO_WEIGHT_BOLD:
451 ADD_KEYVAL (FONT_WEIGHT"font-weight", "bold");
452 break;
453
454 case PANGO_WEIGHT_THIN:
455 case PANGO_WEIGHT_ULTRALIGHT:
456 case PANGO_WEIGHT_LIGHT:
457 case PANGO_WEIGHT_BOOK:
458 case PANGO_WEIGHT_MEDIUM:
459 case PANGO_WEIGHT_SEMIBOLD:
460 case PANGO_WEIGHT_ULTRABOLD:
461 case PANGO_WEIGHT_HEAVY:
462 case PANGO_WEIGHT_ULTRAHEAVY:
463 default:
464 /* round to nearest hundred */
465 weight = round (weight / 100.0) * 100;
466 ADD_KEYVAL_PRINTF ("font-weight", "%d", weight);
467 break;
468 }
469 }
470
471 if ((mask & PANGO_FONT_MASK_STRETCH))
472 {
473 switch (pango_font_description_get_stretch (font_desc))
474 {
475 case PANGO_STRETCH_ULTRA_CONDENSED:
476 ADD_KEYVAL (FONT_STRETCH"font-stretch", "ultra-condensed");
477 break;
478
479 case PANGO_STRETCH_EXTRA_CONDENSED:
480 ADD_KEYVAL (FONT_STRETCH"font-stretch", "extra-condensed");
481 break;
482
483 case PANGO_STRETCH_CONDENSED:
484 ADD_KEYVAL (FONT_STRETCH"font-stretch", "condensed");
485 break;
486
487 case PANGO_STRETCH_SEMI_CONDENSED:
488 ADD_KEYVAL (FONT_STRETCH"font-stretch", "semi-condensed");
489 break;
490
491 case PANGO_STRETCH_NORMAL:
492 ADD_KEYVAL (FONT_STRETCH"font-stretch", "normal");
493 break;
494
495 case PANGO_STRETCH_SEMI_EXPANDED:
496 ADD_KEYVAL (FONT_STRETCH"font-stretch", "semi-expanded");
497 break;
498
499 case PANGO_STRETCH_EXPANDED:
500 ADD_KEYVAL (FONT_STRETCH"font-stretch", "expanded");
501 break;
502
503 case PANGO_STRETCH_EXTRA_EXPANDED:
504 ADD_KEYVAL (FONT_STRETCH"font-stretch", "extra-expanded");
505 break;
506
507 case PANGO_STRETCH_ULTRA_EXPANDED:
508 ADD_KEYVAL (FONT_STRETCH"font-stretch", "ultra-expanded");
509 break;
510
511 default:
512 break;
513 }
514 }
515
516 if ((mask & PANGO_FONT_MASK_SIZE))
517 {
518 gint font_size;
519
520 font_size = pango_font_description_get_size (font_desc) / PANGO_SCALE1024;
521 ADD_KEYVAL_PRINTF ("font-size", "%dpt", font_size);
522 }
523
524 return g_string_free (str, FALSE(0));
525
526#undef ADD_KEYVAL
527#undef ADD_KEYVAL_PRINTF
528}
529
530/*
531 * _ctk_source_utils_dgettext:
532 *
533 * Try to translate string from given domain. It returns
534 * duplicated string which must be freed with g_free().
535 */
536gchar *
537_ctk_source_utils_dgettext (const gchar *domain,
538 const gchar *string)
539{
540 const gchar *translated;
541 gchar *tmp;
542
543 g_return_val_if_fail (string != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_64
= 0; if (string != ((void*)0)) _g_boolean_var_64 = 1; _g_boolean_var_64
; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView"
, ((const char*) (__func__)), "string != NULL"); return (((void
*)0)); } } while (0)
;
544
545 if (domain == NULL((void*)0))
546 {
547 return g_strdup (_(string))g_strdup_inline (((char *) g_dgettext ("ctksourceview-4", string
)))
;
548 }
549
550 translated = dgettext (domain, string)dcgettext (domain, string, 5);
551
552 if (g_strcmp0 (translated, string) == 0)
553 {
554 return g_strdup (_(string))g_strdup_inline (((char *) g_dgettext ("ctksourceview-4", string
)))
;
555 }
556
557 if (g_utf8_validate (translated, -1, NULL((void*)0)))
558 {
559 return g_strdup (translated)g_strdup_inline (translated);
560 }
561
562 tmp = g_locale_to_utf8 (translated, -1, NULL((void*)0), NULL((void*)0), NULL((void*)0));
563 return tmp != NULL((void*)0) ? tmp : g_strdup (string)g_strdup_inline (string);
564}
565
566/*
567 * _ctk_source_utils_int_to_string:
568 * @value: the integer to convert to a string
569 * @outstr: (out): a location for a pointer to the result string
570 *
571 * The following implementation uses an internal cache to speed up the
572 * conversion of integers to strings by comparing the value to the
573 * previous value that was calculated.
574 *
575 * If we detect a simple increment, we can alter the previous string directly
576 * and then carry the number to each of the previous chars sequentually. If we
577 * still have a carry bit at the end of the loop, we need to move the whole
578 * string over 1 place to take account for the new "1" at the start.
579 *
580 * This function is not thread-safe, as the resulting string is stored in
581 * static data.
582 *
583 * Returns: the number of characters in the resulting string
584 */
585gint
586_ctk_source_utils_int_to_string (guint value,
587 const gchar **outstr)
588{
589 static struct{
590 guint value;
591 guint len;
592 gchar str[12];
593 } fi;
594
595 *outstr = fi.str;
596
597 if (value == fi.value)
598 {
599 return fi.len;
600 }
601
602 if G_LIKELY (value == fi.value + 1)(__builtin_expect (__extension__ ({ int _g_boolean_var_65 = 0
; if (value == fi.value + 1) _g_boolean_var_65 = 1; _g_boolean_var_65
; }), 1))
603 {
604 guint carry = 1;
605 gint i;
606
607 for (i = fi.len - 1; i >= 0; i--)
608 {
609 fi.str[i] += carry;
610 carry = fi.str[i] == ':';
611
612 if (carry)
613 {
614 fi.str[i] = '0';
615 }
616 else
617 {
618 break;
619 }
620 }
621
622 if G_UNLIKELY (carry)(__builtin_expect (__extension__ ({ int _g_boolean_var_66 = 0
; if (carry) _g_boolean_var_66 = 1; _g_boolean_var_66; }), 0)
)
623 {
624 for (i = fi.len; i > 0; i--)
625 {
626 fi.str[i] = fi.str[i-1];
627 }
628
629 fi.len++;
630 fi.str[0] = '1';
631 fi.str[fi.len] = 0;
632 }
633
634 fi.value++;
635
636 return fi.len;
637 }
638
639#ifdef G_OS_WIN32
640 fi.len = g_snprintf (fi.str, sizeof fi.str - 1, "%u", value);
641#else
642 /* Use snprintf() directly when possible to reduce overhead */
643 fi.len = snprintf (fi.str, sizeof fi.str - 1, "%u", value);
644#endif
645 fi.str[fi.len] = 0;
646 fi.value = value;
647
648 return fi.len;
649}
650
651/*
652 * The goal of this function is to be like ctk_text_view_scroll_to_iter() but
653 * without any of the scrolling animation. We use it from the source map where
654 * the updates are so fast the scrolling animation makes it feel very delayed.
655 *
656 * Many parts of this function were taken from ctk_text_view_scroll_to_iter ()
657 * https://developer.gnome.org/ctk3/stable/CtkTextView.html#ctk-text-view-scroll-to-iter
658 */
659void
660_ctk_source_view_jump_to_iter (CtkTextView *text_view,
661 const CtkTextIter *iter,
662 double within_margin,
663 gboolean use_align,
664 double xalign,
665 double yalign)
666{
667 CtkAdjustment *hadj;
668 CtkAdjustment *vadj;
669 CdkRectangle rect;
670 CdkRectangle screen;
671 int xvalue = 0;
672 int yvalue = 0;
673 int scroll_dest;
674 int screen_bottom;
675 int screen_right;
676 int screen_xoffset;
677 int screen_yoffset;
678 int current_x_scroll;
679 int current_y_scroll;
680
681 g_return_if_fail (CTK_IS_TEXT_VIEW (text_view))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_67
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((text_view)); GType __t = ((ctk_text_view_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_boolean_var_67
= 1; _g_boolean_var_67; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_IS_TEXT_VIEW (text_view)"
); return; } } while (0)
;
682 g_return_if_fail (iter != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_68
= 0; if (iter != ((void*)0)) _g_boolean_var_68 = 1; _g_boolean_var_68
; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView"
, ((const char*) (__func__)), "iter != NULL"); return; } } while
(0)
;
683 g_return_if_fail (within_margin >= 0.0 && within_margin <= 0.5)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_69
= 0; if (within_margin >= 0.0 && within_margin <=
0.5) _g_boolean_var_69 = 1; _g_boolean_var_69; }), 1))) { } else
{ g_return_if_fail_warning ("CtkSourceView", ((const char*) (
__func__)), "within_margin >= 0.0 && within_margin <= 0.5"
); return; } } while (0)
;
684 g_return_if_fail (xalign >= 0.0 && xalign <= 1.0)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_70
= 0; if (xalign >= 0.0 && xalign <= 1.0) _g_boolean_var_70
= 1; _g_boolean_var_70; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "xalign >= 0.0 && xalign <= 1.0"
); return; } } while (0)
;
685 g_return_if_fail (yalign >= 0.0 && yalign <= 1.0)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_71
= 0; if (yalign >= 0.0 && yalign <= 1.0) _g_boolean_var_71
= 1; _g_boolean_var_71; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "yalign >= 0.0 && yalign <= 1.0"
); return; } } while (0)
;
686
687 hadj = ctk_scrollable_get_hadjustment (CTK_SCROLLABLE (text_view)((((CtkScrollable*) (void *) ((text_view))))));
688 vadj = ctk_scrollable_get_vadjustment (CTK_SCROLLABLE (text_view)((((CtkScrollable*) (void *) ((text_view))))));
689
690 ctk_text_view_get_iter_location (text_view, iter, &rect);
691 ctk_text_view_get_visible_rect (text_view, &screen);
692
693 current_x_scroll = screen.x;
694 current_y_scroll = screen.y;
695
696 screen_xoffset = screen.width * within_margin;
697 screen_yoffset = screen.height * within_margin;
698
699 screen.x += screen_xoffset;
700 screen.y += screen_yoffset;
701 screen.width -= screen_xoffset * 2;
702 screen.height -= screen_yoffset * 2;
703
704
705 /* paranoia check */
706 if (screen.width < 1)
707 screen.width = 1;
708 if (screen.height < 1)
709 screen.height = 1;
710
711 /* The -1 here ensures that we leave enough space to draw the cursor
712 * when this function is used for horizontal scrolling.
713 */
714 screen_right = screen.x + screen.width - 1;
715 screen_bottom = screen.y + screen.height;
716
717
718 /* The alignment affects the point in the target character that we
719 * choose to align. If we're doing right/bottom alignment, we align
720 * the right/bottom edge of the character the mark is at; if we're
721 * doing left/top we align the left/top edge of the character; if
722 * we're doing center alignment we align the center of the
723 * character.
724 */
725
726 /* Vertical alignment */
727 scroll_dest = current_y_scroll;
Value stored to 'scroll_dest' is never read
728 if (use_align)
729 {
730 scroll_dest = rect.y + (rect.height * yalign) - (screen.height * yalign);
731
732 /* if scroll_dest < screen.y, we move a negative increment (up),
733 * else a positive increment (down)
734 */
735 yvalue = scroll_dest - screen.y + screen_yoffset;
736 }
737 else
738 {
739 /* move minimum to get onscreen */
740 if (rect.y < screen.y)
741 {
742 scroll_dest = rect.y;
743 yvalue = scroll_dest - screen.y - screen_yoffset;
744 }
745 else if ((rect.y + rect.height) > screen_bottom)
746 {
747 scroll_dest = rect.y + rect.height;
748 yvalue = scroll_dest - screen_bottom + screen_yoffset;
749 }
750 }
751 yvalue += current_y_scroll;
752
753 /* Horizontal alignment */
754 scroll_dest = current_x_scroll;
755 if (use_align)
756 {
757 scroll_dest = rect.x + (rect.width * xalign) - (screen.width * xalign);
758
759 /* if scroll_dest < screen.y, we move a negative increment (left),
760 * else a positive increment (right)
761 */
762 xvalue = scroll_dest - screen.x + screen_xoffset;
763 }
764 else
765 {
766 /* move minimum to get onscreen */
767 if (rect.x < screen.x)
768 {
769 scroll_dest = rect.x;
770 xvalue = scroll_dest - screen.x - screen_xoffset;
771 }
772 else if ((rect.x + rect.width) > screen_right)
773 {
774 scroll_dest = rect.x + rect.width;
775 xvalue = scroll_dest - screen_right + screen_xoffset;
776 }
777 }
778 xvalue += current_x_scroll;
779
780 ctk_adjustment_set_value (hadj, xvalue);
781 ctk_adjustment_set_value (vadj, yvalue);
782}