Home | History | Annotate | Download | only in intltest
      1 // Copyright (C) 2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /*
      4 **********************************************************************
      5 * Copyright (c) 2004,2011 International Business Machines
      6 * Corporation and others.  All Rights Reserved.
      7 **********************************************************************
      8 * Author: Alan Liu
      9 * Created: March 19 2004
     10 * Since: ICU 3.0
     11 **********************************************************************
     12 */
     13 #include "textfile.h"
     14 #include "cmemory.h"
     15 #include "cstring.h"
     16 #include "intltest.h"
     17 #include "util.h"
     18 
     19 // If the symbol CCP is defined, then the 'name' and 'encoding'
     20 // constructor parameters are copied.  Otherwise they are aliased.
     21 // #define CCP
     22 
     23 TextFile::TextFile(const char* _name, const char* _encoding, UErrorCode& ec) :
     24     file(0),
     25     name(0), encoding(0),
     26     buffer(0),
     27     capacity(0),
     28     lineNo(0)
     29 {
     30     if (U_FAILURE(ec) || _name == 0 || _encoding == 0) {
     31         if (U_SUCCESS(ec)) {
     32             ec = U_ILLEGAL_ARGUMENT_ERROR;
     33         }
     34         return;
     35     }
     36 
     37 #ifdef CCP
     38     name = uprv_malloc(uprv_strlen(_name) + 1);
     39     encoding = uprv_malloc(uprv_strlen(_encoding) + 1);
     40     if (name == 0 || encoding == 0) {
     41         ec = U_MEMORY_ALLOCATION_ERROR;
     42         return;
     43     }
     44     uprv_strcpy(name, _name);
     45     uprv_strcpy(encoding, _encoding);
     46 #else
     47     name = (char*) _name;
     48     encoding = (char*) _encoding;
     49 #endif
     50 
     51     const char* testDir = IntlTest::getSourceTestData(ec);
     52     if (U_FAILURE(ec)) {
     53         return;
     54     }
     55     if (!ensureCapacity((int32_t)(uprv_strlen(testDir) + uprv_strlen(name) + 1))) {
     56         ec = U_MEMORY_ALLOCATION_ERROR;
     57         return;
     58     }
     59     uprv_strcpy(buffer, testDir);
     60     uprv_strcat(buffer, name);
     61 
     62     file = T_FileStream_open(buffer, "rb");
     63     if (file == 0) {
     64         ec = U_ILLEGAL_ARGUMENT_ERROR;
     65         return;
     66     }
     67 }
     68 
     69 TextFile::~TextFile() {
     70     if (file != 0) T_FileStream_close(file);
     71     if (buffer != 0) uprv_free(buffer);
     72 #ifdef CCP
     73     uprv_free(name);
     74     uprv_free(encoding);
     75 #endif
     76 }
     77 
     78 UBool TextFile::readLine(UnicodeString& line, UErrorCode& ec) {
     79     if (T_FileStream_eof(file)) {
     80         return FALSE;
     81     }
     82     // Note: 'buffer' may change after ensureCapacity() is called,
     83     // so don't use
     84     //   p=buffer; *p++=c;
     85     // but rather
     86     //   i=; buffer[i++]=c;
     87     int32_t n = 0;
     88     for (;;) {
     89         int c = T_FileStream_getc(file); // sic: int, not int32_t
     90         if (c < 0 || c == 0xD || c == 0xA) {
     91             // consume 0xA following 0xD
     92             if (c == 0xD) {
     93                 c = T_FileStream_getc(file);
     94                 if (c != 0xA && c >= 0) {
     95                     T_FileStream_ungetc(c, file);
     96                 }
     97             }
     98             break;
     99         }
    100         if (!setBuffer(n++, c, ec)) return FALSE;
    101     }
    102     if (!setBuffer(n++, 0, ec)) return FALSE;
    103     UnicodeString str(buffer, encoding);
    104     // Remove BOM in first line, if present
    105     if (lineNo == 0 && str[0] == 0xFEFF) {
    106         str.remove(0, 1);
    107     }
    108     ++lineNo;
    109     line = str.unescape();
    110     return TRUE;
    111 }
    112 
    113 UBool TextFile::readLineSkippingComments(UnicodeString& line, UErrorCode& ec,
    114                                          UBool trim) {
    115     for (;;) {
    116         if (!readLine(line, ec)) return FALSE;
    117         // Skip over white space
    118         int32_t pos = 0;
    119         ICU_Utility::skipWhitespace(line, pos, TRUE);
    120         // Ignore blank lines and comment lines
    121         if (pos == line.length() || line.charAt(pos) == 0x23/*'#'*/) {
    122             continue;
    123         }
    124         // Process line
    125         if (trim) line.remove(0, pos);
    126         return TRUE;
    127     }
    128 }
    129 
    130 /**
    131  * Set buffer[index] to c, growing buffer if necessary. Return TRUE if
    132  * successful.
    133  */
    134 UBool TextFile::setBuffer(int32_t index, char c, UErrorCode& ec) {
    135     if (capacity <= index) {
    136         if (!ensureCapacity(index+1)) {
    137             ec = U_MEMORY_ALLOCATION_ERROR;
    138             return FALSE;
    139         }
    140     }
    141     buffer[index] = c;
    142     return TRUE;
    143 }
    144 
    145 /**
    146  * Make sure that 'buffer' has at least 'mincapacity' bytes.
    147  * Return TRUE upon success. Upon return, 'buffer' may change
    148  * value. In any case, previous contents are preserved.
    149  */
    150  #define LOWEST_MIN_CAPACITY 64
    151 UBool TextFile::ensureCapacity(int32_t mincapacity) {
    152     if (capacity >= mincapacity) {
    153         return TRUE;
    154     }
    155 
    156     // Grow by factor of 2 to prevent frequent allocation
    157     // Note: 'capacity' may be 0
    158     int32_t i = (capacity < LOWEST_MIN_CAPACITY)? LOWEST_MIN_CAPACITY: capacity;
    159     while (i < mincapacity) {
    160         i <<= 1;
    161         if (i < 0) {
    162             i = 0x7FFFFFFF;
    163             break;
    164         }
    165     }
    166     mincapacity = i;
    167 
    168     // Simple realloc() no good; contents not preserved
    169     // Note: 'buffer' may be 0
    170     char* newbuffer = (char*) uprv_malloc(mincapacity);
    171     if (newbuffer == 0) {
    172         return FALSE;
    173     }
    174     if (buffer != 0) {
    175         uprv_strncpy(newbuffer, buffer, capacity);
    176         uprv_free(buffer);
    177     }
    178     buffer = newbuffer;
    179     capacity = mincapacity;
    180     return TRUE;
    181 }
    182 
    183