Home | History | Annotate | Download | only in io
      1 // Copyright (C) 2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /*
      4 ******************************************************************************
      5 *
      6 *   Copyright (C) 1998-2015, International Business Machines
      7 *   Corporation and others.  All Rights Reserved.
      8 *
      9 ******************************************************************************
     10 *
     11 * File ufile.c
     12 *
     13 * Modification History:
     14 *
     15 *   Date        Name        Description
     16 *   11/19/98    stephen     Creation.
     17 *   03/12/99    stephen     Modified for new C API.
     18 *   06/16/99    stephen     Changed T_LocaleBundle to u_locbund
     19 *   07/19/99    stephen     Fixed to use ucnv's default codepage.
     20 ******************************************************************************
     21 */
     22 
     23 /*
     24  * fileno is not declared when building with GCC in strict mode.
     25  */
     26 #if defined(__GNUC__) && defined(__STRICT_ANSI__)
     27 #undef __STRICT_ANSI__
     28 #endif
     29 
     30 #include "locmap.h"
     31 #include "unicode/ustdio.h"
     32 
     33 #if !UCONFIG_NO_CONVERSION
     34 
     35 #include "ufile.h"
     36 #include "unicode/uloc.h"
     37 #include "unicode/ures.h"
     38 #include "unicode/ucnv.h"
     39 #include "unicode/ustring.h"
     40 #include "cstring.h"
     41 #include "cmemory.h"
     42 
     43 #if U_PLATFORM_USES_ONLY_WIN32_API && !defined(fileno)
     44 /* Windows likes to rename Unix-like functions */
     45 #define fileno _fileno
     46 #endif
     47 
     48 static UFILE*
     49 finit_owner(FILE         *f,
     50               const char *locale,
     51               const char *codepage,
     52               UBool       takeOwnership
     53               )
     54 {
     55     UErrorCode status = U_ZERO_ERROR;
     56     UFILE     *result;
     57     if(f == NULL) {
     58         return 0;
     59     }
     60     result = (UFILE*) uprv_malloc(sizeof(UFILE));
     61     if(result == NULL) {
     62         return 0;
     63     }
     64 
     65     uprv_memset(result, 0, sizeof(UFILE));
     66     result->fFileno = fileno(f);
     67 
     68 #if U_PLATFORM_USES_ONLY_WIN32_API && _MSC_VER < 1900
     69     /*
     70      * Below is a very old workaround (ICU ticket:231).
     71      *
     72      * Previously, 'FILE*' from inside and outside ICU's DLL
     73      * were different, because they pointed into local copies
     74      * of the io block. At least by VS 2015 the implementation
     75      * is something like:
     76      *    stdio = _acrt_iob_func(0)
     77      * .. which is a function call, so should return the same pointer
     78      * regardless of call site.
     79      * As of _MSC_VER 1900 this patch is retired, at 16 years old.
     80      */
     81     if (0 <= result->fFileno && result->fFileno <= 2) {
     82         /* stdin, stdout and stderr need to be special cased for Windows 98 */
     83 #if _MSC_VER >= 1400
     84         result->fFile = &__iob_func()[_fileno(f)];
     85 #else
     86         result->fFile = &_iob[_fileno(f)];
     87 #endif
     88     }
     89     else
     90 #endif
     91     {
     92         result->fFile = f;
     93     }
     94 
     95     result->str.fBuffer = result->fUCBuffer;
     96     result->str.fPos    = result->fUCBuffer;
     97     result->str.fLimit  = result->fUCBuffer;
     98 
     99 #if !UCONFIG_NO_FORMATTING
    100         /* if locale is 0, use the default */
    101         if(u_locbund_init(&result->str.fBundle, locale) == 0) {
    102             /* DO NOT FCLOSE HERE! */
    103             uprv_free(result);
    104             return 0;
    105         }
    106 #endif
    107 
    108     /* If the codepage is not "" use the ucnv_open default behavior */
    109     if(codepage == NULL || *codepage != '\0') {
    110         result->fConverter = ucnv_open(codepage, &status);
    111     }
    112     /* else result->fConverter is already memset'd to NULL. */
    113 
    114     if(U_SUCCESS(status)) {
    115         result->fOwnFile = takeOwnership;
    116     }
    117     else {
    118 #if !UCONFIG_NO_FORMATTING
    119         u_locbund_close(&result->str.fBundle);
    120 #endif
    121         /* DO NOT fclose here!!!!!! */
    122         uprv_free(result);
    123         result = NULL;
    124     }
    125 
    126     return result;
    127 }
    128 
    129 U_CAPI UFILE* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
    130 u_finit(FILE          *f,
    131         const char    *locale,
    132         const char    *codepage)
    133 {
    134     return finit_owner(f, locale, codepage, FALSE);
    135 }
    136 
    137 U_CAPI UFILE* U_EXPORT2
    138 u_fadopt(FILE         *f,
    139         const char    *locale,
    140         const char    *codepage)
    141 {
    142     return finit_owner(f, locale, codepage, TRUE);
    143 }
    144 
    145 U_CAPI UFILE* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
    146 u_fopen(const char    *filename,
    147         const char    *perm,
    148         const char    *locale,
    149         const char    *codepage)
    150 {
    151     UFILE     *result;
    152     FILE     *systemFile = fopen(filename, perm);
    153     if(systemFile == 0) {
    154         return 0;
    155     }
    156 
    157     result = finit_owner(systemFile, locale, codepage, TRUE);
    158 
    159     if (!result) {
    160         /* Something bad happened.
    161            Maybe the converter couldn't be opened. */
    162         fclose(systemFile);
    163     }
    164 
    165     return result; /* not a file leak */
    166 }
    167 
    168 U_CAPI UFILE* U_EXPORT2
    169 u_fopen_u(const UChar   *filename,
    170         const char    *perm,
    171         const char    *locale,
    172         const char    *codepage)
    173 {
    174     UFILE     *result;
    175     char buffer[256];
    176 
    177     u_austrcpy(buffer, filename);
    178 
    179     result = u_fopen(buffer, perm, locale, codepage);
    180 #if U_PLATFORM_USES_ONLY_WIN32_API
    181     /* Try Windows API _wfopen if the above fails. */
    182     if (!result) {
    183         FILE *systemFile = _wfopen(filename, (UChar*)perm);
    184         if (systemFile) {
    185             result = finit_owner(systemFile, locale, codepage, TRUE);
    186         }
    187         if (!result) {
    188             /* Something bad happened.
    189                Maybe the converter couldn't be opened. */
    190             fclose(systemFile);
    191         }
    192     }
    193 #endif
    194     return result; /* not a file leak */
    195 }
    196 
    197 U_CAPI UFILE* U_EXPORT2
    198 u_fstropen(UChar *stringBuf,
    199            int32_t      capacity,
    200            const char  *locale)
    201 {
    202     UFILE *result;
    203 
    204     if (capacity < 0) {
    205         return NULL;
    206     }
    207 
    208     result = (UFILE*) uprv_malloc(sizeof(UFILE));
    209     /* Null pointer test */
    210     if (result == NULL) {
    211     	return NULL; /* Just get out. */
    212     }
    213     uprv_memset(result, 0, sizeof(UFILE));
    214     result->str.fBuffer = stringBuf;
    215     result->str.fPos    = stringBuf;
    216     result->str.fLimit  = stringBuf+capacity;
    217 
    218 #if !UCONFIG_NO_FORMATTING
    219     /* if locale is 0, use the default */
    220     if(u_locbund_init(&result->str.fBundle, locale) == 0) {
    221         /* DO NOT FCLOSE HERE! */
    222         uprv_free(result);
    223         return 0;
    224     }
    225 #endif
    226 
    227     return result;
    228 }
    229 
    230 U_CAPI UBool U_EXPORT2
    231 u_feof(UFILE  *f)
    232 {
    233     UBool endOfBuffer;
    234     if (f == NULL) {
    235         return TRUE;
    236     }
    237     endOfBuffer = (UBool)(f->str.fPos >= f->str.fLimit);
    238     if (f->fFile != NULL) {
    239         return endOfBuffer && feof(f->fFile);
    240     }
    241     return endOfBuffer;
    242 }
    243 
    244 U_CAPI void U_EXPORT2
    245 u_fflush(UFILE *file)
    246 {
    247     ufile_flush_translit(file);
    248     ufile_flush_io(file);
    249     if (file->fFile) {
    250         fflush(file->fFile);
    251     }
    252     else if (file->str.fPos < file->str.fLimit) {
    253         *(file->str.fPos++) = 0;
    254     }
    255     /* TODO: flush input */
    256 }
    257 
    258 U_CAPI void
    259 u_frewind(UFILE *file)
    260 {
    261     u_fflush(file);
    262     ucnv_reset(file->fConverter);
    263     if (file->fFile) {
    264         rewind(file->fFile);
    265         file->str.fLimit = file->fUCBuffer;
    266         file->str.fPos   = file->fUCBuffer;
    267     }
    268     else {
    269         file->str.fPos = file->str.fBuffer;
    270     }
    271 }
    272 
    273 U_CAPI void U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
    274 u_fclose(UFILE *file)
    275 {
    276     if (file) {
    277         u_fflush(file);
    278         ufile_close_translit(file);
    279 
    280         if(file->fOwnFile)
    281             fclose(file->fFile);
    282 
    283 #if !UCONFIG_NO_FORMATTING
    284         u_locbund_close(&file->str.fBundle);
    285 #endif
    286 
    287         ucnv_close(file->fConverter);
    288         uprv_free(file);
    289     }
    290 }
    291 
    292 U_CAPI FILE* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
    293 u_fgetfile(    UFILE         *f)
    294 {
    295     return f->fFile;
    296 }
    297 
    298 #if !UCONFIG_NO_FORMATTING
    299 
    300 U_CAPI const char*  U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
    301 u_fgetlocale(    UFILE        *file)
    302 {
    303     return file->str.fBundle.fLocale;
    304 }
    305 
    306 U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
    307 u_fsetlocale(UFILE      *file,
    308              const char *locale)
    309 {
    310     u_locbund_close(&file->str.fBundle);
    311 
    312     return u_locbund_init(&file->str.fBundle, locale) == 0 ? -1 : 0;
    313 }
    314 
    315 #endif
    316 
    317 U_CAPI const char* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
    318 u_fgetcodepage(UFILE        *file)
    319 {
    320     UErrorCode     status = U_ZERO_ERROR;
    321     const char     *codepage = NULL;
    322 
    323     if (file->fConverter) {
    324         codepage = ucnv_getName(file->fConverter, &status);
    325         if(U_FAILURE(status))
    326             return 0;
    327     }
    328     return codepage;
    329 }
    330 
    331 U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
    332 u_fsetcodepage(    const char    *codepage,
    333                UFILE        *file)
    334 {
    335     UErrorCode status = U_ZERO_ERROR;
    336     int32_t retVal = -1;
    337 
    338     /* We use the normal default codepage for this system, and not the one for the locale. */
    339     if ((file->str.fPos == file->str.fBuffer) && (file->str.fLimit == file->str.fBuffer)) {
    340         ucnv_close(file->fConverter);
    341         file->fConverter = ucnv_open(codepage, &status);
    342         if(U_SUCCESS(status)) {
    343             retVal = 0;
    344         }
    345     }
    346     return retVal;
    347 }
    348 
    349 
    350 U_CAPI UConverter * U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
    351 u_fgetConverter(UFILE *file)
    352 {
    353     return file->fConverter;
    354 }
    355 #if !UCONFIG_NO_FORMATTING
    356 U_CAPI const UNumberFormat* U_EXPORT2 u_fgetNumberFormat(UFILE *file)
    357 {
    358     return u_locbund_getNumberFormat(&file->str.fBundle, UNUM_DECIMAL);
    359 }
    360 #endif
    361 
    362 #endif
    363