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