1/******************************************************************************
2 *   Copyright (C) 2009-2010, 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
14static int32_t currentBufferSize = DEFAULT_BUFFER_SIZE;
15
16static void extractFlag(char* buffer, int32_t bufferSize, char* flag, int32_t flagSize, UErrorCode *status);
17static 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 */
22U_CAPI int32_t U_EXPORT2
23parseFlagsFile(const char *fileName, char **flagBuffer, int32_t flagBufferSize, int32_t numOfFlags, UErrorCode *status) {
24    char* buffer = uprv_malloc(sizeof(char) * currentBufferSize);
25    UBool allocateMoreSpace = FALSE;
26    int32_t i;
27    int32_t result = 0;
28
29    FileStream *f = T_FileStream_open(fileName, "r");
30    if (f == NULL) {
31        *status = U_FILE_ACCESS_ERROR;
32        return -1;
33    }
34
35    if (buffer == NULL) {
36        *status = U_MEMORY_ALLOCATION_ERROR;
37        return -1;
38    }
39
40    do {
41        if (allocateMoreSpace) {
42            allocateMoreSpace = FALSE;
43            currentBufferSize *= 2;
44            uprv_free(buffer);
45            buffer = uprv_malloc(sizeof(char) * currentBufferSize);
46            if (buffer == NULL) {
47                *status = U_MEMORY_ALLOCATION_ERROR;
48                return -1;
49            }
50        }
51        for (i = 0; i < numOfFlags; i++) {
52            if (T_FileStream_readLine(f, buffer, currentBufferSize) == NULL) {
53                *status = U_FILE_ACCESS_ERROR;
54                break;
55            }
56
57            if (uprv_strlen(buffer) == (currentBufferSize - 1) && buffer[currentBufferSize-2] != '\n') {
58                /* Allocate more space for buffer if it didnot read the entrire line */
59                allocateMoreSpace = TRUE;
60                T_FileStream_rewind(f);
61                break;
62            } else {
63                extractFlag(buffer, currentBufferSize, flagBuffer[i], flagBufferSize, status);
64                if (U_FAILURE(*status)) {
65                    if (*status == U_BUFFER_OVERFLOW_ERROR) {
66                        result = currentBufferSize;
67                    } else {
68                        result = -1;
69                    }
70                    break;
71                }
72            }
73        }
74    } while (allocateMoreSpace && U_SUCCESS(*status));
75
76    uprv_free(buffer);
77
78    T_FileStream_close(f);
79
80    if (U_SUCCESS(*status) && result == 0) {
81        currentBufferSize = DEFAULT_BUFFER_SIZE;
82    }
83
84    return result;
85}
86
87
88/*
89 * Extract the setting after the '=' and store it in flag excluding the newline character.
90 */
91static void extractFlag(char* buffer, int32_t bufferSize, char* flag, int32_t flagSize, UErrorCode *status) {
92    int32_t i;
93    char *pBuffer;
94    int32_t offset;
95    UBool bufferWritten = FALSE;
96
97    if (buffer[0] != 0) {
98        /* Get the offset (i.e. position after the '=') */
99        offset = getFlagOffset(buffer, bufferSize);
100        pBuffer = buffer+offset;
101        for(i = 0;;i++) {
102            if (i >= flagSize) {
103                *status = U_BUFFER_OVERFLOW_ERROR;
104                return;
105            }
106            if (pBuffer[i+1] == 0) {
107                /* Indicates a new line character. End here. */
108                flag[i] = 0;
109                break;
110            }
111
112            flag[i] = pBuffer[i];
113            if (i == 0) {
114                bufferWritten = TRUE;
115            }
116        }
117    }
118
119    if (!bufferWritten) {
120        flag[0] = 0;
121    }
122}
123
124/*
125 * Get the position after the '=' character.
126 */
127static int32_t getFlagOffset(const char *buffer, int32_t bufferSize) {
128    int32_t offset = 0;
129
130    for (offset = 0; offset < bufferSize;offset++) {
131        if (buffer[offset] == '=') {
132            offset++;
133            break;
134        }
135    }
136
137    if (offset == bufferSize || (offset - 1) == bufferSize) {
138        offset = 0;
139    }
140
141    return offset;
142}
143