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