| // © 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 = NULL; | |
| char* tmpFlagBuffer = NULL; | |
| UBool allocateMoreSpace = FALSE; | |
| int32_t idx, i; | |
| int32_t result = 0; | |
| FileStream *f = T_FileStream_open(fileName, "r"); | |
| if (f == NULL) { | |
| *status = U_FILE_ACCESS_ERROR; | |
| goto parseFlagsFile_cleanup; | |
| } | |
| buffer = (char *)uprv_malloc(sizeof(char) * currentBufferSize); | |
| tmpFlagBuffer = (char *)uprv_malloc(sizeof(char) * flagBufferSize); | |
| if (buffer == NULL || tmpFlagBuffer == NULL) { | |
| *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 == NULL) { | |
| *status = U_MEMORY_ALLOCATION_ERROR; | |
| goto parseFlagsFile_cleanup; | |
| } | |
| } | |
| for (i = 0; i < numOfFlags;) { | |
| if (T_FileStream_readLine(f, buffer, currentBufferSize) == NULL) { | |
| /* 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 didnot read the entrire 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 != NULL) { | |
| 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 != NULL && 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; | |
| } |