blob: e911982880c635a73ce4455d698172ccf50c1be0 [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.
*/
#include <string.h>
#include "hyport.h"
#include "strhelp.h"
#ifdef ZOS
#include "atoe.h"
#endif
static int prop_alloc(HyPortLibrary * portLibrary, key_value_pair* property,
char* start, char* delim, char* end);
/**
* Concatenates a variable number of null-terminated strings into a single string
* using the specified port library to allocate memory. The variable number of
* strings arguments must be terminated by a single NULL value.
*
* @param portLibrary - The port library used to allocate memory.
* @return The concatenated string or NULL if no memory can be allocated.
*/
char *
str_concat (HyPortLibrary * portLibrary, ...)
{
PORT_ACCESS_FROM_PORT (portLibrary);
va_list argp;
char *concatenated;
UDATA concatenatedSize = 0;
/* Walk the variable arguments once to compute the final size */
va_start (argp, portLibrary);
while (1)
{
char *chunk = va_arg (argp, char *);
if (chunk)
{
concatenatedSize += (UDATA)strlen (chunk);
}
else
{
break;
}
}
va_end (argp);
/* Allocate concatenated space */
concatenated =
hymem_allocate_memory (concatenatedSize + 1 /* for null terminator */ );
if (!concatenated)
{
return NULL;
}
concatenated[0] = '\0';
/* Walk again concatenating the pieces */
va_start (argp, portLibrary);
while (1)
{
char *chunk = va_arg (argp, char *);
if (chunk)
{
strcat (concatenated, chunk);
}
else
{
break;
}
}
va_end (argp);
return concatenated;
}
/**
* Frees data of all elements and the array itself.
* @param portLibrary - The port library used to interact with the platform.
* @param properties - The array instance no longer in use.
*/
void
properties_free(HyPortLibrary * portLibrary, key_value_pair * properties)
{
PORT_ACCESS_FROM_PORT (portLibrary);
if (properties) {
unsigned i = 0;
while (properties[i].key) {
hymem_free_memory(properties[i].key);
if (properties[i].value)
hymem_free_memory(properties[i].value);
++i;
}
hymem_free_memory(properties);
}
}
static int
prop_alloc(HyPortLibrary * portLibrary, key_value_pair* property,
char* start, char* delim, char* end)
{
PORT_ACCESS_FROM_PORT (portLibrary);
/* missing delimiter means the whole line is the key and value is empty */
size_t keyLength = (delim ? delim : end) - start;
size_t valueLength = delim ? end - delim - 1 : 0;
property->key = hymem_allocate_memory ((UDATA)(keyLength + 1));
property->value = hymem_allocate_memory ((UDATA)(valueLength + 1));
if (!property->key || !property->value)
{
return 0;
}
memcpy (property->key, start, keyLength);
property->key[keyLength] = '\0';
if (delim) {
memcpy (property->value, delim + 1, valueLength);
}
property->value[valueLength] = '\0';
return 1;
}
/**
* Read the properties file specified by <tt>filename</tt>
* into the array of <tt>properties</tt>,
* using the specified port library to allocate memory.
* The array is terminated with null-keyed element,
* though one can obtain number of elements directly
* via last argument.
*
* @param[in] portLibrary - The port library used to interact with the platform.
* @param[in] filename - The file from which to read data using hyfile* functions.
* @param[out] properties - An array that will contain property file entries.
* @param[out] number - Optional parameter, number of elements in the returned array.
*
* @return JNI_OK on success, or a JNI error code on failure.
*/
jint
properties_load(HyPortLibrary * portLibrary, const char *filename,
key_value_pair** properties, U_32 *number)
{
PORT_ACCESS_FROM_PORT (portLibrary);
void *handle;
I_64 seekResult;
IDATA fileSize;
char *scanCursor, *scanLimit;
char *start, *delim, *end;
key_value_pair *props;
unsigned arraySize;
unsigned count = 0;
jint status = JNI_OK;
/* Determine the file size, fail if > 2G */
seekResult = hyfile_length (filename);
if ((seekResult <= 0) || (seekResult > 0x7FFFFFFF))
{
return JNI_ERR;
}
scanCursor = hymmap_map_file(filename, &handle);
if (!scanCursor) {
return JNI_ERR;
}
#ifdef ZOS
/* Convert the scan buffer into ASCII */
scanCursor = e2a(scanCursor, seekResult);
#endif
fileSize = (IDATA) seekResult;
arraySize = fileSize/50 + 1;
props = hymem_allocate_memory(sizeof(key_value_pair)*(arraySize + 1));
if (!props) {
status = JNI_ENOMEM;
goto finish;
}
start = end = scanCursor;
delim = NULL;
scanLimit = scanCursor + fileSize;
do {
while (scanCursor < scanLimit) {
switch(*scanCursor) {
case '\r':
case '\n':
end = scanCursor;
goto read_line;
case '=':
/* remember only first occurrence which is not key itself */
if (delim == NULL && scanCursor > start) {
delim = scanCursor;
}
default:
++scanCursor;
continue;
}
}
read_line:
if (scanCursor > start && start != delim && *start != '#' && *start != '!')
/* line is not empty, well formed and not commented out */
{
if (end == start) {
/* the last line ends with EOF */
end = scanLimit;
}
if (count == arraySize)
{
void* re_props;
arraySize += arraySize/2 + 1;
re_props = hymem_reallocate_memory(props,
sizeof(key_value_pair)*(arraySize + 1));
if (!re_props) {
status = JNI_ENOMEM;
goto finish;
}
props = re_props;
}
if (!prop_alloc(portLibrary, props + count, start, delim, end)) {
status = JNI_ENOMEM;
goto finish;
}
++count;
}
start = end = ++scanCursor;
delim = NULL;
}
while (scanCursor < scanLimit);
/*set terminating NULL*/
props[count].key = NULL;
finish:
hymmap_unmap_file(handle);
if (status != JNI_OK)
{
properties_free(portLibrary, props);
}
else
{
*properties = props;
if (number){
*number = count;
}
}
return status;
}