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
parseFlagsFile(const char * fileName,char ** flagBuffer,int32_t flagBufferSize,const char ** flagNames,int32_t numOfFlags,UErrorCode * status)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 */
extractFlag(char * buffer,int32_t bufferSize,char * flag,int32_t flagSize,const char ** flagNames,int32_t numOfFlags,UErrorCode * status)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 */
getFlagOffset(const char * buffer,int32_t bufferSize)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