Home | History | Annotate | Download | only in toolutil
      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
     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  */
    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  */
    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