Linux Audio

Check our new training course

Embedded Linux training

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