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