xref: /aosp_15_r20/external/bc/src/file.c (revision 5a6e848804d15c18a0125914844ee4eb0bda4fcf)
1*5a6e8488SAndroid Build Coastguard Worker /*
2*5a6e8488SAndroid Build Coastguard Worker  * *****************************************************************************
3*5a6e8488SAndroid Build Coastguard Worker  *
4*5a6e8488SAndroid Build Coastguard Worker  * SPDX-License-Identifier: BSD-2-Clause
5*5a6e8488SAndroid Build Coastguard Worker  *
6*5a6e8488SAndroid Build Coastguard Worker  * Copyright (c) 2018-2024 Gavin D. Howard and contributors.
7*5a6e8488SAndroid Build Coastguard Worker  *
8*5a6e8488SAndroid Build Coastguard Worker  * Redistribution and use in source and binary forms, with or without
9*5a6e8488SAndroid Build Coastguard Worker  * modification, are permitted provided that the following conditions are met:
10*5a6e8488SAndroid Build Coastguard Worker  *
11*5a6e8488SAndroid Build Coastguard Worker  * * Redistributions of source code must retain the above copyright notice, this
12*5a6e8488SAndroid Build Coastguard Worker  *   list of conditions and the following disclaimer.
13*5a6e8488SAndroid Build Coastguard Worker  *
14*5a6e8488SAndroid Build Coastguard Worker  * * Redistributions in binary form must reproduce the above copyright notice,
15*5a6e8488SAndroid Build Coastguard Worker  *   this list of conditions and the following disclaimer in the documentation
16*5a6e8488SAndroid Build Coastguard Worker  *   and/or other materials provided with the distribution.
17*5a6e8488SAndroid Build Coastguard Worker  *
18*5a6e8488SAndroid Build Coastguard Worker  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19*5a6e8488SAndroid Build Coastguard Worker  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20*5a6e8488SAndroid Build Coastguard Worker  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21*5a6e8488SAndroid Build Coastguard Worker  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22*5a6e8488SAndroid Build Coastguard Worker  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23*5a6e8488SAndroid Build Coastguard Worker  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24*5a6e8488SAndroid Build Coastguard Worker  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25*5a6e8488SAndroid Build Coastguard Worker  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26*5a6e8488SAndroid Build Coastguard Worker  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27*5a6e8488SAndroid Build Coastguard Worker  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28*5a6e8488SAndroid Build Coastguard Worker  * POSSIBILITY OF SUCH DAMAGE.
29*5a6e8488SAndroid Build Coastguard Worker  *
30*5a6e8488SAndroid Build Coastguard Worker  * *****************************************************************************
31*5a6e8488SAndroid Build Coastguard Worker  *
32*5a6e8488SAndroid Build Coastguard Worker  * Code for implementing buffered I/O on my own terms.
33*5a6e8488SAndroid Build Coastguard Worker  *
34*5a6e8488SAndroid Build Coastguard Worker  */
35*5a6e8488SAndroid Build Coastguard Worker 
36*5a6e8488SAndroid Build Coastguard Worker #include <assert.h>
37*5a6e8488SAndroid Build Coastguard Worker #include <errno.h>
38*5a6e8488SAndroid Build Coastguard Worker #include <string.h>
39*5a6e8488SAndroid Build Coastguard Worker 
40*5a6e8488SAndroid Build Coastguard Worker #ifndef _WIN32
41*5a6e8488SAndroid Build Coastguard Worker #include <unistd.h>
42*5a6e8488SAndroid Build Coastguard Worker #endif // _WIN32
43*5a6e8488SAndroid Build Coastguard Worker 
44*5a6e8488SAndroid Build Coastguard Worker #include <file.h>
45*5a6e8488SAndroid Build Coastguard Worker #include <vm.h>
46*5a6e8488SAndroid Build Coastguard Worker 
47*5a6e8488SAndroid Build Coastguard Worker #if !BC_ENABLE_LINE_LIB
48*5a6e8488SAndroid Build Coastguard Worker 
49*5a6e8488SAndroid Build Coastguard Worker /**
50*5a6e8488SAndroid Build Coastguard Worker  * Translates an integer into a string.
51*5a6e8488SAndroid Build Coastguard Worker  * @param val  The value to translate.
52*5a6e8488SAndroid Build Coastguard Worker  * @param buf  The return parameter.
53*5a6e8488SAndroid Build Coastguard Worker  */
54*5a6e8488SAndroid Build Coastguard Worker static void
bc_file_ultoa(unsigned long long val,char buf[BC_FILE_ULL_LENGTH])55*5a6e8488SAndroid Build Coastguard Worker bc_file_ultoa(unsigned long long val, char buf[BC_FILE_ULL_LENGTH])
56*5a6e8488SAndroid Build Coastguard Worker {
57*5a6e8488SAndroid Build Coastguard Worker 	char buf2[BC_FILE_ULL_LENGTH];
58*5a6e8488SAndroid Build Coastguard Worker 	size_t i, len;
59*5a6e8488SAndroid Build Coastguard Worker 
60*5a6e8488SAndroid Build Coastguard Worker 	// We need to make sure the entire thing is zeroed.
61*5a6e8488SAndroid Build Coastguard Worker 	// NOLINTNEXTLINE
62*5a6e8488SAndroid Build Coastguard Worker 	memset(buf2, 0, BC_FILE_ULL_LENGTH);
63*5a6e8488SAndroid Build Coastguard Worker 
64*5a6e8488SAndroid Build Coastguard Worker 	// The i = 1 is to ensure that there is a null byte at the end.
65*5a6e8488SAndroid Build Coastguard Worker 	for (i = 1; val; ++i)
66*5a6e8488SAndroid Build Coastguard Worker 	{
67*5a6e8488SAndroid Build Coastguard Worker 		unsigned long long mod = val % 10;
68*5a6e8488SAndroid Build Coastguard Worker 
69*5a6e8488SAndroid Build Coastguard Worker 		buf2[i] = ((char) mod) + '0';
70*5a6e8488SAndroid Build Coastguard Worker 		val /= 10;
71*5a6e8488SAndroid Build Coastguard Worker 	}
72*5a6e8488SAndroid Build Coastguard Worker 
73*5a6e8488SAndroid Build Coastguard Worker 	len = i;
74*5a6e8488SAndroid Build Coastguard Worker 
75*5a6e8488SAndroid Build Coastguard Worker 	// Since buf2 is reversed, reverse it into buf.
76*5a6e8488SAndroid Build Coastguard Worker 	for (i = 0; i < len; ++i)
77*5a6e8488SAndroid Build Coastguard Worker 	{
78*5a6e8488SAndroid Build Coastguard Worker 		buf[i] = buf2[len - i - 1];
79*5a6e8488SAndroid Build Coastguard Worker 	}
80*5a6e8488SAndroid Build Coastguard Worker }
81*5a6e8488SAndroid Build Coastguard Worker 
82*5a6e8488SAndroid Build Coastguard Worker /**
83*5a6e8488SAndroid Build Coastguard Worker  * Output to the file directly.
84*5a6e8488SAndroid Build Coastguard Worker  * @param fd   The file descriptor.
85*5a6e8488SAndroid Build Coastguard Worker  * @param buf  The buffer of data to output.
86*5a6e8488SAndroid Build Coastguard Worker  * @param n    The number of bytes to output.
87*5a6e8488SAndroid Build Coastguard Worker  * @return     A status indicating error or success. We could have a fatal I/O
88*5a6e8488SAndroid Build Coastguard Worker  *             error or EOF.
89*5a6e8488SAndroid Build Coastguard Worker  */
90*5a6e8488SAndroid Build Coastguard Worker static BcStatus
bc_file_output(int fd,const char * buf,size_t n)91*5a6e8488SAndroid Build Coastguard Worker bc_file_output(int fd, const char* buf, size_t n)
92*5a6e8488SAndroid Build Coastguard Worker {
93*5a6e8488SAndroid Build Coastguard Worker 	size_t bytes = 0;
94*5a6e8488SAndroid Build Coastguard Worker 	sig_atomic_t lock;
95*5a6e8488SAndroid Build Coastguard Worker 
96*5a6e8488SAndroid Build Coastguard Worker 	BC_SIG_TRYLOCK(lock);
97*5a6e8488SAndroid Build Coastguard Worker 
98*5a6e8488SAndroid Build Coastguard Worker 	// While the number of bytes written is less than intended...
99*5a6e8488SAndroid Build Coastguard Worker 	while (bytes < n)
100*5a6e8488SAndroid Build Coastguard Worker 	{
101*5a6e8488SAndroid Build Coastguard Worker 		// Write.
102*5a6e8488SAndroid Build Coastguard Worker 		ssize_t written = write(fd, buf + bytes, n - bytes);
103*5a6e8488SAndroid Build Coastguard Worker 
104*5a6e8488SAndroid Build Coastguard Worker 		// Check for error and return, if any.
105*5a6e8488SAndroid Build Coastguard Worker 		if (BC_ERR(written == -1))
106*5a6e8488SAndroid Build Coastguard Worker 		{
107*5a6e8488SAndroid Build Coastguard Worker 			BC_SIG_TRYUNLOCK(lock);
108*5a6e8488SAndroid Build Coastguard Worker 
109*5a6e8488SAndroid Build Coastguard Worker 			return errno == EPIPE ? BC_STATUS_EOF : BC_STATUS_ERROR_FATAL;
110*5a6e8488SAndroid Build Coastguard Worker 		}
111*5a6e8488SAndroid Build Coastguard Worker 
112*5a6e8488SAndroid Build Coastguard Worker 		bytes += (size_t) written;
113*5a6e8488SAndroid Build Coastguard Worker 	}
114*5a6e8488SAndroid Build Coastguard Worker 
115*5a6e8488SAndroid Build Coastguard Worker 	BC_SIG_TRYUNLOCK(lock);
116*5a6e8488SAndroid Build Coastguard Worker 
117*5a6e8488SAndroid Build Coastguard Worker 	return BC_STATUS_SUCCESS;
118*5a6e8488SAndroid Build Coastguard Worker }
119*5a6e8488SAndroid Build Coastguard Worker 
120*5a6e8488SAndroid Build Coastguard Worker #endif // !BC_ENABLE_LINE_LIB
121*5a6e8488SAndroid Build Coastguard Worker 
122*5a6e8488SAndroid Build Coastguard Worker BcStatus
bc_file_flushErr(BcFile * restrict f,BcFlushType type)123*5a6e8488SAndroid Build Coastguard Worker bc_file_flushErr(BcFile* restrict f, BcFlushType type)
124*5a6e8488SAndroid Build Coastguard Worker {
125*5a6e8488SAndroid Build Coastguard Worker 	BcStatus s;
126*5a6e8488SAndroid Build Coastguard Worker 
127*5a6e8488SAndroid Build Coastguard Worker 	BC_SIG_ASSERT_LOCKED;
128*5a6e8488SAndroid Build Coastguard Worker 
129*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_LINE_LIB
130*5a6e8488SAndroid Build Coastguard Worker 
131*5a6e8488SAndroid Build Coastguard Worker 	// Just flush and propagate the error.
132*5a6e8488SAndroid Build Coastguard Worker 	if (fflush(f->f) == EOF) s = BC_STATUS_ERROR_FATAL;
133*5a6e8488SAndroid Build Coastguard Worker 	else s = BC_STATUS_SUCCESS;
134*5a6e8488SAndroid Build Coastguard Worker 
135*5a6e8488SAndroid Build Coastguard Worker #else // BC_ENABLE_LINE_LIB
136*5a6e8488SAndroid Build Coastguard Worker 
137*5a6e8488SAndroid Build Coastguard Worker 	// If there is stuff to output...
138*5a6e8488SAndroid Build Coastguard Worker 	if (f->len)
139*5a6e8488SAndroid Build Coastguard Worker 	{
140*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_HISTORY
141*5a6e8488SAndroid Build Coastguard Worker 
142*5a6e8488SAndroid Build Coastguard Worker 		// If history is enabled...
143*5a6e8488SAndroid Build Coastguard Worker 		if (BC_TTY)
144*5a6e8488SAndroid Build Coastguard Worker 		{
145*5a6e8488SAndroid Build Coastguard Worker 			// If we have been told to save the extras, and there *are*
146*5a6e8488SAndroid Build Coastguard Worker 			// extras...
147*5a6e8488SAndroid Build Coastguard Worker 			if (f->buf[f->len - 1] != '\n' &&
148*5a6e8488SAndroid Build Coastguard Worker 			    (type == BC_FLUSH_SAVE_EXTRAS_CLEAR ||
149*5a6e8488SAndroid Build Coastguard Worker 			     type == BC_FLUSH_SAVE_EXTRAS_NO_CLEAR))
150*5a6e8488SAndroid Build Coastguard Worker 			{
151*5a6e8488SAndroid Build Coastguard Worker 				size_t i;
152*5a6e8488SAndroid Build Coastguard Worker 
153*5a6e8488SAndroid Build Coastguard Worker 				// Look for the last newline.
154*5a6e8488SAndroid Build Coastguard Worker 				for (i = f->len - 2; i < f->len && f->buf[i] != '\n'; --i)
155*5a6e8488SAndroid Build Coastguard Worker 				{
156*5a6e8488SAndroid Build Coastguard Worker 					continue;
157*5a6e8488SAndroid Build Coastguard Worker 				}
158*5a6e8488SAndroid Build Coastguard Worker 
159*5a6e8488SAndroid Build Coastguard Worker 				i += 1;
160*5a6e8488SAndroid Build Coastguard Worker 
161*5a6e8488SAndroid Build Coastguard Worker 				// Save the extras.
162*5a6e8488SAndroid Build Coastguard Worker 				bc_vec_string(&vm->history.extras, f->len - i, f->buf + i);
163*5a6e8488SAndroid Build Coastguard Worker 			}
164*5a6e8488SAndroid Build Coastguard Worker 			// Else clear the extras if told to.
165*5a6e8488SAndroid Build Coastguard Worker 			else if (type >= BC_FLUSH_NO_EXTRAS_CLEAR)
166*5a6e8488SAndroid Build Coastguard Worker 			{
167*5a6e8488SAndroid Build Coastguard Worker 				bc_vec_popAll(&vm->history.extras);
168*5a6e8488SAndroid Build Coastguard Worker 			}
169*5a6e8488SAndroid Build Coastguard Worker 		}
170*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_HISTORY
171*5a6e8488SAndroid Build Coastguard Worker 
172*5a6e8488SAndroid Build Coastguard Worker 		// Actually output.
173*5a6e8488SAndroid Build Coastguard Worker 		s = bc_file_output(f->fd, f->buf, f->len);
174*5a6e8488SAndroid Build Coastguard Worker 		f->len = 0;
175*5a6e8488SAndroid Build Coastguard Worker 	}
176*5a6e8488SAndroid Build Coastguard Worker 	else s = BC_STATUS_SUCCESS;
177*5a6e8488SAndroid Build Coastguard Worker 
178*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_LINE_LIB
179*5a6e8488SAndroid Build Coastguard Worker 
180*5a6e8488SAndroid Build Coastguard Worker 	return s;
181*5a6e8488SAndroid Build Coastguard Worker }
182*5a6e8488SAndroid Build Coastguard Worker 
183*5a6e8488SAndroid Build Coastguard Worker void
bc_file_flush(BcFile * restrict f,BcFlushType type)184*5a6e8488SAndroid Build Coastguard Worker bc_file_flush(BcFile* restrict f, BcFlushType type)
185*5a6e8488SAndroid Build Coastguard Worker {
186*5a6e8488SAndroid Build Coastguard Worker 	BcStatus s;
187*5a6e8488SAndroid Build Coastguard Worker 	sig_atomic_t lock;
188*5a6e8488SAndroid Build Coastguard Worker 
189*5a6e8488SAndroid Build Coastguard Worker 	BC_SIG_TRYLOCK(lock);
190*5a6e8488SAndroid Build Coastguard Worker 
191*5a6e8488SAndroid Build Coastguard Worker 	s = bc_file_flushErr(f, type);
192*5a6e8488SAndroid Build Coastguard Worker 
193*5a6e8488SAndroid Build Coastguard Worker 	// If we have an error...
194*5a6e8488SAndroid Build Coastguard Worker 	if (BC_ERR(s))
195*5a6e8488SAndroid Build Coastguard Worker 	{
196*5a6e8488SAndroid Build Coastguard Worker 		// For EOF, set it and jump.
197*5a6e8488SAndroid Build Coastguard Worker 		if (s == BC_STATUS_EOF)
198*5a6e8488SAndroid Build Coastguard Worker 		{
199*5a6e8488SAndroid Build Coastguard Worker 			vm->status = (sig_atomic_t) s;
200*5a6e8488SAndroid Build Coastguard Worker 			BC_SIG_TRYUNLOCK(lock);
201*5a6e8488SAndroid Build Coastguard Worker 			BC_JMP;
202*5a6e8488SAndroid Build Coastguard Worker 		}
203*5a6e8488SAndroid Build Coastguard Worker 		// Make sure to handle non-fatal I/O properly.
204*5a6e8488SAndroid Build Coastguard Worker 		else if (!f->errors_fatal)
205*5a6e8488SAndroid Build Coastguard Worker 		{
206*5a6e8488SAndroid Build Coastguard Worker 			bc_vm_fatalError(BC_ERR_FATAL_IO_ERR);
207*5a6e8488SAndroid Build Coastguard Worker 		}
208*5a6e8488SAndroid Build Coastguard Worker 		// Blow up on fatal error. Okay, not blow up, just quit.
209*5a6e8488SAndroid Build Coastguard Worker 		else exit(BC_STATUS_ERROR_FATAL);
210*5a6e8488SAndroid Build Coastguard Worker 	}
211*5a6e8488SAndroid Build Coastguard Worker 
212*5a6e8488SAndroid Build Coastguard Worker 	BC_SIG_TRYUNLOCK(lock);
213*5a6e8488SAndroid Build Coastguard Worker }
214*5a6e8488SAndroid Build Coastguard Worker 
215*5a6e8488SAndroid Build Coastguard Worker #if !BC_ENABLE_LINE_LIB
216*5a6e8488SAndroid Build Coastguard Worker 
217*5a6e8488SAndroid Build Coastguard Worker void
bc_file_write(BcFile * restrict f,BcFlushType type,const char * buf,size_t n)218*5a6e8488SAndroid Build Coastguard Worker bc_file_write(BcFile* restrict f, BcFlushType type, const char* buf, size_t n)
219*5a6e8488SAndroid Build Coastguard Worker {
220*5a6e8488SAndroid Build Coastguard Worker 	sig_atomic_t lock;
221*5a6e8488SAndroid Build Coastguard Worker 
222*5a6e8488SAndroid Build Coastguard Worker 	BC_SIG_TRYLOCK(lock);
223*5a6e8488SAndroid Build Coastguard Worker 
224*5a6e8488SAndroid Build Coastguard Worker 	// If we have enough to flush, do it.
225*5a6e8488SAndroid Build Coastguard Worker 	if (n > f->cap - f->len)
226*5a6e8488SAndroid Build Coastguard Worker 	{
227*5a6e8488SAndroid Build Coastguard Worker 		bc_file_flush(f, type);
228*5a6e8488SAndroid Build Coastguard Worker 		assert(!f->len);
229*5a6e8488SAndroid Build Coastguard Worker 	}
230*5a6e8488SAndroid Build Coastguard Worker 
231*5a6e8488SAndroid Build Coastguard Worker 	// If the output is large enough to flush by itself, just output it.
232*5a6e8488SAndroid Build Coastguard Worker 	// Otherwise, put it into the buffer.
233*5a6e8488SAndroid Build Coastguard Worker 	if (BC_UNLIKELY(n > f->cap - f->len))
234*5a6e8488SAndroid Build Coastguard Worker 	{
235*5a6e8488SAndroid Build Coastguard Worker 		BcStatus s = bc_file_output(f->fd, buf, n);
236*5a6e8488SAndroid Build Coastguard Worker 
237*5a6e8488SAndroid Build Coastguard Worker 		if (BC_ERR(s))
238*5a6e8488SAndroid Build Coastguard Worker 		{
239*5a6e8488SAndroid Build Coastguard Worker 			// For EOF, set it and jump.
240*5a6e8488SAndroid Build Coastguard Worker 			if (s == BC_STATUS_EOF)
241*5a6e8488SAndroid Build Coastguard Worker 			{
242*5a6e8488SAndroid Build Coastguard Worker 				vm->status = (sig_atomic_t) s;
243*5a6e8488SAndroid Build Coastguard Worker 				BC_SIG_TRYUNLOCK(lock);
244*5a6e8488SAndroid Build Coastguard Worker 				BC_JMP;
245*5a6e8488SAndroid Build Coastguard Worker 			}
246*5a6e8488SAndroid Build Coastguard Worker 			// Make sure to handle non-fatal I/O properly.
247*5a6e8488SAndroid Build Coastguard Worker 			else if (!f->errors_fatal)
248*5a6e8488SAndroid Build Coastguard Worker 			{
249*5a6e8488SAndroid Build Coastguard Worker 				bc_vm_fatalError(BC_ERR_FATAL_IO_ERR);
250*5a6e8488SAndroid Build Coastguard Worker 			}
251*5a6e8488SAndroid Build Coastguard Worker 			// Blow up on fatal error. Okay, not blow up, just quit.
252*5a6e8488SAndroid Build Coastguard Worker 			else exit(BC_STATUS_ERROR_FATAL);
253*5a6e8488SAndroid Build Coastguard Worker 		}
254*5a6e8488SAndroid Build Coastguard Worker 	}
255*5a6e8488SAndroid Build Coastguard Worker 	else
256*5a6e8488SAndroid Build Coastguard Worker 	{
257*5a6e8488SAndroid Build Coastguard Worker 		// NOLINTNEXTLINE
258*5a6e8488SAndroid Build Coastguard Worker 		memcpy(f->buf + f->len, buf, n);
259*5a6e8488SAndroid Build Coastguard Worker 		f->len += n;
260*5a6e8488SAndroid Build Coastguard Worker 	}
261*5a6e8488SAndroid Build Coastguard Worker 
262*5a6e8488SAndroid Build Coastguard Worker 	BC_SIG_TRYUNLOCK(lock);
263*5a6e8488SAndroid Build Coastguard Worker }
264*5a6e8488SAndroid Build Coastguard Worker 
265*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_LINE_LIB
266*5a6e8488SAndroid Build Coastguard Worker 
267*5a6e8488SAndroid Build Coastguard Worker void
bc_file_printf(BcFile * restrict f,const char * fmt,...)268*5a6e8488SAndroid Build Coastguard Worker bc_file_printf(BcFile* restrict f, const char* fmt, ...)
269*5a6e8488SAndroid Build Coastguard Worker {
270*5a6e8488SAndroid Build Coastguard Worker 	va_list args;
271*5a6e8488SAndroid Build Coastguard Worker 	sig_atomic_t lock;
272*5a6e8488SAndroid Build Coastguard Worker 
273*5a6e8488SAndroid Build Coastguard Worker 	BC_SIG_TRYLOCK(lock);
274*5a6e8488SAndroid Build Coastguard Worker 
275*5a6e8488SAndroid Build Coastguard Worker 	va_start(args, fmt);
276*5a6e8488SAndroid Build Coastguard Worker 	bc_file_vprintf(f, fmt, args);
277*5a6e8488SAndroid Build Coastguard Worker 	va_end(args);
278*5a6e8488SAndroid Build Coastguard Worker 
279*5a6e8488SAndroid Build Coastguard Worker 	BC_SIG_TRYUNLOCK(lock);
280*5a6e8488SAndroid Build Coastguard Worker }
281*5a6e8488SAndroid Build Coastguard Worker 
282*5a6e8488SAndroid Build Coastguard Worker void
bc_file_vprintf(BcFile * restrict f,const char * fmt,va_list args)283*5a6e8488SAndroid Build Coastguard Worker bc_file_vprintf(BcFile* restrict f, const char* fmt, va_list args)
284*5a6e8488SAndroid Build Coastguard Worker {
285*5a6e8488SAndroid Build Coastguard Worker 	BC_SIG_ASSERT_LOCKED;
286*5a6e8488SAndroid Build Coastguard Worker 
287*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_LINE_LIB
288*5a6e8488SAndroid Build Coastguard Worker 
289*5a6e8488SAndroid Build Coastguard Worker 	{
290*5a6e8488SAndroid Build Coastguard Worker 		int r;
291*5a6e8488SAndroid Build Coastguard Worker 
292*5a6e8488SAndroid Build Coastguard Worker 		// This mess is to silence a warning.
293*5a6e8488SAndroid Build Coastguard Worker #if BC_CLANG
294*5a6e8488SAndroid Build Coastguard Worker #pragma clang diagnostic push
295*5a6e8488SAndroid Build Coastguard Worker #pragma clang diagnostic ignored "-Wformat-nonliteral"
296*5a6e8488SAndroid Build Coastguard Worker #endif // BC_CLANG
297*5a6e8488SAndroid Build Coastguard Worker 		r = vfprintf(f->f, fmt, args);
298*5a6e8488SAndroid Build Coastguard Worker #if BC_CLANG
299*5a6e8488SAndroid Build Coastguard Worker #pragma clang diagnostic pop
300*5a6e8488SAndroid Build Coastguard Worker #endif // BC_CLANG
301*5a6e8488SAndroid Build Coastguard Worker 
302*5a6e8488SAndroid Build Coastguard Worker 		// Just print and propagate the error.
303*5a6e8488SAndroid Build Coastguard Worker 		if (BC_ERR(r < 0))
304*5a6e8488SAndroid Build Coastguard Worker 		{
305*5a6e8488SAndroid Build Coastguard Worker 			// Make sure to handle non-fatal I/O properly.
306*5a6e8488SAndroid Build Coastguard Worker 			if (!f->errors_fatal)
307*5a6e8488SAndroid Build Coastguard Worker 			{
308*5a6e8488SAndroid Build Coastguard Worker 				bc_vm_fatalError(BC_ERR_FATAL_IO_ERR);
309*5a6e8488SAndroid Build Coastguard Worker 			}
310*5a6e8488SAndroid Build Coastguard Worker 			else
311*5a6e8488SAndroid Build Coastguard Worker 			{
312*5a6e8488SAndroid Build Coastguard Worker 				exit(BC_STATUS_ERROR_FATAL);
313*5a6e8488SAndroid Build Coastguard Worker 			}
314*5a6e8488SAndroid Build Coastguard Worker 		}
315*5a6e8488SAndroid Build Coastguard Worker 	}
316*5a6e8488SAndroid Build Coastguard Worker 
317*5a6e8488SAndroid Build Coastguard Worker #else // BC_ENABLE_LINE_LIB
318*5a6e8488SAndroid Build Coastguard Worker 
319*5a6e8488SAndroid Build Coastguard Worker 	{
320*5a6e8488SAndroid Build Coastguard Worker 		char* percent;
321*5a6e8488SAndroid Build Coastguard Worker 		const char* ptr = fmt;
322*5a6e8488SAndroid Build Coastguard Worker 		char buf[BC_FILE_ULL_LENGTH];
323*5a6e8488SAndroid Build Coastguard Worker 
324*5a6e8488SAndroid Build Coastguard Worker 		// This is a poor man's printf(). While I could look up algorithms to
325*5a6e8488SAndroid Build Coastguard Worker 		// make it as fast as possible, and should when I write the standard
326*5a6e8488SAndroid Build Coastguard Worker 		// library for a new language, for bc, outputting is not the bottleneck.
327*5a6e8488SAndroid Build Coastguard Worker 		// So we cheese it for now.
328*5a6e8488SAndroid Build Coastguard Worker 
329*5a6e8488SAndroid Build Coastguard Worker 		// Find each percent sign.
330*5a6e8488SAndroid Build Coastguard Worker 		while ((percent = strchr(ptr, '%')) != NULL)
331*5a6e8488SAndroid Build Coastguard Worker 		{
332*5a6e8488SAndroid Build Coastguard Worker 			char c;
333*5a6e8488SAndroid Build Coastguard Worker 
334*5a6e8488SAndroid Build Coastguard Worker 			// If the percent sign is not where we are, write what's inbetween
335*5a6e8488SAndroid Build Coastguard Worker 			// to the buffer.
336*5a6e8488SAndroid Build Coastguard Worker 			if (percent != ptr)
337*5a6e8488SAndroid Build Coastguard Worker 			{
338*5a6e8488SAndroid Build Coastguard Worker 				size_t len = (size_t) (percent - ptr);
339*5a6e8488SAndroid Build Coastguard Worker 				bc_file_write(f, bc_flush_none, ptr, len);
340*5a6e8488SAndroid Build Coastguard Worker 			}
341*5a6e8488SAndroid Build Coastguard Worker 
342*5a6e8488SAndroid Build Coastguard Worker 			c = percent[1];
343*5a6e8488SAndroid Build Coastguard Worker 
344*5a6e8488SAndroid Build Coastguard Worker 			// We only parse some format specifiers, the ones bc uses. If you
345*5a6e8488SAndroid Build Coastguard Worker 			// add more, you need to make sure to add them here.
346*5a6e8488SAndroid Build Coastguard Worker 			if (c == 'c')
347*5a6e8488SAndroid Build Coastguard Worker 			{
348*5a6e8488SAndroid Build Coastguard Worker 				uchar uc = (uchar) va_arg(args, int);
349*5a6e8488SAndroid Build Coastguard Worker 
350*5a6e8488SAndroid Build Coastguard Worker 				bc_file_putchar(f, bc_flush_none, uc);
351*5a6e8488SAndroid Build Coastguard Worker 			}
352*5a6e8488SAndroid Build Coastguard Worker 			else if (c == 's')
353*5a6e8488SAndroid Build Coastguard Worker 			{
354*5a6e8488SAndroid Build Coastguard Worker 				char* s = va_arg(args, char*);
355*5a6e8488SAndroid Build Coastguard Worker 
356*5a6e8488SAndroid Build Coastguard Worker 				bc_file_puts(f, bc_flush_none, s);
357*5a6e8488SAndroid Build Coastguard Worker 			}
358*5a6e8488SAndroid Build Coastguard Worker #if BC_DEBUG
359*5a6e8488SAndroid Build Coastguard Worker 			// We only print signed integers in debug code.
360*5a6e8488SAndroid Build Coastguard Worker 			else if (c == 'd')
361*5a6e8488SAndroid Build Coastguard Worker 			{
362*5a6e8488SAndroid Build Coastguard Worker 				int d = va_arg(args, int);
363*5a6e8488SAndroid Build Coastguard Worker 
364*5a6e8488SAndroid Build Coastguard Worker 				// Take care of negative. Let's not worry about overflow.
365*5a6e8488SAndroid Build Coastguard Worker 				if (d < 0)
366*5a6e8488SAndroid Build Coastguard Worker 				{
367*5a6e8488SAndroid Build Coastguard Worker 					bc_file_putchar(f, bc_flush_none, '-');
368*5a6e8488SAndroid Build Coastguard Worker 					d = -d;
369*5a6e8488SAndroid Build Coastguard Worker 				}
370*5a6e8488SAndroid Build Coastguard Worker 
371*5a6e8488SAndroid Build Coastguard Worker 				// Either print 0 or translate and print.
372*5a6e8488SAndroid Build Coastguard Worker 				if (!d) bc_file_putchar(f, bc_flush_none, '0');
373*5a6e8488SAndroid Build Coastguard Worker 				else
374*5a6e8488SAndroid Build Coastguard Worker 				{
375*5a6e8488SAndroid Build Coastguard Worker 					bc_file_ultoa((unsigned long long) d, buf);
376*5a6e8488SAndroid Build Coastguard Worker 					bc_file_puts(f, bc_flush_none, buf);
377*5a6e8488SAndroid Build Coastguard Worker 				}
378*5a6e8488SAndroid Build Coastguard Worker 			}
379*5a6e8488SAndroid Build Coastguard Worker #endif // BC_DEBUG
380*5a6e8488SAndroid Build Coastguard Worker 			else
381*5a6e8488SAndroid Build Coastguard Worker 			{
382*5a6e8488SAndroid Build Coastguard Worker 				unsigned long long ull;
383*5a6e8488SAndroid Build Coastguard Worker 
384*5a6e8488SAndroid Build Coastguard Worker 				// These are the ones that it expects from here. Fortunately,
385*5a6e8488SAndroid Build Coastguard Worker 				// all of these are unsigned types, so they can use the same
386*5a6e8488SAndroid Build Coastguard Worker 				// code, more or less.
387*5a6e8488SAndroid Build Coastguard Worker 				assert((c == 'l' || c == 'z') && percent[2] == 'u');
388*5a6e8488SAndroid Build Coastguard Worker 
389*5a6e8488SAndroid Build Coastguard Worker 				if (c == 'z') ull = (unsigned long long) va_arg(args, size_t);
390*5a6e8488SAndroid Build Coastguard Worker 				else ull = (unsigned long long) va_arg(args, unsigned long);
391*5a6e8488SAndroid Build Coastguard Worker 
392*5a6e8488SAndroid Build Coastguard Worker 				// Either print 0 or translate and print.
393*5a6e8488SAndroid Build Coastguard Worker 				if (!ull) bc_file_putchar(f, bc_flush_none, '0');
394*5a6e8488SAndroid Build Coastguard Worker 				else
395*5a6e8488SAndroid Build Coastguard Worker 				{
396*5a6e8488SAndroid Build Coastguard Worker 					bc_file_ultoa(ull, buf);
397*5a6e8488SAndroid Build Coastguard Worker 					bc_file_puts(f, bc_flush_none, buf);
398*5a6e8488SAndroid Build Coastguard Worker 				}
399*5a6e8488SAndroid Build Coastguard Worker 			}
400*5a6e8488SAndroid Build Coastguard Worker 
401*5a6e8488SAndroid Build Coastguard Worker 			// Increment to the next spot after the specifier.
402*5a6e8488SAndroid Build Coastguard Worker 			ptr = percent + 2 + (c == 'l' || c == 'z');
403*5a6e8488SAndroid Build Coastguard Worker 		}
404*5a6e8488SAndroid Build Coastguard Worker 
405*5a6e8488SAndroid Build Coastguard Worker 		// If we get here, there are no more percent signs, so we just output
406*5a6e8488SAndroid Build Coastguard Worker 		// whatever is left.
407*5a6e8488SAndroid Build Coastguard Worker 		if (ptr[0]) bc_file_puts(f, bc_flush_none, ptr);
408*5a6e8488SAndroid Build Coastguard Worker 	}
409*5a6e8488SAndroid Build Coastguard Worker 
410*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_LINE_LIB
411*5a6e8488SAndroid Build Coastguard Worker }
412*5a6e8488SAndroid Build Coastguard Worker 
413*5a6e8488SAndroid Build Coastguard Worker void
bc_file_puts(BcFile * restrict f,BcFlushType type,const char * str)414*5a6e8488SAndroid Build Coastguard Worker bc_file_puts(BcFile* restrict f, BcFlushType type, const char* str)
415*5a6e8488SAndroid Build Coastguard Worker {
416*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_LINE_LIB
417*5a6e8488SAndroid Build Coastguard Worker 	// This is used because of flushing issues with using bc_file_write() when
418*5a6e8488SAndroid Build Coastguard Worker 	// bc is using a line library. It's also using printf() because puts()
419*5a6e8488SAndroid Build Coastguard Worker 	// writes a newline.
420*5a6e8488SAndroid Build Coastguard Worker 	bc_file_printf(f, "%s", str);
421*5a6e8488SAndroid Build Coastguard Worker #else // BC_ENABLE_LINE_LIB
422*5a6e8488SAndroid Build Coastguard Worker 	bc_file_write(f, type, str, strlen(str));
423*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_LINE_LIB
424*5a6e8488SAndroid Build Coastguard Worker }
425*5a6e8488SAndroid Build Coastguard Worker 
426*5a6e8488SAndroid Build Coastguard Worker void
bc_file_putchar(BcFile * restrict f,BcFlushType type,uchar c)427*5a6e8488SAndroid Build Coastguard Worker bc_file_putchar(BcFile* restrict f, BcFlushType type, uchar c)
428*5a6e8488SAndroid Build Coastguard Worker {
429*5a6e8488SAndroid Build Coastguard Worker 	sig_atomic_t lock;
430*5a6e8488SAndroid Build Coastguard Worker 
431*5a6e8488SAndroid Build Coastguard Worker 	BC_SIG_TRYLOCK(lock);
432*5a6e8488SAndroid Build Coastguard Worker 
433*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_LINE_LIB
434*5a6e8488SAndroid Build Coastguard Worker 
435*5a6e8488SAndroid Build Coastguard Worker 	if (BC_ERR(fputc(c, f->f) == EOF))
436*5a6e8488SAndroid Build Coastguard Worker 	{
437*5a6e8488SAndroid Build Coastguard Worker 		// This is here to prevent a stack overflow from unbounded recursion.
438*5a6e8488SAndroid Build Coastguard Worker 		if (f->f == stderr) exit(BC_STATUS_ERROR_FATAL);
439*5a6e8488SAndroid Build Coastguard Worker 
440*5a6e8488SAndroid Build Coastguard Worker 		bc_err(BC_ERR_FATAL_IO_ERR);
441*5a6e8488SAndroid Build Coastguard Worker 	}
442*5a6e8488SAndroid Build Coastguard Worker 
443*5a6e8488SAndroid Build Coastguard Worker #else // BC_ENABLE_LINE_LIB
444*5a6e8488SAndroid Build Coastguard Worker 
445*5a6e8488SAndroid Build Coastguard Worker 	if (f->len == f->cap) bc_file_flush(f, type);
446*5a6e8488SAndroid Build Coastguard Worker 
447*5a6e8488SAndroid Build Coastguard Worker 	assert(f->len < f->cap);
448*5a6e8488SAndroid Build Coastguard Worker 
449*5a6e8488SAndroid Build Coastguard Worker 	f->buf[f->len] = (char) c;
450*5a6e8488SAndroid Build Coastguard Worker 	f->len += 1;
451*5a6e8488SAndroid Build Coastguard Worker 
452*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_LINE_LIB
453*5a6e8488SAndroid Build Coastguard Worker 
454*5a6e8488SAndroid Build Coastguard Worker 	BC_SIG_TRYUNLOCK(lock);
455*5a6e8488SAndroid Build Coastguard Worker }
456*5a6e8488SAndroid Build Coastguard Worker 
457*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_LINE_LIB
458*5a6e8488SAndroid Build Coastguard Worker 
459*5a6e8488SAndroid Build Coastguard Worker void
bc_file_init(BcFile * f,FILE * file,bool errors_fatal)460*5a6e8488SAndroid Build Coastguard Worker bc_file_init(BcFile* f, FILE* file, bool errors_fatal)
461*5a6e8488SAndroid Build Coastguard Worker {
462*5a6e8488SAndroid Build Coastguard Worker 	BC_SIG_ASSERT_LOCKED;
463*5a6e8488SAndroid Build Coastguard Worker 	f->f = file;
464*5a6e8488SAndroid Build Coastguard Worker 	f->errors_fatal = errors_fatal;
465*5a6e8488SAndroid Build Coastguard Worker }
466*5a6e8488SAndroid Build Coastguard Worker 
467*5a6e8488SAndroid Build Coastguard Worker #else // BC_ENABLE_LINE_LIB
468*5a6e8488SAndroid Build Coastguard Worker 
469*5a6e8488SAndroid Build Coastguard Worker void
bc_file_init(BcFile * f,int fd,char * buf,size_t cap,bool errors_fatal)470*5a6e8488SAndroid Build Coastguard Worker bc_file_init(BcFile* f, int fd, char* buf, size_t cap, bool errors_fatal)
471*5a6e8488SAndroid Build Coastguard Worker {
472*5a6e8488SAndroid Build Coastguard Worker 	BC_SIG_ASSERT_LOCKED;
473*5a6e8488SAndroid Build Coastguard Worker 
474*5a6e8488SAndroid Build Coastguard Worker 	f->fd = fd;
475*5a6e8488SAndroid Build Coastguard Worker 	f->buf = buf;
476*5a6e8488SAndroid Build Coastguard Worker 	f->len = 0;
477*5a6e8488SAndroid Build Coastguard Worker 	f->cap = cap;
478*5a6e8488SAndroid Build Coastguard Worker 	f->errors_fatal = errors_fatal;
479*5a6e8488SAndroid Build Coastguard Worker }
480*5a6e8488SAndroid Build Coastguard Worker 
481*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_LINE_LIB
482*5a6e8488SAndroid Build Coastguard Worker 
483*5a6e8488SAndroid Build Coastguard Worker void
bc_file_free(BcFile * f)484*5a6e8488SAndroid Build Coastguard Worker bc_file_free(BcFile* f)
485*5a6e8488SAndroid Build Coastguard Worker {
486*5a6e8488SAndroid Build Coastguard Worker 	BC_SIG_ASSERT_LOCKED;
487*5a6e8488SAndroid Build Coastguard Worker 	bc_file_flush(f, bc_flush_none);
488*5a6e8488SAndroid Build Coastguard Worker }
489