File Index
Files and directories
Sign in
FILE

stdio.h

File preview with syntax highlighting.

linux-6.19.14/tools/include/nolibc/stdio.h OBJECTIVE-C
  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/* make sure to include all global symbols */
  8#include "nolibc.h"
  9
 10#ifndef _NOLIBC_STDIO_H
 11#define _NOLIBC_STDIO_H
 12
 13#include "std.h"
 14#include "arch.h"
 15#include "errno.h"
 16#include "fcntl.h"
 17#include "types.h"
 18#include "sys.h"
 19#include "stdarg.h"
 20#include "stdlib.h"
 21#include "string.h"
 22#include "compiler.h"
 23
 24static const char *strerror(int errnum);
 25
 26#ifndef EOF
 27#define EOF (-1)
 28#endif
 29
 30/* Buffering mode used by setvbuf.  */
 31#define _IOFBF 0	/* Fully buffered. */
 32#define _IOLBF 1	/* Line buffered. */
 33#define _IONBF 2	/* No buffering. */
 34
 35/* just define FILE as a non-empty type. The value of the pointer gives
 36 * the FD: FILE=~fd for fd>=0 or NULL for fd<0. This way positive FILE
 37 * are immediately identified as abnormal entries (i.e. possible copies
 38 * of valid pointers to something else).
 39 */
 40typedef struct FILE {
 41	char dummy[1];
 42} FILE;
 43
 44static __attribute__((unused)) FILE* const stdin  = (FILE*)(intptr_t)~STDIN_FILENO;
 45static __attribute__((unused)) FILE* const stdout = (FILE*)(intptr_t)~STDOUT_FILENO;
 46static __attribute__((unused)) FILE* const stderr = (FILE*)(intptr_t)~STDERR_FILENO;
 47
 48/* provides a FILE* equivalent of fd. The mode is ignored. */
 49static __attribute__((unused))
 50FILE *fdopen(int fd, const char *mode __attribute__((unused)))
 51{
 52	if (fd < 0) {
 53		SET_ERRNO(EBADF);
 54		return NULL;
 55	}
 56	return (FILE*)(intptr_t)~fd;
 57}
 58
 59static __attribute__((unused))
 60FILE *fopen(const char *pathname, const char *mode)
 61{
 62	int flags, fd;
 63
 64	switch (*mode) {
 65	case 'r':
 66		flags = O_RDONLY;
 67		break;
 68	case 'w':
 69		flags = O_WRONLY | O_CREAT | O_TRUNC;
 70		break;
 71	case 'a':
 72		flags = O_WRONLY | O_CREAT | O_APPEND;
 73		break;
 74	default:
 75		SET_ERRNO(EINVAL); return NULL;
 76	}
 77
 78	if (mode[1] == '+')
 79		flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
 80
 81	fd = open(pathname, flags, 0666);
 82	return fdopen(fd, mode);
 83}
 84
 85/* provides the fd of stream. */
 86static __attribute__((unused))
 87int fileno(FILE *stream)
 88{
 89	intptr_t i = (intptr_t)stream;
 90
 91	if (i >= 0) {
 92		SET_ERRNO(EBADF);
 93		return -1;
 94	}
 95	return ~i;
 96}
 97
 98/* flush a stream. */
 99static __attribute__((unused))
