]> Pileus Git - ~andy/gtk/blob - gtk/gtktextiter.c
Add hidden aliases for exported symbols which are used internally in order
[~andy/gtk] / gtk / gtktextiter.c
1 /* GTK - The GIMP Toolkit
2  * gtktextiter.c Copyright (C) 2000 Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
25  */
26
27 #define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
28 #include <config.h>
29 #include "gtkalias.h"
30 #include "gtktextiter.h"
31 #include "gtktextbtree.h"
32 #include "gtktextiterprivate.h"
33 #include "gtkdebug.h"
34 #include <string.h>
35
36 #define FIX_OVERFLOWS(varname) if ((varname) == G_MININT) (varname) = G_MININT + 1
37
38 typedef struct _GtkTextRealIter GtkTextRealIter;
39
40 struct _GtkTextRealIter
41 {
42   /* Always-valid information */
43   GtkTextBTree *tree;
44   GtkTextLine *line;
45   /* At least one of these is always valid;
46      if invalid, they are -1.
47
48      If the line byte offset is valid, so is the segment byte offset;
49      and ditto for char offsets. */
50   gint line_byte_offset;
51   gint line_char_offset;
52   /* These two are valid if >= 0 */
53   gint cached_char_index;
54   gint cached_line_number;
55   /* Stamps to detect the buffer changing under us */
56   gint chars_changed_stamp;
57   gint segments_changed_stamp;
58   /* Valid if the segments_changed_stamp is up-to-date */
59   GtkTextLineSegment *segment;     /* indexable segment we index */
60   GtkTextLineSegment *any_segment; /* first segment in our location,
61                                       maybe same as "segment" */
62   /* One of these will always be valid if segments_changed_stamp is
63      up-to-date. If invalid, they are -1.
64
65      If the line byte offset is valid, so is the segment byte offset;
66      and ditto for char offsets. */
67   gint segment_byte_offset;
68   gint segment_char_offset;
69
70   /* padding */
71   gint pad1;
72   gpointer pad2;
73 };
74
75 /* These "set" functions should not assume any fields
76    other than the char stamp and the tree are valid.
77 */
78 static void
79 iter_set_common (GtkTextRealIter *iter,
80                  GtkTextLine *line)
81 {
82   /* Update segments stamp */
83   iter->segments_changed_stamp =
84     _gtk_text_btree_get_segments_changed_stamp (iter->tree);
85
86   iter->line = line;
87
88   iter->line_byte_offset = -1;
89   iter->line_char_offset = -1;
90   iter->segment_byte_offset = -1;
91   iter->segment_char_offset = -1;
92   iter->cached_char_index = -1;
93   iter->cached_line_number = -1;
94 }
95
96 static void
97 iter_set_from_byte_offset (GtkTextRealIter *iter,
98                            GtkTextLine *line,
99                            gint byte_offset)
100 {
101   iter_set_common (iter, line);
102
103   if (!_gtk_text_line_byte_locate (iter->line,
104                                    byte_offset,
105                                    &iter->segment,
106                                    &iter->any_segment,
107                                    &iter->segment_byte_offset,
108                                    &iter->line_byte_offset))
109     g_error ("Byte index %d is off the end of the line",
110              byte_offset);
111 }
112
113 static void
114 iter_set_from_char_offset (GtkTextRealIter *iter,
115                            GtkTextLine *line,
116                            gint char_offset)
117 {
118   iter_set_common (iter, line);
119
120   if (!_gtk_text_line_char_locate (iter->line,
121                                    char_offset,
122                                    &iter->segment,
123                                    &iter->any_segment,
124                                    &iter->segment_char_offset,
125                                    &iter->line_char_offset))
126     g_error ("Char offset %d is off the end of the line",
127              char_offset);
128 }
129
130 static void
131 iter_set_from_segment (GtkTextRealIter *iter,
132                        GtkTextLine *line,
133                        GtkTextLineSegment *segment)
134 {
135   GtkTextLineSegment *seg;
136   gint byte_offset;
137
138   /* This could theoretically be optimized by computing all the iter
139      fields in this same loop, but I'm skipping it for now. */
140   byte_offset = 0;
141   seg = line->segments;
142   while (seg != segment)
143     {
144       byte_offset += seg->byte_count;
145       seg = seg->next;
146     }
147
148   iter_set_from_byte_offset (iter, line, byte_offset);
149 }
150
151 /* This function ensures that the segment-dependent information is
152    truly computed lazily; often we don't need to do the full make_real
153    work. This ensures the btree and line are valid, but doesn't
154    update the segments. */
155 static GtkTextRealIter*
156 gtk_text_iter_make_surreal (const GtkTextIter *_iter)
157 {
158   GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
159
160   if (iter->chars_changed_stamp !=
161       _gtk_text_btree_get_chars_changed_stamp (iter->tree))
162     {
163       g_warning ("Invalid text buffer iterator: either the iterator "
164                  "is uninitialized, or the characters/pixbufs/widgets "
165                  "in the buffer have been modified since the iterator "
166                  "was created.\nYou must use marks, character numbers, "
167                  "or line numbers to preserve a position across buffer "
168                  "modifications.\nYou can apply tags and insert marks "
169                  "without invalidating your iterators,\n"
170                  "but any mutation that affects 'indexable' buffer contents "
171                  "(contents that can be referred to by character offset)\n"
172                  "will invalidate all outstanding iterators");
173       return NULL;
174     }
175
176   /* We don't update the segments information since we are becoming
177      only surreal. However we do invalidate the segments information
178      if appropriate, to be sure we segfault if we try to use it and we
179      should have used make_real. */
180
181   if (iter->segments_changed_stamp !=
182       _gtk_text_btree_get_segments_changed_stamp (iter->tree))
183     {
184       iter->segment = NULL;
185       iter->any_segment = NULL;
186       /* set to segfault-causing values. */
187       iter->segment_byte_offset = -10000;
188       iter->segment_char_offset = -10000;
189     }
190
191   return iter;
192 }
193
194 static GtkTextRealIter*
195 gtk_text_iter_make_real (const GtkTextIter *_iter)
196 {
197   GtkTextRealIter *iter;
198
199   iter = gtk_text_iter_make_surreal (_iter);
200
201   if (iter->segments_changed_stamp !=
202       _gtk_text_btree_get_segments_changed_stamp (iter->tree))
203     {
204       if (iter->line_byte_offset >= 0)
205         {
206           iter_set_from_byte_offset (iter,
207                                      iter->line,
208                                      iter->line_byte_offset);
209         }
210       else
211         {
212           g_assert (iter->line_char_offset >= 0);
213
214           iter_set_from_char_offset (iter,
215                                      iter->line,
216                                      iter->line_char_offset);
217         }
218     }
219
220   g_assert (iter->segment != NULL);
221   g_assert (iter->any_segment != NULL);
222   g_assert (iter->segment->char_count > 0);
223
224   return iter;
225 }
226
227 static GtkTextRealIter*
228 iter_init_common (GtkTextIter *_iter,
229                   GtkTextBTree *tree)
230 {
231   GtkTextRealIter *iter = (GtkTextRealIter*)_iter;
232
233   g_return_val_if_fail (iter != NULL, NULL);
234   g_return_val_if_fail (tree != NULL, NULL);
235
236   iter->tree = tree;
237
238   iter->chars_changed_stamp =
239     _gtk_text_btree_get_chars_changed_stamp (iter->tree);
240
241   return iter;
242 }
243
244 static GtkTextRealIter*
245 iter_init_from_segment (GtkTextIter *iter,
246                         GtkTextBTree *tree,
247                         GtkTextLine *line,
248                         GtkTextLineSegment *segment)
249 {
250   GtkTextRealIter *real;
251
252   g_return_val_if_fail (line != NULL, NULL);
253
254   real = iter_init_common (iter, tree);
255
256   iter_set_from_segment (real, line, segment);
257
258   return real;
259 }
260
261 static GtkTextRealIter*
262 iter_init_from_byte_offset (GtkTextIter *iter,
263                             GtkTextBTree *tree,
264                             GtkTextLine *line,
265                             gint line_byte_offset)
266 {
267   GtkTextRealIter *real;
268
269   g_return_val_if_fail (line != NULL, NULL);
270
271   real = iter_init_common (iter, tree);
272
273   iter_set_from_byte_offset (real, line, line_byte_offset);
274
275   if (real->segment->type == &gtk_text_char_type &&
276       (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
277     g_warning ("Incorrect line byte index %d falls in the middle of a UTF-8 "
278                "character; this will crash the text buffer. "
279                "Byte indexes must refer to the start of a character.",
280                line_byte_offset);
281   
282   return real;
283 }
284
285 static GtkTextRealIter*
286 iter_init_from_char_offset (GtkTextIter *iter,
287                             GtkTextBTree *tree,
288                             GtkTextLine *line,
289                             gint line_char_offset)
290 {
291   GtkTextRealIter *real;
292
293   g_return_val_if_fail (line != NULL, NULL);
294
295   real = iter_init_common (iter, tree);
296
297   iter_set_from_char_offset (real, line, line_char_offset);
298
299   return real;
300 }
301
302 static inline void
303 invalidate_segment (GtkTextRealIter *iter)
304 {
305   iter->segments_changed_stamp -= 1;
306 }
307
308 static inline void
309 invalidate_char_index (GtkTextRealIter *iter)
310 {
311   iter->cached_char_index = -1;
312 }
313
314 static inline void
315 invalidate_line_number (GtkTextRealIter *iter)
316 {
317   iter->cached_line_number = -1;
318 }
319
320 static inline void
321 adjust_char_index (GtkTextRealIter *iter, gint count)
322 {
323   if (iter->cached_char_index >= 0)
324     iter->cached_char_index += count;
325 }
326
327 static inline void
328 adjust_line_number (GtkTextRealIter *iter, gint count)
329 {
330   if (iter->cached_line_number >= 0)
331     iter->cached_line_number += count;
332 }
333
334 static inline void
335 adjust_char_offsets (GtkTextRealIter *iter, gint count)
336 {
337   if (iter->line_char_offset >= 0)
338     {
339       iter->line_char_offset += count;
340       g_assert (iter->segment_char_offset >= 0);
341       iter->segment_char_offset += count;
342     }
343 }
344
345 static inline void
346 adjust_byte_offsets (GtkTextRealIter *iter, gint count)
347 {
348   if (iter->line_byte_offset >= 0)
349     {
350       iter->line_byte_offset += count;
351       g_assert (iter->segment_byte_offset >= 0);
352       iter->segment_byte_offset += count;
353     }
354 }
355
356 static inline void
357 ensure_char_offsets (GtkTextRealIter *iter)
358 {
359   if (iter->line_char_offset < 0)
360     {
361       g_assert (iter->line_byte_offset >= 0);
362
363       _gtk_text_line_byte_to_char_offsets (iter->line,
364                                           iter->line_byte_offset,
365                                           &iter->line_char_offset,
366                                           &iter->segment_char_offset);
367     }
368 }
369
370 static inline void
371 ensure_byte_offsets (GtkTextRealIter *iter)
372 {
373   if (iter->line_byte_offset < 0)
374     {
375       g_assert (iter->line_char_offset >= 0);
376
377       _gtk_text_line_char_to_byte_offsets (iter->line,
378                                           iter->line_char_offset,
379                                           &iter->line_byte_offset,
380                                           &iter->segment_byte_offset);
381     }
382 }
383
384 static inline gboolean
385 is_segment_start (GtkTextRealIter *real)
386 {
387   return real->segment_byte_offset == 0 || real->segment_char_offset == 0;
388 }
389
390 #if 1
391 static void
392 check_invariants (const GtkTextIter *iter)
393 {
394   if (gtk_debug_flags & GTK_DEBUG_TEXT)
395     _gtk_text_iter_check (iter);
396 }
397 #else
398 #define check_invariants (x)
399 #endif
400
401 /**
402  * gtk_text_iter_get_buffer:
403  * @iter: an iterator
404  *
405  * Returns the #GtkTextBuffer this iterator is associated with.
406  *
407  * Return value: the buffer
408  **/
409 GtkTextBuffer*
410 gtk_text_iter_get_buffer (const GtkTextIter *iter)
411 {
412   GtkTextRealIter *real;
413
414   g_return_val_if_fail (iter != NULL, NULL);
415
416   real = gtk_text_iter_make_surreal (iter);
417
418   if (real == NULL)
419     return NULL;
420
421   check_invariants (iter);
422
423   return _gtk_text_btree_get_buffer (real->tree);
424 }
425
426 /**
427  * gtk_text_iter_copy:
428  * @iter: an iterator
429  *
430  * Creates a dynamically-allocated copy of an iterator. This function
431  * is not useful in applications, because iterators can be copied with a
432  * simple assignment (<literal>GtkTextIter i = j;</literal>). The
433  * function is used by language bindings.
434  *
435  * Return value: a copy of the @iter, free with gtk_text_iter_free ()
436  **/
437 GtkTextIter*
438 gtk_text_iter_copy (const GtkTextIter *iter)
439 {
440   GtkTextIter *new_iter;
441
442   g_return_val_if_fail (iter != NULL, NULL);
443
444   new_iter = g_new (GtkTextIter, 1);
445
446   *new_iter = *iter;
447
448   return new_iter;
449 }
450
451 /**
452  * gtk_text_iter_free:
453  * @iter: a dynamically-allocated iterator
454  *
455  * Free an iterator allocated on the heap. This function
456  * is intended for use in language bindings, and is not
457  * especially useful for applications, because iterators can
458  * simply be allocated on the stack.
459  **/
460 void
461 gtk_text_iter_free (GtkTextIter *iter)
462 {
463   g_return_if_fail (iter != NULL);
464
465   g_free (iter);
466 }
467
468 GType
469 gtk_text_iter_get_type (void)
470 {
471   static GType our_type = 0;
472   
473   if (our_type == 0)
474     our_type = g_boxed_type_register_static ("GtkTextIter",
475                                              (GBoxedCopyFunc) gtk_text_iter_copy,
476                                              (GBoxedFreeFunc) gtk_text_iter_free);
477
478   return our_type;
479 }
480
481 GtkTextLineSegment*
482 _gtk_text_iter_get_indexable_segment (const GtkTextIter *iter)
483 {
484   GtkTextRealIter *real;
485
486   g_return_val_if_fail (iter != NULL, NULL);
487
488   real = gtk_text_iter_make_real (iter);
489
490   if (real == NULL)
491     return NULL;
492
493   check_invariants (iter);
494
495   g_assert (real->segment != NULL);
496
497   return real->segment;
498 }
499
500 GtkTextLineSegment*
501 _gtk_text_iter_get_any_segment (const GtkTextIter *iter)
502 {
503   GtkTextRealIter *real;
504
505   g_return_val_if_fail (iter != NULL, NULL);
506
507   real = gtk_text_iter_make_real (iter);
508
509   if (real == NULL)
510     return NULL;
511
512   check_invariants (iter);
513
514   g_assert (real->any_segment != NULL);
515
516   return real->any_segment;
517 }
518
519 gint
520 _gtk_text_iter_get_segment_byte (const GtkTextIter *iter)
521 {
522   GtkTextRealIter *real;
523
524   g_return_val_if_fail (iter != NULL, 0);
525
526   real = gtk_text_iter_make_real (iter);
527
528   if (real == NULL)
529     return 0;
530
531   ensure_byte_offsets (real);
532
533   check_invariants (iter);
534
535   return real->segment_byte_offset;
536 }
537
538 gint
539 _gtk_text_iter_get_segment_char (const GtkTextIter *iter)
540 {
541   GtkTextRealIter *real;
542
543   g_return_val_if_fail (iter != NULL, 0);
544
545   real = gtk_text_iter_make_real (iter);
546
547   if (real == NULL)
548     return 0;
549
550   ensure_char_offsets (real);
551
552   check_invariants (iter);
553
554   return real->segment_char_offset;
555 }
556
557 /* This function does not require a still-valid
558    iterator */
559 GtkTextLine*
560 _gtk_text_iter_get_text_line (const GtkTextIter *iter)
561 {
562   const GtkTextRealIter *real;
563
564   g_return_val_if_fail (iter != NULL, NULL);
565
566   real = (const GtkTextRealIter*)iter;
567
568   return real->line;
569 }
570
571 /* This function does not require a still-valid
572    iterator */
573 GtkTextBTree*
574 _gtk_text_iter_get_btree (const GtkTextIter *iter)
575 {
576   const GtkTextRealIter *real;
577
578   g_return_val_if_fail (iter != NULL, NULL);
579
580   real = (const GtkTextRealIter*)iter;
581
582   return real->tree;
583 }
584
585 /*
586  * Conversions
587  */
588
589 /**
590  * gtk_text_iter_get_offset:
591  * @iter: an iterator
592  *
593  * Returns the character offset of an iterator.
594  * Each character in a #GtkTextBuffer has an offset,
595  * starting with 0 for the first character in the buffer.
596  * Use gtk_text_buffer_get_iter_at_offset () to convert an
597  * offset back into an iterator.
598  *
599  * Return value: a character offset
600  **/
601 gint
602 gtk_text_iter_get_offset (const GtkTextIter *iter)
603 {
604   GtkTextRealIter *real;
605
606   g_return_val_if_fail (iter != NULL, 0);
607
608   real = gtk_text_iter_make_surreal (iter);
609
610   if (real == NULL)
611     return 0;
612
613   check_invariants (iter);
614   
615   if (real->cached_char_index < 0)
616     {
617       ensure_char_offsets (real);
618       
619       real->cached_char_index =
620         _gtk_text_line_char_index (real->line);
621       real->cached_char_index += real->line_char_offset;
622     }
623
624   check_invariants (iter);
625
626   return real->cached_char_index;
627 }
628
629 /**
630  * gtk_text_iter_get_line:
631  * @iter: an iterator
632  *
633  * Returns the line number containing the iterator. Lines in
634  * a #GtkTextBuffer are numbered beginning with 0 for the first
635  * line in the buffer.
636  *
637  * Return value: a line number
638  **/
639 gint
640 gtk_text_iter_get_line (const GtkTextIter *iter)
641 {
642   GtkTextRealIter *real;
643
644   g_return_val_if_fail (iter != NULL, 0);
645
646   real = gtk_text_iter_make_surreal (iter);
647
648   if (real == NULL)
649     return 0;
650
651   if (real->cached_line_number < 0)
652     real->cached_line_number =
653       _gtk_text_line_get_number (real->line);
654
655   check_invariants (iter);
656
657   return real->cached_line_number;
658 }
659
660 /**
661  * gtk_text_iter_get_line_offset:
662  * @iter: an iterator
663  *
664  * Returns the character offset of the iterator,
665  * counting from the start of a newline-terminated line.
666  * The first character on the line has offset 0.
667  *
668  * Return value: offset from start of line
669  **/
670 gint
671 gtk_text_iter_get_line_offset (const GtkTextIter *iter)
672 {
673   GtkTextRealIter *real;
674
675   g_return_val_if_fail (iter != NULL, 0);
676
677   real = gtk_text_iter_make_surreal (iter);
678
679   if (real == NULL)
680     return 0;
681
682   ensure_char_offsets (real);
683
684   check_invariants (iter);
685
686   return real->line_char_offset;
687 }
688
689 /**
690  * gtk_text_iter_get_line_index:
691  * @iter: an iterator
692  *
693  * Returns the byte index of the iterator, counting
694  * from the start of a newline-terminated line.
695  * Remember that #GtkTextBuffer encodes text in
696  * UTF-8, and that characters can require a variable
697  * number of bytes to represent.
698  *
699  * Return value: distance from start of line, in bytes
700  **/
701 gint
702 gtk_text_iter_get_line_index (const GtkTextIter *iter)
703 {
704   GtkTextRealIter *real;
705   
706   g_return_val_if_fail (iter != NULL, 0);
707
708   real = gtk_text_iter_make_surreal (iter);
709
710   if (real == NULL)
711     return 0;
712
713   ensure_byte_offsets (real);
714
715   check_invariants (iter);
716
717   return real->line_byte_offset;
718 }
719
720 /**
721  * gtk_text_iter_get_visible_line_offset:
722  * @iter: a #GtkTextIter
723  * 
724  * Returns the offset in characters from the start of the
725  * line to the given @iter, not counting characters that
726  * are invisible due to tags with the "invisible" flag
727  * toggled on.
728  * 
729  * Return value: offset in visible characters from the start of the line 
730  **/
731 gint
732 gtk_text_iter_get_visible_line_offset (const GtkTextIter *iter)
733 {
734   GtkTextRealIter *real;
735   gint vis_offset;
736   GtkTextLineSegment *seg;
737   GtkTextIter pos;
738   
739   g_return_val_if_fail (iter != NULL, 0);
740
741   real = gtk_text_iter_make_real (iter);
742
743   if (real == NULL)
744     return 0;
745
746   ensure_char_offsets (real);
747
748   check_invariants (iter);
749   
750   vis_offset = real->line_char_offset;
751
752   g_assert (vis_offset >= 0);
753   
754   _gtk_text_btree_get_iter_at_line (real->tree,
755                                     &pos,
756                                     real->line,
757                                     0);
758
759   seg = _gtk_text_iter_get_indexable_segment (&pos);
760
761   while (seg != real->segment)
762     {
763       /* This is a pretty expensive call, making the
764        * whole function pretty lame; we could keep track
765        * of current invisibility state by looking at toggle
766        * segments as we loop, and then call this function
767        * only once per line, in order to speed up the loop
768        * quite a lot.
769        */
770       if (_gtk_text_btree_char_is_invisible (&pos))
771         vis_offset -= seg->char_count;
772
773       _gtk_text_iter_forward_indexable_segment (&pos);
774
775       seg = _gtk_text_iter_get_indexable_segment (&pos);
776     }
777
778   if (_gtk_text_btree_char_is_invisible (&pos))
779     vis_offset -= real->segment_char_offset;
780   
781   return vis_offset;
782 }
783
784
785 /**
786  * gtk_text_iter_get_visible_line_index:
787  * @iter: a #GtkTextIter
788  * 
789  * Returns the number of bytes from the start of the
790  * line to the given @iter, not counting bytes that
791  * are invisible due to tags with the "invisible" flag
792  * toggled on.
793  * 
794  * Return value: byte index of @iter with respect to the start of the line
795  **/
796 gint
797 gtk_text_iter_get_visible_line_index (const GtkTextIter *iter)
798 {
799   GtkTextRealIter *real;
800   gint vis_offset;
801   GtkTextLineSegment *seg;
802   GtkTextIter pos;
803   
804   g_return_val_if_fail (iter != NULL, 0);
805
806   real = gtk_text_iter_make_real (iter);
807
808   if (real == NULL)
809     return 0;
810
811   ensure_byte_offsets (real);
812
813   check_invariants (iter);
814
815   vis_offset = real->line_byte_offset;
816
817   g_assert (vis_offset >= 0);
818   
819   _gtk_text_btree_get_iter_at_line (real->tree,
820                                     &pos,
821                                     real->line,
822                                     0);
823
824   seg = _gtk_text_iter_get_indexable_segment (&pos);
825
826   while (seg != real->segment)
827     {
828       /* This is a pretty expensive call, making the
829        * whole function pretty lame; we could keep track
830        * of current invisibility state by looking at toggle
831        * segments as we loop, and then call this function
832        * only once per line, in order to speed up the loop
833        * quite a lot.
834        */
835       if (_gtk_text_btree_char_is_invisible (&pos))
836         vis_offset -= seg->byte_count;
837
838       _gtk_text_iter_forward_indexable_segment (&pos);
839
840       seg = _gtk_text_iter_get_indexable_segment (&pos);
841     }
842
843   if (_gtk_text_btree_char_is_invisible (&pos))
844     vis_offset -= real->segment_byte_offset;
845   
846   return vis_offset;
847 }
848
849 /*
850  * Dereferencing
851  */
852
853 /**
854  * gtk_text_iter_get_char:
855  * @iter: an iterator
856  *
857  * Returns the Unicode character at this iterator.  (Equivalent to
858  * operator* on a C++ iterator.)  If the element at this iterator is a
859  * non-character element, such as an image embedded in the buffer, the
860  * Unicode "unknown" character 0xFFFC is returned. If invoked on
861  * the end iterator, zero is returned; zero is not a valid Unicode character.
862  * So you can write a loop which ends when gtk_text_iter_get_char ()
863  * returns 0.
864  *
865  * Return value: a Unicode character, or 0 if @iter is not dereferenceable
866  **/
867 gunichar
868 gtk_text_iter_get_char (const GtkTextIter *iter)
869 {
870   GtkTextRealIter *real;
871
872   g_return_val_if_fail (iter != NULL, 0);
873
874   real = gtk_text_iter_make_real (iter);
875
876   if (real == NULL)
877     return 0;
878
879   check_invariants (iter);
880
881   if (gtk_text_iter_is_end (iter))
882     return 0;
883   else if (real->segment->type == &gtk_text_char_type)
884     {
885       ensure_byte_offsets (real);
886       
887       return g_utf8_get_char (real->segment->body.chars +
888                               real->segment_byte_offset);
889     }
890   else
891     {
892       /* Unicode "unknown character" 0xFFFC */
893       return GTK_TEXT_UNKNOWN_CHAR;
894     }
895 }
896
897 /**
898  * gtk_text_iter_get_slice:
899  * @start: iterator at start of a range
900  * @end: iterator at end of a range
901  *
902  * Returns the text in the given range. A "slice" is an array of
903  * characters encoded in UTF-8 format, including the Unicode "unknown"
904  * character 0xFFFC for iterable non-character elements in the buffer,
905  * such as images.  Because images are encoded in the slice, byte and
906  * character offsets in the returned array will correspond to byte
907  * offsets in the text buffer. Note that 0xFFFC can occur in normal
908  * text as well, so it is not a reliable indicator that a pixbuf or
909  * widget is in the buffer.
910  *
911  * Return value: slice of text from the buffer
912  **/
913 gchar*
914 gtk_text_iter_get_slice       (const GtkTextIter *start,
915                                const GtkTextIter *end)
916 {
917   g_return_val_if_fail (start != NULL, NULL);
918   g_return_val_if_fail (end != NULL, NULL);
919
920   check_invariants (start);
921   check_invariants (end);
922
923   return _gtk_text_btree_get_text (start, end, TRUE, TRUE);
924 }
925
926 /**
927  * gtk_text_iter_get_text:
928  * @start: iterator at start of a range
929  * @end: iterator at end of a range
930  *
931  * Returns <emphasis>text</emphasis> in the given range.  If the range
932  * contains non-text elements such as images, the character and byte
933  * offsets in the returned string will not correspond to character and
934  * byte offsets in the buffer. If you want offsets to correspond, see
935  * gtk_text_iter_get_slice ().
936  *
937  * Return value: array of characters from the buffer
938  **/
939 gchar*
940 gtk_text_iter_get_text       (const GtkTextIter *start,
941                               const GtkTextIter *end)
942 {
943   g_return_val_if_fail (start != NULL, NULL);
944   g_return_val_if_fail (end != NULL, NULL);
945
946   check_invariants (start);
947   check_invariants (end);
948
949   return _gtk_text_btree_get_text (start, end, TRUE, FALSE);
950 }
951
952 /**
953  * gtk_text_iter_get_visible_slice:
954  * @start: iterator at start of range
955  * @end: iterator at end of range
956  *
957  * Like gtk_text_iter_get_slice (), but invisible text is not included.
958  * Invisible text is usually invisible because a #GtkTextTag with the
959  * "invisible" attribute turned on has been applied to it.
960  *
961  * Return value: slice of text from the buffer
962  **/
963 gchar*
964 gtk_text_iter_get_visible_slice (const GtkTextIter  *start,
965                                  const GtkTextIter  *end)
966 {
967   g_return_val_if_fail (start != NULL, NULL);
968   g_return_val_if_fail (end != NULL, NULL);
969
970   check_invariants (start);
971   check_invariants (end);
972
973   return _gtk_text_btree_get_text (start, end, FALSE, TRUE);
974 }
975
976 /**
977  * gtk_text_iter_get_visible_text:
978  * @start: iterator at start of range
979  * @end: iterator at end of range
980  *
981  * Like gtk_text_iter_get_text (), but invisible text is not included.
982  * Invisible text is usually invisible because a #GtkTextTag with the
983  * "invisible" attribute turned on has been applied to it.
984  *
985  * Return value: string containing visible text in the range
986  **/
987 gchar*
988 gtk_text_iter_get_visible_text (const GtkTextIter  *start,
989                                 const GtkTextIter  *end)
990 {
991   g_return_val_if_fail (start != NULL, NULL);
992   g_return_val_if_fail (end != NULL, NULL);
993
994   check_invariants (start);
995   check_invariants (end);
996
997   return _gtk_text_btree_get_text (start, end, FALSE, FALSE);
998 }
999
1000 /**
1001  * gtk_text_iter_get_pixbuf:
1002  * @iter: an iterator
1003  *
1004  * If the element at @iter is a pixbuf, the pixbuf is returned
1005  * (with no new reference count added). Otherwise,
1006  * %NULL is returned.
1007  *
1008  * Return value: the pixbuf at @iter
1009  **/
1010 GdkPixbuf*
1011 gtk_text_iter_get_pixbuf (const GtkTextIter *iter)
1012 {
1013   GtkTextRealIter *real;
1014
1015   g_return_val_if_fail (iter != NULL, NULL);
1016
1017   real = gtk_text_iter_make_real (iter);
1018
1019   if (real == NULL)
1020     return NULL;
1021
1022   check_invariants (iter);
1023
1024   if (real->segment->type != &gtk_text_pixbuf_type)
1025     return NULL;
1026   else
1027     return real->segment->body.pixbuf.pixbuf;
1028 }
1029
1030 /**
1031  * gtk_text_iter_get_child_anchor:
1032  * @iter: an iterator
1033  *
1034  * If the location at @iter contains a child anchor, the
1035  * anchor is returned (with no new reference count added). Otherwise,
1036  * %NULL is returned.
1037  *
1038  * Return value: the anchor at @iter
1039  **/
1040 GtkTextChildAnchor*
1041 gtk_text_iter_get_child_anchor (const GtkTextIter *iter)
1042 {
1043   GtkTextRealIter *real;
1044
1045   g_return_val_if_fail (iter != NULL, NULL);
1046
1047   real = gtk_text_iter_make_real (iter);
1048
1049   if (real == NULL)
1050     return NULL;
1051
1052   check_invariants (iter);
1053
1054   if (real->segment->type != &gtk_text_child_type)
1055     return NULL;
1056   else
1057     return real->segment->body.child.obj;
1058 }
1059
1060 /**
1061  * gtk_text_iter_get_marks:
1062  * @iter: an iterator
1063  *
1064  * Returns a list of all #GtkTextMark at this location. Because marks
1065  * are not iterable (they don't take up any "space" in the buffer,
1066  * they are just marks in between iterable locations), multiple marks
1067  * can exist in the same place. The returned list is not in any
1068  * meaningful order.
1069  *
1070  * Return value: list of #GtkTextMark
1071  **/
1072 GSList*
1073 gtk_text_iter_get_marks (const GtkTextIter *iter)
1074 {
1075   GtkTextRealIter *real;
1076   GtkTextLineSegment *seg;
1077   GSList *retval;
1078
1079   g_return_val_if_fail (iter != NULL, NULL);
1080
1081   real = gtk_text_iter_make_real (iter);
1082
1083   if (real == NULL)
1084     return NULL;
1085
1086   check_invariants (iter);
1087
1088   retval = NULL;
1089   seg = real->any_segment;
1090   while (seg != real->segment)
1091     {
1092       if (seg->type == &gtk_text_left_mark_type ||
1093           seg->type == &gtk_text_right_mark_type)
1094         retval = g_slist_prepend (retval, seg->body.mark.obj);
1095
1096       seg = seg->next;
1097     }
1098
1099   /* The returned list isn't guaranteed to be in any special order,
1100      and it isn't. */
1101   return retval;
1102 }
1103
1104 /**
1105  * gtk_text_iter_get_toggled_tags:
1106  * @iter: an iterator
1107  * @toggled_on: %TRUE to get toggled-on tags
1108  *
1109  * Returns a list of #GtkTextTag that are toggled on or off at this
1110  * point.  (If @toggled_on is %TRUE, the list contains tags that are
1111  * toggled on.) If a tag is toggled on at @iter, then some non-empty
1112  * range of characters following @iter has that tag applied to it.  If
1113  * a tag is toggled off, then some non-empty range following @iter
1114  * does <emphasis>not</emphasis> have the tag applied to it.
1115  *
1116  * Return value: tags toggled at this point
1117  **/
1118 GSList*
1119 gtk_text_iter_get_toggled_tags  (const GtkTextIter  *iter,
1120                                  gboolean            toggled_on)
1121 {
1122   GtkTextRealIter *real;
1123   GtkTextLineSegment *seg;
1124   GSList *retval;
1125
1126   g_return_val_if_fail (iter != NULL, NULL);
1127
1128   real = gtk_text_iter_make_real (iter);
1129
1130   if (real == NULL)
1131     return NULL;
1132
1133   check_invariants (iter);
1134
1135   retval = NULL;
1136   seg = real->any_segment;
1137   while (seg != real->segment)
1138     {
1139       if (toggled_on)
1140         {
1141           if (seg->type == &gtk_text_toggle_on_type)
1142             {
1143               retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1144             }
1145         }
1146       else
1147         {
1148           if (seg->type == &gtk_text_toggle_off_type)
1149             {
1150               retval = g_slist_prepend (retval, seg->body.toggle.info->tag);
1151             }
1152         }
1153
1154       seg = seg->next;
1155     }
1156
1157   /* The returned list isn't guaranteed to be in any special order,
1158      and it isn't. */
1159   return retval;
1160 }
1161
1162 /**
1163  * gtk_text_iter_begins_tag:
1164  * @iter: an iterator
1165  * @tag: a #GtkTextTag, or %NULL
1166  *
1167  * Returns %TRUE if @tag is toggled on at exactly this point. If @tag
1168  * is %NULL, returns %TRUE if any tag is toggled on at this point. Note
1169  * that the gtk_text_iter_begins_tag () returns %TRUE if @iter is the
1170  * <emphasis>start</emphasis> of the tagged range;
1171  * gtk_text_iter_has_tag () tells you whether an iterator is
1172  * <emphasis>within</emphasis> a tagged range.
1173  *
1174  * Return value: whether @iter is the start of a range tagged with @tag
1175  **/
1176 gboolean
1177 gtk_text_iter_begins_tag    (const GtkTextIter  *iter,
1178                              GtkTextTag         *tag)
1179 {
1180   GtkTextRealIter *real;
1181   GtkTextLineSegment *seg;
1182
1183   g_return_val_if_fail (iter != NULL, FALSE);
1184
1185   real = gtk_text_iter_make_real (iter);
1186
1187   if (real == NULL)
1188     return FALSE;
1189
1190   check_invariants (iter);
1191
1192   seg = real->any_segment;
1193   while (seg != real->segment)
1194     {
1195       if (seg->type == &gtk_text_toggle_on_type)
1196         {
1197           if (tag == NULL ||
1198               seg->body.toggle.info->tag == tag)
1199             return TRUE;
1200         }
1201
1202       seg = seg->next;
1203     }
1204
1205   return FALSE;
1206 }
1207
1208 /**
1209  * gtk_text_iter_ends_tag:
1210  * @iter: an iterator
1211  * @tag: a #GtkTextTag, or %NULL
1212  *
1213  * Returns %TRUE if @tag is toggled off at exactly this point. If @tag
1214  * is %NULL, returns %TRUE if any tag is toggled off at this point. Note
1215  * that the gtk_text_iter_ends_tag () returns %TRUE if @iter is the
1216  * <emphasis>end</emphasis> of the tagged range;
1217  * gtk_text_iter_has_tag () tells you whether an iterator is
1218  * <emphasis>within</emphasis> a tagged range.
1219  *
1220  * Return value: whether @iter is the end of a range tagged with @tag
1221  *
1222  **/
1223 gboolean
1224 gtk_text_iter_ends_tag   (const GtkTextIter  *iter,
1225                           GtkTextTag         *tag)
1226 {
1227   GtkTextRealIter *real;
1228   GtkTextLineSegment *seg;
1229
1230   g_return_val_if_fail (iter != NULL, FALSE);
1231
1232   real = gtk_text_iter_make_real (iter);
1233
1234   if (real == NULL)
1235     return FALSE;
1236
1237   check_invariants (iter);
1238
1239   seg = real->any_segment;
1240   while (seg != real->segment)
1241     {
1242       if (seg->type == &gtk_text_toggle_off_type)
1243         {
1244           if (tag == NULL ||
1245               seg->body.toggle.info->tag == tag)
1246             return TRUE;
1247         }
1248
1249       seg = seg->next;
1250     }
1251
1252   return FALSE;
1253 }
1254
1255 /**
1256  * gtk_text_iter_toggles_tag:
1257  * @iter: an iterator
1258  * @tag: a #GtkTextTag, or %NULL
1259  *
1260  * This is equivalent to (gtk_text_iter_begins_tag () ||
1261  * gtk_text_iter_ends_tag ()), i.e. it tells you whether a range with
1262  * @tag applied to it begins <emphasis>or</emphasis> ends at @iter.
1263  *
1264  * Return value: whether @tag is toggled on or off at @iter
1265  **/
1266 gboolean
1267 gtk_text_iter_toggles_tag (const GtkTextIter  *iter,
1268                            GtkTextTag         *tag)
1269 {
1270   GtkTextRealIter *real;
1271   GtkTextLineSegment *seg;
1272
1273   g_return_val_if_fail (iter != NULL, FALSE);
1274
1275   real = gtk_text_iter_make_real (iter);
1276
1277   if (real == NULL)
1278     return FALSE;
1279
1280   check_invariants (iter);
1281
1282   seg = real->any_segment;
1283   while (seg != real->segment)
1284     {
1285       if ( (seg->type == &gtk_text_toggle_off_type ||
1286             seg->type == &gtk_text_toggle_on_type) &&
1287            (tag == NULL ||
1288             seg->body.toggle.info->tag == tag) )
1289         return TRUE;
1290
1291       seg = seg->next;
1292     }
1293
1294   return FALSE;
1295 }
1296
1297 /**
1298  * gtk_text_iter_has_tag:
1299  * @iter: an iterator
1300  * @tag: a #GtkTextTag
1301  *
1302  * Returns %TRUE if @iter is within a range tagged with @tag.
1303  *
1304  * Return value: whether @iter is tagged with @tag
1305  **/
1306 gboolean
1307 gtk_text_iter_has_tag (const GtkTextIter   *iter,
1308                        GtkTextTag          *tag)
1309 {
1310   GtkTextRealIter *real;
1311
1312   g_return_val_if_fail (iter != NULL, FALSE);
1313   g_return_val_if_fail (GTK_IS_TEXT_TAG (tag), FALSE);
1314
1315   real = gtk_text_iter_make_surreal (iter);
1316
1317   if (real == NULL)
1318     return FALSE;
1319
1320   check_invariants (iter);
1321
1322   if (real->line_byte_offset >= 0)
1323     {
1324       return _gtk_text_line_byte_has_tag (real->line, real->tree,
1325                                           real->line_byte_offset, tag);
1326     }
1327   else
1328     {
1329       g_assert (real->line_char_offset >= 0);
1330       return _gtk_text_line_char_has_tag (real->line, real->tree,
1331                                           real->line_char_offset, tag);
1332     }
1333 }
1334
1335 /**
1336  * gtk_text_iter_get_tags:
1337  * @iter: a #GtkTextIter
1338  * 
1339  * Returns a list of tags that apply to @iter, in ascending order of
1340  * priority (highest-priority tags are last). The #GtkTextTag in the
1341  * list don't have a reference added, but you have to free the list
1342  * itself.
1343  * 
1344  * Return value: list of #GtkTextTag
1345  **/
1346 GSList*
1347 gtk_text_iter_get_tags (const GtkTextIter *iter)
1348 {
1349   GtkTextTag** tags;
1350   gint tag_count = 0;
1351   gint i;
1352   GSList *retval;
1353   
1354   g_return_val_if_fail (iter != NULL, NULL);
1355   
1356   /* Get the tags at this spot */
1357   tags = _gtk_text_btree_get_tags (iter, &tag_count);
1358
1359   /* No tags, use default style */
1360   if (tags == NULL || tag_count == 0)
1361     {
1362       if (tags)
1363         g_free (tags);
1364
1365       return NULL;
1366     }
1367
1368   /* Sort tags in ascending order of priority */
1369   _gtk_text_tag_array_sort (tags, tag_count);
1370
1371   retval = NULL;
1372   i = 0;
1373   while (i < tag_count)
1374     {
1375       retval = g_slist_prepend (retval, tags[i]);
1376       ++i;
1377     }
1378   
1379   g_free (tags);
1380
1381   /* Return tags in ascending order of priority */
1382   return g_slist_reverse (retval);
1383 }
1384
1385 /**
1386  * gtk_text_iter_editable:
1387  * @iter: an iterator
1388  * @default_setting: %TRUE if text is editable by default
1389  *
1390  * Returns whether the character at @iter is within an editable region
1391  * of text.  Non-editable text is "locked" and can't be changed by the
1392  * user via #GtkTextView. This function is simply a convenience
1393  * wrapper around gtk_text_iter_get_attributes (). If no tags applied
1394  * to this text affect editability, @default_setting will be returned.
1395  *
1396  * You don't want to use this function to decide whether text can be
1397  * inserted at @iter, because for insertion you don't want to know
1398  * whether the char at @iter is inside an editable range, you want to
1399  * know whether a new character inserted at @iter would be inside an
1400  * editable range. Use gtk_text_iter_can_insert() to handle this
1401  * case.
1402  * 
1403  * Return value: whether @iter is inside an editable range
1404  **/
1405 gboolean
1406 gtk_text_iter_editable (const GtkTextIter *iter,
1407                         gboolean           default_setting)
1408 {
1409   GtkTextAttributes *values;
1410   gboolean retval;
1411
1412   g_return_val_if_fail (iter != NULL, FALSE);
1413   
1414   values = gtk_text_attributes_new ();
1415
1416   values->editable = default_setting;
1417
1418   gtk_text_iter_get_attributes (iter, values);
1419
1420   retval = values->editable;
1421
1422   gtk_text_attributes_unref (values);
1423
1424   return retval;
1425 }
1426
1427 /**
1428  * gtk_text_iter_can_insert:
1429  * @iter: an iterator
1430  * @default_editability: %TRUE if text is editable by default
1431  * 
1432  * Considering the default editability of the buffer, and tags that
1433  * affect editability, determines whether text inserted at @iter would
1434  * be editable. If text inserted at @iter would be editable then the
1435  * user should be allowed to insert text at @iter.
1436  * gtk_text_buffer_insert_interactive() uses this function to decide
1437  * whether insertions are allowed at a given position.
1438  * 
1439  * Return value: whether text inserted at @iter would be editable
1440  **/
1441 gboolean
1442 gtk_text_iter_can_insert (const GtkTextIter *iter,
1443                           gboolean           default_editability)
1444 {
1445   g_return_val_if_fail (iter != NULL, FALSE);
1446   
1447   if (gtk_text_iter_editable (iter, default_editability))
1448     return TRUE;
1449   /* If at start/end of buffer, default editability is used */
1450   else if ((gtk_text_iter_is_start (iter) ||
1451             gtk_text_iter_is_end (iter)) &&
1452            default_editability)
1453     return TRUE;
1454   else
1455     {
1456       /* if iter isn't editable, and the char before iter is,
1457        * then iter is the first char in an editable region
1458        * and thus insertion at iter results in editable text.
1459        */
1460       GtkTextIter prev = *iter;
1461       gtk_text_iter_backward_char (&prev);
1462       return gtk_text_iter_editable (&prev, default_editability);
1463     }
1464 }
1465
1466
1467 /**
1468  * gtk_text_iter_get_language:
1469  * @iter: an iterator
1470  *
1471  * A convenience wrapper around gtk_text_iter_get_attributes (),
1472  * which returns the language in effect at @iter. If no tags affecting
1473  * language apply to @iter, the return value is identical to that of
1474  * gtk_get_default_language ().
1475  *
1476  * Return value: language in effect at @iter
1477  **/
1478 PangoLanguage *
1479 gtk_text_iter_get_language (const GtkTextIter *iter)
1480 {
1481   GtkTextAttributes *values;
1482   PangoLanguage *retval;
1483   
1484   values = gtk_text_attributes_new ();
1485
1486   gtk_text_iter_get_attributes (iter, values);
1487
1488   retval = values->language;
1489
1490   gtk_text_attributes_unref (values);
1491
1492   return retval;
1493 }
1494
1495 /**
1496  * gtk_text_iter_starts_line:
1497  * @iter: an iterator
1498  *
1499  * Returns %TRUE if @iter begins a paragraph,
1500  * i.e. if gtk_text_iter_get_line_offset () would return 0.
1501  * However this function is potentially more efficient than
1502  * gtk_text_iter_get_line_offset () because it doesn't have to compute
1503  * the offset, it just has to see whether it's 0.
1504  *
1505  * Return value: whether @iter begins a line
1506  **/
1507 gboolean
1508 gtk_text_iter_starts_line (const GtkTextIter   *iter)
1509 {
1510   GtkTextRealIter *real;
1511
1512   g_return_val_if_fail (iter != NULL, FALSE);
1513
1514   real = gtk_text_iter_make_surreal (iter);
1515
1516   if (real == NULL)
1517     return FALSE;
1518
1519   check_invariants (iter);
1520
1521   if (real->line_byte_offset >= 0)
1522     {
1523       return (real->line_byte_offset == 0);
1524     }
1525   else
1526     {
1527       g_assert (real->line_char_offset >= 0);
1528       return (real->line_char_offset == 0);
1529     }
1530 }
1531
1532 /**
1533  * gtk_text_iter_ends_line:
1534  * @iter: an iterator
1535  *
1536  * Returns %TRUE if @iter points to the start of the paragraph
1537  * delimiter characters for a line (delimiters will be either a
1538  * newline, a carriage return, a carriage return followed by a
1539  * newline, or a Unicode paragraph separator character). Note that an
1540  * iterator pointing to the \n of a \r\n pair will not be counted as
1541  * the end of a line, the line ends before the \r. The end iterator is
1542  * considered to be at the end of a line, even though there are no
1543  * paragraph delimiter chars there.
1544  *
1545  * Return value: whether @iter is at the end of a line
1546  **/
1547 gboolean
1548 gtk_text_iter_ends_line (const GtkTextIter   *iter)
1549 {
1550   GtkTextRealIter *real;
1551   gunichar wc;
1552   
1553   g_return_val_if_fail (iter != NULL, FALSE);
1554
1555   real = gtk_text_iter_make_real (iter);
1556   
1557   check_invariants (iter);
1558
1559   /* Only one character has type G_UNICODE_PARAGRAPH_SEPARATOR in
1560    * Unicode 3.0; update this if that changes.
1561    */
1562 #define PARAGRAPH_SEPARATOR 0x2029
1563
1564   wc = gtk_text_iter_get_char (iter);
1565   
1566   if (wc == '\r' || wc == PARAGRAPH_SEPARATOR || wc == 0) /* wc == 0 is end iterator */
1567     return TRUE;
1568   else if (wc == '\n')
1569     {
1570       /* need to determine if a \r precedes the \n, in which case
1571        * we aren't the end of the line
1572        */
1573       GtkTextIter tmp = *iter;
1574       if (!gtk_text_iter_backward_char (&tmp))
1575         return TRUE;
1576
1577       return gtk_text_iter_get_char (&tmp) != '\r';
1578     }
1579   else
1580     return FALSE;
1581 }
1582
1583 /**
1584  * gtk_text_iter_is_end:
1585  * @iter: an iterator
1586  *
1587  * Returns %TRUE if @iter is the end iterator, i.e. one past the last
1588  * dereferenceable iterator in the buffer. gtk_text_iter_is_end () is
1589  * the most efficient way to check whether an iterator is the end
1590  * iterator.
1591  *
1592  * Return value: whether @iter is the end iterator
1593  **/
1594 gboolean
1595 gtk_text_iter_is_end (const GtkTextIter *iter)
1596 {
1597   GtkTextRealIter *real;
1598
1599   g_return_val_if_fail (iter != NULL, FALSE);
1600
1601   real = gtk_text_iter_make_surreal (iter);
1602
1603   if (real == NULL)
1604     return FALSE;
1605
1606   check_invariants (iter);
1607
1608   if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1609     return FALSE;
1610
1611   /* Now we need the segments validated */
1612   real = gtk_text_iter_make_real (iter);
1613
1614   if (real == NULL)
1615     return FALSE;
1616   
1617   return _gtk_text_btree_is_end (real->tree, real->line,
1618                                  real->segment,
1619                                  real->segment_byte_offset,
1620                                  real->segment_char_offset);
1621 }
1622
1623 /**
1624  * gtk_text_iter_is_start:
1625  * @iter: an iterator
1626  *
1627  * Returns %TRUE if @iter is the first iterator in the buffer, that is
1628  * if @iter has a character offset of 0.
1629  *
1630  * Return value: whether @iter is the first in the buffer
1631  **/
1632 gboolean
1633 gtk_text_iter_is_start (const GtkTextIter *iter)
1634 {
1635   return gtk_text_iter_get_offset (iter) == 0;
1636 }
1637
1638 /**
1639  * gtk_text_iter_get_chars_in_line:
1640  * @iter: an iterator
1641  *
1642  * Returns the number of characters in the line containing @iter,
1643  * including the paragraph delimiters.
1644  *
1645  * Return value: number of characters in the line
1646  **/
1647 gint
1648 gtk_text_iter_get_chars_in_line (const GtkTextIter   *iter)
1649 {
1650   GtkTextRealIter *real;
1651   gint count;
1652   GtkTextLineSegment *seg;
1653
1654   g_return_val_if_fail (iter != NULL, 0);
1655
1656   real = gtk_text_iter_make_surreal (iter);
1657
1658   if (real == NULL)
1659     return 0;
1660
1661   check_invariants (iter);
1662
1663   if (real->line_char_offset >= 0)
1664     {
1665       /* We can start at the segments we've already found. */
1666       count = real->line_char_offset - real->segment_char_offset;
1667       seg = _gtk_text_iter_get_indexable_segment (iter);
1668     }
1669   else
1670     {
1671       /* count whole line. */
1672       seg = real->line->segments;
1673       count = 0;
1674     }
1675
1676
1677   while (seg != NULL)
1678     {
1679       count += seg->char_count;
1680
1681       seg = seg->next;
1682     }
1683
1684   if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1685     count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1686   
1687   return count;
1688 }
1689
1690 /**
1691  * gtk_text_iter_get_bytes_in_line:
1692  * @iter: an iterator
1693  *
1694  * Returns the number of bytes in the line containing @iter,
1695  * including the paragraph delimiters.
1696  *
1697  * Return value: number of bytes in the line
1698  **/
1699 gint
1700 gtk_text_iter_get_bytes_in_line (const GtkTextIter   *iter)
1701 {
1702   GtkTextRealIter *real;
1703   gint count;
1704   GtkTextLineSegment *seg;
1705
1706   g_return_val_if_fail (iter != NULL, 0);
1707
1708   real = gtk_text_iter_make_surreal (iter);
1709
1710   if (real == NULL)
1711     return 0;
1712
1713   check_invariants (iter);
1714
1715   if (real->line_byte_offset >= 0)
1716     {
1717       /* We can start at the segments we've already found. */
1718       count = real->line_byte_offset - real->segment_byte_offset;
1719       seg = _gtk_text_iter_get_indexable_segment (iter);
1720     }
1721   else
1722     {
1723       /* count whole line. */
1724       seg = real->line->segments;
1725       count = 0;
1726     }
1727
1728   while (seg != NULL)
1729     {
1730       count += seg->byte_count;
1731
1732       seg = seg->next;
1733     }
1734
1735   if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1736     count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1737   
1738   return count;
1739 }
1740
1741 /**
1742  * gtk_text_iter_get_attributes:
1743  * @iter: an iterator
1744  * @values: a #GtkTextAttributes to be filled in
1745  *
1746  * Computes the effect of any tags applied to this spot in the
1747  * text. The @values parameter should be initialized to the default
1748  * settings you wish to use if no tags are in effect. You'd typically
1749  * obtain the defaults from gtk_text_view_get_default_attributes().
1750  *
1751  * gtk_text_iter_get_attributes () will modify @values, applying the
1752  * effects of any tags present at @iter. If any tags affected @values,
1753  * the function returns %TRUE.
1754  *
1755  * Return value: %TRUE if @values was modified
1756  **/
1757 gboolean
1758 gtk_text_iter_get_attributes (const GtkTextIter  *iter,
1759                               GtkTextAttributes  *values)
1760 {
1761   GtkTextTag** tags;
1762   gint tag_count = 0;
1763
1764   /* Get the tags at this spot */
1765   tags = _gtk_text_btree_get_tags (iter, &tag_count);
1766
1767   /* No tags, use default style */
1768   if (tags == NULL || tag_count == 0)
1769     {
1770       if (tags)
1771         g_free (tags);
1772
1773       return FALSE;
1774     }
1775
1776   /* Sort tags in ascending order of priority */
1777   _gtk_text_tag_array_sort (tags, tag_count);
1778
1779   _gtk_text_attributes_fill_from_tags (values,
1780                                        tags,
1781                                        tag_count);
1782
1783   g_free (tags);
1784
1785   return TRUE;
1786 }
1787
1788 /*
1789  * Increments/decrements
1790  */
1791
1792 /* The return value of this indicates WHETHER WE MOVED.
1793  * The return value of public functions indicates
1794  * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1795  *
1796  * This function will not change the iterator if
1797  * it's already on the last (end iter) line, i.e. it
1798  * won't move to the end of the last line.
1799  */
1800 static gboolean
1801 forward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1802 {
1803   if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1804     {
1805       GtkTextLine *new_line;
1806       
1807       new_line = _gtk_text_line_next (real->line);
1808       g_assert (new_line);
1809       g_assert (new_line != real->line);
1810       g_assert (!_gtk_text_line_is_last (new_line, real->tree));
1811       
1812       real->line = new_line;
1813
1814       real->line_byte_offset = 0;
1815       real->line_char_offset = 0;
1816
1817       real->segment_byte_offset = 0;
1818       real->segment_char_offset = 0;
1819
1820       /* Find first segments in new line */
1821       real->any_segment = real->line->segments;
1822       real->segment = real->any_segment;
1823       while (real->segment->char_count == 0)
1824         real->segment = real->segment->next;
1825
1826       return TRUE;
1827     }
1828   else
1829     {
1830       /* There is no way to move forward a line; we were already at
1831        * the line containing the end iterator.
1832        * However we may not be at the end iterator itself.
1833        */
1834       
1835       return FALSE;
1836     }
1837 }
1838
1839 #if 0
1840 /* The return value of this indicates WHETHER WE MOVED.
1841  * The return value of public functions indicates
1842  * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1843  *
1844  * This function is currently unused, thus it is #if-0-ed. It is
1845  * left here, since it's non-trivial code that might be useful in
1846  * the future.
1847  */
1848 static gboolean
1849 backward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1850 {
1851   GtkTextLine *new_line;
1852
1853   new_line = _gtk_text_line_previous (real->line);
1854
1855   g_assert (new_line != real->line);
1856
1857   if (new_line != NULL)
1858     {
1859       real->line = new_line;
1860
1861       real->line_byte_offset = 0;
1862       real->line_char_offset = 0;
1863
1864       real->segment_byte_offset = 0;
1865       real->segment_char_offset = 0;
1866
1867       /* Find first segments in new line */
1868       real->any_segment = real->line->segments;
1869       real->segment = real->any_segment;
1870       while (real->segment->char_count == 0)
1871         real->segment = real->segment->next;
1872
1873       return TRUE;
1874     }
1875   else
1876     {
1877       /* There is no way to move backward; we were already
1878          at the first line. */
1879
1880       /* We leave real->line as-is */
1881
1882       /* Note that we didn't clamp to the start of the first line. */
1883
1884       return FALSE;
1885     }
1886 }
1887 #endif 
1888
1889 /* The return value indicates (MOVEMENT OCCURRED && NEW ITER IS
1890  * DEREFERENCEABLE)
1891  */
1892 static gboolean
1893 forward_char (GtkTextRealIter *real)
1894 {
1895   GtkTextIter *iter = (GtkTextIter*)real;
1896
1897   check_invariants ((GtkTextIter*)real);
1898
1899   ensure_char_offsets (real);
1900
1901   if ( (real->segment_char_offset + 1) == real->segment->char_count)
1902     {
1903       /* Need to move to the next segment; if no next segment,
1904          need to move to next line. */
1905       return _gtk_text_iter_forward_indexable_segment (iter);
1906     }
1907   else
1908     {
1909       /* Just moving within a segment. Keep byte count
1910          up-to-date, if it was already up-to-date. */
1911
1912       g_assert (real->segment->type == &gtk_text_char_type);
1913
1914       if (real->line_byte_offset >= 0)
1915         {
1916           gint bytes;
1917           const char * start =
1918             real->segment->body.chars + real->segment_byte_offset;
1919
1920           bytes = g_utf8_next_char (start) - start;
1921
1922           real->line_byte_offset += bytes;
1923           real->segment_byte_offset += bytes;
1924
1925           g_assert (real->segment_byte_offset < real->segment->byte_count);
1926         }
1927
1928       real->line_char_offset += 1;
1929       real->segment_char_offset += 1;
1930
1931       adjust_char_index (real, 1);
1932
1933       g_assert (real->segment_char_offset < real->segment->char_count);
1934
1935       /* We moved into the middle of a segment, so the any_segment
1936          must now be the segment we're in the middle of. */
1937       real->any_segment = real->segment;
1938
1939       check_invariants ((GtkTextIter*)real);
1940
1941       if (gtk_text_iter_is_end ((GtkTextIter*)real))
1942         return FALSE;
1943       else
1944         return TRUE;
1945     }
1946 }
1947
1948 gboolean
1949 _gtk_text_iter_forward_indexable_segment (GtkTextIter *iter)
1950 {
1951   /* Need to move to the next segment; if no next segment,
1952      need to move to next line. */
1953   GtkTextLineSegment *seg;
1954   GtkTextLineSegment *any_seg;
1955   GtkTextRealIter *real;
1956   gint chars_skipped;
1957   gint bytes_skipped;
1958
1959   g_return_val_if_fail (iter != NULL, FALSE);
1960
1961   real = gtk_text_iter_make_real (iter);
1962
1963   if (real == NULL)
1964     return FALSE;
1965
1966   check_invariants (iter);
1967
1968   if (real->line_char_offset >= 0)
1969     {
1970       chars_skipped = real->segment->char_count - real->segment_char_offset;
1971       g_assert (chars_skipped > 0);
1972     }
1973   else
1974     chars_skipped = 0;
1975
1976   if (real->line_byte_offset >= 0)
1977     {
1978       bytes_skipped = real->segment->byte_count - real->segment_byte_offset;
1979       g_assert (bytes_skipped > 0);
1980     }
1981   else
1982     bytes_skipped = 0;
1983
1984   /* Get first segment of any kind */
1985   any_seg = real->segment->next;
1986   /* skip non-indexable segments, if any */
1987   seg = any_seg;
1988   while (seg != NULL && seg->char_count == 0)
1989     seg = seg->next;
1990
1991   if (seg != NULL)
1992     {
1993       real->any_segment = any_seg;
1994       real->segment = seg;
1995
1996       if (real->line_byte_offset >= 0)
1997         {
1998           g_assert (bytes_skipped > 0);
1999           real->segment_byte_offset = 0;
2000           real->line_byte_offset += bytes_skipped;
2001         }
2002
2003       if (real->line_char_offset >= 0)
2004         {
2005           g_assert (chars_skipped > 0);
2006           real->segment_char_offset = 0;
2007           real->line_char_offset += chars_skipped;
2008           adjust_char_index (real, chars_skipped);
2009         }
2010
2011       check_invariants (iter);
2012
2013       return !gtk_text_iter_is_end (iter);
2014     }
2015   else
2016     {
2017       /* End of the line */
2018       if (forward_line_leaving_caches_unmodified (real))
2019         {
2020           adjust_line_number (real, 1);
2021           if (real->line_char_offset >= 0)
2022             adjust_char_index (real, chars_skipped);
2023
2024           g_assert (real->line_byte_offset == 0);
2025           g_assert (real->line_char_offset == 0);
2026           g_assert (real->segment_byte_offset == 0);
2027           g_assert (real->segment_char_offset == 0);
2028           g_assert (gtk_text_iter_starts_line (iter));
2029
2030           check_invariants (iter);
2031
2032           return !gtk_text_iter_is_end (iter);
2033         }
2034       else
2035         {
2036           /* End of buffer, but iter is still at start of last segment,
2037            * not at the end iterator. We put it on the end iterator.
2038            */
2039           
2040           check_invariants (iter);
2041
2042           g_assert (!_gtk_text_line_is_last (real->line, real->tree));
2043           g_assert (_gtk_text_line_contains_end_iter (real->line, real->tree));
2044
2045           gtk_text_iter_forward_to_line_end (iter);
2046
2047           g_assert (gtk_text_iter_is_end (iter));
2048           
2049           return FALSE;
2050         }
2051     }
2052 }
2053
2054 static gboolean
2055 at_last_indexable_segment (GtkTextRealIter *real)
2056 {
2057   GtkTextLineSegment *seg;
2058
2059   /* Return TRUE if there are no indexable segments after
2060    * this iterator.
2061    */
2062
2063   seg = real->segment->next;
2064   while (seg)
2065     {
2066       if (seg->char_count > 0)
2067         return FALSE;
2068       seg = seg->next;
2069     }
2070   return TRUE;
2071 }
2072
2073 /* Goes back to the start of the next segment, even if
2074  * we're not at the start of the current segment (always
2075  * ends up on a different segment if it returns TRUE)
2076  */
2077 gboolean
2078 _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
2079 {
2080   /* Move to the start of the previous segment; if no previous
2081    * segment, to the last segment in the previous line. This is
2082    * inherently a bit inefficient due to the singly-linked list and
2083    * tree nodes, but we can't afford the RAM for doubly-linked.
2084    */
2085   GtkTextRealIter *real;
2086   GtkTextLineSegment *seg;
2087   GtkTextLineSegment *any_seg;
2088   GtkTextLineSegment *prev_seg;
2089   GtkTextLineSegment *prev_any_seg;
2090   gint bytes_skipped;
2091   gint chars_skipped;
2092
2093   g_return_val_if_fail (iter != NULL, FALSE);
2094
2095   real = gtk_text_iter_make_real (iter);
2096
2097   if (real == NULL)
2098     return FALSE;
2099
2100   check_invariants (iter);
2101
2102   /* Find first segments in line */
2103   any_seg = real->line->segments;
2104   seg = any_seg;
2105   while (seg->char_count == 0)
2106     seg = seg->next;
2107
2108   if (seg == real->segment)
2109     {
2110       /* Could probably do this case faster by hand-coding the
2111        * iteration.
2112        */
2113
2114       /* We were already at the start of a line;
2115        * go back to the previous line.
2116        */
2117       if (gtk_text_iter_backward_line (iter))
2118         {
2119           /* Go forward to last indexable segment in line. */
2120           while (!at_last_indexable_segment (real))
2121             _gtk_text_iter_forward_indexable_segment (iter);
2122
2123           check_invariants (iter);
2124
2125           return TRUE;
2126         }
2127       else
2128         return FALSE; /* We were at the start of the first line. */
2129     }
2130
2131   /* We must be in the middle of a line; so find the indexable
2132    * segment just before our current segment.
2133    */
2134   g_assert (seg != real->segment);
2135   do
2136     {
2137       prev_seg = seg;
2138       prev_any_seg = any_seg;
2139
2140       any_seg = seg->next;
2141       seg = any_seg;
2142       while (seg->char_count == 0)
2143         seg = seg->next;
2144     }
2145   while (seg != real->segment);
2146
2147   g_assert (prev_seg != NULL);
2148   g_assert (prev_any_seg != NULL);
2149   g_assert (prev_seg->char_count > 0);
2150
2151   /* We skipped the entire previous segment, plus any
2152    * chars we were into the current segment.
2153    */
2154   if (real->segment_byte_offset >= 0)
2155     bytes_skipped = prev_seg->byte_count + real->segment_byte_offset;
2156   else
2157     bytes_skipped = -1;
2158
2159   if (real->segment_char_offset >= 0)
2160     chars_skipped = prev_seg->char_count + real->segment_char_offset;
2161   else
2162     chars_skipped = -1;
2163
2164   real->segment = prev_seg;
2165   real->any_segment = prev_any_seg;
2166   real->segment_byte_offset = 0;
2167   real->segment_char_offset = 0;
2168
2169   if (bytes_skipped >= 0)
2170     {
2171       if (real->line_byte_offset >= 0)
2172         {
2173           real->line_byte_offset -= bytes_skipped;
2174           g_assert (real->line_byte_offset >= 0);
2175         }
2176     }
2177   else
2178     real->line_byte_offset = -1;
2179
2180   if (chars_skipped >= 0)
2181     {
2182       if (real->line_char_offset >= 0)
2183         {
2184           real->line_char_offset -= chars_skipped;
2185           g_assert (real->line_char_offset >= 0);
2186         }
2187
2188       if (real->cached_char_index >= 0)
2189         {
2190           real->cached_char_index -= chars_skipped;
2191           g_assert (real->cached_char_index >= 0);
2192         }
2193     }
2194   else
2195     {
2196       real->line_char_offset = -1;
2197       real->cached_char_index = -1;
2198     }
2199
2200   /* line number is unchanged. */
2201
2202   check_invariants (iter);
2203
2204   return TRUE;
2205 }
2206
2207 /**
2208  * gtk_text_iter_forward_char:
2209  * @iter: an iterator
2210  *
2211  * Moves @iter forward by one character offset. Note that images
2212  * embedded in the buffer occupy 1 character slot, so
2213  * gtk_text_iter_forward_char () may actually move onto an image instead
2214  * of a character, if you have images in your buffer.  If @iter is the
2215  * end iterator or one character before it, @iter will now point at
2216  * the end iterator, and gtk_text_iter_forward_char () returns %FALSE for
2217  * convenience when writing loops.
2218  *
2219  * Return value: whether @iter moved and is dereferenceable
2220  **/
2221 gboolean
2222 gtk_text_iter_forward_char (GtkTextIter *iter)
2223 {
2224   GtkTextRealIter *real;
2225
2226   g_return_val_if_fail (iter != NULL, FALSE);
2227
2228   real = gtk_text_iter_make_real (iter);
2229
2230   if (real == NULL)
2231     return FALSE;
2232   else
2233     {
2234       check_invariants (iter);
2235       return forward_char (real);
2236     }
2237 }
2238
2239 /**
2240  * gtk_text_iter_backward_char:
2241  * @iter: an iterator
2242  *
2243  * Moves backward by one character offset. Returns %TRUE if movement
2244  * was possible; if @iter was the first in the buffer (character
2245  * offset 0), gtk_text_iter_backward_char () returns %FALSE for convenience when
2246  * writing loops.
2247  *
2248  * Return value: whether movement was possible
2249  **/
2250 gboolean
2251 gtk_text_iter_backward_char (GtkTextIter *iter)
2252 {
2253   g_return_val_if_fail (iter != NULL, FALSE);
2254
2255   check_invariants (iter);
2256
2257   return gtk_text_iter_backward_chars (iter, 1);
2258 }
2259
2260 /*
2261   Definitely we should try to linear scan as often as possible for
2262   movement within a single line, because we can't use the BTree to
2263   speed within-line searches up; for movement between lines, we would
2264   like to avoid the linear scan probably.
2265
2266   Instead of using this constant, it might be nice to cache the line
2267   length in the iterator and linear scan if motion is within a single
2268   line.
2269
2270   I guess you'd have to profile the various approaches.
2271 */
2272 #define MAX_LINEAR_SCAN 150
2273
2274
2275 /**
2276  * gtk_text_iter_forward_chars:
2277  * @iter: an iterator
2278  * @count: number of characters to move, may be negative
2279  *
2280  * Moves @count characters if possible (if @count would move past the
2281  * start or end of the buffer, moves to the start or end of the
2282  * buffer). The return value indicates whether the new position of
2283  * @iter is different from its original position, and dereferenceable
2284  * (the last iterator in the buffer is not dereferenceable). If @count
2285  * is 0, the function does nothing and returns %FALSE.
2286  *
2287  * Return value: whether @iter moved and is dereferenceable
2288  **/
2289 gboolean
2290 gtk_text_iter_forward_chars (GtkTextIter *iter, gint count)
2291 {
2292   GtkTextRealIter *real;
2293
2294   g_return_val_if_fail (iter != NULL, FALSE);
2295
2296   FIX_OVERFLOWS (count);
2297   
2298   real = gtk_text_iter_make_real (iter);
2299
2300   if (real == NULL)
2301     return FALSE;
2302   else if (count == 0)
2303     return FALSE;
2304   else if (count < 0)
2305     return gtk_text_iter_backward_chars (iter, 0 - count);
2306   else if (count < MAX_LINEAR_SCAN)
2307     {
2308       check_invariants (iter);
2309
2310       while (count > 1)
2311         {
2312           if (!forward_char (real))
2313             return FALSE;
2314           --count;
2315         }
2316
2317       return forward_char (real);
2318     }
2319   else
2320     {
2321       gint current_char_index;
2322       gint new_char_index;
2323
2324       check_invariants (iter);
2325
2326       current_char_index = gtk_text_iter_get_offset (iter);
2327
2328       if (current_char_index == _gtk_text_btree_char_count (real->tree))
2329         return FALSE; /* can't move forward */
2330
2331       new_char_index = current_char_index + count;
2332       gtk_text_iter_set_offset (iter, new_char_index);
2333
2334       check_invariants (iter);
2335
2336       /* Return FALSE if we're on the non-dereferenceable end
2337        * iterator.
2338        */
2339       if (gtk_text_iter_is_end (iter))
2340         return FALSE;
2341       else
2342         return TRUE;
2343     }
2344 }
2345
2346 /**
2347  * gtk_text_iter_backward_chars:
2348  * @iter: an iterator
2349  * @count: number of characters to move
2350  *
2351  * Moves @count characters backward, if possible (if @count would move
2352  * past the start or end of the buffer, moves to the start or end of
2353  * the buffer).  The return value indicates whether the iterator moved
2354  * onto a dereferenceable position; if the iterator didn't move, or
2355  * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2356  * the function does nothing and returns %FALSE.
2357  *
2358  * Return value: whether @iter moved and is dereferenceable
2359  *
2360  **/
2361 gboolean
2362 gtk_text_iter_backward_chars (GtkTextIter *iter, gint count)
2363 {
2364   GtkTextRealIter *real;
2365
2366   g_return_val_if_fail (iter != NULL, FALSE);
2367
2368   FIX_OVERFLOWS (count);
2369   
2370   real = gtk_text_iter_make_real (iter);
2371
2372   if (real == NULL)
2373     return FALSE;
2374   else if (count == 0)
2375     return FALSE;
2376   else if (count < 0)
2377     return gtk_text_iter_forward_chars (iter, 0 - count);
2378
2379   ensure_char_offsets (real);
2380   check_invariants (iter);
2381
2382   /* <, not <=, because if count == segment_char_offset
2383    * we're going to the front of the segment and the any_segment
2384    * might change
2385    */
2386   if (count < real->segment_char_offset)
2387     {
2388       /* Optimize the within-segment case */
2389       g_assert (real->segment->char_count > 0);
2390       g_assert (real->segment->type == &gtk_text_char_type);
2391
2392       real->segment_char_offset -= count;
2393       g_assert (real->segment_char_offset >= 0);
2394
2395       if (real->line_byte_offset >= 0)
2396         {
2397           gint new_byte_offset;
2398           gint i;
2399
2400           new_byte_offset = 0;
2401           i = 0;
2402           while (i < real->segment_char_offset)
2403             {
2404               const char * start = real->segment->body.chars + new_byte_offset;
2405               new_byte_offset += g_utf8_next_char (start) - start;
2406
2407               ++i;
2408             }
2409
2410           real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
2411           real->segment_byte_offset = new_byte_offset;
2412         }
2413
2414       real->line_char_offset -= count;
2415
2416       adjust_char_index (real, 0 - count);
2417
2418       check_invariants (iter);
2419
2420       return TRUE;
2421     }
2422   else
2423     {
2424       /* We need to go back into previous segments. For now,
2425        * just keep this really simple. FIXME
2426        * use backward_indexable_segment.
2427        */
2428       if (TRUE || count > MAX_LINEAR_SCAN)
2429         {
2430           gint current_char_index;
2431           gint new_char_index;
2432
2433           current_char_index = gtk_text_iter_get_offset (iter);
2434
2435           if (current_char_index == 0)
2436             return FALSE; /* can't move backward */
2437
2438           new_char_index = current_char_index - count;
2439           if (new_char_index < 0)
2440             new_char_index = 0;
2441
2442           gtk_text_iter_set_offset (iter, new_char_index);
2443
2444           check_invariants (iter);
2445
2446           return TRUE;
2447         }
2448       else
2449         {
2450           /* FIXME backward_indexable_segment here */
2451
2452           return FALSE;
2453         }
2454     }
2455 }
2456
2457 #if 0
2458
2459 /* These two can't be implemented efficiently (always have to use
2460  * a linear scan, since that's the only way to find all the non-text
2461  * segments)
2462  */
2463
2464 /**
2465  * gtk_text_iter_forward_text_chars:
2466  * @iter: a #GtkTextIter
2467  * @count: number of chars to move
2468  *
2469  * Moves forward by @count text characters (pixbufs, widgets,
2470  * etc. do not count as characters for this). Equivalent to moving
2471  * through the results of gtk_text_iter_get_text (), rather than
2472  * gtk_text_iter_get_slice ().
2473  *
2474  * Return value: whether @iter moved and is dereferenceable
2475  **/
2476 gboolean
2477 gtk_text_iter_forward_text_chars  (GtkTextIter *iter,
2478                                    gint         count)
2479 {
2480
2481
2482
2483 }
2484
2485 /**
2486  * gtk_text_iter_forward_text_chars:
2487  * @iter: a #GtkTextIter
2488  * @count: number of chars to move
2489  *
2490  * Moves backward by @count text characters (pixbufs, widgets,
2491  * etc. do not count as characters for this). Equivalent to moving
2492  * through the results of gtk_text_iter_get_text (), rather than
2493  * gtk_text_iter_get_slice ().
2494  *
2495  * Return value: whether @iter moved and is dereferenceable
2496  **/
2497 gboolean
2498 gtk_text_iter_backward_text_chars (GtkTextIter *iter,
2499                                    gint         count)
2500 {
2501
2502
2503 }
2504 #endif
2505
2506 /**
2507  * gtk_text_iter_forward_line:
2508  * @iter: an iterator
2509  *
2510  * Moves @iter to the start of the next line. Returns %TRUE if there
2511  * was a next line to move to, and %FALSE if @iter was simply moved to
2512  * the end of the buffer and is now not dereferenceable, or if @iter was
2513  * already at the end of the buffer.
2514  *
2515  * Return value: whether @iter can be dereferenced
2516  **/
2517 gboolean
2518 gtk_text_iter_forward_line (GtkTextIter *iter)
2519 {
2520   GtkTextRealIter *real;
2521
2522   g_return_val_if_fail (iter != NULL, FALSE);
2523   
2524   real = gtk_text_iter_make_real (iter);
2525
2526   if (real == NULL)
2527     return FALSE;
2528
2529   check_invariants (iter);
2530
2531   if (forward_line_leaving_caches_unmodified (real))
2532     {
2533       invalidate_char_index (real);
2534       adjust_line_number (real, 1);
2535
2536       check_invariants (iter);
2537
2538       if (gtk_text_iter_is_end (iter))
2539         return FALSE;
2540       else
2541         return TRUE;
2542     }
2543   else
2544     {
2545       /* On the last line, move to end of it */
2546       
2547       if (!gtk_text_iter_is_end (iter))
2548         gtk_text_iter_forward_to_end (iter);
2549       
2550       check_invariants (iter);
2551       return FALSE;
2552     }
2553 }
2554
2555 /**
2556  * gtk_text_iter_backward_line:
2557  * @iter: an iterator
2558  *
2559  * Moves @iter to the start of the previous line. Returns %TRUE if
2560  * @iter could be moved; i.e. if @iter was at character offset 0, this
2561  * function returns %FALSE. Therefore if @iter was already on line 0,
2562  * but not at the start of the line, @iter is snapped to the start of
2563  * the line and the function returns %TRUE. (Note that this implies that
2564  * in a loop calling this function, the line number may not change on
2565  * every iteration, if your first iteration is on line 0.)
2566  *
2567  * Return value: whether @iter moved
2568  **/
2569 gboolean
2570 gtk_text_iter_backward_line (GtkTextIter *iter)
2571 {
2572   GtkTextLine *new_line;
2573   GtkTextRealIter *real;
2574   gboolean offset_will_change;
2575   gint offset;
2576
2577   g_return_val_if_fail (iter != NULL, FALSE);
2578
2579   real = gtk_text_iter_make_real (iter);
2580
2581   if (real == NULL)
2582     return FALSE;
2583
2584   check_invariants (iter);
2585
2586   new_line = _gtk_text_line_previous (real->line);
2587
2588   offset_will_change = FALSE;
2589   if (real->line_char_offset > 0)
2590     offset_will_change = TRUE;
2591
2592   if (new_line != NULL)
2593     {
2594       real->line = new_line;
2595
2596       adjust_line_number (real, -1);
2597     }
2598   else
2599     {
2600       if (!offset_will_change)
2601         return FALSE;
2602     }
2603
2604   invalidate_char_index (real);
2605
2606   real->line_byte_offset = 0;
2607   real->line_char_offset = 0;
2608
2609   real->segment_byte_offset = 0;
2610   real->segment_char_offset = 0;
2611
2612   /* Find first segment in line */
2613   real->any_segment = real->line->segments;
2614   real->segment = _gtk_text_line_byte_to_segment (real->line,
2615                                                   0, &offset);
2616
2617   g_assert (offset == 0);
2618
2619   /* Note that if we are on the first line, we snap to the start of
2620    * the first line and return TRUE, so TRUE means the iterator
2621    * changed, not that the line changed; this is maybe a bit
2622    * weird. I'm not sure there's an obvious right thing to do though.
2623    */
2624
2625   check_invariants (iter);
2626
2627   return TRUE;
2628 }
2629
2630
2631 /**
2632  * gtk_text_iter_forward_lines:
2633  * @iter: a #GtkTextIter
2634  * @count: number of lines to move forward
2635  *
2636  * Moves @count lines forward, if possible (if @count would move
2637  * past the start or end of the buffer, moves to the start or end of
2638  * the buffer).  The return value indicates whether the iterator moved
2639  * onto a dereferenceable position; if the iterator didn't move, or
2640  * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2641  * the function does nothing and returns %FALSE. If @count is negative,
2642  * moves backward by 0 - @count lines.
2643  *
2644  * Return value: whether @iter moved and is dereferenceable
2645  **/
2646 gboolean
2647 gtk_text_iter_forward_lines (GtkTextIter *iter, gint count)
2648 {
2649   FIX_OVERFLOWS (count);
2650   
2651   if (count < 0)
2652     return gtk_text_iter_backward_lines (iter, 0 - count);
2653   else if (count == 0)
2654     return FALSE;
2655   else if (count == 1)
2656     {
2657       check_invariants (iter);
2658       return gtk_text_iter_forward_line (iter);
2659     }
2660   else
2661     {
2662       gint old_line;
2663
2664       if (gtk_text_iter_is_end (iter))
2665         return FALSE;
2666       
2667       old_line = gtk_text_iter_get_line (iter);
2668
2669       gtk_text_iter_set_line (iter, old_line + count);
2670
2671       if ((gtk_text_iter_get_line (iter) - old_line) < count)
2672         {
2673           /* count went past the last line, so move to end of last line */
2674           if (!gtk_text_iter_is_end (iter))
2675             gtk_text_iter_forward_to_end (iter);
2676         }
2677       
2678       return !gtk_text_iter_is_end (iter);
2679     }
2680 }
2681
2682 /**
2683  * gtk_text_iter_backward_lines:
2684  * @iter: a #GtkTextIter
2685  * @count: number of lines to move backward
2686  *
2687  * Moves @count lines backward, if possible (if @count would move
2688  * past the start or end of the buffer, moves to the start or end of
2689  * the buffer).  The return value indicates whether the iterator moved
2690  * onto a dereferenceable position; if the iterator didn't move, or
2691  * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2692  * the function does nothing and returns %FALSE. If @count is negative,
2693  * moves forward by 0 - @count lines.
2694  *
2695  * Return value: whether @iter moved and is dereferenceable
2696  **/
2697 gboolean
2698 gtk_text_iter_backward_lines (GtkTextIter *iter, gint count)
2699 {
2700   FIX_OVERFLOWS (count);
2701   
2702   if (count < 0)
2703     return gtk_text_iter_forward_lines (iter, 0 - count);
2704   else if (count == 0)
2705     return FALSE;
2706   else if (count == 1)
2707     {
2708       return gtk_text_iter_backward_line (iter);
2709     }
2710   else
2711     {
2712       gint old_line;
2713
2714       old_line = gtk_text_iter_get_line (iter);
2715
2716       gtk_text_iter_set_line (iter, MAX (old_line - count, 0));
2717
2718       return (gtk_text_iter_get_line (iter) != old_line);
2719     }
2720 }
2721
2722 typedef gboolean (* FindLogAttrFunc) (const PangoLogAttr *attrs,
2723                                       gint                offset,
2724                                       gint                min_offset,
2725                                       gint                len,
2726                                       gint               *found_offset,
2727                                       gboolean            already_moved_initially);
2728
2729 typedef gboolean (* TestLogAttrFunc) (const PangoLogAttr *attrs,
2730                                       gint                offset,
2731                                       gint                min_offset,
2732                                       gint                len);
2733
2734 /* Word funcs */
2735
2736 static gboolean
2737 find_word_end_func (const PangoLogAttr *attrs,
2738                     gint          offset,
2739                     gint          min_offset,
2740                     gint          len,
2741                     gint         *found_offset,
2742                     gboolean      already_moved_initially)
2743 {
2744   if (!already_moved_initially)
2745     ++offset;
2746
2747   /* Find end of next word */
2748   while (offset < min_offset + len &&
2749          !attrs[offset].is_word_end)
2750     ++offset;
2751
2752   *found_offset = offset;
2753
2754   return offset < min_offset + len;
2755 }
2756
2757 static gboolean
2758 is_word_end_func (const PangoLogAttr *attrs,
2759                   gint          offset,
2760                   gint          min_offset,
2761                   gint          len)
2762 {
2763   return attrs[offset].is_word_end;
2764 }
2765
2766 static gboolean
2767 find_word_start_func (const PangoLogAttr *attrs,
2768                       gint          offset,
2769                       gint          min_offset,
2770                       gint          len,
2771                       gint         *found_offset,
2772                       gboolean      already_moved_initially)
2773 {
2774   if (!already_moved_initially)
2775     --offset;
2776
2777   /* Find start of prev word */
2778   while (offset >= min_offset &&
2779          !attrs[offset].is_word_start)
2780     --offset;
2781
2782   *found_offset = offset;
2783
2784   return offset >= min_offset;
2785 }
2786
2787 static gboolean
2788 is_word_start_func (const PangoLogAttr *attrs,
2789                     gint          offset,
2790                     gint          min_offset,
2791                     gint          len)
2792 {
2793   return attrs[offset].is_word_start;
2794 }
2795
2796 static gboolean
2797 inside_word_func (const PangoLogAttr *attrs,
2798                   gint          offset,
2799                   gint          min_offset,
2800                   gint          len)
2801 {
2802   /* Find next word start or end */
2803   while (offset >= min_offset &&
2804          !(attrs[offset].is_word_start || attrs[offset].is_word_end))
2805     --offset;
2806
2807   return attrs[offset].is_word_start;
2808 }
2809
2810 /* Sentence funcs */
2811
2812 static gboolean
2813 find_sentence_end_func (const PangoLogAttr *attrs,
2814                         gint          offset,
2815                         gint          min_offset,
2816                         gint          len,
2817                         gint         *found_offset,
2818                         gboolean      already_moved_initially)
2819 {
2820   if (!already_moved_initially)
2821     ++offset;
2822
2823   /* Find end of next sentence */
2824   while (offset < min_offset + len &&
2825          !attrs[offset].is_sentence_end)
2826     ++offset;
2827
2828   *found_offset = offset;
2829
2830   return offset < min_offset + len;
2831 }
2832
2833 static gboolean
2834 is_sentence_end_func (const PangoLogAttr *attrs,
2835                       gint          offset,
2836                       gint          min_offset,
2837                       gint          len)
2838 {
2839   return attrs[offset].is_sentence_end;
2840 }
2841
2842 static gboolean
2843 find_sentence_start_func (const PangoLogAttr *attrs,
2844                           gint          offset,
2845                           gint          min_offset,
2846                           gint          len,
2847                           gint         *found_offset,
2848                           gboolean      already_moved_initially)
2849 {
2850   if (!already_moved_initially)
2851     --offset;
2852
2853   /* Find start of prev sentence */
2854   while (offset >= min_offset &&
2855          !attrs[offset].is_sentence_start)
2856     --offset;
2857
2858   *found_offset = offset;
2859
2860   return offset >= min_offset;
2861 }
2862
2863 static gboolean
2864 is_sentence_start_func (const PangoLogAttr *attrs,
2865                         gint          offset,
2866                         gint          min_offset,
2867                         gint          len)
2868 {
2869   return attrs[offset].is_sentence_start;
2870 }
2871
2872 static gboolean
2873 inside_sentence_func (const PangoLogAttr *attrs,
2874                       gint          offset,
2875                       gint          min_offset,
2876                       gint          len)
2877 {
2878   /* Find next sentence start or end */
2879   while (offset >= min_offset &&
2880          !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end))
2881     --offset;
2882
2883   return attrs[offset].is_sentence_start;
2884 }
2885
2886 static gboolean
2887 test_log_attrs (const GtkTextIter *iter,
2888                 TestLogAttrFunc    func)
2889 {
2890   gint char_len;
2891   const PangoLogAttr *attrs;
2892   int offset;
2893   gboolean result = FALSE;
2894
2895   g_return_val_if_fail (iter != NULL, FALSE);
2896
2897   attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2898                                                iter, &char_len);
2899
2900   offset = gtk_text_iter_get_line_offset (iter);
2901
2902   /* char_len may be 0 and attrs will be NULL if so, if
2903    * iter is the end iter and the last line is empty.
2904    * 
2905    * offset may be equal to char_len, since attrs contains an entry
2906    * for one past the end
2907    */
2908   
2909   if (attrs && offset <= char_len)
2910     result = (* func) (attrs, offset, 0, char_len);
2911
2912   return result;
2913 }
2914
2915 static gboolean
2916 find_line_log_attrs (const GtkTextIter *iter,
2917                      FindLogAttrFunc    func,
2918                      gint              *found_offset,
2919                      gboolean           already_moved_initially)
2920 {
2921   gint char_len;
2922   const PangoLogAttr *attrs;
2923   int offset;
2924   gboolean result = FALSE;
2925
2926   g_return_val_if_fail (iter != NULL, FALSE);
2927   
2928   attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
2929                                                iter, &char_len);      
2930
2931   offset = gtk_text_iter_get_line_offset (iter);
2932   
2933   /* char_len may be 0 and attrs will be NULL if so, if
2934    * iter is the end iter and the last line is empty
2935    */
2936   
2937   if (attrs)
2938     result = (* func) (attrs, offset, 0, char_len, found_offset,
2939                        already_moved_initially);
2940
2941   return result;
2942 }
2943
2944 /* FIXME this function is very, very gratuitously slow */
2945 static gboolean
2946 find_by_log_attrs (GtkTextIter    *iter,
2947                    FindLogAttrFunc func,
2948                    gboolean        forward,
2949                    gboolean        already_moved_initially)
2950 {
2951   GtkTextIter orig;
2952   gint offset = 0;
2953   gboolean found = FALSE;
2954
2955   g_return_val_if_fail (iter != NULL, FALSE);
2956
2957   orig = *iter;
2958   
2959   found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
2960   
2961   if (!found)
2962     {
2963       if (forward)
2964         {
2965           if (gtk_text_iter_forward_line (iter))
2966             return find_by_log_attrs (iter, func, forward,
2967                                       TRUE);
2968           else
2969             return FALSE;
2970         }
2971       else
2972         {                    
2973           /* go to end of previous line. need to check that
2974            * line is > 0 because backward_line snaps to start of
2975            * line 0 if it's on line 0
2976            */
2977           if (gtk_text_iter_get_line (iter) > 0 && 
2978               gtk_text_iter_backward_line (iter))
2979             {
2980               if (!gtk_text_iter_ends_line (iter))
2981                 gtk_text_iter_forward_to_line_end (iter);
2982               
2983               return find_by_log_attrs (iter, func, forward,
2984                                         TRUE);
2985             }
2986           else
2987             return FALSE;
2988         }
2989     }
2990   else
2991     {      
2992       gtk_text_iter_set_line_offset (iter, offset);
2993
2994       return
2995         (already_moved_initially || !gtk_text_iter_equal (iter, &orig)) &&
2996         !gtk_text_iter_is_end (iter);
2997     }
2998 }
2999
3000 static gboolean 
3001 find_visible_by_log_attrs (GtkTextIter    *iter,
3002                            FindLogAttrFunc func,
3003                            gboolean        forward,
3004                            gboolean        already_moved_initially)
3005 {
3006   GtkTextIter pos;
3007
3008   g_return_val_if_fail (iter != NULL, FALSE);
3009   
3010   pos = *iter;
3011   
3012   while (find_by_log_attrs (&pos, func, forward, already_moved_initially)) 
3013     {
3014       if (!_gtk_text_btree_char_is_invisible (&pos)) 
3015         {
3016           *iter = pos;
3017           return TRUE;
3018         }
3019   }
3020
3021   return FALSE;
3022 }
3023
3024 typedef gboolean (* OneStepFunc) (GtkTextIter *iter);
3025 typedef gboolean (* MultipleStepFunc) (GtkTextIter *iter, gint count);
3026                                   
3027 static gboolean 
3028 move_multiple_steps (GtkTextIter *iter, 
3029                      gint count,
3030                      OneStepFunc step_forward,
3031                      MultipleStepFunc n_steps_backward)
3032 {
3033   g_return_val_if_fail (iter != NULL, FALSE);
3034
3035   FIX_OVERFLOWS (count);
3036   
3037   if (count == 0)
3038     return FALSE;
3039   
3040   if (count < 0)
3041     return n_steps_backward (iter, -count);
3042   
3043   if (!step_forward (iter))
3044     return FALSE;
3045   --count;
3046
3047   while (count > 0)
3048     {
3049       if (!step_forward (iter))
3050         break;
3051       --count;
3052     }
3053   
3054   return !gtk_text_iter_is_end (iter);  
3055 }
3056                
3057
3058 /**
3059  * gtk_text_iter_forward_word_end:
3060  * @iter: a #GtkTextIter
3061  * 
3062  * Moves forward to the next word end. (If @iter is currently on a
3063  * word end, moves forward to the next one after that.) Word breaks
3064  * are determined by Pango and should be correct for nearly any
3065  * language (if not, the correct fix would be to the Pango word break
3066  * algorithms).
3067  * 
3068  * Return value: %TRUE if @iter moved and is not the end iterator 
3069  **/
3070 gboolean
3071 gtk_text_iter_forward_word_end (GtkTextIter *iter)
3072 {
3073   return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3074 }
3075
3076 /**
3077  * gtk_text_iter_backward_word_start:
3078  * @iter: a #GtkTextIter
3079  * 
3080  * Moves backward to the previous word start. (If @iter is currently on a
3081  * word start, moves backward to the next one after that.) Word breaks
3082  * are determined by Pango and should be correct for nearly any
3083  * language (if not, the correct fix would be to the Pango word break
3084  * algorithms).
3085  * 
3086  * Return value: %TRUE if @iter moved and is not the end iterator 
3087  **/
3088 gboolean
3089 gtk_text_iter_backward_word_start (GtkTextIter      *iter)
3090 {
3091   return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3092 }
3093
3094 /* FIXME a loop around a truly slow function means
3095  * a truly spectacularly slow function.
3096  */
3097
3098 /**
3099  * gtk_text_iter_forward_word_ends:
3100  * @iter: a #GtkTextIter
3101  * @count: number of times to move
3102  * 
3103  * Calls gtk_text_iter_forward_word_end() up to @count times.
3104  *
3105  * Return value: %TRUE if @iter moved and is not the end iterator 
3106  **/
3107 gboolean
3108 gtk_text_iter_forward_word_ends (GtkTextIter      *iter,
3109                                  gint              count)
3110 {
3111   return move_multiple_steps (iter, count, 
3112                               gtk_text_iter_forward_word_end,
3113                               gtk_text_iter_backward_word_starts);
3114 }
3115
3116 /**
3117  * gtk_text_iter_backward_word_starts
3118  * @iter: a #GtkTextIter
3119  * @count: number of times to move
3120  * 
3121  * Calls gtk_text_iter_backward_word_start() up to @count times.
3122  *
3123  * Return value: %TRUE if @iter moved and is not the end iterator 
3124  **/
3125 gboolean
3126 gtk_text_iter_backward_word_starts (GtkTextIter      *iter,
3127                                     gint               count)
3128 {
3129   return move_multiple_steps (iter, count, 
3130                               gtk_text_iter_backward_word_start,
3131                               gtk_text_iter_forward_word_ends);
3132 }
3133
3134 /**
3135  * gtk_text_iter_forward_visible_word_end:
3136  * @iter: a #GtkTextIter
3137  * 
3138  * Moves forward to the next visible word end. (If @iter is currently on a
3139  * word end, moves forward to the next one after that.) Word breaks
3140  * are determined by Pango and should be correct for nearly any
3141  * language (if not, the correct fix would be to the Pango word break
3142  * algorithms).
3143  * 
3144  * Return value: %TRUE if @iter moved and is not the end iterator 
3145  *
3146  * Since: 2.4
3147  **/
3148 gboolean
3149 gtk_text_iter_forward_visible_word_end (GtkTextIter *iter)
3150 {
3151   return find_visible_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3152 }
3153
3154 /**
3155  * gtk_text_iter_backward_visible_word_start:
3156  * @iter: a #GtkTextIter
3157  * 
3158  * Moves backward to the previous visible word start. (If @iter is currently 
3159  * on a word start, moves backward to the next one after that.) Word breaks
3160  * are determined by Pango and should be correct for nearly any
3161  * language (if not, the correct fix would be to the Pango word break
3162  * algorithms).
3163  * 
3164  * Return value: %TRUE if @iter moved and is not the end iterator 
3165  * 
3166  * Since: 2.4
3167  **/
3168 gboolean
3169 gtk_text_iter_backward_visible_word_start (GtkTextIter      *iter)
3170 {
3171   return find_visible_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3172 }
3173
3174 /**
3175  * gtk_text_iter_forward_visible_word_ends:
3176  * @iter: a #GtkTextIter
3177  * @count: number of times to move
3178  * 
3179  * Calls gtk_text_iter_forward_visible_word_end() up to @count times.
3180  *
3181  * Return value: %TRUE if @iter moved and is not the end iterator 
3182  *
3183  * Since: 2.4
3184  **/
3185 gboolean
3186 gtk_text_iter_forward_visible_word_ends (GtkTextIter *iter,
3187                                          gint         count)
3188 {
3189   return move_multiple_steps (iter, count, 
3190                               gtk_text_iter_forward_visible_word_end,
3191                               gtk_text_iter_backward_visible_word_starts);
3192 }
3193
3194 /**
3195  * gtk_text_iter_backward_visible_word_starts
3196  * @iter: a #GtkTextIter
3197  * @count: number of times to move
3198  * 
3199  * Calls gtk_text_iter_backward_visible_word_start() up to @count times.
3200  *
3201  * Return value: %TRUE if @iter moved and is not the end iterator 
3202  * 
3203  * Since: 2.4
3204  **/
3205 gboolean
3206 gtk_text_iter_backward_visible_word_starts (GtkTextIter *iter,
3207                                             gint         count)
3208 {
3209   return move_multiple_steps (iter, count, 
3210                               gtk_text_iter_backward_visible_word_start,
3211                               gtk_text_iter_forward_visible_word_ends);
3212 }
3213
3214 /**
3215  * gtk_text_iter_starts_word:
3216  * @iter: a #GtkTextIter
3217  * 
3218  * Determines whether @iter begins a natural-language word.  Word
3219  * breaks are determined by Pango and should be correct for nearly any
3220  * language (if not, the correct fix would be to the Pango word break
3221  * algorithms).
3222  *
3223  * Return value: %TRUE if @iter is at the start of a word
3224  **/
3225 gboolean
3226 gtk_text_iter_starts_word (const GtkTextIter *iter)
3227 {
3228   return test_log_attrs (iter, is_word_start_func);
3229 }
3230
3231 /**
3232  * gtk_text_iter_ends_word:
3233  * @iter: a #GtkTextIter
3234  * 
3235  * Determines whether @iter ends a natural-language word.  Word breaks
3236  * are determined by Pango and should be correct for nearly any
3237  * language (if not, the correct fix would be to the Pango word break
3238  * algorithms).
3239  *
3240  * Return value: %TRUE if @iter is at the end of a word
3241  **/
3242 gboolean
3243 gtk_text_iter_ends_word (const GtkTextIter *iter)
3244 {
3245   return test_log_attrs (iter, is_word_end_func);
3246 }
3247
3248 /**
3249  * gtk_text_iter_inside_word:
3250  * @iter: a #GtkTextIter
3251  * 
3252  * Determines whether @iter is inside a natural-language word (as
3253  * opposed to say inside some whitespace).  Word breaks are determined
3254  * by Pango and should be correct for nearly any language (if not, the
3255  * correct fix would be to the Pango word break algorithms).
3256  * 
3257  * Return value: %TRUE if @iter is inside a word
3258  **/
3259 gboolean
3260 gtk_text_iter_inside_word (const GtkTextIter *iter)
3261 {
3262   return test_log_attrs (iter, inside_word_func);
3263 }
3264
3265 /**
3266  * gtk_text_iter_starts_sentence:
3267  * @iter: a #GtkTextIter
3268  * 
3269  * Determines whether @iter begins a sentence.  Sentence boundaries are
3270  * determined by Pango and should be correct for nearly any language
3271  * (if not, the correct fix would be to the Pango text boundary
3272  * algorithms).
3273  * 
3274  * Return value: %TRUE if @iter is at the start of a sentence.
3275  **/
3276 gboolean
3277 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
3278 {
3279   return test_log_attrs (iter, is_sentence_start_func);
3280 }
3281
3282 /**
3283  * gtk_text_iter_ends_sentence:
3284  * @iter: a #GtkTextIter
3285  * 
3286  * Determines whether @iter ends a sentence.  Sentence boundaries are
3287  * determined by Pango and should be correct for nearly any language
3288  * (if not, the correct fix would be to the Pango text boundary
3289  * algorithms).
3290  * 
3291  * Return value: %TRUE if @iter is at the end of a sentence.
3292  **/
3293 gboolean
3294 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
3295 {
3296   return test_log_attrs (iter, is_sentence_end_func);
3297 }
3298
3299 /**
3300  * gtk_text_iter_inside_sentence:
3301  * @iter: a #GtkTextIter
3302  * 
3303  * Determines whether @iter is inside a sentence (as opposed to in
3304  * between two sentences, e.g. after a period and before the first
3305  * letter of the next sentence).  Sentence boundaries are determined
3306  * by Pango and should be correct for nearly any language (if not, the
3307  * correct fix would be to the Pango text boundary algorithms).
3308  * 
3309  * Return value: %TRUE if @iter is inside a sentence.
3310  **/
3311 gboolean
3312 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
3313 {
3314   return test_log_attrs (iter, inside_sentence_func);
3315 }
3316
3317 /**
3318  * gtk_text_iter_forward_sentence_end:
3319  * @iter: a #GtkTextIter
3320  * 
3321  * Moves forward to the next sentence end. (If @iter is at the end of
3322  * a sentence, moves to the next end of sentence.)  Sentence
3323  * boundaries are determined by Pango and should be correct for nearly
3324  * any language (if not, the correct fix would be to the Pango text
3325  * boundary algorithms).
3326  * 
3327  * Return value: %TRUE if @iter moved and is not the end iterator
3328  **/
3329 gboolean
3330 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
3331 {
3332   return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
3333 }
3334
3335 /**
3336  * gtk_text_iter_backward_sentence_start:
3337  * @iter: a #GtkTextIter
3338  * 
3339  * Moves backward to the previous sentence start; if @iter is already at
3340  * the start of a sentence, moves backward to the next one.  Sentence
3341  * boundaries are determined by Pango and should be correct for nearly
3342  * any language (if not, the correct fix would be to the Pango text
3343  * boundary algorithms).
3344  * 
3345  * Return value: %TRUE if @iter moved and is not the end iterator
3346  **/
3347 gboolean
3348 gtk_text_iter_backward_sentence_start (GtkTextIter      *iter)
3349 {
3350   return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
3351 }
3352
3353 /* FIXME a loop around a truly slow function means
3354  * a truly spectacularly slow function.
3355  */
3356 /**
3357  * gtk_text_iter_forward_sentence_ends:
3358  * @iter: a #GtkTextIter
3359  * @count: number of sentences to move
3360  * 
3361  * Calls gtk_text_iter_forward_sentence_end() @count times (or until
3362  * gtk_text_iter_forward_sentence_end() returns %FALSE). If @count is
3363  * negative, moves backward instead of forward.
3364  * 
3365  * Return value: %TRUE if @iter moved and is not the end iterator
3366  **/
3367 gboolean
3368 gtk_text_iter_forward_sentence_ends (GtkTextIter      *iter,
3369                                      gint              count)
3370 {
3371   return move_multiple_steps (iter, count, 
3372                               gtk_text_iter_forward_sentence_end,
3373                               gtk_text_iter_backward_sentence_starts);
3374 }
3375
3376 /**
3377  * gtk_text_iter_backward_sentence_starts:
3378  * @iter: a #GtkTextIter
3379  * @count: number of sentences to move
3380  * 
3381  * Calls gtk_text_iter_backward_sentence_start() up to @count times,
3382  * or until it returns %FALSE. If @count is negative, moves forward
3383  * instead of backward.
3384  * 
3385  * Return value: %TRUE if @iter moved and is not the end iterator
3386  **/
3387 gboolean
3388 gtk_text_iter_backward_sentence_starts (GtkTextIter      *iter,
3389                                         gint               count)
3390 {
3391   return move_multiple_steps (iter, count, 
3392                               gtk_text_iter_backward_sentence_start,
3393                               gtk_text_iter_forward_sentence_ends);
3394 }
3395
3396 static gboolean
3397 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3398                               gint          offset,
3399                               gint          min_offset,
3400                               gint          len,
3401                               gint         *found_offset,
3402                               gboolean      already_moved_initially)
3403 {
3404   if (!already_moved_initially)
3405     ++offset;
3406
3407   while (offset < (min_offset + len) &&
3408          !attrs[offset].is_cursor_position)
3409     ++offset;
3410
3411   *found_offset = offset;
3412
3413   return offset < (min_offset + len);
3414 }
3415
3416 static gboolean
3417 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3418                                gint          offset,
3419                                gint          min_offset,
3420                                gint          len,
3421                                gint         *found_offset,
3422                                gboolean      already_moved_initially)
3423 {  
3424   if (!already_moved_initially)
3425     --offset;
3426
3427   while (offset > min_offset &&
3428          !attrs[offset].is_cursor_position)
3429     --offset;
3430
3431   *found_offset = offset;
3432   
3433   return offset >= min_offset;
3434 }
3435
3436 static gboolean
3437 is_cursor_pos_func (const PangoLogAttr *attrs,
3438                     gint          offset,
3439                     gint          min_offset,
3440                     gint          len)
3441 {
3442   return attrs[offset].is_cursor_position;
3443 }
3444
3445 /**
3446  * gtk_text_iter_forward_cursor_position:
3447  * @iter: a #GtkTextIter
3448  * 
3449  * Moves @iter forward by a single cursor position. Cursor positions
3450  * are (unsurprisingly) positions where the cursor can appear. Perhaps
3451  * surprisingly, there may not be a cursor position between all
3452  * characters. The most common example for European languages would be
3453  * a carriage return/newline sequence. For some Unicode characters,
3454  * the equivalent of say the letter "a" with an accent mark will be
3455  * represented as two characters, first the letter then a "combining
3456  * mark" that causes the accent to be rendered; so the cursor can't go
3457  * between those two characters. See also the #PangoLogAttr structure and
3458  * pango_break() function.
3459  * 
3460  * Return value: %TRUE if we moved and the new position is dereferenceable
3461  **/
3462 gboolean
3463 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3464 {
3465   return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3466 }
3467
3468 /**
3469  * gtk_text_iter_backward_cursor_position:
3470  * @iter: a #GtkTextIter
3471  * 
3472  * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3473  * 
3474  * Return value: %TRUE if we moved
3475  **/
3476 gboolean
3477 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3478 {
3479   return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3480 }
3481
3482 /**
3483  * gtk_text_iter_forward_cursor_positions:
3484  * @iter: a #GtkTextIter
3485  * @count: number of positions to move
3486  * 
3487  * Moves up to @count cursor positions. See
3488  * gtk_text_iter_forward_cursor_position() for details.
3489  * 
3490  * Return value: %TRUE if we moved and the new position is dereferenceable
3491  **/
3492 gboolean
3493 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3494                                         gint         count)
3495 {
3496   return move_multiple_steps (iter, count, 
3497                               gtk_text_iter_forward_cursor_position,
3498                               gtk_text_iter_backward_cursor_positions);
3499 }
3500
3501 /**
3502  * gtk_text_iter_backward_cursor_positions:
3503  * @iter: a #GtkTextIter
3504  * @count: number of positions to move
3505  *
3506  * Moves up to @count cursor positions. See
3507  * gtk_text_iter_forward_cursor_position() for details.
3508  * 
3509  * Return value: %TRUE if we moved and the new position is dereferenceable
3510  **/
3511 gboolean
3512 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3513                                          gint         count)
3514 {
3515   return move_multiple_steps (iter, count, 
3516                               gtk_text_iter_backward_cursor_position,
3517                               gtk_text_iter_forward_cursor_positions);
3518 }
3519
3520 /**
3521  * gtk_text_iter_forward_visible_cursor_position:
3522  * @iter: a #GtkTextIter
3523  * 
3524  * Moves @iter forward to the next visible cursor position. See 
3525  * gtk_text_iter_forward_cursor_position() for details.
3526  * 
3527  * Return value: %TRUE if we moved and the new position is dereferenceable
3528  * 
3529  * Since: 2.4
3530  **/
3531 gboolean
3532 gtk_text_iter_forward_visible_cursor_position (GtkTextIter *iter)
3533 {
3534   return find_visible_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3535 }
3536
3537 /**
3538  * gtk_text_iter_backward_visible_cursor_position:
3539  * @iter: a #GtkTextIter
3540  * 
3541  * Moves @iter forward to the previous visible cursor position. See 
3542  * gtk_text_iter_backward_cursor_position() for details.
3543  * 
3544  * Return value: %TRUE if we moved and the new position is dereferenceable
3545  * 
3546  * Since: 2.4
3547  **/
3548 gboolean
3549 gtk_text_iter_backward_visible_cursor_position (GtkTextIter *iter)
3550 {
3551   return find_visible_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3552 }
3553
3554 /**
3555  * gtk_text_iter_forward_visible_cursor_positions:
3556  * @iter: a #GtkTextIter
3557  * @count: number of positions to move
3558  * 
3559  * Moves up to @count visible cursor positions. See
3560  * gtk_text_iter_forward_cursor_position() for details.
3561  * 
3562  * Return value: %TRUE if we moved and the new position is dereferenceable
3563  * 
3564  * Since: 2.4
3565  **/
3566 gboolean
3567 gtk_text_iter_forward_visible_cursor_positions (GtkTextIter *iter,
3568                                                 gint         count)
3569 {
3570   return move_multiple_steps (iter, count, 
3571                               gtk_text_iter_forward_visible_cursor_position,
3572                               gtk_text_iter_backward_visible_cursor_positions);
3573 }
3574
3575 /**
3576  * gtk_text_iter_backward_visible_cursor_positions:
3577  * @iter: a #GtkTextIter
3578  * @count: number of positions to move
3579  *
3580  * Moves up to @count visible cursor positions. See
3581  * gtk_text_iter_forward_cursor_position() for details.
3582  * 
3583  * Return value: %TRUE if we moved and the new position is dereferenceable
3584  * 
3585  * Since: 2.4
3586  **/
3587 gboolean
3588 gtk_text_iter_backward_visible_cursor_positions (GtkTextIter *iter,
3589                                                  gint         count)
3590 {
3591   return move_multiple_steps (iter, count, 
3592                               gtk_text_iter_backward_visible_cursor_position,
3593                               gtk_text_iter_forward_visible_cursor_positions);
3594 }
3595
3596 /**
3597  * gtk_text_iter_is_cursor_position:
3598  * @iter: a #GtkTextIter
3599  * 
3600  * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3601  * pango_break() for details on what a cursor position is.
3602  * 
3603  * Return value: %TRUE if the cursor can be placed at @iter
3604  **/
3605 gboolean
3606 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3607 {
3608   return test_log_attrs (iter, is_cursor_pos_func);
3609 }
3610
3611 /**
3612  * gtk_text_iter_set_line_offset:
3613  * @iter: a #GtkTextIter 
3614  * @char_on_line: a character offset relative to the start of @iter's current line
3615  * 
3616  * Moves @iter within a line, to a new <emphasis>character</emphasis>
3617  * (not byte) offset. The given character offset must be less than or
3618  * equal to the number of characters in the line; if equal, @iter
3619  * moves to the start of the next line. See
3620  * gtk_text_iter_set_line_index() if you have a byte index rather than
3621  * a character offset.
3622  *
3623  **/
3624 void
3625 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3626                                gint         char_on_line)
3627 {
3628   GtkTextRealIter *real;
3629   gint chars_in_line;
3630   
3631   g_return_if_fail (iter != NULL);
3632
3633   real = gtk_text_iter_make_surreal (iter);
3634
3635   if (real == NULL)
3636     return;
3637   
3638   check_invariants (iter);
3639
3640   chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3641
3642   g_return_if_fail (char_on_line <= chars_in_line);
3643
3644   if (char_on_line < chars_in_line)
3645     iter_set_from_char_offset (real, real->line, char_on_line);
3646   else
3647     gtk_text_iter_forward_line (iter); /* set to start of next line */
3648   
3649   check_invariants (iter);
3650 }
3651
3652 /**
3653  * gtk_text_iter_set_line_index:
3654  * @iter: a #GtkTextIter
3655  * @byte_on_line: a byte index relative to the start of @iter's current line
3656  *
3657  * Same as gtk_text_iter_set_line_offset(), but works with a
3658  * <emphasis>byte</emphasis> index. The given byte index must be at
3659  * the start of a character, it can't be in the middle of a UTF-8
3660  * encoded character.
3661  * 
3662  **/
3663 void
3664 gtk_text_iter_set_line_index (GtkTextIter *iter,
3665                               gint         byte_on_line)
3666 {
3667   GtkTextRealIter *real;
3668   gint bytes_in_line;
3669   
3670   g_return_if_fail (iter != NULL);
3671
3672   real = gtk_text_iter_make_surreal (iter);
3673
3674   if (real == NULL)
3675     return;
3676
3677   check_invariants (iter);
3678
3679   bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3680
3681   g_return_if_fail (byte_on_line <= bytes_in_line);
3682   
3683   if (byte_on_line < bytes_in_line)
3684     iter_set_from_byte_offset (real, real->line, byte_on_line);
3685   else
3686     gtk_text_iter_forward_line (iter);
3687
3688   if (real->segment->type == &gtk_text_char_type &&
3689       (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3690     g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3691                "character; this will crash the text buffer. "
3692                "Byte indexes must refer to the start of a character.",
3693                G_STRLOC, byte_on_line);
3694
3695   check_invariants (iter);
3696 }
3697
3698
3699 /**
3700  * gtk_text_iter_set_visible_line_offset:
3701  * @iter: a #GtkTextIter
3702  * @char_on_line: a character offset
3703  * 
3704  * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3705  * characters, i.e. text with a tag making it invisible is not
3706  * counted in the offset.
3707  **/
3708 void
3709 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3710                                        gint         char_on_line)
3711 {
3712   gint chars_seen = 0;
3713   GtkTextIter pos;
3714
3715   g_return_if_fail (iter != NULL);
3716   
3717   pos = *iter;
3718
3719   /* For now we use a ludicrously slow implementation */
3720   while (chars_seen < char_on_line)
3721     {
3722       if (!_gtk_text_btree_char_is_invisible (&pos))
3723         ++chars_seen;
3724
3725       if (!gtk_text_iter_forward_char (&pos))
3726         break;
3727
3728       if (chars_seen == char_on_line)
3729         break;
3730     }
3731   
3732   if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3733     *iter = pos;
3734   else
3735     gtk_text_iter_forward_line (iter);
3736 }
3737
3738 static gint
3739 bytes_in_char (GtkTextIter *iter)
3740 {
3741   return g_unichar_to_utf8 (gtk_text_iter_get_char (iter), NULL);
3742 }
3743
3744 /**
3745  * gtk_text_iter_set_visible_line_index:
3746  * @iter: a #GtkTextIter
3747  * @byte_on_line: a byte index
3748  * 
3749  * Like gtk_text_iter_set_line_index(), but the index is in visible
3750  * bytes, i.e. text with a tag making it invisible is not counted
3751  * in the index.
3752  **/
3753 void
3754 gtk_text_iter_set_visible_line_index  (GtkTextIter *iter,
3755                                        gint         byte_on_line)
3756 {
3757   gint bytes_seen = 0;
3758   gint skipped = 0;
3759   GtkTextIter pos;
3760
3761   g_return_if_fail (iter != NULL);
3762   
3763   pos = *iter;
3764
3765   /* For now we use a ludicrously slow implementation */
3766   while (bytes_seen < byte_on_line)
3767     {
3768       if (!_gtk_text_btree_char_is_invisible (&pos))
3769         bytes_seen += bytes_in_char (&pos);
3770       else skipped++;
3771
3772       if (!gtk_text_iter_forward_char (&pos))
3773         break;
3774
3775       if (bytes_seen >= byte_on_line)
3776         break;
3777     }
3778
3779   if (bytes_seen > byte_on_line)
3780     g_warning ("%s: Incorrect visible byte index %d falls in the middle of a UTF-8 "
3781                "character; this will crash the text buffer. "
3782                "Byte indexes must refer to the start of a character.",
3783                G_STRLOC, byte_on_line);
3784   
3785   if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3786     *iter = pos;
3787   else
3788     gtk_text_iter_forward_line (iter);
3789 }
3790
3791 /**
3792  * gtk_text_iter_set_line:
3793  * @iter: a #GtkTextIter
3794  * @line_number: line number (counted from 0)
3795  *
3796  * Moves iterator @iter to the start of the line @line_number.  If
3797  * @line_number is negative or larger than the number of lines in the
3798  * buffer, moves @iter to the start of the last line in the buffer.
3799  * 
3800  **/
3801 void
3802 gtk_text_iter_set_line (GtkTextIter *iter,
3803                         gint         line_number)
3804 {
3805   GtkTextLine *line;
3806   gint real_line;
3807   GtkTextRealIter *real;
3808
3809   g_return_if_fail (iter != NULL);
3810
3811   real = gtk_text_iter_make_surreal (iter);
3812
3813   if (real == NULL)
3814     return;
3815
3816   check_invariants (iter);
3817
3818   line = _gtk_text_btree_get_line_no_last (real->tree, line_number, &real_line);
3819
3820   iter_set_from_char_offset (real, line, 0);
3821
3822   /* We might as well cache this, since we know it. */
3823   real->cached_line_number = real_line;
3824
3825   check_invariants (iter);
3826 }
3827
3828 /**
3829  * gtk_text_iter_set_offset:
3830  * @iter: a #GtkTextIter
3831  * @char_offset: a character number
3832  *
3833  * Sets @iter to point to @char_offset. @char_offset counts from the start
3834  * of the entire text buffer, starting with 0.
3835  **/
3836 void
3837 gtk_text_iter_set_offset (GtkTextIter *iter,
3838                           gint         char_offset)
3839 {
3840   GtkTextLine *line;
3841   GtkTextRealIter *real;
3842   gint line_start;
3843   gint real_char_index;
3844
3845   g_return_if_fail (iter != NULL);
3846
3847   real = gtk_text_iter_make_surreal (iter);
3848
3849   if (real == NULL)
3850     return;
3851
3852   check_invariants (iter);
3853
3854   if (real->cached_char_index >= 0 &&
3855       real->cached_char_index == char_offset)
3856     return;
3857
3858   line = _gtk_text_btree_get_line_at_char (real->tree,
3859                                            char_offset,
3860                                            &line_start,
3861                                            &real_char_index);
3862
3863   iter_set_from_char_offset (real, line, real_char_index - line_start);
3864
3865   /* Go ahead and cache this since we have it. */
3866   real->cached_char_index = real_char_index;
3867
3868   check_invariants (iter);
3869 }
3870
3871 /**
3872  * gtk_text_iter_forward_to_end:
3873  * @iter: a #GtkTextIter
3874  *
3875  * Moves @iter forward to the "end iterator," which points one past the last
3876  * valid character in the buffer. gtk_text_iter_get_char() called on the
3877  * end iterator returns 0, which is convenient for writing loops.
3878  **/
3879 void
3880 gtk_text_iter_forward_to_end  (GtkTextIter *iter)
3881 {
3882   GtkTextBuffer *buffer;
3883   GtkTextRealIter *real;
3884
3885   g_return_if_fail (iter != NULL);
3886
3887   real = gtk_text_iter_make_surreal (iter);
3888
3889   if (real == NULL)
3890     return;
3891
3892   buffer = _gtk_text_btree_get_buffer (real->tree);
3893
3894   gtk_text_buffer_get_end_iter (buffer, iter);
3895 }
3896
3897 /* FIXME this and gtk_text_iter_forward_to_line_end() could be cleaned up
3898  * and made faster. Look at iter_ends_line() for inspiration, perhaps.
3899  * If all else fails we could cache the para delimiter pos in the iter.
3900  * I think forward_to_line_end() actually gets called fairly often.
3901  */
3902 static int
3903 find_paragraph_delimiter_for_line (GtkTextIter *iter)
3904 {
3905   GtkTextIter end;
3906   end = *iter;
3907
3908   if (_gtk_text_line_contains_end_iter (_gtk_text_iter_get_text_line (&end),
3909                                         _gtk_text_iter_get_btree (&end)))
3910     {
3911       gtk_text_iter_forward_to_end (&end);
3912     }
3913   else
3914     {
3915       /* if we aren't on the last line, go forward to start of next line, then scan
3916        * back for the delimiters on the previous line
3917        */
3918       gtk_text_iter_forward_line (&end);
3919       gtk_text_iter_backward_char (&end);
3920       while (!gtk_text_iter_ends_line (&end))
3921         gtk_text_iter_backward_char (&end);
3922     }
3923
3924   return gtk_text_iter_get_line_offset (&end);
3925 }
3926
3927 /**
3928  * gtk_text_iter_forward_to_line_end:
3929  * @iter: a #GtkTextIter
3930  * 
3931  * Moves the iterator to point to the paragraph delimiter characters,
3932  * which will be either a newline, a carriage return, a carriage
3933  * return/newline in sequence, or the Unicode paragraph separator
3934  * character. If the iterator is already at the paragraph delimiter
3935  * characters, moves to the paragraph delimiter characters for the
3936  * next line. If @iter is on the last line in the buffer, which does
3937  * not end in paragraph delimiters, moves to the end iterator (end of
3938  * the last line), and returns %FALSE.
3939  * 
3940  * Return value: %TRUE if we moved and the new location is not the end iterator
3941  **/
3942 gboolean
3943 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
3944 {
3945   gint current_offset;
3946   gint new_offset;
3947
3948   
3949   g_return_val_if_fail (iter != NULL, FALSE);
3950
3951   current_offset = gtk_text_iter_get_line_offset (iter);
3952   new_offset = find_paragraph_delimiter_for_line (iter);
3953   
3954   if (current_offset < new_offset)
3955     {
3956       /* Move to end of this line. */
3957       gtk_text_iter_set_line_offset (iter, new_offset);
3958       return !gtk_text_iter_is_end (iter);
3959     }
3960   else
3961     {
3962       /* Move to end of next line. */
3963       if (gtk_text_iter_forward_line (iter))
3964         {
3965           /* We don't want to move past all
3966            * empty lines.
3967            */
3968           if (!gtk_text_iter_ends_line (iter))
3969             gtk_text_iter_forward_to_line_end (iter);
3970           return !gtk_text_iter_is_end (iter);
3971         }
3972       else
3973         return FALSE;
3974     }
3975 }
3976
3977 /**
3978  * gtk_text_iter_forward_to_tag_toggle:
3979  * @iter: a #GtkTextIter
3980  * @tag: a #GtkTextTag, or %NULL
3981  *
3982  * Moves forward to the next toggle (on or off) of the
3983  * #GtkTextTag @tag, or to the next toggle of any tag if
3984  * @tag is %NULL. If no matching tag toggles are found,
3985  * returns %FALSE, otherwise %TRUE. Does not return toggles
3986  * located at @iter, only toggles after @iter. Sets @iter to
3987  * the location of the toggle, or to the end of the buffer
3988  * if no toggle is found.
3989  *
3990  * Return value: whether we found a tag toggle after @iter
3991  **/
3992 gboolean
3993 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
3994                                      GtkTextTag  *tag)
3995 {
3996   GtkTextLine *next_line;
3997   GtkTextLine *current_line;
3998   GtkTextRealIter *real;
3999
4000   g_return_val_if_fail (iter != NULL, FALSE);
4001
4002   real = gtk_text_iter_make_real (iter);
4003
4004   if (real == NULL)
4005     return FALSE;
4006
4007   check_invariants (iter);
4008
4009   current_line = real->line;
4010   next_line = _gtk_text_line_next_could_contain_tag (current_line,
4011                                                      real->tree, tag);
4012
4013   while (_gtk_text_iter_forward_indexable_segment (iter))
4014     {
4015       /* If we went forward to a line that couldn't contain a toggle
4016          for the tag, then skip forward to a line that could contain
4017          it. This potentially skips huge hunks of the tree, so we
4018          aren't a purely linear search. */
4019       if (real->line != current_line)
4020         {
4021           if (next_line == NULL)
4022             {
4023               /* End of search. Set to end of buffer. */
4024               _gtk_text_btree_get_end_iter (real->tree, iter);
4025               return FALSE;
4026             }
4027
4028           if (real->line != next_line)
4029             iter_set_from_byte_offset (real, next_line, 0);
4030
4031           current_line = real->line;
4032           next_line = _gtk_text_line_next_could_contain_tag (current_line,
4033                                                              real->tree,
4034                                                              tag);
4035         }
4036
4037       if (gtk_text_iter_toggles_tag (iter, tag))
4038         {
4039           /* If there's a toggle here, it isn't indexable so
4040              any_segment can't be the indexable segment. */
4041           g_assert (real->any_segment != real->segment);
4042           return TRUE;
4043         }
4044     }
4045
4046   /* Check end iterator for tags */
4047   if (gtk_text_iter_toggles_tag (iter, tag))
4048     {
4049       /* If there's a toggle here, it isn't indexable so
4050          any_segment can't be the indexable segment. */
4051       g_assert (real->any_segment != real->segment);
4052       return TRUE;
4053     }
4054
4055   /* Reached end of buffer */
4056   return FALSE;
4057 }
4058
4059 /**
4060  * gtk_text_iter_backward_to_tag_toggle:
4061  * @iter: a #GtkTextIter
4062  * @tag: a #GtkTextTag, or %NULL
4063  *
4064  * Moves backward to the next toggle (on or off) of the
4065  * #GtkTextTag @tag, or to the next toggle of any tag if
4066  * @tag is %NULL. If no matching tag toggles are found,
4067  * returns %FALSE, otherwise %TRUE. Does not return toggles
4068  * located at @iter, only toggles before @iter. Sets @iter
4069  * to the location of the toggle, or the start of the buffer
4070  * if no toggle is found.
4071  *
4072  * Return value: whether we found a tag toggle before @iter
4073  **/
4074 gboolean
4075 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
4076                                       GtkTextTag  *tag)
4077 {
4078   GtkTextLine *prev_line;
4079   GtkTextLine *current_line;
4080   GtkTextRealIter *real;
4081
4082   g_return_val_if_fail (iter != NULL, FALSE);
4083
4084   real = gtk_text_iter_make_real (iter);
4085
4086   if (real == NULL)
4087     return FALSE;
4088
4089   check_invariants (iter);
4090
4091   current_line = real->line;
4092   prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4093                                                         real->tree, tag);
4094
4095
4096   /* If we're at segment start, go to the previous segment;
4097    * if mid-segment, snap to start of current segment.
4098    */
4099   if (is_segment_start (real))
4100     {
4101       if (!_gtk_text_iter_backward_indexable_segment (iter))
4102         return FALSE;
4103     }
4104   else
4105     {
4106       ensure_char_offsets (real);
4107
4108       if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
4109         return FALSE;
4110     }
4111
4112   do
4113     {
4114       /* If we went backward to a line that couldn't contain a toggle
4115        * for the tag, then skip backward further to a line that
4116        * could contain it. This potentially skips huge hunks of the
4117        * tree, so we aren't a purely linear search.
4118        */
4119       if (real->line != current_line)
4120         {
4121           if (prev_line == NULL)
4122             {
4123               /* End of search. Set to start of buffer. */
4124               _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
4125               return FALSE;
4126             }
4127
4128           if (real->line != prev_line)
4129             {
4130               /* Set to last segment in prev_line (could do this
4131                * more quickly)
4132                */
4133               iter_set_from_byte_offset (real, prev_line, 0);
4134
4135               while (!at_last_indexable_segment (real))
4136                 _gtk_text_iter_forward_indexable_segment (iter);
4137             }
4138
4139           current_line = real->line;
4140           prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4141                                                                 real->tree,
4142                                                                 tag);
4143         }
4144
4145       if (gtk_text_iter_toggles_tag (iter, tag))
4146         {
4147           /* If there's a toggle here, it isn't indexable so
4148            * any_segment can't be the indexable segment.
4149            */
4150           g_assert (real->any_segment != real->segment);
4151           return TRUE;
4152         }
4153     }
4154   while (_gtk_text_iter_backward_indexable_segment (iter));
4155
4156   /* Reached front of buffer */
4157   return FALSE;
4158 }
4159
4160 static gboolean
4161 matches_pred (GtkTextIter *iter,
4162               GtkTextCharPredicate pred,
4163               gpointer user_data)
4164 {
4165   gint ch;
4166
4167   ch = gtk_text_iter_get_char (iter);
4168
4169   return (*pred) (ch, user_data);
4170 }
4171
4172 /**
4173  * gtk_text_iter_forward_find_char:
4174  * @iter: a #GtkTextIter
4175  * @pred: a function to be called on each character
4176  * @user_data: user data for @pred
4177  * @limit: search limit, or %NULL for none 
4178  * 
4179  * Advances @iter, calling @pred on each character. If
4180  * @pred returns %TRUE, returns %TRUE and stops scanning.
4181  * If @pred never returns %TRUE, @iter is set to @limit if
4182  * @limit is non-%NULL, otherwise to the end iterator.
4183  * 
4184  * Return value: whether a match was found
4185  **/
4186 gboolean
4187 gtk_text_iter_forward_find_char (GtkTextIter         *iter,
4188                                  GtkTextCharPredicate pred,
4189                                  gpointer             user_data,
4190                                  const GtkTextIter   *limit)
4191 {
4192   g_return_val_if_fail (iter != NULL, FALSE);
4193   g_return_val_if_fail (pred != NULL, FALSE);
4194
4195   if (limit &&
4196       gtk_text_iter_compare (iter, limit) >= 0)
4197     return FALSE;
4198   
4199   while ((limit == NULL ||
4200           !gtk_text_iter_equal (limit, iter)) &&
4201          gtk_text_iter_forward_char (iter))
4202     {      
4203       if (matches_pred (iter, pred, user_data))
4204         return TRUE;
4205     }
4206
4207   return FALSE;
4208 }
4209
4210 /**
4211  * gtk_text_iter_backward_find_char:
4212  * @iter: a #GtkTextIter
4213  * @pred: function to be called on each character
4214  * @user_data: user data for @pred
4215  * @limit: search limit, or %NULL for none
4216  * 
4217  * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
4218  * 
4219  * Return value: whether a match was found
4220  **/
4221 gboolean
4222 gtk_text_iter_backward_find_char (GtkTextIter         *iter,
4223                                   GtkTextCharPredicate pred,
4224                                   gpointer             user_data,
4225                                   const GtkTextIter   *limit)
4226 {
4227   g_return_val_if_fail (iter != NULL, FALSE);
4228   g_return_val_if_fail (pred != NULL, FALSE);
4229
4230   if (limit &&
4231       gtk_text_iter_compare (iter, limit) <= 0)
4232     return FALSE;
4233   
4234   while ((limit == NULL ||
4235           !gtk_text_iter_equal (limit, iter)) &&
4236          gtk_text_iter_backward_char (iter))
4237     {
4238       if (matches_pred (iter, pred, user_data))
4239         return TRUE;
4240     }
4241
4242   return FALSE;
4243 }
4244
4245 static void
4246 forward_chars_with_skipping (GtkTextIter *iter,
4247                              gint         count,
4248                              gboolean     skip_invisible,
4249                              gboolean     skip_nontext)
4250 {
4251
4252   gint i;
4253
4254   g_return_if_fail (count >= 0);
4255
4256   i = count;
4257
4258   while (i > 0)
4259     {
4260       gboolean ignored = FALSE;
4261
4262       if (skip_nontext &&
4263           gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
4264         ignored = TRUE;
4265
4266       if (!ignored &&
4267           skip_invisible &&
4268           _gtk_text_btree_char_is_invisible (iter))
4269         ignored = TRUE;
4270
4271       gtk_text_iter_forward_char (iter);
4272
4273       if (!ignored)
4274         --i;
4275     }
4276 }
4277
4278 static gboolean
4279 lines_match (const GtkTextIter *start,
4280              const gchar **lines,
4281              gboolean visible_only,
4282              gboolean slice,
4283              GtkTextIter *match_start,
4284              GtkTextIter *match_end)
4285 {
4286   GtkTextIter next;
4287   gchar *line_text;
4288   const gchar *found;
4289   gint offset;
4290
4291   if (*lines == NULL || **lines == '\0')
4292     {
4293       if (match_start)
4294         *match_start = *start;
4295
4296       if (match_end)
4297         *match_end = *start;
4298       return TRUE;
4299     }
4300
4301   next = *start;
4302   gtk_text_iter_forward_line (&next);
4303
4304   /* No more text in buffer, but *lines is nonempty */
4305   if (gtk_text_iter_equal (start, &next))
4306     {
4307       return FALSE;
4308     }
4309
4310   if (slice)
4311     {
4312       if (visible_only)
4313         line_text = gtk_text_iter_get_visible_slice (start, &next);
4314       else
4315         line_text = gtk_text_iter_get_slice (start, &next);
4316     }
4317   else
4318     {
4319       if (visible_only)
4320         line_text = gtk_text_iter_get_visible_text (start, &next);
4321       else
4322         line_text = gtk_text_iter_get_text (start, &next);
4323     }
4324
4325   if (match_start) /* if this is the first line we're matching */
4326     found = strstr (line_text, *lines);
4327   else
4328     {
4329       /* If it's not the first line, we have to match from the
4330        * start of the line.
4331        */
4332       if (strncmp (line_text, *lines, strlen (*lines)) == 0)
4333         found = line_text;
4334       else
4335         found = NULL;
4336     }
4337
4338   if (found == NULL)
4339     {
4340       g_free (line_text);
4341       return FALSE;
4342     }
4343
4344   /* Get offset to start of search string */
4345   offset = g_utf8_strlen (line_text, found - line_text);
4346
4347   next = *start;
4348
4349   /* If match start needs to be returned, set it to the
4350    * start of the search string.
4351    */
4352   if (match_start)
4353     {
4354       *match_start = next;
4355
4356       forward_chars_with_skipping (match_start, offset,
4357                                    visible_only, !slice);
4358     }
4359
4360   /* Go to end of search string */
4361   offset += g_utf8_strlen (*lines, -1);
4362
4363   forward_chars_with_skipping (&next, offset,
4364                                visible_only, !slice);
4365
4366   g_free (line_text);
4367
4368   ++lines;
4369
4370   if (match_end)
4371     *match_end = next;
4372
4373   /* pass NULL for match_start, since we don't need to find the
4374    * start again.
4375    */
4376   return lines_match (&next, lines, visible_only, slice, NULL, match_end);
4377 }
4378
4379 /* strsplit () that retains the delimiter as part of the string. */
4380 static gchar **
4381 strbreakup (const char *string,
4382             const char *delimiter,
4383             gint        max_tokens)
4384 {
4385   GSList *string_list = NULL, *slist;
4386   gchar **str_array, *s;
4387   guint i, n = 1;
4388
4389   g_return_val_if_fail (string != NULL, NULL);
4390   g_return_val_if_fail (delimiter != NULL, NULL);
4391
4392   if (max_tokens < 1)
4393     max_tokens = G_MAXINT;
4394
4395   s = strstr (string, delimiter);
4396   if (s)
4397     {
4398       guint delimiter_len = strlen (delimiter);
4399
4400       do
4401         {
4402           guint len;
4403           gchar *new_string;
4404
4405           len = s - string + delimiter_len;
4406           new_string = g_new (gchar, len + 1);
4407           strncpy (new_string, string, len);
4408           new_string[len] = 0;
4409           string_list = g_slist_prepend (string_list, new_string);
4410           n++;
4411           string = s + delimiter_len;
4412           s = strstr (string, delimiter);
4413         }
4414       while (--max_tokens && s);
4415     }
4416   if (*string)
4417     {
4418       n++;
4419       string_list = g_slist_prepend (string_list, g_strdup (string));
4420     }
4421
4422   str_array = g_new (gchar*, n);
4423
4424   i = n - 1;
4425
4426   str_array[i--] = NULL;
4427   for (slist = string_list; slist; slist = slist->next)
4428     str_array[i--] = slist->data;
4429
4430   g_slist_free (string_list);
4431
4432   return str_array;
4433 }
4434
4435 /**
4436  * gtk_text_iter_forward_search:
4437  * @iter: start of search
4438  * @str: a search string
4439  * @flags: flags affecting how the search is done
4440  * @match_start: return location for start of match, or %NULL
4441  * @match_end: return location for end of match, or %NULL
4442  * @limit: bound for the search, or %NULL for the end of the buffer
4443  * 
4444  * Searches forward for @str. Any match is returned by setting 
4445  * @match_start to the first character of the match and @match_end to the 
4446  * first character after the match. The search will not continue past
4447  * @limit. Note that a search is a linear or O(n) operation, so you
4448  * may wish to use @limit to avoid locking up your UI on large
4449  * buffers.
4450  * 
4451  * If the #GTK_TEXT_SEARCH_VISIBLE_ONLY flag is present, the match may
4452  * have invisible text interspersed in @str. i.e. @str will be a
4453  * possibly-noncontiguous subsequence of the matched range. similarly,
4454  * if you specify #GTK_TEXT_SEARCH_TEXT_ONLY, the match may have
4455  * pixbufs or child widgets mixed inside the matched range. If these
4456  * flags are not given, the match must be exact; the special 0xFFFC
4457  * character in @str will match embedded pixbufs or child widgets.
4458  *
4459  * Return value: whether a match was found
4460  **/
4461 gboolean
4462 gtk_text_iter_forward_search (const GtkTextIter *iter,
4463                               const gchar       *str,
4464                               GtkTextSearchFlags flags,
4465                               GtkTextIter       *match_start,
4466                               GtkTextIter       *match_end,
4467                               const GtkTextIter *limit)
4468 {
4469   gchar **lines = NULL;
4470   GtkTextIter match;
4471   gboolean retval = FALSE;
4472   GtkTextIter search;
4473   gboolean visible_only;
4474   gboolean slice;
4475   
4476   g_return_val_if_fail (iter != NULL, FALSE);
4477   g_return_val_if_fail (str != NULL, FALSE);
4478
4479   if (limit &&
4480       gtk_text_iter_compare (iter, limit) >= 0)
4481     return FALSE;
4482   
4483   if (*str == '\0')
4484     {
4485       /* If we can move one char, return the empty string there */
4486       match = *iter;
4487       
4488       if (gtk_text_iter_forward_char (&match))
4489         {
4490           if (limit &&
4491               gtk_text_iter_equal (&match, limit))
4492             return FALSE;
4493           
4494           if (match_start)
4495             *match_start = match;
4496           if (match_end)
4497             *match_end = match;
4498           return TRUE;
4499         }
4500       else
4501         return FALSE;
4502     }
4503
4504   visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4505   slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4506   
4507   /* locate all lines */
4508
4509   lines = strbreakup (str, "\n", -1);
4510
4511   search = *iter;
4512
4513   do
4514     {
4515       /* This loop has an inefficient worst-case, where
4516        * gtk_text_iter_get_text () is called repeatedly on
4517        * a single line.
4518        */
4519       GtkTextIter end;
4520
4521       if (limit &&
4522           gtk_text_iter_compare (&search, limit) >= 0)
4523         break;
4524       
4525       if (lines_match (&search, (const gchar**)lines,
4526                        visible_only, slice, &match, &end))
4527         {
4528           if (limit == NULL ||
4529               (limit &&
4530                gtk_text_iter_compare (&end, limit) < 0))
4531             {
4532               retval = TRUE;
4533               
4534               if (match_start)
4535                 *match_start = match;
4536               
4537               if (match_end)
4538                 *match_end = end;
4539             }
4540           
4541           break;
4542         }
4543     }
4544   while (gtk_text_iter_forward_line (&search));
4545
4546   g_strfreev ((gchar**)lines);
4547
4548   return retval;
4549 }
4550
4551 static gboolean
4552 vectors_equal_ignoring_trailing (gchar **vec1,
4553                                  gchar **vec2)
4554 {
4555   /* Ignores trailing chars in vec2's last line */
4556
4557   gchar **i1, **i2;
4558
4559   i1 = vec1;
4560   i2 = vec2;
4561
4562   while (*i1 && *i2)
4563     {
4564       if (strcmp (*i1, *i2) != 0)
4565         {
4566           if (*(i2 + 1) == NULL) /* if this is the last line */
4567             {
4568               gint len1 = strlen (*i1);
4569               gint len2 = strlen (*i2);
4570
4571               if (len2 >= len1 &&
4572                   strncmp (*i1, *i2, len1) == 0)
4573                 {
4574                   /* We matched ignoring the trailing stuff in vec2 */
4575                   return TRUE;
4576                 }
4577               else
4578                 {
4579                   return FALSE;
4580                 }
4581             }
4582           else
4583             {
4584               return FALSE;
4585             }
4586         }
4587       ++i1;
4588       ++i2;
4589     }
4590
4591   if (*i1 || *i2)
4592     {
4593       return FALSE;
4594     }
4595   else
4596     return TRUE;
4597 }
4598
4599 typedef struct _LinesWindow LinesWindow;
4600
4601 struct _LinesWindow
4602 {
4603   gint n_lines;
4604   gchar **lines;
4605   GtkTextIter first_line_start;
4606   GtkTextIter first_line_end;
4607   gboolean slice;
4608   gboolean visible_only;
4609 };
4610
4611 static void
4612 lines_window_init (LinesWindow       *win,
4613                    const GtkTextIter *start)
4614 {
4615   gint i;
4616   GtkTextIter line_start;
4617   GtkTextIter line_end;
4618
4619   /* If we start on line 1, there are 2 lines to search (0 and 1), so
4620    * n_lines can be 2.
4621    */
4622   if (gtk_text_iter_is_start (start) ||
4623       gtk_text_iter_get_line (start) + 1 < win->n_lines)
4624     {
4625       /* Already at the end, or not enough lines to match */
4626       win->lines = g_new0 (gchar*, 1);
4627       *win->lines = NULL;
4628       return;
4629     }
4630
4631   line_start = *start;
4632   line_end = *start;
4633
4634   /* Move to start iter to start of line */
4635   gtk_text_iter_set_line_offset (&line_start, 0);
4636
4637   if (gtk_text_iter_equal (&line_start, &line_end))
4638     {
4639       /* we were already at the start; so go back one line */
4640       gtk_text_iter_backward_line (&line_start);
4641     }
4642
4643   win->first_line_start = line_start;
4644   win->first_line_end = line_end;
4645
4646   win->lines = g_new0 (gchar*, win->n_lines + 1);
4647
4648   i = win->n_lines - 1;
4649   while (i >= 0)
4650     {
4651       gchar *line_text;
4652
4653       if (win->slice)
4654         {
4655           if (win->visible_only)
4656             line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
4657           else
4658             line_text = gtk_text_iter_get_slice (&line_start, &line_end);
4659         }
4660       else
4661         {
4662           if (win->visible_only)
4663             line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
4664           else
4665             line_text = gtk_text_iter_get_text (&line_start, &line_end);
4666         }
4667
4668       win->lines[i] = line_text;
4669
4670       line_end = line_start;
4671       gtk_text_iter_backward_line (&line_start);
4672
4673       --i;
4674     }
4675 }
4676
4677 static gboolean
4678 lines_window_back (LinesWindow *win)
4679 {
4680   GtkTextIter new_start;
4681   gchar *line_text;
4682
4683   new_start = win->first_line_start;
4684
4685   if (!gtk_text_iter_backward_line (&new_start))
4686     return FALSE;
4687   else
4688     {
4689       win->first_line_start = new_start;
4690       win->first_line_end = new_start;
4691
4692       gtk_text_iter_forward_line (&win->first_line_end);
4693     }
4694
4695   if (win->slice)
4696     {
4697       if (win->visible_only)
4698         line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
4699                                                      &win->first_line_end);
4700       else
4701         line_text = gtk_text_iter_get_slice (&win->first_line_start,
4702                                              &win->first_line_end);
4703     }
4704   else
4705     {
4706       if (win->visible_only)
4707         line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
4708                                                     &win->first_line_end);
4709       else
4710         line_text = gtk_text_iter_get_text (&win->first_line_start,
4711                                             &win->first_line_end);
4712     }
4713
4714   /* Move lines to make room for first line. */
4715   g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
4716
4717   *win->lines = line_text;
4718
4719   /* Free old last line and NULL-terminate */
4720   g_free (win->lines[win->n_lines]);
4721   win->lines[win->n_lines] = NULL;
4722
4723   return TRUE;
4724 }
4725
4726 static void
4727 lines_window_free (LinesWindow *win)
4728 {
4729   g_strfreev (win->lines);
4730 }
4731
4732 /**
4733  * gtk_text_iter_backward_search:
4734  * @iter: a #GtkTextIter where the search begins
4735  * @str: search string
4736  * @flags: bitmask of flags affecting the search
4737  * @match_start: return location for start of match, or %NULL
4738  * @match_end: return location for end of match, or %NULL
4739  * @limit: location of last possible @match_start, or %NULL for start of buffer
4740  * 
4741  * Same as gtk_text_iter_forward_search(), but moves backward.
4742  * 
4743  * Return value: whether a match was found
4744  **/
4745 gboolean
4746 gtk_text_iter_backward_search (const GtkTextIter *iter,
4747                                const gchar       *str,
4748                                GtkTextSearchFlags flags,
4749                                GtkTextIter       *match_start,
4750                                GtkTextIter       *match_end,
4751                                const GtkTextIter *limit)
4752 {
4753   gchar **lines = NULL;
4754   gchar **l;
4755   gint n_lines;
4756   LinesWindow win;
4757   gboolean retval = FALSE;
4758   gboolean visible_only;
4759   gboolean slice;
4760   
4761   g_return_val_if_fail (iter != NULL, FALSE);
4762   g_return_val_if_fail (str != NULL, FALSE);
4763
4764   if (limit &&
4765       gtk_text_iter_compare (limit, iter) > 0)
4766     return FALSE;
4767   
4768   if (*str == '\0')
4769     {
4770       /* If we can move one char, return the empty string there */
4771       GtkTextIter match = *iter;
4772
4773       if (limit && gtk_text_iter_equal (limit, &match))
4774         return FALSE;
4775       
4776       if (gtk_text_iter_backward_char (&match))
4777         {
4778           if (match_start)
4779             *match_start = match;
4780           if (match_end)
4781             *match_end = match;
4782           return TRUE;
4783         }
4784       else
4785         return FALSE;
4786     }
4787
4788   visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4789   slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4790   
4791   /* locate all lines */
4792
4793   lines = strbreakup (str, "\n", -1);
4794
4795   l = lines;
4796   n_lines = 0;
4797   while (*l)
4798     {
4799       ++n_lines;
4800       ++l;
4801     }
4802
4803   win.n_lines = n_lines;
4804   win.slice = slice;
4805   win.visible_only = visible_only;
4806
4807   lines_window_init (&win, iter);
4808
4809   if (*win.lines == NULL)
4810     goto out;
4811
4812   do
4813     {
4814       gchar *first_line_match;
4815
4816       if (limit &&
4817           gtk_text_iter_compare (limit, &win.first_line_end) > 0)
4818         {
4819           /* We're now before the search limit, abort. */
4820           goto out;
4821         }
4822       
4823       /* If there are multiple lines, the first line will
4824        * end in '\n', so this will only match at the
4825        * end of the first line, which is correct.
4826        */
4827       first_line_match = g_strrstr (*win.lines, *lines);
4828
4829       if (first_line_match &&
4830           vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
4831         {
4832           /* Match! */
4833           gint offset;
4834           GtkTextIter next;
4835           GtkTextIter start_tmp;
4836           
4837           /* Offset to start of search string */
4838           offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
4839
4840           next = win.first_line_start;
4841           start_tmp = next;
4842           forward_chars_with_skipping (&start_tmp, offset,
4843                                        visible_only, !slice);
4844
4845           if (limit &&
4846               gtk_text_iter_compare (limit, &start_tmp) > 0)
4847             goto out; /* match was bogus */
4848           
4849           if (match_start)
4850             *match_start = start_tmp;
4851
4852           /* Go to end of search string */
4853           l = lines;
4854           while (*l)
4855             {
4856               offset += g_utf8_strlen (*l, -1);
4857               ++l;
4858             }
4859
4860           forward_chars_with_skipping (&next, offset,
4861                                        visible_only, !slice);
4862
4863           if (match_end)
4864             *match_end = next;
4865
4866           retval = TRUE;
4867           goto out;
4868         }
4869     }
4870   while (lines_window_back (&win));
4871
4872  out:
4873   lines_window_free (&win);
4874   g_strfreev (lines);
4875   
4876   return retval;
4877 }
4878
4879 /*
4880  * Comparisons
4881  */
4882
4883 /**
4884  * gtk_text_iter_equal:
4885  * @lhs: a #GtkTextIter
4886  * @rhs: another #GtkTextIter
4887  * 
4888  * Tests whether two iterators are equal, using the fastest possible
4889  * mechanism. This function is very fast; you can expect it to perform
4890  * better than e.g. getting the character offset for each iterator and
4891  * comparing the offsets yourself. Also, it's a bit faster than
4892  * gtk_text_iter_compare().
4893  * 
4894  * Return value: %TRUE if the iterators point to the same place in the buffer
4895  **/
4896 gboolean
4897 gtk_text_iter_equal (const GtkTextIter *lhs,
4898                      const GtkTextIter *rhs)
4899 {
4900   GtkTextRealIter *real_lhs;
4901   GtkTextRealIter *real_rhs;
4902
4903   real_lhs = (GtkTextRealIter*)lhs;
4904   real_rhs = (GtkTextRealIter*)rhs;
4905
4906   check_invariants (lhs);
4907   check_invariants (rhs);
4908
4909   if (real_lhs->line != real_rhs->line)
4910     return FALSE;
4911   else if (real_lhs->line_byte_offset >= 0 &&
4912            real_rhs->line_byte_offset >= 0)
4913     return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
4914   else
4915     {
4916       /* the ensure_char_offsets () calls do nothing if the char offsets
4917          are already up-to-date. */
4918       ensure_char_offsets (real_lhs);
4919       ensure_char_offsets (real_rhs);
4920       return real_lhs->line_char_offset == real_rhs->line_char_offset;
4921     }
4922 }
4923
4924 /**
4925  * gtk_text_iter_compare:
4926  * @lhs: a #GtkTextIter
4927  * @rhs: another #GtkTextIter
4928  * 
4929  * A qsort()-style function that returns negative if @lhs is less than
4930  * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
4931  * Ordering is in character offset order, i.e. the first character in the buffer
4932  * is less than the second character in the buffer.
4933  * 
4934  * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
4935  **/
4936 gint
4937 gtk_text_iter_compare (const GtkTextIter *lhs,
4938                        const GtkTextIter *rhs)
4939 {
4940   GtkTextRealIter *real_lhs;
4941   GtkTextRealIter *real_rhs;
4942
4943   real_lhs = gtk_text_iter_make_surreal (lhs);
4944   real_rhs = gtk_text_iter_make_surreal (rhs);
4945
4946   if (real_lhs == NULL ||
4947       real_rhs == NULL)
4948     return -1; /* why not */
4949
4950   check_invariants (lhs);
4951   check_invariants (rhs);
4952   
4953   if (real_lhs->line == real_rhs->line)
4954     {
4955       gint left_index, right_index;
4956
4957       if (real_lhs->line_byte_offset >= 0 &&
4958           real_rhs->line_byte_offset >= 0)
4959         {
4960           left_index = real_lhs->line_byte_offset;
4961           right_index = real_rhs->line_byte_offset;
4962         }
4963       else
4964         {
4965           /* the ensure_char_offsets () calls do nothing if
4966              the offsets are already up-to-date. */
4967           ensure_char_offsets (real_lhs);
4968           ensure_char_offsets (real_rhs);
4969           left_index = real_lhs->line_char_offset;
4970           right_index = real_rhs->line_char_offset;
4971         }
4972
4973       if (left_index < right_index)
4974         return -1;
4975       else if (left_index > right_index)
4976         return 1;
4977       else
4978         return 0;
4979     }
4980   else
4981     {
4982       gint line1, line2;
4983
4984       line1 = gtk_text_iter_get_line (lhs);
4985       line2 = gtk_text_iter_get_line (rhs);
4986       if (line1 < line2)
4987         return -1;
4988       else if (line1 > line2)
4989         return 1;
4990       else
4991         return 0;
4992     }
4993 }
4994
4995 /**
4996  * gtk_text_iter_in_range:
4997  * @iter: a #GtkTextIter
4998  * @start: start of range
4999  * @end: end of range
5000  * 
5001  * Checks whether @iter falls in the range [@start, @end).
5002  * @start and @end must be in ascending order.
5003  * 
5004  * Return value: %TRUE if @iter is in the range
5005  **/
5006 gboolean
5007 gtk_text_iter_in_range (const GtkTextIter *iter,
5008                         const GtkTextIter *start,
5009                         const GtkTextIter *end)
5010 {
5011   g_return_val_if_fail (iter != NULL, FALSE);
5012   g_return_val_if_fail (start != NULL, FALSE);
5013   g_return_val_if_fail (end != NULL, FALSE);
5014   g_return_val_if_fail (gtk_text_iter_compare (start, end) <= 0, FALSE);
5015   
5016   return gtk_text_iter_compare (iter, start) >= 0 &&
5017     gtk_text_iter_compare (iter, end) < 0;
5018 }
5019
5020 /**
5021  * gtk_text_iter_order:
5022  * @first: a #GtkTextIter
5023  * @second: another #GtkTextIter
5024  *
5025  * Swaps the value of @first and @second if @second comes before
5026  * @first in the buffer. That is, ensures that @first and @second are
5027  * in sequence. Most text buffer functions that take a range call this
5028  * automatically on your behalf, so there's no real reason to call it yourself
5029  * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
5030  * that expect a pre-sorted range.
5031  * 
5032  **/
5033 void
5034 gtk_text_iter_order (GtkTextIter *first,
5035                      GtkTextIter *second)
5036 {
5037   g_return_if_fail (first != NULL);
5038   g_return_if_fail (second != NULL);
5039
5040   if (gtk_text_iter_compare (first, second) > 0)
5041     {
5042       GtkTextIter tmp;
5043
5044       tmp = *first;
5045       *first = *second;
5046       *second = tmp;
5047     }
5048 }
5049
5050 /*
5051  * Init iterators from the BTree
5052  */
5053
5054 void
5055 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
5056                                   GtkTextIter *iter,
5057                                   gint char_index)
5058 {
5059   GtkTextRealIter *real = (GtkTextRealIter*)iter;
5060   gint real_char_index;
5061   gint line_start;
5062   GtkTextLine *line;
5063
5064   g_return_if_fail (iter != NULL);
5065   g_return_if_fail (tree != NULL);
5066
5067   line = _gtk_text_btree_get_line_at_char (tree, char_index,
5068                                            &line_start, &real_char_index);
5069
5070   iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
5071
5072   real->cached_char_index = real_char_index;
5073
5074   check_invariants (iter);
5075 }
5076
5077 void
5078 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
5079                                        GtkTextIter  *iter,
5080                                        gint          line_number,
5081                                        gint          char_on_line)
5082 {
5083   GtkTextRealIter *real = (GtkTextRealIter*)iter;
5084   GtkTextLine *line;
5085   gint real_line;
5086
5087   g_return_if_fail (iter != NULL);
5088   g_return_if_fail (tree != NULL);
5089
5090   line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5091   
5092   iter_init_from_char_offset (iter, tree, line, char_on_line);
5093
5094   /* We might as well cache this, since we know it. */
5095   real->cached_line_number = real_line;
5096
5097   check_invariants (iter);
5098 }
5099
5100 void
5101 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree   *tree,
5102                                        GtkTextIter    *iter,
5103                                        gint            line_number,
5104                                        gint            byte_index)
5105 {
5106   GtkTextRealIter *real = (GtkTextRealIter*)iter;
5107   GtkTextLine *line;
5108   gint real_line;
5109
5110   g_return_if_fail (iter != NULL);
5111   g_return_if_fail (tree != NULL);
5112
5113   line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5114
5115   iter_init_from_byte_offset (iter, tree, line, byte_index);
5116
5117   /* We might as well cache this, since we know it. */
5118   real->cached_line_number = real_line;
5119
5120   check_invariants (iter);
5121 }
5122
5123 void
5124 _gtk_text_btree_get_iter_at_line      (GtkTextBTree   *tree,
5125                                        GtkTextIter    *iter,
5126                                        GtkTextLine    *line,
5127                                        gint            byte_offset)
5128 {
5129   g_return_if_fail (iter != NULL);
5130   g_return_if_fail (tree != NULL);
5131   g_return_if_fail (line != NULL);
5132
5133   iter_init_from_byte_offset (iter, tree, line, byte_offset);
5134
5135   check_invariants (iter);
5136 }
5137
5138 gboolean
5139 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree   *tree,
5140                                           GtkTextIter    *iter,
5141                                           GtkTextTag     *tag)
5142 {
5143   GtkTextLine *line;
5144
5145   g_return_val_if_fail (iter != NULL, FALSE);
5146   g_return_val_if_fail (tree != NULL, FALSE);
5147
5148   line = _gtk_text_btree_first_could_contain_tag (tree, tag);
5149
5150   if (line == NULL)
5151     {
5152       /* Set iter to last in tree */
5153       _gtk_text_btree_get_end_iter (tree, iter);
5154       check_invariants (iter);
5155       return FALSE;
5156     }
5157   else
5158     {
5159       iter_init_from_byte_offset (iter, tree, line, 0);
5160
5161       if (!gtk_text_iter_toggles_tag (iter, tag))
5162         gtk_text_iter_forward_to_tag_toggle (iter, tag);
5163
5164       check_invariants (iter);
5165       return TRUE;
5166     }
5167 }
5168
5169 gboolean
5170 _gtk_text_btree_get_iter_at_last_toggle  (GtkTextBTree   *tree,
5171                                           GtkTextIter    *iter,
5172                                           GtkTextTag     *tag)
5173 {
5174   g_return_val_if_fail (iter != NULL, FALSE);
5175   g_return_val_if_fail (tree != NULL, FALSE);
5176
5177   _gtk_text_btree_get_end_iter (tree, iter);
5178   gtk_text_iter_backward_to_tag_toggle (iter, tag);
5179   check_invariants (iter);
5180   
5181   return TRUE;
5182 }
5183
5184 gboolean
5185 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
5186                                        GtkTextIter *iter,
5187                                        const gchar *mark_name)
5188 {
5189   GtkTextMark *mark;
5190
5191   g_return_val_if_fail (iter != NULL, FALSE);
5192   g_return_val_if_fail (tree != NULL, FALSE);
5193
5194   mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
5195
5196   if (mark == NULL)
5197     return FALSE;
5198   else
5199     {
5200       _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
5201       check_invariants (iter);
5202       return TRUE;
5203     }
5204 }
5205
5206 void
5207 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
5208                                   GtkTextIter *iter,
5209                                   GtkTextMark *mark)
5210 {
5211   GtkTextLineSegment *seg;
5212
5213   g_return_if_fail (iter != NULL);
5214   g_return_if_fail (tree != NULL);
5215   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
5216
5217   seg = mark->segment;
5218
5219   iter_init_from_segment (iter, tree,
5220                           seg->body.mark.line, seg);
5221   g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
5222   check_invariants (iter);
5223 }
5224
5225 void
5226 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree       *tree,
5227                                           GtkTextIter        *iter,
5228                                           GtkTextChildAnchor *anchor)
5229 {
5230   GtkTextLineSegment *seg;
5231
5232   g_return_if_fail (iter != NULL);
5233   g_return_if_fail (tree != NULL);
5234   g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
5235   
5236   seg = anchor->segment;  
5237
5238   g_assert (seg->body.child.line != NULL);
5239   
5240   iter_init_from_segment (iter, tree,
5241                           seg->body.child.line, seg);
5242   g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
5243   check_invariants (iter);
5244 }
5245
5246 void
5247 _gtk_text_btree_get_end_iter         (GtkTextBTree   *tree,
5248                                       GtkTextIter    *iter)
5249 {
5250   g_return_if_fail (iter != NULL);
5251   g_return_if_fail (tree != NULL);
5252
5253   _gtk_text_btree_get_iter_at_char (tree,
5254                                    iter,
5255                                    _gtk_text_btree_char_count (tree));
5256   check_invariants (iter);
5257 }
5258
5259 void
5260 _gtk_text_iter_check (const GtkTextIter *iter)
5261 {
5262   const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
5263   gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
5264   GtkTextLineSegment *byte_segment = NULL;
5265   GtkTextLineSegment *byte_any_segment = NULL;
5266   GtkTextLineSegment *char_segment = NULL;
5267   GtkTextLineSegment *char_any_segment = NULL;
5268   gboolean segments_updated;
5269
5270   /* This function checks our class invariants for the Iter class. */
5271
5272   g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
5273
5274   if (real->chars_changed_stamp !=
5275       _gtk_text_btree_get_chars_changed_stamp (real->tree))
5276     g_error ("iterator check failed: invalid iterator");
5277
5278   if (real->line_char_offset < 0 && real->line_byte_offset < 0)
5279     g_error ("iterator check failed: both char and byte offsets are invalid");
5280
5281   segments_updated = (real->segments_changed_stamp ==
5282                       _gtk_text_btree_get_segments_changed_stamp (real->tree));
5283
5284 #if 0
5285   printf ("checking iter, segments %s updated, byte %d char %d\n",
5286           segments_updated ? "are" : "aren't",
5287           real->line_byte_offset,
5288           real->line_char_offset);
5289 #endif
5290
5291   if (segments_updated)
5292     {
5293       if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
5294         g_error ("iterator check failed: both char and byte segment offsets are invalid");
5295
5296       if (real->segment->char_count == 0)
5297         g_error ("iterator check failed: segment is not indexable.");
5298
5299       if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
5300         g_error ("segment char offset is not properly up-to-date");
5301
5302       if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
5303         g_error ("segment byte offset is not properly up-to-date");
5304
5305       if (real->segment_byte_offset >= 0 &&
5306           real->segment_byte_offset >= real->segment->byte_count)
5307         g_error ("segment byte offset is too large.");
5308
5309       if (real->segment_char_offset >= 0 &&
5310           real->segment_char_offset >= real->segment->char_count)
5311         g_error ("segment char offset is too large.");
5312     }
5313
5314   if (real->line_byte_offset >= 0)
5315     {
5316       _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5317                                   &byte_segment, &byte_any_segment,
5318                                   &seg_byte_offset, &line_byte_offset);
5319
5320       if (line_byte_offset != real->line_byte_offset)
5321         g_error ("wrong byte offset was stored in iterator");
5322
5323       if (segments_updated)
5324         {
5325           if (real->segment != byte_segment)
5326             g_error ("wrong segment was stored in iterator");
5327
5328           if (real->any_segment != byte_any_segment)
5329             g_error ("wrong any_segment was stored in iterator");
5330
5331           if (seg_byte_offset != real->segment_byte_offset)
5332             g_error ("wrong segment byte offset was stored in iterator");
5333
5334           if (byte_segment->type == &gtk_text_char_type)
5335             {
5336               const gchar *p;
5337               p = byte_segment->body.chars + seg_byte_offset;
5338               
5339               if (!gtk_text_byte_begins_utf8_char (p))
5340                 g_error ("broken iterator byte index pointed into the middle of a character");
5341             }
5342         }
5343     }
5344
5345   if (real->line_char_offset >= 0)
5346     {
5347       _gtk_text_line_char_locate (real->line, real->line_char_offset,
5348                                   &char_segment, &char_any_segment,
5349                                   &seg_char_offset, &line_char_offset);
5350
5351       if (line_char_offset != real->line_char_offset)
5352         g_error ("wrong char offset was stored in iterator");
5353
5354       if (segments_updated)
5355         {          
5356           if (real->segment != char_segment)
5357             g_error ("wrong segment was stored in iterator");
5358
5359           if (real->any_segment != char_any_segment)
5360             g_error ("wrong any_segment was stored in iterator");
5361
5362           if (seg_char_offset != real->segment_char_offset)
5363             g_error ("wrong segment char offset was stored in iterator");
5364
5365           if (char_segment->type == &gtk_text_char_type)
5366             {
5367               const gchar *p;
5368               p = g_utf8_offset_to_pointer (char_segment->body.chars,
5369                                             seg_char_offset);
5370
5371               /* hmm, not likely to happen eh */
5372               if (!gtk_text_byte_begins_utf8_char (p))
5373                 g_error ("broken iterator char offset pointed into the middle of a character");
5374             }
5375         }
5376     }
5377
5378   if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5379     {
5380       if (byte_segment != char_segment)
5381         g_error ("char and byte offsets did not point to the same segment");
5382
5383       if (byte_any_segment != char_any_segment)
5384         g_error ("char and byte offsets did not point to the same any segment");
5385
5386       /* Make sure the segment offsets are equivalent, if it's a char
5387          segment. */
5388       if (char_segment->type == &gtk_text_char_type)
5389         {
5390           gint byte_offset = 0;
5391           gint char_offset = 0;
5392           while (char_offset < seg_char_offset)
5393             {
5394               const char * start = char_segment->body.chars + byte_offset;
5395               byte_offset += g_utf8_next_char (start) - start;
5396               char_offset += 1;
5397             }
5398
5399           if (byte_offset != seg_byte_offset)
5400             g_error ("byte offset did not correspond to char offset");
5401
5402           char_offset =
5403             g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5404
5405           if (char_offset != seg_char_offset)
5406             g_error ("char offset did not correspond to byte offset");
5407
5408           if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5409             g_error ("byte index for iterator does not index the start of a character");
5410         }
5411     }
5412
5413   if (real->cached_line_number >= 0)
5414     {
5415       gint should_be;
5416
5417       should_be = _gtk_text_line_get_number (real->line);
5418       if (real->cached_line_number != should_be)
5419         g_error ("wrong line number was cached");
5420     }
5421
5422   if (real->cached_char_index >= 0)
5423     {
5424       if (real->line_char_offset >= 0) /* only way we can check it
5425                                           efficiently, not a real
5426                                           invariant. */
5427         {
5428           gint char_index;
5429
5430           char_index = _gtk_text_line_char_index (real->line);
5431           char_index += real->line_char_offset;
5432
5433           if (real->cached_char_index != char_index)
5434             g_error ("wrong char index was cached");
5435         }
5436     }
5437
5438   if (_gtk_text_line_is_last (real->line, real->tree))
5439     g_error ("Iterator was on last line (past the end iterator)");
5440 }
5441