blob: ccdda111ef0d640a9d9010ec54ebf5d32a0639a4 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* @ingroup Port
* @brief Native language support
*/
#define CDEV_CURRENT_FUNCTION include_header
#undef CDEV_CURRENT_FUNCTION
#include "hycomp.h"
#include "hyport.h"
#include "portpriv.h"
#include "hythread.h"
#include "hynlshelpers.h"
#include "portnls.h"
#include <stdlib.h>
#include <string.h>
#ifdef ZOS
#include <iconv.h>
#endif
#define CDEV_CURRENT_FUNCTION _prototypes_private
static const char *nlsh_lookup (struct HyPortLibrary *portLibrary,
U_32 module_name, U_32 message_num);
static char *build_catalog_name (struct HyPortLibrary *portLibrary,
I_32 usePath, I_32 useDepth);
static void free_catalog (struct HyPortLibrary *portLibrary);
char *read_from_catalog (struct HyPortLibrary *portLibrary, IDATA fd,
char *buf, IDATA bufsize);
static HyNLSHashEntry *nls_allocateHashEntry (struct HyPortLibrary
*portLibrary, U_32 module_name,
U_32 message_num,
const char *message,
U_32 sizeOfMessage);
static const char *parse_catalogues (struct HyPortLibrary *portLibrary,
UDATA flags, U_32 module_name,
U_32 message_num,
const char *default_string);
static void nlsh_insert (struct HyPortLibrary *portLibrary,
HyNLSHashEntry * entry);
static void open_catalog (struct HyPortLibrary *portLibrary);
void convertModuleName (U_32 module_name, U_8 * module_str);
static U_32 nlsh_hash (U_32 module_name, U_32 message_num);
#undef CDEV_CURRENT_FUNCTION
/* a sample key */
#define HYNLS_EXEMPLAR "XXXX000"
#define BUF_SIZE 1024
#define CDEV_CURRENT_FUNCTION hynls_set_locale
/**
* Set the language, region, and variant of the locale.
*
* @param[in] portLibrary The port library
* @param[in] lang - the language of the locale (e.g., "en"), 2 characters or less
* @param[in] region - the region of the locale (e.g., "US"), 2 characters or less
* @param[in] variant - the variant of the locale (e.g., "boont"), 31 characters or less
*/
void VMCALL
hynls_set_locale (struct HyPortLibrary *portLibrary, const char *lang,
const char *region, const char *variant)
{
#ifdef HY_NO_THR
THREAD_ACCESS_FROM_PORT(portLibrary);
#endif /* HY_NO_THR */
HyNLSDataCache *nls = &portLibrary->portGlobals->nls_data;
#if defined(NLS_DEBUG_TRACE)
portLibrary->tty_printf (portLibrary, "NLS - hynls_set_locale\n");
#endif
hythread_monitor_enter (nls->monitor);
if (lang && strlen (lang) <= 2)
strcpy (nls->language, lang);
if (region && strlen (region) <= 2)
strcpy (nls->region, region);
if (variant && strlen (variant) <= 31)
strcpy (nls->variant, variant);
hythread_monitor_exit (nls->monitor);
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hynls_get_language
/**
* Return the string representing the currently set language.
*
* @param[in] portLibrary The port library
*
* @return language string
*/
const char *VMCALL
hynls_get_language (struct HyPortLibrary *portLibrary)
{
#if defined(NLS_DEBUG_TRACE)
portLibrary->tty_printf (portLibrary, "NLS - hynls_get_language\n");
#endif
return portLibrary->portGlobals->nls_data.language;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hynls_get_region
/**
* Return the string representing the currently set region.
*
* @param[in] portLibrary The port library
*
* @return region string
*/
const char *VMCALL
hynls_get_region (struct HyPortLibrary *portLibrary)
{
#if defined(NLS_DEBUG_TRACE)
portLibrary->tty_printf (portLibrary, "NLS - hynls_get_region\n");
#endif
return portLibrary->portGlobals->nls_data.region;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hynls_get_variant
/**
* Return the string representing the currently set variant.
*
* @param[in] portLibrary The port library
*
* @return variant string
*/
const char *VMCALL
hynls_get_variant (struct HyPortLibrary *portLibrary)
{
#if defined(NLS_DEBUG_TRACE)
portLibrary->tty_printf (portLibrary, "NLS - hynls_get_variant\n");
#endif
return portLibrary->portGlobals->nls_data.variant;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hynls_printf
/**
* Print a formatted NLS message.
*
* @param[in] portLibrary The port library
* @param[in] flags - to indicate what type of message (e.g., ERROR) and whether a newline is required
* @param[in] module_name - the module identifier of the NLS message
* @param[in] message_num - the NLS message number within the module
* @param[in] ... - arguments used in the NLS message format
*
*/
void VMCALL
hynls_printf (struct HyPortLibrary *portLibrary, UDATA flags,
U_32 module_name, U_32 message_num, ...)
{
va_list args;
#if defined(NLS_DEBUG_TRACE)
portLibrary->tty_printf (portLibrary, "NLS - hynls_printf\n");
#endif
va_start (args, message_num);
portLibrary->nls_vprintf (portLibrary, flags, module_name, message_num,
args);
va_end (args);
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hynls_vprintf
/**
* Print a formatted NLS message.
*
* @param[in] portLibrary The port library
* @param[in] flags - to indicate what type of message (e.g., ERROR) and whether a newline is required
* @param[in] module_name - the module identifier of the NLS message
* @param[in] message_num - the NLS message number within the module
* @param[in] args - arguments used in the NLS message format
*
*/
void VMCALL
hynls_vprintf (struct HyPortLibrary *portLibrary, UDATA flags,
U_32 module_name, U_32 message_num, va_list args)
{
const char *message;
#if defined(NLS_DEBUG_TRACE)
portLibrary->tty_printf (portLibrary, "NLS - hynls_vprintf\n");
#endif
message =
portLibrary->nls_lookup_message (portLibrary, flags, module_name,
message_num, NULL);
#if defined(NLS_DEBUG)
portLibrary->tty_printf (portLibrary, "NLS - vprintf - message: %s\n",
message);
#endif
if (flags & HYNLS_STDOUT)
{
portLibrary->file_vprintf (portLibrary, HYPORT_TTY_OUT, message, args);
}
else
{
portLibrary->file_vprintf (portLibrary, HYPORT_TTY_ERR, message, args);
}
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hynls_lookup_message
/**
* Return the NLS string for the module name and message number. If no string is found,
* or a failure occurs, return the default_string.
*
* @param[in] portLibrary The port library
* @param[in] flags - to indicate what type of message (e.g., ERROR) and whether a newline is required
* @param[in] module_name - the module identifier of the NLS message
* @param[in] message_num - the NLS message number within the module
* @param[in] default_string - a default message, in case no NLS message is found
*
* @return NLS String
*/
const char *VMCALL
hynls_lookup_message (struct HyPortLibrary *portLibrary, UDATA flags,
U_32 module_name, U_32 message_num,
const char *default_string)
{
#ifdef HY_NO_THR
THREAD_ACCESS_FROM_PORT(portLibrary);
#endif /* HY_NO_THR */
HyNLSDataCache *nls = &portLibrary->portGlobals->nls_data;
const char *message;
#if defined(NLS_DEBUG_TRACE)
portLibrary->tty_printf (portLibrary, "NLS - hynls_lookup_message\n");
#endif
hythread_monitor_enter (nls->monitor);
if (!nls->catalogues[0])
open_catalog (portLibrary);
message = nlsh_lookup (portLibrary, module_name, message_num);
if (!message)
{
message =
parse_catalogues (portLibrary, flags, module_name, message_num,
default_string);
if (!message)
message =
HYNLS_ERROR_MESSAGE (HYNLS_PORT_NLS_FAILURE, "NLS Failure\n");
}
hythread_monitor_exit (nls->monitor);
return message;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hynls_release_message
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hynls_set_catalog
/**
* Setup the path to the NLS catalog.
*
* @param[in] portLibrary The port library
* @param[in] paths - an array of directory paths where the NLS catalog may be found
* @param[in] nPaths - the number of entries in the @ref paths array
* @param[in] baseName - the lead name of the catalog file name (i.e., the "java" in java_en_US.properties)
* @param[in] extension - the extension of the catalog file name (i.e., the "properties in java_en_US.properties)
*/
void VMCALL
hynls_set_catalog (struct HyPortLibrary *portLibrary, const char **paths,
const int nPaths, const char *baseName,
const char *extension)
{
#ifdef HY_NO_THR
THREAD_ACCESS_FROM_PORT(portLibrary);
#endif /* HY_NO_THR */
int i;
char *p;
HyNLSDataCache *nls = &portLibrary->portGlobals->nls_data;
#if defined(NLS_DEBUG_TRACE)
portLibrary->tty_printf (portLibrary, "NLS - hynls_set_catalog\n");
#endif
hythread_monitor_enter (nls->monitor);
if (!baseName || !extension)
goto clean_exit;
for (i = 0; i < nPaths; i++)
{
if (nls->baseCatalogPaths[i])
portLibrary->mem_free_memory (portLibrary, nls->baseCatalogPaths[i]);
nls->baseCatalogPaths[i] = NULL;
if (nls->catalogues[i])
portLibrary->mem_free_memory (portLibrary, nls->catalogues[i]);
nls->catalogues[i] = NULL;
}
nls->nPaths = 0;
if (nls->baseCatalogName)
{
portLibrary->mem_free_memory (portLibrary, nls->baseCatalogName);
nls->baseCatalogName = NULL;
}
if (nls->baseCatalogExtension)
{
portLibrary->mem_free_memory (portLibrary, nls->baseCatalogExtension);
nls->baseCatalogExtension = NULL;
}
for (i = 0; i < nPaths; i++)
{
nls->baseCatalogPaths[i] =
portLibrary->mem_allocate_memory (portLibrary, strlen (paths[i]) + 1);
if (nls->baseCatalogPaths[i])
{
strcpy (nls->baseCatalogPaths[i], paths[i]);
p = strrchr (nls->baseCatalogPaths[i], DIR_SEPARATOR);
if (p)
p[1] = '\0';
nls->nPaths++;
}
}
nls->baseCatalogName =
portLibrary->mem_allocate_memory (portLibrary, strlen (baseName) + 1);
if (nls->baseCatalogName)
strcpy (nls->baseCatalogName, baseName);
nls->baseCatalogExtension =
portLibrary->mem_allocate_memory (portLibrary, strlen (extension) + 1);
if (nls->baseCatalogExtension)
strcpy (nls->baseCatalogExtension, extension);
if (nls->language[0] == 0 && nls->region[0] == 0 && nls->variant[0] == 0)
{
nls_determine_locale (portLibrary);
}
clean_exit:
hythread_monitor_exit (nls->monitor);
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION build_catalog_name
static char *
build_catalog_name (struct HyPortLibrary *portLibrary, I_32 usePath,
I_32 useDepth)
{
HyNLSDataCache *nls = &portLibrary->portGlobals->nls_data;
I_32 len = 1;
char *catalog = NULL;
char *defaultCatalog = NULL;
char *endPathPtr = NULL;
hysysinfo_get_executable_name (portLibrary, NULL, &defaultCatalog);
endPathPtr = strrchr (defaultCatalog, DIR_SEPARATOR);
endPathPtr[1] = '\0';
// defaultCatalog now holds the name of the launcher's home directory
#if defined(NLS_DEBUG_TRACE)
portLibrary->tty_printf (portLibrary, "NLS - build_catalog_name\n");
#endif
if (!nls->nPaths)
{
portLibrary->nls_set_catalog (portLibrary,
(const char **) &defaultCatalog, 1,
"harmony", "properties");
if (!nls->baseCatalogName)
goto _done;
if (nls->language[0] == 0 && nls->region[0] == 0
&& nls->variant[0] == 0)
{
nls_determine_locale (portLibrary);
}
}
if (useDepth > 0)
{
if (nls->language[0] == 0)
goto _done;
if (useDepth > 1)
{
if (nls->region[0] == 0)
goto _done;
if (useDepth > 2)
{
if (nls->variant[0] == 0)
goto _done;
}
}
}
len += strlen (nls->baseCatalogPaths[usePath]);
len += strlen (nls->baseCatalogName);
len += strlen (nls->baseCatalogExtension);
len += 1; /* the . before the extension */
len += strlen (nls->language) + 1; /* '_en' */
len += strlen (nls->region) + 1;
len += strlen (nls->variant) + 1;
len += 1; /* null terminator */
catalog = portLibrary->mem_allocate_memory (portLibrary, len);
if (!catalog)
goto _done;
strcpy (catalog, nls->baseCatalogPaths[usePath]);
strcat (catalog, nls->baseCatalogName);
if (useDepth > 0)
{
strcat (catalog, "_");
strcat (catalog, nls->language);
if (useDepth > 1)
{
strcat (catalog, "_");
strcat (catalog, nls->region);
if (useDepth > 2)
{
strcat (catalog, "_");
strcat (catalog, nls->variant);
}
}
}
strcat (catalog, ".");
strcat (catalog, nls->baseCatalogExtension);
_done:
// Free memory for defaultCatalog -- necessary ??
if (defaultCatalog)
{
portLibrary->mem_free_memory (portLibrary, defaultCatalog);
}
return catalog;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION open_catalog
static void
open_catalog (struct HyPortLibrary *portLibrary)
{
HyNLSDataCache *nls = &portLibrary->portGlobals->nls_data;
char *catalog = NULL;
char *add_catalog = NULL;
I_32 position = 0;
I_32 fd = -1, d, p, successfully_opened = 0;
#if defined(NLS_DEBUG_TRACE)
portLibrary->tty_printf (portLibrary, "NLS - open_catalog\n");
portLibrary->tty_printf (portLibrary, "nPaths = %d\n", (I_32) nls->nPaths);
#endif
/* try the following way to look for the catalog:
* The base name will typically be "<path>/java.properties". Append as many locale descriptors to the file name as possible to find a file.
* e.g.
* harmony_en_GB.properties
* harmony_en.properties
* harmony.properties
*/
for (p = 0; p < (I_32) nls->nPaths; p++)
{
for (d = 3; d >= 0; d--)
{
if (catalog)
portLibrary->mem_free_memory (portLibrary, catalog);
catalog = build_catalog_name (portLibrary, p, d);
if (!catalog)
continue;
#if defined(NLS_DEBUG)
portLibrary->tty_printf (portLibrary,
"NLS - attempting to open: %s\n", catalog);
#endif
fd = portLibrary->file_open (portLibrary, catalog, HyOpenRead, 0);
if (fd != -1)
break;
}
if (fd != -1)
{
add_catalog = portLibrary->mem_allocate_memory (portLibrary, strlen(catalog) +1);
strcpy(add_catalog, catalog);
portLibrary->portGlobals->nls_data.catalogues[position++] = add_catalog;
portLibrary->file_close (portLibrary, fd);
#if defined(NLS_DEBUG)
portLibrary->tty_printf (portLibrary, "NLS - successfully opened %s\n", catalog);
#endif
successfully_opened = 1;
fd = -1;
}
}
if (!successfully_opened)
{
#if defined(NLS_DEBUG)
portLibrary->tty_printf (portLibrary,
"NLS - failed to open the nls catalog\n");
#endif
return;
}
free_catalog(portLibrary);
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION parse_catalogues
static const char *
parse_catalogues (struct HyPortLibrary *portLibrary, UDATA flags,
U_32 module_name, U_32 message_num, const char *default_string)
{
#define MSG_NONE 0
#define MSG_SLASH 1
#define MSG_UNICODE 2
#define MSG_CONTINUE 3
#define MSG_DONE 4
#define MSG_IGNORE 5
U_8 dataBuf[BUF_SIZE];
U_8 *charPointer = NULL;
U_8 *endPointer = NULL;
int mode = MSG_NONE, count = 0, digit;
U_32 unicode = 0;
char nextChar;
U_32 offset = 0, bufSize = BUF_SIZE, maxOffset = 0;
I_32 keyLength = -1;
char *buf, *newBuf;
BOOLEAN firstChar = TRUE;
IDATA fd = -1;
I_32 success_reading = 0;
HyNLSDataCache *nls = &portLibrary->portGlobals->nls_data;
HyNLSHashEntry *entry = NULL;
char *message = NULL;
char convertedModuleEnum[5];
U_32 catalog_index;
/* calculate a size which is larger than we could possibly need by putting together all of the prefixes and suffixes */
char
prefix[sizeof
(HYNLS_ERROR_PREFIX "" HYNLS_INFO_PREFIX "" HYNLS_WARNING_PREFIX ""
HYNLS_COMMON_PREFIX "" HYNLS_EXEMPLAR "" HYNLS_ERROR_SUFFIX ""
HYNLS_INFO_SUFFIX "" HYNLS_WARNING_SUFFIX " \n")];
char *searchKey;
BOOLEAN newline = !(flags & HYNLS_DO_NOT_APPEND_NEWLINE);
const char *format;
#if defined(NLS_DEBUG_TRACE)
portLibrary->tty_printf (portLibrary, "NLS - parse_catalog\n");
#endif
convertModuleName (module_name, (U_8 *) convertedModuleEnum);
format = "" HYNLS_COMMON_PREFIX "%s%03u %s";
if (0 == (flags & HYNLS_DO_NOT_PRINT_MESSAGE_TAG))
{
if (flags & HYNLS_ERROR)
{
format =
"" HYNLS_ERROR_PREFIX "" HYNLS_COMMON_PREFIX "%s%03u"
HYNLS_ERROR_SUFFIX " %s";
}
else if (flags & HYNLS_WARNING)
{
format =
"" HYNLS_WARNING_PREFIX "" HYNLS_COMMON_PREFIX "%s%03u"
HYNLS_WARNING_SUFFIX " %s";
}
else if (flags & HYNLS_INFO)
{
format =
"" HYNLS_INFO_PREFIX "" HYNLS_COMMON_PREFIX "%s%03u"
HYNLS_INFO_SUFFIX " %s";
}
}
portLibrary->str_printf (portLibrary, prefix, sizeof (prefix), format,
convertedModuleEnum, message_num,
newline ? "\n" : "");
/* make sure the searchKey string starts at HYVM001 instead of (E)HYVM001 */
searchKey = prefix + (strchr (format, '%') - format);
#if defined(NLS_DEBUG)
portLibrary->tty_printf (portLibrary,
"NLS - parse_catalog - searchKey: %s\n",
searchKey);
#endif
/* we do a lazy caching, populate the cache as we look up messages */
if (!(buf = portLibrary->mem_allocate_memory (portLibrary, bufSize)))
{
goto finished;
}
for(catalog_index = 0; catalog_index < nls->nPaths; catalog_index++)
{
if (nls->catalogues[catalog_index])
{
fd = -1;
fd = portLibrary->file_open (portLibrary, (char *) nls->catalogues[catalog_index], HyOpenRead, 0);
offset = 0;
maxOffset = 0;
keyLength = -1;
firstChar = TRUE;
mode = MSG_NONE;
count = 0;
unicode = 0;
}
if (fd != -1)
{
success_reading = 1;
while (read_from_catalog (portLibrary, fd, (char *) dataBuf, BUF_SIZE) !=
NULL)
{
charPointer = dataBuf;
endPointer = charPointer + strlen ((char *) dataBuf);
while (charPointer < endPointer)
{
nextChar = *charPointer++;
if (offset + 2 >= bufSize)
{
bufSize <<= 1;
if (!
(newBuf =
portLibrary->mem_allocate_memory (portLibrary, bufSize)))
goto finished;
memcpy (newBuf, buf, offset);
portLibrary->mem_free_memory (portLibrary, buf);
buf = newBuf;
}
if (mode == MSG_UNICODE)
{
if (nextChar >= '0' && nextChar <= '9')
digit = nextChar - '0';
else if (nextChar >= 'a' && nextChar <= 'f')
digit = (nextChar - 'a') + 10;
else if (nextChar >= 'A' && nextChar <= 'F')
digit = (nextChar - 'A') + 10;
else
digit = -1;
if (digit >= 0)
{
unicode = (unicode << 4) + digit;
if (++count < 4)
continue;
}
mode = MSG_NONE;
if (unicode >= 0x01 && unicode <= 0x7f)
{
buf[offset++] = unicode;
}
else if (unicode == 0 || (unicode >= 0x80 && unicode <= 0x7ff))
{
buf[offset++] = ((unicode >> 6) & 0x1f) | 0xc0;
buf[offset++] = (unicode & 0x3f) | 0x80;
}
else if (unicode >= 0x800 && unicode <= 0xffff)
{
buf[offset++] = ((unicode >> 12) & 0x0f) | 0xe0;
buf[offset++] = ((unicode >> 6) & 0x3f) | 0x80;
buf[offset++] = (unicode & 0x3f) | 0x80;
}
if (nextChar != '\n')
continue;
}
if (mode == MSG_SLASH)
{
mode = MSG_NONE;
switch (nextChar)
{
case '\r':
mode = MSG_CONTINUE; /* Look for a following 'n */
continue;
case '\n':
mode = MSG_IGNORE; /* Ignore whitespace on the next line */
continue;
case 'b':
nextChar = '\b';
break;
case 'f':
nextChar = '\f';
break;
case 'n':
nextChar = '\n';
break;
case 'r':
nextChar = '\r';
break;
case 't':
nextChar = '\t';
break;
case 'u':
mode = MSG_UNICODE;
unicode = count = 0;
continue;
}
}
else
{
switch (nextChar)
{
case '#':
case '!':
if (firstChar)
{
while (1)
{
if (charPointer >= endPointer)
{
if (read_from_catalog
(portLibrary, fd, (char *) dataBuf,
BUF_SIZE) != NULL)
{
charPointer = dataBuf;
endPointer =
charPointer + strlen ((char *)charPointer);
}
}
if (charPointer >= endPointer)
break;
nextChar = *charPointer++;
if (nextChar == '\r' || nextChar == '\n')
break;
}
continue;
}
break;
case '\n':
if (mode == MSG_CONTINUE)
{ /* Part of a \r\n sequence */
mode = MSG_IGNORE;
continue;
}
/* fall into next case */
case '\r':
mode = MSG_NONE;
firstChar = TRUE;
makeStrings:
if (keyLength >= 0)
{
#if defined(NLS_DEBUG)
portLibrary->tty_printf (portLibrary,
"NLS - parse_catalog - keyLength: %d -- buf: %20.20s\n",
keyLength, buf);
#endif
if (strncmp
(searchKey, buf, sizeof (HYNLS_EXEMPLAR) - 1) == 0)
{
#if defined(NLS_DEBUG)
portLibrary->tty_printf (portLibrary,
"NLS - parse_catalog - key match\n");
#endif
/* we have the exact message */
if (flags & HYNLS_DO_NOT_PRINT_MESSAGE_TAG)
{
entry =
nls_allocateHashEntry (portLibrary,
module_name,
message_num,
buf + keyLength,
offset - keyLength +
1);
if (entry)
{
entry->message[offset - keyLength] = '\0';
if (newline)
strcat (entry->message, "\n");
}
}
else
{
entry =
nls_allocateHashEntry (portLibrary,
module_name,
message_num, prefix,
offset - keyLength +
strlen (prefix));
if (entry)
{
/* null terminate and trim the \n if required */
entry->message[strlen (prefix) -
(newline ? 1 : 0)] = '\0';
strncat (entry->message, buf + keyLength,
offset - keyLength);
if (newline)
strcat (entry->message, "\n");
}
}
goto finished;
}
keyLength = -1;
}
if (charPointer >= endPointer)
{
if (read_from_catalog
(portLibrary, fd, (char *) dataBuf,
BUF_SIZE) != NULL)
{
charPointer = dataBuf;
endPointer = charPointer + strlen ((char *)charPointer);
}
}
if (charPointer >= endPointer)
{
finished:
if (buf)
portLibrary->mem_free_memory (portLibrary, buf);
#if defined(NLS_DEBUG)
portLibrary->tty_printf (portLibrary,
"NLS - parse_catalog - inserting message\n");
#endif
if (!entry)
{
char *tmpStr = prefix;
if (default_string)
tmpStr = (char *) default_string;
entry =
nls_allocateHashEntry (portLibrary, module_name,
message_num, tmpStr,
strlen (tmpStr));
if (!entry)
{
portLibrary->file_close (portLibrary, fd);
return default_string;
}
}
nlsh_insert (portLibrary, entry);
portLibrary->file_close (portLibrary, fd);
return entry->message;
}
if (offset > maxOffset)
maxOffset = offset;
offset = 0;
continue;
case '\\':
mode = MSG_SLASH;
continue;
case ':':
case '=':
if (keyLength == -1)
{ /* if parsing the key */
keyLength = offset;
continue;
}
break;
}
if ((nextChar >= 0x1c && nextChar <= ' ')
|| (nextChar >= 9 && nextChar <= 0xd))
{
if (mode == MSG_CONTINUE)
mode = MSG_IGNORE;
/* if key length == 0 or value length == 0 */
if (offset == 0 || offset == (U_32) keyLength
|| mode == MSG_IGNORE)
continue;
if (keyLength == -1)
{ /* if parsing the key */
mode = MSG_DONE;
continue;
}
}
if (mode == MSG_IGNORE || mode == MSG_CONTINUE)
mode = MSG_NONE;
}
firstChar = FALSE;
if (mode == MSG_DONE)
{
keyLength = offset;
mode = MSG_NONE;
}
buf[offset++] = nextChar;
}
}
}
}
if (!success_reading)
{
/* couldn't open the file, store the searchKey instead */
char *tmpStr = prefix;
if (default_string)
{
tmpStr = (char *) default_string;
}
entry =
nls_allocateHashEntry (portLibrary, module_name, message_num, tmpStr,
strlen (tmpStr));
if (!entry)
{
return default_string;
}
nlsh_insert (portLibrary, entry);
return entry->message;
}
goto makeStrings;
#undef MSG_NONE
#undef MSG_SLASH
#undef MSG_UNICODE
#undef MSG_CONTINUE
#undef MSG_DONE
#undef MSG_IGNORE
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION free_catalog
static void
free_catalog (struct HyPortLibrary *portLibrary)
{
HyNLSDataCache *nls = &portLibrary->portGlobals->nls_data;
HyNLSHashEntry *old_hashEntries = nls->old_hashEntries;
U_32 i;
#if defined(NLS_DEBUG_TRACE)
portLibrary->tty_printf (portLibrary, "NLS - free_catalog\n");
#endif
for (i = 0; i < HYNLS_NUM_HASH_BUCKETS; i++)
{
HyNLSHashEntry *entry = nls->hash_buckets[i];
if (entry)
{
while (entry->next)
{
entry = entry->next;
}
entry->next = nls->old_hashEntries;
nls->old_hashEntries = nls->hash_buckets[i];
nls->hash_buckets[i] = NULL;
}
}
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION nlsh_hash
static U_32
nlsh_hash (U_32 module_name, U_32 message_num)
{
return (module_name ^ message_num);
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION nlsh_lookup
static const char *
nlsh_lookup (struct HyPortLibrary *portLibrary, U_32 module_name,
U_32 message_num)
{
HyNLSDataCache *nls = &portLibrary->portGlobals->nls_data;
U_32 hashKey = nlsh_hash (module_name, message_num);
U_32 index;
HyNLSHashEntry *entry;
#if defined(NLS_DEBUG_TRACE)
portLibrary->tty_printf (portLibrary, "NLS - nlsh_lookup\n");
#endif
index = hashKey % HYNLS_NUM_HASH_BUCKETS;
entry = nls->hash_buckets[index];
while (entry)
{
if (entry->module_name == module_name
&& entry->message_num == message_num)
{
return entry->message;
}
entry = entry->next;
}
return NULL;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION nlsh_insert
static void
nlsh_insert (struct HyPortLibrary *portLibrary, HyNLSHashEntry * entry)
{
HyNLSDataCache *nls = &portLibrary->portGlobals->nls_data;
U_32 hashKey = nlsh_hash (entry->module_name, entry->message_num);
U_32 index;
#if defined(NLS_DEBUG_TRACE)
portLibrary->tty_printf (portLibrary, "NLS - nlsh_insert\n");
#endif
index = hashKey % HYNLS_NUM_HASH_BUCKETS;
entry->next = nls->hash_buckets[index];
nls->hash_buckets[index] = entry;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hynls_startup
/**
* PortLibrary startup.
*
* This function is called during startup of the portLibrary. Any resources that are required for
* the NLS library operations may be created here. All resources created here should be destroyed
* in @ref hynls_shutdown.
*
* @param[in] portLibrary The port library
*
* @return 0 on success, negative error code on failure. Error code values returned are
* \arg HYPORT_ERROR_STARTUP_NLS
*/
I_32 VMCALL
hynls_startup (struct HyPortLibrary *portLibrary)
{
#ifdef HY_NO_THR
THREAD_ACCESS_FROM_PORT(portLibrary);
#endif /* HY_NO_THR */
HyNLSDataCache *nls = &portLibrary->portGlobals->nls_data;
if (0 !=
hythread_monitor_init_with_name (&nls->monitor, 0, "NLS hash table"))
{
return (I_32) HYPORT_ERROR_STARTUP_NLS;
}
nls_determine_locale (portLibrary);
return (I_32) 0;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION hynls_shutdown
/**
* PortLibrary shutdown.
*
* This function is called during shutdown of the portLibrary. Any resources that were created by
* @ref hynls_startup should be destroyed here.
*
* @param[in] portLibrary The port library
*/
void VMCALL
hynls_shutdown (struct HyPortLibrary *portLibrary)
{
#ifdef HY_NO_THR
THREAD_ACCESS_FROM_PORT(portLibrary);
#endif /* HY_NO_THR */
HyNLSDataCache *nls = &portLibrary->portGlobals->nls_data;
HyNLSHashEntry *entry;
U_32 i;
for (i = 0; i < HYNLS_NUM_HASH_BUCKETS; i++)
{
entry = nls->hash_buckets[i];
while (entry)
{
HyNLSHashEntry *next = entry->next;
portLibrary->mem_free_memory (portLibrary, entry);
entry = next;
}
}
/* Free the baseCatalogPaths allocated in hynls_set_catalog */
for (i = 0; i < nls->nPaths; i++)
{
if (nls->baseCatalogPaths[i])
{
portLibrary->mem_free_memory (portLibrary,
nls->baseCatalogPaths[i]);
nls->baseCatalogPaths[i] = NULL;
}
if (nls->catalogues[i])
{
portLibrary->mem_free_memory (portLibrary, nls->catalogues[i]);
nls->catalogues[i] = NULL;
}
}
if (nls->baseCatalogExtension)
{
portLibrary->mem_free_memory (portLibrary, nls->baseCatalogExtension);
nls->baseCatalogExtension = NULL;
}
/* catalog is never free'd without this flag */
entry = nls->old_hashEntries;
while (entry)
{
HyNLSHashEntry *next = entry->next;
portLibrary->mem_free_memory (portLibrary, entry);
entry = next;
}
if (nls->baseCatalogName)
portLibrary->mem_free_memory (portLibrary, nls->baseCatalogName);
hythread_monitor_destroy (nls->monitor);
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION nls_allocateHashEntry
static HyNLSHashEntry *
nls_allocateHashEntry (struct HyPortLibrary *portLibrary, U_32 module_name,
U_32 message_num, const char *message,
U_32 sizeOfMessage)
{
HyNLSHashEntry *entry = portLibrary->mem_allocate_memory (portLibrary,
sizeof
(HyNLSHashEntry) +
sizeOfMessage +
1 -
sizeof (entry->
message));
#if defined(NLS_DEBUG_TRACE)
portLibrary->tty_printf (portLibrary, "NLS - nls_allocateHashEntry\n");
#endif
if (!entry)
return NULL;
entry->module_name = module_name;
entry->message_num = message_num;
entry->next = NULL;
memcpy (entry->message, message, sizeOfMessage);
entry->message[sizeOfMessage] = '\0';
#if defined(NLS_DEBUG)
portLibrary->tty_printf (portLibrary,
"NLS - nls_allocateHashEntry - message: %s - sizeOfMessage: %d\n",
entry->message, sizeOfMessage);
#endif
return entry;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION convertModuleName
void
convertModuleName (U_32 module_name, U_8 * module_str)
{
module_str[0] = (U_8) ((module_name >> 24) & 0xff);
module_str[1] = (U_8) ((module_name >> 16) & 0xff);
module_str[2] = (U_8) ((module_name >> 8) & 0xff);
module_str[3] = (U_8) ((module_name) & 0xff);
module_str[4] = 0;
}
#undef CDEV_CURRENT_FUNCTION
#define CDEV_CURRENT_FUNCTION read_from_catalog
char *
read_from_catalog (struct HyPortLibrary *portLibrary, IDATA fd, char *buf,
IDATA bufsize)
{
char temp[BUF_SIZE];
IDATA count, nbytes = bufsize;
char *cursor = buf;
#ifdef ZOS
iconv_t converter;
size_t inbytesleft, outbytesleft;
char* inbuf, *outbuf;
#endif
if (nbytes <= 0)
return 0;
/* discount 1 for the trailing NUL */
nbytes -= 1;
#ifdef ZOS
/* iconv_open is not an a2e function, so we need to pass it EBCDIC strings */
#pragma convlit(suspend)
converter = iconv_open("UTF-8", "IBM-1047");
#pragma convlit(resume)
if ( converter == (iconv_t)-1 ) return NULL;
#endif
while (nbytes)
{
count = BUF_SIZE > nbytes ? nbytes : BUF_SIZE;
count = portLibrary->file_read (portLibrary, fd, temp, count);
if (count < 0)
{
#ifdef ZOS
iconv_close(converter);
#endif
/* if we've made it through a successful read, return the buf. */
if (nbytes + 1 != bufsize)
return buf;
return NULL;
}
#ifdef ZOS
inbuf = temp;
inbytesleft = count;
outbuf = cursor;
outbytesleft = nbytes;
if ( (size_t)-1 == iconv(converter, &inbuf, &inbytesleft, &outbuf, &outbytesleft) || inbytesleft == count ) {
/* conversion failed */
iconv_close(converter);
portLibrary->file_seek(portLibrary, fd, -1 * count, HySeekCur);
return NULL;
}
if ( inbytesleft > 0 ) {
portLibrary->file_seek(portLibrary, fd, inbytesleft - count, HySeekCur);
}
nbytes -= count - inbytesleft;
cursor += count - inbytesleft;
#else
memcpy (cursor, temp, count);
cursor += count;
nbytes -= count;
#endif /* ZOS */
}
*cursor = '\0';
#ifdef ZOS
if ( converter != (iconv_t)-1 ) iconv_close(converter);
#endif
return buf;
}
#undef CDEV_CURRENT_FUNCTION