summaryrefslogtreecommitdiff
path: root/libc/stdio/fputc.c
blob: 4cc396e08ee8597d389c771f46cc9828eba46141 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/* Copyright (C) 2004       Manuel Novoa III    <mjn3@codepoet.org>
 *
 * GNU Library General Public License (LGPL) version 2 or later.
 *
 * Dedicated to Toni.  See uClibc/DEDICATION.mjn3 for details.
 */

#include "_stdio.h"

#undef fputc
#undef fputc_unlocked
#undef putc
#undef putc_unlocked

#ifdef __DO_UNLOCKED

int attribute_hidden __fputc_unlocked_internal(int c, register FILE *stream)
{
	__STDIO_STREAM_VALIDATE(stream);

	/* First the fast path.  We're good to go if putc macro enabled. */
	if (__STDIO_STREAM_CAN_USE_BUFFER_ADD(stream)) {
		__STDIO_STREAM_BUFFER_ADD(stream, ((unsigned char) c));
		return (unsigned char) c;
	}

	/* Next quickest... writing and narrow oriented, but macro
	 * disabled and/or buffer is full. */
	if (__STDIO_STREAM_IS_NARROW_WRITING(stream)
		|| !__STDIO_STREAM_TRANS_TO_WRITE(stream, __FLAG_NARROW)
		) {
		if (__STDIO_STREAM_IS_FAKE_VSNPRINTF(stream)) {
			return (unsigned char) c;
		}

		if (__STDIO_STREAM_BUFFER_SIZE(stream)) { /* Do we have a buffer? */
			/* The buffer is full and/or the stream is line buffered. */
			if (!__STDIO_STREAM_BUFFER_WAVAIL(stream) /* Buffer full? */
				&& __STDIO_COMMIT_WRITE_BUFFER(stream) /* Commit failed! */
				) {
				goto BAD;
			}
#ifdef __UCLIBC_MJN3_ONLY__
#warning CONSIDER: Should we fail if the commit fails but we now have room?
#endif

			__STDIO_STREAM_BUFFER_ADD(stream, ((unsigned char) c));

			if (__STDIO_STREAM_IS_LBF(stream)) {
				if ((((unsigned char) c) == '\n')
					&& __STDIO_COMMIT_WRITE_BUFFER(stream)) {
					/* Commit failed! */
					__STDIO_STREAM_BUFFER_UNADD(stream); /* Undo the write! */
					goto BAD;
				}
			}
		} else {
			/* NOTE: Do not try to save space by moving uc to the top of
			 * the file, as that dramaticly increases runtime. */
			unsigned char uc = (unsigned char) c;
			if (! __stdio_WRITE(stream, &uc, 1)) {
				goto BAD;
			}
		}
		return (unsigned char) c;
	}

 BAD:
	return EOF;
}

strong_alias(__fputc_unlocked_internal,__fputc_unlocked)
weak_alias(__fputc_unlocked_internal,fputc_unlocked)
weak_alias(__fputc_unlocked_internal,putc_unlocked)
#ifndef __UCLIBC_HAS_THREADS__
hidden_strong_alias(__fputc_unlocked_internal,__fputc)
weak_alias(__fputc_unlocked_internal,fputc)
hidden_strong_alias(__fputc_unlocked_internal,__putc)
weak_alias(__fputc_unlocked_internal,putc)
#endif

#elif defined __UCLIBC_HAS_THREADS__

int attribute_hidden __fputc(int c, register FILE *stream)
{
	if (stream->__user_locking != 0) {
		return __PUTC_UNLOCKED_MACRO(c, stream);
	} else {
		int retval;
		__STDIO_ALWAYS_THREADLOCK(stream);
		retval = __PUTC_UNLOCKED_MACRO(c, stream);
		__STDIO_ALWAYS_THREADUNLOCK(stream);
		return retval;
	}
}
strong_alias(__fputc,fputc)
hidden_strong_alias(__fputc,__putc)
weak_alias(__fputc,putc)

#endif