Imported Upstream version 58.1
[platform/upstream/icu.git] / source / tools / toolutil / flagparser.c
1 // Copyright (C) 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 = uprv_malloc(sizeof(char) * currentBufferSize);
39     tmpFlagBuffer = 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 = 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 }