summaryrefslogtreecommitdiff
path: root/ext/unicode/transform.c
blob: 9ecf867de299bfea5ff34aa1c68b2947d063f4f3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/*
   +----------------------------------------------------------------------+
   | PHP Version 6                                                        |
   +----------------------------------------------------------------------+
   | This source file is subject to version 3.01 of the PHP license,      |
   | that is bundled with this package in the file LICENSE, and is        |
   | available through the world-wide-web at the following url:           |
   | http://www.php.net/license/3_01.txt                                  |
   | If you did not receive a copy of the PHP license and are unable to   |
   | obtain it through the world-wide-web, please send a note to          |
   | license@php.net so we can mail you a copy immediately.               |
   +----------------------------------------------------------------------+
   | Authors: Andrei Zmievski <andrei@php.net>                            |
   +----------------------------------------------------------------------+
 */

/* $Id$ */ 

#include "php_unicode.h"

/* {{{ proto string str_transliterate(string str, string from_script, string to_script[, string variant]) U
   Transliterate a string from the source script to the target script */
PHP_FUNCTION(str_transliterate)
{
	UChar	   *str, *from, *to, *variant = NULL;
	int			str_len, from_len, to_len, variant_len = 0;
	UChar		id[256];
	int			id_len;
	UChar	   *result = NULL;
	int			result_len = 0;
	UTransliterator *trans = NULL;
	UErrorCode	status = U_ZERO_ERROR;
	int32_t		capacity, limit;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "uuu|u", &str,
							  &str_len, &from, &from_len, &to, &to_len,
							  &variant, &variant_len) == FAILURE) {
		return;
	}

	if (variant) {
		id_len = u_snprintf(id, TEXT_CHARS(sizeof(id))-1, "%S-%S/%S", from, to, variant);
	} else {
		id_len = u_snprintf(id, TEXT_CHARS(sizeof(id))-1, "%S-%S", from, to);
	}

	if (id_len < 0) {
		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Transliterator ID too long");
		return;
	}

	id[id_len] = 0;

	trans = utrans_openU(id, id_len, UTRANS_FORWARD, NULL, 0, NULL, &status);
	if (U_FAILURE(status)) {
		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to create transliterator");
		return;
	}

	result = eustrndup(str, str_len);
	result_len = limit = str_len;
	capacity = str_len + 1;

	while (1) {
		utrans_transUChars(trans, result, &result_len, capacity, 0, &limit, &status);
		if (status == U_BUFFER_OVERFLOW_ERROR) {
			result = eurealloc(result, result_len + 1);
			memcpy(result, str, UBYTES(str_len));
			capacity = result_len + 1;
			result_len = limit = str_len;
			status = U_ZERO_ERROR;
			utrans_transUChars(trans, result, &result_len, capacity, 0, &limit, &status);
		} else {
			if (status == U_STRING_NOT_TERMINATED_WARNING) {
				result = eurealloc(result, result_len + 1);
			}
			break;
		}
	}

	result[result_len] = 0;
	utrans_close(trans);

	RETURN_UNICODEL(result, result_len, 0);
}
/* }}} */

/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 * vim600: noet sw=4 ts=4 fdm=marker
 * vim<600: noet sw=4 ts=4
 */