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