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