1 /****************************************************************************** 2 * Copyright (C) 2009-2015, International Business Machines 3 * Corporation and others. All Rights Reserved. 4 ******************************************************************************* 5 */ 6 7 #include "flagparser.h" 8 #include "filestrm.h" 9 #include "cstring.h" 10 #include "cmemory.h" 11 12 #define DEFAULT_BUFFER_SIZE 512 13 14 static int32_t currentBufferSize = DEFAULT_BUFFER_SIZE; 15 16 static int32_t extractFlag(char* buffer, int32_t bufferSize, char* flag, int32_t flagSize, const char ** flagNames, int32_t numOfFlags, UErrorCode *status); 17 static int32_t getFlagOffset(const char *buffer, int32_t bufferSize); 18 19 /* 20 * Opens the given fileName and reads in the information storing the data in flagBuffer. 21 */ 22 U_CAPI int32_t U_EXPORT2 23 parseFlagsFile(const char *fileName, char **flagBuffer, int32_t flagBufferSize, const char ** flagNames, int32_t numOfFlags, UErrorCode *status) { 24 char* buffer = NULL; 25 char* tmpFlagBuffer = NULL; 26 UBool allocateMoreSpace = FALSE; 27 int32_t idx, i; 28 int32_t result = 0; 29 30 FileStream *f = T_FileStream_open(fileName, "r"); 31 if (f == NULL) { 32 *status = U_FILE_ACCESS_ERROR; 33 goto parseFlagsFile_cleanup; 34 } 35 36 buffer = uprv_malloc(sizeof(char) * currentBufferSize); 37 tmpFlagBuffer = uprv_malloc(sizeof(char) * flagBufferSize); 38 39 if (buffer == NULL || tmpFlagBuffer == NULL) { 40 *status = U_MEMORY_ALLOCATION_ERROR; 41 goto parseFlagsFile_cleanup; 42 } 43 44 do { 45 if (allocateMoreSpace) { 46 allocateMoreSpace = FALSE; 47 currentBufferSize *= 2; 48 uprv_free(buffer); 49 buffer = uprv_malloc(sizeof(char) * currentBufferSize); 50 if (buffer == NULL) { 51 *status = U_MEMORY_ALLOCATION_ERROR; 52 goto parseFlagsFile_cleanup; 53 } 54 } 55 for (i = 0; i < numOfFlags;) { 56 if (T_FileStream_readLine(f, buffer, currentBufferSize) == NULL) { 57 /* End of file reached. */ 58 break; 59 } 60 if (buffer[0] == '#') { 61 continue; 62 } 63 64 if (uprv_strlen(buffer) == (currentBufferSize - 1) && buffer[currentBufferSize-2] != '\n') { 65 /* Allocate more space for buffer if it didnot read the entrire line */ 66 allocateMoreSpace = TRUE; 67 T_FileStream_rewind(f); 68 break; 69 } else { 70 idx = extractFlag(buffer, currentBufferSize, tmpFlagBuffer, flagBufferSize, flagNames, numOfFlags, status); 71 if (U_FAILURE(*status)) { 72 if (*status == U_BUFFER_OVERFLOW_ERROR) { 73 result = currentBufferSize; 74 } else { 75 result = -1; 76 } 77 break; 78 } else { 79 if (flagNames != NULL) { 80 if (idx >= 0) { 81 uprv_strcpy(flagBuffer[idx], tmpFlagBuffer); 82 } else { 83 /* No match found. Skip it. */ 84 continue; 85 } 86 } else { 87 uprv_strcpy(flagBuffer[i++], tmpFlagBuffer); 88 } 89 } 90 } 91 } 92 } while (allocateMoreSpace && U_SUCCESS(*status)); 93 94 parseFlagsFile_cleanup: 95 uprv_free(tmpFlagBuffer); 96 uprv_free(buffer); 97 98 T_FileStream_close(f); 99 100 if (U_FAILURE(*status)) { 101 return -1; 102 } 103 104 if (U_SUCCESS(*status) && result == 0) { 105 currentBufferSize = DEFAULT_BUFFER_SIZE; 106 } 107 108 return result; 109 } 110 111 112 /* 113 * Extract the setting after the '=' and store it in flag excluding the newline character. 114 */ 115 static int32_t extractFlag(char* buffer, int32_t bufferSize, char* flag, int32_t flagSize, const char **flagNames, int32_t numOfFlags, UErrorCode *status) { 116 int32_t i, idx = -1; 117 char *pBuffer; 118 int32_t offset=0; 119 UBool bufferWritten = FALSE; 120 121 if (buffer[0] != 0) { 122 /* Get the offset (i.e. position after the '=') */ 123 offset = getFlagOffset(buffer, bufferSize); 124 pBuffer = buffer+offset; 125 for(i = 0;;i++) { 126 if (i >= flagSize) { 127 *status = U_BUFFER_OVERFLOW_ERROR; 128 return -1; 129 } 130 if (pBuffer[i+1] == 0) { 131 /* Indicates a new line character. End here. */ 132 flag[i] = 0; 133 break; 134 } 135 136 flag[i] = pBuffer[i]; 137 if (i == 0) { 138 bufferWritten = TRUE; 139 } 140 } 141 } 142 143 if (!bufferWritten) { 144 flag[0] = 0; 145 } 146 147 if (flagNames != NULL && offset>0) { 148 offset--; /* Move offset back 1 because of '='*/ 149 for (i = 0; i < numOfFlags; i++) { 150 if (uprv_strncmp(buffer, flagNames[i], offset) == 0) { 151 idx = i; 152 break; 153 } 154 } 155 } 156 157 return idx; 158 } 159 160 /* 161 * Get the position after the '=' character. 162 */ 163 static int32_t getFlagOffset(const char *buffer, int32_t bufferSize) { 164 int32_t offset = 0; 165 166 for (offset = 0; offset < bufferSize;offset++) { 167 if (buffer[offset] == '=') { 168 offset++; 169 break; 170 } 171 } 172 173 if (offset == bufferSize || (offset - 1) == bufferSize) { 174 offset = 0; 175 } 176 177 return offset; 178 } 179