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