1 /****************************************************************************** 2 * Copyright (C) 2009-2012, 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 = uprv_malloc(sizeof(char) * currentBufferSize); 25 char* tmpFlagBuffer = uprv_malloc(sizeof(char) * flagBufferSize); 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 return -1; 34 } 35 36 if (buffer == NULL) { 37 *status = U_MEMORY_ALLOCATION_ERROR; 38 return -1; 39 } 40 41 do { 42 if (allocateMoreSpace) { 43 allocateMoreSpace = FALSE; 44 currentBufferSize *= 2; 45 uprv_free(buffer); 46 buffer = uprv_malloc(sizeof(char) * currentBufferSize); 47 if (buffer == NULL) { 48 uprv_free(tmpFlagBuffer); 49 *status = U_MEMORY_ALLOCATION_ERROR; 50 return -1; 51 } 52 } 53 for (i = 0; i < numOfFlags;) { 54 if (T_FileStream_readLine(f, buffer, currentBufferSize) == NULL) { 55 /* End of file reached. */ 56 break; 57 } 58 if (buffer[0] == '#') { 59 continue; 60 } 61 62 if (uprv_strlen(buffer) == (currentBufferSize - 1) && buffer[currentBufferSize-2] != '\n') { 63 /* Allocate more space for buffer if it didnot read the entrire line */ 64 allocateMoreSpace = TRUE; 65 T_FileStream_rewind(f); 66 break; 67 } else { 68 idx = extractFlag(buffer, currentBufferSize, tmpFlagBuffer, flagBufferSize, flagNames, numOfFlags, status); 69 if (U_FAILURE(*status)) { 70 if (*status == U_BUFFER_OVERFLOW_ERROR) { 71 result = currentBufferSize; 72 } else { 73 result = -1; 74 } 75 break; 76 } else { 77 if (flagNames != NULL) { 78 if (idx >= 0) { 79 uprv_strcpy(flagBuffer[idx], tmpFlagBuffer); 80 } else { 81 /* No match found. Skip it. */ 82 continue; 83 } 84 } else { 85 uprv_strcpy(flagBuffer[i++], tmpFlagBuffer); 86 } 87 } 88 } 89 } 90 } while (allocateMoreSpace && U_SUCCESS(*status)); 91 92 uprv_free(tmpFlagBuffer); 93 uprv_free(buffer); 94 95 T_FileStream_close(f); 96 97 if (U_SUCCESS(*status) && result == 0) { 98 currentBufferSize = DEFAULT_BUFFER_SIZE; 99 } 100 101 return result; 102 } 103 104 105 /* 106 * Extract the setting after the '=' and store it in flag excluding the newline character. 107 */ 108 static int32_t extractFlag(char* buffer, int32_t bufferSize, char* flag, int32_t flagSize, const char **flagNames, int32_t numOfFlags, UErrorCode *status) { 109 int32_t i, idx = -1; 110 char *pBuffer; 111 int32_t offset=0; 112 UBool bufferWritten = FALSE; 113 114 if (buffer[0] != 0) { 115 /* Get the offset (i.e. position after the '=') */ 116 offset = getFlagOffset(buffer, bufferSize); 117 pBuffer = buffer+offset; 118 for(i = 0;;i++) { 119 if (i >= flagSize) { 120 *status = U_BUFFER_OVERFLOW_ERROR; 121 return -1; 122 } 123 if (pBuffer[i+1] == 0) { 124 /* Indicates a new line character. End here. */ 125 flag[i] = 0; 126 break; 127 } 128 129 flag[i] = pBuffer[i]; 130 if (i == 0) { 131 bufferWritten = TRUE; 132 } 133 } 134 } 135 136 if (!bufferWritten) { 137 flag[0] = 0; 138 } 139 140 if (flagNames != NULL && offset>0) { 141 offset--; /* Move offset back 1 because of '='*/ 142 for (i = 0; i < numOfFlags; i++) { 143 if (uprv_strncmp(buffer, flagNames[i], offset) == 0) { 144 idx = i; 145 break; 146 } 147 } 148 } 149 150 return idx; 151 } 152 153 /* 154 * Get the position after the '=' character. 155 */ 156 static int32_t getFlagOffset(const char *buffer, int32_t bufferSize) { 157 int32_t offset = 0; 158 159 for (offset = 0; offset < bufferSize;offset++) { 160 if (buffer[offset] == '=') { 161 offset++; 162 break; 163 } 164 } 165 166 if (offset == bufferSize || (offset - 1) == bufferSize) { 167 offset = 0; 168 } 169 170 return offset; 171 } 172