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