michael@0: /****************************************************************************** michael@0: * Copyright (C) 2009-2012, International Business Machines michael@0: * Corporation and others. All Rights Reserved. michael@0: ******************************************************************************* michael@0: */ michael@0: michael@0: #include "flagparser.h" michael@0: #include "filestrm.h" michael@0: #include "cstring.h" michael@0: #include "cmemory.h" michael@0: michael@0: #define DEFAULT_BUFFER_SIZE 512 michael@0: michael@0: static int32_t currentBufferSize = DEFAULT_BUFFER_SIZE; michael@0: michael@0: static int32_t extractFlag(char* buffer, int32_t bufferSize, char* flag, int32_t flagSize, const char ** flagNames, int32_t numOfFlags, UErrorCode *status); michael@0: static int32_t getFlagOffset(const char *buffer, int32_t bufferSize); michael@0: michael@0: /* michael@0: * Opens the given fileName and reads in the information storing the data in flagBuffer. michael@0: */ michael@0: U_CAPI int32_t U_EXPORT2 michael@0: parseFlagsFile(const char *fileName, char **flagBuffer, int32_t flagBufferSize, const char ** flagNames, int32_t numOfFlags, UErrorCode *status) { michael@0: char* buffer = uprv_malloc(sizeof(char) * currentBufferSize); michael@0: char* tmpFlagBuffer = uprv_malloc(sizeof(char) * flagBufferSize); michael@0: UBool allocateMoreSpace = FALSE; michael@0: int32_t idx, i; michael@0: int32_t result = 0; michael@0: michael@0: FileStream *f = T_FileStream_open(fileName, "r"); michael@0: if (f == NULL) { michael@0: *status = U_FILE_ACCESS_ERROR; michael@0: return -1; michael@0: } michael@0: michael@0: if (buffer == NULL) { michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: return -1; michael@0: } michael@0: michael@0: do { michael@0: if (allocateMoreSpace) { michael@0: allocateMoreSpace = FALSE; michael@0: currentBufferSize *= 2; michael@0: uprv_free(buffer); michael@0: buffer = uprv_malloc(sizeof(char) * currentBufferSize); michael@0: if (buffer == NULL) { michael@0: uprv_free(tmpFlagBuffer); michael@0: *status = U_MEMORY_ALLOCATION_ERROR; michael@0: return -1; michael@0: } michael@0: } michael@0: for (i = 0; i < numOfFlags;) { michael@0: if (T_FileStream_readLine(f, buffer, currentBufferSize) == NULL) { michael@0: /* End of file reached. */ michael@0: break; michael@0: } michael@0: if (buffer[0] == '#') { michael@0: continue; michael@0: } michael@0: michael@0: if (uprv_strlen(buffer) == (currentBufferSize - 1) && buffer[currentBufferSize-2] != '\n') { michael@0: /* Allocate more space for buffer if it didnot read the entrire line */ michael@0: allocateMoreSpace = TRUE; michael@0: T_FileStream_rewind(f); michael@0: break; michael@0: } else { michael@0: idx = extractFlag(buffer, currentBufferSize, tmpFlagBuffer, flagBufferSize, flagNames, numOfFlags, status); michael@0: if (U_FAILURE(*status)) { michael@0: if (*status == U_BUFFER_OVERFLOW_ERROR) { michael@0: result = currentBufferSize; michael@0: } else { michael@0: result = -1; michael@0: } michael@0: break; michael@0: } else { michael@0: if (flagNames != NULL) { michael@0: if (idx >= 0) { michael@0: uprv_strcpy(flagBuffer[idx], tmpFlagBuffer); michael@0: } else { michael@0: /* No match found. Skip it. */ michael@0: continue; michael@0: } michael@0: } else { michael@0: uprv_strcpy(flagBuffer[i++], tmpFlagBuffer); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } while (allocateMoreSpace && U_SUCCESS(*status)); michael@0: michael@0: uprv_free(tmpFlagBuffer); michael@0: uprv_free(buffer); michael@0: michael@0: T_FileStream_close(f); michael@0: michael@0: if (U_SUCCESS(*status) && result == 0) { michael@0: currentBufferSize = DEFAULT_BUFFER_SIZE; michael@0: } michael@0: michael@0: return result; michael@0: } michael@0: michael@0: michael@0: /* michael@0: * Extract the setting after the '=' and store it in flag excluding the newline character. michael@0: */ michael@0: static int32_t extractFlag(char* buffer, int32_t bufferSize, char* flag, int32_t flagSize, const char **flagNames, int32_t numOfFlags, UErrorCode *status) { michael@0: int32_t i, idx = -1; michael@0: char *pBuffer; michael@0: int32_t offset=0; michael@0: UBool bufferWritten = FALSE; michael@0: michael@0: if (buffer[0] != 0) { michael@0: /* Get the offset (i.e. position after the '=') */ michael@0: offset = getFlagOffset(buffer, bufferSize); michael@0: pBuffer = buffer+offset; michael@0: for(i = 0;;i++) { michael@0: if (i >= flagSize) { michael@0: *status = U_BUFFER_OVERFLOW_ERROR; michael@0: return -1; michael@0: } michael@0: if (pBuffer[i+1] == 0) { michael@0: /* Indicates a new line character. End here. */ michael@0: flag[i] = 0; michael@0: break; michael@0: } michael@0: michael@0: flag[i] = pBuffer[i]; michael@0: if (i == 0) { michael@0: bufferWritten = TRUE; michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (!bufferWritten) { michael@0: flag[0] = 0; michael@0: } michael@0: michael@0: if (flagNames != NULL && offset>0) { michael@0: offset--; /* Move offset back 1 because of '='*/ michael@0: for (i = 0; i < numOfFlags; i++) { michael@0: if (uprv_strncmp(buffer, flagNames[i], offset) == 0) { michael@0: idx = i; michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: michael@0: return idx; michael@0: } michael@0: michael@0: /* michael@0: * Get the position after the '=' character. michael@0: */ michael@0: static int32_t getFlagOffset(const char *buffer, int32_t bufferSize) { michael@0: int32_t offset = 0; michael@0: michael@0: for (offset = 0; offset < bufferSize;offset++) { michael@0: if (buffer[offset] == '=') { michael@0: offset++; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (offset == bufferSize || (offset - 1) == bufferSize) { michael@0: offset = 0; michael@0: } michael@0: michael@0: return offset; michael@0: }