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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [uClibc/] [libc/] [stdio/] [stdio.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1325 phoenix
/*  Copyright (C) 2002,2003,2004     Manuel Novoa III
2
 *  My stdio library for linux and (soon) elks.
3
 *
4
 *  This library is free software; you can redistribute it and/or
5
 *  modify it under the terms of the GNU Library General Public
6
 *  License as published by the Free Software Foundation; either
7
 *  version 2 of the License, or (at your option) any later version.
8
 *
9
 *  This library is distributed in the hope that it will be useful,
10
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 *  Library General Public License for more details.
13
 *
14
 *  You should have received a copy of the GNU Library General Public
15
 *  License along with this library; if not, write to the Free
16
 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
 */
18
 
19
/*  ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION!
20
 *
21
 *  This code is currently under development.  Also, I plan to port
22
 *  it to elks which is a 16-bit environment with a fairly limited
23
 *  compiler.  Therefore, please refrain from modifying this code
24
 *  and, instead, pass any bug-fixes, etc. to me.  Thanks.  Manuel
25
 *
26
 *  ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION!   ATTENTION! */
27
 
28
/*  8-05-2002
29
 *  Changed fflush() behavior to no-op for r/w streams in read-mode.
30
 *     This falls under undefined behavior wrt ANSI/ISO C99, but
31
 *     SUSv3 seems to treat it as a no-op and it occurs in some apps.
32
 *  Fixed a problem with _stdio_fwrite() not checking for underlying
33
 *     write() failures.
34
 *  Fixed both _stdio_fwrite() and _stdio_fread() to make sure that
35
 *     the putc and getc macros were disabled if the stream was in
36
 *     and error state.
37
 *  The above changes should take care of a problem initially reported
38
 *  by "Steven J. Hill" <sjhill@realitydiluted.com>.
39
 *
40
 *  8-25-2002
41
 *  Changed fclose behavior when custom streams were enabled.  Previously,
42
 *     the cookie pointer was set to NULL as a debugging aid.  However,
43
 *     some of the perl 5.8 test rely on being able to close stderr and
44
 *     still try writing to it.  So now, the cookie pointer and handler
45
 *     function pointers are set to that it is a "normal" file with a
46
 *     file descriptor of -1.  Note: The cookie pointer is reset to NULL
47
 *     if the FILE struct is free'd by fclose.
48
 *
49
 *  Nov 21, 2002
50
 *  Added internal function _wstdio_fwrite.
51
 *  Jan 3, 2003
52
 *  Fixed a bug in _wstdio_fwrite.
53
 *
54
 *  Jan 22, 2003
55
 *  Fixed a bug related file position in append mode.  _stdio_fwrite now
56
 *     seeks to the end of the stream when append mode is set and we are
57
 *     transitioning to write mode, so that subsequent ftell() return
58
 *     values are correct.
59
 *  Also fix _stdio_fopen to support fdopen() with append specified when
60
 *     the underlying file didn't have O_APPEND set.  It now sets the
61
 *     O_APPEND flag as recommended by SUSv3 and is done by glibc.
62
 *
63
 *  May 15, 2003
64
 *  Modify __stdio_fread to deal with fake streams used by *sscanf.
65
 *  Set EOF to end of buffer when fmemopen used on a readonly stream.
66
 *    Note: I really need to run some tests on this to see what the
67
 *    glibc code does in each case.
68
 *
69
 * Sept 21, 2003
70
 * Modify _stdio_READ to conform with C99, as stdio input behavior upon
71
 *    encountering EOF changed with Defect Report #141.  In the current
72
 *    standard, the stream's EOF indicator is "sticky".  Once it is set,
73
 *    all further input from the stream should fail until the application
74
 *    explicitly clears the EOF indicator (clearerr(), file positioning),
75
 *    even if more data becomes available.
76
 * Fixed a bug in fgets.  Wasn't checking for read errors.
77
 * Minor thread locking optimizations to avoid some unnecessary locking.
78
 * Remove the explicit calls to __builtin_* funcs, as we really need to
79
 *    implement a more general solution.
80
 *
81
 * Nov 17, 2003
82
 * Fix the return value for fputs when passed an empty string.
83
 *
84
 * Jan 1, 2004
85
 * Fix __freadable and __fwritable... were using '~' instead of '!'. (ugh)
86
 * Fix (hopefully) a potential problem with failed freopen() calls.  The
87
 *   fix isn't tested since I've been working on the replacement stdio
88
 *   core code which will go in after the next release.
89
 */
90
 
91
/* Before we include anything, convert L_ctermid to L_ctermid_function
92
 * and undef L_ctermid if defined.  This is necessary as L_ctermid is
93
 * a SUSv3 standard macro defined in stdio.h. */
94
#ifdef L_ctermid
95
#define L_ctermid_function
96
#undef L_ctermid
97
#endif
98
 
99
#define _ISOC99_SOURCE                  /* for ULLONG primarily... */
100
#define _GNU_SOURCE
101
#define _STDIO_UTILITY                  /* for _stdio_fdout and _uintmaxtostr. */
102
#include <stdio.h>
103
#include <stddef.h>
104
#include <stdlib.h>
105
#include <string.h>
106
#include <limits.h>
107
#include <stdint.h>
108
#include <stdarg.h>
109
#include <errno.h>
110
#include <assert.h>
111
#include <stdio_ext.h>
112
#include <unistd.h>
113
#include <fcntl.h>
114
 
115
#ifndef O_LARGEFILE             /* uClibc undefines this if no large file support. */
116
#ifdef __STDIO_LARGE_FILES
117
#error missing define for O_LARGEFILE!
118
#endif
119
#define O_LARGEFILE             0
120
#endif
121
 
122
/**********************************************************************/
123
/* First deal with some build issues... */
124
 
125
#ifndef __STDIO_THREADSAFE
126
/* Just build empty object files if any of these were defined. */
127
/* Note though that we do keep the various *_unlocked names as aliases. */
128
#undef L___fsetlocking
129
#undef L___flockfile
130
#undef L___ftrylockfile
131
#undef L___funlockfile
132
#endif
133
 
134
#ifndef __STDIO_LARGE_FILES
135
/* Just build empty object files if any of these were defined. */
136
#undef L_fopen64
137
#undef L_freopen64
138
#undef L_ftello64
139
#undef L_fseeko64
140
#undef L_fsetpos64
141
#undef L_fgetpos64
142
#endif
143
 
144
/**********************************************************************/
145
 
146
#ifndef __STDIO_THREADSAFE
147
 
148
#if defined(__BCC__) && 0
149
#define UNLOCKED_STREAM(RETURNTYPE,NAME,PARAMS,ARGS,STREAM) \
150
asm(".text\nexport _" "NAME" "_unlocked\n_" "NAME" "_unlocked = _" "NAME"); \
151
RETURNTYPE NAME PARAMS
152
#else
153
#define UNLOCKED_STREAM(RETURNTYPE,NAME,PARAMS,ARGS,STREAM) \
154
strong_alias(NAME,NAME##_unlocked) \
155
RETURNTYPE NAME PARAMS
156
#endif
157
 
158
#define UNLOCKED(RETURNTYPE,NAME,PARAMS,ARGS) \
159
        UNLOCKED_STREAM(RETURNTYPE,NAME,PARAMS,ARGS,stream)
160
 
161
#if defined(__BCC__) && 0
162
#define UNLOCKED_VOID_RETURN(NAME,PARAMS,ARGS) \
163
asm(".text\nexport _" "NAME" "_unlocked\n_" "NAME" "_unlocked = _" "NAME"); \
164
void NAME PARAMS
165
#else
166
#define UNLOCKED_VOID_RETURN(NAME,PARAMS,ARGS) \
167
strong_alias(NAME,NAME##_unlocked) \
168
void NAME PARAMS
169
#endif
170
 
171
#define __STDIO_THREADLOCK_OPENLIST
172
#define __STDIO_THREADUNLOCK_OPENLIST
173
 
174
#else  /* __STDIO_THREADSAFE */
175
 
176
#include <pthread.h>
177
 
178
#define UNLOCKED_STREAM(RETURNTYPE,NAME,PARAMS,ARGS,STREAM) \
179
RETURNTYPE NAME PARAMS \
180
{ \
181
        RETURNTYPE retval; \
182
        __STDIO_THREADLOCK(STREAM); \
183
        retval = NAME##_unlocked ARGS ; \
184
        __STDIO_THREADUNLOCK(STREAM); \
185
        return retval; \
186
} \
187
RETURNTYPE NAME##_unlocked PARAMS
188
 
189
#define UNLOCKED(RETURNTYPE,NAME,PARAMS,ARGS) \
190
        UNLOCKED_STREAM(RETURNTYPE,NAME,PARAMS,ARGS,stream)
191
 
192
#define UNLOCKED_VOID_RETURN(NAME,PARAMS,ARGS) \
193
void NAME PARAMS \
194
{ \
195
        __STDIO_THREADLOCK(stream); \
196
        NAME##_unlocked ARGS ; \
197
        __STDIO_THREADUNLOCK(stream); \
198
} \
199
void NAME##_unlocked PARAMS
200
 
201
#define __STDIO_THREADLOCK_OPENLIST \
202
        __pthread_mutex_lock(&_stdio_openlist_lock)
203
 
204
#define __STDIO_THREADUNLOCK_OPENLIST \
205
        __pthread_mutex_unlock(&_stdio_openlist_lock)
206
 
207
#define __STDIO_THREADTRYLOCK_OPENLIST \
208
        __pthread_mutex_trylock(&_stdio_openlist_lock)
209
 
210
#endif /* __STDIO_THREADSAFE */
211
 
212
/**********************************************************************/
213
 
214
#ifdef __STDIO_WIDE
215
#define __STDIO_FILE_INIT_UNGOT         { 0, 0 }, { 0, 0 },
216
#else
217
#define __STDIO_FILE_INIT_UNGOT         { 0, 0 },
218
#endif
219
 
220
#ifdef __STDIO_GETC_MACRO
221
#define __STDIO_FILE_INIT_BUFGETC(x) x,
222
#else
223
#define __STDIO_FILE_INIT_BUFGETC(x)
224
#endif
225
 
226
#ifdef __STDIO_PUTC_MACRO
227
#define __STDIO_FILE_INIT_BUFPUTC(x) x,
228
#else
229
#define __STDIO_FILE_INIT_BUFPUTC(x)
230
#endif
231
 
232
#if defined(__STDIO_BUFFERS) || defined(__STDIO_GLIBC_CUSTOM_STREAMS)
233
#define __STDIO_FILE_INIT_NEXT(next)    (next),
234
#else  /* defined(__STDIO_BUFFERS) || defined(__STDIO_GLIBC_CUSTOM_STREAMS) */
235
#define __STDIO_FILE_INIT_NEXT(next)
236
#endif /* defined(__STDIO_BUFFERS) || defined(__STDIO_GLIBC_CUSTOM_STREAMS) */
237
 
238
#ifdef __STDIO_BUFFERS
239
#define __STDIO_FILE_INIT_BUFFERS(buf,bufsize) \
240
        (buf), (buf)+(bufsize), (buf), (buf),
241
#else
242
#define __STDIO_FILE_INIT_BUFFERS(buf,bufsize)
243
#endif
244
 
245
#ifdef __STDIO_GLIBC_CUSTOM_STREAMS
246
#define __STDIO_FILE_INIT_CUSTOM_STREAM(stream) \
247
        &((stream).filedes), { _cs_read, _cs_write, NULL, _cs_close },
248
#else
249
#define __STDIO_FILE_INIT_CUSTOM_STREAM(stream)
250
#endif
251
 
252
#ifdef __STDIO_MBSTATE
253
#define __STDIO_FILE_INIT_MBSTATE \
254
        { 0, 0 },
255
#else
256
#define __STDIO_FILE_INIT_MBSTATE
257
#endif
258
 
259
 
260
#ifdef __STDIO_THREADSAFE
261
#define __STDIO_FILE_INIT_THREADSAFE \
262
        0, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
263
#else
264
#define __STDIO_FILE_INIT_THREADSAFE
265
#endif
266
 
267
#define __STDIO_INIT_FILE_STRUCT(stream, flags, filedes, next, buf, bufsize) \
268
        { (flags), \
269
        __STDIO_FILE_INIT_UNGOT \
270
        (filedes), \
271
        __STDIO_FILE_INIT_NEXT(next) \
272
        __STDIO_FILE_INIT_BUFFERS(buf,bufsize) \
273
        __STDIO_FILE_INIT_BUFGETC((buf)) \
274
        __STDIO_FILE_INIT_BUFPUTC((buf)) \
275
        __STDIO_FILE_INIT_CUSTOM_STREAM(stream) \
276
        __STDIO_FILE_INIT_MBSTATE \
277
        __STDIO_FILE_INIT_THREADSAFE \
278
} /* TODO: mbstate and builtin buf */
279
 
280
#ifdef __STDIO_GLIBC_CUSTOM_STREAMS
281
 
282
/* TODO -- what does glibc do for undefined funcs?  errno set? */
283
#define __READ(STREAMPTR,BUF,SIZE) \
284
        ((((STREAMPTR)->gcs.read) == NULL) ? -1 : \
285
        (((STREAMPTR)->gcs.read)((STREAMPTR)->cookie,(BUF),(SIZE))))
286
#define __WRITE(STREAMPTR,BUF,SIZE) \
287
        ((((STREAMPTR)->gcs.write) == NULL) ? -1 : \
288
        (((STREAMPTR)->gcs.write)((STREAMPTR)->cookie,(BUF),(SIZE))))
289
#define __CLOSE(STREAMPTR) \
290
        ((((STREAMPTR)->gcs.close) == NULL) ? 0 : \
291
        (((STREAMPTR)->gcs.close)((STREAMPTR)->cookie)))
292
 
293
#else  /* __STDIO_GLIBC_CUSTOM_STREAMS */
294
 
295
#define __READ(STREAMPTR,BUF,SIZE) \
296
        (read((STREAMPTR)->filedes,(BUF),(SIZE)))
297
#define __WRITE(STREAMPTR,BUF,SIZE) \
298
        (write((STREAMPTR)->filedes,(BUF),(SIZE)))
299
#define __CLOSE(STREAMPTR) \
300
        (close((STREAMPTR)->filedes))
301
 
302
#endif /* __STDIO_GLIBC_CUSTOM_STREAMS */
303
 
304
/**********************************************************************/
305
/* POSIX functions */
306
/**********************************************************************/
307
#ifdef L_getw
308
 
309
/* SUSv2 Legacy function -- need not be reentrant. */
310
 
311
int getw(FILE *stream)
312
{
313
        int aw[1];
314
 
315
#ifdef __STDIO_WIDE
316
 
317
        return (fread_unlocked((void *)aw, sizeof(int), 1, stream) > 0)
318
                ? (*aw) : EOF;
319
 
320
#else  /* __STDIO_WIDE */
321
 
322
        return (_stdio_fread((unsigned char *)(aw), sizeof(int), stream)
323
                        == sizeof(int)) ? (*aw) : EOF;
324
 
325
#endif /* __STDIO_WIDE */
326
}
327
 
328
#endif
329
/**********************************************************************/
330
#ifdef L_putw
331
 
332
/* SUSv2 Legacy function -- need not be reentrant. */
333
 
334
int putw(int w, FILE *stream)
335
{
336
        int aw[1];
337
 
338
        *aw = w;                                        /* In case 'w' is in a register... */
339
 
340
#ifdef __STDIO_WIDE
341
 
342
        return (fwrite_unlocked((void *)aw, sizeof(int), 1, stream) == 1)
343
                ? 0 : EOF;
344
 
345
#else  /* __STDIO_WIDE */
346
 
347
        return (_stdio_fwrite((unsigned char *)aw, sizeof(int), stream)
348
                        == sizeof(int)) ? 0 : EOF;
349
 
350
#endif /* __STDIO_WIDE */
351
}
352
 
353
#endif
354
/**********************************************************************/
355
#ifdef L_fileno
356
 
357
/* Reentrancy handled by UNLOCKED() macro. */
358
 
359
UNLOCKED(int,fileno,(register FILE *stream),(stream))
360
{
361
#ifdef __STDIO_GLIBC_CUSTOM_STREAMS
362
        return ( (stream && (stream->cookie == &(stream->filedes)) && (stream->filedes >= 0))
363
                         ? stream->filedes
364
                         : (__set_errno(EBADF), -1) );
365
#else  /* __STDIO_GLIBC_CUSTOM_STREAMS */
366
        return ((stream && stream->filedes >= 0)) ? stream->filedes : (__set_errno(EBADF), -1);
367
#endif /* __STDIO_GLIBC_CUSTOM_STREAMS */
368
}
369
 
370
#endif
371
/**********************************************************************/
372
#ifdef L_fdopen
373
 
374
/* No reentrancy issues. */
375
 
376
FILE *fdopen(int filedes, const char *mode)
377
{
378
        register char *cur_mode;        /* TODO -- use intptr_t?? (also fopencookie) */
379
 
380
        return (((int)(cur_mode = (char *) fcntl(filedes, F_GETFL))) != -1)
381
                ? _stdio_fopen(cur_mode, mode, NULL, filedes)
382
                : NULL;
383
}
384
 
385
#endif
386
/**********************************************************************/
387
#ifdef L_fopen64
388
 
389
/* No reentrancy issues. */
390
 
391
FILE *fopen64(const char * __restrict filename, const char * __restrict mode)
392
{
393
        return _stdio_fopen(filename, mode, NULL, -2);
394
}
395
 
396
#endif
397
/**********************************************************************/
398
#ifdef L_ctermid_function
399
 
400
/* Not required to be reentrant. */
401
 
402
char *ctermid(register char *s)
403
{
404
        static char sbuf[L_ctermid];
405
 
406
#ifdef __BCC__
407
        /* Currently elks doesn't support /dev/tty. */
408
        if (!s) {
409
                s = sbuf;
410
        }
411
        *s = 0;
412
 
413
        return s;
414
#else
415
        /* glibc always returns /dev/tty for linux. */
416
        return strcpy((s ? s : sbuf), "/dev/tty");
417
#endif
418
}
419
 
420
#endif
421
/**********************************************************************/
422
/* BSD functions */
423
/**********************************************************************/
424
#ifdef L_setbuffer
425
 
426
/* No reentrancy issues. */
427
 
428
void setbuffer(FILE * __restrict stream, register char * __restrict buf,
429
                           size_t size)
430
{
431
#ifdef __STDIO_BUFFERS
432
        setvbuf(stream, buf, (buf ? _IOFBF : _IONBF), size);
433
#else  /* __STDIO_BUFFERS */
434
        /* Nothing to do. */
435
#endif /* __STDIO_BUFFERS */
436
}
437
 
438
#endif
439
/**********************************************************************/
440
#ifdef L_setlinebuf
441
 
442
/* No reentrancy issues. */
443
 
444
void setlinebuf(FILE * __restrict stream)
445
{
446
#ifdef __STDIO_BUFFERS
447
        setvbuf(stream, NULL, _IOLBF, (size_t) 0);
448
#else  /* __STDIO_BUFFERS */
449
        /* Nothing to do. */
450
#endif /* __STDIO_BUFFERS */
451
}
452
 
453
#endif
454
/**********************************************************************/
455
/* GLIBC functions */
456
/**********************************************************************/
457
#ifdef L_fcloseall
458
 
459
/* NOTE: GLIBC difference!!! -- fcloseall
460
 * According to the info pages, glibc actually fclose()s all open files.
461
 * Apparently, glibc's new version only fflush()s and unbuffers all
462
 * writing streams to cope with unordered destruction of c++ static
463
 * objects.  Here we implement the old behavior as default.
464
 */
465
 
466
/* Not reentrant. */
467
 
468
int fcloseall (void)
469
{
470
#if defined(__STDIO_BUFFERS) || defined(__STDIO_GLIBC_CUSTOM_STREAMS)
471
        register FILE *stream;
472
        int rv;
473
 
474
        _stdio_term();                          /* Let _stdio_term() do all the work. */
475
 
476
        rv = 0;
477
        for (stream = _stdio_openlist ; stream ; stream = stream->nextopen) {
478
                if (stream->modeflags & (__FLAG_WRITING|__FLAG_ERROR)) {
479
                        /* TODO -- is this correct?  Maybe ferror set before flush...
480
                        * could check if pending writable but what if term unbuffers?
481
                        * in that case, could clear error flag... */
482
                        rv = EOF;                       /* Only care about failed writes. */
483
                }
484
        }
485
 
486
        /* Make sure _stdio_term() does nothing on exit. */
487
        _stdio_openlist = NULL;
488
 
489
        return rv;
490
#else  /* defined(__STDIO_BUFFERS) || defined(__STDIO_GLIBC_CUSTOM_STREAMS) */
491
 
492
        return 0;
493
 
494
#endif /* defined(__STDIO_BUFFERS) || defined(__STDIO_GLIBC_CUSTOM_STREAMS) */
495
}
496
 
497
#endif
498
/**********************************************************************/
499
#ifdef L_fmemopen
500
#ifdef __STDIO_GLIBC_CUSTOM_STREAMS
501
 
502
typedef struct {
503
        size_t pos;
504
        size_t len;
505
        size_t eof;
506
        int dynbuf;
507
        unsigned char *buf;
508
        FILE *fp;
509
} __fmo_cookie;
510
 
511
#define COOKIE ((__fmo_cookie *) cookie)
512
 
513
static ssize_t fmo_read(register void *cookie, char *buf, size_t bufsize)
514
{
515
        size_t count = COOKIE->len - COOKIE->pos;
516
 
517
        /* Note: 0 < bufsize < SSIZE_MAX because of _stdio_READ. */
518
        if (!count) {                           /* EOF! */
519
                return 0;
520
        }
521
 
522
        if (bufsize > count) {
523
                bufsize = count;
524
        }
525
 
526
#if 1                                                   /* TODO - choose code option */
527
        memcpy(buf, COOKIE->buf + COOKIE->pos, bufsize);
528
        COOKIE->pos += bufsize;
529
#else
530
        {
531
                register char *p = COOKIE->buf + COOKIE->pos;
532
 
533
                count = bufsize;
534
                while (count) {
535
                        *buf++ = *p++;
536
                        --count;
537
                }
538
                COOKIE->pos += bufsize;
539
        }
540
#endif
541
 
542
        return bufsize;
543
}
544
 
545
static ssize_t fmo_write(register void *cookie, const char *buf, size_t bufsize)
546
{
547
        size_t count;
548
 
549
        /* Note: bufsize < SSIZE_MAX because of _stdio_WRITE. */
550
 
551
        /* If appending, need to seek to end of file!!!! */
552
        if (COOKIE->fp->modeflags & __FLAG_APPEND) {
553
                COOKIE->pos = COOKIE->eof;
554
        }
555
 
556
        count = COOKIE->len - COOKIE->pos;
557
 
558
        if (bufsize > count) {
559
                bufsize = count;
560
                if (count == 0) {                /* We're at the end of the buffer... */
561
                        __set_errno(EFBIG);
562
                        return -1;
563
                }
564
        }
565
 
566
#if 1                                                   /* TODO - choose code option */
567
        memcpy(COOKIE->buf + COOKIE->pos, buf, bufsize);
568
        COOKIE->pos += bufsize;
569
 
570
        if (COOKIE->pos > COOKIE->eof) {
571
                COOKIE->eof = COOKIE->pos;
572
                if (bufsize < count) {  /* New eof and still room in buffer? */
573
                        *(COOKIE->buf + COOKIE->pos) = 0;
574
                }
575
        }
576
 
577
#else
578
        {
579
                register char *p = COOKIE->buf + COOKIE->pos;
580
                size_t i = bufsize;
581
 
582
                while (i > 0) {
583
                        *p++ = *buf++;
584
                        --i;
585
                }
586
                COOKIE->pos += bufsize;
587
 
588
                if (COOKIE->pos > COOKIE->eof) {
589
                        COOKIE->eof = COOKIE->pos;
590
                        if (bufsize < count) {  /* New eof and still room in buffer? */
591
                                *p = 0;
592
                        }
593
                }
594
        }
595
 
596
#endif
597
 
598
        return bufsize;
599
}
600
 
601
/* glibc doesn't allow seeking, but it has in-buffer seeks... we don't. */
602
static int fmo_seek(register void *cookie, __offmax_t *pos, int whence)
603
{
604
        __offmax_t p = *pos;
605
 
606
        /* Note: fseek already checks that whence is legal, so don't check here
607
         * unless debugging. */
608
        assert(((unsigned int) whence) <= 2);
609
 
610
        if (whence != SEEK_SET) {
611
                p += (whence == SEEK_CUR) ? COOKIE->pos : /* SEEK_END */ COOKIE->eof;
612
        }
613
 
614
        /* Note: glibc only allows seeking in the buffer.  We'll actually restrict
615
         * to the data. */
616
        /* Check for offset < 0, offset > eof, or offset overflow... */
617
        if (((uintmax_t) p) > COOKIE->eof) {
618
                return -1;
619
        }
620
 
621
        COOKIE->pos = *pos = p;
622
        return 0;
623
}
624
 
625
static int fmo_close(register void *cookie)
626
{
627
        if (COOKIE->dynbuf) {
628
                free(COOKIE->buf);
629
        }
630
        free(cookie);
631
        return 0;
632
}
633
 
634
#undef COOKIE
635
 
636
static const cookie_io_functions_t _fmo_io_funcs = {
637
        fmo_read, fmo_write, fmo_seek, fmo_close
638
};
639
 
640
/* TODO: If we have buffers enabled, it might be worthwile to add a pointer
641
 * to the FILE in the cookie and have read, write, and seek operate directly
642
 * on the buffer itself (ie replace the FILE buffer with the cookie buffer
643
 * and update FILE bufstart, etc. whenever we seek). */
644
 
645
FILE *fmemopen(void *s, size_t len, const char *modes)
646
{
647
        FILE *fp;
648
        register __fmo_cookie *cookie;
649
        size_t i;
650
 
651
        if ((cookie = malloc(sizeof(__fmo_cookie))) != NULL) {
652
                cookie->len = len;
653
                cookie->eof = cookie->pos = 0; /* pos and eof adjusted below. */
654
                cookie->dynbuf = 0;
655
                if (((cookie->buf = s) == NULL) && (len > 0)) {
656
                        if ((cookie->buf = malloc(len)) == NULL) {
657
                                goto EXIT_cookie;
658
                        }
659
                        cookie->dynbuf = 1;
660
                        *cookie->buf = 0;        /* If we're appending, treat as empty file. */
661
                }
662
 
663
#ifndef __BCC__
664
                fp = fopencookie(cookie, modes, _fmo_io_funcs);
665
#else
666
                fp = fopencookie(cookie, modes, &_fmo_io_funcs);
667
#endif
668
                /* Note: We don't need to worry about locking fp in the thread case
669
                 * as the only possible access would be a close or flush with
670
                 * nothing currently in the FILE's write buffer. */
671
 
672
                if (fp != NULL) {
673
                        cookie->fp = fp;
674
                        if (fp->modeflags & __FLAG_READONLY) {
675
                                cookie->eof = len;
676
                        }
677
                        if ((fp->modeflags & __FLAG_APPEND) && (len > 0)) {
678
                                for (i = 0 ; i < len ; i++) {
679
                                        if (cookie->buf[i] == 0) {
680
                                                break;
681
                                        }
682
                                }
683
                                cookie->eof = cookie->pos = i; /* Adjust eof and pos. */
684
                        }
685
                        return fp;
686
                }
687
        }
688
 
689
        if (!s) {
690
                free(cookie->buf);
691
        }
692
 EXIT_cookie:
693
        free(cookie);
694
 
695
        return NULL;
696
}
697
 
698
#endif /* __STDIO_GLIBC_CUSTOM_STREAMS */
699
#endif
700
/**********************************************************************/
701
#ifdef L_open_memstream
702
#ifdef __STDIO_GLIBC_CUSTOM_STREAMS
703
 
704
#define COOKIE ((__oms_cookie *) cookie)
705
 
706
typedef struct {
707
        char *buf;
708
        size_t len;
709
        size_t pos;
710
        size_t eof;
711
        char **bufloc;
712
        size_t *sizeloc;
713
} __oms_cookie;
714
 
715
/* Nothing to do here, as memstreams are write-only. */
716
/*  static ssize_t oms_read(void *cookie, char *buf, size_t bufsize) */
717
/*  { */
718
/*  } */
719
 
720
static ssize_t oms_write(register void *cookie, const char *buf, size_t bufsize)
721
{
722
        register char *newbuf;
723
        size_t count;
724
 
725
        /* Note: we already know bufsize < SSIZE_MAX... */
726
 
727
        count = COOKIE->len - COOKIE->pos - 1;
728
        assert(COOKIE->pos < COOKIE->len); /* Always nul-terminate! */
729
 
730
        if (bufsize > count) {
731
                newbuf = realloc(COOKIE->buf, COOKIE->len + bufsize - count);
732
                if (newbuf) {
733
                        *COOKIE->bufloc = COOKIE->buf = newbuf;
734
                        COOKIE->len += (bufsize - count);
735
                } else {
736
                        bufsize = count;
737
                        if (count == 0) {
738
                                __set_errno(EFBIG);     /* TODO: check glibc errno setting... */
739
                                return -1;
740
                        }
741
                }
742
        }
743
 
744
        memcpy(COOKIE->buf + COOKIE->pos, buf, bufsize);
745
        COOKIE->pos += bufsize;
746
 
747
        if (COOKIE->pos > COOKIE->eof) {
748
                *COOKIE->sizeloc = COOKIE->eof = COOKIE->pos;
749
                COOKIE->buf[COOKIE->eof] = 0; /* Need to nul-terminate. */
750
        }
751
 
752
        return bufsize;
753
}
754
 
755
static int oms_seek(register void *cookie, __offmax_t *pos, int whence)
756
{
757
        __offmax_t p = *pos;
758
        register char *buf;
759
        size_t leastlen;
760
 
761
        /* Note: fseek already checks that whence is legal, so don't check here
762
         * unless debugging. */
763
        assert(((unsigned int) whence) <= 2);
764
 
765
        if (whence != SEEK_SET) {
766
                p += (whence == SEEK_CUR) ? COOKIE->pos : /* SEEK_END */ COOKIE->eof;
767
        }
768
 
769
        /* Note: glibc only allows seeking in the buffer.  We'll actually restrict
770
         * to the data. */
771
        /* Check for offset < 0, offset >= too big (need nul), or overflow... */
772
        if (((uintmax_t) p) >= SIZE_MAX - 1) {
773
                return -1;
774
        }
775
 
776
        leastlen = ((size_t) p) + 1; /* New pos + 1 for nul if necessary. */
777
 
778
        if (leastlen >= COOKIE->len) { /* Need to grow buffer... */
779
                buf = realloc(COOKIE->buf, leastlen);
780
                if (buf) {
781
                        *COOKIE->bufloc = COOKIE->buf = buf;
782
                        COOKIE->len = leastlen;
783
                        memset(buf + COOKIE->eof, leastlen - COOKIE->eof, 0); /* 0-fill */
784
                } else {
785
                        /* TODO: check glibc errno setting... */
786
                        return -1;
787
                }
788
        }
789
 
790
        *pos = COOKIE->pos = --leastlen;
791
 
792
        if (leastlen > COOKIE->eof) {
793
                memset(COOKIE->buf + COOKIE->eof, leastlen - COOKIE->eof, 0);
794
                *COOKIE->sizeloc = COOKIE->eof;
795
        }
796
 
797
        return 0;
798
}
799
 
800
static int oms_close(void *cookie)
801
{
802
        free(cookie);
803
        return 0;
804
}
805
 
806
#undef COOKIE
807
 
808
static const cookie_io_functions_t _oms_io_funcs = {
809
        NULL, oms_write, oms_seek, oms_close
810
};
811
 
812
/* TODO: If we have buffers enabled, it might be worthwile to add a pointer
813
 * to the FILE in the cookie and operate directly on the buffer itself
814
 * (ie replace the FILE buffer with the cookie buffer and update FILE bufstart,
815
 * etc. whenever we seek). */
816
 
817
FILE *open_memstream(char **__restrict bufloc, size_t *__restrict sizeloc)
818
{
819
        register __oms_cookie *cookie;
820
        register FILE *fp;
821
 
822
        if ((cookie = malloc(sizeof(__oms_cookie))) != NULL) {
823
                if ((cookie->buf = malloc(cookie->len = BUFSIZ)) == NULL) {
824
                        goto EXIT_cookie;
825
                }
826
                *cookie->buf = 0;                /* Set nul terminator for buffer. */
827
                *(cookie->bufloc = bufloc) = cookie->buf;
828
                *(cookie->sizeloc = sizeloc) = cookie->eof = cookie->pos = 0;
829
 
830
#ifndef __BCC__
831
                fp = fopencookie(cookie, "w", _oms_io_funcs);
832
#else
833
                fp = fopencookie(cookie, "w", &_oms_io_funcs);
834
#endif
835
                /* Note: We don't need to worry about locking fp in the thread case
836
                 * as the only possible access would be a close or flush with
837
                 * nothing currently in the FILE's write buffer. */
838
 
839
                if (fp != NULL) {
840
                        return fp;
841
                }
842
        }
843
 
844
        if (cookie->buf != NULL) {
845
                free(cookie->buf);
846
        }
847
 EXIT_cookie:
848
        free(cookie);
849
 
850
        return NULL;
851
}
852
 
853
#endif /* __STDIO_GLIBC_CUSTOM_STREAMS */
854
#endif
855
/**********************************************************************/
856
#ifdef L_fopencookie
857
#ifdef __STDIO_GLIBC_CUSTOM_STREAMS
858
 
859
/* NOTE: GLIBC difference!!! -- fopencookie
860
 * According to the info pages, glibc allows seeking within buffers even if
861
 * no seek function is supplied.  We don't. */
862
 
863
/* NOTE: GLIBC difference!!! -- fopencookie
864
 * When compiled without large file support, the offset pointer for the
865
 * cookie_seek function is off_t * and not off64_t * as for glibc. */
866
 
867
/* Currently no real reentrancy issues other than a possible double close(). */
868
 
869
#ifndef __BCC__
870
 
871
FILE *fopencookie(void * __restrict cookie, const char * __restrict mode,
872
                                  cookie_io_functions_t io_functions)
873
{
874
        FILE *stream;
875
 
876
        /* Fake an fdopen guaranteed to pass the _stdio_fopen basic agreement
877
         * check without an fcntl call. */
878
        if ((stream = _stdio_fopen(((char *)(INT_MAX-1)),
879
                                                           mode, NULL, INT_MAX)) /* TODO: use intptr_t? */
880
                != NULL
881
                ) {
882
                stream->filedes = -1;
883
                stream->gcs = io_functions;
884
                stream->cookie = cookie;
885
        }
886
 
887
#if !defined(__STDIO_BUFFERS) && !defined(__STDIO_THREADSAFE)
888
        /* I we don't have buffers or threads, we only need to worry about
889
         * custom streams on the open list, as no flushing is necessary and
890
         * no locking of possible underlying normal streams need be done.
891
         * We do need to explicitly close custom streams on termination of stdio,
892
         * and we need to lock the list as it can be modified by fclose(). */
893
        __STDIO_THREADLOCK_OPENLIST;
894
        stream->nextopen = _stdio_openlist;     /* New files are inserted at */
895
        _stdio_openlist = stream;                       /*   the head of the list. */
896
        __STDIO_THREADUNLOCK_OPENLIST;
897
#endif /* !defined(__STDIO_BUFFERS) && !defined(__STDIO_THREADSAFE) */
898
 
899
        return stream;
900
}
901
 
902
#else  /* __BCC__ */
903
 
904
/* NOTE: GLIBC difference!!! -- fopencookie (bcc only)
905
 * Since bcc doesn't support passing of structs, we define fopencookie as a
906
 * macro in terms of _fopencookie which takes a struct * for the io functions
907
 * instead.
908
 */
909
 
910
FILE *_fopencookie(void * __restrict cookie, const char * __restrict mode,
911
                                   register cookie_io_functions_t *io_functions)
912
{
913
        register FILE *stream;
914
 
915
        /* Fake an fdopen guaranteed to pass the _stdio_fopen basic agreement
916
         * check without an fcntl call. */
917
        if ((stream = _stdio_fopen(((char *)(INT_MAX-1)),
918
                                                           mode, NULL, INT_MAX)) /* TODO: use intptr_t? */
919
                != NULL
920
                ) {
921
                stream->filedes = -1;
922
                stream->gcs.read  = io_functions->read;
923
                stream->gcs.write = io_functions->write;
924
                stream->gcs.seek  = io_functions->seek;
925
                stream->gcs.close = io_functions->close;
926
                stream->cookie = cookie;
927
        }
928
 
929
#if !defined(__STDIO_BUFFERS) && !defined(__STDIO_THREADSAFE)
930
        /* I we don't have buffers or threads, we only need to worry about
931
         * custom streams on the open list, as no flushing is necessary and
932
         * no locking of possible underlying normal streams need be done.
933
         * We do need to explicitly close custom streams on termination of stdio,
934
         * and we need to lock the list as it can be modified by fclose(). */
935
        __STDIO_THREADLOCK_OPENLIST;
936
        stream->nextopen = _stdio_openlist;     /* New files are inserted at */
937
        _stdio_openlist = stream;                       /*   the head of the list. */
938
        __STDIO_THREADUNLOCK_OPENLIST;
939
#endif /* !defined(__STDIO_BUFFERS) && !defined(__STDIO_THREADSAFE) */
940
 
941
        return stream;
942
}
943
 
944
#endif  /* __BCC__ */
945
 
946
#endif /* __STDIO_GLIBC_CUSTOM_STREAMS */
947
#endif
948
/**********************************************************************/
949
#ifdef L___fbufsize
950
 
951
/* Not reentrant. */
952
 
953
size_t __fbufsize(register FILE * __restrict stream)
954
{
955
#ifdef __STDIO_BUFFERS
956
        return (stream->modeflags & __FLAG_NBF)
957
                ? 0 : (stream->bufend - stream->bufstart);
958
#else  /* __STDIO_BUFFERS */
959
        return 0;
960
#endif /* __STDIO_BUFFERS */
961
}
962
 
963
#endif
964
/**********************************************************************/
965
#ifdef L___freading
966
 
967
/* No reentrancy issues. */
968
 
969
int __freading(FILE * __restrict stream)
970
{
971
        return stream->modeflags & (__FLAG_READING|__FLAG_READONLY);
972
}
973
 
974
#endif
975
/**********************************************************************/
976
#ifdef L___fwriting
977
 
978
/* No reentrancy issues. */
979
 
980
int __fwriting(FILE * __restrict stream)
981
{
982
        return stream->modeflags & (__FLAG_WRITING|__FLAG_WRITEONLY);
983
}
984
 
985
#endif
986
/**********************************************************************/
987
#ifdef L___freadable
988
 
989
/* No reentrancy issues. */
990
 
991
int __freadable(FILE * __restrict stream)
992
{
993
        return !(stream->modeflags & __FLAG_WRITEONLY);
994
}
995
 
996
#endif
997
/**********************************************************************/
998
#ifdef L___fwritable
999
 
1000
/* No reentrancy issues. */
1001
 
1002
int __fwritable(FILE * __restrict stream)
1003
{
1004
        return !(stream->modeflags & __FLAG_READONLY);
1005
}
1006
 
1007
#endif
1008
/**********************************************************************/
1009
#ifdef L___flbf
1010
 
1011
/* No reentrancy issues. */
1012
 
1013
int __flbf(FILE * __restrict stream)
1014
{
1015
#ifdef __STDIO_BUFFERS
1016
        return (stream->modeflags & __FLAG_LBF);
1017
#else  /* __STDIO_BUFFERS */
1018
        /* TODO -- Even though there is no buffer, return flag setting? */
1019
        return __FLAG_NBF;
1020
#endif /* __STDIO_BUFFERS */
1021
}
1022
 
1023
#endif
1024
/**********************************************************************/
1025
#ifdef L___fpurge
1026
 
1027
/* Not reentrant. */
1028
 
1029
void __fpurge(register FILE * __restrict stream)
1030
{
1031
#ifdef __STDIO_BUFFERS
1032
#ifdef __STDIO_PUTC_MACRO
1033
        stream->bufputc =                       /* Must disable putc. */
1034
#endif /* __STDIO_PUTC_MACRO */
1035
#ifdef __STDIO_GETC_MACRO
1036
        stream->bufgetc =                       /* Must disable getc. */
1037
#endif
1038
        stream->bufpos = stream->bufread = stream->bufstart; /* Reset pointers. */
1039
#endif /* __STDIO_BUFFERS */
1040
        /* Reset r/w flags and clear ungots. */
1041
        stream->modeflags &= ~(__FLAG_READING|__FLAG_WRITING|__MASK_UNGOT);
1042
}
1043
 
1044
#endif
1045
/**********************************************************************/
1046
#ifdef L___fpending
1047
 
1048
/* Not reentrant. */
1049
 
1050
#ifdef __STDIO_WIDE
1051
#warning Unlike the glibc version, this __fpending returns bytes in buffer for wide streams too!
1052
 
1053
link_warning(__fpending, "This version of __fpending returns bytes remaining in buffer for both narrow and wide streams.  glibc's version returns wide chars in buffer for the wide stream case.")
1054
 
1055
#endif  /* __STDIO_WIDE */
1056
 
1057
size_t __fpending(register FILE * __restrict stream)
1058
{
1059
#ifdef __STDIO_BUFFERS
1060
        /* TODO -- should we check this?  should we set errno?  just assert? */
1061
        return (stream->modeflags & (__FLAG_READING|__FLAG_READONLY))
1062
                ? 0 : (stream->bufpos - stream->bufstart);
1063
#else  /* __STDIO_BUFFERS */
1064
        return 0;
1065
#endif /* __STDIO_BUFFERS */
1066
}
1067
 
1068
#endif
1069
/**********************************************************************/
1070
#ifdef L__flushlbf
1071
 
1072
/* No reentrancy issues. */
1073
 
1074
void _flushlbf(void)
1075
{
1076
#if defined(__STDIO_BUFFERS) || defined(__STDIO_GLIBC_CUSTOM_STREAMS)
1077
        fflush((FILE *) &_stdio_openlist); /* Uses an implementation hack!!! */
1078
#else  /* defined(__STDIO_BUFFERS) || defined(__STDIO_GLIBC_CUSTOM_STREAMS) */
1079
        /* Nothing to do. */
1080
#endif /* defined(__STDIO_BUFFERS) || defined(__STDIO_GLIBC_CUSTOM_STREAMS) */
1081
}
1082
 
1083
#endif
1084
/**********************************************************************/
1085
#ifdef L___fsetlocking
1086
 
1087
/* NOT threadsafe!!!  (I don't think glibc's is either)
1088
 *
1089
 * This interacts badly with internal locking/unlocking.  If you use this routine,
1090
 * make sure the file isn't being accessed by any other threads.  Typical use would
1091
 * be to change to user locking immediately after opening the stream.
1092
 */
1093
 
1094
#ifdef __UCLIBC_MJN3_ONLY__
1095
link_warning(__fsetlocking, "Oddly enough, __fsetlocking() is NOT threadsafe.")
1096
#endif
1097
 
1098
int __fsetlocking(FILE *stream, int locking_mode)
1099
{
1100
#ifdef __STDIO_THREADSAFE
1101
        int old_mode;
1102
#endif
1103
 
1104
        assert((FSETLOCKING_QUERY == 0) && (FSETLOCKING_INTERNAL == 1)
1105
                   && (FSETLOCKING_BYCALLER == 2));
1106
 
1107
        assert(((unsigned int) locking_mode) <= 2);
1108
 
1109
#ifdef __STDIO_THREADSAFE
1110
        old_mode = stream->user_locking;
1111
 
1112
        assert(((unsigned int) old_mode) <= 1); /* Must be 0 (internal) or 1 (user). */
1113
 
1114
        if (locking_mode != FSETLOCKING_QUERY) {
1115
                /* In case we're not debugging, treat any unknown as a request to
1116
                 * set internal locking, in order to match glibc behavior. */
1117
                stream->user_locking = (locking_mode == FSETLOCKING_BYCALLER);
1118
        }
1119
 
1120
        return 2 - old_mode;
1121
#else
1122
        return FSETLOCKING_BYCALLER; /* Well, without thread support... */
1123
#endif
1124
}
1125
 
1126
#endif
1127
/**********************************************************************/
1128
#ifdef L_flockfile
1129
 
1130
void flockfile(FILE *stream)
1131
{
1132
#ifdef __STDIO_THREADSAFE
1133
        __pthread_mutex_lock(&stream->lock);
1134
#endif
1135
}
1136
 
1137
#endif
1138
/**********************************************************************/
1139
#ifdef L_ftrylockfile
1140
 
1141
int ftrylockfile(FILE *stream)
1142
{
1143
#ifdef __STDIO_THREADSAFE
1144
        return __pthread_mutex_trylock(&stream->lock);
1145
#else
1146
        return 1;
1147
#endif
1148
}
1149
 
1150
#endif
1151
/**********************************************************************/
1152
#ifdef L_funlockfile
1153
 
1154
void funlockfile(FILE *stream)
1155
{
1156
#ifdef __STDIO_THREADSAFE
1157
        __pthread_mutex_unlock(&stream->lock);
1158
#endif
1159
}
1160
 
1161
#endif
1162
/**********************************************************************/
1163
#ifdef L_getline
1164
 
1165
ssize_t getline(char **__restrict lineptr, size_t *__restrict n,
1166
                                FILE *__restrict stream)
1167
{
1168
        return __getdelim(lineptr, n, '\n', stream);
1169
}
1170
 
1171
#endif
1172
/**********************************************************************/
1173
#ifdef L_getdelim
1174
 
1175
weak_alias(__getdelim,getdelim);
1176
 
1177
#define GETDELIM_GROWBY         64
1178
 
1179
ssize_t __getdelim(char **__restrict lineptr, size_t *__restrict n,
1180
                                   int delimiter, register FILE *__restrict stream)
1181
{
1182
        register char *buf;
1183
        size_t pos;
1184
        int c;
1185
 
1186
        if (!lineptr || !n || !stream) { /* Be compatable with glibc... even */
1187
                __set_errno(EINVAL);    /* though I think we should assert here */
1188
                return -1;                              /* if anything. */
1189
        }
1190
 
1191
        if (!(buf = *lineptr)) {        /* If passed NULL for buffer, */
1192
                *n = 0;                                  /* ignore value passed and treat size as 0. */
1193
        }
1194
        pos = 1;                        /* Make sure we have space for terminating nul. */
1195
 
1196
        __STDIO_THREADLOCK(stream);
1197
 
1198
        do {
1199
                if (pos >= *n) {
1200
                        if (!(buf = realloc(buf, *n + GETDELIM_GROWBY))) {
1201
                                __set_errno(ENOMEM); /* Emulate old uClibc implementation. */
1202
                                break;
1203
                        }
1204
                        *n += GETDELIM_GROWBY;
1205
                        *lineptr = buf;
1206
                }
1207
        } while (((c = (getc_unlocked)(stream)) != EOF) /* Disable the macro */
1208
                         && ((buf[pos++ - 1] = c) != delimiter));
1209
 
1210
        __STDIO_THREADUNLOCK(stream);
1211
 
1212
        if (--pos) {
1213
                buf[pos] = 0;
1214
                return pos;
1215
        }
1216
 
1217
        return -1;              /* Either initial realloc failed or first read was EOF. */
1218
}
1219
 
1220
#endif
1221
/**********************************************************************/
1222
/* my extension functions */
1223
/**********************************************************************/
1224
#ifdef L__stdio_fsfopen
1225
/*
1226
 * Stack|Static File open -- open a file where the FILE is either
1227
 * stack or staticly allocated.
1228
 */
1229
 
1230
/* No reentrancy issues. */
1231
 
1232
FILE *_stdio_fsfopen(const char * __restrict filename,
1233
                                         const char * __restrict mode,
1234
                                         register FILE * __restrict stream)
1235
{
1236
#ifdef __STDIO_BUFFERS
1237
        stream->modeflags = __FLAG_FBF;
1238
#if __STDIO_BUILTIN_BUF_SIZE > 0
1239
        stream->bufstart = stream->builtinbuf;
1240
        stream->bufend = stream->builtinbuf + sizeof(stream->builtinbuf);
1241
#else  /* __STDIO_BUILTIN_BUF_SIZE > 0 */
1242
        stream->bufend = stream->bufstart = NULL;
1243
#endif /* __STDIO_BUILTIN_BUF_SIZE > 0 */
1244
#endif /* __STDIO_BUFFERS */
1245
 
1246
        return _stdio_fopen(filename, mode, stream, -1);
1247
}
1248
#endif
1249
/**********************************************************************/
1250
/* stdio internal functions */
1251
/**********************************************************************/
1252
#ifdef L__stdio_adjpos
1253
 
1254
/* According to the ANSI/ISO C99 definition of ungetwc()
1255
 *     For a text or binary stream, the value of its file position indicator
1256
 *     after a successful call to the ungetwc function is unspecified until
1257
 *     all pushed­back wide characters are read or discarded.
1258
 * Note however, that this applies only to _user_ calls to ungetwc.  We
1259
 * need to allow for internal calls by scanf.
1260
 
1261
 
1262
 *  So we store the byte count
1263
 * of the first ungot wide char in ungot_width.  If it is 0 (user case)
1264
 * then the file position is treated as unknown.
1265
 */
1266
 
1267
/* Internal function -- not reentrant. */
1268
 
1269
int _stdio_adjpos(register FILE * __restrict stream, register __offmax_t *pos)
1270
{
1271
        __offmax_t r;
1272
        int cor = stream->modeflags & __MASK_UNGOT;     /* handle ungots */
1273
 
1274
        assert(cor <= 2);
1275
 
1276
#ifdef __STDIO_WIDE
1277
        /* Assumed narrow stream so correct if wide. */
1278
        if (cor && (stream->modeflags & __FLAG_WIDE)) {
1279
                if ((((stream->modeflags & __MASK_UNGOT) > 1) || stream->ungot[1])) {
1280
                        return -1; /* App did ungetwc, so position is indeterminate. */
1281
                }
1282
                if (stream->modeflags & __MASK_UNGOT) {
1283
                        cor = cor - 1 + stream->ungot_width[1];
1284
                }
1285
                if (stream->state.mask > 0) { /* Incomplete character (possible bad) */
1286
                        cor -= stream->ungot_width[0];
1287
                }
1288
        }
1289
#endif /* __STDIO_WIDE */
1290
 
1291
#ifdef __STDIO_BUFFERS
1292
        if (stream->modeflags & __FLAG_WRITING) {
1293
                cor -= (stream->bufpos - stream->bufstart); /* pending writes */
1294
        }
1295
        if (stream->modeflags & __FLAG_READING) {
1296
                cor += (stream->bufread - stream->bufpos); /* extra's read */
1297
        }
1298
#endif /* __STDIO_BUFFERS */
1299
 
1300
        r = *pos;
1301
        return ((*pos -= cor) > r) ? -cor : cor;
1302
}
1303
 
1304
#endif
1305
/**********************************************************************/
1306
#ifdef L__stdio_lseek
1307
/*
1308
 * This function is only called by fseek and ftell.
1309
 * fseek -- doesn't care about pos val, just success or failure.
1310
 * ftell -- needs pos val but offset == 0 and whence == SET_CUR.
1311
 */
1312
 
1313
/* Internal function -- not reentrant. */
1314
 
1315
int _stdio_lseek(register FILE *stream, register __offmax_t *pos, int whence)
1316
{
1317
        __offmax_t res;
1318
 
1319
#ifdef __STDIO_GLIBC_CUSTOM_STREAMS
1320
        if (stream->cookie != &stream->filedes) {
1321
                return (((stream->gcs.seek == NULL)
1322
                                 || ((stream->gcs.seek)(stream->cookie, pos, whence) < 0))
1323
                                ? -1 : 0);
1324
        }
1325
#endif /* __STDIO_GLIBC_CUSTOM_STREAMS */
1326
#ifdef __STDIO_LARGE_FILES
1327
        res = lseek64(stream->filedes, *pos, whence);
1328
#else
1329
        res = lseek(stream->filedes, *pos, whence);
1330
#endif /* __STDIO_LARGE_FILES */
1331
        return (res >= 0) ? ((*pos = res), 0) : -1;
1332
}
1333
 
1334
#endif
1335
/**********************************************************************/
1336
#ifdef L__stdio_fread
1337
/*
1338
 * NOTE!!! This routine is meant to be callable by both narrow and wide
1339
 * functions.  However, if called by a wide function, there must be
1340
 * NO pending ungetwc()s!!!
1341
 */
1342
 
1343
/* Unlike write, it's ok for read to return fewer than bufsize, since
1344
 * we may not need all of them. */
1345
static ssize_t _stdio_READ(register FILE *stream, unsigned char *buf, size_t bufsize)
1346
{
1347
        ssize_t rv;
1348
 
1349
        /* NOTE: C99 change: Input fails once the stream's EOF indicator is set. */
1350
        if ((bufsize == 0) || (stream->modeflags & __FLAG_EOF)) {
1351
                return 0;
1352
        }
1353
 
1354
        if (bufsize > SSIZE_MAX) {
1355
                bufsize = SSIZE_MAX;
1356
        }
1357
 
1358
#ifdef __BCC__
1359
 TRY_READ:
1360
#endif
1361
        rv = __READ(stream, buf, bufsize);
1362
        if (rv > 0) {
1363
#ifdef __STDIO_GLIBC_CUSTOM_STREAMS
1364
                assert(rv <= bufsize);  /* buggy user handler... TODO: check? */
1365
                if (rv > bufsize) {     /* Num reported written > number requested */
1366
                        rv = bufsize;           /* Treat as a full read??? */
1367
                }
1368
#endif
1369
        } else if (rv == 0) {
1370
                stream->modeflags |= __FLAG_EOF;
1371
        } else {
1372
#ifdef __BCC__
1373
                if (errno == EINTR) {
1374
                        goto TRY_READ;
1375
                }
1376
#endif
1377
                stream->modeflags |= __FLAG_ERROR;
1378
                rv = 0;
1379
        }
1380
 
1381
        return rv;
1382
}
1383
 
1384
/* Internal function -- not reentrant. */
1385
 
1386
size_t _stdio_fread(unsigned char *buffer, size_t bytes, register FILE *stream)
1387
{
1388
        __stdio_validate_FILE(stream); /* debugging only */
1389
 
1390
#ifdef __STDIO_BUFFERS
1391
 
1392
        if (stream->modeflags
1393
#ifdef __STDIO_AUTO_RW_TRANSITION
1394
                & (__FLAG_WRITEONLY)
1395
#else  /* __STDIO_AUTO_RW_TRANSITION */
1396
                /* ANSI/ISO and SUSv3 require not currently writing. */
1397
                & (__FLAG_WRITEONLY|__FLAG_WRITING)
1398
#endif /* __STDIO_AUTO_RW_TRANSITION */
1399
                ) {
1400
#ifdef __STDIO_PUTC_MACRO
1401
                stream->bufputc = stream->bufstart;     /* Must disable putc. */
1402
#endif /* __STDIO_PUTC_MACRO */
1403
                stream->modeflags |= __FLAG_ERROR;
1404
                /* TODO: This is for posix behavior if writeonly.  To save space, we
1405
                 * use this errno for read attempt while writing, as no errno is
1406
                 * specified by posix for this case, even though the restriction is
1407
                 * mentioned in fopen(). */
1408
                __set_errno(EBADF);
1409
                return 0;
1410
        }
1411
 
1412
        /* We need to disable putc and getc macros in case of error */
1413
#if defined(__STDIO_PUTC_MACRO) || defined(__STDIO_GETC_MACRO)
1414
#ifdef __STDIO_PUTC_MACRO
1415
        stream->bufputc =
1416
#endif /* __STDIO_GETC_MACRO */
1417
#ifdef __STDIO_GETC_MACRO
1418
        stream->bufgetc =
1419
#endif /* __STDIO_GETC_MACRO */
1420
        stream->bufstart;
1421
#endif /*  defined(__STDIO_PUTC_MACRO) || defined(__STDIO_GETC_MACRO) */
1422
 
1423
        if (stream->modeflags & __MASK_BUFMODE) {
1424
                /* If the stream is readable and not fully buffered, we must first
1425
                 * flush all line buffered output streams.  Do this before the
1426
                 * error check as this may be a read/write line-buffered stream.
1427
                 * Note: Uses an implementation-specific hack!!! */
1428
                fflush_unlocked((FILE *) &_stdio_openlist);
1429
        }
1430
 
1431
#ifdef __STDIO_AUTO_RW_TRANSITION
1432
        if ((stream->modeflags & __FLAG_WRITING)
1433
                && (fflush_unlocked(stream) == EOF)
1434
                ) {
1435
                return 0;                                /* Fail if we need to fflush but can't. */
1436
        }
1437
#endif /* __STDIO_AUTO_RW_TRANSITION */
1438
 
1439
        stream->modeflags |= __FLAG_READING; /* Make sure Reading flag is set. */
1440
 
1441
        {
1442
                register unsigned char *p = (unsigned char *) buffer;
1443
 
1444
                /* First, grab appropriate ungetc() chars.  NOT FOR WIDE ORIENTATED! */
1445
                while (bytes && (stream->modeflags & __MASK_UNGOT)) {
1446
#ifdef __STDIO_WIDE
1447
                        assert(stream->modeflags & __FLAG_NARROW);
1448
#endif /* __STDIO_WIDE */
1449
                        *p++ = stream->ungot[(--stream->modeflags) & __MASK_UNGOT];
1450
                        stream->ungot[1] = 0;
1451
                        --bytes;
1452
                }
1453
 
1454
                /* Now get any other needed chars from the buffer or the file. */
1455
        FROM_BUF:
1456
                while (bytes && (stream->bufpos < stream->bufread)) {
1457
                        --bytes;
1458
                        *p++ = *stream->bufpos++;
1459
                }
1460
 
1461
                if (bytes > 0) {
1462
                        ssize_t len;
1463
 
1464
                        if (stream->filedes == -2) {
1465
                                stream->modeflags |= __FLAG_EOF;
1466
                                goto DONE;
1467
                        }
1468
 
1469
                        /* The buffer is exhausted, but we still need chars.  */
1470
                        stream->bufpos = stream->bufread = stream->bufstart;
1471
 
1472
                        if (bytes <= stream->bufend - stream->bufread) {
1473
                                /* We have sufficient space in the buffer. */
1474
                                len = _stdio_READ(stream, stream->bufread,
1475
                                                                  stream->bufend - stream->bufread);
1476
                                if (len > 0) {
1477
                                        stream->bufread += len;
1478
                                        goto FROM_BUF;
1479
                                }
1480
                        } else {
1481
                                /* More bytes needed than fit in the buffer, so read */
1482
                                /* directly into caller's buffer. */
1483
                                len = _stdio_READ(stream, p, bytes);
1484
                                if (len > 0) {
1485
                                        p += len;
1486
                                        bytes -= len;
1487
                                        goto FROM_BUF; /* Redundant work, but stops extra read. */
1488
                                }
1489
                        }
1490
                }
1491
 
1492
#ifdef __STDIO_GETC_MACRO
1493
                if (!(stream->modeflags
1494
                          & (__FLAG_WIDE|__MASK_UNGOT|__MASK_BUFMODE|__FLAG_ERROR))
1495
                        ) {
1496
                        stream->bufgetc = stream->bufread; /* Enable getc macro. */
1497
                }
1498
#endif
1499
 
1500
        DONE:
1501
                __stdio_validate_FILE(stream); /* debugging only */
1502
                return (p - (unsigned char *)buffer);
1503
        }
1504
 
1505
#else  /* __STDIO_BUFFERS --------------------------------------- */
1506
 
1507
        if (stream->modeflags
1508
#ifdef __STDIO_AUTO_RW_TRANSITION
1509
                & (__FLAG_WRITEONLY)
1510
#else  /* __STDIO_AUTO_RW_TRANSITION */
1511
                /* ANSI/ISO and SUSv3 require not currently writing. */
1512
                & (__FLAG_WRITEONLY|__FLAG_WRITING)
1513
#endif /* __STDIO_AUTO_RW_TRANSITION */
1514
                ) {
1515
                stream->modeflags |= __FLAG_ERROR;
1516
                /* TODO: This is for posix behavior if writeonly.  To save space, we
1517
                 * use this errno for read attempt while writing, as no errno is
1518
                 * specified by posix for this case, even though the restriction is
1519
                 * mentioned in fopen(). */
1520
                __set_errno(EBADF);
1521
                return 0;
1522
        }
1523
 
1524
#ifdef __STDIO_AUTO_RW_TRANSITION
1525
        stream->modeflags &= ~(__FLAG_WRITING); /* Make sure Writing flag clear. */
1526
#endif /* __STDIO_AUTO_RW_TRANSITION */
1527
 
1528
        stream->modeflags |= __FLAG_READING; /* Make sure Reading flag is set. */
1529
 
1530
        {
1531
                register unsigned char *p = (unsigned char *) buffer;
1532
 
1533
                /* First, grab appropriate ungetc() chars.  NOT FOR WIDE ORIENTATED! */
1534
                while (bytes && (stream->modeflags & __MASK_UNGOT)) {
1535
#ifdef __STDIO_WIDE
1536
                        assert(stream->modeflags & __FLAG_NARROW);
1537
#endif /* __STDIO_WIDE */
1538
                        *p++ = stream->ungot[(--stream->modeflags) & __MASK_UNGOT];
1539
                        stream->ungot[1] = 0;
1540
                        --bytes;
1541
                }
1542
 
1543
                while (bytes > 0) {
1544
                        ssize_t len = _stdio_READ(stream, p, (unsigned) bytes);
1545
                        if (len == 0) {
1546
                                break;
1547
                        }
1548
                        p += len;
1549
                        bytes -= len;
1550
                }
1551
 
1552
                __stdio_validate_FILE(stream); /* debugging only */
1553
                return (p - (unsigned char *)buffer);
1554
        }
1555
 
1556
#endif /* __STDIO_BUFFERS */
1557
}
1558
 
1559
#endif
1560
/**********************************************************************/
1561
#ifdef L__stdio_fwrite
1562
/*
1563
 * If buffer == NULL, attempt to fflush and return number of chars
1564
 * remaining in buffer (0 if successful fflush).
1565
 */
1566
 
1567
/* WARNING!!!! Current standards say that termination due to an asyncronous
1568
 * signal may not result in stdio streams being flushed.  This libary makes
1569
 * an effort to do so but there is no way, short of blocking signals for
1570
 * each _stdio_fwrite call, that we can maintain the correct state if a
1571
 * signal is recieved mid-call.  So any stream in mid-_stdio_fwrite could
1572
 * not some flush data or even duplicate-flush some data.  It is possible
1573
 * to avoid the duplicate-flush case by setting/clearing the stream
1574
 * error flag before/after the write process, but it doesn't seem worth
1575
 * the trouble. */
1576
 
1577
/* Like standard write, but always does a full write unless error, plus
1578
 * deals correctly with bufsize > SSIZE_MAX... not much on an issue on linux
1579
 * but definitly could be on Elks.  Also on Elks, always loops for EINTR..
1580
 * Returns number of bytes written, so a short write indicates an error */
1581
static size_t _stdio_WRITE(register FILE *stream,
1582
                                                   register const unsigned char *buf, size_t bufsize)
1583
{
1584
        size_t todo;
1585
        ssize_t rv, stodo;
1586
 
1587
        todo = bufsize;
1588
 
1589
        while (todo) {
1590
                stodo = (todo <= SSIZE_MAX) ? todo : SSIZE_MAX;
1591
                rv = __WRITE(stream, buf, stodo);
1592
                if (rv >= 0) {
1593
#ifdef __STDIO_GLIBC_CUSTOM_STREAMS
1594
                        assert(rv <= stodo);    /* buggy user handler... TODO: check? */
1595
                        if (rv > stodo) {       /* Num reported written > number requested */
1596
                                rv = stodo;             /* Treat as a full write??? */
1597
                        }
1598
#endif
1599
                        todo -= rv;
1600
                        buf += rv;
1601
                } else
1602
#ifdef __BCC__
1603
                        if (errno != EINTR)
1604
#endif
1605
                {
1606
                        stream->modeflags |= __FLAG_ERROR;
1607
                        break;
1608
                }
1609
        }
1610
 
1611
        return bufsize - todo;
1612
}
1613
 
1614
/* Internal function -- not reentrant. */
1615
 
1616
size_t _stdio_fwrite(const unsigned char *buffer, size_t bytes,
1617
                                         register FILE *stream)
1618
{
1619
#ifdef __STDIO_BUFFERS
1620
        register const unsigned char *p;
1621
 
1622
        __stdio_validate_FILE(stream); /* debugging only */
1623
 
1624
        if ((stream->modeflags & __FLAG_READONLY)
1625
#ifndef __STDIO_AUTO_RW_TRANSITION
1626
        /* ANSI/ISO requires either at EOF or currently not reading. */
1627
                || ((stream->modeflags & (__FLAG_READING|__FLAG_EOF))
1628
                        == __FLAG_READING)
1629
#endif /* __STDIO_AUTO_RW_TRANSITION */
1630
                ) {
1631
                stream->modeflags |= __FLAG_ERROR;
1632
                /* TODO: This is for posix behavior if readonly.  To save space, we
1633
                 * use this errno for write attempt while reading, as no errno is
1634
                 * specified by posix for this case, even though the restriction is
1635
                 * mentioned in fopen(). */
1636
                __set_errno(EBADF);
1637
                return 0;
1638
        }
1639
 
1640
#ifdef __STDIO_AUTO_RW_TRANSITION
1641
        /* If reading, deal with ungots and read-buffered chars. */
1642
        if (stream->modeflags & __FLAG_READING) {
1643
                if (((stream->bufpos < stream->bufread)
1644
                         || (stream->modeflags & __MASK_UNGOT))
1645
                        /* If appending, we might as well seek to end to save a seek. */
1646
                        /* TODO: set EOF in fseek when appropriate? */
1647
                        && fseek(stream, 0L,
1648
                                         ((stream->modeflags & __FLAG_APPEND)
1649
                                          ? SEEK_END : SEEK_CUR))
1650
                        ) {
1651
                        /* Note: This differs from glibc's apparent behavior of
1652
                           not setting the error flag and discarding the buffered
1653
                           read data. */
1654
                        stream->modeflags |= __FLAG_ERROR; /* fseek may not set this. */
1655
                        return 0;                        /* Fail if we need to fseek but can't. */
1656
                }
1657
                /* Always reset even if fseek called (saves a test). */
1658
#ifdef __STDIO_GETC_MACRO
1659
                stream->bufgetc =
1660
#endif /* __STDIO_GETC_MACRO */
1661
                stream->bufpos = stream->bufread = stream->bufstart;
1662
        } else
1663
#endif
1664
        if ((stream->modeflags & (__FLAG_WRITING|__FLAG_APPEND)) == __FLAG_APPEND) {
1665
                /* Append mode, but not currently writing.  Need to seek to end for proper
1666
                 * ftell() return values.  Don't worry if the stream isn't seekable. */
1667
                __offmax_t pos[1];
1668
                *pos = 0;
1669
                if (_stdio_lseek(stream, pos, SEEK_END) && (errno != EPIPE)) { /* Too big? */
1670
                        stream->modeflags |= __FLAG_ERROR;
1671
                        return 0;
1672
                }
1673
        }
1674
 
1675
#ifdef __STDIO_PUTC_MACRO
1676
        /* We need to disable putc macro in case of error */
1677
        stream->bufputc = stream->bufstart;
1678
#endif /* __STDIO_GETC_MACRO */
1679
 
1680
        /* Clear both reading and writing flags.  We need to clear the writing
1681
         * flag in case we're fflush()ing or in case of an error. */
1682
        stream->modeflags &= ~(__FLAG_READING|__FLAG_WRITING);
1683
 
1684
        {
1685
                const unsigned char *buf0 = buffer;
1686
                size_t write_count = 1; /* 0 means a write failed */
1687
 
1688
                if (!buffer) {                          /* fflush the stream */
1689
                FFLUSH:
1690
                        {
1691
                                size_t count = stream->bufpos - stream->bufstart;
1692
                                p = stream->bufstart;
1693
 
1694
                                if (stream->filedes == -2) { /* TODO -- document this hack! */
1695
                                        stream->modeflags |= __FLAG_WRITING;
1696
                                        return (!buffer) ? 0 : ((buffer - buf0) + bytes);
1697
                                }
1698
 
1699
                                {
1700
                                        write_count = _stdio_WRITE(stream, p, count);
1701
                                        p += write_count;
1702
                                        count -= write_count;
1703
                                }
1704
 
1705
                                stream->bufpos = stream->bufstart;
1706
                                while (count) {
1707
                                        *stream->bufpos++ = *p++;
1708
                                        --count;
1709
                                }
1710
 
1711
                                if (!buffer) {  /* fflush case... */
1712
                                        __stdio_validate_FILE(stream); /* debugging only */
1713
                                        return stream->bufpos - stream->bufstart;
1714
                                }
1715
                        }
1716
                }
1717
 
1718
#if 1
1719
                /* TODO: If the stream is buffered, we may be able to omit. */
1720
                if ((stream->bufpos == stream->bufstart) /* buf empty */
1721
                        && (stream->bufend - stream->bufstart <= bytes) /* fills */
1722
                        && (stream->filedes != -2)) { /* not strinf fake file */
1723
                        /* so want to do a direct write of supplied buffer */
1724
                        {
1725
                                size_t rv = _stdio_WRITE(stream, buffer, bytes);
1726
                                buffer += rv;
1727
                                bytes -= rv;
1728
                        }
1729
                } else
1730
#endif
1731
                /* otherwise buffer not empty and/or data fits */
1732
                {
1733
                        size_t count = stream->bufend - stream->bufpos;
1734
                        p = buffer;
1735
 
1736
                        if (count > bytes) {
1737
                                count = bytes;
1738
                        }
1739
                        bytes -= count;
1740
 
1741
                        while (count) {
1742
                                *stream->bufpos++ = *buffer++;
1743
                                --count;
1744
                        }
1745
 
1746
                        if (write_count) {      /* no write errors */
1747
                                if (bytes) {
1748
                                        goto FFLUSH;
1749
                                }
1750
 
1751
                                if (stream->modeflags & __FLAG_LBF) {
1752
                                        while (p < buffer) { /* check for newline. */
1753
                                                if (*p++ == '\n') {
1754
                                                        goto FFLUSH;
1755
                                                }
1756
                                        }
1757
                                }
1758
                        }
1759
                }
1760
 
1761
#ifdef __STDIO_PUTC_MACRO
1762
                if (!(stream->modeflags & (__FLAG_WIDE|__MASK_BUFMODE|__FLAG_ERROR))) {
1763
                        /* Not wide, no errors and fully buffered, so enable putc macro. */
1764
                        stream->bufputc = stream->bufend;
1765
                }
1766
#endif /* __STDIO_GETC_MACRO */
1767
                stream->modeflags |= __FLAG_WRITING; /* Ensure Writing flag is set. */
1768
 
1769
                __stdio_validate_FILE(stream); /* debugging only */
1770
                return buffer - buf0;
1771
 
1772
        }
1773
 
1774
#else  /* __STDIO_BUFFERS --------------------------------------- */
1775
 
1776
        __stdio_validate_FILE(stream); /* debugging only */
1777
 
1778
        if ((stream->modeflags & __FLAG_READONLY)
1779
#ifndef __STDIO_AUTO_RW_TRANSITION
1780
        /* ANSI/ISO requires either at EOF or currently not reading. */
1781
                || ((stream->modeflags & (__FLAG_READING|__FLAG_EOF))
1782
                        == __FLAG_READING)
1783
#endif /* __STDIO_AUTO_RW_TRANSITION */
1784
                ) {
1785
                stream->modeflags |= __FLAG_ERROR;
1786
                /* TODO: This is for posix behavior if readonly.  To save space, we
1787
                 * use this errno for write attempt while reading, as no errno is
1788
                 * specified by posix for this case, even though the restriction is
1789
                 * mentioned in fopen(). */
1790
                __set_errno(EBADF);
1791
                return 0;
1792
        }
1793
 
1794
        /* We always clear the reading flag in case at EOF. */
1795
        stream->modeflags &= ~(__FLAG_READING);
1796
 
1797
        /* Unlike the buffered case, we set the writing flag now since we don't
1798
         * need to do anything here for fflush(). */
1799
        stream->modeflags |= __FLAG_WRITING;
1800
 
1801
        {
1802
                register unsigned char *p = (unsigned char *) buffer;
1803
 
1804
                ssize_t rv = _stdio_WRITE(stream, p, bytes);
1805
 
1806
                p += rv;
1807
                bytes -= rv;
1808
 
1809
                __stdio_validate_FILE(stream); /* debugging only */
1810
                return (p - (unsigned char *)buffer);
1811
        }
1812
 
1813
#endif /* __STDIO_BUFFERS *****************************************/
1814
}
1815
 
1816
#endif
1817
/**********************************************************************/
1818
#ifdef L__stdio_init
1819
 
1820
/* Internal functions -- _stdio_init() and __stdio_validate_FILE
1821
 * are not reentrant, but _stdio_term() is through fflush().
1822
 * Also, the _cs_{read|write|close} functions are not reentrant. */
1823
 
1824
#ifndef NDEBUG
1825
void __stdio_validate_FILE(FILE *stream)
1826
{
1827
        if (stream->filedes == -2) { /* fake FILE for sprintf, scanf, etc. */
1828
                return;
1829
        }
1830
 
1831
        __STDIO_THREADLOCK(stream);
1832
 
1833
#ifdef __STDIO_BUFFERS
1834
        assert(stream->bufstart <= stream->bufread);
1835
        if (stream->modeflags & (__FLAG_READING)) {
1836
                assert(stream->bufpos <= stream->bufread);
1837
        }
1838
        assert(stream->bufread <= stream->bufend);
1839
        assert(stream->bufpos <= stream->bufend);
1840
        if ((stream->modeflags & __MASK_BUFMODE) == __FLAG_NBF) {
1841
                assert(stream->bufstart == stream->bufend);
1842
        }
1843
        assert((stream->modeflags & __MASK_BUFMODE) <= __FLAG_NBF);
1844
#endif
1845
#ifdef __STDIO_PUTC_MACRO
1846
        assert(stream->bufstart <= stream->bufputc);
1847
        assert(stream->bufputc <= stream->bufend);
1848
        if (stream->bufstart < stream->bufputc) {
1849
                assert(stream->bufputc == stream->bufend);
1850
                assert(stream->modeflags & (__FLAG_WRITING));
1851
                assert(!(stream->modeflags
1852
                                 & (__FLAG_WIDE|__MASK_BUFMODE|__MASK_UNGOT|__FLAG_READONLY))
1853
                           );
1854
        }
1855
#endif
1856
#ifdef __STDIO_GETC_MACRO
1857
        assert(stream->bufstart <= stream->bufgetc);
1858
        assert(stream->bufgetc <= stream->bufread);
1859
        if (stream->bufstart < stream->bufgetc) {
1860
                assert(stream->modeflags & (__FLAG_READING));
1861
                assert(!(stream->modeflags
1862
                                 & (__FLAG_WIDE|__MASK_BUFMODE|__MASK_UNGOT|__FLAG_WRITEONLY))
1863
                           );
1864
        }
1865
#endif
1866
        assert((stream->modeflags & __MASK_UNGOT) != __MASK_UNGOT);
1867
        if (stream->modeflags & __MASK_UNGOT1) {
1868
                assert(stream->ungot[1] <= 1);
1869
        }
1870
        if (stream->modeflags & __MASK_UNGOT) {
1871
                assert(!(stream->modeflags & __FLAG_EOF));
1872
        }
1873
        assert((stream->modeflags & (__FLAG_READONLY|__FLAG_WRITEONLY))
1874
                   != (__FLAG_READONLY|__FLAG_WRITEONLY));
1875
 
1876
        /* TODO -- filepos?  ungot_width?  filedes?  nextopen? */
1877
 
1878
        __STDIO_THREADUNLOCK(stream);
1879
}
1880
#endif
1881
 
1882
#ifdef __STDIO_GLIBC_CUSTOM_STREAMS
1883
ssize_t _cs_read(void *cookie, char *buf, size_t bufsize)
1884
{
1885
        return read(*((int *) cookie), buf, bufsize);
1886
}
1887
 
1888
ssize_t _cs_write(void *cookie, const char *buf, size_t bufsize)
1889
{
1890
        return write(*((int *) cookie), (char *) buf, bufsize);
1891
}
1892
 
1893
int _cs_close(void *cookie)
1894
{
1895
        return close(*((int *) cookie));
1896
}
1897
#endif /* __STDIO_GLIBC_CUSTOM_STREAMS */
1898
 
1899
#ifdef __STDIO_BUFFERS
1900
static unsigned char _fixed_buffers[2 * BUFSIZ];
1901
#define bufin (_fixed_buffers)
1902
#define bufout (_fixed_buffers + BUFSIZ)
1903
#endif /* __STDIO_BUFFERS */
1904
 
1905
static FILE _stdio_streams[] = {
1906
        __STDIO_INIT_FILE_STRUCT(_stdio_streams[0], __FLAG_LBF|__FLAG_READONLY, \
1907
                                                         0, _stdio_streams + 1, bufin, BUFSIZ ),
1908
        __STDIO_INIT_FILE_STRUCT(_stdio_streams[1], __FLAG_LBF|__FLAG_WRITEONLY, \
1909
                                                         1, _stdio_streams + 2, bufout, BUFSIZ ),
1910
        __STDIO_INIT_FILE_STRUCT(_stdio_streams[2], __FLAG_NBF|__FLAG_WRITEONLY, \
1911
                                                         2, 0, 0, 0 )
1912
};
1913
 
1914
FILE *stdin = _stdio_streams + 0;
1915
FILE *stdout = _stdio_streams + 1;
1916
FILE *stderr = _stdio_streams + 2;
1917
 
1918
#if defined(__STDIO_BUFFERS) || defined(__STDIO_GLIBC_CUSTOM_STREAMS)
1919
 
1920
#ifdef __STDIO_BUFFERS
1921
FILE *_stdio_openlist = _stdio_streams;
1922
#else  /* __STDIO_BUFFERS */
1923
FILE *_stdio_openlist = NULL;
1924
#endif /* __STDIO_BUFFERS */
1925
 
1926
#ifdef __STDIO_THREADSAFE
1927
pthread_mutex_t _stdio_openlist_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
1928
 
1929
 
1930
void __stdio_init_mutex(pthread_mutex_t *m)
1931
{
1932
        static const pthread_mutex_t __stdio_mutex_initializer
1933
                = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
1934
 
1935
        memcpy(m, &__stdio_mutex_initializer, sizeof(__stdio_mutex_initializer));
1936
}
1937
#endif /* __STDIO_THREADSAFE */
1938
 
1939
/* TODO - do we need to lock things, or do we just assume we're the only
1940
 * remaining thread? */
1941
 
1942
/* Note: We assume here that we are the only remaining thread. */
1943
void _stdio_term(void)
1944
{
1945
#if defined(__STDIO_GLIBC_CUSTOM_STREAMS) || defined(__STDIO_THREADSAFE)
1946
        register FILE *ptr;
1947
#endif
1948
 
1949
        /* TODO: if called via a signal handler for a signal mid _stdio_fwrite,
1950
         * the stream may be in an unstable state... what do we do?
1951
         * perhaps set error flag before and clear when done if successful? */
1952
 
1953
#if defined(__STDIO_BUFFERS) || defined(__STDIO_GLIBC_CUSTOM_STREAMS)
1954
#ifdef __STDIO_THREADSAFE
1955
        /* First, forceably unlock the open file list and all files.
1956
         * Note: Set locking mode to "by caller" to save some overhead later. */
1957
        __stdio_init_mutex(&_stdio_openlist_lock);
1958
        for (ptr = _stdio_openlist ; ptr ; ptr = ptr->nextopen ) {
1959
                ptr->user_locking = 1;
1960
                __stdio_init_mutex(&ptr->lock);
1961
        }
1962
#endif /* __STDIO_THREADSAFE */
1963
#endif /* defined(__STDIO_BUFFERS) || defined(__STDIO_GLIBC_CUSTOM_STREAMS) */
1964
 
1965
#ifdef __STDIO_BUFFERS
1966
        /* TODO -- set an alarm and flush each file "by hand"? to avoid blocking? */
1967
 
1968
        /* Now flush all streams. */
1969
        fflush_unlocked(NULL);
1970
#endif /* __STDIO_BUFFERS */
1971
 
1972
        /* Next close all custom streams in case of any special cleanup, but
1973
         * don't use fclose() because that pulls in free and malloc.  Also,
1974
         * don't worry about removing them from the list.  Just set the cookie
1975
         * pointer to NULL so that an error will be generated if someone tries
1976
         * to use the stream. */
1977
#ifdef __STDIO_GLIBC_CUSTOM_STREAMS
1978
        for (ptr = _stdio_openlist ; ptr ; ptr = ptr->nextopen ) {
1979
                if (ptr->cookie != &ptr->filedes) {     /* custom stream */
1980
                        __CLOSE(ptr);
1981
                        ptr->cookie = NULL;     /* Generate an error if used later. */
1982
#if 0
1983
/*  #ifdef __STDIO_BUFFERS */
1984
                } else {
1985
                        /* TODO: "unbuffer" files like glibc does?  Inconsistent with
1986
                         * custom stream handling above, but that's necessary to deal
1987
                         * with special user-defined close behavior. */
1988
                        stream->bufpos = stream->bufread = stream->bufend
1989
#ifdef __STDIO_GETC_MACRO
1990
                                = stream->bufgetc
1991
#endif
1992
#ifdef __STDIO_PUTC_MACRO
1993
                                = stream->bufputc
1994
#endif
1995
                                = stream->bufstart;
1996
#endif /* __STDIO_BUFFERS */
1997
                }
1998
        }
1999
#endif /* __STDIO_GLIBC_CUSTOM_STREAMS */
2000
}
2001
 
2002
 
2003
#if defined(__STDIO_BUFFERS) || !defined(__UCLIBC__)
2004
void _stdio_init(void)
2005
{
2006
#ifdef __STDIO_BUFFERS
2007
        int old_errno = errno;
2008
        /* stdin and stdout uses line buffering when connected to a tty. */
2009
        _stdio_streams[0].modeflags ^= (1-isatty(0)) * __FLAG_LBF;
2010
        _stdio_streams[1].modeflags ^= (1-isatty(1)) * __FLAG_LBF;
2011
        __set_errno(old_errno);
2012
#endif /* __STDIO_BUFFERS */
2013
#ifndef __UCLIBC__
2014
/* __stdio_term is automatically when exiting if stdio is used.
2015
 * See misc/internals/__uClibc_main.c and and stdlib/atexit.c. */
2016
        atexit(_stdio_term);
2017
#endif /* __UCLIBC__ */
2018
}
2019
#endif /* defined(__STDIO_BUFFERS) || !defined(__UCLIBC__) */
2020
#endif /* defined(__STDIO_BUFFERS) || defined(__STDIO_GLIBC_CUSTOM_STREAMS) */
2021
 
2022
#endif
2023
/**********************************************************************/
2024
/* ANSI/ISO functions. */
2025
/**********************************************************************/
2026
#ifdef L_remove
2027
#include <unistd.h>
2028
#include <errno.h>
2029
 
2030
/* No reentrancy issues. */
2031
 
2032
int remove(register const char *filename)
2033
{
2034
        int old_errno = errno;
2035
 
2036
        /* SUSv3 says equivalent to rmdir() if a directory, and unlink()
2037
         * otherwise.  Hence, we need to try rmdir() first. */
2038
 
2039
        return (((rmdir(filename) == 0)
2040
                         || ((errno == ENOTDIR)
2041
                                 && ((__set_errno(old_errno), unlink(filename)) == 0)))
2042
                        ? 0 : -1);
2043
}
2044
#endif
2045
/**********************************************************************/
2046
/* rename is a syscall
2047
#ifdef L_rename
2048
int rename(const char *old, const char *new);
2049
#endif
2050
*/
2051
/**********************************************************************/
2052
/* TODO: tmpfile */
2053
/*  #ifdef L_tmpfile */
2054
/*  FILE *tmpfile(void); */
2055
/*  #endif */
2056
/**********************************************************************/
2057
/* TODO: tmpname */
2058
/*  #ifdef L_tmpname */
2059
/*  char *tmpname(char *s); */
2060
/*  #endif */
2061
/**********************************************************************/
2062
#ifdef L_fclose
2063
 
2064
/* We need to be careful here to avoid deadlock when threading, as we
2065
 * need to lock both the file and the open file list.  This can clash
2066
 * with fflush.  Since fflush is much more common, we do the extra
2067
 * work here. */
2068
 
2069
int fclose(register FILE *stream)
2070
{
2071
#if defined(__STDIO_BUFFERS) || defined(__STDIO_GLIBC_CUSTOM_STREAMS)
2072
 
2073
        register FILE *ptr;
2074
        int rv = 0;
2075
 
2076
#ifdef __STDIO_THREADSAFE
2077
        /* Need two non-heirchal mutexs... be careful to avoid deadlock*/
2078
        do {
2079
                __STDIO_THREADLOCK(stream);
2080
                if (__STDIO_THREADTRYLOCK_OPENLIST == 0) {
2081
                        break;
2082
                }
2083
                __STDIO_THREADUNLOCK(stream);
2084
                usleep(10000);
2085
        } while (1);
2086
#endif /* __STDIO_THREADSAFE */
2087
 
2088
        __stdio_validate_FILE(stream); /* debugging only */
2089
 
2090
#ifdef __STDIO_BUFFERS
2091
        if (stream->modeflags & __FLAG_WRITING) {
2092
                rv = fflush_unlocked(stream); /* Write any pending buffered chars. */
2093
        }                                                                 /* Also disables putc macro if used. */
2094
 
2095
#ifdef __STDIO_GETC_MACRO
2096
        /* Not necessary after fflush, but always do this to reduce size. */
2097
        stream->bufgetc = stream->bufstart;     /* Disable getc macro for safety. */
2098
#endif /* __STDIO_GETC_MACRO */
2099
#endif /* __STDIO_BUFFERS */
2100
 
2101
        /* Remove file from open list before closing file descriptor. */
2102
        ptr = _stdio_openlist;
2103
        if (ptr == stream) {
2104
                _stdio_openlist = stream->nextopen;
2105
        } else {
2106
                while (ptr) {
2107
                        if (ptr->nextopen == stream) {
2108
                                ptr->nextopen = stream->nextopen;
2109
                                break;
2110
                        }
2111
                        ptr = ptr->nextopen;
2112
                }
2113
        }
2114
        __STDIO_THREADUNLOCK_OPENLIST; /* We're done with the open file list. */
2115
 
2116
        if (__CLOSE(stream) < 0) {       /* Must close even if fflush failed. */
2117
                rv = EOF;
2118
        }
2119
#ifdef __STDIO_GLIBC_CUSTOM_STREAMS
2120
        stream->cookie = &(stream->filedes);
2121
        stream->gcs.read = _cs_read;
2122
        stream->gcs.write = _cs_write;
2123
        stream->gcs.seek = 0;            /* The internal seek func handles normals. */
2124
        stream->gcs.close = _cs_close;
2125
#endif
2126
        stream->filedes = -1;           /* To aid debugging... */
2127
 
2128
#ifdef __STDIO_BUFFERS
2129
        if (stream->modeflags & __FLAG_FREEBUF) {
2130
                free(stream->bufstart);
2131
        }
2132
#endif /* __STDIO_BUFFERS */
2133
 
2134
        /* TODO -- leave the stream locked to catch any dangling refs? */
2135
        __STDIO_THREADUNLOCK(stream);
2136
 
2137
        /* At this point, any dangling refs to the stream are the result of
2138
         * a programming bug... so free the unlocked stream. */
2139
        if (stream->modeflags & __FLAG_FREEFILE) {
2140
#ifdef __STDIO_GLIBC_CUSTOM_STREAMS
2141
            stream->cookie = NULL;      /* To aid debugging... */
2142
#endif
2143
                free(stream);
2144
        }
2145
 
2146
        return rv;
2147
 
2148
#else  /* defined(__STDIO_BUFFERS) || defined(__STDIO_GLIBC_CUSTOM_STREAMS) */
2149
 
2150
        int rv = 0;
2151
 
2152
        __STDIO_THREADLOCK(stream);
2153
 
2154
        __stdio_validate_FILE(stream); /* debugging only */
2155
 
2156
        if (__CLOSE(stream) < 0) {       /* Must close even if fflush failed. */
2157
                rv = EOF;
2158
        }
2159
 
2160
#ifdef __STDIO_GLIBC_CUSTOM_STREAMS
2161
        stream->cookie = &(stream->filedes);
2162
        stream->gcs.read = _cs_read;
2163
        stream->gcs.write = _cs_write;
2164
        stream->gcs.seek = 0;            /* The internal seek func handles normals. */
2165
        stream->gcs.close = _cs_close;
2166
#endif
2167
        stream->filedes = -1;           /* To aid debugging... */
2168
 
2169
        __STDIO_THREADUNLOCK(stream);
2170
 
2171
        /* At this point, any dangling refs to the stream are the result of
2172
         * a programming bug... so free the unlocked stream. */
2173
        if (stream->modeflags & __FLAG_FREEFILE) {
2174
#ifdef __STDIO_GLIBC_CUSTOM_STREAMS
2175
            stream->cookie = NULL;      /* To aid debugging... */
2176
#endif
2177
                free(stream);
2178
        }
2179
 
2180
        return rv;
2181
 
2182
#endif /* defined(__STDIO_BUFFERS) || defined(__STDIO_GLIBC_CUSTOM_STREAMS )*/
2183
}
2184
 
2185
#endif
2186
/**********************************************************************/
2187
#ifdef L_fflush
2188
 
2189
/*
2190
 * Special cases:
2191
 *   stream == NULL means fflush all writing streams (ANSI/ISO).
2192
 *   stream == (FILE *) &_stdio_openlist -- implementation-specific hack
2193
 *      meaning fflush all line buffered writing streams
2194
 */
2195
 
2196
/*
2197
 * NOTE: ANSI/ISO difference!!!  According to the standard, fflush is only
2198
 * defined for write-only streams, or read/write streams whose last op
2199
 * was a write.  However, reading is allowed for a read/write stream if
2200
 * a file positioning operation was done (fseek, fsetpos) even though there
2201
 * is no guarantee of flushing the write data in that case.  Hence, for
2202
 * this case we keep a flag to indicate whether or not the buffer needs to
2203
 * be flushed even if the last operation was a read.  This falls under the
2204
 * implementation-defined behavior.  Otherwise, we would need to flush
2205
 * every time we did fseek, etc. even if we were still in the buffer's range.
2206
 */
2207
 
2208
/* Since the stream pointer arg is allowed to be NULL, or the address of the
2209
 * stdio open file list if stdio is buffered in this implementation, we can't
2210
 * use the UNLOCKED() macro here. */
2211
 
2212
#ifndef __STDIO_THREADSAFE
2213
strong_alias(fflush_unlocked,fflush)
2214
#else  /* __STDIO_THREADSAFE */
2215
int fflush(register FILE *stream)
2216
{
2217
        int retval;
2218
 
2219
        if ((stream != NULL)
2220
#if defined(__STDIO_BUFFERS) || defined(__STDIO_GLIBC_CUSTOM_STREAMS)
2221
                && (stream != (FILE *) &_stdio_openlist)
2222
#endif /* defined(__STDIO_BUFFERS) || defined(__STDIO_GLIBC_CUSTOM_STREAMS) */
2223
                ) {
2224
                __STDIO_THREADLOCK(stream);
2225
                retval = fflush_unlocked(stream);
2226
                __STDIO_THREADUNLOCK(stream);
2227
        } else {
2228
                retval = fflush_unlocked(stream);
2229
        }
2230
 
2231
        return retval;
2232
}
2233
#endif /* __STDIO_THREADSAFE */
2234
 
2235
int fflush_unlocked(register FILE *stream)
2236
{
2237
#ifdef __STDIO_BUFFERS
2238
 
2239
        int rv = 0;
2240
        unsigned short mask = (__FLAG_NBF|__FLAG_LBF);
2241
 
2242
#ifndef NDEBUG
2243
        if ((stream != NULL) && (stream != (FILE *) &_stdio_openlist)) {
2244
                __stdio_validate_FILE(stream); /* debugging only */
2245
        }
2246
#endif
2247
 
2248
        if (stream == (FILE *) &_stdio_openlist) { /* fflush all line-buffered */
2249
                stream = NULL;
2250
                mask = __FLAG_LBF;
2251
        }
2252
 
2253
        if (stream == NULL) {           /* flush all (line) buffered writing streams */
2254
                /* Note -- We have to lock the list even in the unlocked function. */
2255
                __STDIO_THREADLOCK_OPENLIST;
2256
                /* TODO -- Can we work around locking the list to avoid keeping it
2257
                 * locked if the write blocks? */
2258
                for (stream = _stdio_openlist; stream; stream = stream->nextopen) {
2259
                        if (((stream->modeflags ^ __FLAG_NBF) & mask)
2260
                                && (stream->modeflags & __FLAG_WRITING)
2261
                                && fflush(stream)) {
2262
                                rv = EOF;
2263
                        }
2264
                }
2265
                __STDIO_THREADUNLOCK_OPENLIST;
2266
        } else if (stream->modeflags & __FLAG_WRITING) {
2267
                if (_stdio_fwrite(NULL, 0, stream) > 0) { /* flush buffer contents. */
2268
                        rv = -1;                        /* Not all chars written. */
2269
                }
2270
#ifdef __UCLIBC_MJN3_ONLY__
2271
#warning WISHLIST: Add option to test for undefined behavior of fflush.
2272
#endif /* __UCLIBC_MJN3_ONLY__ */
2273
#if 0
2274
        } else if (stream->modeflags & (__FLAG_READING|__FLAG_READONLY)) {
2275
                /* ANSI/ISO says behavior in this case is undefined but also says you
2276
                 * shouldn't flush a stream you were reading from.  As usual, glibc
2277
                 * caters to broken programs and simply ignores this. */
2278
                stream->modeflags |= __FLAG_ERROR;
2279
                __set_errno(EBADF);
2280
                rv = -1;
2281
#endif
2282
        }
2283
 
2284
#ifndef NDEBUG
2285
        if ((stream != NULL) && (stream != (FILE *) &_stdio_openlist)) {
2286
                __stdio_validate_FILE(stream); /* debugging only */
2287
        }
2288
#endif
2289
        return rv;
2290
 
2291
#else  /* __STDIO_BUFFERS --------------------------------------- */
2292
 
2293
#ifndef NDEBUG
2294
        if ((stream != NULL)
2295
#if defined(__STDIO_BUFFERS) || defined(__STDIO_GLIBC_CUSTOM_STREAMS)
2296
                && (stream != (FILE *) &_stdio_openlist)
2297
#endif /* defined(__STDIO_BUFFERS) || defined(__STDIO_GLIBC_CUSTOM_STREAMS) */
2298
                ) {
2299
                __stdio_validate_FILE(stream); /* debugging only */
2300
        }
2301
#endif
2302
 
2303
#ifdef __UCLIBC_MJN3_ONLY__
2304
#warning WISHLIST: Add option to test for undefined behavior of fflush.
2305
#endif /* __UCLIBC_MJN3_ONLY__ */
2306
#if 0
2307
        return ((stream != NULL)
2308
                        && (stream->modeflags & (__FLAG_READING|__FLAG_READONLY))
2309
                        ? ((stream->modeflags |= __FLAG_ERROR), __set_errno(EBADF), EOF)
2310
                        : 0 );
2311
#else
2312
        return 0;
2313
#endif
2314
 
2315
#endif /* __STDIO_BUFFERS */
2316
}
2317
#endif
2318
/**********************************************************************/
2319
#ifdef L_fopen
2320
 
2321
/* No reentrancy issues. */
2322
 
2323
FILE *fopen(const char * __restrict filename, const char * __restrict mode)
2324
{
2325
        return _stdio_fopen(filename, mode, NULL, -1);
2326
}
2327
 
2328
#endif
2329
/**********************************************************************/
2330
#ifdef L__stdio_fopen
2331
 
2332
/*
2333
 * Cases:
2334
 *  fopen    : filename != NULL, stream == NULL, filedes == -1
2335
 *  freopen  : filename != NULL, stream != NULL, filedes == -1
2336
 *  fdopen   : filename == NULL, stream == NULL, filedes valid
2337
 *  fsfopen  : filename != NULL, stream != NULL, filedes == -1
2338
 *  fopen64  : filename != NULL, stream == NULL, filedes == -2
2339
 */
2340
 
2341
#if O_ACCMODE != 3 || O_RDONLY != 0 || O_WRONLY != 1 || O_RDWR != 2
2342
#error Assumption violated - mode constants
2343
#endif
2344
 
2345
/* Internal function -- reentrant (locks open file list) */
2346
 
2347
FILE *_stdio_fopen(const char * __restrict filename,
2348
                                   register const char * __restrict mode,
2349
                                   register FILE * __restrict stream, int filedes)
2350
{
2351
        __mode_t open_mode;
2352
 
2353
        /* parse mode */
2354
        open_mode = O_RDONLY;
2355
        if (*mode != 'r') {                     /* not read */
2356
                open_mode = (O_WRONLY | O_CREAT | O_TRUNC);
2357
                if (*mode != 'w') {             /* not write (create or truncate)*/
2358
                        open_mode = (O_WRONLY | O_CREAT | O_APPEND);
2359
                        if (*mode != 'a') {     /* not write (create or append) */
2360
                                __set_errno(EINVAL); /* then illegal mode */
2361
                                return NULL;
2362
                        }
2363
                }
2364
        }
2365
 
2366
        if ((*++mode == 'b')) {         /* binary mode (NOP currently) */
2367
                ++mode;
2368
        }
2369
 
2370
        if (*mode == '+') {                     /* read-write */
2371
                ++mode;
2372
                open_mode &= ~(O_RDONLY | O_WRONLY);
2373
                open_mode |= O_RDWR;
2374
        }
2375
 
2376
#if defined(__STDIO_FOPEN_EXCLUSIVE_MODE) || defined(__STDIO_FOPEN_LARGEFILE_MODE)
2377
        for ( ; *mode ; ++mode) {  /* ignore everything else except ... */
2378
#ifdef __STDIO_FOPEN_EXCLUSIVE_MODE
2379
                if (*mode == 'x') {        /* open exclusive -- glibc extension */
2380
                        open_mode |= O_EXCL;
2381
                        continue;
2382
                }
2383
#endif /* __STDIO_FOPEN_EXCLUSIVE_MODE */
2384
#ifdef __STDIO_FOPEN_LARGEFILE_MODE
2385
                if (*mode == 'F') {             /* open large file */
2386
                        open_mode |= O_LARGEFILE;
2387
                        continue;
2388
                }
2389
#endif /* __STDIO_FOPEN_LARGEFILE_MODE */
2390
        }
2391
#endif /* __STDIO_FOPEN_EXCLUSIVE_MODE or __STDIO_FOPEN_LARGEFILE_MODE def'd */
2392
 
2393
#ifdef __BCC__
2394
        mode = filename;                        /* TODO:  help BCC with register allocation. */
2395
#define filename mode
2396
#endif /* __BCC__ */
2397
 
2398
        if (!stream) {                          /* Need to allocate a FILE. */
2399
#ifdef __STDIO_BUFFERS
2400
                if ((stream = malloc(sizeof(FILE))) == NULL) {
2401
                        return stream;
2402
                }
2403
                stream->modeflags = __FLAG_FREEFILE;
2404
                if ((stream->bufstart = malloc(BUFSIZ)) != 0) {
2405
                        stream->bufend = stream->bufstart + BUFSIZ;
2406
                        stream->modeflags |= __FLAG_FREEBUF;
2407
                } else {
2408
#if __STDIO_BUILTIN_BUF_SIZE > 0
2409
                        stream->bufstart = stream->unbuf;
2410
                        stream->bufend = stream->unbuf + sizeof(stream->unbuf);
2411
#else  /* __STDIO_BUILTIN_BUF_SIZE > 0 */
2412
                        stream->bufstart = stream->bufend = NULL;
2413
#endif /* __STDIO_BUILTIN_BUF_SIZE > 0 */
2414
                }
2415
#else  /* __STDIO_BUFFERS */
2416
                if ((stream = malloc(sizeof(FILE))) == NULL) {
2417
                        return stream;
2418
                }
2419
                stream->modeflags = __FLAG_FREEFILE;
2420
#endif /* __STDIO_BUFFERS */
2421
        }
2422
 
2423
        if (filedes >= 0) {                      /* Handle fdopen trickery. */
2424
                /* NOTE: it is insufficient to just check R/W/RW agreement.
2425
                 * We must also check largefile compatibility if applicable.
2426
                 * Also, if append mode is desired for fdopen but O_APPEND isn't
2427
                 * currently set, then set it as recommended by SUSv3.  However,
2428
                 * if append mode is not specified for fdopen but O_APPEND is set,
2429
                 * leave it set (glibc compat). */
2430
                int i = (open_mode & (O_ACCMODE|O_LARGEFILE)) + 1;
2431
 
2432
                /* NOTE: fopencookie needs changing if the basic check changes! */
2433
                if (((i & (((int) filename) + 1)) != i) /* Check basic agreement. */
2434
                        || (((open_mode & O_APPEND)
2435
                                 && !(((int) filename) & O_APPEND)
2436
                                 && fcntl(filedes, F_SETFL, O_APPEND))) /* Need O_APPEND. */
2437
                        ) {
2438
                        __set_errno(EINVAL);
2439
                        filedes = -1;
2440
                }
2441
#ifdef __STDIO_LARGE_FILES
2442
                /* For later... to reflect largefile setting in stream flags. */
2443
                open_mode |= (((int) filename) & O_LARGEFILE);
2444
#endif /* __STDIO_LARGE_FILES */
2445
                stream->filedes = filedes;
2446
        } else {
2447
#ifdef __STDIO_LARGE_FILES
2448
                if (filedes < -1) {
2449
                        open_mode |= O_LARGEFILE;
2450
                }
2451
#endif /* __STDIO_LARGE_FILES */
2452
                stream->filedes = open(filename, open_mode, 0666);
2453
        }
2454
 
2455
        if (stream->filedes < 0) {
2456
#ifdef __STDIO_BUFFERS
2457
                if (stream->modeflags & __FLAG_FREEBUF) {
2458
                        free(stream->bufstart);
2459
                }
2460
#endif /* __STDIO_BUFFERS */
2461
                if (stream->modeflags & __FLAG_FREEFILE) {
2462
                        free(stream);
2463
                }
2464
                return NULL;
2465
        }
2466
 
2467
#ifdef __STDIO_BUFFERS
2468
        {
2469
            /* Do not let isatty mess up errno */
2470
            int old_errno = errno;
2471
            stream->modeflags |= (isatty(stream->filedes) * __FLAG_LBF);
2472
            __set_errno(old_errno);
2473
        }
2474
#endif
2475
 
2476
        stream->modeflags |=
2477
#if (O_APPEND == __FLAG_APPEND) \
2478
&& ((O_LARGEFILE == __FLAG_LARGEFILE) || (O_LARGEFILE == 0))
2479
                (open_mode & (O_APPEND|O_LARGEFILE)) | /* i386 linux and elks */
2480
#else  /* (O_APPEND == __FLAG_APPEND) && (O_LARGEFILE == __FLAG_LARGEFILE) */
2481
                ((open_mode & O_APPEND) ? __FLAG_APPEND : 0) |
2482
#ifdef __STDIO_LARGE_FILES
2483
                ((open_mode & O_LARGEFILE) ? __FLAG_LARGEFILE : 0) |
2484
#endif /* __STDIO_LARGE_FILES */
2485
#endif /* (O_APPEND == __FLAG_APPEND) && (O_LARGEFILE == __FLAG_LARGEFILE) */
2486
                ((((open_mode & O_ACCMODE) + 1) ^ 0x03) * __FLAG_WRITEONLY);
2487
 
2488
#ifdef __STDIO_BUFFERS
2489
#ifdef __STDIO_GETC_MACRO
2490
        stream->bufgetc =
2491
#endif
2492
#ifdef __STDIO_PUTC_MACRO
2493
        stream->bufputc =
2494
#endif
2495
        stream->bufpos = stream->bufread = stream->bufstart;
2496
#endif /* __STDIO_BUFFERS */
2497
 
2498
#ifdef __STDIO_GLIBC_CUSTOM_STREAMS
2499
        stream->cookie = &(stream->filedes);
2500
        stream->gcs.read = _cs_read;
2501
        stream->gcs.write = _cs_write;
2502
        stream->gcs.seek = 0;            /* The internal seek func handles normals. */
2503
        stream->gcs.close = _cs_close;
2504
#endif /* __STDIO_GLIBC_CUSTOM_STREAMS */
2505
 
2506
#ifdef __STDIO_WIDE
2507
        stream->ungot_width[0] = 0;
2508
#endif /* __STDIO_WIDE */
2509
#ifdef __STDIO_MBSTATE
2510
        __INIT_MBSTATE(&(stream->state));
2511
#endif /* __STDIO_MBSTATE */
2512
 
2513
#ifdef __STDIO_THREADSAFE
2514
        stream->user_locking = 0;
2515
        __stdio_init_mutex(&stream->lock);
2516
#endif /* __STDIO_THREADSAFE */
2517
 
2518
#if defined(__STDIO_BUFFERS) \
2519
|| (defined(__STDIO_THREADSAFE) && defined(__STDIO_GLIBC_CUSTOM_STREAMS))
2520
        __STDIO_THREADLOCK_OPENLIST;
2521
        stream->nextopen = _stdio_openlist;     /* New files are inserted at */
2522
        _stdio_openlist = stream;                       /*   the head of the list. */
2523
        __STDIO_THREADUNLOCK_OPENLIST;
2524
#endif
2525
 
2526
        __stdio_validate_FILE(stream); /* debugging only */
2527
        return stream;
2528
#ifdef __BCC__
2529
#undef filename
2530
#endif /* __BCC__ */
2531
}
2532
 
2533
#endif
2534
/**********************************************************************/
2535
#ifdef L_freopen
2536
 
2537
/* Reentrant. */
2538
 
2539
FILE *freopen(const char * __restrict filename, const char * __restrict mode,
2540
                          register FILE * __restrict stream)
2541
{
2542
        /*
2543
         * ANSI/ISO allow (implementation-defined) change of mode for an
2544
         * existing file if filename is NULL.  It doesn't look like Linux
2545
         * supports this, so we don't here.
2546
         *
2547
         * NOTE: Whether or not the stream is free'd on failure is unclear
2548
         *       w.r.t. ANSI/ISO.  This implementation chooses to NOT free
2549
         *       the stream and associated buffer if they were dynamically
2550
         *       allocated.
2551
         * TODO: Check the above.
2552
         * TODO: Apparently linux allows setting append mode.  Implement?
2553
         */
2554
        unsigned short dynmode;
2555
        register FILE *fp;
2556
 
2557
        __STDIO_THREADLOCK(stream);
2558
 
2559
        /* First, flush and close, but don't deallocate, the stream. */
2560
        /* This also removes the stream for the open file list. */
2561
        dynmode =
2562
#ifdef __STDIO_BUFFERS
2563
                /*              __MASK_BUFMODE | */             /* TODO: check */
2564
#endif /* __STDIO_BUFFERS */
2565
                (stream->modeflags & (__FLAG_FREEBUF|__FLAG_FREEFILE));
2566
 
2567
        stream->modeflags &= ~(__FLAG_FREEBUF|__FLAG_FREEFILE);
2568
        fclose(stream);                         /* Failures are ignored. */
2569
 
2570
        fp = _stdio_fopen(filename, mode, stream, -1);
2571
 
2572
        stream->modeflags |= dynmode;
2573
 
2574
        __STDIO_THREADUNLOCK(stream);
2575
 
2576
        return fp;
2577
}
2578
#endif
2579
/**********************************************************************/
2580
#ifdef L_freopen64
2581
 
2582
/* Reentrant. */
2583
 
2584
/* TODO -- is it worth collecting the common work (40 bytes) in a function? */
2585
FILE *freopen64(const char * __restrict filename, const char * __restrict mode,
2586
                                register FILE * __restrict stream)
2587
{
2588
        unsigned short dynmode;
2589
        register FILE *fp;
2590
 
2591
        __STDIO_THREADLOCK(stream);
2592
 
2593
        /* First, flush and close, but don't deallocate, the stream. */
2594
        /* This also removes the stream for the open file list. */
2595
        dynmode =
2596
#ifdef __STDIO_BUFFERS
2597
                /*              __MASK_BUFMODE | */             /* TODO: check */
2598
#endif /* __STDIO_BUFFERS */
2599
                (stream->modeflags & (__FLAG_FREEBUF|__FLAG_FREEFILE));
2600
 
2601
        stream->modeflags &= ~(__FLAG_FREEBUF|__FLAG_FREEFILE);
2602
        fclose(stream);                         /* Failures are ignored. */
2603
        stream->modeflags = dynmode;
2604
 
2605
        fp = _stdio_fopen(filename, mode, stream, -2); /* TODO -- magic const */
2606
 
2607
        __STDIO_THREADUNLOCK(stream);
2608
 
2609
        return fp;
2610
}
2611
 
2612
#endif
2613
/**********************************************************************/
2614
#ifdef L_setbuf
2615
 
2616
/* Reentrant through setvbuf(). */
2617
 
2618
void setbuf(FILE * __restrict stream, register char * __restrict buf)
2619
{
2620
#ifdef __STDIO_BUFFERS
2621
        int mode;
2622
 
2623
        mode = (buf != NULL) ? _IOFBF : _IONBF;
2624
        setvbuf(stream, buf, mode, BUFSIZ);
2625
#else  /* __STDIO_BUFFERS */
2626
        /* TODO -- assert on stream? */
2627
        /* Nothing to do. */
2628
#endif /* __STDIO_BUFFERS */
2629
}
2630
 
2631
#endif
2632
/**********************************************************************/
2633
#ifdef L_setvbuf
2634
 
2635
/* Reentrant. */
2636
 
2637
int setvbuf(register FILE * __restrict stream, register char * __restrict buf,
2638
                        int mode, size_t size)
2639
{
2640
#ifdef __STDIO_BUFFERS
2641
 
2642
        int allocated_buf_flag;
2643
        int rv = EOF;
2644
 
2645
        __STDIO_THREADLOCK(stream);
2646
 
2647
        __stdio_validate_FILE(stream); /* debugging only */
2648
 
2649
        if (((unsigned int) mode) > 2) { /* Illegal mode. */
2650
                /* TODO -- set an errno? */
2651
                goto DONE;
2652
        }
2653
 
2654
#ifdef __STDIO_FLEXIBLE_SETVBUF
2655
        /* C89 standard requires no ops before setvbuf, but we can be flexible. */
2656
        /* NOTE: This will trash any chars ungetc'd!!! */
2657
        /* TODO: hmm could preserve unget count since ungot slots aren't changed (true?)
2658
         * but this will fail when buffered chars read from a pipe unless the user buf
2659
         * is big enough to copy everything over. */
2660
        if (fseek(stream, 0L, SEEK_CUR)) {
2661
                goto DONE;
2662
        }
2663
#else  /* __STDIO_FLEXIBLE_SETVBUF */
2664
        /*
2665
         * Note: ANSI/ISO requires setvbuf to be called after opening the file
2666
         * but before any other operation other than a failed setvbuf call.
2667
         * We'll cheat here and only test if the wide or narrow mode flag has
2668
         * been set; i.e. no read or write (or unget or fwide) operations have
2669
         * taken place.
2670
         */
2671
#ifdef __STDIO_WIDE
2672
        if (stream->modeflags & (__FLAG_WIDE|__FLAG_NARROW)) {
2673
                goto DONE;
2674
        }
2675
#else  /* __STDIO_WIDE */
2676
        /* Note: This only checks if not currently reading or writing. */
2677
        if (stream->modeflags & (__FLAG_READING|__FLAG_WRITING)) {
2678
                goto DONE;
2679
        }
2680
#endif /* __STDIO_WIDE */
2681
#endif /* __STDIO_FLEXIBLE_SETVBUF */
2682
 
2683
        if (mode == _IONBF) {
2684
                size = 0;
2685
                buf = NULL;
2686
        } else if (!buf && !size) {
2687
                /* If buf==NULL && size==0 && either _IOFBF or _IOLBF, keep
2688
                 * current buffer and only set buffering mode. */
2689
                size = stream->bufend - stream->bufstart;
2690
        }
2691
 
2692
        stream->modeflags &= ~(__MASK_BUFMODE); /* Clear current mode */
2693
        stream->modeflags |= mode * __FLAG_LBF; /* and set new one. */
2694
 
2695
        allocated_buf_flag = 0;
2696
        if ((!buf) && (size != (stream->bufend - stream->bufstart))) {
2697
                /* No buffer supplied and requested size different from current. */
2698
                /* If size == 0, create a (hopefully) bogus non-null pointer... */
2699
                if (!(buf = ((size > 0)
2700
                                         ? ((allocated_buf_flag = __FLAG_FREEBUF), malloc(size))
2701
                                         : ((char *)NULL) + 1))
2702
                        ) {
2703
                        /* TODO -- should we really keep current buffer if it was passed
2704
                         * to us earlier by the app? */
2705
                        goto DONE;              /* Keep current buffer. */
2706
                }
2707
        }
2708
 
2709
        /* TODO: setvbuf "signal" safety */
2710
        if (buf && (buf != (char *) stream->bufstart)) { /* Want new buffer. */
2711
                if (stream->modeflags & __FLAG_FREEBUF) {
2712
                        stream->modeflags &= ~(__FLAG_FREEBUF);
2713
                        free(stream->bufstart);
2714
                }
2715
                stream->modeflags |= allocated_buf_flag;        /* Free-able buffer? */
2716
#ifdef __STDIO_GETC_MACRO
2717
                stream->bufgetc =
2718
#endif
2719
#ifdef __STDIO_PUTC_MACRO
2720
                stream->bufputc =
2721
#endif
2722
                stream->bufpos = stream->bufread = stream->bufstart = buf;
2723
                stream->bufend = buf + size;
2724
        }
2725
 
2726
        __stdio_validate_FILE(stream); /* debugging only */
2727
 
2728
        rv = 0;
2729
 
2730
 DONE:
2731
        __STDIO_THREADUNLOCK(stream);
2732
 
2733
        return rv;
2734
 
2735
#else  /* __STDIO_BUFFERS */
2736
        __stdio_validate_FILE(stream); /* debugging only */
2737
        /* TODO -- set errno for illegal mode? */
2738
 
2739
        return EOF;
2740
#endif /* __STDIO_BUFFERS */
2741
}
2742
 
2743
#endif
2744
/**********************************************************************
2745
int fprintf(FILE * __restrict stream, const char * __restrict format, ...);
2746
int fscanf(FILE * __restrict stream, const char * __restrict format, ...);
2747
int printf(const char * __restrict format, ...);
2748
int scanf(const char * __restrict format, ...);
2749
int snprintf(char * __restrict s, size_t n,
2750
                                        const char * __restrict format, ...);
2751
int sprintf(char * __restrict s, const char * __restrict format, ...);
2752
int sscanf(char * __restrict s, const char * __restrict format, ...);
2753
int vfprintf(FILE * __restrict stream, const char * __restrict format,
2754
                                        va_list arg);
2755
int vfscanf(FILE * __restrict stream, const char * __restrict format,
2756
                                   va_list arg);
2757
int vprintf(const char * __restrict format, va_list arg);
2758
int vscanf(const char * __restrict format, va_list arg);
2759
int vsnprintf(char * __restrict s, size_t n,
2760
                                         const char * __restrict format, va_list arg);
2761
int vsprintf(char * __restrict s, const char * __restrict format,
2762
                                        va_list arg);
2763
int vsscanf(char * __restrict s, const char * __restrict format,
2764
                                   va_list arg);
2765
**********************************************************************/
2766
#ifdef L_fgetc
2767
 
2768
/* Reentrancy handled by UNLOCKED() macro. */
2769
 
2770
UNLOCKED(int,fgetc,(FILE *stream),(stream))
2771
{
2772
        unsigned char buf[1];
2773
 
2774
#ifdef __STDIO_WIDE
2775
 
2776
        return (fread_unlocked(buf, (size_t) 1, (size_t) 1, stream) > 0)
2777
                ? *buf : EOF;
2778
 
2779
#else  /* __STDIO_WIDE */
2780
 
2781
        return (_stdio_fread(buf, (size_t) 1, stream) > 0) ? *buf : EOF;
2782
 
2783
#endif /* __STDIO_WIDE */
2784
}
2785
 
2786
#endif
2787
/**********************************************************************/
2788
#ifdef L_fgets
2789
 
2790
/* Reentrancy handled by UNLOCKED() macro. */
2791
 
2792
UNLOCKED(char *,fgets,
2793
                 (char *__restrict s, int n, register FILE * __restrict stream),
2794
                 (s, n, stream))
2795
{
2796
        register char *p;
2797
        int c;
2798
 
2799
#ifdef __UCLIBC_MJN3_ONLY__
2800
#warning CONSIDER: What should fgets do if n <= 0?
2801
#endif /* __UCLIBC_MJN3_ONLY__ */
2802
        /* Should we assert here?  Or set errno?  Or just fail... */
2803
        if (n <= 0) {
2804
/*              __set_errno(EINVAL); */
2805
                goto ERROR;
2806
        }
2807
 
2808
        p = s;
2809
 
2810
        while (--n) {
2811
                if ((c = (getc_unlocked)(stream)) == EOF) {     /* Disable the macro. */
2812
                        if (__FERROR(stream)) {
2813
                                goto ERROR;
2814
                        }
2815
                        break;
2816
                }
2817
                if ((*p++ = c) == '\n') {
2818
                        break;
2819
                }
2820
        }
2821
 
2822
#ifdef __UCLIBC_MJN3_ONLY__
2823
#warning CONSIDER: If n==1 and not at EOF, should fgets return an empty string?
2824
#endif /* __UCLIBC_MJN3_ONLY__ */
2825
        if (p > s) {
2826
                *p = 0;
2827
                return s;
2828
        }
2829
 
2830
 ERROR:
2831
        return NULL;
2832
}
2833
 
2834
#endif
2835
/**********************************************************************/
2836
#ifdef L_fputc
2837
 
2838
/* Reentrancy handled by UNLOCKED() macro. */
2839
 
2840
UNLOCKED(int,fputc,(int c, FILE *stream),(c,stream))
2841
{
2842
        unsigned char buf[1];
2843
 
2844
        *buf = (unsigned char) c;
2845
 
2846
#ifdef __STDIO_WIDE
2847
 
2848
        return (fwrite_unlocked(buf, (size_t) 1, (size_t) 1, stream) > 0)
2849
                ? (*buf) : EOF;
2850
 
2851
#else  /* __STDIO_WIDE */
2852
 
2853
        return (_stdio_fwrite(buf, (size_t) 1, stream) > 0) ? (*buf) : EOF;
2854
 
2855
#endif /* __STDIO_WIDE */
2856
}
2857
#endif
2858
/**********************************************************************/
2859
#ifdef L_fputs
2860
 
2861
/* Reentrancy handled by UNLOCKED() macro. */
2862
 
2863
UNLOCKED(int,fputs,
2864
                 (register const char * __restrict s, FILE * __restrict stream),
2865
                 (s, stream))
2866
{
2867
        size_t n = strlen(s);
2868
 
2869
#ifdef __STDIO_WIDE
2870
 
2871
        return (fwrite_unlocked(s, (size_t) 1, n, stream) == n) ? n : EOF;
2872
 
2873
#else  /* __STDIO_WIDE */
2874
 
2875
        return (_stdio_fwrite(s, n, stream) == n) ? n : EOF;
2876
 
2877
#endif /* __STDIO_WIDE */
2878
}
2879
 
2880
#endif
2881
/**********************************************************************/
2882
#ifdef L_getc
2883
#undef getc
2884
#undef getc_unlocked
2885
 
2886
/* Reentrancy handled by UNLOCKED() macro. */
2887
 
2888
UNLOCKED(int,getc,(register FILE *stream),(stream))
2889
{
2890
        return __GETC(stream);          /* Invoke the macro. */
2891
}
2892
 
2893
#endif
2894
/**********************************************************************/
2895
#ifdef L_getchar
2896
#undef getchar                                  /* Just in case. */
2897
 
2898
/* Reentrancy handled by UNLOCKED() macro. */
2899
 
2900
UNLOCKED_STREAM(int,getchar,(void),(),stdin)
2901
{
2902
        register FILE *stream = stdin; /* This helps bcc optimize. */
2903
 
2904
        return __GETC(stream);
2905
}
2906
 
2907
#endif
2908
/**********************************************************************/
2909
#ifdef L_gets
2910
 
2911
link_warning(gets, "the 'gets' function is dangerous and should not be used.")
2912
 
2913
/* Reentrant. */
2914
 
2915
char *gets(char *s)                             /* WARNING!!! UNSAFE FUNCTION!!! */
2916
{
2917
        register FILE *stream = stdin;  /* This helps bcc optimize. */
2918
        register char *p = s;
2919
        int c;
2920
 
2921
        __STDIO_THREADLOCK(stream);
2922
 
2923
        /* Note: don't worry about performance here... this shouldn't be used!
2924
         * Therefore, force actual function call. */
2925
        while (((c = (getc_unlocked)(stream)) != EOF) && ((*p = c) != '\n')) {
2926
                ++p;
2927
        }
2928
        if ((c == EOF) || (s == p)) {
2929
                s = NULL;
2930
        } else {
2931
                *p = 0;
2932
        }
2933
 
2934
        __STDIO_THREADUNLOCK(stream);
2935
 
2936
        return s;
2937
}
2938
 
2939
#endif
2940
/**********************************************************************/
2941
#ifdef L_putc
2942
#undef putc
2943
#undef putc_unlocked
2944
 
2945
/* Reentrancy handled by UNLOCKED() macro. */
2946
 
2947
UNLOCKED(int,putc,(int c, register FILE *stream),(c,stream))
2948
{
2949
        return __PUTC(c, stream);       /* Invoke the macro. */
2950
}
2951
 
2952
#endif
2953
/**********************************************************************/
2954
#ifdef L_putchar
2955
#undef putchar                                  /* Just in case. */
2956
 
2957
/* Reentrancy handled by UNLOCKED() macro. */
2958
 
2959
UNLOCKED_STREAM(int,putchar,(int c),(c),stdout)
2960
{
2961
        register FILE *stream = stdout; /* This helps bcc optimize. */
2962
 
2963
        return __PUTC(c, stream);
2964
}
2965
 
2966
#endif
2967
/**********************************************************************/
2968
#ifdef L_puts
2969
 
2970
/* Reentrant. */
2971
 
2972
int puts(register const char *s)
2973
{
2974
        register FILE *stream = stdout; /* This helps bcc optimize. */
2975
        int n;
2976
 
2977
        __STDIO_THREADLOCK(stream);
2978
 
2979
        n = fputs_unlocked(s,stream) + 1;
2980
        if (
2981
#if 1
2982
                fputc_unlocked('\n',stream)
2983
#else
2984
                fputs_unlocked("\n",stream)
2985
#endif
2986
                == EOF) {
2987
                n = EOF;
2988
        }
2989
 
2990
        __STDIO_THREADUNLOCK(stream);
2991
 
2992
        return n;
2993
}
2994
 
2995
#endif
2996
/**********************************************************************/
2997
#ifdef L_ungetc
2998
/*
2999
 * Note: This is the application-callable ungetc.  If scanf calls this, it
3000
 * should also set stream->ungot[1] to 0 if this is the only ungot.
3001
 */
3002
 
3003
/* Reentrant. */
3004
 
3005
int ungetc(int c, register FILE *stream)
3006
{
3007
        __STDIO_THREADLOCK(stream);
3008
 
3009
        __stdio_validate_FILE(stream); /* debugging only */
3010
 
3011
#ifdef __STDIO_WIDE
3012
        if (stream->modeflags & __FLAG_WIDE) {
3013
                stream->modeflags |= __FLAG_ERROR;
3014
                c = EOF;
3015
                goto DONE;
3016
        }
3017
        stream->modeflags |= __FLAG_NARROW;
3018
#endif /* __STDIO_WIDE */
3019
 
3020
        /* If can't read or c == EOF or ungot slots already filled, then fail. */
3021
        if ((stream->modeflags
3022
                 & (__MASK_UNGOT2|__FLAG_WRITEONLY
3023
#ifndef __STDIO_AUTO_RW_TRANSITION
3024
                        |__FLAG_WRITING         /* Note: technically no, but yes in spirit */
3025
#endif /* __STDIO_AUTO_RW_TRANSITION */
3026
                        ))
3027
                || ((stream->modeflags & __MASK_UNGOT1) && (stream->ungot[1]))
3028
                || (c == EOF) ) {
3029
                c = EOF;
3030
                goto DONE;;
3031
        }
3032
 
3033
#ifdef __STDIO_BUFFERS
3034
#ifdef __STDIO_AUTO_RW_TRANSITION
3035
        if (stream->modeflags & __FLAG_WRITING) {
3036
                fflush_unlocked(stream); /* Commit any write-buffered chars. */
3037
        }
3038
#endif /* __STDIO_AUTO_RW_TRANSITION */
3039
#endif /* __STDIO_BUFFERS */
3040
 
3041
        /* Clear EOF and WRITING flags, and set READING FLAG */
3042
        stream->modeflags &= ~(__FLAG_EOF|__FLAG_WRITING);
3043
#ifdef __UCLIBC_MJN3_ONLY__
3044
#warning CONSIDER: Is setting the reading flag after an ungetc necessary?
3045
#endif /* __UCLIBC_MJN3_ONLY__ */
3046
        stream->modeflags |= __FLAG_READING;
3047
        stream->ungot[1] = 1;           /* Flag as app ungetc call; scanf fixes up. */
3048
        stream->ungot[(stream->modeflags++) & __MASK_UNGOT] = c;
3049
 
3050
#ifdef __STDIO_GETC_MACRO
3051
        stream->bufgetc = stream->bufstart;     /* Must disable getc macro. */
3052
#endif
3053
 
3054
        __stdio_validate_FILE(stream); /* debugging only */
3055
 
3056
 DONE:
3057
        __STDIO_THREADUNLOCK(stream);
3058
 
3059
        return c;
3060
}
3061
 
3062
#endif
3063
/**********************************************************************/
3064
#ifdef L_fread
3065
/* NOTE: Surely ptr cannot point to a buffer of size > SIZE_MAX.
3066
 * Therefore, we treat the case size * nmemb > SIZE_MAX as an error,
3067
 * and include an assert() for it. */
3068
 
3069
/* Reentrancy handled by UNLOCKED() macro. */
3070
 
3071
UNLOCKED(size_t,fread,
3072
                 (void * __restrict ptr, size_t size, size_t nmemb,
3073
                  FILE * __restrict stream),
3074
                 (ptr,size,nmemb,stream))
3075
{
3076
#ifdef __STDIO_WIDE
3077
        if (stream->modeflags & __FLAG_WIDE) {
3078
                stream->modeflags |= __FLAG_ERROR;
3079
                /* TODO -- errno?  it this correct? */
3080
                return 0;
3081
        }
3082
        stream->modeflags |= __FLAG_NARROW;
3083
#endif /* __STDIO_WIDE */
3084
 
3085
        return (size == 0)
3086
                ? 0
3087
                : (     assert( ((size_t)(-1)) / size >= nmemb ),
3088
                        _stdio_fread(ptr, nmemb * size, stream) / size );
3089
}
3090
 
3091
#endif
3092
/**********************************************************************/
3093
#ifdef L_fwrite
3094
/* NOTE: Surely ptr cannot point to a buffer of size > SIZE_MAX.
3095
 * Therefore, we treat the case size * nmemb > SIZE_MAX as an error,
3096
 * and include an assert() for it. */
3097
 
3098
/* Reentrancy handled by UNLOCKED() macro. */
3099
 
3100
UNLOCKED(size_t,fwrite,
3101
                 (const void * __restrict ptr, size_t size, size_t nmemb,
3102
                  FILE * __restrict stream),
3103
                 (ptr,size,nmemb,stream))
3104
{
3105
#ifdef __STDIO_WIDE
3106
        if (stream->modeflags & __FLAG_WIDE) {
3107
                stream->modeflags |= __FLAG_ERROR;
3108
                /* TODO -- errno?  it this correct? */
3109
                return 0;
3110
        }
3111
        stream->modeflags |= __FLAG_NARROW;
3112
#endif /* __STDIO_WIDE */
3113
 
3114
        return (size == 0)
3115
                ? 0
3116
                : (     assert( ((size_t)(-1)) / size >= nmemb ),
3117
                        _stdio_fwrite(ptr, nmemb * size, stream) / size );
3118
}
3119
 
3120
#endif
3121
/**********************************************************************/
3122
#if defined(L_fgetpos) || defined(L_fgetpos64)
3123
 
3124
/* Reentrant -- fgetpos() and fgetpos64(). */
3125
 
3126
#if defined(L_fgetpos) && defined(L_fgetpos64)
3127
#error L_fgetpos and L_fgetpos64 are defined simultaneously!
3128
#endif
3129
 
3130
#ifndef L_fgetpos64
3131
#define fgetpos64       fgetpos
3132
#define fpos64_t        fpos_t
3133
#define ftello64        ftell
3134
#endif
3135
 
3136
 
3137
int fgetpos64(FILE * __restrict stream, register fpos64_t * __restrict pos)
3138
{
3139
        int retval = -1;
3140
 
3141
#ifdef __STDIO_WIDE
3142
 
3143
        if (pos == NULL) {
3144
                __set_errno(EINVAL);
3145
        } else {
3146
                __STDIO_THREADLOCK(stream);
3147
 
3148
                if ((pos->__pos = ftello64(stream)) >= 0) {
3149
                        __COPY_MBSTATE(&(pos->__mbstate), &(stream->state));
3150
                        pos->mblen_pending = stream->ungot_width[0];
3151
                        retval = 0;
3152
                }
3153
 
3154
                __STDIO_THREADUNLOCK(stream);
3155
        }
3156
 
3157
#else  /* __STDIO_WIDE */
3158
 
3159
        if (pos == NULL) {
3160
                __set_errno(EINVAL);
3161
        } else if ((pos->__pos = ftello64(stream)) >= 0) {
3162
                retval = 0;
3163
        }
3164
 
3165
#endif /* __STDIO_WIDE */
3166
 
3167
        return retval;
3168
}
3169
 
3170
#ifndef L_fgetpos64
3171
#undef fgetpos64
3172
#undef fpos64_t
3173
#undef ftello64
3174
#endif
3175
 
3176
#endif
3177
/**********************************************************************/
3178
#ifdef L_fseek
3179
strong_alias(fseek,fseeko);
3180
#endif
3181
 
3182
#if defined(L_fseek) && defined(__STDIO_LARGE_FILES)
3183
 
3184
int fseek(register FILE *stream, long int offset, int whence)
3185
{
3186
        return fseeko64(stream, offset, whence);
3187
}
3188
 
3189
#endif
3190
 
3191
#if defined(L_fseeko64) || (defined(L_fseek) && !defined(__STDIO_LARGE_FILES))
3192
 
3193
#ifndef L_fseeko64
3194
#define fseeko64        fseek
3195
#define __off64_t       long int
3196
#endif
3197
 
3198
/* Reentrant -- fseek(), fseeko(), fseeko64() */
3199
 
3200
int fseeko64(register FILE *stream, __off64_t offset, int whence)
3201
{
3202
#if SEEK_SET != 0 || SEEK_CUR != 1 || SEEK_END != 2
3203
#error Assumption violated -- values of SEEK_SET, SEEK_CUR, SEEK_END
3204
#endif
3205
        __offmax_t pos[1];
3206
        int retval;
3207
 
3208
        if ( ((unsigned int) whence) > 2 ) {
3209
                __set_errno(EINVAL);
3210
                return -1;
3211
        }
3212
 
3213
        __STDIO_THREADLOCK(stream);
3214
 
3215
        __stdio_validate_FILE(stream); /* debugging only */
3216
 
3217
        retval = -1;
3218
        *pos = offset;
3219
        if (
3220
#ifdef __STDIO_BUFFERS
3221
                /* First commit any pending buffered writes. */
3222
                ((stream->modeflags & __FLAG_WRITING) && fflush_unlocked(stream)) ||
3223
#endif /* __STDIO_BUFFERS */
3224
                ((whence == SEEK_CUR) && (_stdio_adjpos(stream, pos) < 0))
3225
                || (_stdio_lseek(stream, pos, whence) < 0)
3226
                ) {
3227
                __stdio_validate_FILE(stream); /* debugging only */
3228
                goto DONE;
3229
        }
3230
 
3231
#ifdef __STDIO_BUFFERS
3232
        /* only needed if reading but do it anyway to avoid test */
3233
#ifdef __STDIO_GETC_MACRO
3234
        stream->bufgetc =                       /* Must disable getc. */
3235
#endif
3236
        stream->bufpos = stream->bufread = stream->bufstart;
3237
#endif /* __STDIO_BUFFERS */
3238
 
3239
        stream->modeflags &=
3240
                ~(__FLAG_READING|__FLAG_WRITING|__FLAG_EOF|__MASK_UNGOT);
3241
 
3242
#ifdef __UCLIBC_MJN3_ONLY__
3243
#warning CONSIDER: How do we deal with fseek to an ftell position for incomplete or error wide?  Right now, we clear all multibyte state info.  If we do not clear, then fix rewind() to do so if fseek() succeeds.
3244
#endif /* __UCLIBC_MJN3_ONLY__ */
3245
 
3246
#ifdef __STDIO_WIDE
3247
        /* TODO: don't clear state if don't move? */
3248
        stream->ungot_width[0] = 0;
3249
#endif /* __STDIO_WIDE */
3250
#ifdef __STDIO_MBSTATE
3251
        /* TODO: don't clear state if don't move? */
3252
        __INIT_MBSTATE(&(stream->state));
3253
#endif /* __STDIO_MBSTATE */
3254
 
3255
        __stdio_validate_FILE(stream); /* debugging only */
3256
 
3257
        retval = 0;
3258
 
3259
 DONE:
3260
        __STDIO_THREADUNLOCK(stream);
3261
 
3262
        return retval;
3263
}
3264
 
3265
#ifndef L_fseeko64
3266
#undef fseeko64
3267
#undef __off64_t
3268
#endif
3269
 
3270
#endif
3271
/**********************************************************************/
3272
#if defined(L_fsetpos) || defined(L_fsetpos64)
3273
 
3274
#if defined(L_fsetpos) && defined(L_fsetpos64)
3275
#error L_fsetpos and L_fsetpos64 are defined simultaneously!
3276
#endif
3277
 
3278
#ifndef L_fsetpos64
3279
#define fsetpos64       fsetpos
3280
#define fpos64_t        fpos_t
3281
#define fseeko64        fseek
3282
#endif
3283
 
3284
/* Reentrant -- fgetpos{64}() through fseek{64}(). */
3285
 
3286
int fsetpos64(FILE *stream, register const fpos64_t *pos)
3287
{
3288
        if (!pos) {
3289
                __set_errno(EINVAL);
3290
                return EOF;
3291
        }
3292
#ifdef __STDIO_WIDE
3293
        {
3294
                int retval;
3295
 
3296
                __STDIO_THREADLOCK(stream);
3297
 
3298
                if ((retval = fseeko64(stream, pos->__pos, SEEK_SET)) == 0) {
3299
                        __COPY_MBSTATE(&(stream->state), &(pos->__mbstate));
3300
#ifdef __UCLIBC_MJN3_ONLY__
3301
#warning CONSIDER: Moving mblen_pending into some mbstate field might be useful.  But we would need to modify all the mb<->wc funcs.
3302
#endif /* __UCLIBC_MJN3_ONLY__ */
3303
                        stream->ungot_width[0] = pos->mblen_pending;
3304
                }
3305
 
3306
                __STDIO_THREADUNLOCK(stream);
3307
 
3308
                return retval;
3309
        }
3310
#else  /* __STDIO_WIDE */
3311
        return fseeko64(stream, pos->__pos, SEEK_SET);
3312
#endif /* __STDIO_WIDE */
3313
}
3314
 
3315
#ifndef L_fsetpos64
3316
#undef fsetpos64
3317
#undef fpos64_t
3318
#undef fseeko64
3319
#endif
3320
 
3321
#endif
3322
/**********************************************************************/
3323
#ifdef L_ftell
3324
strong_alias(ftell,ftello);
3325
#endif
3326
 
3327
#if defined(L_ftell) && defined(__STDIO_LARGE_FILES)
3328
long int ftell(register FILE *stream)
3329
{
3330
        __offmax_t pos = ftello64(stream);
3331
 
3332
        return (pos == ((long int) pos)) ? pos : (__set_errno(EOVERFLOW), -1);
3333
}
3334
#endif
3335
 
3336
#if defined(L_ftello64) || (defined(L_ftell) && !defined(__STDIO_LARGE_FILES))
3337
 
3338
#ifndef L_ftello64
3339
#define ftello64        ftell
3340
#define __off64_t       long int
3341
#endif
3342
 
3343
/* Reentrant -- ftell, ftello, ftello64. */
3344
 
3345
__off64_t ftello64(register FILE *stream)
3346
{
3347
        __offmax_t pos[1];
3348
        __off64_t retval;
3349
 
3350
        __STDIO_THREADLOCK(stream);
3351
 
3352
        retval = (((*pos = 0), (_stdio_lseek(stream, pos, SEEK_CUR) < 0))
3353
                          || (_stdio_adjpos(stream, pos) < 0)) ? -1 : *pos;
3354
 
3355
        __STDIO_THREADUNLOCK(stream);
3356
 
3357
        return retval;
3358
}
3359
 
3360
#ifndef L_ftello64
3361
#undef ftello64
3362
#undef __off64_t
3363
#endif
3364
 
3365
#endif
3366
/**********************************************************************/
3367
#ifdef L_rewind
3368
 
3369
void rewind(register FILE *stream)
3370
{
3371
        __STDIO_THREADLOCK(stream);
3372
 
3373
        __CLEARERR(stream);                     /* Clear errors first and then seek */
3374
        fseek(stream, 0L, SEEK_SET); /* in case there is an error seeking. */
3375
 
3376
        __STDIO_THREADUNLOCK(stream);
3377
}
3378
 
3379
#endif
3380
/**********************************************************************/
3381
#ifdef L_clearerr
3382
#undef clearerr
3383
 
3384
/* Reentrancy handled by UNLOCKED_VOID_RETURN() macro. */
3385
 
3386
UNLOCKED_VOID_RETURN(clearerr,(FILE *stream),(stream))
3387
{
3388
        __CLEARERR(stream);
3389
}
3390
 
3391
#endif
3392
/**********************************************************************/
3393
#ifdef L_feof
3394
#undef feof
3395
 
3396
/* Reentrancy handled by UNLOCKED() macro. */
3397
 
3398
UNLOCKED(int,feof,(FILE *stream),(stream))
3399
{
3400
        return __FEOF(stream);
3401
}
3402
 
3403
#endif
3404
/**********************************************************************/
3405
#ifdef L_ferror
3406
#undef ferror
3407
 
3408
/* Reentrancy handled by UNLOCKED() macro. */
3409
 
3410
UNLOCKED(int,ferror,(FILE *stream),(stream))
3411
{
3412
        return __FERROR(stream);
3413
}
3414
 
3415
#endif
3416
/**********************************************************************/
3417
#ifdef L_perror
3418
 
3419
void perror(register const char *s)
3420
{
3421
        /* If the program is calling perror, it's a safe bet that printf and
3422
         * friends are used as well.  It is also possible that the calling
3423
         * program could buffer stderr, or reassign it. */
3424
 
3425
        register const char *sep;
3426
 
3427
        sep = ": ";
3428
        if (!(s && *s)) {                       /* Caller did not supply a prefix message */
3429
                s = (sep += 2);                 /* or passed an empty string. */
3430
        }
3431
 
3432
#if 1
3433
#ifdef __STDIO_PRINTF_M_SPEC
3434
        fprintf(stderr, "%s%s%m\n", s, sep); /* Use the gnu %m feature. */
3435
#else
3436
        {
3437
                char buf[64];
3438
                fprintf(stderr, "%s%s%s\n", s, sep,
3439
                                _glibc_strerror_r(errno, buf, sizeof(buf)));
3440
        }
3441
#endif
3442
#else
3443
        /* Note: Assumes stderr not closed or buffered. */
3444
        {
3445
                char buf[64];
3446
 
3447
                __STDIO_THREADLOCK(stderr);
3448
                _stdio_fdout(STDERR_FILENO, s, sep,
3449
                                         _glibc_strerror_r(errno, buf, sizeof(buf)));
3450
                __STDIO_THREADUNLOCK(stderr);
3451
        }
3452
#endif
3453
}
3454
 
3455
#endif
3456
/**********************************************************************/
3457
/* UTILITY funcs */
3458
/**********************************************************************/
3459
#ifdef L__stdio_fdout
3460
 
3461
/* Not reentrant -- TODO: lock associated stream if a know file descriptor? */
3462
 
3463
void _stdio_fdout(int fd, ...)
3464
{
3465
        va_list arg;
3466
        register const char *p;
3467
 
3468
        va_start(arg, fd);
3469
        while ((p = va_arg(arg, const char *)) != NULL) {
3470
                write(fd, p, strlen(p));
3471
        }
3472
        va_end(arg);
3473
}
3474
 
3475
#endif
3476
/**********************************************************************/
3477
#ifdef L__uintmaxtostr
3478
 
3479
/* Avoid using long long / and % operations to cut down dependencies on
3480
 * libgcc.a.  Definitely helps on i386 at least. */
3481
#if (INTMAX_MAX > INT_MAX) && (((INTMAX_MAX/INT_MAX)/2) - 2 <= INT_MAX)
3482
#define INTERNAL_DIV_MOD
3483
#endif
3484
 
3485
#include <locale.h>
3486
 
3487
char *_uintmaxtostr(register char * __restrict bufend, uintmax_t uval,
3488
                                        int base, __UIM_CASE alphacase)
3489
{
3490
    int negative;
3491
    unsigned int digit;
3492
#ifdef INTERNAL_DIV_MOD
3493
        unsigned int H, L, high, low, rh;
3494
#endif
3495
#ifndef __LOCALE_C_ONLY
3496
        int grouping, outdigit;
3497
        const char *g;             /* This does not need to be initialized. */
3498
#endif /* __LOCALE_C_ONLY */
3499
 
3500
        negative = 0;
3501
        if (base < 0) {                          /* signed value */
3502
                base = -base;
3503
                if (uval > INTMAX_MAX) {
3504
                        uval = -uval;
3505
                        negative = 1;
3506
                }
3507
        }
3508
 
3509
        /* this is an internal routine -- we shouldn't need to check this */
3510
        assert(!((base < 2) || (base > 36)));
3511
 
3512
#ifndef __LOCALE_C_ONLY
3513
        grouping = -1;
3514
        outdigit = 0x80 & alphacase;
3515
        alphacase ^= outdigit;
3516
        if (alphacase == __UIM_GROUP) {
3517
                assert(base == 10);
3518
                if (*(g = __UCLIBC_CURLOCALE_DATA.grouping)) {
3519
                        grouping = *g;
3520
                }
3521
        }
3522
#endif /* __LOCALE_C_ONLY */
3523
 
3524
    *bufend = '\0';
3525
 
3526
#ifndef INTERNAL_DIV_MOD
3527
    do {
3528
#ifndef __LOCALE_C_ONLY
3529
                if (!grouping) {                /* Finished a group. */
3530
                        bufend -= __UCLIBC_CURLOCALE_DATA.thousands_sep_len;
3531
                        memcpy(bufend, __UCLIBC_CURLOCALE_DATA.thousands_sep,
3532
                                   __UCLIBC_CURLOCALE_DATA.thousands_sep_len);
3533
                        if (g[1] != 0) {         /* g[1] == 0 means repeat last grouping. */
3534
                                /* Note: g[1] == -1 means no further grouping.  But since
3535
                                 * we'll never wrap around, we can set grouping to -1 without
3536
                                 * fear of */
3537
                                ++g;
3538
                        }
3539
                        grouping = *g;
3540
                }
3541
                --grouping;
3542
#endif /* __LOCALE_C_ONLY */
3543
                digit = uval % base;
3544
                uval /= base;
3545
 
3546
#ifndef __LOCALE_C_ONLY
3547
                if (unlikely(outdigit)) {
3548
                        bufend -= __UCLIBC_CURLOCALE_DATA.outdigit_length[digit];
3549
                        memcpy(bufend,
3550
                                   (&__UCLIBC_CURLOCALE_DATA.outdigit0_mb)[digit],
3551
                                   __UCLIBC_CURLOCALE_DATA.outdigit_length[digit]);
3552
                } else
3553
#endif
3554
                {
3555
                        *--bufend = ( (digit < 10) ? digit + '0' : digit + alphacase );
3556
                }
3557
    } while (uval);
3558
 
3559
#else  /* ************************************************** */
3560
 
3561
        H = (UINT_MAX / base);
3562
        L = UINT_MAX % base + 1;
3563
        if (L == base) {
3564
                ++H;
3565
                L = 0;
3566
        }
3567
        low = (unsigned int) uval;
3568
        high = (unsigned int) (uval >> (sizeof(unsigned int) * CHAR_BIT));
3569
 
3570
    do {
3571
#ifndef __LOCALE_C_ONLY
3572
                if (!grouping) {                /* Finished a group. */
3573
                        bufend -= __UCLIBC_CURLOCALE_DATA.thousands_sep_len;
3574
                        memcpy(bufend, __UCLIBC_CURLOCALE_DATA.thousands_sep,
3575
                                   __UCLIBC_CURLOCALE_DATA.thousands_sep_len);
3576
                        if (g[1] != 0) {         /* g[1] == 0 means repeat last grouping. */
3577
                                /* Note: g[1] == -1 means no further grouping.  But since
3578
                                 * we'll never wrap around, we can set grouping to -1 without
3579
                                 * fear of */
3580
                                ++g;
3581
                        }
3582
                        grouping = *g;
3583
                }
3584
                --grouping;
3585
#endif /* __LOCALE_C_ONLY */
3586
 
3587
                if (unlikely(high)) {
3588
                        rh = high % base;
3589
                        high /= base;
3590
                        digit = (low % base) + (L * rh);
3591
                        low = (low / base) + (H * rh) + (digit / base);
3592
                        digit %= base;
3593
                } else {
3594
                        digit = low % base;
3595
                        low /= base;
3596
                }
3597
 
3598
#ifndef __LOCALE_C_ONLY
3599
                if (unlikely(outdigit)) {
3600
                        bufend -= __UCLIBC_CURLOCALE_DATA.outdigit_length[digit];
3601
                        memcpy(bufend,
3602
                                   (&__UCLIBC_CURLOCALE_DATA.outdigit0_mb)[digit],
3603
                                   __UCLIBC_CURLOCALE_DATA.outdigit_length[digit]);
3604
                } else
3605
#endif
3606
                {
3607
                        *--bufend = ( (digit < 10) ? digit + '0' : digit + alphacase );
3608
                }
3609
    } while (low | high);
3610
 
3611
#endif /******************************************************/
3612
 
3613
    if (negative) {
3614
                *--bufend = '-';
3615
    }
3616
 
3617
    return bufend;
3618
}
3619
#undef INTERNAL_DIV_MOD
3620
 
3621
#endif
3622
/**********************************************************************/
3623
#ifdef L__wstdio_fwrite
3624
 
3625
#include <wchar.h>
3626
 
3627
size_t _wstdio_fwrite(const wchar_t *__restrict ws, size_t n,
3628
                                          register FILE *__restrict stream)
3629
{
3630
        size_t r, count;
3631
        char buf[64];
3632
        const wchar_t *pw;
3633
 
3634
#if defined(__STDIO_WIDE) && defined(__STDIO_BUFFERS)
3635
        if (stream->filedes == -3) { /* Special case to support {v}swprintf. */
3636
                count = ((wchar_t *)(stream->bufend)) - ((wchar_t *)(stream->bufpos));
3637
                if (count > n) {
3638
                        count = n;
3639
                }
3640
                if (count) {
3641
                        wmemcpy((wchar_t *)(stream->bufpos), ws, count);
3642
                        stream->bufpos = (char *)(((wchar_t *)(stream->bufpos)) + count);
3643
                }
3644
                return n;
3645
        }
3646
#endif /* defined(__STDIO_WIDE) && defined(__STDIO_BUFFERS) */
3647
 
3648
        if (stream->modeflags & __FLAG_NARROW) {
3649
                stream->modeflags |= __FLAG_ERROR;
3650
                __set_errno(EBADF);
3651
                return 0;
3652
        }
3653
        stream->modeflags |= __FLAG_WIDE;
3654
 
3655
        pw = ws;
3656
        count = 0;
3657
        while (n > count) {
3658
                r = wcsnrtombs(buf, &pw, n-count, sizeof(buf), &stream->state);
3659
                if (r != ((size_t) -1)) { /* No encoding errors */
3660
                        if (!r) {
3661
                                ++r;              /* 0 is returned when nul is reached. */
3662
                                pw = ws + count + r; /* pw was set to NULL, so correct. */
3663
                        }
3664
                        if (_stdio_fwrite(buf, r, stream) == r) {
3665
                                count = pw - ws;
3666
                                continue;
3667
                        }
3668
                }
3669
                break;
3670
        }
3671
 
3672
        /* Note: The count is incorrect if 0 < _stdio_fwrite return < r!!! */
3673
        return count;
3674
}
3675
 
3676
#endif
3677
/**********************************************************************/

powered by: WebSVN 2.1.0

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