OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [linux/] [uClibc/] [libc/] [misc/] [wchar/] [wstdio.c] - Blame information for rev 1782

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1325 phoenix
/*  Copyright (C) 2002     Manuel Novoa III
2
 *
3
 *  This library is free software; you can redistribute it and/or
4
 *  modify it under the terms of the GNU Library General Public
5
 *  License as published by the Free Software Foundation; either
6
 *  version 2 of the License, or (at your option) any later version.
7
 *
8
 *  This library is distributed in the hope that it will be useful,
9
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
 *  Library General Public License for more details.
12
 *
13
 *  You should have received a copy of the GNU Library General Public
14
 *  License along with this library; if not, write to the Free
15
 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16
 */
17
 
18
/*  ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION!
19
 *
20
 *  Besides uClibc, I'm using this code in my libc for elks, which is
21
 *  a 16-bit environment with a fairly limited compiler.  It would make
22
 *  things much easier for me if this file isn't modified unnecessarily.
23
 *  In particular, please put any new or replacement functions somewhere
24
 *  else, and modify the makefile to use your version instead.
25
 *  Thanks.  Manuel
26
 *
27
 *  ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION! */
28
 
29
/* Nov 21, 2002
30
 *
31
 * Reimplement fputwc and fputws in terms of internal function _wstdio_fwrite.
32
 */
33
 
34
 
35
 
36
 
37
/*
38
 * ANSI/ISO C99 says
39
 
40
 9 Although both text and binary wide­oriented streams are conceptually sequences of wide
41
 characters, the external file associated with a wide­oriented stream is a sequence of
42
 multibyte characters, generalized as follows:
43
 --- Multibyte encodings within files may contain embedded null bytes (unlike multibyte
44
 encodings valid for use internal to the program).
45
 --- A file need not begin nor end in the initial shift state. 225)
46
 
47
 * How do we deal with this?
48
 
49
 * Should auto_wr_transition init the mbstate object?
50
*/
51
 
52
 
53
#define _GNU_SOURCE
54
#include <stdio.h>
55
#include <wchar.h>
56
#include <limits.h>
57
#include <errno.h>
58
#include <assert.h>
59
 
60
#ifndef __STDIO_THREADSAFE
61
 
