1/*
2******************************************************************************
3*
4*   Copyright (C) 1998-2013, 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#include "ufile.h"
31#include "unicode/uloc.h"
32#include "unicode/ures.h"
33#include "unicode/ucnv.h"
34#include "cstring.h"
35#include "cmemory.h"
36
37#if U_PLATFORM_USES_ONLY_WIN32_API && !defined(fileno)
38/* Windows likes to rename Unix-like functions */
39#define fileno _fileno
40#endif
41
42static UFILE*
43finit_owner(FILE         *f,
44              const char *locale,
45              const char *codepage,
46              UBool       takeOwnership
47              )
48{
49    UErrorCode status = U_ZERO_ERROR;
50    UFILE     *result;
51    if(f == NULL) {
52        return 0;
53    }
54    result = (UFILE*) uprv_malloc(sizeof(UFILE));
55    if(result == NULL) {
56        return 0;
57    }
58
59    uprv_memset(result, 0, sizeof(UFILE));
60    result->fFileno = fileno(f);
61
62#if U_PLATFORM_USES_ONLY_WIN32_API
63    if (0 <= result->fFileno && result->fFileno <= 2) {
64        /* stdin, stdout and stderr need to be special cased for Windows 98 */
65#if _MSC_VER >= 1400
66        result->fFile = &__iob_func()[_fileno(f)];
67#else
68        result->fFile = &_iob[_fileno(f)];
69#endif
70    }
71    else
72#endif
73    {
74        result->fFile = f;
75    }
76
77    result->str.fBuffer = result->fUCBuffer;
78    result->str.fPos    = result->fUCBuffer;
79    result->str.fLimit  = result->fUCBuffer;
80
81#if !UCONFIG_NO_FORMATTING
82        /* if locale is 0, use the default */
83        if(u_locbund_init(&result->str.fBundle, locale) == 0) {
84            /* DO NOT FCLOSE HERE! */
85            uprv_free(result);
86            return 0;
87        }
88#endif
89
90    /* If the codepage is not "" use the ucnv_open default behavior */
91    if(codepage == NULL || *codepage != '\0') {
92        result->fConverter = ucnv_open(codepage, &status);
93    }
94    /* else result->fConverter is already memset'd to NULL. */
95
96    if(U_SUCCESS(status)) {
97        result->fOwnFile = takeOwnership;
98    }
99    else {
100#if !UCONFIG_NO_FORMATTING
101        u_locbund_close(&result->str.fBundle);
102#endif
103        /* DO NOT fclose here!!!!!! */
104        uprv_free(result);
105        result = NULL;
106    }
107
108    return result;
109}
110
111U_CAPI UFILE* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
112u_finit(FILE          *f,
113        const char    *locale,
114        const char    *codepage)
115{
116    return finit_owner(f, locale, codepage, FALSE);
117}
118
119U_CAPI UFILE* U_EXPORT2
120u_fadopt(FILE         *f,
121        const char    *locale,
122        const char    *codepage)
123{
124    return finit_owner(f, locale, codepage, TRUE);
125}
126
127U_CAPI UFILE* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
128u_fopen(const char    *filename,
129        const char    *perm,
130        const char    *locale,
131        const char    *codepage)
132{
133    UFILE     *result;
134    FILE     *systemFile = fopen(filename, perm);
135    if(systemFile == 0) {
136        return 0;
137    }
138
139    result = finit_owner(systemFile, locale, codepage, TRUE);
140
141    if (!result) {
142        /* Something bad happened.
143           Maybe the converter couldn't be opened. */
144        fclose(systemFile);
145    }
146
147    return result; /* not a file leak */
148}
149
150U_CAPI UFILE* U_EXPORT2
151u_fstropen(UChar *stringBuf,
152           int32_t      capacity,
153           const char  *locale)
154{
155    UFILE *result;
156
157    if (capacity < 0) {
158        return NULL;
159    }
160
161    result = (UFILE*) uprv_malloc(sizeof(UFILE));
162    /* Null pointer test */
163    if (result == NULL) {
164    	return NULL; /* Just get out. */
165    }
166    uprv_memset(result, 0, sizeof(UFILE));
167    result->str.fBuffer = stringBuf;
168    result->str.fPos    = stringBuf;
169    result->str.fLimit  = stringBuf+capacity;
170
171#if !UCONFIG_NO_FORMATTING
172    /* if locale is 0, use the default */
173    if(u_locbund_init(&result->str.fBundle, locale) == 0) {
174        /* DO NOT FCLOSE HERE! */
175        uprv_free(result);
176        return 0;
177    }
178#endif
179
180    return result;
181}
182
183U_CAPI UBool U_EXPORT2
184u_feof(UFILE  *f)
185{
186    UBool endOfBuffer;
187    if (f == NULL) {
188        return TRUE;
189    }
190    endOfBuffer = (UBool)(f->str.fPos >= f->str.fLimit);
191    if (f->fFile != NULL) {
192        return endOfBuffer && feof(f->fFile);
193    }
194    return endOfBuffer;
195}
196
197U_CAPI void U_EXPORT2
198u_fflush(UFILE *file)
199{
200    ufile_flush_translit(file);
201    ufile_flush_io(file);
202    if (file->fFile) {
203        fflush(file->fFile);
204    }
205    else if (file->str.fPos < file->str.fLimit) {
206        *(file->str.fPos++) = 0;
207    }
208    /* TODO: flush input */
209}
210
211U_CAPI void
212u_frewind(UFILE *file)
213{
214    u_fflush(file);
215    ucnv_reset(file->fConverter);
216    if (file->fFile) {
217        rewind(file->fFile);
218        file->str.fLimit = file->fUCBuffer;
219        file->str.fPos   = file->fUCBuffer;
220    }
221    else {
222        file->str.fPos = file->str.fBuffer;
223    }
224}
225
226U_CAPI void U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
227u_fclose(UFILE *file)
228{
229    if (file) {
230        u_fflush(file);
231        ufile_close_translit(file);
232
233        if(file->fOwnFile)
234            fclose(file->fFile);
235
236#if !UCONFIG_NO_FORMATTING
237        u_locbund_close(&file->str.fBundle);
238#endif
239
240        ucnv_close(file->fConverter);
241        uprv_free(file);
242    }
243}
244
245U_CAPI FILE* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
246u_fgetfile(    UFILE         *f)
247{
248    return f->fFile;
249}
250
251#if !UCONFIG_NO_FORMATTING
252
253U_CAPI const char*  U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
254u_fgetlocale(    UFILE        *file)
255{
256    return file->str.fBundle.fLocale;
257}
258
259U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
260u_fsetlocale(UFILE      *file,
261             const char *locale)
262{
263    u_locbund_close(&file->str.fBundle);
264
265    return u_locbund_init(&file->str.fBundle, locale) == 0 ? -1 : 0;
266}
267
268#endif
269
270U_CAPI const char* U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
271u_fgetcodepage(UFILE        *file)
272{
273    UErrorCode     status = U_ZERO_ERROR;
274    const char     *codepage = NULL;
275
276    if (file->fConverter) {
277        codepage = ucnv_getName(file->fConverter, &status);
278        if(U_FAILURE(status))
279            return 0;
280    }
281    return codepage;
282}
283
284U_CAPI int32_t U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
285u_fsetcodepage(    const char    *codepage,
286               UFILE        *file)
287{
288    UErrorCode status = U_ZERO_ERROR;
289    int32_t retVal = -1;
290
291    /* We use the normal default codepage for this system, and not the one for the locale. */
292    if ((file->str.fPos == file->str.fBuffer) && (file->str.fLimit == file->str.fBuffer)) {
293        ucnv_close(file->fConverter);
294        file->fConverter = ucnv_open(codepage, &status);
295        if(U_SUCCESS(status)) {
296            retVal = 0;
297        }
298    }
299    return retVal;
300}
301
302
303U_CAPI UConverter * U_EXPORT2 /* U_CAPI ... U_EXPORT2 added by Peter Kirk 17 Nov 2001 */
304u_fgetConverter(UFILE *file)
305{
306    return file->fConverter;
307}
308#if !UCONFIG_NO_FORMATTING
309U_CAPI const UNumberFormat* U_EXPORT2 u_fgetNumberFormat(UFILE *file)
310{
311    return u_locbund_getNumberFormat(&file->str.fBundle, UNUM_DECIMAL);
312}
313#endif
314
315