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