| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | UNIT * |
| | FUNC (uninorm_t nf, const UNIT *s, size_t n, |
| | UNIT *resultbuf, size_t *lengthp) |
| | { |
| | int (*decomposer) (ucs4_t uc, ucs4_t *decomposition) = nf->decomposer; |
| | ucs4_t (*composer) (ucs4_t uc1, ucs4_t uc2) = nf->composer; |
| |
|
| | |
| | UNIT *result; |
| | size_t length; |
| | size_t allocated; |
| | |
| | #define SORTBUF_PREALLOCATED 64 |
| | struct ucs4_with_ccc sortbuf_preallocated[2 * SORTBUF_PREALLOCATED]; |
| | struct ucs4_with_ccc *sortbuf; |
| | size_t sortbuf_allocated; |
| | size_t sortbuf_count; |
| |
|
| | |
| | if (resultbuf == NULL) |
| | { |
| | result = NULL; |
| | allocated = 0; |
| | } |
| | else |
| | { |
| | result = resultbuf; |
| | allocated = *lengthp; |
| | } |
| | length = 0; |
| |
|
| | |
| | sortbuf = sortbuf_preallocated; |
| | sortbuf_allocated = SORTBUF_PREALLOCATED; |
| | sortbuf_count = 0; |
| |
|
| | { |
| | const UNIT *s_end = s + n; |
| |
|
| | for (;;) |
| | { |
| | int count; |
| | ucs4_t decomposed[UC_DECOMPOSITION_MAX_LENGTH]; |
| | int decomposed_count; |
| | int i; |
| |
|
| | if (s < s_end) |
| | { |
| | |
| | count = U_MBTOUC_UNSAFE (&decomposed[0], s, s_end - s); |
| | decomposed_count = 1; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | { |
| | int curr; |
| |
|
| | for (curr = 0; curr < decomposed_count; ) |
| | { |
| | |
| | |
| | ucs4_t curr_decomposed[UC_DECOMPOSITION_MAX_LENGTH]; |
| | int curr_decomposed_count; |
| |
|
| | curr_decomposed_count = decomposer (decomposed[curr], curr_decomposed); |
| | if (curr_decomposed_count >= 0) |
| | { |
| | |
| | |
| | |
| | int shift = curr_decomposed_count - 1; |
| |
|
| | if (shift < 0) |
| | abort (); |
| | if (shift > 0) |
| | { |
| | int j; |
| |
|
| | decomposed_count += shift; |
| | if (decomposed_count > UC_DECOMPOSITION_MAX_LENGTH) |
| | abort (); |
| | for (j = decomposed_count - 1 - shift; j > curr; j--) |
| | decomposed[j + shift] = decomposed[j]; |
| | } |
| | for (; shift >= 0; shift--) |
| | decomposed[curr + shift] = curr_decomposed[shift]; |
| | } |
| | else |
| | { |
| | |
| | curr++; |
| | } |
| | } |
| | } |
| | } |
| | else |
| | { |
| | count = 0; |
| | decomposed_count = 0; |
| | } |
| |
|
| | i = 0; |
| | for (;;) |
| | { |
| | ucs4_t uc; |
| | int ccc; |
| |
|
| | if (s < s_end) |
| | { |
| | |
| | if (i == decomposed_count) |
| | break; |
| | uc = decomposed[i]; |
| | ccc = uc_combining_class (uc); |
| | } |
| | else |
| | { |
| | |
| | uc = 0; |
| | ccc = 0; |
| | } |
| |
|
| | if (ccc == 0) |
| | { |
| | size_t j; |
| |
|
| | |
| | |
| | if (sortbuf_count > 1) |
| | gl_uninorm_decompose_merge_sort_inplace (sortbuf, sortbuf_count, |
| | sortbuf + sortbuf_count); |
| |
|
| | if (composer != NULL) |
| | { |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | if (sortbuf_count > 0 && sortbuf[0].ccc == 0) |
| | { |
| | for (j = 1; j < sortbuf_count; ) |
| | { |
| | if (sortbuf[j].ccc > sortbuf[j - 1].ccc) |
| | { |
| | ucs4_t combined = |
| | composer (sortbuf[0].code, sortbuf[j].code); |
| | if (combined) |
| | { |
| | size_t k; |
| |
|
| | sortbuf[0].code = combined; |
| | |
| | for (k = j + 1; k < sortbuf_count; k++) |
| | sortbuf[k - 1] = sortbuf[k]; |
| | sortbuf_count--; |
| | continue; |
| | } |
| | } |
| | j++; |
| | } |
| | if (s < s_end && sortbuf_count == 1) |
| | { |
| | ucs4_t combined = |
| | composer (sortbuf[0].code, uc); |
| | if (combined) |
| | { |
| | uc = combined; |
| | ccc = 0; |
| | |
| | |
| | |
| | sortbuf_count = 0; |
| | } |
| | } |
| | } |
| | } |
| |
|
| | for (j = 0; j < sortbuf_count; j++) |
| | { |
| | ucs4_t muc = sortbuf[j].code; |
| |
|
| | |
| | if (length < allocated) |
| | { |
| | int ret = |
| | U_UCTOMB (result + length, muc, allocated - length); |
| | if (ret == -1) |
| | { |
| | errno = EINVAL; |
| | goto fail; |
| | } |
| | if (ret >= 0) |
| | { |
| | length += ret; |
| | goto done_appending; |
| | } |
| | } |
| | { |
| | size_t old_allocated = allocated; |
| | size_t new_allocated = 2 * old_allocated; |
| | if (new_allocated < 64) |
| | new_allocated = 64; |
| | if (new_allocated < old_allocated) |
| | abort (); |
| | { |
| | UNIT *larger_result; |
| | if (result == NULL) |
| | { |
| | larger_result = |
| | (UNIT *) malloc (new_allocated * sizeof (UNIT)); |
| | if (larger_result == NULL) |
| | { |
| | errno = ENOMEM; |
| | goto fail; |
| | } |
| | } |
| | else if (result == resultbuf) |
| | { |
| | larger_result = |
| | (UNIT *) malloc (new_allocated * sizeof (UNIT)); |
| | if (larger_result == NULL) |
| | { |
| | errno = ENOMEM; |
| | goto fail; |
| | } |
| | U_CPY (larger_result, resultbuf, length); |
| | } |
| | else |
| | { |
| | larger_result = |
| | (UNIT *) realloc (result, new_allocated * sizeof (UNIT)); |
| | if (larger_result == NULL) |
| | { |
| | errno = ENOMEM; |
| | goto fail; |
| | } |
| | } |
| | result = larger_result; |
| | allocated = new_allocated; |
| | { |
| | int ret = |
| | U_UCTOMB (result + length, muc, allocated - length); |
| | if (ret == -1) |
| | { |
| | errno = EINVAL; |
| | goto fail; |
| | } |
| | if (ret < 0) |
| | abort (); |
| | length += ret; |
| | goto done_appending; |
| | } |
| | } |
| | } |
| | done_appending: ; |
| | } |
| |
|
| | |
| | sortbuf_count = 0; |
| | } |
| |
|
| | if (!(s < s_end)) |
| | |
| | break; |
| |
|
| | |
| | if (sortbuf_count == sortbuf_allocated) |
| | { |
| | struct ucs4_with_ccc *new_sortbuf; |
| |
|
| | sortbuf_allocated = 2 * sortbuf_allocated; |
| | if (sortbuf_allocated < sortbuf_count) |
| | abort (); |
| | new_sortbuf = |
| | (struct ucs4_with_ccc *) malloc (2 * sortbuf_allocated * sizeof (struct ucs4_with_ccc)); |
| | if (new_sortbuf == NULL) |
| | { |
| | errno = ENOMEM; |
| | goto fail; |
| | } |
| | memcpy (new_sortbuf, sortbuf, |
| | sortbuf_count * sizeof (struct ucs4_with_ccc)); |
| | if (sortbuf != sortbuf_preallocated) |
| | free (sortbuf); |
| | sortbuf = new_sortbuf; |
| | } |
| | sortbuf[sortbuf_count].code = uc; |
| | sortbuf[sortbuf_count].ccc = ccc; |
| | sortbuf_count++; |
| |
|
| | i++; |
| | } |
| |
|
| | if (!(s < s_end)) |
| | |
| | break; |
| |
|
| | s += count; |
| | } |
| | } |
| |
|
| | if (length == 0) |
| | { |
| | if (result == NULL) |
| | { |
| | |
| | result = (UNIT *) malloc (1); |
| | if (result == NULL) |
| | { |
| | errno = ENOMEM; |
| | goto fail; |
| | } |
| | } |
| | } |
| | else if (result != resultbuf && length < allocated) |
| | { |
| | |
| | UNIT *memory; |
| |
|
| | memory = (UNIT *) realloc (result, length * sizeof (UNIT)); |
| | if (memory != NULL) |
| | result = memory; |
| | } |
| |
|
| | if (sortbuf_count > 0) |
| | abort (); |
| | if (sortbuf != sortbuf_preallocated) |
| | free (sortbuf); |
| |
|
| | *lengthp = length; |
| | return result; |
| |
|
| | fail: |
| | { |
| | int saved_errno = errno; |
| | if (sortbuf != sortbuf_preallocated) |
| | free (sortbuf); |
| | if (result != resultbuf) |
| | free (result); |
| | errno = saved_errno; |
| | } |
| | return NULL; |
| | } |
| |
|