Commit 32101fed authored by Vitaly Lipatov's avatar Vitaly Lipatov

commit 19.0.1 upon wine-4.12.1

parent abbc020b
...@@ -15135,14 +15135,9 @@ fi ...@@ -15135,14 +15135,9 @@ fi
done done
CPPFLAGS=$ac_save_CPPFLAGS
test -z "$FAUDIO_CFLAGS" || FAUDIO_CFLAGS=`echo " $FAUDIO_CFLAGS" | sed 's/ -I\([^/]\)/ -I\$(top_builddir)\/\1/g'`
test -z "$FAUDIO_LIBS" || FAUDIO_LIBS=`echo " $FAUDIO_LIBS" | sed 's/ -L\([^/]\)/ -L\$(top_builddir)\/\1/g'`
ac_wine_check_funcs_save_LIBS="$LIBS" ac_wine_check_funcs_save_LIBS="$LIBS"
LIBS="$LIBS $FAUDIO_LIBS" LIBS="$LIBS $FAUDIO_LIBS"
for ac_func in \ for ac_func in FAudio_CommitOperationSet \
FAudio_CommitOperationSet \
F3DAudioInitialize8 F3DAudioInitialize8
do : do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
...@@ -15156,6 +15151,11 @@ fi ...@@ -15156,6 +15151,11 @@ fi
done done
LIBS="$ac_wine_check_funcs_save_LIBS" LIBS="$ac_wine_check_funcs_save_LIBS"
CPPFLAGS=$ac_save_CPPFLAGS
test -z "$FAUDIO_CFLAGS" || FAUDIO_CFLAGS=`echo " $FAUDIO_CFLAGS" | sed 's/ -I\([^/]\)/ -I\$(top_builddir)\/\1/g'`
test -z "$FAUDIO_LIBS" || FAUDIO_LIBS=`echo " $FAUDIO_LIBS" | sed 's/ -L\([^/]\)/ -L\$(top_builddir)\/\1/g'`
fi fi
if test "x$ac_cv_lib_soname_FAudio" = "x"; then : if test "x$ac_cv_lib_soname_FAudio" = "x"; then :
case "x$with_faudio" in case "x$with_faudio" in
......
...@@ -1760,11 +1760,10 @@ if test "x$with_faudio" != "xno" ...@@ -1760,11 +1760,10 @@ if test "x$with_faudio" != "xno"
then then
WINE_PACKAGE_FLAGS(FAUDIO,[faudio],[-lFAudio],,, WINE_PACKAGE_FLAGS(FAUDIO,[faudio],[-lFAudio],,,
[AC_CHECK_HEADERS([FAudio.h], [AC_CHECK_HEADERS([FAudio.h],
[WINE_CHECK_SONAME(FAudio,FAudioCreate,,,[$FAUDIO_LIBS],[[libFAudio*]])])]) [WINE_CHECK_SONAME(FAudio,FAudioCreate,,,[$FAUDIO_LIBS],[[libFAudio*]])])
WINE_CHECK_LIB_FUNCS(\ WINE_CHECK_LIB_FUNCS([FAudio_CommitOperationSet \
FAudio_CommitOperationSet \ F3DAudioInitialize8], [$FAUDIO_LIBS])
F3DAudioInitialize8, ])
[$FAUDIO_LIBS])
fi fi
WINE_NOTICE_WITH(faudio,[test "x$ac_cv_lib_soname_FAudio" = "x"], WINE_NOTICE_WITH(faudio,[test "x$ac_cv_lib_soname_FAudio" = "x"],
[libFAudio ${notice_platform}development files not found, XAudio2 won't be supported.]) [libFAudio ${notice_platform}development files not found, XAudio2 won't be supported.])
......
...@@ -2713,6 +2713,7 @@ HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode ) ...@@ -2713,6 +2713,7 @@ HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
HANDLE handle; HANDLE handle;
FILETIME filetime; FILETIME filetime;
WORD filedatetime[2]; WORD filedatetime[2];
DWORD len;
if (!ofs) return HFILE_ERROR; if (!ofs) return HFILE_ERROR;
...@@ -2748,7 +2749,13 @@ HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode ) ...@@ -2748,7 +2749,13 @@ HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
/* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
Are there any cases where getting the path here is wrong? Are there any cases where getting the path here is wrong?
Uwe Bonnes 1997 Apr 2 */ Uwe Bonnes 1997 Apr 2 */
if (!GetFullPathNameA( name, sizeof(ofs->szPathName), ofs->szPathName, NULL )) goto error; len = GetFullPathNameA( name, sizeof(ofs->szPathName), ofs->szPathName, NULL );
if (!len) goto error;
if (len >= sizeof(ofs->szPathName))
{
SetLastError(ERROR_INVALID_DATA);
goto error;
}
/* OF_PARSE simply fills the structure */ /* OF_PARSE simply fills the structure */
...@@ -2771,8 +2778,13 @@ HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode ) ...@@ -2771,8 +2778,13 @@ HFILE WINAPI OpenFile( LPCSTR name, OFSTRUCT *ofs, UINT mode )
{ {
/* Now look for the file */ /* Now look for the file */
if (!SearchPathA( NULL, name, NULL, sizeof(ofs->szPathName), ofs->szPathName, NULL )) len = SearchPathA( NULL, name, NULL, sizeof(ofs->szPathName), ofs->szPathName, NULL );
if (!len) goto error;
if (len >= sizeof(ofs->szPathName))
{
SetLastError(ERROR_INVALID_DATA);
goto error; goto error;
}
TRACE("found %s\n", debugstr_a(ofs->szPathName) ); TRACE("found %s\n", debugstr_a(ofs->szPathName) );
......
...@@ -3826,6 +3826,11 @@ DWORD WINAPI TlsAlloc( void ) ...@@ -3826,6 +3826,11 @@ DWORD WINAPI TlsAlloc( void )
!(NtCurrentTeb()->TlsExpansionSlots = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, !(NtCurrentTeb()->TlsExpansionSlots = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
8 * sizeof(peb->TlsExpansionBitmapBits) * sizeof(void*) ))) 8 * sizeof(peb->TlsExpansionBitmapBits) * sizeof(void*) )))
{ {
#if defined(__APPLE__) && defined(__x86_64__) && !defined(__i386_on_x86_64__)
__asm__ volatile (".byte 0x65\n\tmovq %0,%c1"
:
: "r" (NtCurrentTeb()->TlsExpansionSlots), "n" (FIELD_OFFSET(TEB, TlsExpansionSlots)));
#endif
RtlClearBits( peb->TlsExpansionBitmap, index, 1 ); RtlClearBits( peb->TlsExpansionBitmap, index, 1 );
index = ~0U; index = ~0U;
SetLastError( ERROR_NOT_ENOUGH_MEMORY ); SetLastError( ERROR_NOT_ENOUGH_MEMORY );
...@@ -3947,6 +3952,11 @@ BOOL WINAPI TlsSetValue( DWORD index, LPVOID value ) ...@@ -3947,6 +3952,11 @@ BOOL WINAPI TlsSetValue( DWORD index, LPVOID value )
SetLastError( ERROR_NOT_ENOUGH_MEMORY ); SetLastError( ERROR_NOT_ENOUGH_MEMORY );
return FALSE; return FALSE;
} }
#if defined(__APPLE__) && defined(__x86_64__) && !defined(__i386_on_x86_64__)
__asm__ volatile (".byte 0x65\n\tmovq %0,%c1"
:
: "r" (NtCurrentTeb()->TlsExpansionSlots), "n" (FIELD_OFFSET(TEB, TlsExpansionSlots)));
#endif
NtCurrentTeb()->TlsExpansionSlots[index] = value; NtCurrentTeb()->TlsExpansionSlots[index] = value;
} }
return TRUE; return TRUE;
......
...@@ -1972,13 +1972,21 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package) ...@@ -1972,13 +1972,21 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package)
component->ActionRequest = INSTALLSTATE_UNKNOWN; component->ActionRequest = INSTALLSTATE_UNKNOWN;
} }
TRACE("component %s (installed %d request %d action %d)\n",
debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
if (component->Action == INSTALLSTATE_LOCAL || component->Action == INSTALLSTATE_SOURCE) if (component->Action == INSTALLSTATE_LOCAL || component->Action == INSTALLSTATE_SOURCE)
component->num_clients++; component->num_clients++;
else if (component->Action == INSTALLSTATE_ABSENT) else if (component->Action == INSTALLSTATE_ABSENT)
{
component->num_clients--; component->num_clients--;
if (component->num_clients > 0)
{
TRACE("multiple clients uses %s - disallowing uninstallation\n", debugstr_w(component->Component));
component->Action = INSTALLSTATE_UNKNOWN;
}
}
TRACE("component %s (installed %d request %d action %d)\n",
debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
} }
return ERROR_SUCCESS; return ERROR_SUCCESS;
......
...@@ -1223,7 +1223,9 @@ static const char shc_custom_action_dat[] = ...@@ -1223,7 +1223,9 @@ static const char shc_custom_action_dat[] =
"Action\tType\tSource\tTarget\tISComments\n" "Action\tType\tSource\tTarget\tISComments\n"
"s72\ti2\tS64\tS0\tS255\n" "s72\ti2\tS64\tS0\tS255\n"
"CustomAction\tAction\n" "CustomAction\tAction\n"
"TestComponentAction\t19\t\twrong component action on install\t\n"; "TestComponentAction\t19\t\twrong component action on install\t\n"
"TestDisallowedAction\t19\t\twrong component action on disallowed remove\t\n"
"TestRemoveAction\t19\t\twrong component action on remove\t\n";
static const char shc_install_exec_seq_dat[] = static const char shc_install_exec_seq_dat[] =
"Action\tCondition\tSequence\n" "Action\tCondition\tSequence\n"
...@@ -1233,6 +1235,27 @@ static const char shc_install_exec_seq_dat[] = ...@@ -1233,6 +1235,27 @@ static const char shc_install_exec_seq_dat[] =
"CostInitialize\t\t200\n" "CostInitialize\t\t200\n"
"FileCost\t\t300\n" "FileCost\t\t300\n"
"CostFinalize\t\t600\n" "CostFinalize\t\t600\n"
"TestDisallowedAction\tREMOVE AND ($sharedcomponent <> -1)\t700\n"
"InstallValidate\t\t900\n"
"InstallInitialize\t\t1200\n"
"ProcessComponents\t\t1300\n"
"RemoveFiles\t\t1400\n"
"InstallFiles\t\t1500\n"
"TestComponentAction\tNOT REMOVE AND ($sharedcomponent <> 3)\t1600\n"
"RegisterProduct\t\t1700\n"
"PublishFeatures\t\t1800\n"
"PublishProduct\t\t1900\n"
"InstallFinalize\t\t2000\n";
static const char shc2_install_exec_seq_dat[] =
"Action\tCondition\tSequence\n"
"s72\tS255\tI2\n"
"InstallExecuteSequence\tAction\n"
"LaunchConditions\t\t100\n"
"CostInitialize\t\t200\n"
"FileCost\t\t300\n"
"CostFinalize\t\t600\n"
"TestRemoveAction\tREMOVE AND ($sharedcomponent <> 2)\t700\n"
"InstallValidate\t\t900\n" "InstallValidate\t\t900\n"
"InstallInitialize\t\t1200\n" "InstallInitialize\t\t1200\n"
"ProcessComponents\t\t1300\n" "ProcessComponents\t\t1300\n"
...@@ -1990,7 +2013,7 @@ static const msi_table shc2_tables[] = ...@@ -1990,7 +2013,7 @@ static const msi_table shc2_tables[] =
ADD_TABLE(shc_feature), ADD_TABLE(shc_feature),
ADD_TABLE(shc_feature_comp), ADD_TABLE(shc_feature_comp),
ADD_TABLE(shc_custom_action), ADD_TABLE(shc_custom_action),
ADD_TABLE(shc_install_exec_seq), ADD_TABLE(shc2_install_exec_seq),
ADD_TABLE(shc2_property) ADD_TABLE(shc2_property)
}; };
......
...@@ -819,6 +819,29 @@ static inline const char* debugstr_version(const struct assembly_version *ver) ...@@ -819,6 +819,29 @@ static inline const char* debugstr_version(const struct assembly_version *ver)
return wine_dbg_sprintf("%u.%u.%u.%u", ver->major, ver->minor, ver->build, ver->revision); return wine_dbg_sprintf("%u.%u.%u.%u", ver->major, ver->minor, ver->build, ver->revision);
} }
static NTSTATUS get_module_filename( HMODULE module, UNICODE_STRING *str, unsigned int extra_len )
{
NTSTATUS status;
ULONG_PTR magic;
LDR_MODULE *pldr;
LdrLockLoaderLock(0, NULL, &magic);
status = LdrFindEntryForAddress( module, &pldr );
if (status == STATUS_SUCCESS)
{
if ((str->Buffer = RtlAllocateHeap( GetProcessHeap(), 0,
pldr->FullDllName.Length + extra_len + sizeof(WCHAR) )))
{
memcpy( str->Buffer, pldr->FullDllName.Buffer, pldr->FullDllName.Length + sizeof(WCHAR) );
str->Length = pldr->FullDllName.Length;
str->MaximumLength = pldr->FullDllName.Length + extra_len + sizeof(WCHAR);
}
else status = STATUS_NO_MEMORY;
}
LdrUnlockLoaderLock(0, magic);
return status;
}
static struct assembly *add_assembly(ACTIVATION_CONTEXT *actctx, enum assembly_type at) static struct assembly *add_assembly(ACTIVATION_CONTEXT *actctx, enum assembly_type at)
{ {
struct assembly *assembly; struct assembly *assembly;
...@@ -2791,7 +2814,7 @@ static NTSTATUS parse_manifest_buffer( struct actctx_loader* acl, struct assembl ...@@ -2791,7 +2814,7 @@ static NTSTATUS parse_manifest_buffer( struct actctx_loader* acl, struct assembl
} }
static NTSTATUS parse_manifest( struct actctx_loader* acl, struct assembly_identity* ai, static NTSTATUS parse_manifest( struct actctx_loader* acl, struct assembly_identity* ai,
LPCWSTR filename, LPCWSTR directory, BOOL shared, LPCWSTR filename, HANDLE module, LPCWSTR directory, BOOL shared,
const void *buffer, SIZE_T size ) const void *buffer, SIZE_T size )
{ {
xmlbuf_t xmlbuf; xmlbuf_t xmlbuf;
...@@ -2807,7 +2830,14 @@ static NTSTATUS parse_manifest( struct actctx_loader* acl, struct assembly_ident ...@@ -2807,7 +2830,14 @@ static NTSTATUS parse_manifest( struct actctx_loader* acl, struct assembly_ident
if (directory && !(assembly->directory = strdupW(directory))) if (directory && !(assembly->directory = strdupW(directory)))
return STATUS_NO_MEMORY; return STATUS_NO_MEMORY;
if (filename) assembly->manifest.info = strdupW( filename + 4 /* skip \??\ prefix */ ); if (!filename)
{
UNICODE_STRING module_path;
if ((status = get_module_filename( module, &module_path, 0 ))) return status;
assembly->manifest.info = module_path.Buffer;
}
else if(!(assembly->manifest.info = strdupW( filename + 4 /* skip \??\ prefix */ ))) return STATUS_NO_MEMORY;
assembly->manifest.type = assembly->manifest.info ? ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE assembly->manifest.type = assembly->manifest.info ? ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE
: ACTIVATION_CONTEXT_PATH_TYPE_NONE; : ACTIVATION_CONTEXT_PATH_TYPE_NONE;
...@@ -2869,29 +2899,6 @@ static NTSTATUS open_nt_file( HANDLE *handle, UNICODE_STRING *name ) ...@@ -2869,29 +2899,6 @@ static NTSTATUS open_nt_file( HANDLE *handle, UNICODE_STRING *name )
return NtOpenFile( handle, GENERIC_READ | SYNCHRONIZE, &attr, &io, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_ALERT ); return NtOpenFile( handle, GENERIC_READ | SYNCHRONIZE, &attr, &io, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_ALERT );
} }
static NTSTATUS get_module_filename( HMODULE module, UNICODE_STRING *str, unsigned int extra_len )
{
NTSTATUS status;
ULONG_PTR magic;
LDR_MODULE *pldr;
LdrLockLoaderLock(0, NULL, &magic);
status = LdrFindEntryForAddress( module, &pldr );
if (status == STATUS_SUCCESS)
{
if ((str->Buffer = RtlAllocateHeap( GetProcessHeap(), 0,
pldr->FullDllName.Length + extra_len + sizeof(WCHAR) )))
{
memcpy( str->Buffer, pldr->FullDllName.Buffer, pldr->FullDllName.Length + sizeof(WCHAR) );
str->Length = pldr->FullDllName.Length;
str->MaximumLength = pldr->FullDllName.Length + extra_len + sizeof(WCHAR);
}
else status = STATUS_NO_MEMORY;
}
LdrUnlockLoaderLock(0, magic);
return status;
}
static NTSTATUS get_manifest_in_module( struct actctx_loader* acl, struct assembly_identity* ai, static NTSTATUS get_manifest_in_module( struct actctx_loader* acl, struct assembly_identity* ai,
LPCWSTR filename, LPCWSTR directory, BOOL shared, LPCWSTR filename, LPCWSTR directory, BOOL shared,
HANDLE hModule, LPCWSTR resname, ULONG lang ) HANDLE hModule, LPCWSTR resname, ULONG lang )
...@@ -2943,7 +2950,7 @@ static NTSTATUS get_manifest_in_module( struct actctx_loader* acl, struct assemb ...@@ -2943,7 +2950,7 @@ static NTSTATUS get_manifest_in_module( struct actctx_loader* acl, struct assemb
if (status == STATUS_SUCCESS) status = LdrAccessResource(hModule, entry, &ptr, NULL); if (status == STATUS_SUCCESS) status = LdrAccessResource(hModule, entry, &ptr, NULL);
if (status == STATUS_SUCCESS) if (status == STATUS_SUCCESS)
status = parse_manifest(acl, ai, filename, directory, shared, ptr, entry->Size); status = parse_manifest(acl, ai, filename, hModule, directory, shared, ptr, entry->Size);
return status; return status;
} }
...@@ -3030,7 +3037,7 @@ static NTSTATUS get_manifest_in_manifest_file( struct actctx_loader* acl, struct ...@@ -3030,7 +3037,7 @@ static NTSTATUS get_manifest_in_manifest_file( struct actctx_loader* acl, struct
status = NtQueryInformationFile( file, &io, &info, sizeof(info), FileEndOfFileInformation ); status = NtQueryInformationFile( file, &io, &info, sizeof(info), FileEndOfFileInformation );
if (status == STATUS_SUCCESS) if (status == STATUS_SUCCESS)
status = parse_manifest(acl, ai, filename, directory, shared, base, info.EndOfFile.QuadPart); status = parse_manifest(acl, ai, filename, NULL, directory, shared, base, info.EndOfFile.QuadPart);
NtUnmapViewOfSection( GetCurrentProcess(), base ); NtUnmapViewOfSection( GetCurrentProcess(), base );
return status; return status;
......
...@@ -2778,7 +2778,7 @@ static NTSTATUS find_actctx_dll( LPCWSTR libname, LPWSTR *fullname ) ...@@ -2778,7 +2778,7 @@ static NTSTATUS find_actctx_dll( LPCWSTR libname, LPWSTR *fullname )
/* restart with larger buffer */ /* restart with larger buffer */
} }
if (!info->lpAssemblyManifestPath || !info->lpAssemblyDirectoryName) if (!info->lpAssemblyManifestPath)
{ {
status = STATUS_SXS_KEY_NOT_FOUND; status = STATUS_SXS_KEY_NOT_FOUND;
goto done; goto done;
...@@ -2789,7 +2789,7 @@ static NTSTATUS find_actctx_dll( LPCWSTR libname, LPWSTR *fullname ) ...@@ -2789,7 +2789,7 @@ static NTSTATUS find_actctx_dll( LPCWSTR libname, LPWSTR *fullname )
DWORD dirlen = info->ulAssemblyDirectoryNameLength / sizeof(WCHAR); DWORD dirlen = info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
p++; p++;
if (strncmpiW( p, info->lpAssemblyDirectoryName, dirlen ) || strcmpiW( p + dirlen, dotManifestW )) if (!dirlen || strncmpiW( p, info->lpAssemblyDirectoryName, dirlen ) || strcmpiW( p + dirlen, dotManifestW ))
{ {
/* manifest name does not match directory name, so it's not a global /* manifest name does not match directory name, so it's not a global
* windows/winsxs manifest; use the manifest directory name instead */ * windows/winsxs manifest; use the manifest directory name instead */
......
...@@ -2613,6 +2613,7 @@ static DWORD call_handler( EXCEPTION_RECORD *rec, CONTEXT *context, DISPATCHER_C ...@@ -2613,6 +2613,7 @@ static DWORD call_handler( EXCEPTION_RECORD *rec, CONTEXT *context, DISPATCHER_C
res = dispatch->LanguageHandler( rec, dispatch->EstablisherFrame, context, dispatch ); res = dispatch->LanguageHandler( rec, dispatch->EstablisherFrame, context, dispatch );
TRACE( "handler at %p returned %u\n", dispatch->LanguageHandler, res ); TRACE( "handler at %p returned %u\n", dispatch->LanguageHandler, res );
rec->ExceptionFlags &= EH_NONCONTINUABLE;
__wine_pop_frame( &frame ); __wine_pop_frame( &frame );
return res; return res;
} }
......
...@@ -218,6 +218,11 @@ void thread_init(void) ...@@ -218,6 +218,11 @@ void thread_init(void)
sizeof(peb->TlsExpansionBitmapBits) * 8 ); sizeof(peb->TlsExpansionBitmapBits) * 8 );
RtlInitializeBitMap( &fls_bitmap, peb->FlsBitmapBits, sizeof(peb->FlsBitmapBits) * 8 ); RtlInitializeBitMap( &fls_bitmap, peb->FlsBitmapBits, sizeof(peb->FlsBitmapBits) * 8 );
RtlSetBits( peb->TlsBitmap, 0, 1 ); /* TLS index 0 is reserved and should be initialized to NULL. */ RtlSetBits( peb->TlsBitmap, 0, 1 ); /* TLS index 0 is reserved and should be initialized to NULL. */
#if defined(__APPLE__) && defined(__x86_64__) && !defined(__i386_on_x86_64__)
while (RtlFindClearBitsAndSet( peb->TlsBitmap, 1, 1 ) != ~0U);
#endif
RtlSetBits( peb->FlsBitmap, 0, 1 ); RtlSetBits( peb->FlsBitmap, 0, 1 );
InitializeListHead( &peb->FlsListHead ); InitializeListHead( &peb->FlsListHead );
InitializeListHead( &ldr.InLoadOrderModuleList ); InitializeListHead( &ldr.InLoadOrderModuleList );
......
...@@ -629,6 +629,8 @@ static void HandleCommandLine(LPWSTR cmdline) ...@@ -629,6 +629,8 @@ static void HandleCommandLine(LPWSTR cmdline)
if (*cmdline == delimiter) cmdline++; if (*cmdline == delimiter) cmdline++;
while (*cmdline == ' ') cmdline++;
ptr = cmdline; ptr = cmdline;
while (*ptr == ' ' || *ptr == '-' || *ptr == '/') while (*ptr == ' ' || *ptr == '-' || *ptr == '/')
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment