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