]> git.sur5r.net Git - openldap/blob - libraries/liblunicode/ucdata/ucpgba.c
ITS#1708 ldap_pvt_tls_sb_ctx() et al
[openldap] / libraries / liblunicode / ucdata / ucpgba.c
1 /*
2  * Copyright 2001 Computing Research Labs, New Mexico State University
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
18  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
19  * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
20  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 #ifndef lint
23 #ifdef __GNUC__
24 static char rcsid[] __attribute__ ((unused)) = "$Id: ucpgba.c,v 1.5 2001/01/02 18:46:20 mleisher Exp $";
25 #else
26 static char rcsid[] = "$Id: ucpgba.c,v 1.5 2001/01/02 18:46:20 mleisher Exp $";
27 #endif
28 #endif
29
30 #include "portable.h"
31
32 #include <stdio.h>
33 #include <stdlib.h>
34
35 #include "ucdata.h"
36 #include "ucpgba.h"
37
38 /*
39  * These macros are used while reordering of RTL runs of text for the
40  * special case of non-spacing characters being in runs of weakly
41  * directional text.  They check for weak and non-spacing, and digits and
42  * non-spacing.
43  */
44 #define ISWEAKSPECIAL(cc)  ucisprop(cc, UC_EN|UC_ES|UC_MN, UC_ET|UC_AN|UC_CS)
45 #define ISDIGITSPECIAL(cc) ucisprop(cc, UC_ND|UC_MN, 0)
46
47 /*
48  * These macros are used while breaking a string into runs of text in
49  * different directions.  Descriptions:
50  *
51  * ISLTR_LTR - Test for members of an LTR run in an LTR context.  This looks
52  *             for characters with ltr, non-spacing, weak, and neutral
53  *             properties.
54  *
55  * ISRTL_RTL - Test for members of an RTL run in an RTL context.  This looks
56  *             for characters with rtl, non-spacing, weak, and neutral
57  *             properties.
58  *
59  * ISRTL_NEUTRAL  - Test for RTL or neutral characters.
60  *
61  * ISWEAK_NEUTRAL - Test for weak or neutral characters.
62  */
63 #define ISLTR_LTR(cc) ucisprop(cc, UC_L|UC_MN|UC_EN|UC_ES,\
64                                UC_ET|UC_CS|UC_B|UC_S|UC_WS|UC_ON)
65
66 #define ISRTL_RTL(cc) ucisprop(cc, UC_R|UC_MN|UC_EN|UC_ES,\
67                                UC_ET|UC_AN|UC_CS|UC_B|UC_S|UC_WS|UC_ON)
68
69 #define ISRTL_NEUTRAL(cc) ucisprop(cc, UC_R, UC_B|UC_S|UC_WS|UC_ON)
70 #define ISWEAK_NEUTRAL(cc) ucisprop(cc, UC_EN|UC_ES, \
71                                     UC_B|UC_S|UC_WS|UC_ON|UC_ET|UC_AN|UC_CS)
72
73 /*
74  * This table is temporarily hard-coded here until it can be constructed
75  * automatically somehow.
76  */
77 static unsigned long _symmetric_pairs[] = {
78     0x0028, 0x0029, 0x0029, 0x0028, 0x003C, 0x003E, 0x003E, 0x003C,
79     0x005B, 0x005D, 0x005D, 0x005B, 0x007B, 0x007D, 0x007D, 0x007B,
80     0x2045, 0x2046, 0x2046, 0x2045, 0x207D, 0x207E, 0x207E, 0x207D,
81     0x208D, 0x208E, 0x208E, 0x208D, 0x3008, 0x3009, 0x3009, 0x3008,
82     0x300A, 0x300B, 0x300B, 0x300A, 0x300C, 0x300D, 0x300D, 0x300C,
83     0x300E, 0x300F, 0x300F, 0x300E, 0x3010, 0x3011, 0x3011, 0x3010,
84     0x3014, 0x3015, 0x3015, 0x3014, 0x3016, 0x3017, 0x3017, 0x3016,
85     0x3018, 0x3019, 0x3019, 0x3018, 0x301A, 0x301B, 0x301B, 0x301A,
86     0xFD3E, 0xFD3F, 0xFD3F, 0xFD3E, 0xFE59, 0xFE5A, 0xFE5A, 0xFE59,
87     0xFE5B, 0xFE5C, 0xFE5C, 0xFE5B, 0xFE5D, 0xFE5E, 0xFE5E, 0xFE5D,
88     0xFF08, 0xFF09, 0xFF09, 0xFF08, 0xFF3B, 0xFF3D, 0xFF3D, 0xFF3B,
89     0xFF5B, 0xFF5D, 0xFF5D, 0xFF5B, 0xFF62, 0xFF63, 0xFF63, 0xFF62,
90 };
91
92 static int _symmetric_pairs_size =
93 sizeof(_symmetric_pairs)/sizeof(_symmetric_pairs[0]);
94
95 /*
96  * This routine looks up the other form of a symmetric pair.
97  */
98 static unsigned long
99 _ucsymmetric_pair(unsigned long c)
100 {
101     int i;
102
103     for (i = 0; i < _symmetric_pairs_size; i += 2) {
104         if (_symmetric_pairs[i] == c)
105           return _symmetric_pairs[i+1];
106     }
107     return c;
108 }
109
110 /*
111  * This routine creates a new run, copies the text into it, links it into the
112  * logical text order chain and returns it to the caller to be linked into
113  * the visual text order chain.
114  */
115 static ucrun_t *
116 _add_run(ucstring_t *str, unsigned long *src,
117          unsigned long start, unsigned long end, int direction)
118 {
119     long i, t;
120     ucrun_t *run;
121
122     run = (ucrun_t *) malloc(sizeof(ucrun_t));
123     run->visual_next = run->visual_prev = 0;
124     run->direction = direction;
125
126     run->cursor = ~0;
127
128     run->chars = (unsigned long *)
129         malloc(sizeof(unsigned long) * ((end - start) << 1));
130     run->positions = run->chars + (end - start);
131
132     run->source = src;
133     run->start = start;
134     run->end = end;
135
136     if (direction == UCPGBA_RTL) {
137         /*
138          * Copy the source text into the run in reverse order and select
139          * replacements for the pairwise punctuation and the <> characters.
140          */
141         for (i = 0, t = end - 1; start < end; start++, t--, i++) {
142             run->positions[i] = t;
143             if (ucissymmetric(src[t]) || src[t] == '<' || src[t] == '>')
144               run->chars[i] = _ucsymmetric_pair(src[t]);
145             else
146               run->chars[i] = src[t];
147         }
148     } else {
149         /*
150          * Copy the source text into the run directly.
151          */
152         for (i = start; i < end; i++) {
153             run->positions[i - start] = i;
154             run->chars[i - start] = src[i];
155         }
156     }
157
158     /*
159      * Add the run to the logical list for cursor traversal.
160      */
161     if (str->logical_first == 0)
162       str->logical_first = str->logical_last = run;
163     else {
164         run->logical_prev = str->logical_last;
165         str->logical_last->logical_next = run;
166         str->logical_last = run;
167     }
168
169     return run;
170 }
171
172 static void
173 _ucadd_rtl_segment(ucstring_t *str, unsigned long *source, unsigned long start,
174                    unsigned long end)
175 {
176     unsigned long s, e;
177     ucrun_t *run, *lrun;
178
179     /*
180      * This is used to splice runs into strings with overall LTR direction.
181      * The `lrun' variable will never be NULL because at least one LTR run was
182      * added before this RTL run.
183      */
184     lrun = str->visual_last;
185
186     for (e = s = start; s < end;) {
187         for (; e < end && ISRTL_NEUTRAL(source[e]); e++) ;
188
189         if (e > s) {
190             run = _add_run(str, source, s, e, UCPGBA_RTL);
191
192             /*
193              * Add the run to the visual list for cursor traversal.
194              */
195             if (str->visual_first != 0) {
196                 if (str->direction == UCPGBA_LTR) {
197                     run->visual_prev = lrun;
198                     run->visual_next = lrun->visual_next;
199                     if (lrun->visual_next != 0)
200                       lrun->visual_next->visual_prev = run;
201                     lrun->visual_next = run;
202                     if (lrun == str->visual_last)
203                       str->visual_last = run;
204                 } else {
205                     run->visual_next = str->visual_first;
206                     str->visual_first->visual_prev = run;
207                     str->visual_first = run;
208                 }
209             } else
210               str->visual_first = str->visual_last = run;
211         }
212
213         /*
214          * Handle digits in a special way.  This makes sure the weakly
215          * directional characters appear on the expected sides of a number
216          * depending on whether that number is Arabic or not.
217          */
218         for (s = e; e < end && ISWEAKSPECIAL(source[e]); e++) {
219             if (!ISDIGITSPECIAL(source[e]) &&
220                 (e + 1 == end || !ISDIGITSPECIAL(source[e + 1])))
221               break;
222         }
223
224         if (e > s) {
225             run = _add_run(str, source, s, e, UCPGBA_LTR);
226
227             /*
228              * Add the run to the visual list for cursor traversal.
229              */
230             if (str->visual_first != 0) {
231                 if (str->direction == UCPGBA_LTR) {
232                     run->visual_prev = lrun;
233                     run->visual_next = lrun->visual_next;
234                     if (lrun->visual_next != 0)
235                       lrun->visual_next->visual_prev = run;
236                     lrun->visual_next = run;
237                     if (lrun == str->visual_last)
238                       str->visual_last = run;
239                 } else {
240                     run->visual_next = str->visual_first;
241                     str->visual_first->visual_prev = run;
242                     str->visual_first = run;
243                 }
244             } else
245               str->visual_first = str->visual_last = run;
246         }
247
248         /*
249          * Collect all weak non-digit sequences for an RTL segment.  These
250          * will appear as part of the next RTL segment or will be added as
251          * an RTL segment by themselves.
252          */
253         for (s = e; e < end && ucisweak(source[e]) && !ucisdigit(source[e]);
254              e++) ;
255     }
256
257     /*
258      * Capture any weak non-digit sequences that occur at the end of the RTL
259      * run.
260      */
261     if (e > s) {
262         run = _add_run(str, source, s, e, UCPGBA_RTL);
263
264         /*
265          * Add the run to the visual list for cursor traversal.
266          */
267         if (str->visual_first != 0) {
268             if (str->direction == UCPGBA_LTR) {
269                 run->visual_prev = lrun;
270                 run->visual_next = lrun->visual_next;
271                 if (lrun->visual_next != 0)
272                   lrun->visual_next->visual_prev = run;
273                 lrun->visual_next = run;
274                 if (lrun == str->visual_last)
275                   str->visual_last = run;
276             } else {
277                 run->visual_next = str->visual_first;
278                 str->visual_first->visual_prev = run;
279                 str->visual_first = run;
280             }
281         } else
282           str->visual_first = str->visual_last = run;
283     }
284 }
285
286 static void
287 _ucadd_ltr_segment(ucstring_t *str, unsigned long *source, unsigned long start,
288                    unsigned long end)
289 {
290     ucrun_t *run;
291
292     run = _add_run(str, source, start, end, UCPGBA_LTR);
293
294     /*
295      * Add the run to the visual list for cursor traversal.
296      */
297     if (str->visual_first != 0) {
298         if (str->direction == UCPGBA_LTR) {
299             run->visual_prev = str->visual_last;
300             str->visual_last->visual_next = run;
301             str->visual_last = run;
302         } else {
303             run->visual_next = str->visual_first;
304             str->visual_first->visual_prev = run;
305             str->visual_first = run;
306         }
307     } else
308       str->visual_first = str->visual_last = run;
309 }
310
311 ucstring_t *
312 ucstring_create(unsigned long *source, unsigned long start, unsigned long end,
313                 int default_direction, int cursor_motion)
314 {
315     int rtl_first;
316     unsigned long s, e, ld;
317     ucstring_t *str;
318
319     str = (ucstring_t *) malloc(sizeof(ucstring_t));
320
321     /*
322      * Set the initial values.
323      */
324     str->cursor_motion = cursor_motion;
325     str->logical_first = str->logical_last = 0;
326     str->visual_first = str->visual_last = str->cursor = 0;
327     str->source = source;
328     str->start = start;
329     str->end = end;
330
331     /*
332      * If the length of the string is 0, then just return it at this point.
333      */
334     if (start == end)
335       return str;
336
337     /*
338      * This flag indicates whether the collection loop for RTL is called
339      * before the LTR loop the first time.
340      */
341     rtl_first = 0;
342
343     /*
344      * Look for the first character in the string that has strong
345      * directionality.
346      */
347     for (s = start; s < end && !ucisstrong(source[s]); s++) ;
348
349     if (s == end)
350       /*
351        * If the string contains no characters with strong directionality, use
352        * the default direction.
353        */
354       str->direction = default_direction;
355     else
356       str->direction = ucisrtl(source[s]) ? UCPGBA_RTL : UCPGBA_LTR;
357
358     if (str->direction == UCPGBA_RTL)
359       /*
360        * Set the flag that causes the RTL collection loop to run first.
361        */
362       rtl_first = 1;
363
364     /*
365      * This loop now separates the string into runs based on directionality.
366      */
367     for (s = e = 0; s < end; s = e) {
368         if (!rtl_first) {
369             /*
370              * Determine the next run of LTR text.
371              */
372
373             ld = s;
374             while (e < end && ISLTR_LTR(source[e])) {
375                 if (ucisdigit(source[e]) &&
376                     !(0x660 <= source[e] && source[e] <= 0x669))
377                   ld = e;
378                 e++;
379             }
380             if (str->direction != UCPGBA_LTR) {
381                 while (e > ld && ISWEAK_NEUTRAL(source[e - 1]))
382                   e--;
383             }
384
385             /*
386              * Add the LTR segment to the string.
387              */
388             if (e > s)
389               _ucadd_ltr_segment(str, source, s, e);
390         }
391
392         /*
393          * Determine the next run of RTL text.
394          */
395         ld = s = e;
396         while (e < end && ISRTL_RTL(source[e])) {
397             if (ucisdigit(source[e]) &&
398                 !(0x660 <= source[e] && source[e] <= 0x669))
399               ld = e;
400             e++;
401         }
402         if (str->direction != UCPGBA_RTL) {
403             while (e > ld && ISWEAK_NEUTRAL(source[e - 1]))
404               e--;
405         }
406
407         /*
408          * Add the RTL segment to the string.
409          */
410         if (e > s)
411           _ucadd_rtl_segment(str, source, s, e);
412
413         /*
414          * Clear the flag that allowed the RTL collection loop to run first
415          * for strings with overall RTL directionality.
416          */
417         rtl_first = 0;
418     }
419
420     /*
421      * Set up the initial cursor run.
422      */
423     str->cursor = str->logical_first;
424     if (str != 0)
425       str->cursor->cursor = (str->cursor->direction == UCPGBA_RTL) ?
426           str->cursor->end - str->cursor->start : 0;
427
428     return str;
429 }
430
431 void
432 ucstring_free(ucstring_t *s)
433 {
434     ucrun_t *l, *r;
435
436     if (s == 0)
437       return;
438
439     for (l = 0, r = s->visual_first; r != 0; r = r->visual_next) {
440         if (r->end > r->start)
441           free((char *) r->chars);
442         if (l)
443           free((char *) l);
444         l = r;
445     }
446     if (l)
447       free((char *) l);
448
449     free((char *) s);
450 }
451
452 int
453 ucstring_set_cursor_motion(ucstring_t *str, int cursor_motion)
454 {
455     int n;
456
457     if (str == 0)
458       return -1;
459
460     n = str->cursor_motion;
461     str->cursor_motion = cursor_motion;
462     return n;
463 }
464
465 static int
466 _ucstring_visual_cursor_right(ucstring_t *str, int count)
467 {
468     int cnt = count;
469     unsigned long size;
470     ucrun_t *cursor;
471
472     if (str == 0)
473       return 0;
474
475     cursor = str->cursor;
476     while (cnt > 0) {
477         size = cursor->end - cursor->start;
478         if ((cursor->direction == UCPGBA_RTL && cursor->cursor + 1 == size) ||
479             cursor->cursor + 1 > size) {
480             /*
481              * If the next run is NULL, then the cursor is already on the
482              * far right end already.
483              */
484             if (cursor->visual_next == 0)
485               /*
486                * If movement occured, then report it.
487                */
488               return (cnt != count);
489
490             /*
491              * Move to the next run.
492              */
493             str->cursor = cursor = cursor->visual_next;
494             cursor->cursor = (cursor->direction == UCPGBA_RTL) ? -1 : 0;
495             size = cursor->end - cursor->start;
496         } else
497           cursor->cursor++;
498         cnt--;
499     }
500     return 1;
501 }
502
503 static int
504 _ucstring_logical_cursor_right(ucstring_t *str, int count)
505 {
506     int cnt = count;
507     unsigned long size;
508     ucrun_t *cursor;
509
510     if (str == 0)
511       return 0;
512
513     cursor = str->cursor;
514     while (cnt > 0) {
515         size = cursor->end - cursor->start;
516         if (str->direction == UCPGBA_RTL) {
517             if (cursor->direction == UCPGBA_RTL) {
518                 if (cursor->cursor + 1 == size) {
519                     if (cursor == str->logical_first)
520                       /*
521                        * Already at the beginning of the string.
522                        */
523                       return (cnt != count);
524
525                     str->cursor = cursor = cursor->logical_prev;
526                     size = cursor->end - cursor->start;
527                     cursor->cursor = (cursor->direction == UCPGBA_LTR) ?
528                         size : 0;
529                 } else
530                   cursor->cursor++;
531             } else {
532                 if (cursor->cursor == 0) {
533                     if (cursor == str->logical_first)
534                       /*
535                        * At the beginning of the string already.
536                        */
537                       return (cnt != count);
538
539                     str->cursor = cursor = cursor->logical_prev;
540                     size = cursor->end - cursor->start;
541                     cursor->cursor = (cursor->direction == UCPGBA_LTR) ?
542                         size : 0;
543                 } else
544                   cursor->cursor--;
545             }
546         } else {
547             if (cursor->direction == UCPGBA_RTL) {
548                 if (cursor->cursor == 0) {
549                     if (cursor == str->logical_last)
550                       /*
551                        * Already at the end of the string.
552                        */
553                       return (cnt != count);
554
555                     str->cursor = cursor = cursor->logical_next;
556                     size = cursor->end - cursor->start;
557                     cursor->cursor = (cursor->direction == UCPGBA_LTR) ?
558                         0 : size - 1;
559                 } else
560                   cursor->cursor--;
561             } else {
562                 if (cursor->cursor + 1 > size) {
563                     if (cursor == str->logical_last)
564                       /*
565                        * Already at the end of the string.
566                        */
567                       return (cnt != count);
568
569                     str->cursor = cursor = cursor->logical_next;
570                     cursor->cursor = (cursor->direction == UCPGBA_LTR) ?
571                         0 : size - 1;
572                 } else
573                   cursor->cursor++;
574             }
575         }
576         cnt--;
577     }
578     return 1;
579 }
580
581 int
582 ucstring_cursor_right(ucstring_t *str, int count)
583 {
584     if (str == 0)
585       return 0;
586     return (str->cursor_motion == UCPGBA_CURSOR_VISUAL) ?
587         _ucstring_visual_cursor_right(str, count) :
588         _ucstring_logical_cursor_right(str, count);
589 }
590
591 static int
592 _ucstring_visual_cursor_left(ucstring_t *str, int count)
593 {
594     int cnt = count;
595     unsigned long size;
596     ucrun_t *cursor;
597
598     if (str == 0)
599       return 0;
600
601     cursor = str->cursor;
602     while (cnt > 0) {
603         size = cursor->end - cursor->start;
604         if ((cursor->direction == UCPGBA_LTR && cursor->cursor == 0) ||
605             cursor->cursor - 1 < -1) {
606             /*
607              * If the preceding run is NULL, then the cursor is already on the
608              * far left end already.
609              */
610             if (cursor->visual_prev == 0)
611               /*
612                * If movement occured, then report it.
613                */
614               return (cnt != count);
615
616             /*
617              * Move to the previous run.
618              */
619             str->cursor = cursor = cursor->visual_prev;
620             size = cursor->end - cursor->start;
621             cursor->cursor = (cursor->direction == UCPGBA_RTL) ?
622                 size : size - 1;
623         } else
624           cursor->cursor--;
625         cnt--;
626     }
627     return 1;
628 }
629
630 static int
631 _ucstring_logical_cursor_left(ucstring_t *str, int count)
632 {
633     int cnt = count;
634     unsigned long size;
635     ucrun_t *cursor;
636
637     if (str == 0)
638       return 0;
639
640     cursor = str->cursor;
641     while (cnt > 0) {
642         size = cursor->end - cursor->start;
643         if (str->direction == UCPGBA_RTL) {
644             if (cursor->direction == UCPGBA_RTL) {
645                 if (cursor->cursor == -1) {
646                     if (cursor == str->logical_last)
647                       /*
648                        * Already at the end of the string.
649                        */
650                       return (cnt != count);
651
652                     str->cursor = cursor = cursor->logical_next;
653                     size = cursor->end - cursor->start;
654                     cursor->cursor = (cursor->direction == UCPGBA_LTR) ?
655                         0 : size - 1;
656                 } else
657                   cursor->cursor--;
658             } else {
659                 if (cursor->cursor + 1 > size) {
660                     if (cursor == str->logical_last)
661                       /*
662                        * At the end of the string already.
663                        */
664                       return (cnt != count);
665
666                     str->cursor = cursor = cursor->logical_next;
667                     size = cursor->end - cursor->start;
668                     cursor->cursor = (cursor->direction == UCPGBA_LTR) ?
669                         0 : size - 1;
670                 } else
671                   cursor->cursor++;
672             }
673         } else {
674             if (cursor->direction == UCPGBA_RTL) {
675                 if (cursor->cursor + 1 == size) {
676                     if (cursor == str->logical_first)
677                       /*
678                        * Already at the beginning of the string.
679                        */
680                       return (cnt != count);
681
682                     str->cursor = cursor = cursor->logical_prev;
683                     size = cursor->end - cursor->start;
684                     cursor->cursor = (cursor->direction == UCPGBA_LTR) ?
685                         size : 0;
686                 } else
687                   cursor->cursor++;
688             } else {
689                 if (cursor->cursor == 0) {
690                     if (cursor == str->logical_first)
691                       /*
692                        * Already at the beginning of the string.
693                        */
694                       return (cnt != count);
695
696                     str->cursor = cursor = cursor->logical_prev;
697                     cursor->cursor = (cursor->direction == UCPGBA_LTR) ?
698                         size : 0;
699                 } else
700                   cursor->cursor--;
701             }
702         }
703         cnt--;
704     }
705     return 1;
706 }
707
708 int
709 ucstring_cursor_left(ucstring_t *str, int count)
710 {
711     if (str == 0)
712       return 0;
713     return (str->cursor_motion == UCPGBA_CURSOR_VISUAL) ?
714         _ucstring_visual_cursor_left(str, count) :
715         _ucstring_logical_cursor_left(str, count);
716 }
717
718 void
719 ucstring_cursor_info(ucstring_t *str, int *direction, unsigned long *position)
720 {
721     long c;
722     unsigned long size;
723     ucrun_t *cursor;
724
725     if (str == 0 || direction == 0 || position == 0)
726       return;
727
728     cursor = str->cursor;
729
730     *direction = cursor->direction;
731
732     c = cursor->cursor;
733     size = cursor->end - cursor->start;
734
735     if (c == size)
736       *position = (cursor->direction == UCPGBA_RTL) ?
737           cursor->start : cursor->positions[c - 1];
738     else if (c == -1)
739       *position = (cursor->direction == UCPGBA_RTL) ?
740           cursor->end : cursor->start;
741     else
742       *position = cursor->positions[c];
743 }