diff options
Diffstat (limited to 'intl/icu/source/tools/toolutil/flagparser.cpp')
-rw-r--r-- | intl/icu/source/tools/toolutil/flagparser.cpp | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/intl/icu/source/tools/toolutil/flagparser.cpp b/intl/icu/source/tools/toolutil/flagparser.cpp new file mode 100644 index 0000000000..8bbceb4f73 --- /dev/null +++ b/intl/icu/source/tools/toolutil/flagparser.cpp @@ -0,0 +1,180 @@ +// © 2016 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html +/****************************************************************************** + * Copyright (C) 2009-2015, International Business Machines + * Corporation and others. All Rights Reserved. + ******************************************************************************* + */ + +#include "flagparser.h" +#include "filestrm.h" +#include "cstring.h" +#include "cmemory.h" + +#define DEFAULT_BUFFER_SIZE 512 + +static int32_t currentBufferSize = DEFAULT_BUFFER_SIZE; + +static int32_t extractFlag(char* buffer, int32_t bufferSize, char* flag, int32_t flagSize, const char ** flagNames, int32_t numOfFlags, UErrorCode *status); +static int32_t getFlagOffset(const char *buffer, int32_t bufferSize); + +/* + * Opens the given fileName and reads in the information storing the data in flagBuffer. + */ +U_CAPI int32_t U_EXPORT2 +parseFlagsFile(const char *fileName, char **flagBuffer, int32_t flagBufferSize, const char ** flagNames, int32_t numOfFlags, UErrorCode *status) { + char* buffer = nullptr; + char* tmpFlagBuffer = nullptr; + UBool allocateMoreSpace = false; + int32_t idx, i; + int32_t result = 0; + + FileStream *f = T_FileStream_open(fileName, "r"); + if (f == nullptr) { + *status = U_FILE_ACCESS_ERROR; + goto parseFlagsFile_cleanup; + } + + buffer = (char *)uprv_malloc(sizeof(char) * currentBufferSize); + tmpFlagBuffer = (char *)uprv_malloc(sizeof(char) * flagBufferSize); + + if (buffer == nullptr || tmpFlagBuffer == nullptr) { + *status = U_MEMORY_ALLOCATION_ERROR; + goto parseFlagsFile_cleanup; + } + + do { + if (allocateMoreSpace) { + allocateMoreSpace = false; + currentBufferSize *= 2; + uprv_free(buffer); + buffer = (char *)uprv_malloc(sizeof(char) * currentBufferSize); + if (buffer == nullptr) { + *status = U_MEMORY_ALLOCATION_ERROR; + goto parseFlagsFile_cleanup; + } + } + for (i = 0; i < numOfFlags;) { + if (T_FileStream_readLine(f, buffer, currentBufferSize) == nullptr) { + /* End of file reached. */ + break; + } + if (buffer[0] == '#') { + continue; + } + + if ((int32_t)uprv_strlen(buffer) == (currentBufferSize - 1) && buffer[currentBufferSize-2] != '\n') { + /* Allocate more space for buffer if it did not read the entire line */ + allocateMoreSpace = true; + T_FileStream_rewind(f); + break; + } else { + idx = extractFlag(buffer, currentBufferSize, tmpFlagBuffer, flagBufferSize, flagNames, numOfFlags, status); + if (U_FAILURE(*status)) { + if (*status == U_BUFFER_OVERFLOW_ERROR) { + result = currentBufferSize; + } else { + result = -1; + } + break; + } else { + if (flagNames != nullptr) { + if (idx >= 0) { + uprv_strcpy(flagBuffer[idx], tmpFlagBuffer); + } else { + /* No match found. Skip it. */ + continue; + } + } else { + uprv_strcpy(flagBuffer[i++], tmpFlagBuffer); + } + } + } + } + } while (allocateMoreSpace && U_SUCCESS(*status)); + +parseFlagsFile_cleanup: + uprv_free(tmpFlagBuffer); + uprv_free(buffer); + + T_FileStream_close(f); + + if (U_FAILURE(*status) && *status != U_BUFFER_OVERFLOW_ERROR) { + return -1; + } + + if (U_SUCCESS(*status) && result == 0) { + currentBufferSize = DEFAULT_BUFFER_SIZE; + } + + return result; +} + + +/* + * Extract the setting after the '=' and store it in flag excluding the newline character. + */ +static int32_t extractFlag(char* buffer, int32_t bufferSize, char* flag, int32_t flagSize, const char **flagNames, int32_t numOfFlags, UErrorCode *status) { + int32_t i, idx = -1; + char *pBuffer; + int32_t offset=0; + UBool bufferWritten = false; + + if (buffer[0] != 0) { + /* Get the offset (i.e. position after the '=') */ + offset = getFlagOffset(buffer, bufferSize); + pBuffer = buffer+offset; + for(i = 0;;i++) { + if (i >= flagSize) { + *status = U_BUFFER_OVERFLOW_ERROR; + return -1; + } + if (pBuffer[i+1] == 0) { + /* Indicates a new line character. End here. */ + flag[i] = 0; + break; + } + + flag[i] = pBuffer[i]; + if (i == 0) { + bufferWritten = true; + } + } + } + + if (!bufferWritten) { + flag[0] = 0; + } + + if (flagNames != nullptr && offset>0) { + offset--; /* Move offset back 1 because of '='*/ + for (i = 0; i < numOfFlags; i++) { + if (uprv_strncmp(buffer, flagNames[i], offset) == 0) { + idx = i; + break; + } + } + } + + return idx; +} + +/* + * Get the position after the '=' character. + */ +static int32_t getFlagOffset(const char *buffer, int32_t bufferSize) { + int32_t offset = 0; + + for (offset = 0; offset < bufferSize;offset++) { + if (buffer[offset] == '=') { + offset++; + break; + } + } + + if (offset == bufferSize || (offset - 1) == bufferSize) { + offset = 0; + } + + return offset; +} |