msvcp60: Fixed basic_filebuf<short> implementation.
This commit is contained in:
parent
043fcc92be
commit
3b69e28a89
|
@ -76,10 +76,11 @@ typedef struct {
|
|||
typedef struct {
|
||||
basic_streambuf_wchar base;
|
||||
codecvt_wchar *cvt;
|
||||
wchar_t putback;
|
||||
MSVCP_bool wrotesome;
|
||||
int state0;
|
||||
int state;
|
||||
basic_string_char *str;
|
||||
MSVCP_bool close;
|
||||
locale loc;
|
||||
FILE *file;
|
||||
} basic_filebuf_wchar;
|
||||
|
||||
|
@ -747,7 +748,7 @@ void __asm_dummy_vtables(void) {
|
|||
VTABLE_ADD_FUNC(basic_filebuf_wchar_seekpos)
|
||||
VTABLE_ADD_FUNC(basic_filebuf_wchar_setbuf)
|
||||
VTABLE_ADD_FUNC(basic_filebuf_wchar_sync)
|
||||
VTABLE_ADD_FUNC(basic_filebuf_wchar_imbue));
|
||||
VTABLE_ADD_FUNC(basic_streambuf_wchar_imbue));
|
||||
__ASM_VTABLE(basic_filebuf_short,
|
||||
VTABLE_ADD_FUNC(basic_filebuf_wchar_vector_dtor)
|
||||
VTABLE_ADD_FUNC(basic_filebuf_wchar_overflow)
|
||||
|
@ -761,7 +762,7 @@ void __asm_dummy_vtables(void) {
|
|||
VTABLE_ADD_FUNC(basic_filebuf_wchar_seekpos)
|
||||
VTABLE_ADD_FUNC(basic_filebuf_short_setbuf)
|
||||
VTABLE_ADD_FUNC(basic_filebuf_wchar_sync)
|
||||
VTABLE_ADD_FUNC(basic_filebuf_short_imbue));
|
||||
VTABLE_ADD_FUNC(basic_streambuf_wchar_imbue));
|
||||
__ASM_VTABLE(basic_stringbuf_char,
|
||||
VTABLE_ADD_FUNC(basic_stringbuf_char_vector_dtor)
|
||||
VTABLE_ADD_FUNC(basic_stringbuf_char_overflow)
|
||||
|
@ -2292,6 +2293,15 @@ streamsize __thiscall basic_streambuf_wchar_sputn(basic_streambuf_wchar *this, c
|
|||
return call_basic_streambuf_wchar_xsputn(this, ptr, count);
|
||||
}
|
||||
|
||||
/* ?getloc@?$basic_streambuf@_WU?$char_traits@_W@std@@@std@@QAE?AVlocale@2@XZ */
|
||||
/* ?getloc@?$basic_streambuf@_WU?$char_traits@_W@std@@@std@@QEAA?AVlocale@2@XZ */
|
||||
DEFINE_THISCALL_WRAPPER(basic_streambuf_wchar_getloc, 8)
|
||||
locale* __thiscall basic_streambuf_wchar_getloc(basic_streambuf_wchar *this, locale *ret)
|
||||
{
|
||||
TRACE("(%p %p)\n", this, ret);
|
||||
return locale_copy_ctor(ret, &this->loc);
|
||||
}
|
||||
|
||||
/* ?_Stinit@?1??_Init@?$basic_filebuf@DU?$char_traits@D@std@@@std@@IAEXPAU_iobuf@@W4_Initfl@23@@Z@4HA */
|
||||
/* ?_Stinit@?1??_Init@?$basic_filebuf@DU?$char_traits@D@std@@@std@@IEAAXPEAU_iobuf@@W4_Initfl@23@@Z@4HA */
|
||||
int basic_filebuf_char__Init__Stinit = 0;
|
||||
|
@ -2796,8 +2806,9 @@ static void basic_filebuf_wchar__Init(basic_filebuf_wchar *this, FILE *file, bas
|
|||
TRACE("(%p %p %d)\n", this, file, which);
|
||||
|
||||
this->cvt = NULL;
|
||||
this->wrotesome = FALSE;
|
||||
this->state = 0;
|
||||
this->state0 = basic_filebuf_short__Init__Stinit;
|
||||
this->state = basic_filebuf_short__Init__Stinit;
|
||||
this->str = NULL;
|
||||
this->close = (which == INITFL_open);
|
||||
this->file = file;
|
||||
|
||||
|
@ -2812,68 +2823,29 @@ void __thiscall basic_filebuf_short__Init(basic_filebuf_wchar *this, FILE *file,
|
|||
TRACE("(%p %p %d)\n", this, file, which);
|
||||
|
||||
this->cvt = NULL;
|
||||
this->wrotesome = FALSE;
|
||||
this->state0 = basic_filebuf_short__Init__Stinit;
|
||||
this->state = basic_filebuf_short__Init__Stinit;
|
||||
this->str = NULL;
|
||||
this->close = (which == INITFL_open);
|
||||
this->file = file;
|
||||
|
||||
basic_streambuf_wchar__Init_empty(&this->base);
|
||||
}
|
||||
|
||||
/* ?_Initcvt@?$basic_filebuf@_WU?$char_traits@_W@std@@@std@@IAEXPAV?$codecvt@_WDH@2@@Z */
|
||||
/* ?_Initcvt@?$basic_filebuf@_WU?$char_traits@_W@std@@@std@@IEAAXPEAV?$codecvt@_WDH@2@@Z */
|
||||
/* ?_Initcvt@?$basic_filebuf@GU?$char_traits@G@std@@@std@@IAEXPAV?$codecvt@GDH@2@@Z */
|
||||
/* ?_Initcvt@?$basic_filebuf@GU?$char_traits@G@std@@@std@@IEAAXPEAV?$codecvt@GDH@2@@Z */
|
||||
static void basic_filebuf_wchar__Initcvt(basic_filebuf_wchar *this, codecvt_wchar *cvt)
|
||||
{
|
||||
TRACE("(%p %p)\n", this, cvt);
|
||||
|
||||
if(codecvt_base_always_noconv(&cvt->base)) {
|
||||
this->cvt = NULL;
|
||||
}else {
|
||||
basic_streambuf_wchar__Init_empty(&this->base);
|
||||
this->cvt = cvt;
|
||||
}
|
||||
}
|
||||
|
||||
/* ?_Endwrite@?$basic_filebuf@_WU?$char_traits@_W@std@@@std@@IAE_NXZ */
|
||||
/* ?_Endwrite@?$basic_filebuf@_WU?$char_traits@_W@std@@@std@@IEAA_NXZ */
|
||||
/* ?_Endwrite@?$basic_filebuf@GU?$char_traits@G@std@@@std@@IAE_NXZ */
|
||||
/* ?_Endwrite@?$basic_filebuf@GU?$char_traits@G@std@@@std@@IEAA_NXZ */
|
||||
static MSVCP_bool basic_filebuf_wchar__Endwrite(basic_filebuf_wchar *this)
|
||||
/* ?_Initcvt@?$basic_filebuf@GU?$char_traits@G@std@@@std@@IAEXXZ */
|
||||
/* ?_Initcvt@?$basic_filebuf@GU?$char_traits@G@std@@@std@@IEAAXXZ */
|
||||
DEFINE_THISCALL_WRAPPER(basic_filebuf_wchar__Initcvt, 4)
|
||||
void __thiscall basic_filebuf_wchar__Initcvt(basic_filebuf_wchar *this)
|
||||
{
|
||||
TRACE("(%p)\n", this);
|
||||
|
||||
if(!this->wrotesome || !this->cvt)
|
||||
return TRUE;
|
||||
|
||||
if(call_basic_streambuf_wchar_overflow(&this->base, WEOF) == WEOF)
|
||||
return FALSE;
|
||||
|
||||
while(1) {
|
||||
/* TODO: check if we need a dynamic buffer here */
|
||||
char buf[128];
|
||||
char *next;
|
||||
int ret;
|
||||
|
||||
ret = codecvt_wchar_unshift(this->cvt, &this->state, buf, buf+sizeof(buf), &next);
|
||||
switch(ret) {
|
||||
case CODECVT_ok:
|
||||
this->wrotesome = FALSE;
|
||||
/* fall through */
|
||||
case CODECVT_partial:
|
||||
if(!fwrite(buf, next-buf, 1, this->file))
|
||||
return FALSE;
|
||||
if(this->wrotesome)
|
||||
break;
|
||||
/* fall through */
|
||||
case CODECVT_noconv:
|
||||
if(call_basic_streambuf_wchar_overflow(&this->base, WEOF) == WEOF)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
this->cvt = codecvt_short_use_facet(&this->base.loc);
|
||||
locale__Addfac(&this->loc, &this->cvt->base.facet, codecvt_short_id.id, LC_CTYPE);
|
||||
if(codecvt_base_always_noconv(&this->cvt->base)) {
|
||||
this->cvt = NULL;
|
||||
}else {
|
||||
this->str = MSVCRT_operator_new(sizeof(basic_string_char));
|
||||
basic_string_char_ctor(this->str);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2888,15 +2860,9 @@ basic_filebuf_wchar* __thiscall basic_filebuf_wchar_close(basic_filebuf_wchar *t
|
|||
|
||||
TRACE("(%p)\n", this);
|
||||
|
||||
if(!this->file)
|
||||
if(!this->file || fclose(this->file))
|
||||
return NULL;
|
||||
|
||||
/* TODO: handle exceptions */
|
||||
if(!basic_filebuf_wchar__Endwrite(this))
|
||||
ret = NULL;
|
||||
if(fclose(this->file))
|
||||
ret = NULL;
|
||||
|
||||
basic_filebuf_wchar__Init(this, NULL, INITFL_close);
|
||||
return ret;
|
||||
}
|
||||
|
@ -2910,6 +2876,7 @@ static basic_filebuf_wchar* basic_filebuf_wchar_ctor_file(basic_filebuf_wchar *t
|
|||
basic_streambuf_wchar_ctor(&this->base);
|
||||
this->base.vtable = &MSVCP_basic_filebuf_wchar_vtable;
|
||||
|
||||
locale_ctor(&this->loc);
|
||||
basic_filebuf_wchar__Init(this, file, INITFL_new);
|
||||
return this;
|
||||
}
|
||||
|
@ -2924,6 +2891,7 @@ basic_filebuf_wchar* __thiscall basic_filebuf_short_ctor_file(basic_filebuf_wcha
|
|||
basic_streambuf_short_ctor(&this->base);
|
||||
this->base.vtable = &MSVCP_basic_filebuf_short_vtable;
|
||||
|
||||
locale_ctor(&this->loc);
|
||||
basic_filebuf_short__Init(this, file, INITFL_new);
|
||||
return this;
|
||||
}
|
||||
|
@ -2950,8 +2918,9 @@ basic_filebuf_wchar* __thiscall basic_filebuf_short_ctor_uninitialized(basic_fil
|
|||
{
|
||||
TRACE("(%p %d)\n", this, uninitialized);
|
||||
|
||||
basic_streambuf_short_ctor(&this->base);
|
||||
basic_streambuf_short_ctor_uninitialized(&this->base, 0);
|
||||
this->base.vtable = &MSVCP_basic_filebuf_short_vtable;
|
||||
locale_ctor(&this->loc);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -2966,6 +2935,11 @@ void __thiscall basic_filebuf_wchar_dtor(basic_filebuf_wchar *this)
|
|||
|
||||
if(this->close)
|
||||
basic_filebuf_wchar_close(this);
|
||||
if(this->str) {
|
||||
basic_string_char_dtor(this->str);
|
||||
MSVCRT_operator_delete(this->str);
|
||||
}
|
||||
locale_dtor(&this->loc);
|
||||
basic_streambuf_wchar_dtor(&this->base);
|
||||
}
|
||||
|
||||
|
@ -3017,7 +2991,7 @@ static basic_filebuf_wchar* basic_filebuf_wchar_open_wchar(basic_filebuf_wchar *
|
|||
return NULL;
|
||||
|
||||
basic_filebuf_wchar__Init(this, f, INITFL_open);
|
||||
basic_filebuf_wchar__Initcvt(this, codecvt_wchar_use_facet(&this->base.loc));
|
||||
basic_filebuf_wchar__Initcvt(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -3059,10 +3033,9 @@ basic_filebuf_wchar* __thiscall basic_filebuf_wchar_open_mode(basic_filebuf_wcha
|
|||
DEFINE_THISCALL_WRAPPER(basic_filebuf_wchar_overflow, 8)
|
||||
unsigned short __thiscall basic_filebuf_wchar_overflow(basic_filebuf_wchar *this, unsigned short c)
|
||||
{
|
||||
char buf[8], *dyn_buf, *to_next;
|
||||
char *ptr, *to_next;
|
||||
wchar_t ch = c;
|
||||
const wchar_t *from_next;
|
||||
int max_size;
|
||||
unsigned short ret;
|
||||
|
||||
|
||||
|
@ -3077,48 +3050,24 @@ unsigned short __thiscall basic_filebuf_wchar_overflow(basic_filebuf_wchar *this
|
|||
return fwrite(&ch, sizeof(wchar_t), 1, this->file) ? c : WEOF;
|
||||
|
||||
from_next = &ch;
|
||||
do {
|
||||
ret = codecvt_wchar_out(this->cvt, &this->state, from_next, &ch+1,
|
||||
&from_next, buf, buf+sizeof(buf), &to_next);
|
||||
|
||||
switch(ret) {
|
||||
case CODECVT_partial:
|
||||
if(to_next == buf)
|
||||
break;
|
||||
/* fall through */
|
||||
case CODECVT_ok:
|
||||
if(!fwrite(buf, to_next-buf, 1, this->file))
|
||||
return WEOF;
|
||||
if(ret == CODECVT_partial)
|
||||
continue;
|
||||
return c;
|
||||
case CODECVT_noconv:
|
||||
return fwrite(&ch, sizeof(wchar_t), 1, this->file) ? c : WEOF;
|
||||
default:
|
||||
return WEOF;
|
||||
}
|
||||
|
||||
break;
|
||||
} while(1);
|
||||
|
||||
max_size = codecvt_base_max_length(&this->cvt->base);
|
||||
dyn_buf = malloc(max_size);
|
||||
if(!dyn_buf)
|
||||
return WEOF;
|
||||
|
||||
ret = codecvt_wchar_out(this->cvt, &this->state, from_next, &ch+1,
|
||||
&from_next, dyn_buf, dyn_buf+max_size, &to_next);
|
||||
basic_string_char_clear(this->str);
|
||||
basic_string_char_append_len_ch(this->str, 8, '\0');
|
||||
ptr = this->str->ptr;
|
||||
ret = codecvt_wchar_out(this->cvt, &this->state, &ch, &ch+1, &from_next,
|
||||
ptr, ptr+basic_string_char_length(this->str), &to_next);
|
||||
|
||||
switch(ret) {
|
||||
case CODECVT_ok:
|
||||
ret = fwrite(dyn_buf, to_next-dyn_buf, 1, this->file);
|
||||
free(dyn_buf);
|
||||
return ret ? c : WEOF;
|
||||
case CODECVT_partial:
|
||||
ERR("buffer should be big enough to store all output\n");
|
||||
if(from_next == &ch)
|
||||
return WEOF;
|
||||
/* fall through */
|
||||
case CODECVT_ok:
|
||||
if(!fwrite(ptr, to_next-ptr, 1, this->file))
|
||||
return WEOF;
|
||||
return c;
|
||||
case CODECVT_noconv:
|
||||
return fwrite(&ch, sizeof(wchar_t), 1, this->file) ? c : WEOF;
|
||||
default:
|
||||
free(dyn_buf);
|
||||
return WEOF;
|
||||
}
|
||||
}
|
||||
|
@ -3139,11 +3088,24 @@ unsigned short __thiscall basic_filebuf_wchar_pbackfail(basic_filebuf_wchar *thi
|
|||
&& (c==WEOF || basic_streambuf_wchar_gptr(&this->base)[-1]==c)) {
|
||||
basic_streambuf_wchar__Gndec(&this->base);
|
||||
return c==WEOF ? !c : c;
|
||||
}else if(c!=WEOF && !this->cvt) {
|
||||
}else if(c == WEOF) {
|
||||
return WEOF;
|
||||
}else if(!this->cvt) {
|
||||
return ungetwc(c, this->file);
|
||||
}else if(c!=WEOF && basic_streambuf_wchar_gptr(&this->base)!=&this->putback) {
|
||||
this->putback = c;
|
||||
basic_streambuf_wchar_setg(&this->base, &this->putback, &this->putback, &this->putback+1);
|
||||
}else if(basic_string_char_length(this->str)) {
|
||||
char *b, *e, *cur;
|
||||
|
||||
e = this->str->ptr;
|
||||
b = e+this->str->size-1;
|
||||
for(cur = b; cur>=e; cur--) {
|
||||
if(ungetc(*cur, this->file) == EOF) {
|
||||
for(; cur<=b; cur++)
|
||||
fgetc(this->file);
|
||||
return WEOF;
|
||||
}
|
||||
}
|
||||
basic_string_char_clear(this->str);
|
||||
this->state = this->state0;
|
||||
return c;
|
||||
}
|
||||
|
||||
|
@ -3158,9 +3120,8 @@ DEFINE_THISCALL_WRAPPER(basic_filebuf_wchar_uflow, 4)
|
|||
unsigned short __thiscall basic_filebuf_wchar_uflow(basic_filebuf_wchar *this)
|
||||
{
|
||||
wchar_t ch, *to_next;
|
||||
char buf[128];
|
||||
const char *buf_next;
|
||||
int c, i;
|
||||
int c;
|
||||
|
||||
TRACE("(%p)\n", this);
|
||||
|
||||
|
@ -3173,35 +3134,28 @@ unsigned short __thiscall basic_filebuf_wchar_uflow(basic_filebuf_wchar *this)
|
|||
if(!this->cvt)
|
||||
return fgetwc(this->file);
|
||||
|
||||
buf_next = buf;
|
||||
for(i=0; i < sizeof(buf)/sizeof(buf[0]); i++) {
|
||||
basic_string_char_clear(this->str);
|
||||
this->state0 = this->state;
|
||||
while(1) {
|
||||
if((c = fgetc(this->file)) == EOF)
|
||||
return WEOF;
|
||||
buf[i] = c;
|
||||
basic_string_char_append_ch(this->str, c);
|
||||
this->state = this->state0;
|
||||
|
||||
switch(codecvt_wchar_in(this->cvt, &this->state, buf_next,
|
||||
buf+i+1, &buf_next, &ch, &ch+1, &to_next)) {
|
||||
switch(codecvt_wchar_in(this->cvt, &this->state, this->str->ptr,
|
||||
this->str->ptr+this->str->size, &buf_next, &ch, &ch+1, &to_next)) {
|
||||
case CODECVT_partial:
|
||||
case CODECVT_ok:
|
||||
if(to_next == &ch)
|
||||
continue;
|
||||
|
||||
for(i--; i>=buf_next-buf; i--)
|
||||
ungetc(buf[i], this->file);
|
||||
return ch;
|
||||
break;
|
||||
case CODECVT_noconv:
|
||||
if(i+1 < sizeof(wchar_t))
|
||||
continue;
|
||||
|
||||
memcpy(&ch, buf, sizeof(wchar_t));
|
||||
return ch;
|
||||
if(this->str->size < sizeof(unsigned short)/sizeof(char))
|
||||
break;
|
||||
return *(unsigned short*)this->str->ptr;
|
||||
case CODECVT_ok:
|
||||
return (unsigned short)ch;
|
||||
default:
|
||||
return WEOF;
|
||||
}
|
||||
}
|
||||
|
||||
FIXME("buffer is too small\n");
|
||||
return WEOF;
|
||||
}
|
||||
|
||||
/* ?underflow@?$basic_filebuf@_WU?$char_traits@_W@std@@@std@@MAEGXZ */
|
||||
|
@ -3236,15 +3190,7 @@ fpos_int* __thiscall basic_filebuf_wchar_seekoff(basic_filebuf_wchar *this,
|
|||
|
||||
TRACE("(%p %p %ld %d %d)\n", this, ret, off, way, mode);
|
||||
|
||||
if(basic_streambuf_wchar_gptr(&this->base) == &this->putback) {
|
||||
if(way == SEEKDIR_cur)
|
||||
off -= sizeof(wchar_t);
|
||||
|
||||
basic_streambuf_wchar_setg(&this->base, &this->putback, &this->putback+1, &this->putback+1);
|
||||
}
|
||||
|
||||
if(!basic_filebuf_wchar_is_open(this) || !basic_filebuf_wchar__Endwrite(this)
|
||||
|| fseek(this->file, off, way)) {
|
||||
if(!basic_filebuf_wchar_is_open(this) || fseek(this->file, off, way)) {
|
||||
ret->off = -1;
|
||||
ret->pos = 0;
|
||||
ret->state = 0;
|
||||
|
@ -3270,8 +3216,7 @@ fpos_int* __thiscall basic_filebuf_wchar_seekpos(basic_filebuf_wchar *this,
|
|||
|
||||
TRACE("(%p %p %s %d)\n", this, ret, debugstr_fpos_int(&pos), mode);
|
||||
|
||||
if(!basic_filebuf_wchar_is_open(this) || !basic_filebuf_wchar__Endwrite(this)
|
||||
|| fseek(this->file, (LONG)pos.pos, SEEK_SET)
|
||||
if(!basic_filebuf_wchar_is_open(this) || fseek(this->file, (LONG)pos.pos, SEEK_SET)
|
||||
|| (pos.off && fseek(this->file, pos.off, SEEK_CUR))) {
|
||||
ret->off = -1;
|
||||
ret->pos = 0;
|
||||
|
@ -3279,9 +3224,6 @@ fpos_int* __thiscall basic_filebuf_wchar_seekpos(basic_filebuf_wchar *this,
|
|||
return ret;
|
||||
}
|
||||
|
||||
if(basic_streambuf_wchar_gptr(&this->base) == &this->putback)
|
||||
basic_streambuf_wchar_setg(&this->base, &this->putback, &this->putback+1, &this->putback+1);
|
||||
|
||||
fgetpos(this->file, &fpos);
|
||||
ret->off = 0;
|
||||
ret->pos = fpos;
|
||||
|
@ -3340,24 +3282,6 @@ int __thiscall basic_filebuf_wchar_sync(basic_filebuf_wchar *this)
|
|||
return fflush(this->file);
|
||||
}
|
||||
|
||||
/* ?imbue@?$basic_filebuf@_WU?$char_traits@_W@std@@@std@@MAEXABVlocale@2@@Z */
|
||||
/* ?imbue@?$basic_filebuf@_WU?$char_traits@_W@std@@@std@@MEAAXAEBVlocale@2@@Z */
|
||||
DEFINE_THISCALL_WRAPPER(basic_filebuf_wchar_imbue, 8)
|
||||
void __thiscall basic_filebuf_wchar_imbue(basic_filebuf_wchar *this, const locale *loc)
|
||||
{
|
||||
TRACE("(%p %p)\n", this, loc);
|
||||
basic_filebuf_wchar__Initcvt(this, codecvt_wchar_use_facet(loc));
|
||||
}
|
||||
|
||||
/* ?imbue@?$basic_filebuf@GU?$char_traits@G@std@@@std@@MAEXABVlocale@2@@Z */
|
||||
/* ?imbue@?$basic_filebuf@GU?$char_traits@G@std@@@std@@MEAAXAEBVlocale@2@@Z */
|
||||
DEFINE_THISCALL_WRAPPER(basic_filebuf_short_imbue, 8)
|
||||
void __thiscall basic_filebuf_short_imbue(basic_filebuf_wchar *this, const locale *loc)
|
||||
{
|
||||
TRACE("(%p %p)\n", this, loc);
|
||||
basic_filebuf_wchar__Initcvt(this, codecvt_short_use_facet(loc));
|
||||
}
|
||||
|
||||
/* ?_Getstate@?$basic_stringbuf@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AAEHH@Z */
|
||||
/* ?_Getstate@?$basic_stringbuf@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEAAHH@Z */
|
||||
static int basic_stringbuf_char__Getstate(basic_stringbuf_char *this, IOSB_openmode mode)
|
||||
|
|
|
@ -180,6 +180,7 @@ typedef struct {
|
|||
MSVCP_size_t id;
|
||||
} locale_id;
|
||||
extern locale_id codecvt_char_id;
|
||||
extern locale_id codecvt_short_id;
|
||||
|
||||
/* class _Lockit */
|
||||
typedef struct {
|
||||
|
|
Loading…
Reference in New Issue