Bug Summary

File:ctk/ctktextsegment.c
Warning:line 148, column 10
This statement is never executed

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 ctktextsegment.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 -fdebug-compilation-dir=/rootdir/ctk -fcoverage-compilation-dir=/rootdir/ctk -resource-dir /usr/lib/llvm-21/lib/clang/21 -D HAVE_CONFIG_H -I . -I .. -D G_LOG_DOMAIN="Ctk" -D G_LOG_USE_STRUCTURED=1 -D CTK_VERSION="3.25.7" -D CTK_BINARY_VERSION="3.0.0" -D CTK_COMPILATION -D CTK_PRINT_BACKEND_ENABLE_UNSUPPORTED -D CTK_LIBDIR="/usr/lib" -D CTK_LOCALEDIR="/usr/share/locale" -D CTK_DATADIR="/usr/share" -D CTK_DATA_PREFIX="/usr" -D CTK_SYSCONFDIR="/usr/etc" -D CTK_HOST="x86_64-pc-linux-gnu" -D CTK_PRINT_BACKENDS="file,cups" -D X11_DATA_PREFIX="/usr" -D ISO_CODES_PREFIX="" -I .. -I ../ctk -I .. -I ../cdk -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -D G_ENABLE_DEBUG -D G_ENABLE_CONSISTENCY_CHECKS -D GLIB_MIN_REQUIRED_VERSION=GLIB_VERSION_2_66 -D GLIB_MAX_ALLOWED_VERSION=GLIB_VERSION_2_66 -I /usr/include/pango-1.0 -I /usr/include/cairo -I /usr/local/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/atk-1.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/fribidi -I /usr/include/pixman-1 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/gio-unix-2.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/sysprof-6 -I /usr/include/pango-1.0 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -D PIC -internal-isystem /usr/lib/llvm-21/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/15/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -ferror-limit 19 -fvisibility=hidden -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -analyzer-checker deadcode.DeadStores -analyzer-checker security.ArrayBound -analyzer-checker unix.cstring.NotNullTerminated -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -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/2026-05-20-082140-45483-1 -x c ctktextsegment.c
1/*
2 * ctktextsegment.c --
3 *
4 * Code for segments in general, and toggle/char segments in particular.
5 *
6 * Copyright (c) 1992-1994 The Regents of the University of California.
7 * Copyright (c) 1994-1995 Sun Microsystems, Inc.
8 * Copyright (c) 2000 Red Hat, Inc.
9 * Tk -> Ctk port by Havoc Pennington <hp@redhat.com>
10 *
11 * This software is copyrighted by the Regents of the University of
12 * California, Sun Microsystems, Inc., and other parties. The
13 * following terms apply to all files associated with the software
14 * unless explicitly disclaimed in individual files.
15 *
16 * The authors hereby grant permission to use, copy, modify,
17 * distribute, and license this software and its documentation for any
18 * purpose, provided that existing copyright notices are retained in
19 * all copies and that this notice is included verbatim in any
20 * distributions. No written agreement, license, or royalty fee is
21 * required for any of the authorized uses. Modifications to this
22 * software may be copyrighted by their authors and need not follow
23 * the licensing terms described here, provided that the new terms are
24 * clearly indicated on the first page of each file where they apply.
25 *
26 * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY
27 * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
28 * DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION,
29 * OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED
30 * OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
33 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
34 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
35 * NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
36 * AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
37 * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
38 *
39 * GOVERNMENT USE: If you are acquiring this software on behalf of the
40 * U.S. government, the Government shall have only "Restricted Rights"
41 * in the software and related documentation as defined in the Federal
42 * Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you
43 * are acquiring the software on behalf of the Department of Defense,
44 * the software shall be classified as "Commercial Computer Software"
45 * and the Government shall have only "Restricted Rights" as defined
46 * in Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the
47 * foregoing, the authors grant the U.S. Government and others acting
48 * in its behalf permission to use and distribute the software in
49 * accordance with the terms specified in this license.
50 *
51 */
52
53#define CTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
54#include "config.h"
55#include "ctktextbtree.h"
56#include <string.h>
57#include <stdlib.h>
58#include <stdio.h>
59#include "ctktexttag.h"
60#include "ctktexttagtable.h"
61#include "ctktextlayout.h"
62#include "ctktextiterprivate.h"
63#include "ctkdebug.h"
64
65/*
66 *--------------------------------------------------------------
67 *
68 * split_segment --
69 *
70 * This procedure is called before adding or deleting
71 * segments. It does three things: (a) it finds the segment
72 * containing iter; (b) if there are several such
73 * segments (because some segments have zero length) then
74 * it picks the first segment that does not have left
75 * gravity; (c) if the index refers to the middle of
76 * a segment then it splits the segment so that the
77 * index now refers to the beginning of a segment.
78 *
79 * Results:
80 * The return value is a pointer to the segment just
81 * before the segment corresponding to iter (as
82 * described above). If the segment corresponding to
83 * iter is the first in its line then the return
84 * value is NULL.
85 *
86 * Side effects:
87 * The segment referred to by iter is split unless
88 * iter refers to its first character.
89 *
90 *--------------------------------------------------------------
91 */
92
93CtkTextLineSegment*
94ctk_text_line_segment_split (const CtkTextIter *iter)
95{
96 CtkTextLineSegment *prev, *seg;
97 CtkTextBTree *tree;
98 CtkTextLine *line;
99 int count;
100
101 line = _ctk_text_iter_get_text_line (iter);
102 tree = _ctk_text_iter_get_btree (iter);
103
104 count = ctk_text_iter_get_line_index (iter);
105
106 if (CTK_DEBUG_CHECK (TEXT)(ctk_get_debug_flags () & CTK_DEBUG_TEXT))
107 _ctk_text_iter_check (iter);
108
109 prev = NULL((void*)0);
110 seg = line->segments;
111
112 while (seg != NULL((void*)0))
113 {
114 if (seg->byte_count > count)
115 {
116 if (count == 0)
117 {
118 return prev;
119 }
120 else
121 {
122 g_assert (count != seg->byte_count)do { if (count != seg->byte_count) ; else g_assertion_message_expr
("Ctk", "ctktextsegment.c", 122, ((const char*) (__func__)),
"count != seg->byte_count"); } while (0)
;
123 g_assert (seg->byte_count > 0)do { if (seg->byte_count > 0) ; else g_assertion_message_expr
("Ctk", "ctktextsegment.c", 123, ((const char*) (__func__)),
"seg->byte_count > 0"); } while (0)
;
124
125 _ctk_text_btree_segments_changed (tree);
126
127 seg = (*seg->type->splitFunc)(seg, count);
128
129 if (prev == NULL((void*)0))
130 line->segments = seg;
131 else
132 prev->next = seg;
133
134 return seg;
135 }
136 }
137 else if ((seg->byte_count == 0) && (count == 0)
138 && !seg->type->leftGravity)
139 {
140 return prev;
141 }
142
143 count -= seg->byte_count;
144 prev = seg;
145 seg = seg->next;
146 }
147 g_error ("split_segment reached end of line!");
148 return NULL((void*)0);
This statement is never executed
149}
150
151
152/*
153 * Macros that determine how much space to allocate for new segments:
154 */
155
156#define CSEG_SIZE(chars)((unsigned) (((glong) __builtin_offsetof(CtkTextLineSegment, body
)) + 1 + (chars)))
((unsigned) (G_STRUCT_OFFSET (CtkTextLineSegment, body)((glong) __builtin_offsetof(CtkTextLineSegment, body)) \
157 + 1 + (chars)))
158#define TSEG_SIZE((unsigned) (((glong) __builtin_offsetof(CtkTextLineSegment, body
)) + sizeof (CtkTextToggleBody)))
((unsigned) (G_STRUCT_OFFSET (CtkTextLineSegment, body)((glong) __builtin_offsetof(CtkTextLineSegment, body)) \
159 + sizeof (CtkTextToggleBody)))
160
161/*
162 * Type functions
163 */
164
165static void
166char_segment_self_check (CtkTextLineSegment *seg)
167{
168 /* This function checks the segment itself, but doesn't
169 assume the segment has been validly inserted into
170 the btree. */
171
172 g_assert (seg != NULL)do { if (seg != ((void*)0)) ; else g_assertion_message_expr (
"Ctk", "ctktextsegment.c", 172, ((const char*) (__func__)), "seg != NULL"
); } while (0)
;
173
174 if (seg->byte_count <= 0)
175 {
176 g_error ("segment has size <= 0");
177 }
178
179 if (strlen (seg->body.chars) != seg->byte_count)
180 {
181 g_error ("segment has wrong size");
182 }
183
184 if (g_utf8_strlen (seg->body.chars, seg->byte_count) != seg->char_count)
185 {
186 g_error ("char segment has wrong character count");
187 }
188}
189
190CtkTextLineSegment*
191_ctk_char_segment_new (const gchar *text, guint len)
192{
193 CtkTextLineSegment *seg;
194
195 g_assert (ctk_text_byte_begins_utf8_char (text))do { if (ctk_text_byte_begins_utf8_char (text)) ; else g_assertion_message_expr
("Ctk", "ctktextsegment.c", 195, ((const char*) (__func__)),
"ctk_text_byte_begins_utf8_char (text)"); } while (0)
;
196
197 seg = g_slice_alloc (CSEG_SIZE (len)((unsigned) (((glong) __builtin_offsetof(CtkTextLineSegment, body
)) + 1 + (len)))
);
198 seg->type = (CtkTextLineSegmentClass *)&ctk_text_char_type;
199 seg->next = NULL((void*)0);
200 seg->byte_count = len;
201 memcpy (seg->body.chars, text, len);
202 seg->body.chars[len] = '\0';
203
204 seg->char_count = g_utf8_strlen (seg->body.chars, seg->byte_count);
205
206 if (CTK_DEBUG_CHECK (TEXT)(ctk_get_debug_flags () & CTK_DEBUG_TEXT))
207 char_segment_self_check (seg);
208
209 return seg;
210}
211
212CtkTextLineSegment*
213_ctk_char_segment_new_from_two_strings (const gchar *text1,
214 guint len1,
215 guint chars1,
216 const gchar *text2,
217 guint len2,
218 guint chars2)
219{
220 CtkTextLineSegment *seg;
221
222 g_assert (ctk_text_byte_begins_utf8_char (text1))do { if (ctk_text_byte_begins_utf8_char (text1)) ; else g_assertion_message_expr
("Ctk", "ctktextsegment.c", 222, ((const char*) (__func__)),
"ctk_text_byte_begins_utf8_char (text1)"); } while (0)
;
223 g_assert (ctk_text_byte_begins_utf8_char (text2))do { if (ctk_text_byte_begins_utf8_char (text2)) ; else g_assertion_message_expr
("Ctk", "ctktextsegment.c", 223, ((const char*) (__func__)),
"ctk_text_byte_begins_utf8_char (text2)"); } while (0)
;
224
225 seg = g_slice_alloc (CSEG_SIZE (len1+len2)((unsigned) (((glong) __builtin_offsetof(CtkTextLineSegment, body
)) + 1 + (len1+len2)))
);
226 seg->type = &ctk_text_char_type;
227 seg->next = NULL((void*)0);
228 seg->byte_count = len1 + len2;
229 memcpy (seg->body.chars, text1, len1);
230 memcpy (seg->body.chars + len1, text2, len2);
231 seg->body.chars[len1+len2] = '\0';
232
233 seg->char_count = chars1 + chars2;
234
235 if (CTK_DEBUG_CHECK (TEXT)(ctk_get_debug_flags () & CTK_DEBUG_TEXT))
236 char_segment_self_check (seg);
237
238 return seg;
239}
240
241static void
242_ctk_char_segment_free (CtkTextLineSegment *seg)
243{
244 if (seg == NULL((void*)0))
245 return;
246
247 g_assert (seg->type == &ctk_text_char_type)do { if (seg->type == &ctk_text_char_type) ; else g_assertion_message_expr
("Ctk", "ctktextsegment.c", 247, ((const char*) (__func__)),
"seg->type == &ctk_text_char_type"); } while (0)
;
248
249 g_slice_free1 (CSEG_SIZE (seg->byte_count)((unsigned) (((glong) __builtin_offsetof(CtkTextLineSegment, body
)) + 1 + (seg->byte_count)))
, seg);
250}
251
252/*
253 *--------------------------------------------------------------
254 *
255 * char_segment_split_func --
256 *
257 * This procedure implements splitting for character segments.
258 *
259 * Results:
260 * The return value is a pointer to a chain of two segments
261 * that have the same characters as segPtr except split
262 * among the two segments.
263 *
264 * Side effects:
265 * Storage for segPtr is freed.
266 *
267 *--------------------------------------------------------------
268 */
269
270static CtkTextLineSegment *
271char_segment_split_func (CtkTextLineSegment *seg, int index)
272{
273 CtkTextLineSegment *new1, *new2;
274
275 g_assert (index < seg->byte_count)do { if (index < seg->byte_count) ; else g_assertion_message_expr
("Ctk", "ctktextsegment.c", 275, ((const char*) (__func__)),
"index < seg->byte_count"); } while (0)
;
276
277 if (CTK_DEBUG_CHECK (TEXT)(ctk_get_debug_flags () & CTK_DEBUG_TEXT))
278 {
279 char_segment_self_check (seg);
280 }
281
282 new1 = _ctk_char_segment_new (seg->body.chars, index);
283 new2 = _ctk_char_segment_new (seg->body.chars + index, seg->byte_count - index);
284
285 g_assert (ctk_text_byte_begins_utf8_char (new1->body.chars))do { if (ctk_text_byte_begins_utf8_char (new1->body.chars)
) ; else g_assertion_message_expr ("Ctk", "ctktextsegment.c",
285, ((const char*) (__func__)), "ctk_text_byte_begins_utf8_char (new1->body.chars)"
); } while (0)
;
286 g_assert (ctk_text_byte_begins_utf8_char (new2->body.chars))do { if (ctk_text_byte_begins_utf8_char (new2->body.chars)
) ; else g_assertion_message_expr ("Ctk", "ctktextsegment.c",
286, ((const char*) (__func__)), "ctk_text_byte_begins_utf8_char (new2->body.chars)"
); } while (0)
;
287 g_assert (new1->byte_count + new2->byte_count == seg->byte_count)do { if (new1->byte_count + new2->byte_count == seg->
byte_count) ; else g_assertion_message_expr ("Ctk", "ctktextsegment.c"
, 287, ((const char*) (__func__)), "new1->byte_count + new2->byte_count == seg->byte_count"
); } while (0)
;
288 g_assert (new1->char_count + new2->char_count == seg->char_count)do { if (new1->char_count + new2->char_count == seg->
char_count) ; else g_assertion_message_expr ("Ctk", "ctktextsegment.c"
, 288, ((const char*) (__func__)), "new1->char_count + new2->char_count == seg->char_count"
); } while (0)
;
289
290 new1->next = new2;
291 new2->next = seg->next;
292
293 if (CTK_DEBUG_CHECK (TEXT)(ctk_get_debug_flags () & CTK_DEBUG_TEXT))
294 {
295 char_segment_self_check (new1);
296 char_segment_self_check (new2);
297 }
298
299 _ctk_char_segment_free (seg);
300 return new1;
301}
302
303/*
304 *--------------------------------------------------------------
305 *
306 * char_segment_cleanup_func --
307 *
308 * This procedure merges adjacent character segments into
309 * a single character segment, if possible.
310 *
311 * Arguments:
312 * segPtr: Pointer to the first of two adjacent segments to
313 * join.
314 * line: Line containing segments (not used).
315 *
316 * Results:
317 * The return value is a pointer to the first segment in
318 * the (new) list of segments that used to start with segPtr.
319 *
320 * Side effects:
321 * Storage for the segments may be allocated and freed.
322 *
323 *--------------------------------------------------------------
324 */
325
326 /* ARGSUSED */
327static CtkTextLineSegment *
328char_segment_cleanup_func (CtkTextLineSegment *segPtr,
329 CtkTextLine *line G_GNUC_UNUSED__attribute__ ((__unused__)))
330{
331 CtkTextLineSegment *segPtr2, *newPtr;
332
333 if (CTK_DEBUG_CHECK (TEXT)(ctk_get_debug_flags () & CTK_DEBUG_TEXT))
334 char_segment_self_check (segPtr);
335
336 segPtr2 = segPtr->next;
337 if ((segPtr2 == NULL((void*)0)) || (segPtr2->type != &ctk_text_char_type))
338 {
339 return segPtr;
340 }
341
342 newPtr =
343 _ctk_char_segment_new_from_two_strings (segPtr->body.chars,
344 segPtr->byte_count,
345 segPtr->char_count,
346 segPtr2->body.chars,
347 segPtr2->byte_count,
348 segPtr2->char_count);
349
350 newPtr->next = segPtr2->next;
351
352 if (CTK_DEBUG_CHECK (TEXT)(ctk_get_debug_flags () & CTK_DEBUG_TEXT))
353 char_segment_self_check (newPtr);
354
355 _ctk_char_segment_free (segPtr);
356 _ctk_char_segment_free (segPtr2);
357 return newPtr;
358}
359
360/*
361 *--------------------------------------------------------------
362 *
363 * char_segment_delete_func --
364 *
365 * This procedure is invoked to delete a character segment.
366 *
367 * Arguments:
368 * segPtr : Segment to delete
369 * line : Line containing segment
370 * treeGone : Non-zero means the entire tree is being
371 * deleted, so everything must get cleaned up.
372 *
373 * Results:
374 * Always returns 0 to indicate that the segment was deleted.
375 *
376 * Side effects:
377 * Storage for the segment is freed.
378 *
379 *--------------------------------------------------------------
380 */
381
382 /* ARGSUSED */
383static int
384char_segment_delete_func (CtkTextLineSegment *segPtr,
385 CtkTextLine *line G_GNUC_UNUSED__attribute__ ((__unused__)),
386 int treeGone G_GNUC_UNUSED__attribute__ ((__unused__)))
387{
388 _ctk_char_segment_free (segPtr);
389 return 0;
390}
391
392/*
393 *--------------------------------------------------------------
394 *
395 * char_segment_check_func --
396 *
397 * This procedure is invoked to perform consistency checks
398 * on character segments.
399 *
400 * Arguments:
401 * segPtr : Segment to check
402 * line : Line containing segment
403 *
404 * Results:
405 * None.
406 *
407 * Side effects:
408 * If the segment isn’t inconsistent then the procedure
409 * g_errors.
410 *
411 *--------------------------------------------------------------
412 */
413
414 /* ARGSUSED */
415static void
416char_segment_check_func (CtkTextLineSegment *segPtr,
417 CtkTextLine *line G_GNUC_UNUSED__attribute__ ((__unused__)))
418{
419 char_segment_self_check (segPtr);
420
421 if (segPtr->next != NULL((void*)0))
422 {
423 if (segPtr->next->type == &ctk_text_char_type)
424 {
425 g_error ("adjacent character segments weren't merged");
426 }
427 }
428}
429
430CtkTextLineSegment*
431_ctk_toggle_segment_new (CtkTextTagInfo *info, gboolean on)
432{
433 /* gcc-11 issues a diagnostic here because the size allocated
434 for SEG does not cover the entire size of a CtkTextLineSegment
435 and gcc has no way to know that the union will only be used
436 for limited types and the additional space is not needed. */
437#pragma GCC diagnostic push
438#pragma GCC diagnostic ignored "-Warray-bounds"
439 CtkTextLineSegment *seg;
440
441 seg = g_slice_alloc (TSEG_SIZE((unsigned) (((glong) __builtin_offsetof(CtkTextLineSegment, body
)) + sizeof (CtkTextToggleBody)))
);
442
443 seg->type = on ? &ctk_text_toggle_on_type : &ctk_text_toggle_off_type;
444
445 seg->next = NULL((void*)0);
446
447 seg->byte_count = 0;
448 seg->char_count = 0;
449
450 seg->body.toggle.info = info;
451 seg->body.toggle.inNodeCounts = 0;
452
453 return seg;
454#pragma GCC diagnostic pop
455}
456
457void
458_ctk_toggle_segment_free (CtkTextLineSegment *seg)
459{
460 if (seg == NULL((void*)0))
461 return;
462
463 g_assert (seg->type == &ctk_text_toggle_on_type ||do { if (seg->type == &ctk_text_toggle_on_type || seg->
type == &ctk_text_toggle_off_type) ; else g_assertion_message_expr
("Ctk", "ctktextsegment.c", 464, ((const char*) (__func__)),
"seg->type == &ctk_text_toggle_on_type || seg->type == &ctk_text_toggle_off_type"
); } while (0)
464 seg->type == &ctk_text_toggle_off_type)do { if (seg->type == &ctk_text_toggle_on_type || seg->
type == &ctk_text_toggle_off_type) ; else g_assertion_message_expr
("Ctk", "ctktextsegment.c", 464, ((const char*) (__func__)),
"seg->type == &ctk_text_toggle_on_type || seg->type == &ctk_text_toggle_off_type"
); } while (0)
;
465
466 g_slice_free1 (TSEG_SIZE((unsigned) (((glong) __builtin_offsetof(CtkTextLineSegment, body
)) + sizeof (CtkTextToggleBody)))
, seg);
467}
468
469/*
470 *--------------------------------------------------------------
471 *
472 * toggle_segment_delete_func --
473 *
474 * This procedure is invoked to delete toggle segments.
475 *
476 * Arguments:
477 * segPtr : Segment to check
478 * line : Line containing segment
479 * treeGone : Non-zero means the entire tree is being
480 * deleted so everything must get cleaned up
481 *
482 * Results:
483 * Returns 1 to indicate that the segment may not be deleted,
484 * unless the entire B-tree is going away.
485 *
486 * Side effects:
487 * If the tree is going away then the toggle’s memory is
488 * freed; otherwise the toggle counts in CtkTextBTreeNodes above the
489 * segment get updated.
490 *
491 *--------------------------------------------------------------
492 */
493
494static int
495toggle_segment_delete_func (CtkTextLineSegment *segPtr, CtkTextLine *line, int treeGone)
496{
497 if (treeGone)
498 {
499 _ctk_toggle_segment_free (segPtr);
500 return 0;
501 }
502
503 /*
504 * This toggle is in the middle of a range of characters that's
505 * being deleted. Refuse to die. We'll be moved to the end of
506 * the deleted range and our cleanup procedure will be called
507 * later. Decrement CtkTextBTreeNode toggle counts here, and set a flag
508 * so we'll re-increment them in the cleanup procedure.
509 */
510
511 if (segPtr->body.toggle.inNodeCounts)
512 {
513 _ctk_change_node_toggle_count (line->parent,
514 segPtr->body.toggle.info, -1);
515 segPtr->body.toggle.inNodeCounts = 0;
516 }
517 return 1;
518}
519
520/*
521 *--------------------------------------------------------------
522 *
523 * toggle_segment_cleanup_func --
524 *
525 * This procedure is called when a toggle is part of a line that's
526 * been modified in some way. It’s invoked after the
527 * modifications are complete.
528 *
529 * Arguments:
530 * segPtr : Segment to check
531 * line : Line that now contains segment
532 *
533 * Results:
534 * The return value is the head segment in a new list
535 * that is to replace the tail of the line that used to
536 * start at segPtr. This allows the procedure to delete
537 * or modify segPtr.
538 *
539 * Side effects:
540 * Toggle counts in the CtkTextBTreeNodes above the new line will be
541 * updated if they’re not already. Toggles may be collapsed
542 * if there are duplicate toggles at the same position.
543 *
544 *--------------------------------------------------------------
545 */
546
547static CtkTextLineSegment *
548toggle_segment_cleanup_func (CtkTextLineSegment *segPtr, CtkTextLine *line)
549{
550 CtkTextLineSegment *segPtr2, *prevPtr;
551
552 /*
553 * If this is a toggle-off segment, look ahead through the next
554 * segments to see if there's a toggle-on segment for the same tag
555 * before any segments with non-zero size. If so then the two
556 * toggles cancel each other; remove them both.
557 */
558
559 if (segPtr->type == &ctk_text_toggle_off_type)
560 {
561 for (prevPtr = segPtr, segPtr2 = prevPtr->next;
562 (segPtr2 != NULL((void*)0)) && (segPtr2->byte_count == 0);
563 prevPtr = segPtr2, segPtr2 = prevPtr->next)
564 {
565 int counts;
566
567 if (segPtr2->type != &ctk_text_toggle_on_type)
568 {
569 continue;
570 }
571 if (segPtr2->body.toggle.info != segPtr->body.toggle.info)
572 {
573 continue;
574 }
575 counts = segPtr->body.toggle.inNodeCounts
576 + segPtr2->body.toggle.inNodeCounts;
577 if (counts != 0)
578 {
579 _ctk_change_node_toggle_count (line->parent,
580 segPtr->body.toggle.info, -counts);
581 }
582 prevPtr->next = segPtr2->next;
583 _ctk_toggle_segment_free (segPtr2);
584 segPtr2 = segPtr->next;
585 _ctk_toggle_segment_free (segPtr);
586 return segPtr2;
587 }
588 }
589
590 if (!segPtr->body.toggle.inNodeCounts)
591 {
592 _ctk_change_node_toggle_count (line->parent,
593 segPtr->body.toggle.info, 1);
594 segPtr->body.toggle.inNodeCounts = 1;
595 }
596 return segPtr;
597}
598
599/*
600 *--------------------------------------------------------------
601 *
602 * toggle_segment_line_change_func --
603 *
604 * This procedure is invoked when a toggle segment is about
605 * to move from one line to another.
606 *
607 * Arguments:
608 * segPtr : Segment to check
609 * line : Line that used to contain segment
610 *
611 * Results:
612 * None.
613 *
614 * Side effects:
615 * Toggle counts are decremented in the CtkTextBTreeNodes above the line.
616 *
617 *--------------------------------------------------------------
618 */
619
620static void
621toggle_segment_line_change_func (CtkTextLineSegment *segPtr, CtkTextLine *line)
622{
623 if (segPtr->body.toggle.inNodeCounts)
624 {
625 _ctk_change_node_toggle_count (line->parent,
626 segPtr->body.toggle.info, -1);
627 segPtr->body.toggle.inNodeCounts = 0;
628 }
629}
630
631/*
632 * Virtual tables
633 */
634
635
636const CtkTextLineSegmentClass ctk_text_char_type = {
637 "character", /* name */
638 0, /* leftGravity */
639 char_segment_split_func, /* splitFunc */
640 char_segment_delete_func, /* deleteFunc */
641 char_segment_cleanup_func, /* cleanupFunc */
642 NULL((void*)0), /* lineChangeFunc */
643 char_segment_check_func /* checkFunc */
644};
645
646/*
647 * Type record for segments marking the beginning of a tagged
648 * range:
649 */
650
651const CtkTextLineSegmentClass ctk_text_toggle_on_type = {
652 "toggleOn", /* name */
653 0, /* leftGravity */
654 NULL((void*)0), /* splitFunc */
655 toggle_segment_delete_func, /* deleteFunc */
656 toggle_segment_cleanup_func, /* cleanupFunc */
657 toggle_segment_line_change_func, /* lineChangeFunc */
658 _ctk_toggle_segment_check_func /* checkFunc */
659};
660
661/*
662 * Type record for segments marking the end of a tagged
663 * range:
664 */
665
666const CtkTextLineSegmentClass ctk_text_toggle_off_type = {
667 "toggleOff", /* name */
668 1, /* leftGravity */
669 NULL((void*)0), /* splitFunc */
670 toggle_segment_delete_func, /* deleteFunc */
671 toggle_segment_cleanup_func, /* cleanupFunc */
672 toggle_segment_line_change_func, /* lineChangeFunc */
673 _ctk_toggle_segment_check_func /* checkFunc */
674};