100int fflush(FILE *stream)
101{
102	intptr_t i = (intptr_t)stream;
103
104	/* NULL is valid here. */
105	if (i > 0) {
106		SET_ERRNO(EBADF);
107		return -1;
108	}
109
110	/* Don't do anything, nolibc does not support buffering. */
111	return 0;
112}
113
114/* flush a stream. */
115static __attribute__((unused))
116int fclose(FILE *stream)
117{
118	intptr_t i = (intptr_t)stream;
119
120	if (i >= 0) {
121		SET_ERRNO(EBADF);
122		return -1;
123	}
124
125	if (close(~i))
126		return EOF;
127
128	return 0;
129}
130
131/* getc(), fgetc(), getchar() */
132
133#define getc(stream) fgetc(stream)
134
135static __attribute__((unused))
136int fgetc(FILE* stream)
137{
138	unsigned char ch;
139
140	if (read(fileno(stream), &ch, 1) <= 0)
141		return EOF;
142	return ch;
143}
144
145static __attribute__((unused))
146int getchar(void)
147{
148	return fgetc(stdin);
149}
150
151
152/* putc(), fputc(), putchar() */
153
154#define putc(c, stream) fputc(c, stream)
155
156static __attribute__((unused))
157int fputc(int c, FILE* stream)
158{
159	unsigned char ch = c;
160
161	if (write(fileno(stream), &ch, 1) <= 0)
162		return EOF;
163	return ch;
164}
165
166static __attribute__((unused))
167int putchar(int c)
168{
169	return fputc(c, stdout);
170}
171
172
173/* fwrite(), puts(), fputs(). Note that puts() emits '\n' but not fputs(). */
174
175/* internal fwrite()-like function which only takes a size and returns 0 on
176 * success or EOF on error. It automatically retries on short writes.
177 */
178static __attribute__((unused))
179int _fwrite(const void *buf, size_t size, FILE *stream)
180{
181	ssize_t ret;
182	int fd = fileno(stream);
183
184	while (size) {
185		ret = write(fd, buf, size);
186		if (ret <= 0)
187			return EOF;
188		size -= ret;
189		buf += ret;
190	}
191	return 0;
192}
193
194static __attribute__((unused))
195size_t fwrite(const void *s, size_t size, size_t nmemb, FILE *stream)
196{
197	size_t written;
198
199	for (written = 0; written < nmemb; written++) {
200		if (_fwrite(s, size, stream) != 0)
201			break;
202		s += size;
203	}
204	return written;
205}
206
207static __attribute__((unused))
208int fputs(const char *s, FILE *stream)
209{
210	return _fwrite(s, strlen(s), stream);
211}
212
213static __attribute__((unused))
214int puts(const char *s)
215{
216	if (fputs(s, stdout) == EOF)
217		return EOF;
218	return putchar('\n');
219}
220
221
222/* fgets() */
223static __attribute__((unused))
224char *fgets(char *s, int size, FILE *stream)
225{
226	int ofs;
227	int c;
228
229	for (ofs = 0; ofs + 1 < size;) {
230		c = fgetc(stream);
231		if (c == EOF)
232			break;
233		s[ofs++] = c;
234		if (c == '\n')
235			break;
236	}
237	if (ofs < size)
238		s[ofs] = 0;
239	return ofs ? s : NULL;
240}
241
242
243/* minimal printf(). It supports the following formats:
244 *  - %[l*]{d,u,c,x,p}
245 *  - %s
246 *  - unknown modifiers are ignored.
247 */
248typedef int (*__nolibc_printf_cb)(intptr_t state, const char *buf, size_t size);
249
250static __attribute__((unused, format(printf, 4, 0)))
251int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char *fmt, va_list args)
252{
253	char escape, lpref, c;
254	unsigned long long v;
255	unsigned int written, width;
256	size_t len, ofs, w;
257	char tmpbuf[21];
258	const char *outstr;
259
260	written = ofs = escape = lpref = 0;
261	while (1) {
262		c = fmt[ofs++];
263		width = 0;
264
265		if (escape) {
266			/* we're in an escape sequence, ofs == 1 */
267			escape = 0;
268
269			/* width */
270			while (c >= '0' && c <= '9') {
271				width *= 10;
272				width += c - '0';
273
274				c = fmt[ofs++];
275			}
276
277			if (c == 'c' || c == 'd' || c == 'u' || c == 'x' || c == 'p') {
278				char *out = tmpbuf;
279
280				if (c == 'p')
281					v = va_arg(args, unsigned long);
282				else if (lpref) {
283					if (lpref > 1)
284						v = va_arg(args, unsigned long long);
285					else
286						v = va_arg(args, unsigned long);
287				} else
288					v = va_arg(args, unsigned int);
289
290				if (c == 'd') {
291					/* sign-extend the value */
292					if (lpref == 0)
293						v = (long long)(int)v;
294					else if (lpref == 1)
295						v = (long long)(long)v;
296				}
297
298				switch (c) {
299				case 'c':
300					out[0] = v;
301					out[1] = 0;
302					break;
303				case 'd':
304					i64toa_r(v, out);
305					break;
306				case 'u':
307					u64toa_r(v, out);
308					break;
309				case 'p':
310					*(out++) = '0';
311					*(out++) = 'x';
312					__nolibc_fallthrough;
313				default: /* 'x' and 'p' above */
314					u64toh_r(v, out);
315					break;
316				}
317				outstr = tmpbuf;
318			}
319			else if (c == 's') {
320				outstr = va_arg(args, char *);
321				if (!outstr)
322					outstr="(null)";
323			}
324			else if (c == 'm') {
325#ifdef NOLIBC_IGNORE_ERRNO
326				outstr = "unknown error";
327#else
328				outstr = strerror(errno);
329#endif /* NOLIBC_IGNORE_ERRNO */
330			}
331			else if (c == '%') {
332				/* queue it verbatim */
333				continue;
334			}
335			else {
336				/* modifiers or final 0 */
337				if (c == 'l') {
338					/* long format prefix, maintain the escape */
339					lpref++;
340				} else if (c == 'j') {
341					lpref = 2;
342				}
343				escape = 1;
344				goto do_escape;
345			}
346			len = strlen(outstr);
347			goto flush_str;
348		}
349
350		/* not an escape sequence */
351		if (c == 0 || c == '%') {
352			/* flush pending data on escape or end */
353			escape = 1;
354			lpref = 0;
355			outstr = fmt;
356			len = ofs - 1;
357		flush_str:
358			if (n) {
359				w = len < n ? len : n;
360				n -= w;
361				while (width-- > w) {
362					if (cb(state, " ", 1) != 0)
363						return -1;
364					written += 1;
365				}
366				if (cb(state, outstr, w) != 0)
367					return -1;
368			}
369
370			written += len;
371		do_escape:
372			if (c == 0)
373				break;
374			fmt += ofs;
375			ofs = 0;
376			continue;
377		}
378
379		/* literal char, just queue it */
380	}
381	return written;
382}
383
384static int __nolibc_fprintf_cb(intptr_t state, const char *buf, size_t size)
385{
386	return _fwrite(buf, size, (FILE *)state);
387}
388
389static __attribute__((unused, format(printf, 2, 0)))
390int vfprintf(FILE *stream, const char *fmt, va_list args)
391{
392	return __nolibc_printf(__nolibc_fprintf_cb, (intptr_t)stream, SIZE_MAX, fmt, args);
393}
394
395static __attribute__((unused, format(printf, 1, 0)))
396int vprintf(const char *fmt, va_list args)
397{
398	return vfprintf(stdout, fmt, args);
399}
400
401static __attribute__((unused, format(printf, 2, 3)))
402int fprintf(FILE *stream, const char *fmt, ...)
403{
404	va_list args;
405	int ret;
406
407	va_start(args, fmt);
408	ret = vfprintf(stream, fmt, args);
409	va_end(args);
410	return ret;
411}
412
413static __attribute__((unused, format(printf, 1, 2)))
414int printf(const char *fmt, ...)
415{
416	va_list args;
417	int ret;
418
419	va_start(args, fmt);
420	ret = vfprintf(stdout, fmt, args);
421	va_end(args);
422	return ret;
423}
424
425static __attribute__((unused, format(printf, 2, 0)))
426int vdprintf(int fd, const char *fmt, va_list args)
427{
428	FILE *stream;
429
430	stream = fdopen(fd, NULL);
431	if (!stream)
432		return -1;
433	/* Technically 'stream' is leaked, but as it's only a wrapper around 'fd' that is fine */
434	return vfprintf(stream, fmt, args);
435}
436
437static __attribute__((unused, format(printf, 2, 3)))
438int dprintf(int fd, const char *fmt, ...)
439{
440	va_list args;
441	int ret;
442
443	va_start(args, fmt);
444	ret = vdprintf(fd, fmt, args);
445	va_end(args);
446
447	return ret;
448}
449
450static int __nolibc_sprintf_cb(intptr_t _state, const char *buf, size_t size)
451{
452	char **state = (char **)_state;
453
454	memcpy(*state, buf, size);
455	*state += size;
456	return 0;
457}
458
459static __attribute__((unused, format(printf, 3, 0)))
460int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
461{
462	char *state = buf;
463	int ret;
464
465	ret = __nolibc_printf(__nolibc_sprintf_cb, (intptr_t)&state, size, fmt, args);
466	if (ret < 0)
467		return ret;
468	buf[(size_t)ret < size ? (size_t)ret : size - 1] = '\0';
469	return ret;
470}
471
472static __attribute__((unused, format(printf, 3, 4)))
473int snprintf(char *buf, size_t size, const char *fmt, ...)
474{
475	va_list args;
476	int ret;
477
478	va_start(args, fmt);
479	ret = vsnprintf(buf, size, fmt, args);
480	va_end(args);
481
482	return ret;
483}
484
485static __attribute__((unused, format(printf, 2, 0)))
486int vsprintf(char *buf, const char *fmt, va_list args)
487{
488	return vsnprintf(buf, SIZE_MAX, fmt, args);
489}
490
491static __attribute__((unused, format(printf, 2, 3)))
492int sprintf(char *buf, const char *fmt, ...)
493{
494	va_list args;
495	int ret;
496
497	va_start(args, fmt);
498	ret = vsprintf(buf, fmt, args);
499	va_end(args);
500
501	return ret;
502}
503
504static __attribute__((unused))
505int vsscanf(const char *str, const char *format, va_list args)
506{
507	uintmax_t uval;
508	intmax_t ival;
509	int base;
510	char *endptr;
511	int matches;
512	int lpref;
513
514	matches = 0;
515
516	while (1) {
517		if (*format == '%') {
518			/* start of pattern */
519			lpref = 0;
520			format++;
521
522			if (*format == 'l') {
523				/* same as in printf() */
524				lpref = 1;
525				format++;
526				if (*format == 'l') {
527					lpref = 2;
528					format++;
529				}
530			}
531
532			if (*format == '%') {
533				/* literal % */
534				if ('%' != *str)
535					goto done;
536				str++;
537				format++;
538				continue;
539			} else if (*format == 'd') {
540				ival = strtoll(str, &endptr, 10);
541				if (lpref == 0)
542					*va_arg(args, int *) = ival;
543				else if (lpref == 1)
544					*va_arg(args, long *) = ival;
545				else if (lpref == 2)
546					*va_arg(args, long long *) = ival;
547			} else if (*format == 'u' || *format == 'x' || *format == 'X') {
548				base = *format == 'u' ? 10 : 16;
549				uval = strtoull(str, &endptr, base);
550				if (lpref == 0)
551					*va_arg(args, unsigned int *) = uval;
552				else if (lpref == 1)
553					*va_arg(args, unsigned long *) = uval;
554				else if (lpref == 2)
555					*va_arg(args, unsigned long long *) = uval;
556			} else if (*format == 'p') {
557				*va_arg(args, void **) = (void *)strtoul(str, &endptr, 16);
558			} else {
559				SET_ERRNO(EILSEQ);
560				goto done;
561			}
562
563			format++;
564			str = endptr;
565			matches++;
566
567		} else if (*format == '\0') {
568			goto done;
569		} else if (isspace(*format)) {
570			/* skip spaces in format and str */
571			while (isspace(*format))
572				format++;
573			while (isspace(*str))
574				str++;
575		} else if (*format == *str) {
576			/* literal match */
577			format++;
578			str++;
579		} else {
580			if (!matches)
581				matches = EOF;
582			goto done;
583		}
584	}
585
586done:
587	return matches;
588}
589
590static __attribute__((unused, format(scanf, 2, 3)))
591int sscanf(const char *str, const char *format, ...)
592{
593	va_list args;
594	int ret;
595
596	va_start(args, format);
597	ret = vsscanf(str, format, args);
598	va_end(args);
599	return ret;
600}
601
602static __attribute__((unused))
603void perror(const char *msg)
604{
605#ifdef NOLIBC_IGNORE_ERRNO
606	fprintf(stderr, "%s%sunknown error\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "");
607#else
608	fprintf(stderr, "%s%serrno=%d\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "", errno);
609#endif
610}
611
612static __attribute__((unused))
613int setvbuf(FILE *stream __attribute__((unused)),
614	    char *buf __attribute__((unused)),
615	    int mode,
616	    size_t size __attribute__((unused)))
617{
618	/*
619	 * nolibc does not support buffering so this is a nop. Just check mode
620	 * is valid as required by the spec.
621	 */
622	switch (mode) {
623	case _IOFBF:
624	case _IOLBF:
625	case _IONBF:
626		break;
627	default:
628		return EOF;
629	}
630
631	return 0;
632}
633
634static __attribute__((unused))
635const char *strerror(int errno)
636{
637	static char buf[18] = "errno=";
638
639	i64toa_r(errno, &buf[6]);
640
641	return buf;
642}
643
644#endif /* _NOLIBC_STDIO_H */
~/ Read-only file preview.