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