// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include #include #include #include #include #include "syscalls_real.hpp" #include "debug.hpp" namespace { namespace real { __REAL_DECL(ungetc); __REAL_DECL(vfscanf); } // namespace real void __attribute__((constructor)) _syscalls_scan_family() { __REAL_DLSYM(ungetc); __REAL_DLSYM(vfscanf); if (!(real::ungetc && real::vfscanf)) { abort(); } } } // namespace namespace { namespace vfs = vfsn::linux::internal; using FILEX = vfs::FILEX; using fs = purefs::fs::filesystem; int ic(FILEX *fp) { char ch; if (fp->ungetchar > 0) { ch = fp->ungetchar; fp->ungetchar = -1; return 0; } else { auto ret = vfs::invoke_fs(&fs::read, fp->fd, &ch, 1); fp->error = errno; return ret == 1 ? 0 : ret; } } int istr(FILEX *fp, char *dst, int wid) { char *d = dst; int c; while ((c = ic(fp)) != EOF && wid-- > 0 && !isspace(c)) { *d++ = c; } *d = '\0'; // ungetc(c, fp); return d == dst; } /* t is 1 for char, 2 for short, 4 for int, and 8 for long */ int iint(FILEX *fp, void *dst, int t, int wid) { long n = 0; int c; int neg = 0; c = ic(fp); if (c == '-') { neg = 1; } if ((c == '-' || c == '+') && wid-- > 0) { c = ic(fp); } if (!isdigit(c) || wid <= 0) { ungetc(c, reinterpret_cast(fp)); return 1; } do { n = n * 10 + c - '0'; } while (isdigit(c = ic(fp)) && --wid > 0); ungetc(c, reinterpret_cast(fp)); if (t == 8) { *reinterpret_cast(dst) = neg ? -n : n; } else if (t == 4) { *reinterpret_cast(dst) = neg ? -n : n; } else if (t == 2) { *reinterpret_cast(dst) = neg ? -n : n; } else { *reinterpret_cast(dst) = neg ? -n : n; } return 0; } } // namespace extern "C" { namespace vfs = vfsn::linux::internal; using FILEX = vfs::FILEX; int ungetc(int __c, FILE *__stream) { if (vfs::is_filex(__stream)) { TRACE_SYSCALLN("(%p) -> VFS", __stream); auto fx = reinterpret_cast(__stream); fx->ungetchar = __c; return 0; } else { TRACE_SYSCALLN("(%p) -> linux fs", __stream); return real::ungetc(__c, __stream); } } /* WARNING: * this implementation of ungetc() is work-in-progress * and should remain local until FILEX buffering is implemented! */ // __asm__(".symver _iosys_ungetc,ungetc@GLIBC_2.2.5"); int _iosys_vfscanf(FILE *__restrict fp, const char *__restrict fmt, __gnuc_va_list ap) { if (!vfs::is_filex(fp)) { TRACE_SYSCALLN("(%p) -> linux fs", fp); return real::vfscanf(fp, fmt, ap); } TRACE_SYSCALLN("(%p) -> VFS", fp); int ret = 0; int t, c; int wid = 1 << 20; auto fx = reinterpret_cast(fp); while (*fmt) { while (isspace(static_cast(*fmt))) { fmt++; } while (isspace(c = ic(fx))) ; ungetc(c, fp); while (*fmt && *fmt != '%' && !isspace((unsigned char)*fmt)) if (*fmt++ != ic(fx)) return ret; if (*fmt != '%') continue; fmt++; if (isdigit((unsigned char)*fmt)) { wid = 0; while (isdigit((unsigned char)*fmt)) wid = wid * 10 + *fmt++ - '0'; } t = sizeof(int); while (*fmt == 'l') { t = sizeof(long); fmt++; } while (*fmt == 'h') { t = unsigned(t) < sizeof(int) ? sizeof(char) : sizeof(short); fmt++; } switch (*fmt++) { case 'u': case 'd': if (iint((fx), va_arg(ap, long *), t, wid)) return ret; ret++; break; case 's': if (istr((fx), va_arg(ap, char *), wid)) return ret; ret++; break; } } return ret; } __asm__(".symver _iosys_vfscanf,vfscanf@GLIBC_2.2.5"); int _iosys_fscanf(FILE *__restrict fp, const char *__restrict fmt, ...) { TRACE_SYSCALLN("(%p) -> vfscanf()", fp); va_list ap; int ret; va_start(ap, fmt); ret = vfscanf(fp, fmt, ap); va_end(ap); return ret; } __asm__(".symver _iosys_fscanf,fscanf@GLIBC_2.2.5"); }