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