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