diff --git a/libretro-common/include/streams/file_stream.h b/libretro-common/include/streams/file_stream.h index 546fd12697..e10c6b3ca2 100644 --- a/libretro-common/include/streams/file_stream.h +++ b/libretro-common/include/streams/file_stream.h @@ -78,6 +78,8 @@ char *filestream_gets(RFILE *stream, char *s, size_t len); int filestream_getc(RFILE *stream); +int filestream_scanf(RFILE *stream, const char* format, ...); + int filestream_eof(RFILE *stream); bool filestream_write_file(const char *path, const void *data, int64_t size); diff --git a/libretro-common/streams/file_stream.c b/libretro-common/streams/file_stream.c index 5ccdbcfacb..b5d54b6223 100644 --- a/libretro-common/streams/file_stream.c +++ b/libretro-common/streams/file_stream.c @@ -191,6 +191,102 @@ int filestream_getc(RFILE *stream) return EOF; } +int filestream_scanf(RFILE *stream, const char* format, ...) +{ + char buf[4096]; + char subfmt[64]; + + const char * bufiter = buf; + + int64_t startpos = filestream_tell(stream); + + va_list args; + + int ret = 0; + + int maxlen = filestream_read(stream, buf, sizeof(buf)-1); + buf[maxlen] = '\0'; + + va_start(args, format); + + while (*format) + { + if (*format == '%') + { + char* subfmtiter = subfmt; + + int subret; + int sublen; + + bool asterisk = false; + + *subfmtiter++ = *format++; /* '%' */ + + /* %[*][width][length]specifier */ + + if (*format == '*') + { + asterisk = true; + *subfmtiter++ = *format++; + } + + while (isdigit(*format)) *subfmtiter++ = *format++; /* width */ + + /* length */ + if (*format == 'h' || *format == 'l') + { + if (format[1] == format[0]) *subfmtiter++ = *format++; + *subfmtiter++ = *format++; + } + else if (*format == 'j' || *format == 'z' || *format == 't' || *format == 'L') + { + *subfmtiter++ = *format++; + } + + /* specifier - always a single character (except ]) */ + if (*format == '[') + { + while (*format != ']') *subfmtiter++ = *format++; + *subfmtiter++ = *format++; + } + else *subfmtiter++ = *format++; + + *subfmtiter++ = '%'; + *subfmtiter++ = 'n'; + *subfmtiter++ = '\0'; + + if (sizeof(void*) != sizeof(long*)) abort(); /* all pointers must have the same size */ + if (asterisk) + { + if (sscanf(bufiter, subfmt, &sublen) != 0) break; + } + else + { + if (sscanf(bufiter, subfmt, va_arg(args, void*), &sublen) != 1) break; + } + + ret++; + bufiter += sublen; + } + else if (isspace(*format)) + { + while (isspace(*bufiter)) bufiter++; + format++; + } + else + { + if (*bufiter != *format) break; + bufiter++; + format++; + } + } + + va_end(args); + filestream_seek(stream, startpos+(bufiter-buf), RETRO_VFS_SEEK_POSITION_START); + + return ret; +} + int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position) { int64_t output;