Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
0002 /*
0003  * minimal stdio function definitions for NOLIBC
0004  * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
0005  */
0006 
0007 #ifndef _NOLIBC_STDIO_H
0008 #define _NOLIBC_STDIO_H
0009 
0010 #include <stdarg.h>
0011 
0012 #include "std.h"
0013 #include "arch.h"
0014 #include "errno.h"
0015 #include "types.h"
0016 #include "sys.h"
0017 #include "stdlib.h"
0018 #include "string.h"
0019 
0020 #ifndef EOF
0021 #define EOF (-1)
0022 #endif
0023 
0024 /* just define FILE as a non-empty type */
0025 typedef struct FILE {
0026     char dummy[1];
0027 } FILE;
0028 
0029 /* We define the 3 common stdio files as constant invalid pointers that
0030  * are easily recognized.
0031  */
0032 static __attribute__((unused)) FILE* const stdin  = (FILE*)-3;
0033 static __attribute__((unused)) FILE* const stdout = (FILE*)-2;
0034 static __attribute__((unused)) FILE* const stderr = (FILE*)-1;
0035 
0036 /* getc(), fgetc(), getchar() */
0037 
0038 #define getc(stream) fgetc(stream)
0039 
0040 static __attribute__((unused))
0041 int fgetc(FILE* stream)
0042 {
0043     unsigned char ch;
0044     int fd;
0045 
0046     if (stream < stdin || stream > stderr)
0047         return EOF;
0048 
0049     fd = 3 + (long)stream;
0050 
0051     if (read(fd, &ch, 1) <= 0)
0052         return EOF;
0053     return ch;
0054 }
0055 
0056 static __attribute__((unused))
0057 int getchar(void)
0058 {
0059     return fgetc(stdin);
0060 }
0061 
0062 
0063 /* putc(), fputc(), putchar() */
0064 
0065 #define putc(c, stream) fputc(c, stream)
0066 
0067 static __attribute__((unused))
0068 int fputc(int c, FILE* stream)
0069 {
0070     unsigned char ch = c;
0071     int fd;
0072 
0073     if (stream < stdin || stream > stderr)
0074         return EOF;
0075 
0076     fd = 3 + (long)stream;
0077 
0078     if (write(fd, &ch, 1) <= 0)
0079         return EOF;
0080     return ch;
0081 }
0082 
0083 static __attribute__((unused))
0084 int putchar(int c)
0085 {
0086     return fputc(c, stdout);
0087 }
0088 
0089 
0090 /* fwrite(), puts(), fputs(). Note that puts() emits '\n' but not fputs(). */
0091 
0092 /* internal fwrite()-like function which only takes a size and returns 0 on
0093  * success or EOF on error. It automatically retries on short writes.
0094  */
0095 static __attribute__((unused))
0096 int _fwrite(const void *buf, size_t size, FILE *stream)
0097 {
0098     ssize_t ret;
0099     int fd;
0100 
0101     if (stream < stdin || stream > stderr)
0102         return EOF;
0103 
0104     fd = 3 + (long)stream;
0105 
0106     while (size) {
0107         ret = write(fd, buf, size);
0108         if (ret <= 0)
0109             return EOF;
0110         size -= ret;
0111         buf += ret;
0112     }
0113     return 0;
0114 }
0115 
0116 static __attribute__((unused))
0117 size_t fwrite(const void *s, size_t size, size_t nmemb, FILE *stream)
0118 {
0119     size_t written;
0120 
0121     for (written = 0; written < nmemb; written++) {
0122         if (_fwrite(s, size, stream) != 0)
0123             break;
0124         s += size;
0125     }
0126     return written;
0127 }
0128 
0129 static __attribute__((unused))
0130 int fputs(const char *s, FILE *stream)
0131 {
0132     return _fwrite(s, strlen(s), stream);
0133 }
0134 
0135 static __attribute__((unused))
0136 int puts(const char *s)
0137 {
0138     if (fputs(s, stdout) == EOF)
0139         return EOF;
0140     return putchar('\n');
0141 }
0142 
0143 
0144 /* fgets() */
0145 static __attribute__((unused))
0146 char *fgets(char *s, int size, FILE *stream)
0147 {
0148     int ofs;
0149     int c;
0150 
0151     for (ofs = 0; ofs + 1 < size;) {
0152         c = fgetc(stream);
0153         if (c == EOF)
0154             break;
0155         s[ofs++] = c;
0156         if (c == '\n')
0157             break;
0158     }
0159     if (ofs < size)
0160         s[ofs] = 0;
0161     return ofs ? s : NULL;
0162 }
0163 
0164 
0165 /* minimal vfprintf(). It supports the following formats:
0166  *  - %[l*]{d,u,c,x,p}
0167  *  - %s
0168  *  - unknown modifiers are ignored.
0169  */
0170 static __attribute__((unused))
0171 int vfprintf(FILE *stream, const char *fmt, va_list args)
0172 {
0173     char escape, lpref, c;
0174     unsigned long long v;
0175     unsigned int written;
0176     size_t len, ofs;
0177     char tmpbuf[21];
0178     const char *outstr;
0179 
0180     written = ofs = escape = lpref = 0;
0181     while (1) {
0182         c = fmt[ofs++];
0183 
0184         if (escape) {
0185             /* we're in an escape sequence, ofs == 1 */
0186             escape = 0;
0187             if (c == 'c' || c == 'd' || c == 'u' || c == 'x' || c == 'p') {
0188                 char *out = tmpbuf;
0189 
0190                 if (c == 'p')
0191                     v = va_arg(args, unsigned long);
0192                 else if (lpref) {
0193                     if (lpref > 1)
0194                         v = va_arg(args, unsigned long long);
0195                     else
0196                         v = va_arg(args, unsigned long);
0197                 } else
0198                     v = va_arg(args, unsigned int);
0199 
0200                 if (c == 'd') {
0201                     /* sign-extend the value */
0202                     if (lpref == 0)
0203                         v = (long long)(int)v;
0204                     else if (lpref == 1)
0205                         v = (long long)(long)v;
0206                 }
0207 
0208                 switch (c) {
0209                 case 'c':
0210                     out[0] = v;
0211                     out[1] = 0;
0212                     break;
0213                 case 'd':
0214                     i64toa_r(v, out);
0215                     break;
0216                 case 'u':
0217                     u64toa_r(v, out);
0218                     break;
0219                 case 'p':
0220                     *(out++) = '0';
0221                     *(out++) = 'x';
0222                     /* fall through */
0223                 default: /* 'x' and 'p' above */
0224                     u64toh_r(v, out);
0225                     break;
0226                 }
0227                 outstr = tmpbuf;
0228             }
0229             else if (c == 's') {
0230                 outstr = va_arg(args, char *);
0231                 if (!outstr)
0232                     outstr="(null)";
0233             }
0234             else if (c == '%') {
0235                 /* queue it verbatim */
0236                 continue;
0237             }
0238             else {
0239                 /* modifiers or final 0 */
0240                 if (c == 'l') {
0241                     /* long format prefix, maintain the escape */
0242                     lpref++;
0243                 }
0244                 escape = 1;
0245                 goto do_escape;
0246             }
0247             len = strlen(outstr);
0248             goto flush_str;
0249         }
0250 
0251         /* not an escape sequence */
0252         if (c == 0 || c == '%') {
0253             /* flush pending data on escape or end */
0254             escape = 1;
0255             lpref = 0;
0256             outstr = fmt;
0257             len = ofs - 1;
0258         flush_str:
0259             if (_fwrite(outstr, len, stream) != 0)
0260                 break;
0261 
0262             written += len;
0263         do_escape:
0264             if (c == 0)
0265                 break;
0266             fmt += ofs;
0267             ofs = 0;
0268             continue;
0269         }
0270 
0271         /* literal char, just queue it */
0272     }
0273     return written;
0274 }
0275 
0276 static __attribute__((unused, format(printf, 2, 3)))
0277 int fprintf(FILE *stream, const char *fmt, ...)
0278 {
0279     va_list args;
0280     int ret;
0281 
0282     va_start(args, fmt);
0283     ret = vfprintf(stream, fmt, args);
0284     va_end(args);
0285     return ret;
0286 }
0287 
0288 static __attribute__((unused, format(printf, 1, 2)))
0289 int printf(const char *fmt, ...)
0290 {
0291     va_list args;
0292     int ret;
0293 
0294     va_start(args, fmt);
0295     ret = vfprintf(stdout, fmt, args);
0296     va_end(args);
0297     return ret;
0298 }
0299 
0300 static __attribute__((unused))
0301 void perror(const char *msg)
0302 {
0303     fprintf(stderr, "%s%serrno=%d\n", (msg && *msg) ? msg : "", (msg && *msg) ? ": " : "", errno);
0304 }
0305 
0306 #endif /* _NOLIBC_STDIO_H */