Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
  1/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
  2/*
  3 * minimal stdio function definitions for NOLIBC
  4 * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
  5 */
  6
  7#ifndef _NOLIBC_STDIO_H
  8#define _NOLIBC_STDIO_H
  9
 10#include "std.h"
 11#include "arch.h"
 12#include "errno.h"
 13#include "types.h"
 14#include "sys.h"
 15#include "stdarg.h"
 16#include "stdlib.h"
 17#include "string.h"
 18#include "compiler.h"
 19
 20#ifndef EOF
 21#define EOF (-1)
 22#endif
 23
 24/* Buffering mode used by setvbuf.  */
 25#define _IOFBF 0	/* Fully buffered. */
 26#define _IOLBF 1	/* Line buffered. */
 27#define _IONBF 2	/* No buffering. */
 28
 29/* just define FILE as a non-empty type. The value of the pointer gives
 30 * the FD: FILE=~fd for fd>=0 or NULL for fd<0. This way positive FILE
 31 * are immediately identified as abnormal entries (i.e. possible copies
 32 * of valid pointers to something else).
 33 */
 34typedef struct FILE {
 35	char dummy[1];
 36} FILE;
 37
 38static __attribute__((unused)) FILE* const stdin  = (FILE*)(intptr_t)~STDIN_FILENO;
 39static __attribute__((unused)) FILE* const stdout = (FILE*)(intptr_t)~STDOUT_FILENO;
 40static __attribute__((unused)) FILE* const stderr = (FILE*)(intptr_t)~STDERR_FILENO;
 41
 42/* provides a FILE* equivalent of fd. The mode is ignored. */
 43static __attribute__((unused))
 44FILE *fdopen(int fd, const char *mode __attribute__((unused)))
 45{
 46	if (fd < 0) {
 47		SET_ERRNO(EBADF);
 48		return NULL;
 49	}
 50	return (FILE*)(intptr_t)~fd;
 51}
 52
 53/* provides the fd of stream. */
 54static __attribute__((unused))
 55int fileno(FILE *stream)
 56{
 57	intptr_t i = (intptr_t)stream;
 58
 59	if (i >= 0) {
 60		SET_ERRNO(EBADF);
 61		return -1;
 62	}
 63	return ~i;
 64}
 65
 66/* flush a stream. */
 67static __attribute__((unused))
 68int fflush(FILE *stream)
 69{
 70	intptr_t i = (intptr_t)stream;
 71
 72	/* NULL is valid here. */
 73	if (i > 0) {
 74		SET_ERRNO(EBADF);
 75		return -1;
 76	}
 77
 78	/* Don't do anything, nolibc does not support buffering. */
 79	return 0;
 80}
 81
 82/* flush a stream. */
 83static __attribute__((unused))
 84int fclose(FILE *stream)
 85{
 86	intptr_t i = (intptr_t)stream;
 87
 88	if (i >= 0) {
 89		SET_ERRNO(EBADF);
 90		return -1;
 91	}
 92
 93	if (close(~i))
 94		return EOF;
 95
 96	return 0;
 97}
 98
 99/* getc(), fgetc(), getchar() */
