mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-17 02:37:25 +00:00
ICU-3651 uloc_setKeywordValue (partial: needs sorting and removal)
X-SVN-Rev: 16240
This commit is contained in:
parent
bd388e4f26
commit
feba47022c
2 changed files with 208 additions and 13 deletions
|
@ -540,6 +540,32 @@ locale_getKeywordsStart(const char *localeID) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param buf buffer of size [ULOC_KEYWORD_BUFFER_LEN]
|
||||
* @param keywordName incoming name to be canonicalized
|
||||
* @param status return status (keyword too long)
|
||||
* @return length of the keyword name
|
||||
*/
|
||||
static const char locale_canonKeywordName(char *buf, const char *keywordName, UErrorCode *status)
|
||||
{
|
||||
int32_t i;
|
||||
int32_t keywordNameLen = uprv_strlen(keywordName);
|
||||
|
||||
if(keywordNameLen >= ULOC_KEYWORD_BUFFER_LEN) {
|
||||
/* keyword name too long for internal buffer */
|
||||
*status = U_INTERNAL_PROGRAM_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* normalize the keyword name */
|
||||
for(i = 0; i < keywordNameLen; i++) {
|
||||
buf[i] = uprv_tolower(keywordName[i]);
|
||||
}
|
||||
buf[i] = 0;
|
||||
|
||||
return keywordNameLen;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char keyword[ULOC_KEYWORD_BUFFER_LEN];
|
||||
int32_t keywordLen;
|
||||
|
@ -746,7 +772,7 @@ uloc_getKeywordValue(const char* localeID,
|
|||
UErrorCode* status)
|
||||
{
|
||||
const char* nextSeparator = NULL;
|
||||
int32_t keywordNameLen = uprv_strlen(keywordName);
|
||||
int32_t keywordNameLen;
|
||||
char keywordNameBuffer[ULOC_KEYWORD_BUFFER_LEN];
|
||||
char localeKeywordNameBuffer[ULOC_KEYWORD_BUFFER_LEN];
|
||||
int32_t i = 0;
|
||||
|
@ -754,24 +780,17 @@ uloc_getKeywordValue(const char* localeID,
|
|||
|
||||
if(status && U_SUCCESS(*status) && localeID) {
|
||||
|
||||
const char* startSearchHere = uprv_strchr(localeID, '@');
|
||||
const char* startSearchHere = uprv_strchr(localeID, '@'); /* TODO: REVISIT: shouldn't this be locale_getKeywordsStart ? */
|
||||
if(startSearchHere == NULL) {
|
||||
/* no keywords, return at once */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(keywordNameLen >= ULOC_KEYWORD_BUFFER_LEN) {
|
||||
/* keyword name too long for internal buffer */
|
||||
*status = U_INTERNAL_PROGRAM_ERROR;
|
||||
return 0;
|
||||
|
||||
keywordNameLen = locale_canonKeywordName(keywordNameBuffer, keywordName, status);
|
||||
if(U_FAILURE(*status)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* normalize the keyword name */
|
||||
for(i = 0; i < keywordNameLen; i++) {
|
||||
keywordNameBuffer[i] = uprv_tolower(keywordName[i]);
|
||||
}
|
||||
keywordNameBuffer[i] = 0;
|
||||
|
||||
/* find the first keyword */
|
||||
while(startSearchHere) {
|
||||
startSearchHere++;
|
||||
|
@ -835,6 +854,157 @@ uloc_getKeywordValue(const char* localeID,
|
|||
return 0;
|
||||
}
|
||||
|
||||
U_CAPI int32_t U_EXPORT2
|
||||
uloc_setKeywordValue(const char* keywordName,
|
||||
const char* keywordValue,
|
||||
char* buffer, int32_t bufferCapacity,
|
||||
UErrorCode* status)
|
||||
{
|
||||
/* TODO: sorting. removal. */
|
||||
int32_t keywordNameLen;
|
||||
int32_t keywordValueLen;
|
||||
int32_t bufLen;
|
||||
int32_t needLen = 0;
|
||||
int32_t foundValueLen;
|
||||
char keywordNameBuffer[ULOC_KEYWORD_BUFFER_LEN];
|
||||
char localeKeywordNameBuffer[ULOC_KEYWORD_BUFFER_LEN];
|
||||
int32_t i = 0;
|
||||
char* nextSeparator = NULL;
|
||||
char* startSearchHere = NULL;
|
||||
if(U_FAILURE(*status)) {
|
||||
return -1;
|
||||
}
|
||||
if(!*keywordValue) {
|
||||
keywordValue = NULL;
|
||||
}
|
||||
if(keywordValue) {
|
||||
keywordValueLen = uprv_strlen(keywordValue);
|
||||
} else {
|
||||
keywordValueLen = 0;
|
||||
}
|
||||
keywordNameLen = locale_canonKeywordName(keywordNameBuffer, keywordName, status);
|
||||
if(U_FAILURE(*status)) {
|
||||
return 0;
|
||||
}
|
||||
startSearchHere = (char*)locale_getKeywordsStart(buffer);
|
||||
if(bufferCapacity>1) {
|
||||
bufLen = uprv_strlen(buffer);
|
||||
} else {
|
||||
*status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return 0;
|
||||
}
|
||||
if(startSearchHere == NULL || (startSearchHere[1]==NULL)) {
|
||||
if(!keywordValue) { /* no keywords = nothing to remove */
|
||||
return bufLen;
|
||||
}
|
||||
needLen = bufLen+1+keywordNameLen+1+keywordValueLen;
|
||||
if(startSearchHere) { /* had a single @ */
|
||||
needLen--; /* already had the @ */
|
||||
/* startSearchHere points at the @ */
|
||||
} else {
|
||||
startSearchHere=buffer+bufLen;
|
||||
}
|
||||
if(needLen >= bufferCapacity) {
|
||||
*status = U_BUFFER_OVERFLOW_ERROR;
|
||||
return needLen; /* no change */
|
||||
}
|
||||
*startSearchHere = '@';
|
||||
startSearchHere++;
|
||||
uprv_strcpy(startSearchHere, keywordNameBuffer);
|
||||
startSearchHere += keywordNameLen;
|
||||
*startSearchHere = '=';
|
||||
startSearchHere++;
|
||||
uprv_strcpy(startSearchHere, keywordValue);
|
||||
startSearchHere+=keywordValueLen;
|
||||
return needLen;
|
||||
} /* end shortcut - no @ */
|
||||
|
||||
/* search for keyword */
|
||||
while(startSearchHere) {
|
||||
startSearchHere++;
|
||||
/* skip leading spaces (allowed?) */
|
||||
while(*startSearchHere == ' ') {
|
||||
startSearchHere++;
|
||||
}
|
||||
nextSeparator = uprv_strchr(startSearchHere, '=');
|
||||
/* need to normalize both keyword and keyword name */
|
||||
if(!nextSeparator) {
|
||||
break;
|
||||
}
|
||||
if(nextSeparator - startSearchHere >= ULOC_KEYWORD_BUFFER_LEN) {
|
||||
/* keyword name too long for internal buffer */
|
||||
*status = U_INTERNAL_PROGRAM_ERROR;
|
||||
return 0;
|
||||
}
|
||||
for(i = 0; i < nextSeparator - startSearchHere; i++) {
|
||||
localeKeywordNameBuffer[i] = uprv_tolower(startSearchHere[i]);
|
||||
}
|
||||
/* trim trailing spaces */
|
||||
while(startSearchHere[i-1] == ' ') {
|
||||
i--;
|
||||
}
|
||||
localeKeywordNameBuffer[i] = 0;
|
||||
|
||||
startSearchHere = uprv_strchr(nextSeparator, ';');
|
||||
|
||||
if(uprv_strcmp(keywordNameBuffer, localeKeywordNameBuffer) == 0) {
|
||||
nextSeparator++;
|
||||
while(*nextSeparator == ' ') {
|
||||
nextSeparator++;
|
||||
}
|
||||
/* we actually found the keyword. Change the value */
|
||||
if (startSearchHere) {
|
||||
foundValueLen = startSearchHere - nextSeparator;
|
||||
} else {
|
||||
foundValueLen = uprv_strlen(nextSeparator);
|
||||
}
|
||||
if(foundValueLen == keywordValueLen) {
|
||||
uprv_strncpy(nextSeparator, keywordValue, keywordValueLen);
|
||||
return bufLen; /* no change in size */
|
||||
} else if(foundValueLen > keywordValueLen) {
|
||||
int32_t delta = foundValueLen - keywordValueLen;
|
||||
if(startSearchHere) { /* RH side */
|
||||
uprv_memmove(startSearchHere - delta, startSearchHere, bufLen-(startSearchHere-buffer));
|
||||
}
|
||||
uprv_strncpy(nextSeparator, keywordValue, keywordValueLen);
|
||||
bufLen -= delta;
|
||||
buffer[bufLen]=0;
|
||||
return bufLen;
|
||||
} else { /* FVL < KVL */
|
||||
int32_t delta = keywordValueLen - foundValueLen;
|
||||
if((bufLen+delta) >= bufferCapacity) {
|
||||
*status = U_BUFFER_OVERFLOW_ERROR;
|
||||
return bufLen+delta;
|
||||
}
|
||||
if(startSearchHere) { /* RH side */
|
||||
uprv_memmove(startSearchHere+delta,startSearchHere, bufLen-(startSearchHere-buffer));
|
||||
}
|
||||
uprv_strncpy(nextSeparator, keywordValue, keywordValueLen);
|
||||
bufLen += delta;
|
||||
buffer[bufLen]=0;
|
||||
return bufLen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* we know there is at least one keyword. */
|
||||
needLen = bufLen+1+keywordNameLen+1+keywordValueLen;
|
||||
if(needLen >= bufferCapacity) {
|
||||
*status = U_BUFFER_OVERFLOW_ERROR;
|
||||
return needLen; /* no change */
|
||||
}
|
||||
startSearchHere=buffer+bufLen;
|
||||
*startSearchHere = ';';
|
||||
startSearchHere++;
|
||||
uprv_strcpy(startSearchHere, keywordNameBuffer);
|
||||
startSearchHere += keywordNameLen;
|
||||
*startSearchHere = '=';
|
||||
startSearchHere++;
|
||||
uprv_strcpy(startSearchHere, keywordValue); /* terminates. */
|
||||
startSearchHere+=keywordValueLen;
|
||||
return needLen;
|
||||
}
|
||||
|
||||
/* ### ID parsing implementation **************************************************/
|
||||
|
||||
/*returns TRUE if a is an ID separator FALSE otherwise*/
|
||||
|
|
|
@ -834,6 +834,31 @@ uloc_getKeywordValue(const char* localeID,
|
|||
char* buffer, int32_t bufferCapacity,
|
||||
UErrorCode* status);
|
||||
|
||||
|
||||
/**
|
||||
* Set the value of the specified keyword.
|
||||
* NOTE: Unlike almost every other ICU function which takes a
|
||||
* buffer, this function will NOT truncate the output text. If a
|
||||
* BUFFER_OVERFLOW_ERROR is received, it means that the original
|
||||
* buffer is untouched. This is done to prevent incorrect or possibly
|
||||
* even malformed locales from being generated and used.
|
||||
*
|
||||
* @param keywordName name of the keyword to be set. Case insensitive.
|
||||
* @param keywordValue value of the keyword to be set. If 0-length or
|
||||
* NULL, will result in the keyword being removed. No error is given if
|
||||
* that keyword does not exist.
|
||||
* @param buffer input buffer containing locale to be modified.
|
||||
* @param bufferCapacity capacity of receiving buffer
|
||||
* @param status containing error code - buffer not big enough.
|
||||
* @return the length needed for the buffer
|
||||
* @see uloc_getKeywordValue
|
||||
* @draft ICU 3.2
|
||||
*/
|
||||
U_DRAFT int32_t U_EXPORT2
|
||||
uloc_setKeywordValue(const char* keywordName,
|
||||
const char* keywordValue,
|
||||
char* buffer, int32_t bufferCapacity,
|
||||
UErrorCode* status);
|
||||
/*eof*/
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue