]> Pileus Git - ~andy/gtk/blob - gtk/gtktextiter.c
handle the case of \r and \n split across lines. Bug #337022. add unit
[~andy/gtk] / gtk / gtktextiter.c
1 /* GTK - The GIMP Toolkit
2  * gtktextiter.c Copyright (C) 2000 Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
25  */
26
27 #define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
28 #include <config.h>
29 #include "gtktextiter.h"
30 #include "gtktextbtree.h"
31 #include "gtktextiterprivate.h"
32 #include "gtkdebug.h"
33 #include "gtkalias.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 #ifdef G_ENABLE_DEBUG
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_slice_new (GtkTextIter);
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_slice_free (GtkTextIter, 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   gunichar wc;
1551   
1552   g_return_val_if_fail (iter != NULL, FALSE);
1553
1554   check_invariants (iter);
1555
1556   /* Only one character has type G_UNICODE_PARAGRAPH_SEPARATOR in
1557    * Unicode 3.0; update this if that changes.
1558    */
1559 #define PARAGRAPH_SEPARATOR 0x2029
1560
1561   wc = gtk_text_iter_get_char (iter);
1562   
1563   if (wc == '\r' || wc == PARAGRAPH_SEPARATOR || wc == 0) /* wc == 0 is end iterator */
1564     return TRUE;
1565   else if (wc == '\n')
1566     {
1567       GtkTextIter tmp = *iter;
1568
1569       /* need to determine if a \r precedes the \n, in which case
1570        * we aren't the end of the line.
1571        * Note however that if \r and \n are on different lines, they
1572        * both are terminators. This for instance may happen after
1573        * deleting some text:
1574
1575           1 some text\r    delete 'a'    1 some text\r
1576           2 a\n            --------->    2 \n
1577           3 ...                          3 ...
1578
1579        */
1580
1581       if (gtk_text_iter_get_line_offset (&tmp) == 0)
1582         return TRUE;
1583
1584       if (!gtk_text_iter_backward_char (&tmp))
1585         return TRUE;
1586
1587       return gtk_text_iter_get_char (&tmp) != '\r';
1588     }
1589   else
1590     return FALSE;
1591 }
1592
1593 /**
1594  * gtk_text_iter_is_end:
1595  * @iter: an iterator
1596  *
1597  * Returns %TRUE if @iter is the end iterator, i.e. one past the last
1598  * dereferenceable iterator in the buffer. gtk_text_iter_is_end () is
1599  * the most efficient way to check whether an iterator is the end
1600  * iterator.
1601  *
1602  * Return value: whether @iter is the end iterator
1603  **/
1604 gboolean
1605 gtk_text_iter_is_end (const GtkTextIter *iter)
1606 {
1607   GtkTextRealIter *real;
1608
1609   g_return_val_if_fail (iter != NULL, FALSE);
1610
1611   real = gtk_text_iter_make_surreal (iter);
1612
1613   if (real == NULL)
1614     return FALSE;
1615
1616   check_invariants (iter);
1617
1618   if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1619     return FALSE;
1620
1621   /* Now we need the segments validated */
1622   real = gtk_text_iter_make_real (iter);
1623
1624   if (real == NULL)
1625     return FALSE;
1626   
1627   return _gtk_text_btree_is_end (real->tree, real->line,
1628                                  real->segment,
1629                                  real->segment_byte_offset,
1630                                  real->segment_char_offset);
1631 }
1632
1633 /**
1634  * gtk_text_iter_is_start:
1635  * @iter: an iterator
1636  *
1637  * Returns %TRUE if @iter is the first iterator in the buffer, that is
1638  * if @iter has a character offset of 0.
1639  *
1640  * Return value: whether @iter is the first in the buffer
1641  **/
1642 gboolean
1643 gtk_text_iter_is_start (const GtkTextIter *iter)
1644 {
1645   return gtk_text_iter_get_offset (iter) == 0;
1646 }
1647
1648 /**
1649  * gtk_text_iter_get_chars_in_line:
1650  * @iter: an iterator
1651  *
1652  * Returns the number of characters in the line containing @iter,
1653  * including the paragraph delimiters.
1654  *
1655  * Return value: number of characters in the line
1656  **/
1657 gint
1658 gtk_text_iter_get_chars_in_line (const GtkTextIter   *iter)
1659 {
1660   GtkTextRealIter *real;
1661   gint count;
1662   GtkTextLineSegment *seg;
1663
1664   g_return_val_if_fail (iter != NULL, 0);
1665
1666   real = gtk_text_iter_make_surreal (iter);
1667
1668   if (real == NULL)
1669     return 0;
1670
1671   check_invariants (iter);
1672
1673   if (real->line_char_offset >= 0)
1674     {
1675       /* We can start at the segments we've already found. */
1676       count = real->line_char_offset - real->segment_char_offset;
1677       seg = _gtk_text_iter_get_indexable_segment (iter);
1678     }
1679   else
1680     {
1681       /* count whole line. */
1682       seg = real->line->segments;
1683       count = 0;
1684     }
1685
1686
1687   while (seg != NULL)
1688     {
1689       count += seg->char_count;
1690
1691       seg = seg->next;
1692     }
1693
1694   if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1695     count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1696   
1697   return count;
1698 }
1699
1700 /**
1701  * gtk_text_iter_get_bytes_in_line:
1702  * @iter: an iterator
1703  *
1704  * Returns the number of bytes in the line containing @iter,
1705  * including the paragraph delimiters.
1706  *
1707  * Return value: number of bytes in the line
1708  **/
1709 gint
1710 gtk_text_iter_get_bytes_in_line (const GtkTextIter   *iter)
1711 {
1712   GtkTextRealIter *real;
1713   gint count;
1714   GtkTextLineSegment *seg;
1715
1716   g_return_val_if_fail (iter != NULL, 0);
1717
1718   real = gtk_text_iter_make_surreal (iter);
1719
1720   if (real == NULL)
1721     return 0;
1722
1723   check_invariants (iter);
1724
1725   if (real->line_byte_offset >= 0)
1726     {
1727       /* We can start at the segments we've already found. */
1728       count = real->line_byte_offset - real->segment_byte_offset;
1729       seg = _gtk_text_iter_get_indexable_segment (iter);
1730     }
1731   else
1732     {
1733       /* count whole line. */
1734       seg = real->line->segments;
1735       count = 0;
1736     }
1737
1738   while (seg != NULL)
1739     {
1740       count += seg->byte_count;
1741
1742       seg = seg->next;
1743     }
1744
1745   if (_gtk_text_line_contains_end_iter (real->line, real->tree))
1746     count -= 1; /* Dump the newline that was in the last segment of the end iter line */
1747   
1748   return count;
1749 }
1750
1751 /**
1752  * gtk_text_iter_get_attributes:
1753  * @iter: an iterator
1754  * @values: a #GtkTextAttributes to be filled in
1755  *
1756  * Computes the effect of any tags applied to this spot in the
1757  * text. The @values parameter should be initialized to the default
1758  * settings you wish to use if no tags are in effect. You'd typically
1759  * obtain the defaults from gtk_text_view_get_default_attributes().
1760  *
1761  * gtk_text_iter_get_attributes () will modify @values, applying the
1762  * effects of any tags present at @iter. If any tags affected @values,
1763  * the function returns %TRUE.
1764  *
1765  * Return value: %TRUE if @values was modified
1766  **/
1767 gboolean
1768 gtk_text_iter_get_attributes (const GtkTextIter  *iter,
1769                               GtkTextAttributes  *values)
1770 {
1771   GtkTextTag** tags;
1772   gint tag_count = 0;
1773
1774   /* Get the tags at this spot */
1775   tags = _gtk_text_btree_get_tags (iter, &tag_count);
1776
1777   /* No tags, use default style */
1778   if (tags == NULL || tag_count == 0)
1779     {
1780       if (tags)
1781         g_free (tags);
1782
1783       return FALSE;
1784     }
1785
1786   /* Sort tags in ascending order of priority */
1787   _gtk_text_tag_array_sort (tags, tag_count);
1788
1789   _gtk_text_attributes_fill_from_tags (values,
1790                                        tags,
1791                                        tag_count);
1792
1793   g_free (tags);
1794
1795   return TRUE;
1796 }
1797
1798 /*
1799  * Increments/decrements
1800  */
1801
1802 /* The return value of this indicates WHETHER WE MOVED.
1803  * The return value of public functions indicates
1804  * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1805  *
1806  * This function will not change the iterator if
1807  * it's already on the last (end iter) line, i.e. it
1808  * won't move to the end of the last line.
1809  */
1810 static gboolean
1811 forward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1812 {
1813   if (!_gtk_text_line_contains_end_iter (real->line, real->tree))
1814     {
1815       GtkTextLine *new_line;
1816       
1817       new_line = _gtk_text_line_next (real->line);
1818       g_assert (new_line);
1819       g_assert (new_line != real->line);
1820       g_assert (!_gtk_text_line_is_last (new_line, real->tree));
1821       
1822       real->line = new_line;
1823
1824       real->line_byte_offset = 0;
1825       real->line_char_offset = 0;
1826
1827       real->segment_byte_offset = 0;
1828       real->segment_char_offset = 0;
1829
1830       /* Find first segments in new line */
1831       real->any_segment = real->line->segments;
1832       real->segment = real->any_segment;
1833       while (real->segment->char_count == 0)
1834         real->segment = real->segment->next;
1835
1836       return TRUE;
1837     }
1838   else
1839     {
1840       /* There is no way to move forward a line; we were already at
1841        * the line containing the end iterator.
1842        * However we may not be at the end iterator itself.
1843        */
1844       
1845       return FALSE;
1846     }
1847 }
1848
1849 #if 0
1850 /* The return value of this indicates WHETHER WE MOVED.
1851  * The return value of public functions indicates
1852  * (MOVEMENT OCCURRED && NEW ITER IS DEREFERENCEABLE)
1853  *
1854  * This function is currently unused, thus it is #if-0-ed. It is
1855  * left here, since it's non-trivial code that might be useful in
1856  * the future.
1857  */
1858 static gboolean
1859 backward_line_leaving_caches_unmodified (GtkTextRealIter *real)
1860 {
1861   GtkTextLine *new_line;
1862
1863   new_line = _gtk_text_line_previous (real->line);
1864
1865   g_assert (new_line != real->line);
1866
1867   if (new_line != NULL)
1868     {
1869       real->line = new_line;
1870
1871       real->line_byte_offset = 0;
1872       real->line_char_offset = 0;
1873
1874       real->segment_byte_offset = 0;
1875       real->segment_char_offset = 0;
1876
1877       /* Find first segments in new line */
1878       real->any_segment = real->line->segments;
1879       real->segment = real->any_segment;
1880       while (real->segment->char_count == 0)
1881         real->segment = real->segment->next;
1882
1883       return TRUE;
1884     }
1885   else
1886     {
1887       /* There is no way to move backward; we were already
1888          at the first line. */
1889
1890       /* We leave real->line as-is */
1891
1892       /* Note that we didn't clamp to the start of the first line. */
1893
1894       return FALSE;
1895     }
1896 }
1897 #endif 
1898
1899 /* The return value indicates (MOVEMENT OCCURRED && NEW ITER IS
1900  * DEREFERENCEABLE)
1901  */
1902 static gboolean
1903 forward_char (GtkTextRealIter *real)
1904 {
1905   GtkTextIter *iter = (GtkTextIter*)real;
1906
1907   check_invariants ((GtkTextIter*)real);
1908
1909   ensure_char_offsets (real);
1910
1911   if ( (real->segment_char_offset + 1) == real->segment->char_count)
1912     {
1913       /* Need to move to the next segment; if no next segment,
1914          need to move to next line. */
1915       return _gtk_text_iter_forward_indexable_segment (iter);
1916     }
1917   else
1918     {
1919       /* Just moving within a segment. Keep byte count
1920          up-to-date, if it was already up-to-date. */
1921
1922       g_assert (real->segment->type == &gtk_text_char_type);
1923
1924       if (real->line_byte_offset >= 0)
1925         {
1926           gint bytes;
1927           const char * start =
1928             real->segment->body.chars + real->segment_byte_offset;
1929
1930           bytes = g_utf8_next_char (start) - start;
1931
1932           real->line_byte_offset += bytes;
1933           real->segment_byte_offset += bytes;
1934
1935           g_assert (real->segment_byte_offset < real->segment->byte_count);
1936         }
1937
1938       real->line_char_offset += 1;
1939       real->segment_char_offset += 1;
1940
1941       adjust_char_index (real, 1);
1942
1943       g_assert (real->segment_char_offset < real->segment->char_count);
1944
1945       /* We moved into the middle of a segment, so the any_segment
1946          must now be the segment we're in the middle of. */
1947       real->any_segment = real->segment;
1948
1949       check_invariants ((GtkTextIter*)real);
1950
1951       if (gtk_text_iter_is_end ((GtkTextIter*)real))
1952         return FALSE;
1953       else
1954         return TRUE;
1955     }
1956 }
1957
1958 gboolean
1959 _gtk_text_iter_forward_indexable_segment (GtkTextIter *iter)
1960 {
1961   /* Need to move to the next segment; if no next segment,
1962      need to move to next line. */
1963   GtkTextLineSegment *seg;
1964   GtkTextLineSegment *any_seg;
1965   GtkTextRealIter *real;
1966   gint chars_skipped;
1967   gint bytes_skipped;
1968
1969   g_return_val_if_fail (iter != NULL, FALSE);
1970
1971   real = gtk_text_iter_make_real (iter);
1972
1973   if (real == NULL)
1974     return FALSE;
1975
1976   check_invariants (iter);
1977
1978   if (real->line_char_offset >= 0)
1979     {
1980       chars_skipped = real->segment->char_count - real->segment_char_offset;
1981       g_assert (chars_skipped > 0);
1982     }
1983   else
1984     chars_skipped = 0;
1985
1986   if (real->line_byte_offset >= 0)
1987     {
1988       bytes_skipped = real->segment->byte_count - real->segment_byte_offset;
1989       g_assert (bytes_skipped > 0);
1990     }
1991   else
1992     bytes_skipped = 0;
1993
1994   /* Get first segment of any kind */
1995   any_seg = real->segment->next;
1996   /* skip non-indexable segments, if any */
1997   seg = any_seg;
1998   while (seg != NULL && seg->char_count == 0)
1999     seg = seg->next;
2000
2001   if (seg != NULL)
2002     {
2003       real->any_segment = any_seg;
2004       real->segment = seg;
2005
2006       if (real->line_byte_offset >= 0)
2007         {
2008           g_assert (bytes_skipped > 0);
2009           real->segment_byte_offset = 0;
2010           real->line_byte_offset += bytes_skipped;
2011         }
2012
2013       if (real->line_char_offset >= 0)
2014         {
2015           g_assert (chars_skipped > 0);
2016           real->segment_char_offset = 0;
2017           real->line_char_offset += chars_skipped;
2018           adjust_char_index (real, chars_skipped);
2019         }
2020
2021       check_invariants (iter);
2022
2023       return !gtk_text_iter_is_end (iter);
2024     }
2025   else
2026     {
2027       /* End of the line */
2028       if (forward_line_leaving_caches_unmodified (real))
2029         {
2030           adjust_line_number (real, 1);
2031           if (real->line_char_offset >= 0)
2032             adjust_char_index (real, chars_skipped);
2033
2034           g_assert (real->line_byte_offset == 0);
2035           g_assert (real->line_char_offset == 0);
2036           g_assert (real->segment_byte_offset == 0);
2037           g_assert (real->segment_char_offset == 0);
2038           g_assert (gtk_text_iter_starts_line (iter));
2039
2040           check_invariants (iter);
2041
2042           return !gtk_text_iter_is_end (iter);
2043         }
2044       else
2045         {
2046           /* End of buffer, but iter is still at start of last segment,
2047            * not at the end iterator. We put it on the end iterator.
2048            */
2049           
2050           check_invariants (iter);
2051
2052           g_assert (!_gtk_text_line_is_last (real->line, real->tree));
2053           g_assert (_gtk_text_line_contains_end_iter (real->line, real->tree));
2054
2055           gtk_text_iter_forward_to_line_end (iter);
2056
2057           g_assert (gtk_text_iter_is_end (iter));
2058           
2059           return FALSE;
2060         }
2061     }
2062 }
2063
2064 static gboolean
2065 at_last_indexable_segment (GtkTextRealIter *real)
2066 {
2067   GtkTextLineSegment *seg;
2068
2069   /* Return TRUE if there are no indexable segments after
2070    * this iterator.
2071    */
2072
2073   seg = real->segment->next;
2074   while (seg)
2075     {
2076       if (seg->char_count > 0)
2077         return FALSE;
2078       seg = seg->next;
2079     }
2080   return TRUE;
2081 }
2082
2083 /* Goes back to the start of the next segment, even if
2084  * we're not at the start of the current segment (always
2085  * ends up on a different segment if it returns TRUE)
2086  */
2087 gboolean
2088 _gtk_text_iter_backward_indexable_segment (GtkTextIter *iter)
2089 {
2090   /* Move to the start of the previous segment; if no previous
2091    * segment, to the last segment in the previous line. This is
2092    * inherently a bit inefficient due to the singly-linked list and
2093    * tree nodes, but we can't afford the RAM for doubly-linked.
2094    */
2095   GtkTextRealIter *real;
2096   GtkTextLineSegment *seg;
2097   GtkTextLineSegment *any_seg;
2098   GtkTextLineSegment *prev_seg;
2099   GtkTextLineSegment *prev_any_seg;
2100   gint bytes_skipped;
2101   gint chars_skipped;
2102
2103   g_return_val_if_fail (iter != NULL, FALSE);
2104
2105   real = gtk_text_iter_make_real (iter);
2106
2107   if (real == NULL)
2108     return FALSE;
2109
2110   check_invariants (iter);
2111
2112   /* Find first segments in line */
2113   any_seg = real->line->segments;
2114   seg = any_seg;
2115   while (seg->char_count == 0)
2116     seg = seg->next;
2117
2118   if (seg == real->segment)
2119     {
2120       /* Could probably do this case faster by hand-coding the
2121        * iteration.
2122        */
2123
2124       /* We were already at the start of a line;
2125        * go back to the previous line.
2126        */
2127       if (gtk_text_iter_backward_line (iter))
2128         {
2129           /* Go forward to last indexable segment in line. */
2130           while (!at_last_indexable_segment (real))
2131             _gtk_text_iter_forward_indexable_segment (iter);
2132
2133           check_invariants (iter);
2134
2135           return TRUE;
2136         }
2137       else
2138         return FALSE; /* We were at the start of the first line. */
2139     }
2140
2141   /* We must be in the middle of a line; so find the indexable
2142    * segment just before our current segment.
2143    */
2144   g_assert (seg != real->segment);
2145   do
2146     {
2147       prev_seg = seg;
2148       prev_any_seg = any_seg;
2149
2150       any_seg = seg->next;
2151       seg = any_seg;
2152       while (seg->char_count == 0)
2153         seg = seg->next;
2154     }
2155   while (seg != real->segment);
2156
2157   g_assert (prev_seg != NULL);
2158   g_assert (prev_any_seg != NULL);
2159   g_assert (prev_seg->char_count > 0);
2160
2161   /* We skipped the entire previous segment, plus any
2162    * chars we were into the current segment.
2163    */
2164   if (real->segment_byte_offset >= 0)
2165     bytes_skipped = prev_seg->byte_count + real->segment_byte_offset;
2166   else
2167     bytes_skipped = -1;
2168
2169   if (real->segment_char_offset >= 0)
2170     chars_skipped = prev_seg->char_count + real->segment_char_offset;
2171   else
2172     chars_skipped = -1;
2173
2174   real->segment = prev_seg;
2175   real->any_segment = prev_any_seg;
2176   real->segment_byte_offset = 0;
2177   real->segment_char_offset = 0;
2178
2179   if (bytes_skipped >= 0)
2180     {
2181       if (real->line_byte_offset >= 0)
2182         {
2183           real->line_byte_offset -= bytes_skipped;
2184           g_assert (real->line_byte_offset >= 0);
2185         }
2186     }
2187   else
2188     real->line_byte_offset = -1;
2189
2190   if (chars_skipped >= 0)
2191     {
2192       if (real->line_char_offset >= 0)
2193         {
2194           real->line_char_offset -= chars_skipped;
2195           g_assert (real->line_char_offset >= 0);
2196         }
2197
2198       if (real->cached_char_index >= 0)
2199         {
2200           real->cached_char_index -= chars_skipped;
2201           g_assert (real->cached_char_index >= 0);
2202         }
2203     }
2204   else
2205     {
2206       real->line_char_offset = -1;
2207       real->cached_char_index = -1;
2208     }
2209
2210   /* line number is unchanged. */
2211
2212   check_invariants (iter);
2213
2214   return TRUE;
2215 }
2216
2217 /**
2218  * gtk_text_iter_forward_char:
2219  * @iter: an iterator
2220  *
2221  * Moves @iter forward by one character offset. Note that images
2222  * embedded in the buffer occupy 1 character slot, so
2223  * gtk_text_iter_forward_char () may actually move onto an image instead
2224  * of a character, if you have images in your buffer.  If @iter is the
2225  * end iterator or one character before it, @iter will now point at
2226  * the end iterator, and gtk_text_iter_forward_char () returns %FALSE for
2227  * convenience when writing loops.
2228  *
2229  * Return value: whether @iter moved and is dereferenceable
2230  **/
2231 gboolean
2232 gtk_text_iter_forward_char (GtkTextIter *iter)
2233 {
2234   GtkTextRealIter *real;
2235
2236   g_return_val_if_fail (iter != NULL, FALSE);
2237
2238   real = gtk_text_iter_make_real (iter);
2239
2240   if (real == NULL)
2241     return FALSE;
2242   else
2243     {
2244       check_invariants (iter);
2245       return forward_char (real);
2246     }
2247 }
2248
2249 /**
2250  * gtk_text_iter_backward_char:
2251  * @iter: an iterator
2252  *
2253  * Moves backward by one character offset. Returns %TRUE if movement
2254  * was possible; if @iter was the first in the buffer (character
2255  * offset 0), gtk_text_iter_backward_char () returns %FALSE for convenience when
2256  * writing loops.
2257  *
2258  * Return value: whether movement was possible
2259  **/
2260 gboolean
2261 gtk_text_iter_backward_char (GtkTextIter *iter)
2262 {
2263   g_return_val_if_fail (iter != NULL, FALSE);
2264
2265   check_invariants (iter);
2266
2267   return gtk_text_iter_backward_chars (iter, 1);
2268 }
2269
2270 /*
2271   Definitely we should try to linear scan as often as possible for
2272   movement within a single line, because we can't use the BTree to
2273   speed within-line searches up; for movement between lines, we would
2274   like to avoid the linear scan probably.
2275
2276   Instead of using this constant, it might be nice to cache the line
2277   length in the iterator and linear scan if motion is within a single
2278   line.
2279
2280   I guess you'd have to profile the various approaches.
2281 */
2282 #define MAX_LINEAR_SCAN 150
2283
2284
2285 /**
2286  * gtk_text_iter_forward_chars:
2287  * @iter: an iterator
2288  * @count: number of characters to move, may be negative
2289  *
2290  * Moves @count characters if possible (if @count would move past the
2291  * start or end of the buffer, moves to the start or end of the
2292  * buffer). The return value indicates whether the new position of
2293  * @iter is different from its original position, and dereferenceable
2294  * (the last iterator in the buffer is not dereferenceable). If @count
2295  * is 0, the function does nothing and returns %FALSE.
2296  *
2297  * Return value: whether @iter moved and is dereferenceable
2298  **/
2299 gboolean
2300 gtk_text_iter_forward_chars (GtkTextIter *iter, gint count)
2301 {
2302   GtkTextRealIter *real;
2303
2304   g_return_val_if_fail (iter != NULL, FALSE);
2305
2306   FIX_OVERFLOWS (count);
2307   
2308   real = gtk_text_iter_make_real (iter);
2309
2310   if (real == NULL)
2311     return FALSE;
2312   else if (count == 0)
2313     return FALSE;
2314   else if (count < 0)
2315     return gtk_text_iter_backward_chars (iter, 0 - count);
2316   else if (count < MAX_LINEAR_SCAN)
2317     {
2318       check_invariants (iter);
2319
2320       while (count > 1)
2321         {
2322           if (!forward_char (real))
2323             return FALSE;
2324           --count;
2325         }
2326
2327       return forward_char (real);
2328     }
2329   else
2330     {
2331       gint current_char_index;
2332       gint new_char_index;
2333
2334       check_invariants (iter);
2335
2336       current_char_index = gtk_text_iter_get_offset (iter);
2337
2338       if (current_char_index == _gtk_text_btree_char_count (real->tree))
2339         return FALSE; /* can't move forward */
2340
2341       new_char_index = current_char_index + count;
2342       gtk_text_iter_set_offset (iter, new_char_index);
2343
2344       check_invariants (iter);
2345
2346       /* Return FALSE if we're on the non-dereferenceable end
2347        * iterator.
2348        */
2349       if (gtk_text_iter_is_end (iter))
2350         return FALSE;
2351       else
2352         return TRUE;
2353     }
2354 }
2355
2356 /**
2357  * gtk_text_iter_backward_chars:
2358  * @iter: an iterator
2359  * @count: number of characters to move
2360  *
2361  * Moves @count characters backward, if possible (if @count would move
2362  * past the start or end of the buffer, moves to the start or end of
2363  * the buffer).  The return value indicates whether the iterator moved
2364  * onto a dereferenceable position; if the iterator didn't move, or
2365  * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2366  * the function does nothing and returns %FALSE.
2367  *
2368  * Return value: whether @iter moved and is dereferenceable
2369  *
2370  **/
2371 gboolean
2372 gtk_text_iter_backward_chars (GtkTextIter *iter, gint count)
2373 {
2374   GtkTextRealIter *real;
2375
2376   g_return_val_if_fail (iter != NULL, FALSE);
2377
2378   FIX_OVERFLOWS (count);
2379   
2380   real = gtk_text_iter_make_real (iter);
2381
2382   if (real == NULL)
2383     return FALSE;
2384   else if (count == 0)
2385     return FALSE;
2386   else if (count < 0)
2387     return gtk_text_iter_forward_chars (iter, 0 - count);
2388
2389   ensure_char_offsets (real);
2390   check_invariants (iter);
2391
2392   /* <, not <=, because if count == segment_char_offset
2393    * we're going to the front of the segment and the any_segment
2394    * might change
2395    */
2396   if (count < real->segment_char_offset)
2397     {
2398       /* Optimize the within-segment case */
2399       g_assert (real->segment->char_count > 0);
2400       g_assert (real->segment->type == &gtk_text_char_type);
2401
2402       if (real->line_byte_offset >= 0)
2403         {
2404           const char *p;
2405           gint new_byte_offset;
2406
2407           /* if in the last fourth of the segment walk backwards */
2408           if (count < real->segment_char_offset / 4)
2409             p = g_utf8_offset_to_pointer (real->segment->body.chars + real->segment_byte_offset, 
2410                                           -count);
2411           else
2412             p = g_utf8_offset_to_pointer (real->segment->body.chars,
2413                                           real->segment_char_offset - count);
2414
2415           new_byte_offset = p - real->segment->body.chars;
2416           real->line_byte_offset -= (real->segment_byte_offset - new_byte_offset);
2417           real->segment_byte_offset = new_byte_offset;
2418         }
2419
2420       real->segment_char_offset -= count;
2421       real->line_char_offset -= count;
2422
2423       adjust_char_index (real, 0 - count);
2424
2425       check_invariants (iter);
2426
2427       return TRUE;
2428     }
2429   else
2430     {
2431       /* We need to go back into previous segments. For now,
2432        * just keep this really simple. FIXME
2433        * use backward_indexable_segment.
2434        */
2435       if (TRUE || count > MAX_LINEAR_SCAN)
2436         {
2437           gint current_char_index;
2438           gint new_char_index;
2439
2440           current_char_index = gtk_text_iter_get_offset (iter);
2441
2442           if (current_char_index == 0)
2443             return FALSE; /* can't move backward */
2444
2445           new_char_index = current_char_index - count;
2446           if (new_char_index < 0)
2447             new_char_index = 0;
2448
2449           gtk_text_iter_set_offset (iter, new_char_index);
2450
2451           check_invariants (iter);
2452
2453           return TRUE;
2454         }
2455       else
2456         {
2457           /* FIXME backward_indexable_segment here */
2458
2459           return FALSE;
2460         }
2461     }
2462 }
2463
2464 #if 0
2465
2466 /* These two can't be implemented efficiently (always have to use
2467  * a linear scan, since that's the only way to find all the non-text
2468  * segments)
2469  */
2470
2471 /**
2472  * gtk_text_iter_forward_text_chars:
2473  * @iter: a #GtkTextIter
2474  * @count: number of chars to move
2475  *
2476  * Moves forward by @count text characters (pixbufs, widgets,
2477  * etc. do not count as characters for this). Equivalent to moving
2478  * through the results of gtk_text_iter_get_text (), rather than
2479  * gtk_text_iter_get_slice ().
2480  *
2481  * Return value: whether @iter moved and is dereferenceable
2482  **/
2483 gboolean
2484 gtk_text_iter_forward_text_chars  (GtkTextIter *iter,
2485                                    gint         count)
2486 {
2487
2488
2489
2490 }
2491
2492 /**
2493  * gtk_text_iter_forward_text_chars:
2494  * @iter: a #GtkTextIter
2495  * @count: number of chars to move
2496  *
2497  * Moves backward by @count text characters (pixbufs, widgets,
2498  * etc. do not count as characters for this). Equivalent to moving
2499  * through the results of gtk_text_iter_get_text (), rather than
2500  * gtk_text_iter_get_slice ().
2501  *
2502  * Return value: whether @iter moved and is dereferenceable
2503  **/
2504 gboolean
2505 gtk_text_iter_backward_text_chars (GtkTextIter *iter,
2506                                    gint         count)
2507 {
2508
2509
2510 }
2511 #endif
2512
2513 /**
2514  * gtk_text_iter_forward_line:
2515  * @iter: an iterator
2516  *
2517  * Moves @iter to the start of the next line. Returns %TRUE if there
2518  * was a next line to move to, and %FALSE if @iter was simply moved to
2519  * the end of the buffer and is now not dereferenceable, or if @iter was
2520  * already at the end of the buffer.
2521  *
2522  * Return value: whether @iter can be dereferenced
2523  **/
2524 gboolean
2525 gtk_text_iter_forward_line (GtkTextIter *iter)
2526 {
2527   GtkTextRealIter *real;
2528
2529   g_return_val_if_fail (iter != NULL, FALSE);
2530   
2531   real = gtk_text_iter_make_real (iter);
2532
2533   if (real == NULL)
2534     return FALSE;
2535
2536   check_invariants (iter);
2537
2538   if (forward_line_leaving_caches_unmodified (real))
2539     {
2540       invalidate_char_index (real);
2541       adjust_line_number (real, 1);
2542
2543       check_invariants (iter);
2544
2545       if (gtk_text_iter_is_end (iter))
2546         return FALSE;
2547       else
2548         return TRUE;
2549     }
2550   else
2551     {
2552       /* On the last line, move to end of it */
2553       
2554       if (!gtk_text_iter_is_end (iter))
2555         gtk_text_iter_forward_to_end (iter);
2556       
2557       check_invariants (iter);
2558       return FALSE;
2559     }
2560 }
2561
2562 /**
2563  * gtk_text_iter_backward_line:
2564  * @iter: an iterator
2565  *
2566  * Moves @iter to the start of the previous line. Returns %TRUE if
2567  * @iter could be moved; i.e. if @iter was at character offset 0, this
2568  * function returns %FALSE. Therefore if @iter was already on line 0,
2569  * but not at the start of the line, @iter is snapped to the start of
2570  * the line and the function returns %TRUE. (Note that this implies that
2571  * in a loop calling this function, the line number may not change on
2572  * every iteration, if your first iteration is on line 0.)
2573  *
2574  * Return value: whether @iter moved
2575  **/
2576 gboolean
2577 gtk_text_iter_backward_line (GtkTextIter *iter)
2578 {
2579   GtkTextLine *new_line;
2580   GtkTextRealIter *real;
2581   gboolean offset_will_change;
2582   gint offset;
2583
2584   g_return_val_if_fail (iter != NULL, FALSE);
2585
2586   real = gtk_text_iter_make_real (iter);
2587
2588   if (real == NULL)
2589     return FALSE;
2590
2591   check_invariants (iter);
2592
2593   new_line = _gtk_text_line_previous (real->line);
2594
2595   offset_will_change = FALSE;
2596   if (real->line_char_offset > 0)
2597     offset_will_change = TRUE;
2598
2599   if (new_line != NULL)
2600     {
2601       real->line = new_line;
2602
2603       adjust_line_number (real, -1);
2604     }
2605   else
2606     {
2607       if (!offset_will_change)
2608         return FALSE;
2609     }
2610
2611   invalidate_char_index (real);
2612
2613   real->line_byte_offset = 0;
2614   real->line_char_offset = 0;
2615
2616   real->segment_byte_offset = 0;
2617   real->segment_char_offset = 0;
2618
2619   /* Find first segment in line */
2620   real->any_segment = real->line->segments;
2621   real->segment = _gtk_text_line_byte_to_segment (real->line,
2622                                                   0, &offset);
2623
2624   g_assert (offset == 0);
2625
2626   /* Note that if we are on the first line, we snap to the start of
2627    * the first line and return TRUE, so TRUE means the iterator
2628    * changed, not that the line changed; this is maybe a bit
2629    * weird. I'm not sure there's an obvious right thing to do though.
2630    */
2631
2632   check_invariants (iter);
2633
2634   return TRUE;
2635 }
2636
2637
2638 /**
2639  * gtk_text_iter_forward_lines:
2640  * @iter: a #GtkTextIter
2641  * @count: number of lines to move forward
2642  *
2643  * Moves @count lines forward, if possible (if @count would move
2644  * past the start or end of the buffer, moves to the start or end of
2645  * the buffer).  The return value indicates whether the iterator moved
2646  * onto a dereferenceable position; if the iterator didn't move, or
2647  * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2648  * the function does nothing and returns %FALSE. If @count is negative,
2649  * moves backward by 0 - @count lines.
2650  *
2651  * Return value: whether @iter moved and is dereferenceable
2652  **/
2653 gboolean
2654 gtk_text_iter_forward_lines (GtkTextIter *iter, gint count)
2655 {
2656   FIX_OVERFLOWS (count);
2657   
2658   if (count < 0)
2659     return gtk_text_iter_backward_lines (iter, 0 - count);
2660   else if (count == 0)
2661     return FALSE;
2662   else if (count == 1)
2663     {
2664       check_invariants (iter);
2665       return gtk_text_iter_forward_line (iter);
2666     }
2667   else
2668     {
2669       gint old_line;
2670
2671       if (gtk_text_iter_is_end (iter))
2672         return FALSE;
2673       
2674       old_line = gtk_text_iter_get_line (iter);
2675
2676       gtk_text_iter_set_line (iter, old_line + count);
2677
2678       if ((gtk_text_iter_get_line (iter) - old_line) < count)
2679         {
2680           /* count went past the last line, so move to end of last line */
2681           if (!gtk_text_iter_is_end (iter))
2682             gtk_text_iter_forward_to_end (iter);
2683         }
2684       
2685       return !gtk_text_iter_is_end (iter);
2686     }
2687 }
2688
2689 /**
2690  * gtk_text_iter_backward_lines:
2691  * @iter: a #GtkTextIter
2692  * @count: number of lines to move backward
2693  *
2694  * Moves @count lines backward, if possible (if @count would move
2695  * past the start or end of the buffer, moves to the start or end of
2696  * the buffer).  The return value indicates whether the iterator moved
2697  * onto a dereferenceable position; if the iterator didn't move, or
2698  * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2699  * the function does nothing and returns %FALSE. If @count is negative,
2700  * moves forward by 0 - @count lines.
2701  *
2702  * Return value: whether @iter moved and is dereferenceable
2703  **/
2704 gboolean
2705 gtk_text_iter_backward_lines (GtkTextIter *iter, gint count)
2706 {
2707   FIX_OVERFLOWS (count);
2708   
2709   if (count < 0)
2710     return gtk_text_iter_forward_lines (iter, 0 - count);
2711   else if (count == 0)
2712     return FALSE;
2713   else if (count == 1)
2714     {
2715       return gtk_text_iter_backward_line (iter);
2716     }
2717   else
2718     {
2719       gint old_line;
2720
2721       old_line = gtk_text_iter_get_line (iter);
2722
2723       gtk_text_iter_set_line (iter, MAX (old_line - count, 0));
2724
2725       return (gtk_text_iter_get_line (iter) != old_line);
2726     }
2727 }
2728
2729 /**
2730  * gtk_text_iter_forward_visible_line:
2731  * @iter: an iterator
2732  *
2733  * Moves @iter to the start of the next visible line. Returns %TRUE if there
2734  * was a next line to move to, and %FALSE if @iter was simply moved to
2735  * the end of the buffer and is now not dereferenceable, or if @iter was
2736  * already at the end of the buffer.
2737  *
2738  * Return value: whether @iter can be dereferenced
2739  * 
2740  * Since: 2.8
2741  **/
2742 gboolean
2743 gtk_text_iter_forward_visible_line (GtkTextIter *iter)
2744 {
2745   while (gtk_text_iter_forward_line (iter))
2746     {
2747       if (!_gtk_text_btree_char_is_invisible (iter))
2748         return TRUE;
2749       else
2750         {
2751           do
2752             {
2753               if (!gtk_text_iter_forward_char (iter))
2754                 return FALSE;
2755           
2756               if (!_gtk_text_btree_char_is_invisible (iter))
2757                 return TRUE;
2758             }
2759           while (!gtk_text_iter_ends_line (iter));
2760         }
2761     }
2762     
2763   return FALSE;
2764 }
2765
2766 /**
2767  * gtk_text_iter_backward_visible_line:
2768  * @iter: an iterator
2769  *
2770  * Moves @iter to the start of the previous visible line. Returns %TRUE if
2771  * @iter could be moved; i.e. if @iter was at character offset 0, this
2772  * function returns %FALSE. Therefore if @iter was already on line 0,
2773  * but not at the start of the line, @iter is snapped to the start of
2774  * the line and the function returns %TRUE. (Note that this implies that
2775  * in a loop calling this function, the line number may not change on
2776  * every iteration, if your first iteration is on line 0.)
2777  *
2778  * Return value: whether @iter moved
2779  *
2780  * Since: 2.8
2781  **/
2782 gboolean
2783 gtk_text_iter_backward_visible_line (GtkTextIter *iter)
2784 {
2785   while (gtk_text_iter_backward_line (iter))
2786     {
2787       if (!_gtk_text_btree_char_is_invisible (iter))
2788         return TRUE;
2789       else
2790         {
2791           do
2792             {
2793               if (!gtk_text_iter_backward_char (iter))
2794                 return FALSE;
2795           
2796               if (!_gtk_text_btree_char_is_invisible (iter))
2797                 return TRUE;
2798             }
2799           while (!gtk_text_iter_starts_line (iter));
2800         }
2801     }
2802     
2803   return FALSE;
2804 }
2805
2806 /**
2807  * gtk_text_iter_forward_visible_lines:
2808  * @iter: a #GtkTextIter
2809  * @count: number of lines to move forward
2810  *
2811  * Moves @count visible lines forward, if possible (if @count would move
2812  * past the start or end of the buffer, moves to the start or end of
2813  * the buffer).  The return value indicates whether the iterator moved
2814  * onto a dereferenceable position; if the iterator didn't move, or
2815  * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2816  * the function does nothing and returns %FALSE. If @count is negative,
2817  * moves backward by 0 - @count lines.
2818  *
2819  * Return value: whether @iter moved and is dereferenceable
2820  * 
2821  * Since: 2.8
2822  **/
2823 gboolean
2824 gtk_text_iter_forward_visible_lines (GtkTextIter *iter,
2825                                      gint         count)
2826 {
2827   FIX_OVERFLOWS (count);
2828   
2829   if (count < 0)
2830     return gtk_text_iter_backward_visible_lines (iter, 0 - count);
2831   else if (count == 0)
2832     return FALSE;
2833   else if (count == 1)
2834     {
2835       check_invariants (iter);
2836       return gtk_text_iter_forward_visible_line (iter);
2837     }
2838   else
2839     {
2840       while (gtk_text_iter_forward_visible_line (iter) && count > 0)
2841         count--;
2842       return count == 0;
2843     }    
2844 }
2845
2846 /**
2847  * gtk_text_iter_backward_visible_lines:
2848  * @iter: a #GtkTextIter
2849  * @count: number of lines to move backward
2850  *
2851  * Moves @count visible lines backward, if possible (if @count would move
2852  * past the start or end of the buffer, moves to the start or end of
2853  * the buffer).  The return value indicates whether the iterator moved
2854  * onto a dereferenceable position; if the iterator didn't move, or
2855  * moved onto the end iterator, then %FALSE is returned. If @count is 0,
2856  * the function does nothing and returns %FALSE. If @count is negative,
2857  * moves forward by 0 - @count lines.
2858  *
2859  * Return value: whether @iter moved and is dereferenceable
2860  *
2861  * Since: 2.8
2862  **/
2863 gboolean
2864 gtk_text_iter_backward_visible_lines (GtkTextIter *iter,
2865                                       gint         count)
2866 {
2867   FIX_OVERFLOWS (count);
2868   
2869   if (count < 0)
2870     return gtk_text_iter_forward_visible_lines (iter, 0 - count);
2871   else if (count == 0)
2872     return FALSE;
2873   else if (count == 1)
2874     {
2875       return gtk_text_iter_backward_visible_line (iter);
2876     }
2877   else
2878     {
2879       while (gtk_text_iter_backward_visible_line (iter) && count > 0)
2880         count--;
2881       return count == 0;
2882     }
2883 }
2884
2885 typedef gboolean (* FindLogAttrFunc) (const PangoLogAttr *attrs,
2886                                       gint                offset,
2887                                       gint                min_offset,
2888                                       gint                len,
2889                                       gint               *found_offset,
2890                                       gboolean            already_moved_initially);
2891
2892 typedef gboolean (* TestLogAttrFunc) (const PangoLogAttr *attrs,
2893                                       gint                offset,
2894                                       gint                min_offset,
2895                                       gint                len);
2896
2897 /* Word funcs */
2898
2899 static gboolean
2900 find_word_end_func (const PangoLogAttr *attrs,
2901                     gint          offset,
2902                     gint          min_offset,
2903                     gint          len,
2904                     gint         *found_offset,
2905                     gboolean      already_moved_initially)
2906 {
2907   if (!already_moved_initially)
2908     ++offset;
2909
2910   /* Find end of next word */
2911   while (offset < min_offset + len &&
2912          !attrs[offset].is_word_end)
2913     ++offset;
2914
2915   *found_offset = offset;
2916
2917   return offset < min_offset + len;
2918 }
2919
2920 static gboolean
2921 is_word_end_func (const PangoLogAttr *attrs,
2922                   gint          offset,
2923                   gint          min_offset,
2924                   gint          len)
2925 {
2926   return attrs[offset].is_word_end;
2927 }
2928
2929 static gboolean
2930 find_word_start_func (const PangoLogAttr *attrs,
2931                       gint          offset,
2932                       gint          min_offset,
2933                       gint          len,
2934                       gint         *found_offset,
2935                       gboolean      already_moved_initially)
2936 {
2937   if (!already_moved_initially)
2938     --offset;
2939
2940   /* Find start of prev word */
2941   while (offset >= min_offset &&
2942          !attrs[offset].is_word_start)
2943     --offset;
2944
2945   *found_offset = offset;
2946
2947   return offset >= min_offset;
2948 }
2949
2950 static gboolean
2951 is_word_start_func (const PangoLogAttr *attrs,
2952                     gint          offset,
2953                     gint          min_offset,
2954                     gint          len)
2955 {
2956   return attrs[offset].is_word_start;
2957 }
2958
2959 static gboolean
2960 inside_word_func (const PangoLogAttr *attrs,
2961                   gint          offset,
2962                   gint          min_offset,
2963                   gint          len)
2964 {
2965   /* Find next word start or end */
2966   while (offset >= min_offset &&
2967          !(attrs[offset].is_word_start || attrs[offset].is_word_end))
2968     --offset;
2969
2970   if (offset >= 0)
2971     return attrs[offset].is_word_start;
2972   else
2973     return FALSE;
2974 }
2975
2976 /* Sentence funcs */
2977
2978 static gboolean
2979 find_sentence_end_func (const PangoLogAttr *attrs,
2980                         gint          offset,
2981                         gint          min_offset,
2982                         gint          len,
2983                         gint         *found_offset,
2984                         gboolean      already_moved_initially)
2985 {
2986   if (!already_moved_initially)
2987     ++offset;
2988
2989   /* Find end of next sentence */
2990   while (offset < min_offset + len &&
2991          !attrs[offset].is_sentence_end)
2992     ++offset;
2993
2994   *found_offset = offset;
2995
2996   return offset < min_offset + len;
2997 }
2998
2999 static gboolean
3000 is_sentence_end_func (const PangoLogAttr *attrs,
3001                       gint          offset,
3002                       gint          min_offset,
3003                       gint          len)
3004 {
3005   return attrs[offset].is_sentence_end;
3006 }
3007
3008 static gboolean
3009 find_sentence_start_func (const PangoLogAttr *attrs,
3010                           gint          offset,
3011                           gint          min_offset,
3012                           gint          len,
3013                           gint         *found_offset,
3014                           gboolean      already_moved_initially)
3015 {
3016   if (!already_moved_initially)
3017     --offset;
3018
3019   /* Find start of prev sentence */
3020   while (offset >= min_offset &&
3021          !attrs[offset].is_sentence_start)
3022     --offset;
3023
3024   *found_offset = offset;
3025
3026   return offset >= min_offset;
3027 }
3028
3029 static gboolean
3030 is_sentence_start_func (const PangoLogAttr *attrs,
3031                         gint          offset,
3032                         gint          min_offset,
3033                         gint          len)
3034 {
3035   return attrs[offset].is_sentence_start;
3036 }
3037
3038 static gboolean
3039 inside_sentence_func (const PangoLogAttr *attrs,
3040                       gint          offset,
3041                       gint          min_offset,
3042                       gint          len)
3043 {
3044   /* Find next sentence start or end */
3045   while (offset >= min_offset &&
3046          !(attrs[offset].is_sentence_start || attrs[offset].is_sentence_end))
3047     --offset;
3048
3049   return attrs[offset].is_sentence_start;
3050 }
3051
3052 static gboolean
3053 test_log_attrs (const GtkTextIter *iter,
3054                 TestLogAttrFunc    func)
3055 {
3056   gint char_len;
3057   const PangoLogAttr *attrs;
3058   int offset;
3059   gboolean result = FALSE;
3060
3061   g_return_val_if_fail (iter != NULL, FALSE);
3062
3063   attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
3064                                                iter, &char_len);
3065
3066   offset = gtk_text_iter_get_line_offset (iter);
3067
3068   /* char_len may be 0 and attrs will be NULL if so, if
3069    * iter is the end iter and the last line is empty.
3070    * 
3071    * offset may be equal to char_len, since attrs contains an entry
3072    * for one past the end
3073    */
3074   
3075   if (attrs && offset <= char_len)
3076     result = (* func) (attrs, offset, 0, char_len);
3077
3078   return result;
3079 }
3080
3081 static gboolean
3082 find_line_log_attrs (const GtkTextIter *iter,
3083                      FindLogAttrFunc    func,
3084                      gint              *found_offset,
3085                      gboolean           already_moved_initially)
3086 {
3087   gint char_len;
3088   const PangoLogAttr *attrs;
3089   int offset;
3090   gboolean result = FALSE;
3091
3092   g_return_val_if_fail (iter != NULL, FALSE);
3093   
3094   attrs = _gtk_text_buffer_get_line_log_attrs (gtk_text_iter_get_buffer (iter),
3095                                                iter, &char_len);      
3096
3097   offset = gtk_text_iter_get_line_offset (iter);
3098   
3099   /* char_len may be 0 and attrs will be NULL if so, if
3100    * iter is the end iter and the last line is empty
3101    */
3102   
3103   if (attrs)
3104     result = (* func) (attrs, offset, 0, char_len, found_offset,
3105                        already_moved_initially);
3106
3107   return result;
3108 }
3109
3110 /* FIXME this function is very, very gratuitously slow */
3111 static gboolean
3112 find_by_log_attrs (GtkTextIter    *iter,
3113                    FindLogAttrFunc func,
3114                    gboolean        forward,
3115                    gboolean        already_moved_initially)
3116 {
3117   GtkTextIter orig;
3118   gint offset = 0;
3119   gboolean found = FALSE;
3120
3121   g_return_val_if_fail (iter != NULL, FALSE);
3122
3123   orig = *iter;
3124   
3125   found = find_line_log_attrs (iter, func, &offset, already_moved_initially);
3126   
3127   if (!found)
3128     {
3129       if (forward)
3130         {
3131           if (gtk_text_iter_forward_line (iter))
3132             return find_by_log_attrs (iter, func, forward,
3133                                       TRUE);
3134           else
3135             return FALSE;
3136         }
3137       else
3138         {                    
3139           /* go to end of previous line. need to check that
3140            * line is > 0 because backward_line snaps to start of
3141            * line 0 if it's on line 0
3142            */
3143           if (gtk_text_iter_get_line (iter) > 0 && 
3144               gtk_text_iter_backward_line (iter))
3145             {
3146               if (!gtk_text_iter_ends_line (iter))
3147                 gtk_text_iter_forward_to_line_end (iter);
3148               
3149               return find_by_log_attrs (iter, func, forward,
3150                                         TRUE);
3151             }
3152           else
3153             return FALSE;
3154         }
3155     }
3156   else
3157     {      
3158       gtk_text_iter_set_line_offset (iter, offset);
3159
3160       return
3161         (already_moved_initially || !gtk_text_iter_equal (iter, &orig)) &&
3162         !gtk_text_iter_is_end (iter);
3163     }
3164 }
3165
3166 static gboolean 
3167 find_visible_by_log_attrs (GtkTextIter    *iter,
3168                            FindLogAttrFunc func,
3169                            gboolean        forward,
3170                            gboolean        already_moved_initially)
3171 {
3172   GtkTextIter pos;
3173
3174   g_return_val_if_fail (iter != NULL, FALSE);
3175   
3176   pos = *iter;
3177   
3178   while (find_by_log_attrs (&pos, func, forward, already_moved_initially)) 
3179     {
3180       if (!_gtk_text_btree_char_is_invisible (&pos)) 
3181         {
3182           *iter = pos;
3183           return TRUE;
3184         }
3185   }
3186
3187   return FALSE;
3188 }
3189
3190 typedef gboolean (* OneStepFunc) (GtkTextIter *iter);
3191 typedef gboolean (* MultipleStepFunc) (GtkTextIter *iter, gint count);
3192                                   
3193 static gboolean 
3194 move_multiple_steps (GtkTextIter *iter, 
3195                      gint count,
3196                      OneStepFunc step_forward,
3197                      MultipleStepFunc n_steps_backward)
3198 {
3199   g_return_val_if_fail (iter != NULL, FALSE);
3200
3201   FIX_OVERFLOWS (count);
3202   
3203   if (count == 0)
3204     return FALSE;
3205   
3206   if (count < 0)
3207     return n_steps_backward (iter, -count);
3208   
3209   if (!step_forward (iter))
3210     return FALSE;
3211   --count;
3212
3213   while (count > 0)
3214     {
3215       if (!step_forward (iter))
3216         break;
3217       --count;
3218     }
3219   
3220   return !gtk_text_iter_is_end (iter);  
3221 }
3222                
3223
3224 /**
3225  * gtk_text_iter_forward_word_end:
3226  * @iter: a #GtkTextIter
3227  * 
3228  * Moves forward to the next word end. (If @iter is currently on a
3229  * word end, moves forward to the next one after that.) Word breaks
3230  * are determined by Pango and should be correct for nearly any
3231  * language (if not, the correct fix would be to the Pango word break
3232  * algorithms).
3233  * 
3234  * Return value: %TRUE if @iter moved and is not the end iterator 
3235  **/
3236 gboolean
3237 gtk_text_iter_forward_word_end (GtkTextIter *iter)
3238 {
3239   return find_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3240 }
3241
3242 /**
3243  * gtk_text_iter_backward_word_start:
3244  * @iter: a #GtkTextIter
3245  * 
3246  * Moves backward to the previous word start. (If @iter is currently on a
3247  * word start, moves backward to the next one after that.) Word breaks
3248  * are determined by Pango and should be correct for nearly any
3249  * language (if not, the correct fix would be to the Pango word break
3250  * algorithms).
3251  * 
3252  * Return value: %TRUE if @iter moved and is not the end iterator 
3253  **/
3254 gboolean
3255 gtk_text_iter_backward_word_start (GtkTextIter      *iter)
3256 {
3257   return find_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3258 }
3259
3260 /* FIXME a loop around a truly slow function means
3261  * a truly spectacularly slow function.
3262  */
3263
3264 /**
3265  * gtk_text_iter_forward_word_ends:
3266  * @iter: a #GtkTextIter
3267  * @count: number of times to move
3268  * 
3269  * Calls gtk_text_iter_forward_word_end() up to @count times.
3270  *
3271  * Return value: %TRUE if @iter moved and is not the end iterator 
3272  **/
3273 gboolean
3274 gtk_text_iter_forward_word_ends (GtkTextIter      *iter,
3275                                  gint              count)
3276 {
3277   return move_multiple_steps (iter, count, 
3278                               gtk_text_iter_forward_word_end,
3279                               gtk_text_iter_backward_word_starts);
3280 }
3281
3282 /**
3283  * gtk_text_iter_backward_word_starts
3284  * @iter: a #GtkTextIter
3285  * @count: number of times to move
3286  * 
3287  * Calls gtk_text_iter_backward_word_start() up to @count times.
3288  *
3289  * Return value: %TRUE if @iter moved and is not the end iterator 
3290  **/
3291 gboolean
3292 gtk_text_iter_backward_word_starts (GtkTextIter      *iter,
3293                                     gint               count)
3294 {
3295   return move_multiple_steps (iter, count, 
3296                               gtk_text_iter_backward_word_start,
3297                               gtk_text_iter_forward_word_ends);
3298 }
3299
3300 /**
3301  * gtk_text_iter_forward_visible_word_end:
3302  * @iter: a #GtkTextIter
3303  * 
3304  * Moves forward to the next visible word end. (If @iter is currently on a
3305  * word end, moves forward to the next one after that.) Word breaks
3306  * are determined by Pango and should be correct for nearly any
3307  * language (if not, the correct fix would be to the Pango word break
3308  * algorithms).
3309  * 
3310  * Return value: %TRUE if @iter moved and is not the end iterator 
3311  *
3312  * Since: 2.4
3313  **/
3314 gboolean
3315 gtk_text_iter_forward_visible_word_end (GtkTextIter *iter)
3316 {
3317   return find_visible_by_log_attrs (iter, find_word_end_func, TRUE, FALSE);
3318 }
3319
3320 /**
3321  * gtk_text_iter_backward_visible_word_start:
3322  * @iter: a #GtkTextIter
3323  * 
3324  * Moves backward to the previous visible word start. (If @iter is currently 
3325  * on a word start, moves backward to the next one after that.) Word breaks
3326  * are determined by Pango and should be correct for nearly any
3327  * language (if not, the correct fix would be to the Pango word break
3328  * algorithms).
3329  * 
3330  * Return value: %TRUE if @iter moved and is not the end iterator 
3331  * 
3332  * Since: 2.4
3333  **/
3334 gboolean
3335 gtk_text_iter_backward_visible_word_start (GtkTextIter      *iter)
3336 {
3337   return find_visible_by_log_attrs (iter, find_word_start_func, FALSE, FALSE);
3338 }
3339
3340 /**
3341  * gtk_text_iter_forward_visible_word_ends:
3342  * @iter: a #GtkTextIter
3343  * @count: number of times to move
3344  * 
3345  * Calls gtk_text_iter_forward_visible_word_end() up to @count times.
3346  *
3347  * Return value: %TRUE if @iter moved and is not the end iterator 
3348  *
3349  * Since: 2.4
3350  **/
3351 gboolean
3352 gtk_text_iter_forward_visible_word_ends (GtkTextIter *iter,
3353                                          gint         count)
3354 {
3355   return move_multiple_steps (iter, count, 
3356                               gtk_text_iter_forward_visible_word_end,
3357                               gtk_text_iter_backward_visible_word_starts);
3358 }
3359
3360 /**
3361  * gtk_text_iter_backward_visible_word_starts
3362  * @iter: a #GtkTextIter
3363  * @count: number of times to move
3364  * 
3365  * Calls gtk_text_iter_backward_visible_word_start() up to @count times.
3366  *
3367  * Return value: %TRUE if @iter moved and is not the end iterator 
3368  * 
3369  * Since: 2.4
3370  **/
3371 gboolean
3372 gtk_text_iter_backward_visible_word_starts (GtkTextIter *iter,
3373                                             gint         count)
3374 {
3375   return move_multiple_steps (iter, count, 
3376                               gtk_text_iter_backward_visible_word_start,
3377                               gtk_text_iter_forward_visible_word_ends);
3378 }
3379
3380 /**
3381  * gtk_text_iter_starts_word:
3382  * @iter: a #GtkTextIter
3383  * 
3384  * Determines whether @iter begins a natural-language word.  Word
3385  * breaks are determined by Pango and should be correct for nearly any
3386  * language (if not, the correct fix would be to the Pango word break
3387  * algorithms).
3388  *
3389  * Return value: %TRUE if @iter is at the start of a word
3390  **/
3391 gboolean
3392 gtk_text_iter_starts_word (const GtkTextIter *iter)
3393 {
3394   return test_log_attrs (iter, is_word_start_func);
3395 }
3396
3397 /**
3398  * gtk_text_iter_ends_word:
3399  * @iter: a #GtkTextIter
3400  * 
3401  * Determines whether @iter ends a natural-language word.  Word breaks
3402  * are determined by Pango and should be correct for nearly any
3403  * language (if not, the correct fix would be to the Pango word break
3404  * algorithms).
3405  *
3406  * Return value: %TRUE if @iter is at the end of a word
3407  **/
3408 gboolean
3409 gtk_text_iter_ends_word (const GtkTextIter *iter)
3410 {
3411   return test_log_attrs (iter, is_word_end_func);
3412 }
3413
3414 /**
3415  * gtk_text_iter_inside_word:
3416  * @iter: a #GtkTextIter
3417  * 
3418  * Determines whether @iter is inside a natural-language word (as
3419  * opposed to say inside some whitespace).  Word breaks are determined
3420  * by Pango and should be correct for nearly any language (if not, the
3421  * correct fix would be to the Pango word break algorithms).
3422  * 
3423  * Return value: %TRUE if @iter is inside a word
3424  **/
3425 gboolean
3426 gtk_text_iter_inside_word (const GtkTextIter *iter)
3427 {
3428   return test_log_attrs (iter, inside_word_func);
3429 }
3430
3431 /**
3432  * gtk_text_iter_starts_sentence:
3433  * @iter: a #GtkTextIter
3434  * 
3435  * Determines whether @iter begins a sentence.  Sentence boundaries are
3436  * determined by Pango and should be correct for nearly any language
3437  * (if not, the correct fix would be to the Pango text boundary
3438  * algorithms).
3439  * 
3440  * Return value: %TRUE if @iter is at the start of a sentence.
3441  **/
3442 gboolean
3443 gtk_text_iter_starts_sentence (const GtkTextIter *iter)
3444 {
3445   return test_log_attrs (iter, is_sentence_start_func);
3446 }
3447
3448 /**
3449  * gtk_text_iter_ends_sentence:
3450  * @iter: a #GtkTextIter
3451  * 
3452  * Determines whether @iter ends a sentence.  Sentence boundaries are
3453  * determined by Pango and should be correct for nearly any language
3454  * (if not, the correct fix would be to the Pango text boundary
3455  * algorithms).
3456  * 
3457  * Return value: %TRUE if @iter is at the end of a sentence.
3458  **/
3459 gboolean
3460 gtk_text_iter_ends_sentence (const GtkTextIter *iter)
3461 {
3462   return test_log_attrs (iter, is_sentence_end_func);
3463 }
3464
3465 /**
3466  * gtk_text_iter_inside_sentence:
3467  * @iter: a #GtkTextIter
3468  * 
3469  * Determines whether @iter is inside a sentence (as opposed to in
3470  * between two sentences, e.g. after a period and before the first
3471  * letter of the next sentence).  Sentence boundaries are determined
3472  * by Pango and should be correct for nearly any language (if not, the
3473  * correct fix would be to the Pango text boundary algorithms).
3474  * 
3475  * Return value: %TRUE if @iter is inside a sentence.
3476  **/
3477 gboolean
3478 gtk_text_iter_inside_sentence (const GtkTextIter *iter)
3479 {
3480   return test_log_attrs (iter, inside_sentence_func);
3481 }
3482
3483 /**
3484  * gtk_text_iter_forward_sentence_end:
3485  * @iter: a #GtkTextIter
3486  * 
3487  * Moves forward to the next sentence end. (If @iter is at the end of
3488  * a sentence, moves to the next end of sentence.)  Sentence
3489  * boundaries are determined by Pango and should be correct for nearly
3490  * any language (if not, the correct fix would be to the Pango text
3491  * boundary algorithms).
3492  * 
3493  * Return value: %TRUE if @iter moved and is not the end iterator
3494  **/
3495 gboolean
3496 gtk_text_iter_forward_sentence_end (GtkTextIter *iter)
3497 {
3498   return find_by_log_attrs (iter, find_sentence_end_func, TRUE, FALSE);
3499 }
3500
3501 /**
3502  * gtk_text_iter_backward_sentence_start:
3503  * @iter: a #GtkTextIter
3504  * 
3505  * Moves backward to the previous sentence start; if @iter is already at
3506  * the start of a sentence, moves backward to the next one.  Sentence
3507  * boundaries are determined by Pango and should be correct for nearly
3508  * any language (if not, the correct fix would be to the Pango text
3509  * boundary algorithms).
3510  * 
3511  * Return value: %TRUE if @iter moved and is not the end iterator
3512  **/
3513 gboolean
3514 gtk_text_iter_backward_sentence_start (GtkTextIter      *iter)
3515 {
3516   return find_by_log_attrs (iter, find_sentence_start_func, FALSE, FALSE);
3517 }
3518
3519 /* FIXME a loop around a truly slow function means
3520  * a truly spectacularly slow function.
3521  */
3522 /**
3523  * gtk_text_iter_forward_sentence_ends:
3524  * @iter: a #GtkTextIter
3525  * @count: number of sentences to move
3526  * 
3527  * Calls gtk_text_iter_forward_sentence_end() @count times (or until
3528  * gtk_text_iter_forward_sentence_end() returns %FALSE). If @count is
3529  * negative, moves backward instead of forward.
3530  * 
3531  * Return value: %TRUE if @iter moved and is not the end iterator
3532  **/
3533 gboolean
3534 gtk_text_iter_forward_sentence_ends (GtkTextIter      *iter,
3535                                      gint              count)
3536 {
3537   return move_multiple_steps (iter, count, 
3538                               gtk_text_iter_forward_sentence_end,
3539                               gtk_text_iter_backward_sentence_starts);
3540 }
3541
3542 /**
3543  * gtk_text_iter_backward_sentence_starts:
3544  * @iter: a #GtkTextIter
3545  * @count: number of sentences to move
3546  * 
3547  * Calls gtk_text_iter_backward_sentence_start() up to @count times,
3548  * or until it returns %FALSE. If @count is negative, moves forward
3549  * instead of backward.
3550  * 
3551  * Return value: %TRUE if @iter moved and is not the end iterator
3552  **/
3553 gboolean
3554 gtk_text_iter_backward_sentence_starts (GtkTextIter      *iter,
3555                                         gint               count)
3556 {
3557   return move_multiple_steps (iter, count, 
3558                               gtk_text_iter_backward_sentence_start,
3559                               gtk_text_iter_forward_sentence_ends);
3560 }
3561
3562 static gboolean
3563 find_forward_cursor_pos_func (const PangoLogAttr *attrs,
3564                               gint          offset,
3565                               gint          min_offset,
3566                               gint          len,
3567                               gint         *found_offset,
3568                               gboolean      already_moved_initially)
3569 {
3570   if (!already_moved_initially)
3571     ++offset;
3572
3573   while (offset < (min_offset + len) &&
3574          !attrs[offset].is_cursor_position)
3575     ++offset;
3576
3577   *found_offset = offset;
3578
3579   return offset < (min_offset + len);
3580 }
3581
3582 static gboolean
3583 find_backward_cursor_pos_func (const PangoLogAttr *attrs,
3584                                gint          offset,
3585                                gint          min_offset,
3586                                gint          len,
3587                                gint         *found_offset,
3588                                gboolean      already_moved_initially)
3589 {  
3590   if (!already_moved_initially)
3591     --offset;
3592
3593   while (offset > min_offset &&
3594          !attrs[offset].is_cursor_position)
3595     --offset;
3596
3597   *found_offset = offset;
3598   
3599   return offset >= min_offset;
3600 }
3601
3602 static gboolean
3603 is_cursor_pos_func (const PangoLogAttr *attrs,
3604                     gint          offset,
3605                     gint          min_offset,
3606                     gint          len)
3607 {
3608   return attrs[offset].is_cursor_position;
3609 }
3610
3611 /**
3612  * gtk_text_iter_forward_cursor_position:
3613  * @iter: a #GtkTextIter
3614  * 
3615  * Moves @iter forward by a single cursor position. Cursor positions
3616  * are (unsurprisingly) positions where the cursor can appear. Perhaps
3617  * surprisingly, there may not be a cursor position between all
3618  * characters. The most common example for European languages would be
3619  * a carriage return/newline sequence. For some Unicode characters,
3620  * the equivalent of say the letter "a" with an accent mark will be
3621  * represented as two characters, first the letter then a "combining
3622  * mark" that causes the accent to be rendered; so the cursor can't go
3623  * between those two characters. See also the #PangoLogAttr structure and
3624  * pango_break() function.
3625  * 
3626  * Return value: %TRUE if we moved and the new position is dereferenceable
3627  **/
3628 gboolean
3629 gtk_text_iter_forward_cursor_position (GtkTextIter *iter)
3630 {
3631   return find_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3632 }
3633
3634 /**
3635  * gtk_text_iter_backward_cursor_position:
3636  * @iter: a #GtkTextIter
3637  * 
3638  * Like gtk_text_iter_forward_cursor_position(), but moves backward.
3639  * 
3640  * Return value: %TRUE if we moved
3641  **/
3642 gboolean
3643 gtk_text_iter_backward_cursor_position (GtkTextIter *iter)
3644 {
3645   return find_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3646 }
3647
3648 /**
3649  * gtk_text_iter_forward_cursor_positions:
3650  * @iter: a #GtkTextIter
3651  * @count: number of positions to move
3652  * 
3653  * Moves up to @count cursor positions. See
3654  * gtk_text_iter_forward_cursor_position() for details.
3655  * 
3656  * Return value: %TRUE if we moved and the new position is dereferenceable
3657  **/
3658 gboolean
3659 gtk_text_iter_forward_cursor_positions (GtkTextIter *iter,
3660                                         gint         count)
3661 {
3662   return move_multiple_steps (iter, count, 
3663                               gtk_text_iter_forward_cursor_position,
3664                               gtk_text_iter_backward_cursor_positions);
3665 }
3666
3667 /**
3668  * gtk_text_iter_backward_cursor_positions:
3669  * @iter: a #GtkTextIter
3670  * @count: number of positions to move
3671  *
3672  * Moves up to @count cursor positions. See
3673  * gtk_text_iter_forward_cursor_position() for details.
3674  * 
3675  * Return value: %TRUE if we moved and the new position is dereferenceable
3676  **/
3677 gboolean
3678 gtk_text_iter_backward_cursor_positions (GtkTextIter *iter,
3679                                          gint         count)
3680 {
3681   return move_multiple_steps (iter, count, 
3682                               gtk_text_iter_backward_cursor_position,
3683                               gtk_text_iter_forward_cursor_positions);
3684 }
3685
3686 /**
3687  * gtk_text_iter_forward_visible_cursor_position:
3688  * @iter: a #GtkTextIter
3689  * 
3690  * Moves @iter forward to the next visible cursor position. See 
3691  * gtk_text_iter_forward_cursor_position() for details.
3692  * 
3693  * Return value: %TRUE if we moved and the new position is dereferenceable
3694  * 
3695  * Since: 2.4
3696  **/
3697 gboolean
3698 gtk_text_iter_forward_visible_cursor_position (GtkTextIter *iter)
3699 {
3700   return find_visible_by_log_attrs (iter, find_forward_cursor_pos_func, TRUE, FALSE);
3701 }
3702
3703 /**
3704  * gtk_text_iter_backward_visible_cursor_position:
3705  * @iter: a #GtkTextIter
3706  * 
3707  * Moves @iter forward to the previous visible cursor position. See 
3708  * gtk_text_iter_backward_cursor_position() for details.
3709  * 
3710  * Return value: %TRUE if we moved and the new position is dereferenceable
3711  * 
3712  * Since: 2.4
3713  **/
3714 gboolean
3715 gtk_text_iter_backward_visible_cursor_position (GtkTextIter *iter)
3716 {
3717   return find_visible_by_log_attrs (iter, find_backward_cursor_pos_func, FALSE, FALSE);
3718 }
3719
3720 /**
3721  * gtk_text_iter_forward_visible_cursor_positions:
3722  * @iter: a #GtkTextIter
3723  * @count: number of positions to move
3724  * 
3725  * Moves up to @count visible cursor positions. See
3726  * gtk_text_iter_forward_cursor_position() for details.
3727  * 
3728  * Return value: %TRUE if we moved and the new position is dereferenceable
3729  * 
3730  * Since: 2.4
3731  **/
3732 gboolean
3733 gtk_text_iter_forward_visible_cursor_positions (GtkTextIter *iter,
3734                                                 gint         count)
3735 {
3736   return move_multiple_steps (iter, count, 
3737                               gtk_text_iter_forward_visible_cursor_position,
3738                               gtk_text_iter_backward_visible_cursor_positions);
3739 }
3740
3741 /**
3742  * gtk_text_iter_backward_visible_cursor_positions:
3743  * @iter: a #GtkTextIter
3744  * @count: number of positions to move
3745  *
3746  * Moves up to @count visible cursor positions. See
3747  * gtk_text_iter_backward_cursor_position() for details.
3748  * 
3749  * Return value: %TRUE if we moved and the new position is dereferenceable
3750  * 
3751  * Since: 2.4
3752  **/
3753 gboolean
3754 gtk_text_iter_backward_visible_cursor_positions (GtkTextIter *iter,
3755                                                  gint         count)
3756 {
3757   return move_multiple_steps (iter, count, 
3758                               gtk_text_iter_backward_visible_cursor_position,
3759                               gtk_text_iter_forward_visible_cursor_positions);
3760 }
3761
3762 /**
3763  * gtk_text_iter_is_cursor_position:
3764  * @iter: a #GtkTextIter
3765  * 
3766  * See gtk_text_iter_forward_cursor_position() or #PangoLogAttr or
3767  * pango_break() for details on what a cursor position is.
3768  * 
3769  * Return value: %TRUE if the cursor can be placed at @iter
3770  **/
3771 gboolean
3772 gtk_text_iter_is_cursor_position (const GtkTextIter *iter)
3773 {
3774   return test_log_attrs (iter, is_cursor_pos_func);
3775 }
3776
3777 /**
3778  * gtk_text_iter_set_line_offset:
3779  * @iter: a #GtkTextIter 
3780  * @char_on_line: a character offset relative to the start of @iter's current line
3781  * 
3782  * Moves @iter within a line, to a new <emphasis>character</emphasis>
3783  * (not byte) offset. The given character offset must be less than or
3784  * equal to the number of characters in the line; if equal, @iter
3785  * moves to the start of the next line. See
3786  * gtk_text_iter_set_line_index() if you have a byte index rather than
3787  * a character offset.
3788  *
3789  **/
3790 void
3791 gtk_text_iter_set_line_offset (GtkTextIter *iter,
3792                                gint         char_on_line)
3793 {
3794   GtkTextRealIter *real;
3795   gint chars_in_line;
3796   
3797   g_return_if_fail (iter != NULL);
3798
3799   real = gtk_text_iter_make_surreal (iter);
3800
3801   if (real == NULL)
3802     return;
3803   
3804   check_invariants (iter);
3805
3806   chars_in_line = gtk_text_iter_get_chars_in_line (iter);
3807
3808   g_return_if_fail (char_on_line <= chars_in_line);
3809
3810   if (char_on_line < chars_in_line)
3811     iter_set_from_char_offset (real, real->line, char_on_line);
3812   else
3813     gtk_text_iter_forward_line (iter); /* set to start of next line */
3814   
3815   check_invariants (iter);
3816 }
3817
3818 /**
3819  * gtk_text_iter_set_line_index:
3820  * @iter: a #GtkTextIter
3821  * @byte_on_line: a byte index relative to the start of @iter's current line
3822  *
3823  * Same as gtk_text_iter_set_line_offset(), but works with a
3824  * <emphasis>byte</emphasis> index. The given byte index must be at
3825  * the start of a character, it can't be in the middle of a UTF-8
3826  * encoded character.
3827  * 
3828  **/
3829 void
3830 gtk_text_iter_set_line_index (GtkTextIter *iter,
3831                               gint         byte_on_line)
3832 {
3833   GtkTextRealIter *real;
3834   gint bytes_in_line;
3835   
3836   g_return_if_fail (iter != NULL);
3837
3838   real = gtk_text_iter_make_surreal (iter);
3839
3840   if (real == NULL)
3841     return;
3842
3843   check_invariants (iter);
3844
3845   bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3846
3847   g_return_if_fail (byte_on_line <= bytes_in_line);
3848   
3849   if (byte_on_line < bytes_in_line)
3850     iter_set_from_byte_offset (real, real->line, byte_on_line);
3851   else
3852     gtk_text_iter_forward_line (iter);
3853
3854   if (real->segment->type == &gtk_text_char_type &&
3855       (real->segment->body.chars[real->segment_byte_offset] & 0xc0) == 0x80)
3856     g_warning ("%s: Incorrect byte offset %d falls in the middle of a UTF-8 "
3857                "character; this will crash the text buffer. "
3858                "Byte indexes must refer to the start of a character.",
3859                G_STRLOC, byte_on_line);
3860
3861   check_invariants (iter);
3862 }
3863
3864
3865 /**
3866  * gtk_text_iter_set_visible_line_offset:
3867  * @iter: a #GtkTextIter
3868  * @char_on_line: a character offset
3869  * 
3870  * Like gtk_text_iter_set_line_offset(), but the offset is in visible
3871  * characters, i.e. text with a tag making it invisible is not
3872  * counted in the offset.
3873  **/
3874 void
3875 gtk_text_iter_set_visible_line_offset (GtkTextIter *iter,
3876                                        gint         char_on_line)
3877 {
3878   gint chars_seen = 0;
3879   GtkTextIter pos;
3880
3881   g_return_if_fail (iter != NULL);
3882   
3883   gtk_text_iter_set_line_offset (iter, 0);
3884
3885   pos = *iter;
3886
3887   /* For now we use a ludicrously slow implementation */
3888   while (chars_seen < char_on_line)
3889     {
3890       if (!_gtk_text_btree_char_is_invisible (&pos))
3891         ++chars_seen;
3892
3893       if (!gtk_text_iter_forward_char (&pos))
3894         break;
3895
3896       if (chars_seen == char_on_line)
3897         break;
3898     }
3899   
3900   if (_gtk_text_iter_get_text_line (&pos) == _gtk_text_iter_get_text_line (iter))
3901     *iter = pos;
3902   else
3903     gtk_text_iter_forward_line (iter);
3904 }
3905
3906 /**
3907  * gtk_text_iter_set_visible_line_index:
3908  * @iter: a #GtkTextIter
3909  * @byte_on_line: a byte index
3910  * 
3911  * Like gtk_text_iter_set_line_index(), but the index is in visible
3912  * bytes, i.e. text with a tag making it invisible is not counted
3913  * in the index.
3914  **/
3915 void
3916 gtk_text_iter_set_visible_line_index (GtkTextIter *iter,
3917                                       gint         byte_on_line)
3918 {
3919   GtkTextRealIter *real;
3920   gint bytes_in_line = 0;
3921   gint offset = 0;
3922   GtkTextIter pos;
3923   GtkTextLineSegment *seg;
3924   
3925   g_return_if_fail (iter != NULL);
3926
3927   gtk_text_iter_set_line_offset (iter, 0);
3928
3929   bytes_in_line = gtk_text_iter_get_bytes_in_line (iter);
3930
3931   pos = *iter;
3932
3933   real = gtk_text_iter_make_real (&pos);
3934
3935   if (real == NULL)
3936     return;
3937
3938   ensure_byte_offsets (real);
3939
3940   check_invariants (&pos);
3941
3942   seg = _gtk_text_iter_get_indexable_segment (&pos);
3943
3944   while (seg != NULL && byte_on_line > 0)
3945     {
3946       if (!_gtk_text_btree_char_is_invisible (&pos))
3947         {
3948           if (byte_on_line < seg->byte_count)
3949             {
3950               iter_set_from_byte_offset (real, real->line, offset + byte_on_line);
3951               byte_on_line = 0;
3952               break;
3953             }
3954           else
3955             byte_on_line -= seg->byte_count;
3956         }
3957
3958       offset += seg->byte_count;
3959       _gtk_text_iter_forward_indexable_segment (&pos);
3960       seg = _gtk_text_iter_get_indexable_segment (&pos);
3961     }
3962
3963   if (byte_on_line == 0)
3964     *iter = pos;
3965   else
3966     gtk_text_iter_forward_line (iter);
3967 }
3968
3969 /**
3970  * gtk_text_iter_set_line:
3971  * @iter: a #GtkTextIter
3972  * @line_number: line number (counted from 0)
3973  *
3974  * Moves iterator @iter to the start of the line @line_number.  If
3975  * @line_number is negative or larger than the number of lines in the
3976  * buffer, moves @iter to the start of the last line in the buffer.
3977  * 
3978  **/
3979 void
3980 gtk_text_iter_set_line (GtkTextIter *iter,
3981                         gint         line_number)
3982 {
3983   GtkTextLine *line;
3984   gint real_line;
3985   GtkTextRealIter *real;
3986
3987   g_return_if_fail (iter != NULL);
3988
3989   real = gtk_text_iter_make_surreal (iter);
3990
3991   if (real == NULL)
3992     return;
3993
3994   check_invariants (iter);
3995
3996   line = _gtk_text_btree_get_line_no_last (real->tree, line_number, &real_line);
3997
3998   iter_set_from_char_offset (real, line, 0);
3999
4000   /* We might as well cache this, since we know it. */
4001   real->cached_line_number = real_line;
4002
4003   check_invariants (iter);
4004 }
4005
4006 /**
4007  * gtk_text_iter_set_offset:
4008  * @iter: a #GtkTextIter
4009  * @char_offset: a character number
4010  *
4011  * Sets @iter to point to @char_offset. @char_offset counts from the start
4012  * of the entire text buffer, starting with 0.
4013  **/
4014 void
4015 gtk_text_iter_set_offset (GtkTextIter *iter,
4016                           gint         char_offset)
4017 {
4018   GtkTextLine *line;
4019   GtkTextRealIter *real;
4020   gint line_start;
4021   gint real_char_index;
4022
4023   g_return_if_fail (iter != NULL);
4024
4025   real = gtk_text_iter_make_surreal (iter);
4026
4027   if (real == NULL)
4028     return;
4029
4030   check_invariants (iter);
4031
4032   if (real->cached_char_index >= 0 &&
4033       real->cached_char_index == char_offset)
4034     return;
4035
4036   line = _gtk_text_btree_get_line_at_char (real->tree,
4037                                            char_offset,
4038                                            &line_start,
4039                                            &real_char_index);
4040
4041   iter_set_from_char_offset (real, line, real_char_index - line_start);
4042
4043   /* Go ahead and cache this since we have it. */
4044   real->cached_char_index = real_char_index;
4045
4046   check_invariants (iter);
4047 }
4048
4049 /**
4050  * gtk_text_iter_forward_to_end:
4051  * @iter: a #GtkTextIter
4052  *
4053  * Moves @iter forward to the "end iterator," which points one past the last
4054  * valid character in the buffer. gtk_text_iter_get_char() called on the
4055  * end iterator returns 0, which is convenient for writing loops.
4056  **/
4057 void
4058 gtk_text_iter_forward_to_end  (GtkTextIter *iter)
4059 {
4060   GtkTextBuffer *buffer;
4061   GtkTextRealIter *real;
4062
4063   g_return_if_fail (iter != NULL);
4064
4065   real = gtk_text_iter_make_surreal (iter);
4066
4067   if (real == NULL)
4068     return;
4069
4070   buffer = _gtk_text_btree_get_buffer (real->tree);
4071
4072   gtk_text_buffer_get_end_iter (buffer, iter);
4073 }
4074
4075 /* FIXME this and gtk_text_iter_forward_to_line_end() could be cleaned up
4076  * and made faster. Look at iter_ends_line() for inspiration, perhaps.
4077  * If all else fails we could cache the para delimiter pos in the iter.
4078  * I think forward_to_line_end() actually gets called fairly often.
4079  */
4080 static int
4081 find_paragraph_delimiter_for_line (GtkTextIter *iter)
4082 {
4083   GtkTextIter end;
4084   end = *iter;
4085
4086   if (_gtk_text_line_contains_end_iter (_gtk_text_iter_get_text_line (&end),
4087                                         _gtk_text_iter_get_btree (&end)))
4088     {
4089       gtk_text_iter_forward_to_end (&end);
4090     }
4091   else
4092     {
4093       /* if we aren't on the last line, go forward to start of next line, then scan
4094        * back for the delimiters on the previous line
4095        */
4096       gtk_text_iter_forward_line (&end);
4097       gtk_text_iter_backward_char (&end);
4098       while (!gtk_text_iter_ends_line (&end))
4099         gtk_text_iter_backward_char (&end);
4100     }
4101
4102   return gtk_text_iter_get_line_offset (&end);
4103 }
4104
4105 /**
4106  * gtk_text_iter_forward_to_line_end:
4107  * @iter: a #GtkTextIter
4108  * 
4109  * Moves the iterator to point to the paragraph delimiter characters,
4110  * which will be either a newline, a carriage return, a carriage
4111  * return/newline in sequence, or the Unicode paragraph separator
4112  * character. If the iterator is already at the paragraph delimiter
4113  * characters, moves to the paragraph delimiter characters for the
4114  * next line. If @iter is on the last line in the buffer, which does
4115  * not end in paragraph delimiters, moves to the end iterator (end of
4116  * the last line), and returns %FALSE.
4117  * 
4118  * Return value: %TRUE if we moved and the new location is not the end iterator
4119  **/
4120 gboolean
4121 gtk_text_iter_forward_to_line_end (GtkTextIter *iter)
4122 {
4123   gint current_offset;
4124   gint new_offset;
4125
4126   
4127   g_return_val_if_fail (iter != NULL, FALSE);
4128
4129   current_offset = gtk_text_iter_get_line_offset (iter);
4130   new_offset = find_paragraph_delimiter_for_line (iter);
4131   
4132   if (current_offset < new_offset)
4133     {
4134       /* Move to end of this line. */
4135       gtk_text_iter_set_line_offset (iter, new_offset);
4136       return !gtk_text_iter_is_end (iter);
4137     }
4138   else
4139     {
4140       /* Move to end of next line. */
4141       if (gtk_text_iter_forward_line (iter))
4142         {
4143           /* We don't want to move past all
4144            * empty lines.
4145            */
4146           if (!gtk_text_iter_ends_line (iter))
4147             gtk_text_iter_forward_to_line_end (iter);
4148           return !gtk_text_iter_is_end (iter);
4149         }
4150       else
4151         return FALSE;
4152     }
4153 }
4154
4155 /**
4156  * gtk_text_iter_forward_to_tag_toggle:
4157  * @iter: a #GtkTextIter
4158  * @tag: a #GtkTextTag, or %NULL
4159  *
4160  * Moves forward to the next toggle (on or off) of the
4161  * #GtkTextTag @tag, or to the next toggle of any tag if
4162  * @tag is %NULL. If no matching tag toggles are found,
4163  * returns %FALSE, otherwise %TRUE. Does not return toggles
4164  * located at @iter, only toggles after @iter. Sets @iter to
4165  * the location of the toggle, or to the end of the buffer
4166  * if no toggle is found.
4167  *
4168  * Return value: whether we found a tag toggle after @iter
4169  **/
4170 gboolean
4171 gtk_text_iter_forward_to_tag_toggle (GtkTextIter *iter,
4172                                      GtkTextTag  *tag)
4173 {
4174   GtkTextLine *next_line;
4175   GtkTextLine *current_line;
4176   GtkTextRealIter *real;
4177
4178   g_return_val_if_fail (iter != NULL, FALSE);
4179
4180   real = gtk_text_iter_make_real (iter);
4181
4182   if (real == NULL)
4183     return FALSE;
4184
4185   check_invariants (iter);
4186
4187   current_line = real->line;
4188   next_line = _gtk_text_line_next_could_contain_tag (current_line,
4189                                                      real->tree, tag);
4190
4191   while (_gtk_text_iter_forward_indexable_segment (iter))
4192     {
4193       /* If we went forward to a line that couldn't contain a toggle
4194          for the tag, then skip forward to a line that could contain
4195          it. This potentially skips huge hunks of the tree, so we
4196          aren't a purely linear search. */
4197       if (real->line != current_line)
4198         {
4199           if (next_line == NULL)
4200             {
4201               /* End of search. Set to end of buffer. */
4202               _gtk_text_btree_get_end_iter (real->tree, iter);
4203               return FALSE;
4204             }
4205
4206           if (real->line != next_line)
4207             iter_set_from_byte_offset (real, next_line, 0);
4208
4209           current_line = real->line;
4210           next_line = _gtk_text_line_next_could_contain_tag (current_line,
4211                                                              real->tree,
4212                                                              tag);
4213         }
4214
4215       if (gtk_text_iter_toggles_tag (iter, tag))
4216         {
4217           /* If there's a toggle here, it isn't indexable so
4218              any_segment can't be the indexable segment. */
4219           g_assert (real->any_segment != real->segment);
4220           return TRUE;
4221         }
4222     }
4223
4224   /* Check end iterator for tags */
4225   if (gtk_text_iter_toggles_tag (iter, tag))
4226     {
4227       /* If there's a toggle here, it isn't indexable so
4228          any_segment can't be the indexable segment. */
4229       g_assert (real->any_segment != real->segment);
4230       return TRUE;
4231     }
4232
4233   /* Reached end of buffer */
4234   return FALSE;
4235 }
4236
4237 /**
4238  * gtk_text_iter_backward_to_tag_toggle:
4239  * @iter: a #GtkTextIter
4240  * @tag: a #GtkTextTag, or %NULL
4241  *
4242  * Moves backward to the next toggle (on or off) of the
4243  * #GtkTextTag @tag, or to the next toggle of any tag if
4244  * @tag is %NULL. If no matching tag toggles are found,
4245  * returns %FALSE, otherwise %TRUE. Does not return toggles
4246  * located at @iter, only toggles before @iter. Sets @iter
4247  * to the location of the toggle, or the start of the buffer
4248  * if no toggle is found.
4249  *
4250  * Return value: whether we found a tag toggle before @iter
4251  **/
4252 gboolean
4253 gtk_text_iter_backward_to_tag_toggle (GtkTextIter *iter,
4254                                       GtkTextTag  *tag)
4255 {
4256   GtkTextLine *prev_line;
4257   GtkTextLine *current_line;
4258   GtkTextRealIter *real;
4259
4260   g_return_val_if_fail (iter != NULL, FALSE);
4261
4262   real = gtk_text_iter_make_real (iter);
4263
4264   if (real == NULL)
4265     return FALSE;
4266
4267   check_invariants (iter);
4268
4269   current_line = real->line;
4270   prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4271                                                         real->tree, tag);
4272
4273
4274   /* If we're at segment start, go to the previous segment;
4275    * if mid-segment, snap to start of current segment.
4276    */
4277   if (is_segment_start (real))
4278     {
4279       if (!_gtk_text_iter_backward_indexable_segment (iter))
4280         return FALSE;
4281     }
4282   else
4283     {
4284       ensure_char_offsets (real);
4285
4286       if (!gtk_text_iter_backward_chars (iter, real->segment_char_offset))
4287         return FALSE;
4288     }
4289
4290   do
4291     {
4292       /* If we went backward to a line that couldn't contain a toggle
4293        * for the tag, then skip backward further to a line that
4294        * could contain it. This potentially skips huge hunks of the
4295        * tree, so we aren't a purely linear search.
4296        */
4297       if (real->line != current_line)
4298         {
4299           if (prev_line == NULL)
4300             {
4301               /* End of search. Set to start of buffer. */
4302               _gtk_text_btree_get_iter_at_char (real->tree, iter, 0);
4303               return FALSE;
4304             }
4305
4306           if (real->line != prev_line)
4307             {
4308               /* Set to last segment in prev_line (could do this
4309                * more quickly)
4310                */
4311               iter_set_from_byte_offset (real, prev_line, 0);
4312
4313               while (!at_last_indexable_segment (real))
4314                 _gtk_text_iter_forward_indexable_segment (iter);
4315             }
4316
4317           current_line = real->line;
4318           prev_line = _gtk_text_line_previous_could_contain_tag (current_line,
4319                                                                 real->tree,
4320                                                                 tag);
4321         }
4322
4323       if (gtk_text_iter_toggles_tag (iter, tag))
4324         {
4325           /* If there's a toggle here, it isn't indexable so
4326            * any_segment can't be the indexable segment.
4327            */
4328           g_assert (real->any_segment != real->segment);
4329           return TRUE;
4330         }
4331     }
4332   while (_gtk_text_iter_backward_indexable_segment (iter));
4333
4334   /* Reached front of buffer */
4335   return FALSE;
4336 }
4337
4338 static gboolean
4339 matches_pred (GtkTextIter *iter,
4340               GtkTextCharPredicate pred,
4341               gpointer user_data)
4342 {
4343   gint ch;
4344
4345   ch = gtk_text_iter_get_char (iter);
4346
4347   return (*pred) (ch, user_data);
4348 }
4349
4350 /**
4351  * gtk_text_iter_forward_find_char:
4352  * @iter: a #GtkTextIter
4353  * @pred: a function to be called on each character
4354  * @user_data: user data for @pred
4355  * @limit: search limit, or %NULL for none 
4356  * 
4357  * Advances @iter, calling @pred on each character. If
4358  * @pred returns %TRUE, returns %TRUE and stops scanning.
4359  * If @pred never returns %TRUE, @iter is set to @limit if
4360  * @limit is non-%NULL, otherwise to the end iterator.
4361  * 
4362  * Return value: whether a match was found
4363  **/
4364 gboolean
4365 gtk_text_iter_forward_find_char (GtkTextIter         *iter,
4366                                  GtkTextCharPredicate pred,
4367                                  gpointer             user_data,
4368                                  const GtkTextIter   *limit)
4369 {
4370   g_return_val_if_fail (iter != NULL, FALSE);
4371   g_return_val_if_fail (pred != NULL, FALSE);
4372
4373   if (limit &&
4374       gtk_text_iter_compare (iter, limit) >= 0)
4375     return FALSE;
4376   
4377   while ((limit == NULL ||
4378           !gtk_text_iter_equal (limit, iter)) &&
4379          gtk_text_iter_forward_char (iter))
4380     {      
4381       if (matches_pred (iter, pred, user_data))
4382         return TRUE;
4383     }
4384
4385   return FALSE;
4386 }
4387
4388 /**
4389  * gtk_text_iter_backward_find_char:
4390  * @iter: a #GtkTextIter
4391  * @pred: function to be called on each character
4392  * @user_data: user data for @pred
4393  * @limit: search limit, or %NULL for none
4394  * 
4395  * Same as gtk_text_iter_forward_find_char(), but goes backward from @iter.
4396  * 
4397  * Return value: whether a match was found
4398  **/
4399 gboolean
4400 gtk_text_iter_backward_find_char (GtkTextIter         *iter,
4401                                   GtkTextCharPredicate pred,
4402                                   gpointer             user_data,
4403                                   const GtkTextIter   *limit)
4404 {
4405   g_return_val_if_fail (iter != NULL, FALSE);
4406   g_return_val_if_fail (pred != NULL, FALSE);
4407
4408   if (limit &&
4409       gtk_text_iter_compare (iter, limit) <= 0)
4410     return FALSE;
4411   
4412   while ((limit == NULL ||
4413           !gtk_text_iter_equal (limit, iter)) &&
4414          gtk_text_iter_backward_char (iter))
4415     {
4416       if (matches_pred (iter, pred, user_data))
4417         return TRUE;
4418     }
4419
4420   return FALSE;
4421 }
4422
4423 static void
4424 forward_chars_with_skipping (GtkTextIter *iter,
4425                              gint         count,
4426                              gboolean     skip_invisible,
4427                              gboolean     skip_nontext)
4428 {
4429
4430   gint i;
4431
4432   g_return_if_fail (count >= 0);
4433
4434   i = count;
4435
4436   while (i > 0)
4437     {
4438       gboolean ignored = FALSE;
4439
4440       if (skip_nontext &&
4441           gtk_text_iter_get_char (iter) == GTK_TEXT_UNKNOWN_CHAR)
4442         ignored = TRUE;
4443
4444       if (!ignored &&
4445           skip_invisible &&
4446           _gtk_text_btree_char_is_invisible (iter))
4447         ignored = TRUE;
4448
4449       gtk_text_iter_forward_char (iter);
4450
4451       if (!ignored)
4452         --i;
4453     }
4454 }
4455
4456 static gboolean
4457 lines_match (const GtkTextIter *start,
4458              const gchar **lines,
4459              gboolean visible_only,
4460              gboolean slice,
4461              GtkTextIter *match_start,
4462              GtkTextIter *match_end)
4463 {
4464   GtkTextIter next;
4465   gchar *line_text;
4466   const gchar *found;
4467   gint offset;
4468
4469   if (*lines == NULL || **lines == '\0')
4470     {
4471       if (match_start)
4472         *match_start = *start;
4473
4474       if (match_end)
4475         *match_end = *start;
4476       return TRUE;
4477     }
4478
4479   next = *start;
4480   gtk_text_iter_forward_line (&next);
4481
4482   /* No more text in buffer, but *lines is nonempty */
4483   if (gtk_text_iter_equal (start, &next))
4484     {
4485       return FALSE;
4486     }
4487
4488   if (slice)
4489     {
4490       if (visible_only)
4491         line_text = gtk_text_iter_get_visible_slice (start, &next);
4492       else
4493         line_text = gtk_text_iter_get_slice (start, &next);
4494     }
4495   else
4496     {
4497       if (visible_only)
4498         line_text = gtk_text_iter_get_visible_text (start, &next);
4499       else
4500         line_text = gtk_text_iter_get_text (start, &next);
4501     }
4502
4503   if (match_start) /* if this is the first line we're matching */
4504     found = strstr (line_text, *lines);
4505   else
4506     {
4507       /* If it's not the first line, we have to match from the
4508        * start of the line.
4509        */
4510       if (strncmp (line_text, *lines, strlen (*lines)) == 0)
4511         found = line_text;
4512       else
4513         found = NULL;
4514     }
4515
4516   if (found == NULL)
4517     {
4518       g_free (line_text);
4519       return FALSE;
4520     }
4521
4522   /* Get offset to start of search string */
4523   offset = g_utf8_strlen (line_text, found - line_text);
4524
4525   next = *start;
4526
4527   /* If match start needs to be returned, set it to the
4528    * start of the search string.
4529    */
4530   if (match_start)
4531     {
4532       *match_start = next;
4533
4534       forward_chars_with_skipping (match_start, offset,
4535                                    visible_only, !slice);
4536     }
4537
4538   /* Go to end of search string */
4539   offset += g_utf8_strlen (*lines, -1);
4540
4541   forward_chars_with_skipping (&next, offset,
4542                                visible_only, !slice);
4543
4544   g_free (line_text);
4545
4546   ++lines;
4547
4548   if (match_end)
4549     *match_end = next;
4550
4551   /* pass NULL for match_start, since we don't need to find the
4552    * start again.
4553    */
4554   return lines_match (&next, lines, visible_only, slice, NULL, match_end);
4555 }
4556
4557 /* strsplit () that retains the delimiter as part of the string. */
4558 static gchar **
4559 strbreakup (const char *string,
4560             const char *delimiter,
4561             gint        max_tokens)
4562 {
4563   GSList *string_list = NULL, *slist;
4564   gchar **str_array, *s;
4565   guint i, n = 1;
4566
4567   g_return_val_if_fail (string != NULL, NULL);
4568   g_return_val_if_fail (delimiter != NULL, NULL);
4569
4570   if (max_tokens < 1)
4571     max_tokens = G_MAXINT;
4572
4573   s = strstr (string, delimiter);
4574   if (s)
4575     {
4576       guint delimiter_len = strlen (delimiter);
4577
4578       do
4579         {
4580           guint len;
4581           gchar *new_string;
4582
4583           len = s - string + delimiter_len;
4584           new_string = g_new (gchar, len + 1);
4585           strncpy (new_string, string, len);
4586           new_string[len] = 0;
4587           string_list = g_slist_prepend (string_list, new_string);
4588           n++;
4589           string = s + delimiter_len;
4590           s = strstr (string, delimiter);
4591         }
4592       while (--max_tokens && s);
4593     }
4594   if (*string)
4595     {
4596       n++;
4597       string_list = g_slist_prepend (string_list, g_strdup (string));
4598     }
4599
4600   str_array = g_new (gchar*, n);
4601
4602   i = n - 1;
4603
4604   str_array[i--] = NULL;
4605   for (slist = string_list; slist; slist = slist->next)
4606     str_array[i--] = slist->data;
4607
4608   g_slist_free (string_list);
4609
4610   return str_array;
4611 }
4612
4613 /**
4614  * gtk_text_iter_forward_search:
4615  * @iter: start of search
4616  * @str: a search string
4617  * @flags: flags affecting how the search is done
4618  * @match_start: return location for start of match, or %NULL
4619  * @match_end: return location for end of match, or %NULL
4620  * @limit: bound for the search, or %NULL for the end of the buffer
4621  * 
4622  * Searches forward for @str. Any match is returned by setting 
4623  * @match_start to the first character of the match and @match_end to the 
4624  * first character after the match. The search will not continue past
4625  * @limit. Note that a search is a linear or O(n) operation, so you
4626  * may wish to use @limit to avoid locking up your UI on large
4627  * buffers.
4628  * 
4629  * If the #GTK_TEXT_SEARCH_VISIBLE_ONLY flag is present, the match may
4630  * have invisible text interspersed in @str. i.e. @str will be a
4631  * possibly-noncontiguous subsequence of the matched range. similarly,
4632  * if you specify #GTK_TEXT_SEARCH_TEXT_ONLY, the match may have
4633  * pixbufs or child widgets mixed inside the matched range. If these
4634  * flags are not given, the match must be exact; the special 0xFFFC
4635  * character in @str will match embedded pixbufs or child widgets.
4636  *
4637  * Return value: whether a match was found
4638  **/
4639 gboolean
4640 gtk_text_iter_forward_search (const GtkTextIter *iter,
4641                               const gchar       *str,
4642                               GtkTextSearchFlags flags,
4643                               GtkTextIter       *match_start,
4644                               GtkTextIter       *match_end,
4645                               const GtkTextIter *limit)
4646 {
4647   gchar **lines = NULL;
4648   GtkTextIter match;
4649   gboolean retval = FALSE;
4650   GtkTextIter search;
4651   gboolean visible_only;
4652   gboolean slice;
4653   
4654   g_return_val_if_fail (iter != NULL, FALSE);
4655   g_return_val_if_fail (str != NULL, FALSE);
4656
4657   if (limit &&
4658       gtk_text_iter_compare (iter, limit) >= 0)
4659     return FALSE;
4660   
4661   if (*str == '\0')
4662     {
4663       /* If we can move one char, return the empty string there */
4664       match = *iter;
4665       
4666       if (gtk_text_iter_forward_char (&match))
4667         {
4668           if (limit &&
4669               gtk_text_iter_equal (&match, limit))
4670             return FALSE;
4671           
4672           if (match_start)
4673             *match_start = match;
4674           if (match_end)
4675             *match_end = match;
4676           return TRUE;
4677         }
4678       else
4679         return FALSE;
4680     }
4681
4682   visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4683   slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4684   
4685   /* locate all lines */
4686
4687   lines = strbreakup (str, "\n", -1);
4688
4689   search = *iter;
4690
4691   do
4692     {
4693       /* This loop has an inefficient worst-case, where
4694        * gtk_text_iter_get_text () is called repeatedly on
4695        * a single line.
4696        */
4697       GtkTextIter end;
4698
4699       if (limit &&
4700           gtk_text_iter_compare (&search, limit) >= 0)
4701         break;
4702       
4703       if (lines_match (&search, (const gchar**)lines,
4704                        visible_only, slice, &match, &end))
4705         {
4706           if (limit == NULL ||
4707               (limit &&
4708                gtk_text_iter_compare (&end, limit) <= 0))
4709             {
4710               retval = TRUE;
4711               
4712               if (match_start)
4713                 *match_start = match;
4714               
4715               if (match_end)
4716                 *match_end = end;
4717             }
4718           
4719           break;
4720         }
4721     }
4722   while (gtk_text_iter_forward_line (&search));
4723
4724   g_strfreev ((gchar**)lines);
4725
4726   return retval;
4727 }
4728
4729 static gboolean
4730 vectors_equal_ignoring_trailing (gchar **vec1,
4731                                  gchar **vec2)
4732 {
4733   /* Ignores trailing chars in vec2's last line */
4734
4735   gchar **i1, **i2;
4736
4737   i1 = vec1;
4738   i2 = vec2;
4739
4740   while (*i1 && *i2)
4741     {
4742       if (strcmp (*i1, *i2) != 0)
4743         {
4744           if (*(i2 + 1) == NULL) /* if this is the last line */
4745             {
4746               gint len1 = strlen (*i1);
4747               gint len2 = strlen (*i2);
4748
4749               if (len2 >= len1 &&
4750                   strncmp (*i1, *i2, len1) == 0)
4751                 {
4752                   /* We matched ignoring the trailing stuff in vec2 */
4753                   return TRUE;
4754                 }
4755               else
4756                 {
4757                   return FALSE;
4758                 }
4759             }
4760           else
4761             {
4762               return FALSE;
4763             }
4764         }
4765       ++i1;
4766       ++i2;
4767     }
4768
4769   if (*i1 || *i2)
4770     {
4771       return FALSE;
4772     }
4773   else
4774     return TRUE;
4775 }
4776
4777 typedef struct _LinesWindow LinesWindow;
4778
4779 struct _LinesWindow
4780 {
4781   gint n_lines;
4782   gchar **lines;
4783   GtkTextIter first_line_start;
4784   GtkTextIter first_line_end;
4785   gboolean slice;
4786   gboolean visible_only;
4787 };
4788
4789 static void
4790 lines_window_init (LinesWindow       *win,
4791                    const GtkTextIter *start)
4792 {
4793   gint i;
4794   GtkTextIter line_start;
4795   GtkTextIter line_end;
4796
4797   /* If we start on line 1, there are 2 lines to search (0 and 1), so
4798    * n_lines can be 2.
4799    */
4800   if (gtk_text_iter_is_start (start) ||
4801       gtk_text_iter_get_line (start) + 1 < win->n_lines)
4802     {
4803       /* Already at the end, or not enough lines to match */
4804       win->lines = g_new0 (gchar*, 1);
4805       *win->lines = NULL;
4806       return;
4807     }
4808
4809   line_start = *start;
4810   line_end = *start;
4811
4812   /* Move to start iter to start of line */
4813   gtk_text_iter_set_line_offset (&line_start, 0);
4814
4815   if (gtk_text_iter_equal (&line_start, &line_end))
4816     {
4817       /* we were already at the start; so go back one line */
4818       gtk_text_iter_backward_line (&line_start);
4819     }
4820
4821   win->first_line_start = line_start;
4822   win->first_line_end = line_end;
4823
4824   win->lines = g_new0 (gchar*, win->n_lines + 1);
4825
4826   i = win->n_lines - 1;
4827   while (i >= 0)
4828     {
4829       gchar *line_text;
4830
4831       if (win->slice)
4832         {
4833           if (win->visible_only)
4834             line_text = gtk_text_iter_get_visible_slice (&line_start, &line_end);
4835           else
4836             line_text = gtk_text_iter_get_slice (&line_start, &line_end);
4837         }
4838       else
4839         {
4840           if (win->visible_only)
4841             line_text = gtk_text_iter_get_visible_text (&line_start, &line_end);
4842           else
4843             line_text = gtk_text_iter_get_text (&line_start, &line_end);
4844         }
4845
4846       win->lines[i] = line_text;
4847
4848       line_end = line_start;
4849       gtk_text_iter_backward_line (&line_start);
4850
4851       --i;
4852     }
4853 }
4854
4855 static gboolean
4856 lines_window_back (LinesWindow *win)
4857 {
4858   GtkTextIter new_start;
4859   gchar *line_text;
4860
4861   new_start = win->first_line_start;
4862
4863   if (!gtk_text_iter_backward_line (&new_start))
4864     return FALSE;
4865   else
4866     {
4867       win->first_line_start = new_start;
4868       win->first_line_end = new_start;
4869
4870       gtk_text_iter_forward_line (&win->first_line_end);
4871     }
4872
4873   if (win->slice)
4874     {
4875       if (win->visible_only)
4876         line_text = gtk_text_iter_get_visible_slice (&win->first_line_start,
4877                                                      &win->first_line_end);
4878       else
4879         line_text = gtk_text_iter_get_slice (&win->first_line_start,
4880                                              &win->first_line_end);
4881     }
4882   else
4883     {
4884       if (win->visible_only)
4885         line_text = gtk_text_iter_get_visible_text (&win->first_line_start,
4886                                                     &win->first_line_end);
4887       else
4888         line_text = gtk_text_iter_get_text (&win->first_line_start,
4889                                             &win->first_line_end);
4890     }
4891
4892   /* Move lines to make room for first line. */
4893   g_memmove (win->lines + 1, win->lines, win->n_lines * sizeof (gchar*));
4894
4895   *win->lines = line_text;
4896
4897   /* Free old last line and NULL-terminate */
4898   g_free (win->lines[win->n_lines]);
4899   win->lines[win->n_lines] = NULL;
4900
4901   return TRUE;
4902 }
4903
4904 static void
4905 lines_window_free (LinesWindow *win)
4906 {
4907   g_strfreev (win->lines);
4908 }
4909
4910 /**
4911  * gtk_text_iter_backward_search:
4912  * @iter: a #GtkTextIter where the search begins
4913  * @str: search string
4914  * @flags: bitmask of flags affecting the search
4915  * @match_start: return location for start of match, or %NULL
4916  * @match_end: return location for end of match, or %NULL
4917  * @limit: location of last possible @match_start, or %NULL for start of buffer
4918  * 
4919  * Same as gtk_text_iter_forward_search(), but moves backward.
4920  * 
4921  * Return value: whether a match was found
4922  **/
4923 gboolean
4924 gtk_text_iter_backward_search (const GtkTextIter *iter,
4925                                const gchar       *str,
4926                                GtkTextSearchFlags flags,
4927                                GtkTextIter       *match_start,
4928                                GtkTextIter       *match_end,
4929                                const GtkTextIter *limit)
4930 {
4931   gchar **lines = NULL;
4932   gchar **l;
4933   gint n_lines;
4934   LinesWindow win;
4935   gboolean retval = FALSE;
4936   gboolean visible_only;
4937   gboolean slice;
4938   
4939   g_return_val_if_fail (iter != NULL, FALSE);
4940   g_return_val_if_fail (str != NULL, FALSE);
4941
4942   if (limit &&
4943       gtk_text_iter_compare (limit, iter) > 0)
4944     return FALSE;
4945   
4946   if (*str == '\0')
4947     {
4948       /* If we can move one char, return the empty string there */
4949       GtkTextIter match = *iter;
4950
4951       if (limit && gtk_text_iter_equal (limit, &match))
4952         return FALSE;
4953       
4954       if (gtk_text_iter_backward_char (&match))
4955         {
4956           if (match_start)
4957             *match_start = match;
4958           if (match_end)
4959             *match_end = match;
4960           return TRUE;
4961         }
4962       else
4963         return FALSE;
4964     }
4965
4966   visible_only = (flags & GTK_TEXT_SEARCH_VISIBLE_ONLY) != 0;
4967   slice = (flags & GTK_TEXT_SEARCH_TEXT_ONLY) == 0;
4968   
4969   /* locate all lines */
4970
4971   lines = strbreakup (str, "\n", -1);
4972
4973   l = lines;
4974   n_lines = 0;
4975   while (*l)
4976     {
4977       ++n_lines;
4978       ++l;
4979     }
4980
4981   win.n_lines = n_lines;
4982   win.slice = slice;
4983   win.visible_only = visible_only;
4984
4985   lines_window_init (&win, iter);
4986
4987   if (*win.lines == NULL)
4988     goto out;
4989
4990   do
4991     {
4992       gchar *first_line_match;
4993
4994       if (limit &&
4995           gtk_text_iter_compare (limit, &win.first_line_end) > 0)
4996         {
4997           /* We're now before the search limit, abort. */
4998           goto out;
4999         }
5000       
5001       /* If there are multiple lines, the first line will
5002        * end in '\n', so this will only match at the
5003        * end of the first line, which is correct.
5004        */
5005       first_line_match = g_strrstr (*win.lines, *lines);
5006
5007       if (first_line_match &&
5008           vectors_equal_ignoring_trailing (lines + 1, win.lines + 1))
5009         {
5010           /* Match! */
5011           gint offset;
5012           GtkTextIter next;
5013           GtkTextIter start_tmp;
5014           
5015           /* Offset to start of search string */
5016           offset = g_utf8_strlen (*win.lines, first_line_match - *win.lines);
5017
5018           next = win.first_line_start;
5019           start_tmp = next;
5020           forward_chars_with_skipping (&start_tmp, offset,
5021                                        visible_only, !slice);
5022
5023           if (limit &&
5024               gtk_text_iter_compare (limit, &start_tmp) > 0)
5025             goto out; /* match was bogus */
5026           
5027           if (match_start)
5028             *match_start = start_tmp;
5029
5030           /* Go to end of search string */
5031           l = lines;
5032           while (*l)
5033             {
5034               offset += g_utf8_strlen (*l, -1);
5035               ++l;
5036             }
5037
5038           forward_chars_with_skipping (&next, offset,
5039                                        visible_only, !slice);
5040
5041           if (match_end)
5042             *match_end = next;
5043
5044           retval = TRUE;
5045           goto out;
5046         }
5047     }
5048   while (lines_window_back (&win));
5049
5050  out:
5051   lines_window_free (&win);
5052   g_strfreev (lines);
5053   
5054   return retval;
5055 }
5056
5057 /*
5058  * Comparisons
5059  */
5060
5061 /**
5062  * gtk_text_iter_equal:
5063  * @lhs: a #GtkTextIter
5064  * @rhs: another #GtkTextIter
5065  * 
5066  * Tests whether two iterators are equal, using the fastest possible
5067  * mechanism. This function is very fast; you can expect it to perform
5068  * better than e.g. getting the character offset for each iterator and
5069  * comparing the offsets yourself. Also, it's a bit faster than
5070  * gtk_text_iter_compare().
5071  * 
5072  * Return value: %TRUE if the iterators point to the same place in the buffer
5073  **/
5074 gboolean
5075 gtk_text_iter_equal (const GtkTextIter *lhs,
5076                      const GtkTextIter *rhs)
5077 {
5078   GtkTextRealIter *real_lhs;
5079   GtkTextRealIter *real_rhs;
5080
5081   real_lhs = (GtkTextRealIter*)lhs;
5082   real_rhs = (GtkTextRealIter*)rhs;
5083
5084   check_invariants (lhs);
5085   check_invariants (rhs);
5086
5087   if (real_lhs->line != real_rhs->line)
5088     return FALSE;
5089   else if (real_lhs->line_byte_offset >= 0 &&
5090            real_rhs->line_byte_offset >= 0)
5091     return real_lhs->line_byte_offset == real_rhs->line_byte_offset;
5092   else
5093     {
5094       /* the ensure_char_offsets () calls do nothing if the char offsets
5095          are already up-to-date. */
5096       ensure_char_offsets (real_lhs);
5097       ensure_char_offsets (real_rhs);
5098       return real_lhs->line_char_offset == real_rhs->line_char_offset;
5099     }
5100 }
5101
5102 /**
5103  * gtk_text_iter_compare:
5104  * @lhs: a #GtkTextIter
5105  * @rhs: another #GtkTextIter
5106  * 
5107  * A qsort()-style function that returns negative if @lhs is less than
5108  * @rhs, positive if @lhs is greater than @rhs, and 0 if they're equal.
5109  * Ordering is in character offset order, i.e. the first character in the buffer
5110  * is less than the second character in the buffer.
5111  * 
5112  * Return value: -1 if @lhs is less than @rhs, 1 if @lhs is greater, 0 if they are equal
5113  **/
5114 gint
5115 gtk_text_iter_compare (const GtkTextIter *lhs,
5116                        const GtkTextIter *rhs)
5117 {
5118   GtkTextRealIter *real_lhs;
5119   GtkTextRealIter *real_rhs;
5120
5121   real_lhs = gtk_text_iter_make_surreal (lhs);
5122   real_rhs = gtk_text_iter_make_surreal (rhs);
5123
5124   if (real_lhs == NULL ||
5125       real_rhs == NULL)
5126     return -1; /* why not */
5127
5128   check_invariants (lhs);
5129   check_invariants (rhs);
5130   
5131   if (real_lhs->line == real_rhs->line)
5132     {
5133       gint left_index, right_index;
5134
5135       if (real_lhs->line_byte_offset >= 0 &&
5136           real_rhs->line_byte_offset >= 0)
5137         {
5138           left_index = real_lhs->line_byte_offset;
5139           right_index = real_rhs->line_byte_offset;
5140         }
5141       else
5142         {
5143           /* the ensure_char_offsets () calls do nothing if
5144              the offsets are already up-to-date. */
5145           ensure_char_offsets (real_lhs);
5146           ensure_char_offsets (real_rhs);
5147           left_index = real_lhs->line_char_offset;
5148           right_index = real_rhs->line_char_offset;
5149         }
5150
5151       if (left_index < right_index)
5152         return -1;
5153       else if (left_index > right_index)
5154         return 1;
5155       else
5156         return 0;
5157     }
5158   else
5159     {
5160       gint line1, line2;
5161
5162       line1 = gtk_text_iter_get_line (lhs);
5163       line2 = gtk_text_iter_get_line (rhs);
5164       if (line1 < line2)
5165         return -1;
5166       else if (line1 > line2)
5167         return 1;
5168       else
5169         return 0;
5170     }
5171 }
5172
5173 /**
5174  * gtk_text_iter_in_range:
5175  * @iter: a #GtkTextIter
5176  * @start: start of range
5177  * @end: end of range
5178  * 
5179  * Checks whether @iter falls in the range [@start, @end).
5180  * @start and @end must be in ascending order.
5181  * 
5182  * Return value: %TRUE if @iter is in the range
5183  **/
5184 gboolean
5185 gtk_text_iter_in_range (const GtkTextIter *iter,
5186                         const GtkTextIter *start,
5187                         const GtkTextIter *end)
5188 {
5189   g_return_val_if_fail (iter != NULL, FALSE);
5190   g_return_val_if_fail (start != NULL, FALSE);
5191   g_return_val_if_fail (end != NULL, FALSE);
5192   g_return_val_if_fail (gtk_text_iter_compare (start, end) <= 0, FALSE);
5193   
5194   return gtk_text_iter_compare (iter, start) >= 0 &&
5195     gtk_text_iter_compare (iter, end) < 0;
5196 }
5197
5198 /**
5199  * gtk_text_iter_order:
5200  * @first: a #GtkTextIter
5201  * @second: another #GtkTextIter
5202  *
5203  * Swaps the value of @first and @second if @second comes before
5204  * @first in the buffer. That is, ensures that @first and @second are
5205  * in sequence. Most text buffer functions that take a range call this
5206  * automatically on your behalf, so there's no real reason to call it yourself
5207  * in those cases. There are some exceptions, such as gtk_text_iter_in_range(),
5208  * that expect a pre-sorted range.
5209  * 
5210  **/
5211 void
5212 gtk_text_iter_order (GtkTextIter *first,
5213                      GtkTextIter *second)
5214 {
5215   g_return_if_fail (first != NULL);
5216   g_return_if_fail (second != NULL);
5217
5218   if (gtk_text_iter_compare (first, second) > 0)
5219     {
5220       GtkTextIter tmp;
5221
5222       tmp = *first;
5223       *first = *second;
5224       *second = tmp;
5225     }
5226 }
5227
5228 /*
5229  * Init iterators from the BTree
5230  */
5231
5232 void
5233 _gtk_text_btree_get_iter_at_char (GtkTextBTree *tree,
5234                                   GtkTextIter *iter,
5235                                   gint char_index)
5236 {
5237   GtkTextRealIter *real = (GtkTextRealIter*)iter;
5238   gint real_char_index;
5239   gint line_start;
5240   GtkTextLine *line;
5241
5242   g_return_if_fail (iter != NULL);
5243   g_return_if_fail (tree != NULL);
5244
5245   line = _gtk_text_btree_get_line_at_char (tree, char_index,
5246                                            &line_start, &real_char_index);
5247
5248   iter_init_from_char_offset (iter, tree, line, real_char_index - line_start);
5249
5250   real->cached_char_index = real_char_index;
5251
5252   check_invariants (iter);
5253 }
5254
5255 void
5256 _gtk_text_btree_get_iter_at_line_char (GtkTextBTree *tree,
5257                                        GtkTextIter  *iter,
5258                                        gint          line_number,
5259                                        gint          char_on_line)
5260 {
5261   GtkTextRealIter *real = (GtkTextRealIter*)iter;
5262   GtkTextLine *line;
5263   gint real_line;
5264
5265   g_return_if_fail (iter != NULL);
5266   g_return_if_fail (tree != NULL);
5267
5268   line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5269   
5270   iter_init_from_char_offset (iter, tree, line, char_on_line);
5271
5272   /* We might as well cache this, since we know it. */
5273   real->cached_line_number = real_line;
5274
5275   check_invariants (iter);
5276 }
5277
5278 void
5279 _gtk_text_btree_get_iter_at_line_byte (GtkTextBTree   *tree,
5280                                        GtkTextIter    *iter,
5281                                        gint            line_number,
5282                                        gint            byte_index)
5283 {
5284   GtkTextRealIter *real = (GtkTextRealIter*)iter;
5285   GtkTextLine *line;
5286   gint real_line;
5287
5288   g_return_if_fail (iter != NULL);
5289   g_return_if_fail (tree != NULL);
5290
5291   line = _gtk_text_btree_get_line_no_last (tree, line_number, &real_line);
5292
5293   iter_init_from_byte_offset (iter, tree, line, byte_index);
5294
5295   /* We might as well cache this, since we know it. */
5296   real->cached_line_number = real_line;
5297
5298   check_invariants (iter);
5299 }
5300
5301 void
5302 _gtk_text_btree_get_iter_at_line      (GtkTextBTree   *tree,
5303                                        GtkTextIter    *iter,
5304                                        GtkTextLine    *line,
5305                                        gint            byte_offset)
5306 {
5307   g_return_if_fail (iter != NULL);
5308   g_return_if_fail (tree != NULL);
5309   g_return_if_fail (line != NULL);
5310
5311   iter_init_from_byte_offset (iter, tree, line, byte_offset);
5312
5313   check_invariants (iter);
5314 }
5315
5316 gboolean
5317 _gtk_text_btree_get_iter_at_first_toggle (GtkTextBTree   *tree,
5318                                           GtkTextIter    *iter,
5319                                           GtkTextTag     *tag)
5320 {
5321   GtkTextLine *line;
5322
5323   g_return_val_if_fail (iter != NULL, FALSE);
5324   g_return_val_if_fail (tree != NULL, FALSE);
5325
5326   line = _gtk_text_btree_first_could_contain_tag (tree, tag);
5327
5328   if (line == NULL)
5329     {
5330       /* Set iter to last in tree */
5331       _gtk_text_btree_get_end_iter (tree, iter);
5332       check_invariants (iter);
5333       return FALSE;
5334     }
5335   else
5336     {
5337       iter_init_from_byte_offset (iter, tree, line, 0);
5338
5339       if (!gtk_text_iter_toggles_tag (iter, tag))
5340         gtk_text_iter_forward_to_tag_toggle (iter, tag);
5341
5342       check_invariants (iter);
5343       return TRUE;
5344     }
5345 }
5346
5347 gboolean
5348 _gtk_text_btree_get_iter_at_last_toggle  (GtkTextBTree   *tree,
5349                                           GtkTextIter    *iter,
5350                                           GtkTextTag     *tag)
5351 {
5352   g_return_val_if_fail (iter != NULL, FALSE);
5353   g_return_val_if_fail (tree != NULL, FALSE);
5354
5355   _gtk_text_btree_get_end_iter (tree, iter);
5356   gtk_text_iter_backward_to_tag_toggle (iter, tag);
5357   check_invariants (iter);
5358   
5359   return TRUE;
5360 }
5361
5362 gboolean
5363 _gtk_text_btree_get_iter_at_mark_name (GtkTextBTree *tree,
5364                                        GtkTextIter *iter,
5365                                        const gchar *mark_name)
5366 {
5367   GtkTextMark *mark;
5368
5369   g_return_val_if_fail (iter != NULL, FALSE);
5370   g_return_val_if_fail (tree != NULL, FALSE);
5371
5372   mark = _gtk_text_btree_get_mark_by_name (tree, mark_name);
5373
5374   if (mark == NULL)
5375     return FALSE;
5376   else
5377     {
5378       _gtk_text_btree_get_iter_at_mark (tree, iter, mark);
5379       check_invariants (iter);
5380       return TRUE;
5381     }
5382 }
5383
5384 void
5385 _gtk_text_btree_get_iter_at_mark (GtkTextBTree *tree,
5386                                   GtkTextIter *iter,
5387                                   GtkTextMark *mark)
5388 {
5389   GtkTextLineSegment *seg;
5390
5391   g_return_if_fail (iter != NULL);
5392   g_return_if_fail (tree != NULL);
5393   g_return_if_fail (GTK_IS_TEXT_MARK (mark));
5394
5395   seg = mark->segment;
5396
5397   iter_init_from_segment (iter, tree,
5398                           seg->body.mark.line, seg);
5399   g_assert (seg->body.mark.line == _gtk_text_iter_get_text_line (iter));
5400   check_invariants (iter);
5401 }
5402
5403 void
5404 _gtk_text_btree_get_iter_at_child_anchor (GtkTextBTree       *tree,
5405                                           GtkTextIter        *iter,
5406                                           GtkTextChildAnchor *anchor)
5407 {
5408   GtkTextLineSegment *seg;
5409
5410   g_return_if_fail (iter != NULL);
5411   g_return_if_fail (tree != NULL);
5412   g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
5413   
5414   seg = anchor->segment;  
5415
5416   g_assert (seg->body.child.line != NULL);
5417   
5418   iter_init_from_segment (iter, tree,
5419                           seg->body.child.line, seg);
5420   g_assert (seg->body.child.line == _gtk_text_iter_get_text_line (iter));
5421   check_invariants (iter);
5422 }
5423
5424 void
5425 _gtk_text_btree_get_end_iter         (GtkTextBTree   *tree,
5426                                       GtkTextIter    *iter)
5427 {
5428   g_return_if_fail (iter != NULL);
5429   g_return_if_fail (tree != NULL);
5430
5431   _gtk_text_btree_get_iter_at_char (tree,
5432                                    iter,
5433                                    _gtk_text_btree_char_count (tree));
5434   check_invariants (iter);
5435 }
5436
5437 void
5438 _gtk_text_iter_check (const GtkTextIter *iter)
5439 {
5440   const GtkTextRealIter *real = (const GtkTextRealIter*)iter;
5441   gint line_char_offset, line_byte_offset, seg_char_offset, seg_byte_offset;
5442   GtkTextLineSegment *byte_segment = NULL;
5443   GtkTextLineSegment *byte_any_segment = NULL;
5444   GtkTextLineSegment *char_segment = NULL;
5445   GtkTextLineSegment *char_any_segment = NULL;
5446   gboolean segments_updated;
5447
5448   /* This function checks our class invariants for the Iter class. */
5449
5450   g_assert (sizeof (GtkTextIter) == sizeof (GtkTextRealIter));
5451
5452   if (real->chars_changed_stamp !=
5453       _gtk_text_btree_get_chars_changed_stamp (real->tree))
5454     g_error ("iterator check failed: invalid iterator");
5455
5456   if (real->line_char_offset < 0 && real->line_byte_offset < 0)
5457     g_error ("iterator check failed: both char and byte offsets are invalid");
5458
5459   segments_updated = (real->segments_changed_stamp ==
5460                       _gtk_text_btree_get_segments_changed_stamp (real->tree));
5461
5462 #if 0
5463   printf ("checking iter, segments %s updated, byte %d char %d\n",
5464           segments_updated ? "are" : "aren't",
5465           real->line_byte_offset,
5466           real->line_char_offset);
5467 #endif
5468
5469   if (segments_updated)
5470     {
5471       if (real->segment_char_offset < 0 && real->segment_byte_offset < 0)
5472         g_error ("iterator check failed: both char and byte segment offsets are invalid");
5473
5474       if (real->segment->char_count == 0)
5475         g_error ("iterator check failed: segment is not indexable.");
5476
5477       if (real->line_char_offset >= 0 && real->segment_char_offset < 0)
5478         g_error ("segment char offset is not properly up-to-date");
5479
5480       if (real->line_byte_offset >= 0 && real->segment_byte_offset < 0)
5481         g_error ("segment byte offset is not properly up-to-date");
5482
5483       if (real->segment_byte_offset >= 0 &&
5484           real->segment_byte_offset >= real->segment->byte_count)
5485         g_error ("segment byte offset is too large.");
5486
5487       if (real->segment_char_offset >= 0 &&
5488           real->segment_char_offset >= real->segment->char_count)
5489         g_error ("segment char offset is too large.");
5490     }
5491
5492   if (real->line_byte_offset >= 0)
5493     {
5494       _gtk_text_line_byte_locate (real->line, real->line_byte_offset,
5495                                   &byte_segment, &byte_any_segment,
5496                                   &seg_byte_offset, &line_byte_offset);
5497
5498       if (line_byte_offset != real->line_byte_offset)
5499         g_error ("wrong byte offset was stored in iterator");
5500
5501       if (segments_updated)
5502         {
5503           if (real->segment != byte_segment)
5504             g_error ("wrong segment was stored in iterator");
5505
5506           if (real->any_segment != byte_any_segment)
5507             g_error ("wrong any_segment was stored in iterator");
5508
5509           if (seg_byte_offset != real->segment_byte_offset)
5510             g_error ("wrong segment byte offset was stored in iterator");
5511
5512           if (byte_segment->type == &gtk_text_char_type)
5513             {
5514               const gchar *p;
5515               p = byte_segment->body.chars + seg_byte_offset;
5516               
5517               if (!gtk_text_byte_begins_utf8_char (p))
5518                 g_error ("broken iterator byte index pointed into the middle of a character");
5519             }
5520         }
5521     }
5522
5523   if (real->line_char_offset >= 0)
5524     {
5525       _gtk_text_line_char_locate (real->line, real->line_char_offset,
5526                                   &char_segment, &char_any_segment,
5527                                   &seg_char_offset, &line_char_offset);
5528
5529       if (line_char_offset != real->line_char_offset)
5530         g_error ("wrong char offset was stored in iterator");
5531
5532       if (segments_updated)
5533         {          
5534           if (real->segment != char_segment)
5535             g_error ("wrong segment was stored in iterator");
5536
5537           if (real->any_segment != char_any_segment)
5538             g_error ("wrong any_segment was stored in iterator");
5539
5540           if (seg_char_offset != real->segment_char_offset)
5541             g_error ("wrong segment char offset was stored in iterator");
5542
5543           if (char_segment->type == &gtk_text_char_type)
5544             {
5545               const gchar *p;
5546               p = g_utf8_offset_to_pointer (char_segment->body.chars,
5547                                             seg_char_offset);
5548
5549               /* hmm, not likely to happen eh */
5550               if (!gtk_text_byte_begins_utf8_char (p))
5551                 g_error ("broken iterator char offset pointed into the middle of a character");
5552             }
5553         }
5554     }
5555
5556   if (real->line_char_offset >= 0 && real->line_byte_offset >= 0)
5557     {
5558       if (byte_segment != char_segment)
5559         g_error ("char and byte offsets did not point to the same segment");
5560
5561       if (byte_any_segment != char_any_segment)
5562         g_error ("char and byte offsets did not point to the same any segment");
5563
5564       /* Make sure the segment offsets are equivalent, if it's a char
5565          segment. */
5566       if (char_segment->type == &gtk_text_char_type)
5567         {
5568           gint byte_offset = 0;
5569           gint char_offset = 0;
5570           while (char_offset < seg_char_offset)
5571             {
5572               const char * start = char_segment->body.chars + byte_offset;
5573               byte_offset += g_utf8_next_char (start) - start;
5574               char_offset += 1;
5575             }
5576
5577           if (byte_offset != seg_byte_offset)
5578             g_error ("byte offset did not correspond to char offset");
5579
5580           char_offset =
5581             g_utf8_strlen (char_segment->body.chars, seg_byte_offset);
5582
5583           if (char_offset != seg_char_offset)
5584             g_error ("char offset did not correspond to byte offset");
5585
5586           if (!gtk_text_byte_begins_utf8_char (char_segment->body.chars + seg_byte_offset))
5587             g_error ("byte index for iterator does not index the start of a character");
5588         }
5589     }
5590
5591   if (real->cached_line_number >= 0)
5592     {
5593       gint should_be;
5594
5595       should_be = _gtk_text_line_get_number (real->line);
5596       if (real->cached_line_number != should_be)
5597         g_error ("wrong line number was cached");
5598     }
5599
5600   if (real->cached_char_index >= 0)
5601     {
5602       if (real->line_char_offset >= 0) /* only way we can check it
5603                                           efficiently, not a real
5604                                           invariant. */
5605         {
5606           gint char_index;
5607
5608           char_index = _gtk_text_line_char_index (real->line);
5609           char_index += real->line_char_offset;
5610
5611           if (real->cached_char_index != char_index)
5612             g_error ("wrong char index was cached");
5613         }
5614     }
5615
5616   if (_gtk_text_line_is_last (real->line, real->tree))
5617     g_error ("Iterator was on last line (past the end iterator)");
5618 }
5619
5620 #define __GTK_TEXT_ITER_C__
5621 #include "gtkaliasdef.c"