100
101#define getc(stream) fgetc(stream)
102
103static __attribute__((unused))
104int fgetc(FILE* stream)
105{
106	unsigned char ch;
107
108	if (read(fileno(stream), &ch, 1) <= 0)
109		return EOF;
110	return ch;
111}
112
113static __attribute__((unused))
114int getchar(void)
115{
116	return fgetc(stdin);
117}
118
119
120/* putc(), fputc(), putchar() */
121
122#define putc(c, stream) fputc(c, stream)
123
124static __attribute__((unused))
125int fputc(int c, FILE* stream)
126{
127	unsigned char ch = c;
128
129	if (write(fileno(stream), &ch, 1) <= 0)
130		return EOF;
131	return ch;
132}
133
134static __attribute__((unused))
135int putchar(int c)
136{
137	return fputc(c, stdout);
138}
139
140
141/* fwrite(), puts(), fputs(). Note that puts() emits '\n' but not fputs(). */
142
143/* internal fwrite()-like function which only takes a size and returns 0 on
144 * success or EOF on error. It automatically retries on short writes.
145 */
146static __attribute__((unused))
147int _fwrite(const void *buf, size_t size, FILE *stream)
148{
149	ssize_t ret;
150	int fd = fileno(stream);
151
152	while (size) {
153		ret = write(fd, buf, size);
154		if (ret <= 0)
155			return EOF;
156		size -= ret;
157		buf += ret;
158	}
159	return 0;
160}
161
162static __attribute__((unused))
163size_t fwrite(const void *s, size_t size, size_t nmemb, FILE *stream)
164{
165	size_t written;
166
167	for (written = 0; written < nmemb; written++) {
168		if (_fwrite(s, size, stream) != 0)
169			break;
170		s += size;
171	}
172	return written;
173}
174
175static __attribute__((unused))
176int fputs(const char *s, FILE *stream)
177{
178	return _fwrite(s, strlen(s), stream);
179}
180
181static __attribute__((unused))
182int puts(const char *s)
183{
184	if (fputs(s, stdout) == EOF)
185		return EOF;
186	return putchar('\n');
187}
188
189
190/* fgets() */
191static __attribute__((unused))
192char *fgets(char *s, int size, FILE *stream)
193{
194	int ofs;
195	int c;
196
197	for (ofs = 0; ofs + 1 < size;) {
198		c = fgetc(stream);
199		if (c == EOF)
200			break;
201		s[ofs++] = c;
202		if (c == '\n')
203			break;
204	}
205	if (ofs < size)
206		s[ofs] = 0;
207	return ofs ? s : NULL;
208}
209
210
211/* minimal vfprintf(). It supports the following formats:
212 *  - %[l*]{d,u,c,x,p}
213 *  - %s
214 *  - unknown modifiers are ignored.
215 */
216static __attribute__((unused, format(printf, 2, 0)))
217int vfprintf(FILE *stream, const char *fmt, va_list args)
218{
219	char escape, lpref, c;
220	unsigned long long v;
221	unsigned int written;
222	size_t len, ofs;
223	char tmpbuf[21];
224	const char *outstr;
225
226	written = ofs = escape = lpref = 0;
227	while (1) {
228		c = fmt[ofs++];
229
230		if (escape) {
231			/* we're in an escape sequence, ofs == 1 */
232			escape = 0;
233			if (c == 'c' || c == 'd' || c == 'u' || c == 'x' || c == 'p') {
234				char *out = tmpbuf;
235
236				if (c == 'p')
237					v = va_arg(args, unsigned long);
238				else if (lpref) {
239					if (lpref > 1)
240						v = va_arg(args, unsigned long long);
241					else
242						v = va_arg(args, unsigned long);
243				} else
244					v = va_arg(args, unsigned int);
245
246				if (c == 'd') {
247					/* sign-extend the value */
248					if (lpref == 0)
249						v = (long long)(int)v;
250					else if (lpref == 1)
251						v = (long long)(long)v;
252				}
253
254				switch (c) {
255				case 'c':
256					out[0] = v;
257					out[1] = 0;
258					break;
259				case 'd':
260					i64toa_r(v, out);
261					break;
262				case 'u':
263					u64toa_r(v, out);
264					break;
265				case 'p':
266					*(out++) = '0';
267					*(out++) = 'x';
268					__nolibc_fallthrough;
269				default: /* 'x' and 'p' above */
270					u64toh_r(v, out);
271					break;
272				}
273				outstr = tmpbuf;
274			}
275			else if (c == 's') {
276				outstr = va_arg(args, char *);
277				if (!outstr)
278					outstr="(null)";
279			}
280			else if (c == '%') {
281				/* queue it verbatim */
282				continue;
283			}
284			else {
285				/* modifiers or final 0 */
286				if (c == 'l') {
287					/* long format prefix, maintain the escape */
288					lpref++;
289				}
290				escape = 1;
291				goto do_escape;
292			}
293			len = strlen(outstr);
294			goto flush_str;
295		}
296
297		/* not an escape sequence */
298		if (c == 0 || c == '%') {
299			/* flush pending data on escape or end */
300			escape = 1;
301			lpref = 0;
302			outstr = fmt;
303			len = ofs - 1;
304		flush_str:
305			if (_fwrite(outstr, len, stream) != 0)
306				break;
307
308			written += len;
309		do_escape:
310			if (c == 0)
311				break;
312			fmt += ofs;
313			ofs = 0;
314			continue;
315		}
316
317		/* literal char, just queue it */
318	}
319	return written;
320}
321
322static __attribute__((unused, format(printf, 1, 0)))
323int vprintf(const char *fmt, va_list args)
324{
325	return vfprintf(stdout, fmt, args);
326}
327
328static __attribute__((unused, format(printf, 2, 3)))
329int fprintf(FILE *stream, const char *fmt, ...)
330{
331	va_list args;
332	int ret;
333
334	va_start(args, fmt);
335	ret = vfprintf(stream, fmt, args);
336	va_end(args);
337	return ret;
338}
339
340static __attribute__((unused, format(printf, 1, 2)))
341int printf(const char *fmt, ...)
342{
343	va_list args;
344	int ret;
345
346	va_start(args, fmt);
347	ret = vfprintf(stdout, fmt, args);
348	va_end(args);
349	return ret;
350}
351
352static __attribute__((unused))
353void perror(const char *msg)
354{
355	fprintf(stderr, "%s%serrno=%d\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "", errno);
356}
357
358static __attribute__((unused))
359int setvbuf(FILE *stream __attribute__((unused)),
360	    char *buf __attribute__((unused)),
361	    int mode,
362	    size_t size __attribute__((unused)))
363{
364	/*
365	 * nolibc does not support buffering so this is a nop. Just check mode
366	 * is valid as required by the spec.
367	 */
368	switch (mode) {
369	case _IOFBF:
370	case _IOLBF:
371	case _IONBF:
372		break;
373	default:
374		return EOF;
375	}
376
377	return 0;
378}
379
380static __attribute__((unused))
381const char *strerror(int errno)
382{
383	static char buf[18] = "errno=";
384
385	i64toa_r(errno, &buf[6]);
386
387	return buf;
388}
389
390/* make sure to include all global symbols */
391#include "nolibc.h"
392
393#endif /* _NOLIBC_STDIO_H */