62
#ifdef __BCC__
63
#define UNLOCKED_STREAM(RETURNTYPE,NAME,PARAMS,ARGS,STREAM) \
64
asm(".text\nexport _" "NAME" "_unlocked\n_" "NAME" "_unlocked = _" "NAME"); \
65
RETURNTYPE NAME PARAMS
66
#else
67
#define UNLOCKED_STREAM(RETURNTYPE,NAME,PARAMS,ARGS,STREAM) \
68
strong_alias(NAME,NAME##_unlocked) \
69
RETURNTYPE NAME PARAMS
70
#endif
71
 
72
#define UNLOCKED(RETURNTYPE,NAME,PARAMS,ARGS) \
73
        UNLOCKED_STREAM(RETURNTYPE,NAME,PARAMS,ARGS,stream)
74
 
75
#ifdef __BCC__
76
#define UNLOCKED_VOID_RETURN(NAME,PARAMS,ARGS) \
77
asm(".text\nexport _" "NAME" "_unlocked\n_" "NAME" "_unlocked = _" "NAME"); \
78
void NAME PARAMS
79
#else
80
#define UNLOCKED_VOID_RETURN(NAME,PARAMS,ARGS) \
81
strong_alias(NAME,NAME##_unlocked) \
82
void NAME PARAMS
83
#endif
84
 
85
#define __STDIO_THREADLOCK_OPENLIST
86
#define __STDIO_THREADUNLOCK_OPENLIST
87
 
88
#else  /* __STDIO_THREADSAFE */
89
 
90
#include <pthread.h>
91
 
92
#define UNLOCKED_STREAM(RETURNTYPE,NAME,PARAMS,ARGS,STREAM) \
93
RETURNTYPE NAME PARAMS \
94
{ \
95
        RETURNTYPE retval; \
96
        __STDIO_THREADLOCK(STREAM); \
97
        retval = NAME##_unlocked ARGS ; \
98
        __STDIO_THREADUNLOCK(STREAM); \
99
        return retval; \
100
} \
101
RETURNTYPE NAME##_unlocked PARAMS
102
 
103
#define UNLOCKED(RETURNTYPE,NAME,PARAMS,ARGS) \
104
        UNLOCKED_STREAM(RETURNTYPE,NAME,PARAMS,ARGS,stream)
105
 
106
#define UNLOCKED_VOID_RETURN(NAME,PARAMS,ARGS) \
107
void NAME PARAMS \
108
{ \
109
        __STDIO_THREADLOCK(stream); \
110
        NAME##_unlocked ARGS ; \
111
        __STDIO_THREADUNLOCK(stream); \
112
} \
113
void NAME##_unlocked PARAMS
114
 
115
#define __STDIO_THREADLOCK_OPENLIST \
116
        __pthread_mutex_lock(&_stdio_openlist_lock)
117
 
118
#define __STDIO_THREADUNLOCK_OPENLIST \
119
        __pthread_mutex_unlock(&_stdio_openlist_lock)
120
 
121
#define __STDIO_THREADTRYLOCK_OPENLIST \
122
        __pthread_mutex_trylock(&_stdio_openlist_lock)
123
 
124
#endif /* __STDIO_THREADSAFE */
125
 
126
#ifndef __STDIO_BUFFERS
127
#error stdio buffers are currently required for wide i/o
128
#endif
129
 
130
/**********************************************************************/
131
#ifdef L_fwide
132
 
133
/* TODO: According to SUSv3 should return EBADF if invalid stream. */
134
 
135
int fwide(register FILE *stream, int mode)
136
{
137
        __STDIO_THREADLOCK(stream);
138
 
139
        if (mode && !(stream->modeflags & (__FLAG_WIDE|__FLAG_NARROW))) {
140
                stream->modeflags |= ((mode > 0) ? __FLAG_WIDE : __FLAG_NARROW);
141
        }
142
 
143
        mode = (stream->modeflags & __FLAG_WIDE)
144
                - (stream->modeflags & __FLAG_NARROW);
145
 
146
        __STDIO_THREADUNLOCK(stream);
147
 
148
        return mode;
149
}
150
 
151
#endif
152
/**********************************************************************/
153
#ifdef L_fgetwc
154
 
155
static void munge_stream(register FILE *stream, unsigned char *buf)
156
{
157
#ifdef __STDIO_GETC_MACRO
158
        stream->bufgetc =
159
#endif
160
#ifdef __STDIO_PUTC_MACRO
161
        stream->bufputc =
162
#endif
163
        stream->bufpos = stream->bufread = stream->bufend = stream->bufstart = buf;
164
}
165
 
166
UNLOCKED(wint_t,fgetwc,(register FILE *stream),(stream))
167
{
168
        wint_t wi;
169
        wchar_t wc[1];
170
        int n;
171
        size_t r;
172
        unsigned char c[1];
173
        unsigned char sbuf[1];
174
 
175
        wi = WEOF;                                      /* Prepare for failure. */
176
 
177
        if (stream->modeflags & __FLAG_NARROW) {
178
                stream->modeflags |= __FLAG_ERROR;
179
                __set_errno(EBADF);
180
                goto DONE;
181
        }
182
        stream->modeflags |= __FLAG_WIDE;
183
 
184
        if (stream->modeflags & __MASK_UNGOT) {/* Any ungetwc()s? */
185
 
186
                assert(stream->modeflags & __FLAG_READING);
187
 
188
/*              assert( (stream->modeflags & (__FLAG_READING|__FLAG_ERROR)) */
189
/*                              == __FLAG_READING); */
190
 
191
                if ((((stream->modeflags & __MASK_UNGOT) > 1) || stream->ungot[1])) {
192
                        stream->ungot_width[0] = 0;       /* Application ungot... */
193
                } else {
194
                        stream->ungot_width[0] = stream->ungot_width[1]; /* scanf ungot */
195
                }
196
 
197
                wi = stream->ungot[(--stream->modeflags) & __MASK_UNGOT];
198
                stream->ungot[1] = 0;
199
                goto DONE;
200
        }
201
 
202
        if (!stream->bufstart) {        /* Ugh... stream isn't buffered! */
203
                /* Munge the stream temporarily to use a 1-byte buffer. */
204
                munge_stream(stream, sbuf);
205
                ++stream->bufend;
206
        }
207
 
208
        if (stream->state.mask == 0) { /* If last was a complete char */
209
                stream->ungot_width[0] = 0;       /* then reset the width. */
210
        }
211
 
212
 LOOP:
213
        if ((n = stream->bufread - stream->bufpos) == 0) {
214
                goto FILL_BUFFER;
215
        }
216
 
217
        r = mbrtowc(wc, stream->bufpos, n, &stream->state);
218
        if (((ssize_t) r) >= 0) {        /* Success... */
219
                if (r == 0) {                    /* Nul wide char... means 0 byte for us so */
220
                        ++r;                            /* increment r and handle below as single. */
221
                }
222
                stream->bufpos += r;
223
                stream->ungot_width[0] += r;
224
                wi = *wc;
225
                goto DONE;
226
        }
227
 
228
        if (r == ((size_t) -2)) {
229
                /* Potentially valid but incomplete and no more buffered. */
230
                stream->bufpos += n;    /* Update bufpos for stream. */
231
                stream->ungot_width[0] += n;
232
        FILL_BUFFER:
233
                if (_stdio_fread(c, (size_t) 1, stream) > 0) {
234
                        assert(stream->bufpos == stream->bufstart + 1);
235
                        *--stream->bufpos = *c; /* Insert byte into buffer. */
236
                        goto LOOP;
237
                }
238
                if (!__FERROR(stream)) { /* EOF with no error. */
239
                        if (!stream->state.mask) {      /* No partially complete wchar. */
240
                                goto DONE;
241
                        }
242
                        /* EOF but partially complete wchar. */
243
                        /* TODO: should EILSEQ be set? */
244
                        __set_errno(EILSEQ);
245
                }
246
        }
247
 
248
        /* If we reach here, either r == ((size_t)-1) and mbrtowc set errno
249
         * to EILSEQ, or r == ((size_t)-2) and stream is in an error state
250
         * or at EOF with a partially complete wchar.  Make sure stream's
251
         * error indicator is set. */
252
        stream->modeflags |= __FLAG_ERROR;
253
 
254
 DONE:
255
        if (stream->bufstart == sbuf) { /* Need to un-munge the stream. */
256
                munge_stream(stream, NULL);
257
        }
258
 
259
        return wi;
260
}
261
 
262
strong_alias(fgetwc_unlocked,getwc_unlocked);
263
strong_alias(fgetwc,getwc);
264
 
265
#endif
266
/**********************************************************************/
267
#ifdef L_getwchar
268
 
269
UNLOCKED_STREAM(wint_t,getwchar,(void),(),stdin)
270
{
271
        register FILE *stream = stdin; /* This helps bcc optimize. */
272
 
273
        return fgetwc_unlocked(stream);
274
}
275
 
276
#endif
277
/**********************************************************************/
278
#ifdef L_fgetws
279
 
280
UNLOCKED(wchar_t *,fgetws,(wchar_t *__restrict ws, int n,
281
                                                   FILE *__restrict stream),(ws, n, stream))
282
{
283
        register wchar_t *p = ws;
284
        wint_t wi;
285
 
286
        while ((n > 1)
287
                   && ((wi = fgetwc_unlocked(stream)) != WEOF)
288
                   && ((*p++ = wi) != '\n')
289
                   ) {
290
                --n;
291
        }
292
        if (p == ws) {
293
                /* TODO -- should we set errno? */
294
/*              if (n <= 0) { */
295
/*                      errno = EINVAL; */
296
/*              } */
297
                return NULL;
298
        }
299
        *p = 0;
300
        return ws;
301
}
302
 
303
#endif
304
/**********************************************************************/
305
#ifdef L_fputwc
306
 
307
UNLOCKED(wint_t,fputwc,(wchar_t wc, FILE *stream),(wc, stream))
308
{
309
#if 1
310
        return _wstdio_fwrite(&wc, 1, stream) ? wc : WEOF;
311
#else
312
        size_t n;
313
        char buf[MB_LEN_MAX];
314
 
315
        if (stream->modeflags & __FLAG_NARROW) {
316
                stream->modeflags |= __FLAG_ERROR;
317
                __set_errno(EBADF);
318
                return WEOF;
319
        }
320
        stream->modeflags |= __FLAG_WIDE;
321
 
322
        return (((n = wcrtomb(buf, wc, &stream->state)) != ((size_t)-1)) /* !EILSEQ */
323
                        && (_stdio_fwrite(buf, n, stream) == n))/* and wrote everything. */
324
                ? wc : WEOF;
325
#endif
326
}
327
 
328
strong_alias(fputwc_unlocked,putwc_unlocked);
329
strong_alias(fputwc,putwc);
330
 
331
#endif
332
/**********************************************************************/
333
#ifdef L_putwchar
334
 
335
UNLOCKED_STREAM(wint_t,putwchar,(wchar_t wc),(wc),stdout)
336
{
337
        register FILE *stream = stdout; /* This helps bcc optimize. */
338
 
339
        return fputwc_unlocked(wc, stream);
340
}
341
 
342
#endif
343
/**********************************************************************/
344
#ifdef L_fputws
345
 
346
UNLOCKED(int,fputws,(const wchar_t *__restrict ws,
347
                                         register FILE *__restrict stream),(ws, stream))
348
{
349
#if 1
350
        size_t n = wcslen(ws);
351
 
352
        return (_wstdio_fwrite(ws, n, stream) == n) ? 0 : -1;
353
#else
354
        size_t n;
355
        char buf[64];
356
 
357
        if (stream->modeflags & __FLAG_NARROW) {
358
                stream->modeflags |= __FLAG_ERROR;
359
                __set_errno(EBADF);
360
                return -1;
361
        }
362
        stream->modeflags |= __FLAG_WIDE;
363
 
364
        while ((n = wcsrtombs(buf, &ws, sizeof(buf), &stream->state)) != 0) {
365
                /* Wasn't an empty wide string. */
366
                if ((n == ((size_t) -1))/* Encoding error! */
367
                         || (_stdio_fwrite(buf, n, stream) != n)/* Didn't write everything. */
368
                         ) {
369
                        return -1;
370
                }
371
                if (!ws) {                              /* Done? */
372
                        break;
373
                }
374
        }
375
 
376
        return 1;
377
#endif
378
}
379
 
380
#endif
381
/**********************************************************************/
382
#ifdef L_ungetwc
383
/*
384
 * Note: This is the application-callable ungetwc.  If wscanf calls this, it
385
 * should also set stream->ungot[1] to 0 if this is the only ungot, as well
386
 * as reset stream->ungot_width[1] for use by _stdio_adjpos().
387
 */
388
 
389
/* Reentrant. */
390
 
391
wint_t ungetwc(wint_t c, register FILE *stream)
392
{
393
        __STDIO_THREADLOCK(stream);
394
 
395
        __stdio_validate_FILE(stream); /* debugging only */
396
 
397
        if (stream->modeflags & __FLAG_NARROW) {
398
                stream->modeflags |= __FLAG_ERROR;
399
                c = WEOF;
400
                goto DONE;
401
        }
402
        stream->modeflags |= __FLAG_WIDE;
403
 
404
        /* If can't read or c == WEOF or ungot slots already filled, then fail. */
405
        if ((stream->modeflags
406
                 & (__MASK_UNGOT2|__FLAG_WRITEONLY
407
#ifndef __STDIO_AUTO_RW_TRANSITION
408
                        |__FLAG_WRITING         /* Note: technically no, but yes in spirit */
409
#endif /* __STDIO_AUTO_RW_TRANSITION */
410
                        ))
411
                || ((stream->modeflags & __MASK_UNGOT1) && (stream->ungot[1]))
412
                || (c == WEOF) ) {
413
                c = WEOF;
414
                goto DONE;;
415
        }
416
 
417
/*  ungot_width */
418
 
419
#ifdef __STDIO_BUFFERS
420
#ifdef __STDIO_AUTO_RW_TRANSITION
421
        if (stream->modeflags & __FLAG_WRITING) {
422
                fflush_unlocked(stream); /* Commit any write-buffered chars. */
423
        }
424
#endif /* __STDIO_AUTO_RW_TRANSITION */
425
#endif /* __STDIO_BUFFERS */
426
 
427
        /* Clear EOF and WRITING flags, and set READING FLAG */
428
        stream->modeflags &= ~(__FLAG_EOF|__FLAG_WRITING);
429
#ifdef __UCLIBC_MJN3_ONLY__
430
#warning CONSIDER: Is setting the reading flag after an ungetwc necessary?
431
#endif /* __UCLIBC_MJN3_ONLY__ */
432
        stream->modeflags |= __FLAG_READING;
433
        stream->ungot[1] = 1;           /* Flag as app ungetc call; wscanf fixes up. */
434
        stream->ungot[(stream->modeflags++) & __MASK_UNGOT] = c;
435
 
436
        __stdio_validate_FILE(stream); /* debugging only */
437
 
438
 DONE:
439
        __STDIO_THREADUNLOCK(stream);
440
 
441
        return c;
442
}
443
 
444
#endif
445
/**********************************************************************/

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.