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