Home | History | Annotate | Download | only in toolutil
      1 //  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 = (char *)uprv_malloc(sizeof(char) * currentBufferSize);
     39     tmpFlagBuffer = (char *)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 = (char *)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 }
    181