Bug Summary

File:_build/../ctksourceview/ctksourceregion.c
Warning:line 504, column 4
Value stored to 'l' 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 ctksourceregion.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-150459-14238-1 -x c ../ctksourceview/ctksourceregion.c
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
2 * ctksourceregion.c - CtkTextMark-based region utility
3 * This file is part of CtkSourceView
4 *
5 * Copyright (C) 2002 Gustavo Giráldez <gustavo.giraldez@gmx.net>
6 * Copyright (C) 2016 Sébastien Wilmet <swilmet@gnome.org>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library 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 GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this library; if not, see <http://www.gnu.org/licenses/>.
20 */
21
22#ifdef HAVE_CONFIG_H1
23#include <config.h>
24#endif
25
26#include "ctksourceregion.h"
27
28/**
29 * SECTION:region
30 * @Short_description: Region utility
31 * @Title: CtkSourceRegion
32 * @See_also: #CtkTextBuffer
33 *
34 * A #CtkSourceRegion permits to store a group of subregions of a
35 * #CtkTextBuffer. #CtkSourceRegion stores the subregions with pairs of
36 * #CtkTextMark's, so the region is still valid after insertions and deletions
37 * in the #CtkTextBuffer.
38 *
39 * The #CtkTextMark for the start of a subregion has a left gravity, while the
40 * #CtkTextMark for the end of a subregion has a right gravity.
41 *
42 * The typical use-case of #CtkSourceRegion is to scan a #CtkTextBuffer chunk by
43 * chunk, not the whole buffer at once to not block the user interface. The
44 * #CtkSourceRegion represents in that case the remaining region to scan. You
45 * can listen to the #CtkTextBuffer::insert-text and
46 * #CtkTextBuffer::delete-range signals to update the #CtkSourceRegion
47 * accordingly.
48 *
49 * To iterate through the subregions, you need to use a #CtkSourceRegionIter,
50 * for example:
51 * |[
52 * CtkSourceRegion *region;
53 * CtkSourceRegionIter region_iter;
54 *
55 * ctk_source_region_get_start_region_iter (region, &region_iter);
56 *
57 * while (!ctk_source_region_iter_is_end (&region_iter))
58 * {
59 * CtkTextIter subregion_start;
60 * CtkTextIter subregion_end;
61 *
62 * if (!ctk_source_region_iter_get_subregion (&region_iter,
63 * &subregion_start,
64 * &subregion_end))
65 * {
66 * break;
67 * }
68 *
69 * // Do something useful with the subregion.
70 *
71 * ctk_source_region_iter_next (&region_iter);
72 * }
73 * ]|
74 */
75
76/* With the gravities of the CtkTextMarks, it is possible for subregions to
77 * become interlaced:
78 * Buffer content:
79 * "hello world"
80 * Add two subregions:
81 * "[hello] [world]"
82 * Delete the space:
83 * "[hello][world]"
84 * Undo:
85 * "[hello[ ]world]"
86 *
87 * FIXME: when iterating through the subregions, it should simplify them first.
88 * I don't know if it's done (swilmet).
89 */
90
91#undef ENABLE_DEBUG
92/*
93#define ENABLE_DEBUG
94*/
95
96#ifdef ENABLE_DEBUG
97#define DEBUG(x) (x)
98#else
99#define DEBUG(x)
100#endif
101
102typedef struct _CtkSourceRegionPrivate CtkSourceRegionPrivate;
103typedef struct _Subregion Subregion;
104typedef struct _CtkSourceRegionIterReal CtkSourceRegionIterReal;
105
106struct _CtkSourceRegionPrivate
107{
108 /* Weak pointer to the buffer. */
109 CtkTextBuffer *buffer;
110
111 /* List of sorted 'Subregion*' */
112 GList *subregions;
113
114 guint32 timestamp;
115};
116
117struct _Subregion
118{
119 CtkTextMark *start;
120 CtkTextMark *end;
121};
122
123struct _CtkSourceRegionIterReal
124{
125 CtkSourceRegion *region;
126 guint32 region_timestamp;
127 GList *subregions;
128};
129
130enum
131{
132 PROP_0,
133 PROP_BUFFER,
134 N_PROPERTIES
135};
136
137static GParamSpec *properties[N_PROPERTIES];
138
139G_DEFINE_TYPE_WITH_PRIVATE (CtkSourceRegion, ctk_source_region, G_TYPE_OBJECT)static void ctk_source_region_init (CtkSourceRegion *self); static
void ctk_source_region_class_init (CtkSourceRegionClass *klass
); static GType ctk_source_region_get_type_once (void); static
gpointer ctk_source_region_parent_class = ((void*)0); static
gint CtkSourceRegion_private_offset; static void ctk_source_region_class_intern_init
(gpointer klass) { ctk_source_region_parent_class = g_type_class_peek_parent
(klass); if (CtkSourceRegion_private_offset != 0) g_type_class_adjust_private_offset
(klass, &CtkSourceRegion_private_offset); ctk_source_region_class_init
((CtkSourceRegionClass*) klass); } __attribute__ ((__unused__
)) static inline gpointer ctk_source_region_get_instance_private
(CtkSourceRegion *self) { return (((gpointer) ((guint8*) (self
) + (glong) (CtkSourceRegion_private_offset)))); } GType ctk_source_region_get_type
(void) { static gsize 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 (&static_g_define_type_id
)); }))) { GType g_define_type_id = ctk_source_region_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 ((&static_g_define_type_id
), (gsize) (g_define_type_id)); })); } return static_g_define_type_id
; } __attribute__ ((__noinline__)) static GType ctk_source_region_get_type_once
(void) { GType g_define_type_id = g_type_register_static_simple
(((GType) ((20) << (2))), g_intern_static_string ("CtkSourceRegion"
), sizeof (CtkSourceRegionClass), (GClassInitFunc)(void (*)(void
)) ctk_source_region_class_intern_init, sizeof (CtkSourceRegion
), (GInstanceInitFunc)(void (*)(void)) ctk_source_region_init
, (GTypeFlags) 0); { {{ CtkSourceRegion_private_offset = g_type_add_instance_private
(g_define_type_id, sizeof (CtkSourceRegionPrivate)); };} } return
g_define_type_id; }
140
141#ifdef ENABLE_DEBUG
142static void
143print_region (CtkSourceRegion *region)
144{
145 gchar *str;
146
147 str = ctk_source_region_to_string (region);
148 g_print ("%s\n", str);
149 g_free (str);
150}
151#endif
152
153/* Find and return a subregion node which contains the given text
154 * iter. If left_side is TRUE, return the subregion which contains
155 * the text iter or which is the leftmost; else return the rightmost
156 * subregion.
157 */
158static GList *
159find_nearest_subregion (CtkSourceRegion *region,
160 const CtkTextIter *iter,
161 GList *begin,
162 gboolean leftmost,
163 gboolean include_edges)
164{
165 CtkSourceRegionPrivate *priv = ctk_source_region_get_instance_private (region);
166 GList *retval;
167 GList *l;
168
169 g_assert (iter != NULL)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_44
= 0; if (iter != ((void*)0)) _g_boolean_var_44 = 1; _g_boolean_var_44
; }), 1)) ; else g_assertion_message_expr ("CtkSourceView", "../ctksourceview/ctksourceregion.c"
, 169, ((const char*) (__func__)), "iter != NULL"); } while (
0)
;
170
171 if (begin == NULL((void*)0))
172 {
173 begin = priv->subregions;
174 }
175
176 if (begin != NULL((void*)0))
177 {
178 retval = begin->prev;
179 }
180 else
181 {
182 retval = NULL((void*)0);
183 }
184
185 for (l = begin; l != NULL((void*)0); l = l->next)
186 {
187 CtkTextIter sr_iter;
188 Subregion *sr = l->data;
189 gint cmp;
190
191 if (!leftmost)
192 {
193 ctk_text_buffer_get_iter_at_mark (priv->buffer, &sr_iter, sr->end);
194 cmp = ctk_text_iter_compare (iter, &sr_iter);
195 if (cmp < 0 || (cmp == 0 && include_edges))
196 {
197 retval = l;
198 break;
199 }
200
201 }
202 else
203 {
204 ctk_text_buffer_get_iter_at_mark (priv->buffer, &sr_iter, sr->start);
205 cmp = ctk_text_iter_compare (iter, &sr_iter);
206 if (cmp > 0 || (cmp == 0 && include_edges))
207 {
208 retval = l;
209 }
210 else
211 {
212 break;
213 }
214 }
215 }
216
217 return retval;
218}
219
220static void
221ctk_source_region_get_property (GObject *object,
222 guint prop_id,
223 GValue *value,
224 GParamSpec *pspec)
225{
226 CtkSourceRegion *region = CTK_SOURCE_REGION (object);
227
228 switch (prop_id)
229 {
230 case PROP_BUFFER:
231 g_value_set_object (value, ctk_source_region_get_buffer (region));
232 break;
233
234 default:
235 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec)do { GObject *_glib__object = (GObject*) ((object)); GParamSpec
*_glib__pspec = (GParamSpec*) ((pspec)); guint _glib__property_id
= ((prop_id)); g_warning ("%s:%d: invalid %s id %u for \"%s\" of type '%s' in '%s'"
, "../ctksourceview/ctksourceregion.c", 235, ("property"), _glib__property_id
, _glib__pspec->name, g_type_name ((((((GTypeClass*) (((GTypeInstance
*) (_glib__pspec))->g_class))->g_type)))), (g_type_name
((((((GTypeClass*) (((GTypeInstance*) (_glib__object))->g_class
))->g_type)))))); } while (0)
;
236 break;
237 }
238}
239
240static void
241ctk_source_region_set_property (GObject *object,
242 guint prop_id,
243 const GValue *value,
244 GParamSpec *pspec)
245{
246 CtkSourceRegionPrivate *priv = ctk_source_region_get_instance_private (CTK_SOURCE_REGION (object));
247
248 switch (prop_id)
249 {
250 case PROP_BUFFER:
251 g_assert (priv->buffer == NULL)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_45
= 0; if (priv->buffer == ((void*)0)) _g_boolean_var_45 = 1
; _g_boolean_var_45; }), 1)) ; else g_assertion_message_expr (
"CtkSourceView", "../ctksourceview/ctksourceregion.c", 251, (
(const char*) (__func__)), "priv->buffer == NULL"); } while
(0)
;
252 priv->buffer = g_value_get_object (value);
253 g_object_add_weak_pointer (G_OBJECT (priv->buffer)((((GObject*) (void *) ((priv->buffer))))),
254 (gpointer *) &priv->buffer);
255 break;
256
257 default:
258 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec)do { GObject *_glib__object = (GObject*) ((object)); GParamSpec
*_glib__pspec = (GParamSpec*) ((pspec)); guint _glib__property_id
= ((prop_id)); g_warning ("%s:%d: invalid %s id %u for \"%s\" of type '%s' in '%s'"
, "../ctksourceview/ctksourceregion.c", 258, ("property"), _glib__property_id
, _glib__pspec->name, g_type_name ((((((GTypeClass*) (((GTypeInstance
*) (_glib__pspec))->g_class))->g_type)))), (g_type_name
((((((GTypeClass*) (((GTypeInstance*) (_glib__object))->g_class
))->g_type)))))); } while (0)
;
259 break;
260 }
261}
262
263static void
264ctk_source_region_dispose (GObject *object)
265{
266 CtkSourceRegionPrivate *priv = ctk_source_region_get_instance_private (CTK_SOURCE_REGION (object));
267
268 while (priv->subregions != NULL((void*)0))
269 {
270 Subregion *sr = priv->subregions->data;
271
272 if (priv->buffer != NULL((void*)0))
273 {
274 ctk_text_buffer_delete_mark (priv->buffer, sr->start);
275 ctk_text_buffer_delete_mark (priv->buffer, sr->end);
276 }
277
278 g_slice_free (Subregion, sr)do { if (1) g_slice_free1 (sizeof (Subregion), (sr)); else (void
) ((Subregion*) 0 == (sr)); } while (0)
;
279 priv->subregions = g_list_delete_link (priv->subregions, priv->subregions);
280 }
281
282 if (priv->buffer != NULL((void*)0))
283 {
284 g_object_remove_weak_pointer (G_OBJECT (priv->buffer)((((GObject*) (void *) ((priv->buffer))))),
285 (gpointer *) &priv->buffer);
286
287 priv->buffer = NULL((void*)0);
288 }
289
290 G_OBJECT_CLASS (ctk_source_region_parent_class)((((GObjectClass*) (void *) ((ctk_source_region_parent_class)
))))
->dispose (object);
291}
292
293static void
294ctk_source_region_class_init (CtkSourceRegionClass *klass)
295{
296 GObjectClass *object_class = G_OBJECT_CLASS (klass)((((GObjectClass*) (void *) ((klass)))));
297
298 object_class->get_property = ctk_source_region_get_property;
299 object_class->set_property = ctk_source_region_set_property;
300 object_class->dispose = ctk_source_region_dispose;
301
302 /**
303 * CtkSourceRegion:buffer:
304 *
305 * The #CtkTextBuffer. The #CtkSourceRegion has a weak reference to the
306 * buffer.
307 *
308 * Since: 3.22
309 */
310 properties[PROP_BUFFER] =
311 g_param_spec_object ("buffer",
312 "Buffer",
313 "",
314 CTK_TYPE_TEXT_BUFFER(ctk_text_buffer_get_type ()),
315 G_PARAM_READWRITE |
316 G_PARAM_CONSTRUCT_ONLY |
317 G_PARAM_STATIC_STRINGS(G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB
)
);
318
319 g_object_class_install_properties (object_class, N_PROPERTIES, properties);
320}
321
322static void
323ctk_source_region_init (CtkSourceRegion *region)
324{
325}
326
327/**
328 * ctk_source_region_new:
329 * @buffer: a #CtkTextBuffer.
330 *
331 * Returns: a new #CtkSourceRegion object for @buffer.
332 * Since: 3.22
333 */
334CtkSourceRegion *
335ctk_source_region_new (CtkTextBuffer *buffer)
336{
337 g_return_val_if_fail (CTK_IS_TEXT_BUFFER (buffer), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_46
= 0; if ((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((buffer)); GType __t = ((ctk_text_buffer_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_46
= 1; _g_boolean_var_46; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_IS_TEXT_BUFFER (buffer)"
); return (((void*)0)); } } while (0)
;
338
339 return g_object_new (CTK_SOURCE_TYPE_REGION(ctk_source_region_get_type ()),
340 "buffer", buffer,
341 NULL((void*)0));
342}
343
344/**
345 * ctk_source_region_get_buffer:
346 * @region: a #CtkSourceRegion.
347 *
348 * Returns: (transfer none) (nullable): the #CtkTextBuffer.
349 * Since: 3.22
350 */
351CtkTextBuffer *
352ctk_source_region_get_buffer (CtkSourceRegion *region)
353{
354 CtkSourceRegionPrivate *priv;
355
356 g_return_val_if_fail (CTK_SOURCE_IS_REGION (region), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_47
= 0; if (CTK_SOURCE_IS_REGION (region)) _g_boolean_var_47 = 1
; _g_boolean_var_47; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_REGION (region)"
); return (((void*)0)); } } while (0)
;
357
358 priv = ctk_source_region_get_instance_private (region);
359 return priv->buffer;
360}
361
362static void
363ctk_source_region_clear_zero_length_subregions (CtkSourceRegion *region)
364{
365 CtkSourceRegionPrivate *priv = ctk_source_region_get_instance_private (region);
366 GList *node;
367
368 node = priv->subregions;
369 while (node != NULL((void*)0))
370 {
371 Subregion *sr = node->data;
372 CtkTextIter start;
373 CtkTextIter end;
374
375 ctk_text_buffer_get_iter_at_mark (priv->buffer, &start, sr->start);
376 ctk_text_buffer_get_iter_at_mark (priv->buffer, &end, sr->end);
377
378 if (ctk_text_iter_equal (&start, &end))
379 {
380 ctk_text_buffer_delete_mark (priv->buffer, sr->start);
381 ctk_text_buffer_delete_mark (priv->buffer, sr->end);
382 g_slice_free (Subregion, sr)do { if (1) g_slice_free1 (sizeof (Subregion), (sr)); else (void
) ((Subregion*) 0 == (sr)); } while (0)
;
383
384 if (node == priv->subregions)
385 {
386 priv->subregions = node = g_list_delete_link (node, node);
387 }
388 else
389 {
390 node = g_list_delete_link (node, node);
391 }
392
393 priv->timestamp++;
394 }
395 else
396 {
397 node = node->next;
398 }
399 }
400}
401
402/**
403 * ctk_source_region_add_subregion:
404 * @region: a #CtkSourceRegion.
405 * @_start: the start of the subregion.
406 * @_end: the end of the subregion.
407 *
408 * Adds the subregion delimited by @_start and @_end to @region.
409 *
410 * Since: 3.22
411 */
412void
413ctk_source_region_add_subregion (CtkSourceRegion *region,
414 const CtkTextIter *_start,
415 const CtkTextIter *_end)
416{
417 CtkSourceRegionPrivate *priv;
418 GList *start_node;
419 GList *end_node;
420 CtkTextIter start;
421 CtkTextIter end;
422
423 g_return_if_fail (CTK_SOURCE_IS_REGION (region))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_48
= 0; if (CTK_SOURCE_IS_REGION (region)) _g_boolean_var_48 = 1
; _g_boolean_var_48; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_REGION (region)"
); return; } } while (0)
;
424 g_return_if_fail (_start != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_49
= 0; if (_start != ((void*)0)) _g_boolean_var_49 = 1; _g_boolean_var_49
; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView"
, ((const char*) (__func__)), "_start != NULL"); return; } } while
(0)
;
425 g_return_if_fail (_end != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_50
= 0; if (_end != ((void*)0)) _g_boolean_var_50 = 1; _g_boolean_var_50
; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView"
, ((const char*) (__func__)), "_end != NULL"); return; } } while
(0)
;
426
427 priv = ctk_source_region_get_instance_private (region);
428
429 if (priv->buffer == NULL((void*)0))
430 {
431 return;
432 }
433
434 start = *_start;
435 end = *_end;
436
437 DEBUG (g_print ("---\n"));
438 DEBUG (print_region (region));
439 DEBUG (g_message ("region_add (%d, %d)",
440 ctk_text_iter_get_offset (&start),
441 ctk_text_iter_get_offset (&end)));
442
443 ctk_text_iter_order (&start, &end);
444
445 /* Don't add zero-length regions. */
446 if (ctk_text_iter_equal (&start, &end))
447 {
448 return;
449 }
450
451 /* Find bounding subregions. */
452 start_node = find_nearest_subregion (region, &start, NULL((void*)0), FALSE(0), TRUE(!(0)));
453 end_node = find_nearest_subregion (region, &end, start_node, TRUE(!(0)), TRUE(!(0)));
454
455 if (start_node == NULL((void*)0) || end_node == NULL((void*)0) || end_node == start_node->prev)
456 {
457 /* Create the new subregion. */
458 Subregion *sr = g_slice_new0 (Subregion)(Subregion *) (__extension__ ({ gsize __s = sizeof (Subregion
); gpointer __p; __p = g_slice_alloc (__s); memset (__p, 0, __s
); __p; }))
;
459 sr->start = ctk_text_buffer_create_mark (priv->buffer, NULL((void*)0), &start, TRUE(!(0)));
460 sr->end = ctk_text_buffer_create_mark (priv->buffer, NULL((void*)0), &end, FALSE(0));
461
462 if (start_node == NULL((void*)0))
463 {
464 /* Append the new region. */
465 priv->subregions = g_list_append (priv->subregions, sr);
466 }
467 else if (end_node == NULL((void*)0))
468 {
469 /* Prepend the new region. */
470 priv->subregions = g_list_prepend (priv->subregions, sr);
471 }
472 else
473 {
474 /* We are in the middle of two subregions. */
475 priv->subregions = g_list_insert_before (priv->subregions, start_node, sr);
476 }
477 }
478 else
479 {
480 CtkTextIter iter;
481 Subregion *sr = start_node->data;
482
483 if (start_node != end_node)
484 {
485 /* We need to merge some subregions. */
486 GList *l = start_node->next;
487 Subregion *q;
488
489 ctk_text_buffer_delete_mark (priv->buffer, sr->end);
490
491 while (l != end_node)
492 {
493 q = l->data;
494 ctk_text_buffer_delete_mark (priv->buffer, q->start);
495 ctk_text_buffer_delete_mark (priv->buffer, q->end);
496 g_slice_free (Subregion, q)do { if (1) g_slice_free1 (sizeof (Subregion), (q)); else (void
) ((Subregion*) 0 == (q)); } while (0)
;
497 l = g_list_delete_link (l, l);
498 }
499
500 q = l->data;
501 ctk_text_buffer_delete_mark (priv->buffer, q->start);
502 sr->end = q->end;
503 g_slice_free (Subregion, q)do { if (1) g_slice_free1 (sizeof (Subregion), (q)); else (void
) ((Subregion*) 0 == (q)); } while (0)
;
504 l = g_list_delete_link (l, l);
Value stored to 'l' is never read
505 }
506
507 /* Now move marks if that action expands the region. */
508 ctk_text_buffer_get_iter_at_mark (priv->buffer, &iter, sr->start);
509 if (ctk_text_iter_compare (&iter, &start) > 0)
510 {
511 ctk_text_buffer_move_mark (priv->buffer, sr->start, &start);
512 }
513
514 ctk_text_buffer_get_iter_at_mark (priv->buffer, &iter, sr->end);
515 if (ctk_text_iter_compare (&iter, &end) < 0)
516 {
517 ctk_text_buffer_move_mark (priv->buffer, sr->end, &end);
518 }
519 }
520
521 priv->timestamp++;
522
523 DEBUG (print_region (region));
524}
525
526/**
527 * ctk_source_region_add_region:
528 * @region: a #CtkSourceRegion.
529 * @region_to_add: (nullable): the #CtkSourceRegion to add to @region, or %NULL.
530 *
531 * Adds @region_to_add to @region. @region_to_add is not modified.
532 *
533 * Since: 3.22
534 */
535void
536ctk_source_region_add_region (CtkSourceRegion *region,
537 CtkSourceRegion *region_to_add)
538{
539 CtkSourceRegionIter iter;
540 CtkTextBuffer *region_buffer;
541 CtkTextBuffer *region_to_add_buffer;
542
543 g_return_if_fail (CTK_SOURCE_IS_REGION (region))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_51
= 0; if (CTK_SOURCE_IS_REGION (region)) _g_boolean_var_51 = 1
; _g_boolean_var_51; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_REGION (region)"
); return; } } while (0)
;
544 g_return_if_fail (region_to_add == NULL || CTK_SOURCE_IS_REGION (region_to_add))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_52
= 0; if (region_to_add == ((void*)0) || CTK_SOURCE_IS_REGION
(region_to_add)) _g_boolean_var_52 = 1; _g_boolean_var_52; }
), 1))) { } else { g_return_if_fail_warning ("CtkSourceView",
((const char*) (__func__)), "region_to_add == NULL || CTK_SOURCE_IS_REGION (region_to_add)"
); return; } } while (0)
;
545
546 if (region_to_add == NULL((void*)0))
547 {
548 return;
549 }
550
551 region_buffer = ctk_source_region_get_buffer (region);
552 region_to_add_buffer = ctk_source_region_get_buffer (region_to_add);
553 g_return_if_fail (region_buffer == region_to_add_buffer)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_53
= 0; if (region_buffer == region_to_add_buffer) _g_boolean_var_53
= 1; _g_boolean_var_53; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "region_buffer == region_to_add_buffer"
); return; } } while (0)
;
554
555 if (region_buffer == NULL((void*)0))
556 {
557 return;
558 }
559
560 ctk_source_region_get_start_region_iter (region_to_add, &iter);
561
562 while (!ctk_source_region_iter_is_end (&iter))
563 {
564 CtkTextIter subregion_start;
565 CtkTextIter subregion_end;
566
567 if (!ctk_source_region_iter_get_subregion (&iter,
568 &subregion_start,
569 &subregion_end))
570 {
571 break;
572 }
573
574 ctk_source_region_add_subregion (region,
575 &subregion_start,
576 &subregion_end);
577
578 ctk_source_region_iter_next (&iter);
579 }
580}
581
582/**
583 * ctk_source_region_subtract_subregion:
584 * @region: a #CtkSourceRegion.
585 * @_start: the start of the subregion.
586 * @_end: the end of the subregion.
587 *
588 * Subtracts the subregion delimited by @_start and @_end from @region.
589 *
590 * Since: 3.22
591 */
592void
593ctk_source_region_subtract_subregion (CtkSourceRegion *region,
594 const CtkTextIter *_start,
595 const CtkTextIter *_end)
596{
597 CtkSourceRegionPrivate *priv;
598 GList *start_node;
599 GList *end_node;
600 GList *node;
601 CtkTextIter sr_start_iter;
602 CtkTextIter sr_end_iter;
603 gboolean done;
604 gboolean start_is_outside;
605 gboolean end_is_outside;
606 Subregion *sr;
607 CtkTextIter start;
608 CtkTextIter end;
609
610 g_return_if_fail (CTK_SOURCE_IS_REGION (region))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_54
= 0; if (CTK_SOURCE_IS_REGION (region)) _g_boolean_var_54 = 1
; _g_boolean_var_54; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_REGION (region)"
); return; } } while (0)
;
611 g_return_if_fail (_start != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_55
= 0; if (_start != ((void*)0)) _g_boolean_var_55 = 1; _g_boolean_var_55
; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView"
, ((const char*) (__func__)), "_start != NULL"); return; } } while
(0)
;
612 g_return_if_fail (_end != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_56
= 0; if (_end != ((void*)0)) _g_boolean_var_56 = 1; _g_boolean_var_56
; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView"
, ((const char*) (__func__)), "_end != NULL"); return; } } while
(0)
;
613
614 priv = ctk_source_region_get_instance_private (region);
615
616 if (priv->buffer == NULL((void*)0))
617 {
618 return;
619 }
620
621 start = *_start;
622 end = *_end;
623
624 DEBUG (g_print ("---\n"));
625 DEBUG (print_region (region));
626 DEBUG (g_message ("region_substract (%d, %d)",
627 ctk_text_iter_get_offset (&start),
628 ctk_text_iter_get_offset (&end)));
629
630 ctk_text_iter_order (&start, &end);
631
632 /* Find bounding subregions. */
633 start_node = find_nearest_subregion (region, &start, NULL((void*)0), FALSE(0), FALSE(0));
634 end_node = find_nearest_subregion (region, &end, start_node, TRUE(!(0)), FALSE(0));
635
636 /* Easy case first. */
637 if (start_node == NULL((void*)0) || end_node == NULL((void*)0) || end_node == start_node->prev)
638 {
639 return;
640 }
641
642 /* Deal with the start point. */
643 start_is_outside = end_is_outside = FALSE(0);
644
645 sr = start_node->data;
646 ctk_text_buffer_get_iter_at_mark (priv->buffer, &sr_start_iter, sr->start);
647 ctk_text_buffer_get_iter_at_mark (priv->buffer, &sr_end_iter, sr->end);
648
649 if (ctk_text_iter_in_range (&start, &sr_start_iter, &sr_end_iter) &&
650 !ctk_text_iter_equal (&start, &sr_start_iter))
651 {
652 /* The starting point is inside the first subregion. */
653 if (ctk_text_iter_in_range (&end, &sr_start_iter, &sr_end_iter) &&
654 !ctk_text_iter_equal (&end, &sr_end_iter))
655 {
656 /* The ending point is also inside the first
657 * subregion: we need to split.
658 */
659 Subregion *new_sr = g_slice_new0 (Subregion)(Subregion *) (__extension__ ({ gsize __s = sizeof (Subregion
); gpointer __p; __p = g_slice_alloc (__s); memset (__p, 0, __s
); __p; }))
;
660 new_sr->end = sr->end;
661 new_sr->start = ctk_text_buffer_create_mark (priv->buffer,
662 NULL((void*)0),
663 &end,
664 TRUE(!(0)));
665
666 start_node = g_list_insert_before (start_node, start_node->next, new_sr);
667
668 sr->end = ctk_text_buffer_create_mark (priv->buffer,
669 NULL((void*)0),
670 &start,
671 FALSE(0));
672
673 /* No further processing needed. */
674 DEBUG (g_message ("subregion splitted"));
675
676 return;
677 }
678 else
679 {
680 /* The ending point is outside, so just move
681 * the end of the subregion to the starting point.
682 */
683 ctk_text_buffer_move_mark (priv->buffer, sr->end, &start);
684 }
685 }
686 else
687 {
688 /* The starting point is outside (and so to the left)
689 * of the first subregion.
690 */
691 DEBUG (g_message ("start is outside"));
692
693 start_is_outside = TRUE(!(0));
694 }
695
696 /* Deal with the end point. */
697 if (start_node != end_node)
698 {
699 sr = end_node->data;
700 ctk_text_buffer_get_iter_at_mark (priv->buffer, &sr_start_iter, sr->start);
701 ctk_text_buffer_get_iter_at_mark (priv->buffer, &sr_end_iter, sr->end);
702 }
703
704 if (ctk_text_iter_in_range (&end, &sr_start_iter, &sr_end_iter) &&
705 !ctk_text_iter_equal (&end, &sr_end_iter))
706 {
707 /* Ending point is inside, move the start mark. */
708 ctk_text_buffer_move_mark (priv->buffer, sr->start, &end);
709 }
710 else
711 {
712 end_is_outside = TRUE(!(0));
713 DEBUG (g_message ("end is outside"));
714 }
715
716 /* Finally remove any intermediate subregions. */
717 done = FALSE(0);
718 node = start_node;
719
720 while (!done)
721 {
722 if (node == end_node)
723 {
724 /* We are done, exit in the next iteration. */
725 done = TRUE(!(0));
726 }
727
728 if ((node == start_node && !start_is_outside) ||
729 (node == end_node && !end_is_outside))
730 {
731 /* Skip starting or ending node. */
732 node = node->next;
733 }
734 else
735 {
736 GList *l = node->next;
737 sr = node->data;
738 ctk_text_buffer_delete_mark (priv->buffer, sr->start);
739 ctk_text_buffer_delete_mark (priv->buffer, sr->end);
740 g_slice_free (Subregion, sr)do { if (1) g_slice_free1 (sizeof (Subregion), (sr)); else (void
) ((Subregion*) 0 == (sr)); } while (0)
;
741 priv->subregions = g_list_delete_link (priv->subregions, node);
742 node = l;
743 }
744 }
745
746 priv->timestamp++;
747
748 DEBUG (print_region (region));
749
750 /* Now get rid of empty subregions. */
751 ctk_source_region_clear_zero_length_subregions (region);
752
753 DEBUG (print_region (region));
754}
755
756/**
757 * ctk_source_region_subtract_region:
758 * @region: a #CtkSourceRegion.
759 * @region_to_subtract: (nullable): the #CtkSourceRegion to subtract from
760 * @region, or %NULL.
761 *
762 * Subtracts @region_to_subtract from @region. @region_to_subtract is not
763 * modified.
764 *
765 * Since: 3.22
766 */
767void
768ctk_source_region_subtract_region (CtkSourceRegion *region,
769 CtkSourceRegion *region_to_subtract)
770{
771 CtkTextBuffer *region_buffer;
772 CtkTextBuffer *region_to_subtract_buffer;
773 CtkSourceRegionIter iter;
774
775 g_return_if_fail (CTK_SOURCE_IS_REGION (region))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_57
= 0; if (CTK_SOURCE_IS_REGION (region)) _g_boolean_var_57 = 1
; _g_boolean_var_57; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_REGION (region)"
); return; } } while (0)
;
776 g_return_if_fail (region_to_subtract == NULL || CTK_SOURCE_IS_REGION (region_to_subtract))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_58
= 0; if (region_to_subtract == ((void*)0) || CTK_SOURCE_IS_REGION
(region_to_subtract)) _g_boolean_var_58 = 1; _g_boolean_var_58
; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView"
, ((const char*) (__func__)), "region_to_subtract == NULL || CTK_SOURCE_IS_REGION (region_to_subtract)"
); return; } } while (0)
;
777
778 region_buffer = ctk_source_region_get_buffer (region);
779 region_to_subtract_buffer = ctk_source_region_get_buffer (region_to_subtract);
780 g_return_if_fail (region_buffer == region_to_subtract_buffer)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_59
= 0; if (region_buffer == region_to_subtract_buffer) _g_boolean_var_59
= 1; _g_boolean_var_59; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "region_buffer == region_to_subtract_buffer"
); return; } } while (0)
;
781
782 if (region_buffer == NULL((void*)0))
783 {
784 return;
785 }
786
787 ctk_source_region_get_start_region_iter (region_to_subtract, &iter);
788
789 while (!ctk_source_region_iter_is_end (&iter))
790 {
791 CtkTextIter subregion_start;
792 CtkTextIter subregion_end;
793
794 if (!ctk_source_region_iter_get_subregion (&iter,
795 &subregion_start,
796 &subregion_end))
797 {
798 break;
799 }
800
801 ctk_source_region_subtract_subregion (region,
802 &subregion_start,
803 &subregion_end);
804
805 ctk_source_region_iter_next (&iter);
806 }
807}
808
809/**
810 * ctk_source_region_is_empty:
811 * @region: (nullable): a #CtkSourceRegion, or %NULL.
812 *
813 * Returns whether the @region is empty. A %NULL @region is considered empty.
814 *
815 * Returns: whether the @region is empty.
816 * Since: 3.22
817 */
818gboolean
819ctk_source_region_is_empty (CtkSourceRegion *region)
820{
821 CtkSourceRegionIter region_iter;
822
823 if (region == NULL((void*)0))
824 {
825 return TRUE(!(0));
826 }
827
828 /* A #CtkSourceRegion can contain empty subregions. So checking the
829 * number of subregions is not sufficient.
830 * When calling ctk_source_region_add_subregion() with equal iters, the
831 * subregion is not added. But when a subregion becomes empty, due to
832 * text deletion, the subregion is not removed from the
833 * #CtkSourceRegion.
834 */
835
836 ctk_source_region_get_start_region_iter (region, &region_iter);
837
838 while (!ctk_source_region_iter_is_end (&region_iter))
839 {
840 CtkTextIter subregion_start;
841 CtkTextIter subregion_end;
842
843 if (!ctk_source_region_iter_get_subregion (&region_iter,
844 &subregion_start,
845 &subregion_end))
846 {
847 return TRUE(!(0));
848 }
849
850 if (!ctk_text_iter_equal (&subregion_start, &subregion_end))
851 {
852 return FALSE(0);
853 }
854
855 ctk_source_region_iter_next (&region_iter);
856 }
857
858 return TRUE(!(0));
859}
860
861/**
862 * ctk_source_region_get_bounds:
863 * @region: a #CtkSourceRegion.
864 * @start: (out) (optional): iterator to initialize with the start of @region,
865 * or %NULL.
866 * @end: (out) (optional): iterator to initialize with the end of @region,
867 * or %NULL.
868 *
869 * Gets the @start and @end bounds of the @region.
870 *
871 * Returns: %TRUE if @start and @end have been set successfully (if non-%NULL),
872 * or %FALSE if the @region is empty.
873 * Since: 3.22
874 */
875gboolean
876ctk_source_region_get_bounds (CtkSourceRegion *region,
877 CtkTextIter *start,
878 CtkTextIter *end)
879{
880 CtkSourceRegionPrivate *priv;
881
882 g_return_val_if_fail (CTK_SOURCE_IS_REGION (region), FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_60
= 0; if (CTK_SOURCE_IS_REGION (region)) _g_boolean_var_60 = 1
; _g_boolean_var_60; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_REGION (region)"
); return ((0)); } } while (0)
;
883
884 priv = ctk_source_region_get_instance_private (region);
885
886 if (priv->buffer == NULL((void*)0) ||
887 ctk_source_region_is_empty (region))
888 {
889 return FALSE(0);
890 }
891
892 g_assert (priv->subregions != NULL)do { if (__builtin_expect (__extension__ ({ int _g_boolean_var_61
= 0; if (priv->subregions != ((void*)0)) _g_boolean_var_61
= 1; _g_boolean_var_61; }), 1)) ; else g_assertion_message_expr
("CtkSourceView", "../ctksourceview/ctksourceregion.c", 892,
((const char*) (__func__)), "priv->subregions != NULL"); }
while (0)
;
893
894 if (start != NULL((void*)0))
895 {
896 Subregion *first_subregion = priv->subregions->data;
897 ctk_text_buffer_get_iter_at_mark (priv->buffer, start, first_subregion->start);
898 }
899
900 if (end != NULL((void*)0))
901 {
902 Subregion *last_subregion = g_list_last (priv->subregions)->data;
903 ctk_text_buffer_get_iter_at_mark (priv->buffer, end, last_subregion->end);
904 }
905
906 return TRUE(!(0));
907}
908
909/**
910 * ctk_source_region_intersect_subregion:
911 * @region: a #CtkSourceRegion.
912 * @_start: the start of the subregion.
913 * @_end: the end of the subregion.
914 *
915 * Returns the intersection between @region and the subregion delimited by
916 * @_start and @_end. @region is not modified.
917 *
918 * Returns: (transfer full) (nullable): the intersection as a new
919 * #CtkSourceRegion.
920 * Since: 3.22
921 */
922CtkSourceRegion *
923ctk_source_region_intersect_subregion (CtkSourceRegion *region,
924 const CtkTextIter *_start,
925 const CtkTextIter *_end)
926{
927 CtkSourceRegionPrivate *priv;
928 CtkSourceRegion *new_region;
929 CtkSourceRegionPrivate *new_priv;
930 GList *start_node;
931 GList *end_node;
932 GList *node;
933 CtkTextIter sr_start_iter;
934 CtkTextIter sr_end_iter;
935 Subregion *sr;
936 Subregion *new_sr;
937 gboolean done;
938 CtkTextIter start;
939 CtkTextIter end;
940
941 g_return_val_if_fail (CTK_SOURCE_IS_REGION (region), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_62
= 0; if (CTK_SOURCE_IS_REGION (region)) _g_boolean_var_62 = 1
; _g_boolean_var_62; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_REGION (region)"
); return (((void*)0)); } } while (0)
;
942 g_return_val_if_fail (_start != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_63
= 0; if (_start != ((void*)0)) _g_boolean_var_63 = 1; _g_boolean_var_63
; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView"
, ((const char*) (__func__)), "_start != NULL"); return (((void
*)0)); } } while (0)
;
943 g_return_val_if_fail (_end != NULL, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_64
= 0; if (_end != ((void*)0)) _g_boolean_var_64 = 1; _g_boolean_var_64
; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView"
, ((const char*) (__func__)), "_end != NULL"); return (((void
*)0)); } } while (0)
;
944
945 priv = ctk_source_region_get_instance_private (region);
946
947 if (priv->buffer == NULL((void*)0))
948 {
949 return NULL((void*)0);
950 }
951
952 start = *_start;
953 end = *_end;
954
955 ctk_text_iter_order (&start, &end);
956
957 /* Find bounding subregions. */
958 start_node = find_nearest_subregion (region, &start, NULL((void*)0), FALSE(0), FALSE(0));
959 end_node = find_nearest_subregion (region, &end, start_node, TRUE(!(0)), FALSE(0));
960
961 /* Easy case first. */
962 if (start_node == NULL((void*)0) || end_node == NULL((void*)0) || end_node == start_node->prev)
963 {
964 return NULL((void*)0);
965 }
966
967 new_region = ctk_source_region_new (priv->buffer);
968 new_priv = ctk_source_region_get_instance_private (new_region);
969 done = FALSE(0);
970
971 sr = start_node->data;
972 ctk_text_buffer_get_iter_at_mark (priv->buffer, &sr_start_iter, sr->start);
973 ctk_text_buffer_get_iter_at_mark (priv->buffer, &sr_end_iter, sr->end);
974
975 /* Starting node. */
976 if (ctk_text_iter_in_range (&start, &sr_start_iter, &sr_end_iter))
977 {
978 new_sr = g_slice_new0 (Subregion)(Subregion *) (__extension__ ({ gsize __s = sizeof (Subregion
); gpointer __p; __p = g_slice_alloc (__s); memset (__p, 0, __s
); __p; }))
;
979 new_priv->subregions = g_list_prepend (new_priv->subregions, new_sr);
980
981 new_sr->start = ctk_text_buffer_create_mark (new_priv->buffer,
982 NULL((void*)0),
983 &start,
984 TRUE(!(0)));
985
986 if (start_node == end_node)
987 {
988 /* Things will finish shortly. */
989 done = TRUE(!(0));
990 if (ctk_text_iter_in_range (&end, &sr_start_iter, &sr_end_iter))
991 {
992 new_sr->end = ctk_text_buffer_create_mark (new_priv->buffer,
993 NULL((void*)0),
994 &end,
995 FALSE(0));
996 }
997 else
998 {
999 new_sr->end = ctk_text_buffer_create_mark (new_priv->buffer,
1000 NULL((void*)0),
1001 &sr_end_iter,
1002 FALSE(0));
1003 }
1004 }
1005 else
1006 {
1007 new_sr->end = ctk_text_buffer_create_mark (new_priv->buffer,
1008 NULL((void*)0),
1009 &sr_end_iter,
1010 FALSE(0));
1011 }
1012
1013 node = start_node->next;
1014 }
1015 else
1016 {
1017 /* start should be the same as the subregion, so copy it in the
1018 * loop.
1019 */
1020 node = start_node;
1021 }
1022
1023 if (!done)
1024 {
1025 while (node != end_node)
1026 {
1027 /* Copy intermediate subregions verbatim. */
1028 sr = node->data;
1029 ctk_text_buffer_get_iter_at_mark (priv->buffer, &sr_start_iter, sr->start);
1030 ctk_text_buffer_get_iter_at_mark (priv->buffer, &sr_end_iter, sr->end);
1031
1032 new_sr = g_slice_new0 (Subregion)(Subregion *) (__extension__ ({ gsize __s = sizeof (Subregion
); gpointer __p; __p = g_slice_alloc (__s); memset (__p, 0, __s
); __p; }))
;
1033 new_priv->subregions = g_list_prepend (new_priv->subregions, new_sr);
1034
1035 new_sr->start = ctk_text_buffer_create_mark (new_priv->buffer,
1036 NULL((void*)0),
1037 &sr_start_iter,
1038 TRUE(!(0)));
1039
1040 new_sr->end = ctk_text_buffer_create_mark (new_priv->buffer,
1041 NULL((void*)0),
1042 &sr_end_iter,
1043 FALSE(0));
1044
1045 /* Next node. */
1046 node = node->next;
1047 }
1048
1049 /* Ending node. */
1050 sr = node->data;
1051 ctk_text_buffer_get_iter_at_mark (priv->buffer, &sr_start_iter, sr->start);
1052 ctk_text_buffer_get_iter_at_mark (priv->buffer, &sr_end_iter, sr->end);
1053
1054 new_sr = g_slice_new0 (Subregion)(Subregion *) (__extension__ ({ gsize __s = sizeof (Subregion
); gpointer __p; __p = g_slice_alloc (__s); memset (__p, 0, __s
); __p; }))
;
1055 new_priv->subregions = g_list_prepend (new_priv->subregions, new_sr);
1056
1057 new_sr->start = ctk_text_buffer_create_mark (new_priv->buffer,
1058 NULL((void*)0),
1059 &sr_start_iter,
1060 TRUE(!(0)));
1061
1062 if (ctk_text_iter_in_range (&end, &sr_start_iter, &sr_end_iter))
1063 {
1064 new_sr->end = ctk_text_buffer_create_mark (new_priv->buffer,
1065 NULL((void*)0),
1066 &end,
1067 FALSE(0));
1068 }
1069 else
1070 {
1071 new_sr->end = ctk_text_buffer_create_mark (new_priv->buffer,
1072 NULL((void*)0),
1073 &sr_end_iter,
1074 FALSE(0));
1075 }
1076 }
1077
1078 new_priv->subregions = g_list_reverse (new_priv->subregions);
1079 return new_region;
1080}
1081
1082/**
1083 * ctk_source_region_intersect_region:
1084 * @region1: (nullable): a #CtkSourceRegion, or %NULL.
1085 * @region2: (nullable): a #CtkSourceRegion, or %NULL.
1086 *
1087 * Returns the intersection between @region1 and @region2. @region1 and
1088 * @region2 are not modified.
1089 *
1090 * Returns: (transfer full) (nullable): the intersection as a #CtkSourceRegion
1091 * object.
1092 * Since: 3.22
1093 */
1094CtkSourceRegion *
1095ctk_source_region_intersect_region (CtkSourceRegion *region1,
1096 CtkSourceRegion *region2)
1097{
1098 CtkTextBuffer *region1_buffer;
1099 CtkTextBuffer *region2_buffer;
1100 CtkSourceRegion *full_intersect = NULL((void*)0);
1101 CtkSourceRegionIter region2_iter;
1102
1103 g_return_val_if_fail (region1 == NULL || CTK_SOURCE_IS_REGION (region1), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_65
= 0; if (region1 == ((void*)0) || CTK_SOURCE_IS_REGION (region1
)) _g_boolean_var_65 = 1; _g_boolean_var_65; }), 1))) { } else
{ g_return_if_fail_warning ("CtkSourceView", ((const char*) (
__func__)), "region1 == NULL || CTK_SOURCE_IS_REGION (region1)"
); return (((void*)0)); } } while (0)
;
1104 g_return_val_if_fail (region2 == NULL || CTK_SOURCE_IS_REGION (region2), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_66
= 0; if (region2 == ((void*)0) || CTK_SOURCE_IS_REGION (region2
)) _g_boolean_var_66 = 1; _g_boolean_var_66; }), 1))) { } else
{ g_return_if_fail_warning ("CtkSourceView", ((const char*) (
__func__)), "region2 == NULL || CTK_SOURCE_IS_REGION (region2)"
); return (((void*)0)); } } while (0)
;
1105
1106 if (region1 == NULL((void*)0) && region2 == NULL((void*)0))
1107 {
1108 return NULL((void*)0);
1109 }
1110 if (region1 == NULL((void*)0))
1111 {
1112 return g_object_ref (region2);
1113 }
1114 if (region2 == NULL((void*)0))
1115 {
1116 return g_object_ref (region1);
1117 }
1118
1119 region1_buffer = ctk_source_region_get_buffer (region1);
1120 region2_buffer = ctk_source_region_get_buffer (region2);
1121 g_return_val_if_fail (region1_buffer == region2_buffer, NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_67
= 0; if (region1_buffer == region2_buffer) _g_boolean_var_67
= 1; _g_boolean_var_67; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "region1_buffer == region2_buffer"
); return (((void*)0)); } } while (0)
;
1122
1123 if (region1_buffer == NULL((void*)0))
1124 {
1125 return NULL((void*)0);
1126 }
1127
1128 ctk_source_region_get_start_region_iter (region2, &region2_iter);
1129
1130 while (!ctk_source_region_iter_is_end (&region2_iter))
1131 {
1132 CtkTextIter subregion2_start;
1133 CtkTextIter subregion2_end;
1134 CtkSourceRegion *sub_intersect;
1135
1136 if (!ctk_source_region_iter_get_subregion (&region2_iter,
1137 &subregion2_start,
1138 &subregion2_end))
1139 {
1140 break;
1141 }
1142
1143 sub_intersect = ctk_source_region_intersect_subregion (region1,
1144 &subregion2_start,
1145 &subregion2_end);
1146
1147 if (full_intersect == NULL((void*)0))
1148 {
1149 full_intersect = sub_intersect;
1150 }
1151 else
1152 {
1153 ctk_source_region_add_region (full_intersect, sub_intersect);
1154 g_clear_object (&sub_intersect)do { _Static_assert (sizeof *((&sub_intersect)) == sizeof
(gpointer), "Expression evaluates to false"); union { char *
in; gpointer *out; } _pp; gpointer _p; GDestroyNotify _destroy
= (GDestroyNotify) (g_object_unref); _pp.in = (char *) ((&
sub_intersect)); _p = *_pp.out; if (_p) { *_pp.out = ((void*)
0); _destroy (_p); } } while (0)
;
1155 }
1156
1157 ctk_source_region_iter_next (&region2_iter);
1158 }
1159
1160 return full_intersect;
1161}
1162
1163static gboolean
1164check_iterator (CtkSourceRegionIterReal *real)
1165{
1166 CtkSourceRegionPrivate *priv;
1167
1168 if (real->region == NULL((void*)0))
1169 {
1170 goto invalid;
1171 }
1172
1173 priv = ctk_source_region_get_instance_private (real->region);
1174
1175 if (real->region_timestamp == priv->timestamp)
1176 {
1177 return TRUE(!(0));
1178 }
1179
1180invalid:
1181 g_warning ("Invalid CtkSourceRegionIter: either the iterator is "
1182 "uninitialized, or the region has been modified since the "
1183 "iterator was created.");
1184
1185 return FALSE(0);
1186}
1187
1188/**
1189 * ctk_source_region_get_start_region_iter:
1190 * @region: a #CtkSourceRegion.
1191 * @iter: (out): iterator to initialize to the first subregion.
1192 *
1193 * Initializes a #CtkSourceRegionIter to the first subregion of @region. If
1194 * @region is empty, @iter will be initialized to the end iterator.
1195 *
1196 * Since: 3.22
1197 */
1198void
1199ctk_source_region_get_start_region_iter (CtkSourceRegion *region,
1200 CtkSourceRegionIter *iter)
1201{
1202 CtkSourceRegionPrivate *priv;
1203 CtkSourceRegionIterReal *real;
1204
1205 g_return_if_fail (CTK_SOURCE_IS_REGION (region))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_68
= 0; if (CTK_SOURCE_IS_REGION (region)) _g_boolean_var_68 = 1
; _g_boolean_var_68; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_REGION (region)"
); return; } } while (0)
;
1206 g_return_if_fail (iter != NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_69
= 0; if (iter != ((void*)0)) _g_boolean_var_69 = 1; _g_boolean_var_69
; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView"
, ((const char*) (__func__)), "iter != NULL"); return; } } while
(0)
;
1207
1208 priv = ctk_source_region_get_instance_private (region);
1209 real = (CtkSourceRegionIterReal *)iter;
1210
1211 /* priv->subregions may be NULL, -> end iter */
1212
1213 real->region = region;
1214 real->subregions = priv->subregions;
1215 real->region_timestamp = priv->timestamp;
1216}
1217
1218/**
1219 * ctk_source_region_iter_is_end:
1220 * @iter: a #CtkSourceRegionIter.
1221 *
1222 * Returns: whether @iter is the end iterator.
1223 * Since: 3.22
1224 */
1225gboolean
1226ctk_source_region_iter_is_end (CtkSourceRegionIter *iter)
1227{
1228 CtkSourceRegionIterReal *real;
1229
1230 g_return_val_if_fail (iter != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_70
= 0; if (iter != ((void*)0)) _g_boolean_var_70 = 1; _g_boolean_var_70
; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView"
, ((const char*) (__func__)), "iter != NULL"); return ((0)); }
} while (0)
;
1231
1232 real = (CtkSourceRegionIterReal *)iter;
1233 g_return_val_if_fail (check_iterator (real), FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_71
= 0; if (check_iterator (real)) _g_boolean_var_71 = 1; _g_boolean_var_71
; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView"
, ((const char*) (__func__)), "check_iterator (real)"); return
((0)); } } while (0)
;
1234
1235 return real->subregions == NULL((void*)0);
1236}
1237
1238/**
1239 * ctk_source_region_iter_next:
1240 * @iter: a #CtkSourceRegionIter.
1241 *
1242 * Moves @iter to the next subregion.
1243 *
1244 * Returns: %TRUE if @iter moved and is dereferenceable, or %FALSE if @iter has
1245 * been set to the end iterator.
1246 * Since: 3.22
1247 */
1248gboolean
1249ctk_source_region_iter_next (CtkSourceRegionIter *iter)
1250{
1251 CtkSourceRegionIterReal *real;
1252
1253 g_return_val_if_fail (iter != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_72
= 0; if (iter != ((void*)0)) _g_boolean_var_72 = 1; _g_boolean_var_72
; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView"
, ((const char*) (__func__)), "iter != NULL"); return ((0)); }
} while (0)
;
1254
1255 real = (CtkSourceRegionIterReal *)iter;
1256 g_return_val_if_fail (check_iterator (real), FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_73
= 0; if (check_iterator (real)) _g_boolean_var_73 = 1; _g_boolean_var_73
; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView"
, ((const char*) (__func__)), "check_iterator (real)"); return
((0)); } } while (0)
;
1257
1258 if (real->subregions != NULL((void*)0))
1259 {
1260 real->subregions = real->subregions->next;
1261 return TRUE(!(0));
1262 }
1263
1264 return FALSE(0);
1265}
1266
1267/**
1268 * ctk_source_region_iter_get_subregion:
1269 * @iter: a #CtkSourceRegionIter.
1270 * @start: (out) (optional): iterator to initialize with the subregion start, or %NULL.
1271 * @end: (out) (optional): iterator to initialize with the subregion end, or %NULL.
1272 *
1273 * Gets the subregion at this iterator.
1274 *
1275 * Returns: %TRUE if @start and @end have been set successfully (if non-%NULL),
1276 * or %FALSE if @iter is the end iterator or if the region is empty.
1277 * Since: 3.22
1278 */
1279gboolean
1280ctk_source_region_iter_get_subregion (CtkSourceRegionIter *iter,
1281 CtkTextIter *start,
1282 CtkTextIter *end)
1283{
1284 CtkSourceRegionIterReal *real;
1285 CtkSourceRegionPrivate *priv;
1286 Subregion *sr;
1287
1288 g_return_val_if_fail (iter != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_74
= 0; if (iter != ((void*)0)) _g_boolean_var_74 = 1; _g_boolean_var_74
; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView"
, ((const char*) (__func__)), "iter != NULL"); return ((0)); }
} while (0)
;
1289
1290 real = (CtkSourceRegionIterReal *)iter;
1291 g_return_val_if_fail (check_iterator (real), FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_75
= 0; if (check_iterator (real)) _g_boolean_var_75 = 1; _g_boolean_var_75
; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView"
, ((const char*) (__func__)), "check_iterator (real)"); return
((0)); } } while (0)
;
1292
1293 if (real->subregions == NULL((void*)0))
1294 {
1295 return FALSE(0);
1296 }
1297
1298 priv = ctk_source_region_get_instance_private (real->region);
1299
1300 if (priv->buffer == NULL((void*)0))
1301 {
1302 return FALSE(0);
1303 }
1304
1305 sr = real->subregions->data;
1306 g_return_val_if_fail (sr != NULL, FALSE)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_76
= 0; if (sr != ((void*)0)) _g_boolean_var_76 = 1; _g_boolean_var_76
; }), 1))) { } else { g_return_if_fail_warning ("CtkSourceView"
, ((const char*) (__func__)), "sr != NULL"); return ((0)); } }
while (0)
;
1307
1308 if (start != NULL((void*)0))
1309 {
1310 ctk_text_buffer_get_iter_at_mark (priv->buffer, start, sr->start);
1311 }
1312
1313 if (end != NULL((void*)0))
1314 {
1315 ctk_text_buffer_get_iter_at_mark (priv->buffer, end, sr->end);
1316 }
1317
1318 return TRUE(!(0));
1319}
1320
1321/**
1322 * ctk_source_region_to_string:
1323 * @region: a #CtkSourceRegion.
1324 *
1325 * Gets a string represention of @region, for debugging purposes.
1326 *
1327 * The returned string contains the character offsets of the subregions. It
1328 * doesn't include a newline character at the end of the string.
1329 *
1330 * Returns: (transfer full) (nullable): a string represention of @region. Free
1331 * with g_free() when no longer needed.
1332 * Since: 3.22
1333 */
1334gchar *
1335ctk_source_region_to_string (CtkSourceRegion *region)
1336{
1337 CtkSourceRegionPrivate *priv;
1338 GString *string;
1339 GList *l;
1340
1341 g_return_val_if_fail (CTK_SOURCE_IS_REGION (region), NULL)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_77
= 0; if (CTK_SOURCE_IS_REGION (region)) _g_boolean_var_77 = 1
; _g_boolean_var_77; }), 1))) { } else { g_return_if_fail_warning
("CtkSourceView", ((const char*) (__func__)), "CTK_SOURCE_IS_REGION (region)"
); return (((void*)0)); } } while (0)
;
1342
1343 priv = ctk_source_region_get_instance_private (region);
1344
1345 if (priv->buffer == NULL((void*)0))
1346 {
1347 return NULL((void*)0);
1348 }
1349
1350 string = g_string_new ("Subregions:");
1351
1352 for (l = priv->subregions; l != NULL((void*)0); l = l->next)
1353 {
1354 Subregion *sr = l->data;
1355 CtkTextIter start;
1356 CtkTextIter end;
1357
1358 ctk_text_buffer_get_iter_at_mark (priv->buffer, &start, sr->start);
1359 ctk_text_buffer_get_iter_at_mark (priv->buffer, &end, sr->end);
1360
1361 g_string_append_printf (string,
1362 " %d-%d",
1363 ctk_text_iter_get_offset (&start),
1364 ctk_text_iter_get_offset (&end));
1365 }
1366
1367 return g_string_free (string, FALSE(0));
1368}