mirror of
https://github.com/PodeCaradox/GalaxyQuest-SteamFrame.git
synced 2026-10-24 13:01:35 +02:00
The sources of Petari (https://github.com/SMGCommunity/Petari), the Super Mario Galaxy decompilation by the SMGCommunity, at commit 0a5c6608dc3b4c44a9aa68c2535d1793dc565f02, unchanged but for LF line endings: LICENSE (as LICENSE-Petari.txt; CC0 1.0), include/, libs/ and src/. Left out: the game data Petari keeps from the original executable, the error message archive (include/Game/System/ ErrorArchive.hpp) and two tables (src/Game/System/GalaxyID.bcsv and StoryEvent.bcsv); GalaxyQuest's converter takes them from the player's own disc. The port's changes follow in the next commit, so `git diff petari-base -- decomp` shows them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
807 lines
19 KiB
C
807 lines
19 KiB
C
#include "stdarg.h"
|
|
#include "stdio_api.h"
|
|
#include "va_list.h"
|
|
#include <cctype>
|
|
#include <cmath>
|
|
|
|
enum argument_options {
|
|
normal_argument,
|
|
char_argument,
|
|
short_argument,
|
|
long_argument,
|
|
intmax_argument,
|
|
size_t_argument,
|
|
ptrdiff_argument,
|
|
long_long_argument,
|
|
double_argument,
|
|
long_double_argument,
|
|
wchar_argument
|
|
};
|
|
|
|
typedef long long intmax_t;
|
|
#define PTRDIFF __typeof__((char*)0-(char*)0)
|
|
typedef PTRDIFF ptrdiff_t;
|
|
|
|
#define conversion_buff_size 512
|
|
#define conversion_max 509
|
|
#define bad_conversion 0xFF
|
|
typedef size_t rsize_t;
|
|
|
|
#define EOF -1L
|
|
|
|
typedef unsigned char char_map[32];
|
|
|
|
extern long double __strtold(int max_width, int (*ReadProc)(void *, int, int), void* ReadProcArg, int* chars_scanned, int* overflow);
|
|
extern unsigned long long __strtoull(int base, int max_width, int (*ReadProc)(void *, int, int), void *ReadProcArg, int* chars_scanned, int* negative, int* overflow);
|
|
extern unsigned long __strtoul(int base, int max_width, int (*ReadProc)(void *, int, int), void *ReadProcArg, int* chars_scanned, int* negative, int* overflow);
|
|
|
|
int mbtowc(wchar_t *pDest, const char *s, size_t num);
|
|
|
|
typedef struct {
|
|
unsigned char suppress_assignment;
|
|
unsigned char field_width_specified;
|
|
unsigned char argument_options;
|
|
unsigned char conversion_char;
|
|
int field_width;
|
|
char_map char_set;
|
|
} scan_format;
|
|
|
|
#define set_char_map(map, ch) map[(unsigned char)ch >> 3] |= (1 << (ch & 7))
|
|
#define tst_char_map(map, ch) (map[(unsigned char)ch >> 3] & (1 << (ch & 7)))
|
|
|
|
const char* parse_format(const char* format_string, scan_format *format) {
|
|
const char* s = format_string;
|
|
int c;
|
|
int flag_found, invert;
|
|
scan_format f = { 0, 0, normal_argument, 0, 2147483647, { 0 } };
|
|
|
|
if (((c = *++s) == '%')) {
|
|
f.conversion_char = c;
|
|
*format = f;
|
|
return ((const char*)s + 1);
|
|
}
|
|
|
|
if (c == '*') {
|
|
f.suppress_assignment = 1;
|
|
c = *++s;
|
|
}
|
|
|
|
if (isdigit(c)) {
|
|
f.field_width = 0;
|
|
|
|
do {
|
|
f.field_width = (f.field_width * 10) + (c - '0');
|
|
c = *++s;
|
|
} while (isdigit(c));
|
|
|
|
if (f.field_width == 0) {
|
|
f.conversion_char = 0xFF;
|
|
*format = f;
|
|
return ((const char*)s + 1);
|
|
}
|
|
|
|
f.field_width_specified = 1;
|
|
}
|
|
|
|
flag_found = 1;
|
|
|
|
switch (c) {
|
|
case 'h':
|
|
f.argument_options = short_argument;
|
|
|
|
if (s[1] == 'h') {
|
|
f.argument_options = char_argument;
|
|
c = *++s;
|
|
}
|
|
|
|
break;
|
|
case 'l':
|
|
f.argument_options = long_argument;
|
|
|
|
if (s[1] == 'l') {
|
|
f.argument_options = long_long_argument;
|
|
c = *++s;
|
|
}
|
|
|
|
break;
|
|
case 'L':
|
|
f.argument_options = long_double_argument;
|
|
break;
|
|
|
|
case 'j':
|
|
f.argument_options = intmax_argument;
|
|
break;
|
|
case 'z':
|
|
f.argument_options = size_t_argument;
|
|
break;
|
|
case 't':
|
|
f.argument_options = ptrdiff_argument;
|
|
break;
|
|
default:
|
|
flag_found = 0;
|
|
}
|
|
|
|
if (flag_found) {
|
|
c = *++s;
|
|
}
|
|
|
|
f.conversion_char = c;
|
|
|
|
switch (c) {
|
|
case 'd':
|
|
case 'i':
|
|
case 'u':
|
|
case 'o':
|
|
case 'x':
|
|
case 'X':
|
|
if (f.argument_options == long_double_argument) {
|
|
f.conversion_char = 0xFF;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
case 'a':
|
|
case 'A':
|
|
case 'f':
|
|
case 'F':
|
|
case 'e':
|
|
case 'E':
|
|
case 'g':
|
|
case 'G':
|
|
if (f.argument_options == char_argument || f.argument_options == short_argument || f.argument_options == intmax_argument || f.argument_options == size_t_argument || f.argument_options == ptrdiff_argument || f.argument_options == long_long_argument) {
|
|
f.conversion_char = 0xFF;
|
|
break;
|
|
}
|
|
|
|
if (f.argument_options == long_argument) {
|
|
f.argument_options = double_argument;
|
|
}
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
f.argument_options = long_argument;
|
|
f.conversion_char = 'x';
|
|
break;
|
|
|
|
case 'c':
|
|
if (f.argument_options == long_argument) {
|
|
f.argument_options = wchar_argument;
|
|
}
|
|
else {
|
|
if (f.argument_options != normal_argument) {
|
|
f.conversion_char = 0xFF;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case 's':
|
|
if (f.argument_options == long_argument) {
|
|
f.argument_options = wchar_argument;
|
|
}
|
|
else {
|
|
if (f.argument_options != normal_argument) {
|
|
f.conversion_char = 0xFF;
|
|
}
|
|
}
|
|
|
|
{
|
|
int i;
|
|
unsigned char* p;
|
|
|
|
for (i = sizeof(f.char_set), p = f.char_set; i; --i) {
|
|
*p++ = 0xFF;
|
|
}
|
|
|
|
f.char_set[1] = 0xC1;
|
|
f.char_set[4] = 0xFE;
|
|
}
|
|
|
|
break;
|
|
|
|
case 'n':
|
|
break;
|
|
|
|
case '[':
|
|
if (f.argument_options == long_argument) {
|
|
f.argument_options = wchar_argument;
|
|
}
|
|
else {
|
|
if (f.argument_options != normal_argument) {
|
|
f.conversion_char = 0xFF;
|
|
}
|
|
}
|
|
|
|
c = *++s;
|
|
invert = 0;
|
|
|
|
if (c == '^') {
|
|
invert = 1;
|
|
c = *++s;
|
|
}
|
|
|
|
if (c == ']') {
|
|
set_char_map(f.char_set, ']');
|
|
c = *++s;
|
|
}
|
|
|
|
while (c && c != ']') {
|
|
int d;
|
|
set_char_map(f.char_set, c);
|
|
|
|
if (*(s + 1) == '-' && (d = *(s + 2)) != 0 && d != ']') {
|
|
while (++c <= d) {
|
|
set_char_map(f.char_set, c);
|
|
}
|
|
|
|
c = *(s += 3);
|
|
}
|
|
else {
|
|
c = *++s;
|
|
}
|
|
}
|
|
|
|
if (!c) {
|
|
f.conversion_char = 0xFF;
|
|
break;
|
|
}
|
|
|
|
if (invert) {
|
|
int i;
|
|
unsigned char* p;
|
|
|
|
for (i = sizeof(f.char_set), p = f.char_set; i; --i, ++p) {
|
|
*p = ~*p;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
f.conversion_char = 0xFF;
|
|
break;
|
|
}
|
|
|
|
*format = f;
|
|
return ((const char*)s + 1);
|
|
}
|
|
|
|
|
|
int __StringRead(void *pPtr, int ch, int act) {
|
|
char ret;
|
|
__InStrCtrl* Iscp = (__InStrCtrl*)pPtr;
|
|
|
|
switch (act) {
|
|
case __GetAChar:
|
|
ret = *(Iscp->NextChar);
|
|
|
|
if (ret == '\0') {
|
|
Iscp->NullCharDetected = 1;
|
|
return -1;
|
|
}
|
|
else {
|
|
Iscp->NextChar++;
|
|
return (unsigned char)ret;
|
|
}
|
|
|
|
case __UngetAChar:
|
|
if (Iscp->NullCharDetected == 0) {
|
|
Iscp->NextChar--;
|
|
}
|
|
else {
|
|
Iscp->NullCharDetected = 0;
|
|
}
|
|
|
|
return ch;
|
|
|
|
case __TestForError:
|
|
return Iscp->NullCharDetected;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int __sformatter(int (*ReadProc)(void *, int, int), void * ReadProcArg, const char * format_str, va_list arg, int is_secure)
|
|
{
|
|
int num_chars, chars_read, items_assigned, conversions;
|
|
int base, negative, overflow;
|
|
int rval;
|
|
const char* format_ptr;
|
|
char format_char;
|
|
char c;
|
|
scan_format format;
|
|
long long_num;
|
|
unsigned long u_long_num;
|
|
long long long_long_num = 0;
|
|
unsigned long long u_long_long_num;
|
|
long double long_double_num;
|
|
char* arg_ptr;
|
|
int elem_valid;
|
|
size_t elem_maxsize;
|
|
int match_failure = 0;
|
|
int terminate = 0;
|
|
|
|
format_ptr = format_str;
|
|
chars_read = 0;
|
|
items_assigned = 0;
|
|
conversions = 0;
|
|
|
|
while (!terminate && (format_char = *format_ptr) != 0) {
|
|
if (isspace(format_char)) {
|
|
do {
|
|
format_char = *++format_ptr;
|
|
}
|
|
while (isspace(format_char));
|
|
|
|
if (!match_failure) {
|
|
while (isspace(c = (*ReadProc)(ReadProcArg, 0, __GetAChar))) {
|
|
++chars_read;
|
|
}
|
|
|
|
(*ReadProc)(ReadProcArg, c, __UngetAChar);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if ((format_char != '%') && (!match_failure)) {
|
|
if ((c = (*ReadProc)(ReadProcArg, 0, __GetAChar)) != (unsigned char)format_char) {
|
|
(*ReadProc)(ReadProcArg, c, __UngetAChar);
|
|
if (!is_secure) {
|
|
goto exit;
|
|
}
|
|
else {
|
|
match_failure = 1;
|
|
++format_ptr;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
++chars_read;
|
|
++format_ptr;
|
|
|
|
continue;
|
|
}
|
|
|
|
format_ptr = parse_format(format_ptr, &format);
|
|
if (!format.suppress_assignment && format.conversion_char != '%') {
|
|
arg_ptr = va_arg(arg, char *);
|
|
}
|
|
else {
|
|
arg_ptr = 0;
|
|
}
|
|
|
|
if ((format.conversion_char != 'n') && (!match_failure) && (*ReadProc)(ReadProcArg, 0, __TestForError)) {
|
|
if (!is_secure) {
|
|
goto exit;
|
|
}
|
|
else {
|
|
match_failure = 1;
|
|
}
|
|
}
|
|
|
|
switch (format.conversion_char) {
|
|
case 'd':
|
|
base = 10;
|
|
goto signed_int;
|
|
|
|
case 'i':
|
|
base = 0;
|
|
|
|
signed_int:
|
|
if (match_failure) {
|
|
long_num = 0;
|
|
long_long_num = 0;
|
|
}
|
|
else {
|
|
if ((format.argument_options == long_long_argument) || (format.argument_options == intmax_argument)) {
|
|
u_long_long_num = __strtoull(base, format.field_width, ReadProc, ReadProcArg, &num_chars, &negative, &overflow);
|
|
}
|
|
else {
|
|
u_long_num = __strtoul(base, format.field_width, ReadProc, ReadProcArg, &num_chars, &negative, &overflow);
|
|
}
|
|
|
|
if (!num_chars) {
|
|
if (!is_secure) {
|
|
goto exit;
|
|
}
|
|
else {
|
|
match_failure = 1;
|
|
long_num = 0;
|
|
long_long_num = 0;
|
|
goto signed_int_assign;
|
|
}
|
|
}
|
|
|
|
chars_read += num_chars;
|
|
|
|
if ((format.argument_options == long_long_argument) || (format.argument_options == intmax_argument)) {
|
|
long_long_num = (negative ? -u_long_long_num : u_long_long_num);
|
|
}
|
|
else {
|
|
long_num = (negative ? -u_long_num : u_long_num);
|
|
}
|
|
}
|
|
|
|
signed_int_assign:
|
|
if (arg_ptr) {
|
|
switch (format.argument_options) {
|
|
case normal_argument: * (int *) arg_ptr = long_num; break;
|
|
case char_argument: * (signed char *) arg_ptr = long_num; break;
|
|
case short_argument: * (short *) arg_ptr = long_num; break;
|
|
case long_argument: * (long *) arg_ptr = long_num; break;
|
|
case intmax_argument: * (intmax_t *) arg_ptr = long_long_num; break;
|
|
case size_t_argument: * (size_t *) arg_ptr = long_num; break;
|
|
case ptrdiff_argument: * (ptrdiff_t *) arg_ptr = long_num; break;
|
|
case long_long_argument: * (long long *) arg_ptr = long_long_num; break;
|
|
}
|
|
if (!match_failure) {
|
|
++items_assigned;
|
|
}
|
|
}
|
|
|
|
++conversions;
|
|
break;
|
|
|
|
case 'o':
|
|
base = 8;
|
|
goto unsigned_int;
|
|
|
|
case 'u':
|
|
base = 10;
|
|
goto unsigned_int;
|
|
|
|
case 'x':
|
|
case 'X':
|
|
base = 16;
|
|
|
|
unsigned_int:
|
|
|
|
if (match_failure) {
|
|
u_long_num = 0;
|
|
u_long_long_num = 0;
|
|
}
|
|
else {
|
|
if ((format.argument_options == long_long_argument) || (format.argument_options == intmax_argument)) {
|
|
u_long_long_num = __strtoull(base, format.field_width, ReadProc, ReadProcArg, &num_chars, &negative, &overflow);
|
|
}
|
|
else {
|
|
u_long_num = __strtoul(base, format.field_width, ReadProc, ReadProcArg, &num_chars, &negative, &overflow);
|
|
}
|
|
|
|
if (!num_chars) {
|
|
if (!is_secure) {
|
|
goto exit;
|
|
}
|
|
else {
|
|
match_failure = 1;
|
|
u_long_num = 0;
|
|
u_long_long_num = 0;
|
|
goto unsigned_int_assign;
|
|
}
|
|
}
|
|
|
|
chars_read += num_chars;
|
|
|
|
if (negative)
|
|
if (format.argument_options == long_long_argument)
|
|
u_long_long_num = -u_long_long_num;
|
|
else
|
|
|
|
u_long_num = -u_long_num;
|
|
}
|
|
|
|
unsigned_int_assign:
|
|
if (arg_ptr) {
|
|
switch (format.argument_options) {
|
|
case normal_argument: * (unsigned int *) arg_ptr = u_long_num; break;
|
|
case char_argument: * (unsigned char *) arg_ptr = u_long_num; break;
|
|
case short_argument: * (unsigned short *) arg_ptr = u_long_num; break;
|
|
case long_argument: * (unsigned long *) arg_ptr = u_long_num; break;
|
|
case intmax_argument: * (intmax_t *) arg_ptr = u_long_long_num; break;
|
|
case size_t_argument: * (size_t *) arg_ptr = u_long_num; break;
|
|
case ptrdiff_argument: * (ptrdiff_t *) arg_ptr = u_long_num; break;
|
|
case long_long_argument: * (unsigned long long *) arg_ptr = u_long_long_num; break;
|
|
}
|
|
|
|
if (!match_failure) {
|
|
++items_assigned;
|
|
}
|
|
}
|
|
|
|
++conversions;
|
|
|
|
break;
|
|
|
|
case 'a':
|
|
case 'A':
|
|
case 'f':
|
|
case 'F':
|
|
case 'e':
|
|
case 'E':
|
|
case 'g':
|
|
case 'G':
|
|
flt:
|
|
if (match_failure) {
|
|
long_double_num = NAN;
|
|
}
|
|
else {
|
|
long_double_num = __strtold(format.field_width, ReadProc, ReadProcArg, &num_chars, &overflow);
|
|
|
|
if (!num_chars) {
|
|
if (!is_secure) {
|
|
goto exit;
|
|
}
|
|
else {
|
|
match_failure = 1;
|
|
long_double_num = NAN;
|
|
goto assign_float;
|
|
}
|
|
}
|
|
|
|
chars_read += num_chars;
|
|
}
|
|
|
|
assign_float:
|
|
if (arg_ptr) {
|
|
switch (format.argument_options) {
|
|
case normal_argument: * (float *) arg_ptr = long_double_num; break;
|
|
case double_argument: * (double *) arg_ptr = long_double_num; break;
|
|
case long_double_argument: * (long double *) arg_ptr = long_double_num; break;
|
|
}
|
|
|
|
if (!match_failure) {
|
|
++items_assigned;
|
|
}
|
|
}
|
|
|
|
++conversions;
|
|
|
|
break;
|
|
case 'c':
|
|
if (!format.field_width_specified) {
|
|
format.field_width = 1;
|
|
}
|
|
|
|
|
|
if (arg_ptr) {
|
|
if (is_secure) {
|
|
elem_valid = 1;
|
|
elem_maxsize = va_arg(arg, rsize_t);
|
|
}
|
|
|
|
num_chars = 0;
|
|
|
|
if (match_failure) {
|
|
if (elem_maxsize > 0) {
|
|
*arg_ptr = 0;
|
|
}
|
|
continue;
|
|
}
|
|
else {
|
|
char* arg_start = arg_ptr;
|
|
while (format.field_width-- &&
|
|
(!is_secure || ((elem_valid = (elem_maxsize > num_chars)) != 0)) &&
|
|
((rval = ((*ReadProc)(ReadProcArg, 0, __GetAChar))) != EOF))
|
|
{
|
|
c = rval;
|
|
if (format.argument_options == wchar_argument) {
|
|
mbtowc(((wchar_t*)arg_ptr), (char*)(&c), 1);
|
|
arg_ptr += sizeof(wchar_t);
|
|
}
|
|
else {
|
|
*arg_ptr++ = c;
|
|
}
|
|
++num_chars;
|
|
}
|
|
|
|
c = rval;
|
|
if (!num_chars || (is_secure && !elem_valid)) {
|
|
if (!is_secure) {
|
|
goto exit;
|
|
}
|
|
else {
|
|
match_failure = 1;
|
|
if (elem_maxsize > 0) {
|
|
*arg_start = 0;
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
|
|
chars_read += num_chars;
|
|
++items_assigned;
|
|
}
|
|
}
|
|
else {
|
|
num_chars = 0;
|
|
|
|
while (format.field_width-- &&
|
|
((rval = ((*ReadProc)(ReadProcArg, 0, __GetAChar))) != EOF))
|
|
{
|
|
c = rval;
|
|
++num_chars;
|
|
}
|
|
c = rval;
|
|
if (!num_chars) {
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
++conversions;
|
|
break;
|
|
|
|
case '%':
|
|
if (match_failure) {
|
|
continue;
|
|
}
|
|
else {
|
|
while (isspace(c = (*ReadProc)(ReadProcArg, 0, __GetAChar)))
|
|
++chars_read;
|
|
|
|
if (c != '%') {
|
|
(*ReadProc)(ReadProcArg, c, __UngetAChar);
|
|
if (!is_secure) {
|
|
goto exit;
|
|
}
|
|
else {
|
|
match_failure = 1;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
++chars_read;
|
|
}
|
|
break;
|
|
|
|
case 's':
|
|
if (!match_failure) {
|
|
c = (*ReadProc)(ReadProcArg, 0, __GetAChar);
|
|
while(isspace(c)) {
|
|
++chars_read;
|
|
c = (*ReadProc)(ReadProcArg, 0, __GetAChar);
|
|
}
|
|
|
|
(*ReadProc)(ReadProcArg, c, __UngetAChar);
|
|
}
|
|
case '[':
|
|
if (arg_ptr) {
|
|
if (is_secure) {
|
|
elem_valid = 1;
|
|
elem_maxsize = va_arg(arg, rsize_t) - 1;
|
|
}
|
|
|
|
num_chars = 0;
|
|
|
|
if (match_failure) {
|
|
if (elem_maxsize > 0) {
|
|
*arg_ptr = 0;
|
|
}
|
|
continue;
|
|
}
|
|
else {
|
|
char* arg_start = arg_ptr;
|
|
|
|
while (format.field_width-- &&
|
|
(!is_secure || ((elem_valid = (elem_maxsize >= num_chars)) != 0)) &&
|
|
((rval = ((*ReadProc)(ReadProcArg, 0, __GetAChar))) != EOF))
|
|
{
|
|
c = rval;
|
|
|
|
if (!tst_char_map(format.char_set, c)) {
|
|
break;
|
|
}
|
|
|
|
if (format.argument_options == wchar_argument) {
|
|
mbtowc(((wchar_t*)arg_ptr), (char*)&c, 1);
|
|
arg_ptr = (char*)((wchar_t*)arg_ptr + 1);
|
|
}
|
|
else {
|
|
*arg_ptr++ = c;
|
|
}
|
|
++num_chars;
|
|
}
|
|
c = rval;
|
|
|
|
if (!num_chars || (is_secure && !elem_valid)) {
|
|
(*ReadProc)(ReadProcArg, c, __UngetAChar);
|
|
if (!is_secure) {
|
|
goto exit;
|
|
}
|
|
else {
|
|
match_failure = 1;
|
|
if (elem_maxsize > 0) {
|
|
*arg_start = 0;
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
|
|
chars_read += num_chars;
|
|
|
|
if (format.argument_options == wchar_argument) {
|
|
*(wchar_t*)arg_ptr = L'\0';
|
|
}
|
|
else {
|
|
*arg_ptr = 0;
|
|
}
|
|
|
|
++items_assigned;
|
|
}
|
|
}
|
|
else {
|
|
num_chars = 0;
|
|
|
|
while (format.field_width-- &&
|
|
((rval = ((*ReadProc)(ReadProcArg, 0, __GetAChar))) != EOF))
|
|
{
|
|
c = rval;
|
|
if (!tst_char_map(format.char_set, c)) {
|
|
break;
|
|
}
|
|
|
|
++num_chars;
|
|
}
|
|
c = rval;
|
|
|
|
if (!num_chars) {
|
|
(*ReadProc)(ReadProcArg, c, __UngetAChar);
|
|
break;
|
|
}
|
|
chars_read += num_chars;
|
|
}
|
|
|
|
if (format.field_width >= 0) {
|
|
(*ReadProc)(ReadProcArg, c, __UngetAChar);
|
|
}
|
|
|
|
++conversions;
|
|
break;
|
|
|
|
case 'n':
|
|
if (arg_ptr) {
|
|
switch (format.argument_options) {
|
|
case normal_argument: *(int *) arg_ptr = chars_read; break;
|
|
case short_argument: *(short *) arg_ptr = chars_read; break;
|
|
case long_argument: *(long *) arg_ptr = chars_read; break;
|
|
case char_argument: *(char *) arg_ptr = chars_read; break;
|
|
case long_long_argument: * (long long *) arg_ptr = chars_read; break;
|
|
}
|
|
}
|
|
|
|
continue;
|
|
|
|
case bad_conversion:
|
|
default:
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
exit:
|
|
|
|
if ((*ReadProc)(ReadProcArg, 0, __TestForError) && conversions == 0) {
|
|
return EOF;
|
|
}
|
|
|
|
return items_assigned;
|
|
}
|
|
|
|
inline int vsscanf(const char *s, const char *format, va_list arg) {
|
|
__InStrCtrl isc;
|
|
isc.NextChar = (char*)s;
|
|
|
|
if ((s == 0) || (*isc.NextChar == '\0')) {
|
|
return -1;
|
|
}
|
|
|
|
isc.NullCharDetected = 0;
|
|
return __sformatter(&__StringRead, (void*)&isc, format, arg, 0);
|
|
}
|
|
|
|
int sscanf(const char *s, const char *pFormat, ...) {
|
|
int ret;
|
|
va_list args;
|
|
va_start(args, pFormat);
|
|
return vsscanf(s, pFormat, args);
|
|
} |