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