~ubuntu-branches/ubuntu/maverick/krb5/maverick

« back to all changes in this revision

Viewing changes to src/lib/krb5/unicode/ucdata/ucpgba.c

  • Committer: Bazaar Package Importer
  • Author(s): Sam Hartman
  • Date: 2009-05-07 16:16:34 UTC
  • mfrom: (13.1.7 sid)
  • Revision ID: james.westby@ubuntu.com-20090507161634-xqyk0s9na0le4flj
Tags: 1.7dfsg~beta1-4
When  decrypting the TGS response fails with the subkey, try with the
session key to work around Heimdal bug, Closes: #527353 

Show diffs side-by-side

added added

removed removed

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