char* path_base_file_name( const char* path ) { unsigned int start, end; if( !path ) return string_allocate( 0 ); start = string_find_last_of( path, "/\\", STRING_NPOS ); end = string_find( path, '.', ( start != STRING_NPOS ) ? start : 0 ); //For "dot" files, i.e files with names like "/path/to/.file", return the dot name ".file" if( !end || ( end == ( start + 1 ) ) ) end = STRING_NPOS; if( start != STRING_NPOS ) return string_substr( path, start + 1, ( end != STRING_NPOS ) ? ( end - start - 1 ) : STRING_NPOS ); return string_substr( path, 0, end ); }
char* path_file_name( const char* path ) { unsigned int end = string_find_last_of( path, "/\\", STRING_NPOS ); if( end == STRING_NPOS ) return string_clone( path ); return string_substr( path, end + 1, STRING_NPOS ); }
char* path_protocol( const char* uri ) { unsigned int end = string_find_string( uri, "://", 0 ); if( end == STRING_NPOS ) return string_allocate( 0 ); return string_substr( uri, 0, end ); }
char* path_file_extension( const char* path ) { unsigned int start = string_find_last_of( path, "/\\", STRING_NPOS ); unsigned int end = string_rfind( path, '.', STRING_NPOS ); if( ( end != STRING_NPOS ) && ( ( start == STRING_NPOS ) || ( end > start ) ) ) return string_substr( path, end + 1, STRING_NPOS ); return string_clone( "" ); }
void config_parse_commandline( const char* const* cmdline, unsigned int num ) { //TODO: Implement, format --section:key=value unsigned int arg; for( arg = 0; arg < num; ++arg ) { if( string_match_pattern( cmdline[arg], "--*:*=*" ) ) { unsigned int first_sep = string_find( cmdline[arg], ':', 0 ); unsigned int second_sep = string_find( cmdline[arg], '=', 0 ); if( ( first_sep != STRING_NPOS ) && ( second_sep != STRING_NPOS ) && ( first_sep < second_sep ) ) { unsigned int section_length = first_sep - 2; unsigned int end_pos = first_sep + 1; unsigned int key_length = second_sep - end_pos; const char* section_str = cmdline[arg] + 2; const char* key_str = pointer_offset_const( cmdline[arg], end_pos ); hash_t section = hash( section_str, section_length ); hash_t key = hash( key_str, key_length ); char* value = string_substr( cmdline[arg], second_sep + 1, STRING_NPOS ); char* set_value = value; unsigned int value_length = string_length( value ); if( !value_length ) config_set_string( section, key, "" ); else if( string_equal( value, "false" ) ) config_set_bool( section, key, false ); else if( string_equal( value, "true" ) ) config_set_bool( section, key, true ); else if( ( string_find( value, '.', 0 ) != STRING_NPOS ) && ( string_find_first_not_of( value, "0123456789.", 0 ) == STRING_NPOS ) && ( string_find( value, '.', string_find( value, '.', 0 ) + 1 ) == STRING_NPOS ) ) //Exactly one "." config_set_real( section, key, string_to_real( value ) ); else if( string_find_first_not_of( value, "0123456789", 0 ) == STRING_NPOS ) config_set_int( section, key, string_to_int64( value ) ); else { if( ( value_length > 1 ) && ( value[0] == '"' ) && ( value[ value_length - 1 ] == '"' ) ) { value[ value_length - 1 ] = 0; set_value = value + 1; config_set_string( section, key, set_value ); } else { config_set_string( section, key, value ); } } log_infof( HASH_CONFIG, "Config value from command line: %.*s:%.*s = %s", section_length, section_str, key_length, key_str, set_value ); string_deallocate( value ); } } } }
String String::substr(int start, int length /* = 0x7FFFFFFF */, bool nullable /* = false */) const { int len = size(); char *ret = string_substr(data(), len, start, length, nullable); if (ret) { return String(ret, len, AttachString); } return String(); }
static int glsl_dim_from_token(const string_const_t token) { string_const_t dim; size_t ofs = string_find(STRING_ARGS(token), '[', 0); if (ofs == STRING_NPOS) return 1; ++ofs; dim = string_substr(STRING_ARGS(token), ofs, string_find(STRING_ARGS(token), ']', ofs) - ofs); return string_to_int(STRING_ARGS(dim)); }
static NOINLINE char* _expand_string( hash_t section_current, char* str ) { char* expanded; char* variable; unsigned int var_pos, var_end_pos, variable_length, separator, var_offset; hash_t section, key; expanded = str; var_pos = string_find_string( expanded, "$(", 0 ); while( var_pos != STRING_NPOS ) { var_end_pos = string_find( expanded, ')', var_pos + 2 ); FOUNDATION_ASSERT_MSG( var_end_pos != STRING_NPOS, "Malformed config variable statement" ); variable = string_substr( expanded, var_pos, ( var_end_pos != STRING_NPOS ) ? ( 1 + var_end_pos - var_pos ) : STRING_NPOS ); section = section_current; key = 0; variable_length = string_length( variable ); separator = string_find( variable, ':', 0 ); if( separator != STRING_NPOS ) { if( separator != 2 ) section = hash( variable + 2, separator - 2 ); var_offset = separator + 1; } else { var_offset = 2; } key = hash( variable + var_offset, variable_length - ( var_offset + ( variable[ variable_length - 1 ] == ')' ? 1 : 0 ) ) ); if( expanded == str ) expanded = string_clone( str ); if( section != HASH_ENVIRONMENT ) expanded = string_replace( expanded, variable, config_string( section, key ), false ); else expanded = string_replace( expanded, variable, _expand_environment( key, variable + var_offset ), false ); string_deallocate( variable ); var_pos = string_find_string( expanded, "$(", 0 ); } #if BUILD_ENABLE_DEBUG_CONFIG if( str != expanded ) log_debugf( HASH_CONFIG, "Expanded config value \"%s\" to \"%s\"", str, expanded ); #endif return expanded; }
char* path_base_file_name_with_path( const char* path ) { unsigned int start, end; char* base; if( !path ) return string_allocate( 0 ); start = string_find_last_of( path, "/\\", STRING_NPOS ); end = string_rfind( path, '.', STRING_NPOS ); //For "dot" files, i.e files with names like "/path/to/.file", return the dot name ".file" if( !end || ( end == ( start + 1 ) ) || ( ( start != STRING_NPOS ) && ( end < start ) ) ) end = STRING_NPOS; base = string_substr( path, 0, ( end != STRING_NPOS ) ? end : STRING_NPOS ); base = path_clean( base, path_is_absolute( base ) ); return base; }
char* path_directory_name( const char* path ) { char* pathname; unsigned int pathprotocol; unsigned int pathstart = 0; unsigned int end = string_find_last_of( path , "/\\", STRING_NPOS ); if( end == 0 ) return string_clone( "/" ); if( end == STRING_NPOS ) return string_allocate( 0 ); pathprotocol = string_find_string( path, "://", 0 ); if( pathprotocol != STRING_NPOS ) pathstart = pathprotocol +=2; // add two to treat as absolute path pathname = string_substr( path, pathstart, end - pathstart ); pathname = path_clean( pathname, path_is_absolute( pathname ) ); return pathname; }
char* path_subdirectory_name( const char* path, const char* root ) { char* subpath; char* testpath; char* testroot; char* pathofpath; unsigned int pathprotocol, rootprotocol; char* cpath = string_clone( path ); char* croot = string_clone( root ); cpath = path_clean( cpath, path_is_absolute( cpath ) ); croot = path_clean( croot, path_is_absolute( croot ) ); pathofpath = path_directory_name( cpath ); testpath = pathofpath; pathprotocol = string_find_string( testpath, "://", 0 ); if( pathprotocol != STRING_NPOS ) testpath += pathprotocol + 2; // add two to treat as absolute path testroot = croot; rootprotocol = string_find_string( testroot, "://", 0 ); if( rootprotocol != STRING_NPOS ) testroot += rootprotocol + 2; if( ( rootprotocol != STRING_NPOS ) && ( ( pathprotocol == STRING_NPOS ) || ( pathprotocol != rootprotocol ) || !string_equal_substr( cpath, croot, rootprotocol ) ) ) subpath = string_allocate( 0 ); else if( !string_equal_substr( testpath, testroot, string_length( testroot ) ) ) subpath = string_allocate( 0 ); else { char* filename = path_file_name( cpath ); subpath = string_substr( testpath, string_length( testroot ), STRING_NPOS ); subpath = path_clean( path_append( subpath, filename ), false ); string_deallocate( filename ); } string_deallocate( pathofpath ); string_deallocate( cpath ); string_deallocate( croot ); return subpath; }
void config_load( const char* name, hash_t filter_section, bool built_in, bool overwrite ) { /*lint --e{838} Safety null assign all pointers for all preprocessor paths */ /*lint --e{750} Unused macros in some paths */ #define NUM_SEARCH_PATHS 10 #define ANDROID_ASSET_PATH_INDEX 5 char* sub_exe_path = 0; char* exe_parent_path = 0; char* exe_processed_path = 0; char* abs_exe_parent_path = 0; char* abs_exe_processed_path = 0; char* bundle_path = 0; char* home_dir = 0; char* cmdline_path = 0; char* cwd_config_path = 0; const char* paths[NUM_SEARCH_PATHS]; #if !FOUNDATION_PLATFORM_FAMILY_MOBILE const char* const* cmd_line; int icl, clsize; #endif int start_path, i, j; const char buildsuffix[4][9] = { "/debug", "/release", "/profile", "/deploy" }; const char platformsuffix[7][14] = { "/win32", "/win64", "/osx", "/ios", "/android", "/raspberrypi", "/unknown" }; const char binsuffix[1][5] = { "/bin" }; FOUNDATION_ASSERT( name ); sub_exe_path = path_merge( environment_executable_directory(), "config" ); exe_parent_path = path_merge( environment_executable_directory(), "../config" ); abs_exe_parent_path = path_make_absolute( exe_parent_path ); exe_processed_path = string_clone( environment_executable_directory() ); for( i = 0; i < 4; ++i ) { if( string_ends_with( exe_processed_path, buildsuffix[i] ) ) { exe_processed_path[ string_length( exe_processed_path ) - string_length( buildsuffix[i] ) ] = 0; break; } } for( i = 0; i < 7; ++i ) { if( string_ends_with( exe_processed_path, platformsuffix[i] ) ) { exe_processed_path[ string_length( exe_processed_path ) - string_length( platformsuffix[i] ) ] = 0; break; } } for( i = 0; i < 1; ++i ) { if( string_ends_with( exe_processed_path, binsuffix[i] ) ) { exe_processed_path[ string_length( exe_processed_path ) - string_length( binsuffix[i] ) ] = 0; break; } } exe_processed_path = path_append( exe_processed_path, "config" ); abs_exe_processed_path = path_make_absolute( exe_processed_path ); paths[0] = environment_executable_directory(); paths[1] = sub_exe_path; paths[2] = abs_exe_parent_path; paths[3] = abs_exe_processed_path; #if FOUNDATION_PLATFORM_FAMILY_DESKTOP && !BUILD_DEPLOY paths[4] = environment_initial_working_directory(); #else paths[4] = 0; #endif #if FOUNDATION_PLATFORM_APPLE bundle_path = path_merge( environment_executable_directory(), "../Resources/config" ); paths[5] = bundle_path; #elif FOUNDATION_PLATFORM_ANDROID paths[5] = "/config"; #else paths[5] = 0; #endif #if FOUNDATION_PLATFORM_FAMILY_DESKTOP paths[6] = environment_current_working_directory(); #else paths[6] = 0; #endif paths[7] = 0; paths[8] = 0; string_deallocate( exe_parent_path ); string_deallocate( exe_processed_path ); #if FOUNDATION_PLATFORM_FAMILY_DESKTOP cwd_config_path = path_merge( environment_current_working_directory(), "config" ); paths[7] = cwd_config_path; cmd_line = environment_command_line(); /*lint -e{850} We modify loop var to skip extra arg */ for( icl = 0, clsize = array_size( cmd_line ); icl < clsize; ++icl ) { /*lint -e{613} array_size( cmd_line ) in loop condition does the null pointer guard */ if( string_equal_substr( cmd_line[icl], "--configdir", 11 ) ) { if( string_equal_substr( cmd_line[icl], "--configdir=", 12 ) ) { paths[8] = cmdline_path = string_substr( cmd_line[icl], 12, STRING_NPOS ); } else if( icl < ( clsize - 1 ) ) { paths[8] = cmdline_path = string_clone( cmd_line[++icl] ); } } } #endif start_path = 0; if( !built_in ) { #if FOUNDATION_PLATFORM_WINDOWS home_dir = path_merge( environment_home_directory(), environment_application()->config_dir ); #elif FOUNDATION_PLATFORM_LINUX || FOUNDATION_PLATFORM_MACOSX home_dir = path_prepend( string_concat( ".", environment_application()->config_dir ), environment_home_directory() ); #endif if( home_dir ) paths[9] = home_dir; start_path = 9; } else { paths[9] = 0; } for( i = start_path; i < NUM_SEARCH_PATHS; ++i ) { char* filename; stream_t* istream; bool path_already_searched = false; if( !paths[i] ) continue; for( j = start_path; j < i; ++j ) { if( paths[j] && string_equal( paths[j], paths[i] ) ) { path_already_searched = true; break; } } if( path_already_searched ) continue; //TODO: Support loading configs from virtual file system (i.e in zip/other packages) filename = string_append( path_merge( paths[i], name ), ".ini" ); istream = 0; #if FOUNDATION_PLATFORM_ANDROID if( i == ANDROID_ASSET_PATH_INDEX ) istream = asset_stream_open( filename, STREAM_IN ); else #endif istream = stream_open( filename, STREAM_IN ); if( istream ) { config_parse( istream, filter_section, overwrite ); stream_deallocate( istream ); } string_deallocate( filename ); if( built_in ) { const char* FOUNDATION_PLATFORM_name = #if FOUNDATION_PLATFORM_WINDOWS "windows"; #elif FOUNDATION_PLATFORM_LINUX_RASPBERRYPI "raspberrypi"; #elif FOUNDATION_PLATFORM_LINUX "linux"; #elif FOUNDATION_PLATFORM_MACOSX "osx"; #elif FOUNDATION_PLATFORM_IOS "ios"; #elif FOUNDATION_PLATFORM_ANDROID "android"; #else # error Insert platform name "unknown"; #endif filename = string_append( path_append( path_merge( paths[i], FOUNDATION_PLATFORM_name ), name ), ".ini" ); #if FOUNDATION_PLATFORM_ANDROID if( i == ANDROID_ASSET_PATH_INDEX ) istream = asset_stream_open( filename, STREAM_IN ); else #endif istream = stream_open( filename, STREAM_IN ); if( istream ) { config_parse( istream, filter_section, overwrite ); stream_deallocate( istream ); } string_deallocate( filename ); } } string_deallocate( home_dir ); string_deallocate( cmdline_path ); string_deallocate( sub_exe_path ); string_deallocate( abs_exe_processed_path ); string_deallocate( abs_exe_parent_path ); string_deallocate( bundle_path ); string_deallocate( cwd_config_path ); }
int main_run( void* main_arg ) { #if !BUILD_MONOLITHIC const char* pattern = 0; char** exe_paths = 0; unsigned int iexe, exesize; process_t* process = 0; char* process_path = 0; unsigned int* exe_flags = 0; #endif #if FOUNDATION_PLATFORM_IOS || FOUNDATION_PLATFORM_ANDROID || FOUNDATION_PLATFORM_PNACL int remain_counter = 0; #endif #if BUILD_DEBUG const char* build_name = "debug"; #elif BUILD_RELEASE const char* build_name = "release"; #elif BUILD_PROFILE const char* build_name = "profile"; #elif BUILD_DEPLOY const char* build_name = "deploy"; #endif int process_result = 0; object_t thread = 0; FOUNDATION_UNUSED( main_arg ); FOUNDATION_UNUSED( build_name ); log_set_suppress( HASH_TEST, ERRORLEVEL_DEBUG ); log_infof( HASH_TEST, "Foundation library v%s built for %s using %s (%s)", string_from_version_static( foundation_version() ), FOUNDATION_PLATFORM_DESCRIPTION, FOUNDATION_COMPILER_DESCRIPTION, build_name ); thread = thread_create( event_thread, "event_thread", THREAD_PRIORITY_NORMAL, 0 ); thread_start( thread, 0 ); while( !thread_is_running( thread ) ) thread_sleep( 10 ); #if FOUNDATION_PLATFORM_IOS || FOUNDATION_PLATFORM_ANDROID while( !_test_should_start ) { #if FOUNDATION_PLATFORM_ANDROID system_process_events(); #endif thread_sleep( 100 ); } #endif fs_remove_directory( environment_temporary_directory() ); #if BUILD_MONOLITHIC test_run_fn tests[] = { test_app_run, test_array_run, test_atomic_run, test_base64_run, test_bitbuffer_run, test_blowfish_run, test_bufferstream_run, test_config_run, test_crash_run, test_environment_run, test_error_run, test_event_run, test_fs_run, test_hash_run, test_hashmap_run, test_hashtable_run, test_library_run, test_math_run, test_md5_run, test_mutex_run, test_objectmap_run, test_path_run, test_pipe_run, test_process_run, test_profile_run, test_radixsort_run, test_random_run, test_regex_run, test_ringbuffer_run, test_semaphore_run, test_stacktrace_run, test_stream_run, //stream test closes stdin test_string_run, test_system_run, test_time_run, test_uuid_run, 0 }; #if FOUNDATION_PLATFORM_ANDROID object_t test_thread = thread_create( test_runner, "test_runner", THREAD_PRIORITY_NORMAL, 0 ); thread_start( test_thread, tests ); log_debug( HASH_TEST, "Starting test runner thread" ); while( !thread_is_running( test_thread ) ) { system_process_events(); thread_sleep( 10 ); } while( thread_is_running( test_thread ) ) { system_process_events(); thread_sleep( 10 ); } process_result = (int)(intptr_t)thread_result( test_thread ); thread_destroy( test_thread ); while( thread_is_thread( test_thread ) ) { system_process_events(); thread_sleep( 10 ); } #else process_result = (int)(intptr_t)test_runner( 0, tests ); #endif if( process_result != 0 ) log_warnf( HASH_TEST, WARNING_SUSPICIOUS, "Tests failed with exit code %d", process_result ); #if FOUNDATION_PLATFORM_IOS || FOUNDATION_PLATFORM_ANDROID || FOUNDATION_PLATFORM_PNACL while( !_test_should_terminate && _test_have_focus && ( remain_counter < 50 ) ) { system_process_events(); thread_sleep( 100 ); ++remain_counter; } #endif log_debug( HASH_TEST, "Exiting main loop" ); #else // !BUILD_MONOLITHIC //Find all test executables in the current executable directory #if FOUNDATION_PLATFORM_WINDOWS pattern = "^test-.*\\.exe$"; #elif FOUNDATION_PLATFORM_MACOSX pattern = "^test-.*$"; #elif FOUNDATION_PLATFORM_POSIX pattern = "^test-.*$"; #else # error Not implemented #endif exe_paths = fs_matching_files( environment_executable_directory(), pattern, false ); array_resize( exe_flags, array_size( exe_paths ) ); memset( exe_flags, 0, sizeof( unsigned int ) * array_size( exe_flags ) ); #if FOUNDATION_PLATFORM_MACOSX //Also search for test applications const char* app_pattern = "^test-.*\\.app$"; regex_t* app_regex = regex_compile( app_pattern ); char** subdirs = fs_subdirs( environment_executable_directory() ); for( int idir = 0, dirsize = array_size( subdirs ); idir < dirsize; ++idir ) { if( regex_match( app_regex, subdirs[idir], string_length( subdirs[idir] ), 0, 0 ) ) { array_push( exe_paths, string_substr( subdirs[idir], 0, string_length( subdirs[idir] ) - 4 ) ); array_push( exe_flags, PROCESS_MACOSX_USE_OPENAPPLICATION ); } } string_array_deallocate( subdirs ); regex_deallocate( app_regex ); #endif for( iexe = 0, exesize = array_size( exe_paths ); iexe < exesize; ++iexe ) { bool is_self = false; char* exe_file_name = path_base_file_name( exe_paths[iexe] ); if( string_equal( exe_file_name, environment_executable_name() ) ) is_self = true; string_deallocate( exe_file_name ); if( is_self ) continue; //Don't run self process_path = path_merge( environment_executable_directory(), exe_paths[iexe] ); process = process_allocate(); process_set_executable_path( process, process_path ); process_set_working_directory( process, environment_executable_directory() ); process_set_flags( process, PROCESS_ATTACHED | exe_flags[iexe] ); log_infof( HASH_TEST, "Running test executable: %s", exe_paths[iexe] ); process_result = process_spawn( process ); while( process_result == PROCESS_WAIT_INTERRUPTED ) { thread_sleep( 10 ); process_result = process_wait( process ); } process_deallocate( process ); string_deallocate( process_path ); if( process_result != 0 ) { if( process_result >= PROCESS_INVALID_ARGS ) log_warnf( HASH_TEST, WARNING_SUSPICIOUS, "Tests failed, process terminated with error %x", process_result ); else log_warnf( HASH_TEST, WARNING_SUSPICIOUS, "Tests failed with exit code %d", process_result ); process_set_exit_code( -1 ); goto exit; } log_infof( HASH_TEST, "All tests from %s passed (%d)", exe_paths[iexe], process_result ); } log_info( HASH_TEST, "All tests passed" ); exit: if( exe_paths ) string_array_deallocate( exe_paths ); array_deallocate( exe_flags ); #endif thread_terminate( thread ); thread_destroy( thread ); while( thread_is_running( thread ) ) thread_sleep( 10 ); while( thread_is_thread( thread ) ) thread_sleep( 10 ); log_infof( HASH_TEST, "Tests exiting: %d", process_result ); return process_result; }
int process_spawn( process_t* proc ) { static char unescaped[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.:/\\"; int i, num_args; int size; #if FOUNDATION_PLATFORM_WINDOWS wchar_t* wcmdline; wchar_t* wwd; char* cmdline = 0; #endif if( !proc ) return PROCESS_INVALID_ARGS; proc->code = PROCESS_INVALID_ARGS; if( !string_length( proc->path ) ) return proc->code; //Always escape path on Windows platforms #if FOUNDATION_PLATFORM_POSIX if( string_find_first_not_of( proc->path, unescaped, 0 ) != STRING_NPOS ) #endif { if( proc->path[0] != '"' ) proc->path = string_prepend( proc->path, "\"" ); if( proc->path[ string_length( proc->path ) - 1 ] != '"' ) proc->path = string_append( proc->path, "\"" ); } size = array_size( proc->args ); for( i = 0, num_args = 0; i < size; ++i ) { char* arg = proc->args[i]; if( !string_length( arg ) ) continue; ++num_args; if( string_find_first_not_of( arg, unescaped, 0 ) != STRING_NPOS ) { if( arg[0] != '"' ) { //Check if we need to escape " characters unsigned int pos = string_find( arg, '"', 0 ); while( pos != STRING_NPOS ) { if( arg[ pos - 1 ] != '\\' ) { char* escarg = string_substr( arg, 0, pos ); char* left = string_substr( arg, pos, STRING_NPOS ); escarg = string_append( escarg, "\\" ); escarg = string_append( escarg, left ); string_deallocate( left ); string_deallocate( arg ); arg = escarg; } pos = string_find( arg, '"', pos + 2 ); } arg = string_prepend( arg, "\"" ); arg = string_append( arg, "\"" ); proc->args[i] = arg; } } } #if FOUNDATION_PLATFORM_WINDOWS # ifndef SEE_MASK_NOASYNC # define SEE_MASK_NOASYNC 0x00000100 # endif if( !( proc->flags & PROCESS_WINDOWS_USE_SHELLEXECUTE ) ) //Don't prepend exe path to parameters if using ShellExecute cmdline = string_clone( proc->path ); //Build command line string for( i = 0; i < size; ++i ) { char* arg = proc->args[i]; if( !string_length( arg ) ) continue; if( cmdline ) cmdline = string_append( cmdline, " " ); cmdline = string_append( cmdline, arg ); } if( !string_length( proc->wd ) ) proc->wd = string_clone( environment_current_working_directory() ); wcmdline = wstring_allocate_from_string( cmdline, 0 ); wwd = wstring_allocate_from_string( proc->wd, 0 ); if( proc->flags & PROCESS_WINDOWS_USE_SHELLEXECUTE ) { SHELLEXECUTEINFOW sei; wchar_t* wverb; wchar_t* wpath; wverb = ( proc->verb && string_length( proc->verb ) ) ? wstring_allocate_from_string( proc->verb, 0 ) : 0; wpath = wstring_allocate_from_string( proc->path, 0 ); ZeroMemory( &sei, sizeof( sei ) ); sei.cbSize = sizeof(SHELLEXECUTEINFOW); sei.hwnd = 0; sei.fMask = SEE_MASK_NOASYNC | SEE_MASK_FLAG_NO_UI | SEE_MASK_NOCLOSEPROCESS; sei.lpVerb = wverb; sei.lpFile = wpath; sei.lpParameters = wcmdline; sei.lpDirectory = wwd; sei.nShow = SW_SHOWNORMAL; if( !( proc->flags & PROCESS_CONSOLE ) ) sei.fMask |= SEE_MASK_NO_CONSOLE; if( proc->flags & PROCESS_STDSTREAMS ) log_warnf( 0, WARNING_UNSUPPORTED, "Unable to redirect standard in/out through pipes when using ShellExecute for process spawning" ); log_debugf( 0, "Spawn process (ShellExecute): %s %s", proc->path, cmdline ); if( !ShellExecuteExW( &sei ) ) { log_warnf( 0, WARNING_SYSTEM_CALL_FAIL, "Unable to spawn process (ShellExecute) for executable '%s': %s", proc->path, system_error_message( GetLastError() ) ); } else { proc->hp = sei.hProcess; proc->ht = 0; proc->code = 0; } wstring_deallocate( wverb ); wstring_deallocate( wpath ); } else { STARTUPINFOW si; PROCESS_INFORMATION pi; BOOL inherit_handles = FALSE; memset( &si, 0, sizeof( si ) ); memset( &pi, 0, sizeof( pi ) ); si.cb = sizeof( si ); if( proc->flags & PROCESS_STDSTREAMS ) { proc->pipeout = pipe_allocate(); proc->pipein = pipe_allocate(); si.dwFlags |= STARTF_USESTDHANDLES; si.hStdOutput = pipe_write_handle( proc->pipeout ); si.hStdError = pipe_write_handle( proc->pipeout ); si.hStdInput = pipe_read_handle( proc->pipein ); //Don't inherit wrong ends of pipes SetHandleInformation( pipe_read_handle( proc->pipeout ), HANDLE_FLAG_INHERIT, 0 ); SetHandleInformation( pipe_write_handle( proc->pipein ), HANDLE_FLAG_INHERIT, 0 ); inherit_handles = TRUE; } log_debugf( 0, "Spawn process (CreateProcess): %s %s", proc->path, cmdline ); if( !CreateProcessW( 0/*wpath*/, wcmdline, 0, 0, inherit_handles, ( proc->flags & PROCESS_CONSOLE ) ? CREATE_NEW_CONSOLE : 0, 0, wwd, &si, &pi ) ) { log_warnf( 0, WARNING_SYSTEM_CALL_FAIL, "Unable to spawn process (CreateProcess) for executable '%s': %s", proc->path, system_error_message( GetLastError() ) ); stream_deallocate( proc->pipeout ); stream_deallocate( proc->pipein ); proc->pipeout = 0; proc->pipein = 0; } else { proc->hp = pi.hProcess; proc->ht = pi.hThread; proc->code = 0; } if( proc->pipeout ) pipe_close_write( proc->pipeout ); if( proc->pipein ) pipe_close_read( proc->pipein ); } wstring_deallocate( wcmdline ); wstring_deallocate( wwd ); string_deallocate( cmdline ); if( proc->code < 0 ) return proc->code; //Error #endif #if FOUNDATION_PLATFORM_MACOSX if( proc->flags & PROCESS_OSX_USE_OPENAPPLICATION ) { proc->pid = 0; LSApplicationParameters params; ProcessSerialNumber psn; FSRef* fsref = memory_allocate( 0, sizeof( FSRef ), 0, MEMORY_TEMPORARY | MEMORY_ZERO_INITIALIZED ); memset( ¶ms, 0, sizeof( LSApplicationParameters ) ); memset( &psn, 0, sizeof( ProcessSerialNumber ) ); char* pathstripped = string_strip( string_clone( proc->path ), "\"" ); OSStatus status = 0; status = FSPathMakeRef( (uint8_t*)pathstripped, fsref, 0 ); if( status < 0 ) { pathstripped = string_append( pathstripped, ".app" ); status = FSPathMakeRef( (uint8_t*)pathstripped, fsref, 0 ); } CFStringRef* args = 0; for( i = 0, size = array_size( proc->args ); i < size; ++i ) //App gets executable path automatically, don't include array_push( args, CFStringCreateWithCString( 0, proc->args[i], kCFStringEncodingUTF8 ) ); CFArrayRef argvref = CFArrayCreate( 0, (const void**)args, (CFIndex)array_size( args ), 0 ); params.flags = kLSLaunchDefaults; params.application = fsref; params.argv = argvref; log_debugf( 0, "Spawn process (LSOpenApplication): %s", pathstripped ); status = LSOpenApplication( ¶ms, &psn ); if( status != 0 ) { proc->code = status; log_warnf( 0, WARNING_BAD_DATA, "Unable to spawn process for executable '%s': %s", proc->path, system_error_message( status ) ); } CFRelease( argvref ); for( i = 0, size = array_size( args ); i < size; ++i ) CFRelease( args[i] ); memory_deallocate( fsref ); string_deallocate( pathstripped ); if( status == 0 ) { pid_t pid = 0; GetProcessPID( &psn, &pid ); proc->pid = pid; //Always "detached" with LSOpenApplication, not a child process at all //Setup a kqueue to watch when process terminates so we can emulate a wait proc->kq = kqueue(); if( proc->kq < 0 ) { log_warnf( 0, WARNING_SYSTEM_CALL_FAIL, "Unable to create kqueue for process watch: %s (%d)", proc->kq, system_error_message( proc->kq ) ); proc->kq = 0; } else { struct kevent changes; EV_SET( &changes, (pid_t)pid, EVFILT_PROC, EV_ADD | EV_RECEIPT, NOTE_EXIT, 0, 0 ); int ret = kevent( proc->kq, &changes, 1, &changes, 1, 0 ); if( ret != 1 ) { log_warnf( 0, WARNING_SYSTEM_CALL_FAIL, "Unable to setup kqueue for process watch, failed to add event to kqueue (%d)", ret ); close( proc->kq ); proc->kq = 0; } } } goto exit; } #endif #if FOUNDATION_PLATFORM_POSIX //Insert executable arg at start and null ptr at end int argc = array_size( proc->args ) + 1; array_grow( proc->args, 2 ); for( int arg = argc - 1; arg > 0; --arg ) proc->args[arg] = proc->args[arg-1]; proc->args[0] = string_clone( proc->path ); proc->args[argc] = 0; if( proc->flags & PROCESS_STDSTREAMS ) { proc->pipeout = pipe_allocate(); proc->pipein = pipe_allocate(); } proc->pid = 0; pid_t pid = fork(); if( pid == 0 ) { //Child if( string_length( proc->wd ) ) { log_debugf( 0, "Spawned child process, setting working directory to %s", proc->wd ); environment_set_current_working_directory( proc->wd ); } log_debugf( 0, "Child process executing: %s", proc->path ); if( proc->flags & PROCESS_STDSTREAMS ) { pipe_close_read( proc->pipeout ); dup2( pipe_write_fd( proc->pipeout ), STDOUT_FILENO ); pipe_close_write( proc->pipein ); dup2( pipe_read_fd( proc->pipein ), STDIN_FILENO ); } int code = execv( proc->path, proc->args ); if( code < 0 ) //Will always be true since this point will never be reached if execve() is successful log_warnf( 0, WARNING_BAD_DATA, "Child process failed execve() : %s : %s", proc->path, system_error_message( errno ) ); //Error process_exit( -1 ); } if( pid > 0 ) { log_debugf( 0, "Child process forked, pid %d", pid ); proc->pid = pid; if( proc->pipeout ) pipe_close_write( proc->pipeout ); if( proc->pipein ) pipe_close_read( proc->pipein ); if( proc->flags & PROCESS_DETACHED ) { int cstatus = 0; pid_t err = waitpid( pid, &cstatus, WNOHANG ); if( err == 0 ) { //TODO: Ugly wait to make sure process spawned correctly thread_sleep( 500 ); err = waitpid( pid, &cstatus, WNOHANG ); } if( err > 0 ) { //Process exited, check code proc->code = (int)((char)WEXITSTATUS( cstatus )); log_debugf( 0, "Child process returned: %d", proc->code ); return proc->code; } } } else { //Error proc->code = errno; log_warnf( 0, WARNING_BAD_DATA, "Unable to spawn process: %s : %s", proc->path, system_error_message( proc->code ) ); if( proc->pipeout ) stream_deallocate( proc->pipeout ); if( proc->pipein ) stream_deallocate( proc->pipein ); proc->pipeout = 0; proc->pipein = 0; return proc->code; } #endif #if !FOUNDATION_PLATFORM_WINDOWS && !FOUNDATION_PLATFORM_POSIX FOUNDATION_ASSERT_FAIL( "Process spawning not supported on platform" ); #endif #if FOUNDATION_PLATFORM_MACOSX exit: #endif if( proc->flags & PROCESS_DETACHED ) return PROCESS_STILL_ACTIVE; return process_wait( proc ); }
DECLARE_TEST( string, utility ) { { char* path1 = string_clone( "" ); char* path2 = string_clone( "/" ); char* path3 = string_clone( "/." ); char* path4 = string_clone( "./" ); char* path5 = string_clone( "./." ); char* path6 = string_clone( "././" ); char* path7 = string_clone( "././//" ); char* path8 = string_clone( "././//./////././////.//////.//." ); char* path9 = string_clone( "http://././//./////././////.//////.//." ); char* path10 = string_clone( "" ); char* path11 = string_clone( "\\" ); char* path12 = string_clone( "/\\." ); char* path13 = string_clone( ".\\/" ); char* path14 = string_clone( "./\\." ); char* path15 = string_clone( ".\\.//\\" ); char* path16 = string_clone( ".\\.\\\\\\" ); char* path17 = string_clone( ".\\.\\\\\\.\\\\////\\///\\\\.\\.\\\\\\\\\\.\\\\\\\\\\\\.\\\\." ); char* path18 = string_clone( "http://\\.\\.\\\\\\.\\\\\\\\//\\.\\.\\\\\\\\//\\.\\\\\\\\\\\\.\\\\." ); char* path19 = string_clone( "testing/path/ext" ); char* path20 = string_clone( "testing/path/extend" ); char* path21 = string_clone( "testing/path/extend/dyn" ); char* path22 = string_clone( "testing/./\\\\/\\/./path/././//./extend/\\\\" ); path1 = path_clean( path1, true ); path2 = path_clean( path2, true ); path3 = path_clean( path3, true ); path4 = path_clean( path4, true ); path5 = path_clean( path5, true ); path6 = path_clean( path6, true ); path7 = path_clean( path7, true ); path8 = path_clean( path8, true ); path9 = path_clean( path9, true ); path10 = path_clean( path10, true ); path11 = path_clean( path11, true ); path12 = path_clean( path12, true ); path13 = path_clean( path13, true ); path14 = path_clean( path14, true ); path15 = path_clean( path15, true ); path16 = path_clean( path16, true ); path17 = path_clean( path17, true ); path18 = path_clean( path18, true ); path19 = path_clean( path19, true ); path20 = path_clean( path20, true ); path21 = path_clean( path21, true ); path22 = path_clean( path22, true ); EXPECT_TRUE( string_equal( path1, "/" ) ); EXPECT_TRUE( string_equal( path2, "/" ) ); EXPECT_TRUE( string_equal( path3, "/" ) ); EXPECT_TRUE( string_equal( path4, "/" ) ); EXPECT_TRUE( string_equal( path5, "/" ) ); EXPECT_TRUE( string_equal( path6, "/" ) ); EXPECT_TRUE( string_equal( path7, "/" ) ); EXPECT_TRUE( string_equal( path8, "/" ) ); EXPECT_TRUE( string_equal( path9, "http://" ) ); EXPECT_TRUE( string_equal( path10, "/" ) ); EXPECT_TRUE( string_equal( path11, "/" ) ); EXPECT_TRUE( string_equal( path12, "/" ) ); EXPECT_TRUE( string_equal( path13, "/" ) ); EXPECT_TRUE( string_equal( path14, "/" ) ); EXPECT_TRUE( string_equal( path15, "/" ) ); EXPECT_TRUE( string_equal( path16, "/" ) ); EXPECT_TRUE( string_equal( path17, "/" ) ); EXPECT_TRUE( string_equal( path18, "http://" ) ); EXPECT_TRUE( string_equal( path19, "/testing/path/ext" ) ); EXPECT_TRUE( string_equal( path20, "/testing/path/extend" ) ); EXPECT_TRUE( string_equal( path21, "/testing/path/extend/dyn" ) ); EXPECT_TRUE( string_equal( path22, "/testing/path/extend" ) ); string_deallocate( path1 ); string_deallocate( path2 ); string_deallocate( path3 ); string_deallocate( path4 ); string_deallocate( path5 ); string_deallocate( path6 ); string_deallocate( path7 ); string_deallocate( path8 ); string_deallocate( path9 ); string_deallocate( path10 ); string_deallocate( path11 ); string_deallocate( path12 ); string_deallocate( path13 ); string_deallocate( path14 ); string_deallocate( path15 ); string_deallocate( path16 ); string_deallocate( path17 ); string_deallocate( path18 ); string_deallocate( path19 ); string_deallocate( path20 ); string_deallocate( path21 ); string_deallocate( path22 ); } { char** explodearr = 0; char* explodestr = string_clone( " .,testing, .,utility.,string methods ..., like,,,finds split..merge .,.explode.and. .., ., similar .,,,. " ); char* mergestr = string_clone( " testing merge string " ); char* mergestr2 = string_clone( " ., testing, .merge.string,. " ); char* merged = 0; char** mergearr, **mergearr2, **mergearr3; char* splitstr = string_clone( " testing split" ); char* splitright = 0, *splitleft = 0; char* splitright2 = 0, *splitleft2 = 0; char* substrtest = string_clone( "testing substr" ); char* substr = 0; explodearr = string_explode( explodestr, " ,.", false ); mergearr = string_explode( mergestr, " .,", true ); mergearr2 = string_explode( mergestr, " .,", false ); mergearr3 = string_explode( mergestr, " .,", true ); merged = string_merge( (const char* const*)mergearr, array_size( mergearr ), " " ); string_split( splitstr, " ", &splitleft, &splitright, false ); string_split( splitstr, " ", &splitleft2, &splitright2, true ); EXPECT_EQ( array_size( explodearr ), 11 ); EXPECT_TRUE( string_equal( explodearr[0], "testing" ) ); EXPECT_TRUE( string_equal( explodearr[1], "utility" ) ); EXPECT_TRUE( string_equal( explodearr[2], "string" ) ); EXPECT_TRUE( string_equal( explodearr[3], "methods" ) ); EXPECT_TRUE( string_equal( explodearr[4], "like" ) ); EXPECT_TRUE( string_equal( explodearr[5], "finds" ) ); EXPECT_TRUE( string_equal( explodearr[6], "split" ) ); EXPECT_TRUE( string_equal( explodearr[7], "merge" ) ); EXPECT_TRUE( string_equal( explodearr[8], "explode" ) ); EXPECT_TRUE( string_equal( explodearr[9], "and" ) ); EXPECT_TRUE( string_equal( explodearr[10], "similar" ) ); EXPECT_EQ( array_size( mergearr ), 12 ); EXPECT_TRUE( string_equal( mergearr[0], "" ) ); EXPECT_TRUE( string_equal( mergearr[1], "" ) ); EXPECT_TRUE( string_equal( mergearr[2], "" ) ); EXPECT_TRUE( string_equal( mergearr[3], "" ) ); EXPECT_TRUE( string_equal( mergearr[4], "testing" ) ); EXPECT_TRUE( string_equal( mergearr[5], "" ) ); EXPECT_TRUE( string_equal( mergearr[6], "" ) ); EXPECT_TRUE( string_equal( mergearr[7], "merge" ) ); EXPECT_TRUE( string_equal( mergearr[8], "string" ) ); EXPECT_TRUE( string_equal( mergearr[9], "" ) ); EXPECT_TRUE( string_equal( mergearr[10], "" ) ); EXPECT_TRUE( string_equal( mergearr[11], "" ) ); EXPECT_EQ( array_size( mergearr2 ), 3 ); EXPECT_TRUE( string_equal( mergearr2[0], "testing" ) ); EXPECT_TRUE( string_equal( mergearr2[1], "merge" ) ); EXPECT_TRUE( string_equal( mergearr2[2], "string" ) ); EXPECT_TRUE( string_equal( merged, mergestr ) ); EXPECT_EQ( array_size( mergearr3 ), 12 ); EXPECT_TRUE( string_equal( mergearr3[0], "" ) ); EXPECT_TRUE( string_equal( mergearr3[1], "" ) ); EXPECT_TRUE( string_equal( mergearr3[2], "" ) ); EXPECT_TRUE( string_equal( mergearr3[3], "" ) ); EXPECT_TRUE( string_equal( mergearr3[4], "testing" ) ); EXPECT_TRUE( string_equal( mergearr3[5], "" ) ); EXPECT_TRUE( string_equal( mergearr3[6], "" ) ); EXPECT_TRUE( string_equal( mergearr3[7], "merge" ) ); EXPECT_TRUE( string_equal( mergearr3[8], "string" ) ); EXPECT_TRUE( string_equal( mergearr3[9], "" ) ); EXPECT_TRUE( string_equal( mergearr3[10], "" ) ); EXPECT_TRUE( string_equal( mergearr3[11], "" ) ); EXPECT_TRUE( string_equal( substr = string_substr( substrtest, 0, 4 ), "test" ) ); string_deallocate( substr ); EXPECT_TRUE( string_equal( substr = string_substr( substrtest, 0, 14 ), "testing substr" ) ); string_deallocate( substr ); EXPECT_TRUE( string_equal( substr = string_substr( substrtest, 0, 20 ), "testing substr" ) ); string_deallocate( substr ); EXPECT_TRUE( string_equal( substr = string_substr( substrtest, 3, 20 ), "ting substr" ) ); string_deallocate( substr ); EXPECT_TRUE( string_equal( substr = string_substr( substrtest, 3, 11 ), "ting substr" ) ); string_deallocate( substr ); EXPECT_TRUE( string_equal( substr = string_substr( substrtest, 3, 1 ), "t" ) ); string_deallocate( substr ); EXPECT_TRUE( string_equal( substr = string_substr( substrtest, 3, 0 ), "" ) ); string_deallocate( substr ); EXPECT_TRUE( string_equal( substr = string_substr( substrtest, 20, 0 ), "" ) ); string_deallocate( substr ); EXPECT_TRUE( string_equal( substr = string_substr( substrtest, 20, 20 ), "" ) ); string_deallocate( substr ); EXPECT_TRUE( string_equal( splitleft, "testing" ) ); EXPECT_TRUE( string_equal( splitright, "split" ) ); EXPECT_TRUE( string_equal( splitleft2, "" ) ); EXPECT_TRUE( string_equal( splitright2, "testing split" ) ); { char* replacestr = string_clone( "testing replace" ); char* replacestr2 = string_clone( "testing replace" ); char* replacestr3 = string_clone( "testing replacelace" ); char* replacestr4 = string_clone( "" ); char* replacestr5 = string_clone( "repppppppppp" ); replacestr = string_replace( replacestr, "rep", "testrep", false ); replacestr2 = string_replace( replacestr2, "rep", "testrep", true ); replacestr3 = string_replace( replacestr3, "replace", "testrep", true ); replacestr4 = string_replace( replacestr4, "foo", "bar", true ); replacestr5 = string_replace( replacestr5, "rep", "re", true ); EXPECT_TRUE( string_equal( replacestr, "testing testreplace" ) ); EXPECT_TRUE( string_equal( replacestr2, "testing testreplace" ) ); EXPECT_TRUE( string_equal( replacestr3, "testing testtestrep" ) ); EXPECT_TRUE( string_equal( replacestr4, "" ) ); EXPECT_TRUE( string_equal( replacestr5, "re" ) ); string_deallocate( replacestr ); string_deallocate( replacestr2 ); string_deallocate( replacestr3 ); string_deallocate( replacestr4 ); string_deallocate( replacestr5 ); } { char* stripstr = string_clone( " testing strip : " ); char* stripstr2 = string_clone( " testing strip : " ); char* stripstr3 = string_clone( " testing strip : " ); stripstr = string_strip( stripstr, " tp: " ); stripstr2 = string_strip( stripstr2, "" ); stripstr3 = string_strip( stripstr3, " tesingrp:" ); EXPECT_TRUE( string_equal( stripstr, "esting stri" ) ); EXPECT_TRUE( string_equal( stripstr2, " testing strip : " ) ); EXPECT_TRUE( string_equal( stripstr3, "" ) ); string_deallocate( stripstr ); string_deallocate( stripstr2 ); string_deallocate( stripstr3 ); } string_array_deallocate( explodearr ); string_deallocate( explodestr ); string_deallocate( mergestr ); string_deallocate( mergestr2 ); string_deallocate( merged ); string_array_deallocate( mergearr ); string_array_deallocate( mergearr2 ); string_array_deallocate( mergearr3 ); string_deallocate( splitstr ); string_deallocate( splitright ); string_deallocate( splitleft ); string_deallocate( splitright2 ); string_deallocate( splitleft2 ); string_deallocate( substrtest ); } { #define SHORTSTRING "short" #define LONGSTRING "long string with dynamic buffer storage but with no real useful data" char* clonestr = string_clone( "" ); char* clonestr2 = string_clone( SHORTSTRING ); char* clonestr3 = string_clone( LONGSTRING ); char* teststr = string_clone( clonestr ); char* teststr2 = string_clone( clonestr2 ); char* teststr3 = string_clone( clonestr3 ); char* concatstr = string_concat( clonestr, teststr ); char* concatstr2 = string_concat( clonestr, teststr2 ); char* concatstr3 = string_concat( teststr2, clonestr ); char* concatstr4 = string_concat( clonestr2, teststr2 ); char* concatstr5 = string_concat( clonestr, teststr3 ); char* concatstr6 = string_concat( teststr3, clonestr ); char* concatstr7 = string_concat( clonestr2, teststr3 ); char* concatstr8 = string_concat( teststr3, clonestr2 ); char* concatstr9 = string_concat( clonestr3, teststr3 ); char* concatstr10 = string_concat( teststr3, clonestr3 ); EXPECT_NE( teststr, clonestr ); EXPECT_TRUE( string_equal( teststr, clonestr ) ); EXPECT_NE( teststr2, clonestr2 ); EXPECT_TRUE( string_equal( teststr2, clonestr2 ) ); EXPECT_NE( teststr3, clonestr3 ); EXPECT_TRUE( string_equal( teststr3, clonestr3 ) ); EXPECT_TRUE( string_equal( concatstr, "" ) ); EXPECT_TRUE( string_equal( concatstr2, SHORTSTRING ) ); EXPECT_TRUE( string_equal( concatstr3, SHORTSTRING ) ); EXPECT_TRUE( string_equal( concatstr4, SHORTSTRING SHORTSTRING ) ); EXPECT_TRUE( string_equal( concatstr5, LONGSTRING ) ); EXPECT_TRUE( string_equal( concatstr6, LONGSTRING ) ); EXPECT_TRUE( string_equal( concatstr7, SHORTSTRING LONGSTRING ) ); EXPECT_TRUE( string_equal( concatstr8, LONGSTRING SHORTSTRING ) ); EXPECT_TRUE( string_equal( concatstr9, LONGSTRING LONGSTRING ) ); EXPECT_TRUE( string_equal( concatstr10, LONGSTRING LONGSTRING ) ); string_deallocate( teststr ); string_deallocate( clonestr ); string_deallocate( teststr2 ); string_deallocate( clonestr2 ); string_deallocate( teststr3 ); string_deallocate( clonestr3 ); string_deallocate( concatstr ); string_deallocate( concatstr2 ); string_deallocate( concatstr3 ); string_deallocate( concatstr4 ); string_deallocate( concatstr5 ); string_deallocate( concatstr6 ); string_deallocate( concatstr7 ); string_deallocate( concatstr8 ); string_deallocate( concatstr9 ); string_deallocate( concatstr10 ); #undef SHORTSTRING #undef LONGSTRING } return 0; }
DECLARE_TEST( string, initialize ) { { char* nullstr1 = string_allocate( 0 ); char* nullstr2 = string_allocate( 1 ); char* nullstr3 = string_allocate( 10 ); EXPECT_EQ( 0U, string_length( nullstr1 ) ); EXPECT_EQ( 0U, string_length( nullstr2 ) ); EXPECT_EQ( 0U, string_length( nullstr3 ) ); EXPECT_EQ( 0, strcmp( nullstr1, "" ) ); EXPECT_EQ( 0, strcmp( nullstr2, "" ) ); EXPECT_EQ( 0, strcmp( nullstr3, "" ) ); string_deallocate( nullstr1 ); string_deallocate( nullstr2 ); string_deallocate( nullstr3 ); } { char teststr1[] = "test"; char teststr2[] = "testing long string with more than 16 characters"; char teststr3[] = "\x01\x02\x03\x04\x05\x06\x07\x08\x90\x01\x02\x03\x04\x05\x06\x07\x08\x90\x01\x02\x03\x04\x05\x06\x07\x08\x90\x01\x02\x03\x04\x05\x06\x07\x08\x90\x01\x02\x03\x04\x05\x06\x07\x08\x90\x01\x02\x03\x04\x05\x06\x07\x08\x09"; char* str1 = string_clone( teststr1 ); char* str2 = string_substr( teststr1, 0, 3 ); char* str3 = string_substr( teststr1, 0, 4 ); char* str4 = string_substr( teststr1, 0, 32 ); char* str5 = string_substr( teststr1, 0, STRING_NPOS ); char* str6 = string_clone( teststr2 ); char* str7 = string_substr( teststr2, 0, 3 ); char* str8 = string_substr( teststr2, 0, 20 ); char* str9 = string_substr( teststr2, 0, STRING_NPOS ); char* str10 = string_clone( teststr3 ); char* str11 = string_substr( teststr3, 0, 3 ); char* str12 = string_substr( teststr3, 0, 20 ); char* str13 = string_substr( teststr3, 0, STRING_NPOS ); EXPECT_EQ( 0, strcmp( str1, teststr1 ) ); EXPECT_EQ( 0, strcmp( str2, "tes" ) ); EXPECT_EQ( 0, strcmp( str3, teststr1 ) ); EXPECT_EQ( 0, strcmp( str4, teststr1 ) ); EXPECT_EQ( 0, strcmp( str5, teststr1 ) ); EXPECT_EQ( 0, strcmp( str6, teststr2 ) ); EXPECT_EQ( 0, strcmp( str7, "tes" ) ); EXPECT_EQ( 0, strcmp( str8, "testing long string " ) ); EXPECT_EQ( 0, strcmp( str9, teststr2 ) ); EXPECT_EQ( 0, strcmp( str10, teststr3 ) ); EXPECT_EQ( 0, strcmp( str11, "\x01\x02\x03" ) ); EXPECT_EQ( 0, strcmp( str12, "\x01\x02\x03\x04\x05\x06\x07\x08\x90\x01\x02\x03\x04\x05\x06\x07\x08\x90\x01\x02" ) ); EXPECT_EQ( 0, strcmp( str13, teststr3 ) ); string_deallocate( str1 ); string_deallocate( str2 ); string_deallocate( str3 ); string_deallocate( str4 ); string_deallocate( str5 ); string_deallocate( str6 ); string_deallocate( str7 ); string_deallocate( str8 ); string_deallocate( str9 ); string_deallocate( str10 ); string_deallocate( str11 ); string_deallocate( str12 ); string_deallocate( str13 ); } { wchar_t teststr1[] = L"test"; wchar_t teststr2[] = L"testing long string with more than 16 characters"; wchar_t teststr3[] = L"0\x0001\x0002\x0003\x0004\x0005\x0006\x0007\x0008\x0009\x0030\x0001\x0002\x0003\x0004\x0005\x0006\x0007\x0008\x0009\x0030\x0001\x0002\x0003\x0004\x0005\x0006\x0007\x0008\x0009\x0030\x0001\x0002\x0003\x0004\x0005\x0006\x0007\x0008\x0009\x0030\x0001\x0002\x0003\x0004\x0005\x0006\x0007\x0008\x0009\x0030\x0001\x0002\x0003\x0004\x0005\x0006\x0007\x0008\x0009"; wchar_t teststr4[] = L"Wide-char string with some strange characters: åäöÅÄÖ_________ (test utf-8 conversions with long strings)"; //char utfteststr4[] = "Wide-char string with some strange characters: \xC3\xA5\xC3\xA4\xC3\xB6\xC3\x85\xC3\x84\xC3\x96\xEF\xB7\xB2\xDA\x81\xED\x80\x83\xEC\x99\xA7\xEB\x96\xAF\xE7\xBF\xB3\xE5\xA1\x8C\xE1\xA7\xBC\xE1\xA7\xAD (test utf-8 conversions with long strings)"; char *str1, *str2, *str3, *str4, *str5, *str6, *str7, *str8, *str9, *str10, *str11, *str12, *str13, *str14, *str15, *str16, *str17; wchar_t *wstr1, *wstr2, *wstr3, *wstr4, *wstr5, *wstr6, *wstr7, *wstr8, *wstr9, *wstr10, *wstr11, *wstr12, *wstr13, *wstr14, *wstr15, *wstr16, *wstr17; teststr4[53] = (wchar_t)0x602f;//L'ﷲ'; teststr4[54] = (wchar_t)0xf045;//L'ځ'; teststr4[55] = (wchar_t)0x1d30;//L'퀃'; teststr4[56] = (wchar_t)0x0378;//L'왧'; teststr4[57] = (wchar_t)0x0ffe;//L'떯'; teststr4[58] = (wchar_t)0xffe0;//L'翳'; teststr4[59] = (wchar_t)0x1234;//L'塌'; teststr4[60] = (wchar_t)0x4321;//L'᧼'; teststr4[61] = (wchar_t)0x0f0f;//L'᧭'; str1 = string_allocate_from_wstring( teststr1, 0 ); str2 = string_allocate_from_wstring( teststr1, 3 ); str3 = string_allocate_from_wstring( teststr1, 4 ); str4 = string_allocate_from_wstring( teststr1, 32 ); str5 = string_allocate_from_wstring( teststr1, STRING_NPOS ); str6 = string_allocate_from_wstring( teststr2, 0 ); str7 = string_allocate_from_wstring( teststr2, 3 ); str8 = string_allocate_from_wstring( teststr2, 20 ); str9 = string_allocate_from_wstring( teststr2, STRING_NPOS ); str10 = string_allocate_from_wstring( teststr3, 0 ); str11 = string_allocate_from_wstring( teststr3, 3 ); str12 = string_allocate_from_wstring( teststr3, 20 ); str13 = string_allocate_from_wstring( teststr3, STRING_NPOS ); str14 = string_allocate_from_wstring( teststr4, 0 ); str15 = string_allocate_from_wstring( teststr4, 3 ); str16 = string_allocate_from_wstring( teststr4, 63 ); str17 = string_allocate_from_wstring( teststr4, STRING_NPOS ); wstr1 = wstring_allocate_from_string( str1, 0 ); wstr2 = wstring_allocate_from_string( str2, 0 ); wstr3 = wstring_allocate_from_string( str3, 0 ); wstr4 = wstring_allocate_from_string( str4, 0 ); wstr5 = wstring_allocate_from_string( str5, 0 ); wstr6 = wstring_allocate_from_string( str6, 0 ); wstr7 = wstring_allocate_from_string( str7, 0 ); wstr8 = wstring_allocate_from_string( str8, 0 ); wstr9 = wstring_allocate_from_string( str9, 0 ); wstr10 = wstring_allocate_from_string( str10, 0 ); wstr11 = wstring_allocate_from_string( str11, 0 ); wstr12 = wstring_allocate_from_string( str12, 0 ); wstr13 = wstring_allocate_from_string( str13, 0 ); wstr14 = wstring_allocate_from_string( str14, 0 ); wstr15 = wstring_allocate_from_string( str15, 0 ); wstr16 = wstring_allocate_from_string( str16, 0 ); wstr17 = wstring_allocate_from_string( str17, 0 ); EXPECT_EQ( 0, wcscmp( wstr1, teststr1 ) ); EXPECT_EQ( 0, wcscmp( wstr2, L"tes" ) ); EXPECT_EQ( 0, wcscmp( wstr3, teststr1 ) ); EXPECT_EQ( 0, wcscmp( wstr4, teststr1 ) ); EXPECT_EQ( 0, wcscmp( wstr5, teststr1 ) ); EXPECT_EQ( 0, wcscmp( wstr6, teststr2 ) ); EXPECT_EQ( 0, wcscmp( wstr7, L"tes" ) ); EXPECT_EQ( 0, wcscmp( wstr8, L"testing long string " ) ); EXPECT_EQ( 0, wcscmp( wstr9, teststr2 ) ); EXPECT_EQ( 0, wcscmp( wstr10, teststr3 ) ); EXPECT_EQ( 0, wcscmp( wstr11, L"0\x0001\x0002" ) ); EXPECT_EQ( 0, wcscmp( wstr12, L"0\x0001\x0002\x0003\x0004\x0005\x0006\x0007\x0008\x0009\x0030\x0001\x0002\x0003\x0004\x0005\x0006\x0007\x0008\x0009" ) ); EXPECT_EQ( 0, wcscmp( wstr13, teststr3 ) ); EXPECT_EQ( 0, wcscmp( wstr14, teststr4 ) ); EXPECT_EQ( 0, wcscmp( wstr15, L"Wid" ) ); EXPECT_EQ( 0, wcscmp( wstr17, teststr4 ) ); teststr4[63] = 0; EXPECT_EQ( 0, wcscmp( wstr16, teststr4 ) ); { wchar_t wteststr[] = { 0x0100, 0x078f, 0x1234, 0xFF03, 0xD854, 0xDC53, 0x0032, 0 }; char* utf8_teststr = string_allocate_from_wstring( wteststr, 0 ); wchar_t* wchar_teststr = wstring_allocate_from_string( utf8_teststr, 0 ); EXPECT_EQ( 0, wcscmp( wteststr, wchar_teststr ) ); wstring_deallocate( wchar_teststr ); string_deallocate( utf8_teststr ); } { uint16_t wteststr[] = { 0xFEFF, 0x0100, 0x078f, 0x1234, 0xFF03, 0xDB02, 0xDC54, 0x0032, 0xFFFE, 0x1234, 0xFF03, 0 }; #if FOUNDATION_WCHAR_SIZE == 32 wchar_t wtestcmpstr[] = { 0x0100, 0x078f, 0x1234, 0xFF03, 0x000D0854, 0x0032, 0x3412, 0x03FF, 0 }; #else wchar_t wtestcmpstr[] = { 0x0100, 0x078f, 0x1234, 0xFF03, 0xDB02, 0xDC54, 0x0032, 0x3412, 0x03FF, 0 }; #endif char* utf8_teststr = string_allocate_from_utf16( wteststr, 0 ); wchar_t* wchar_teststr = wstring_allocate_from_string( utf8_teststr, 0 ); EXPECT_EQ( 0, wcscmp( wtestcmpstr, wchar_teststr ) ); wstring_deallocate( wchar_teststr ); string_deallocate( utf8_teststr ); } { uint32_t wteststr[] = { 0x0000FEFF, 0x00000100, 0x0000078f, 0x00001234, 0x0000FF03, 0x000D0854, 0x000D0C53, 0x00000032, 0xFFFE0000, 0x12340000, 0xFF030000, 0 }; #if FOUNDATION_WCHAR_SIZE == 32 wchar_t wtestcmpstr[] = { 0x0100, 0x078f, 0x1234, 0xFF03, 0x000D0854, 0x000D0C53, 0x0032, 0x3412, 0x03FF, 0 }; #else wchar_t wtestcmpstr[] = { 0x0100, 0x078f, 0x1234, 0xFF03, 0xDB02, 0xDC54, 0xDB03, 0xDC53, 0x0032, 0x3412, 0x03FF, 0 }; #endif char* utf8_teststr = string_allocate_from_utf32( wteststr, 0 ); wchar_t* wchar_teststr = wstring_allocate_from_string( utf8_teststr, 0 ); EXPECT_EQ( 0, wcscmp( wtestcmpstr, wchar_teststr ) ); wstring_deallocate( wchar_teststr ); string_deallocate( utf8_teststr ); } string_deallocate( str1 ); string_deallocate( str2 ); string_deallocate( str3 ); string_deallocate( str4 ); string_deallocate( str5 ); string_deallocate( str6 ); string_deallocate( str7 ); string_deallocate( str8 ); string_deallocate( str9 ); string_deallocate( str10 ); string_deallocate( str11 ); string_deallocate( str12 ); string_deallocate( str13 ); string_deallocate( str14 ); string_deallocate( str15 ); string_deallocate( str16 ); string_deallocate( str17 ); wstring_deallocate( wstr1 ); wstring_deallocate( wstr2 ); wstring_deallocate( wstr3 ); wstring_deallocate( wstr4 ); wstring_deallocate( wstr5 ); wstring_deallocate( wstr6 ); wstring_deallocate( wstr7 ); wstring_deallocate( wstr8 ); wstring_deallocate( wstr9 ); wstring_deallocate( wstr10 ); wstring_deallocate( wstr11 ); wstring_deallocate( wstr12 ); wstring_deallocate( wstr13 ); wstring_deallocate( wstr14 ); wstring_deallocate( wstr15 ); wstring_deallocate( wstr16 ); wstring_deallocate( wstr17 ); } return 0; }
DECLARE_TEST( string, queries ) { { char teststr[] = ""; char teststr2[] = "test"; char teststr3[] = "testing long string with more than 16 characters"; char teststr4[] = "01234567890123456789012345678901234567890123456789012345678901234567890123456789"; char* str1 = string_substr( teststr, 0, 0 ); char* str2 = string_substr( teststr2, 0, 4 ); char* str3 = string_substr( teststr2, 0, 20 ); char* str4 = string_substr( teststr3, 0, 0 ); char* str5 = string_substr( teststr3, 0, 10 ); char* str6 = string_substr( teststr3, 0, STRING_NPOS ); char* str7 = string_substr( teststr4, 0, 0 ); char* str8 = string_substr( teststr4, 0, 20 ); char* str9 = string_substr( teststr4, 0, STRING_NPOS ); EXPECT_EQ( 0, str1[0] ); EXPECT_EQ( 0, str2[ string_length( str2 ) ] ); EXPECT_EQ( 0, str3[ string_length( str3 ) ] ); EXPECT_EQ( 0, str4[ string_length( str4 ) ] ); EXPECT_EQ( 0, str5[ string_length( str5 ) ] ); EXPECT_EQ( 0, str6[ string_length( str6 ) ] ); EXPECT_EQ( 0, str7[ string_length( str7 ) ] ); EXPECT_EQ( 0, str8[ string_length( str8 ) ] ); EXPECT_EQ( 0, str9[ string_length( str9 ) ] ); EXPECT_EQ( strlen( teststr ), string_length( str1 ) ); EXPECT_EQ( strlen( teststr2 ), string_length( str2 ) ); EXPECT_EQ( strlen( teststr2 ), string_length( str3 ) ); EXPECT_EQ( 0U, string_length( str4 ) ); EXPECT_EQ( 10U, string_length( str5 ) ); EXPECT_EQ( strlen( teststr3 ), string_length( str6 ) ); EXPECT_EQ( 0U, string_length( str7 ) ); EXPECT_EQ( 20U, string_length( str8 ) ); EXPECT_EQ( strlen( teststr4 ), string_length( str9 ) ); string_deallocate( str1 ); string_deallocate( str2 ); string_deallocate( str3 ); string_deallocate( str4 ); string_deallocate( str5 ); string_deallocate( str6 ); string_deallocate( str7 ); string_deallocate( str8 ); string_deallocate( str9 ); } { //Only ASCII characters, so wstring->string conversion should not introduce any extra UTF-8 sequences wchar_t teststr[] = L""; wchar_t teststr2[] = L"test"; wchar_t teststr3[] = L"testing long string with more than 16 characters"; wchar_t teststr4[] = L"01234567890123456789012345678901234567890123456789012345678901234567890123456789"; char* str1 = string_allocate_from_wstring( teststr, 0 ); char* str2 = string_allocate_from_wstring( teststr2, 0 ); char* str3 = string_allocate_from_wstring( teststr2, 20 ); char* str4 = string_allocate_from_wstring( teststr3, 0 ); char* str5 = string_allocate_from_wstring( teststr3, 10 ); char* str6 = string_allocate_from_wstring( teststr3, STRING_NPOS ); char* str7 = string_allocate_from_wstring( teststr4, 0 ); char* str8 = string_allocate_from_wstring( teststr4, 20 ); char* str9 = string_allocate_from_wstring( teststr4, STRING_NPOS ); EXPECT_EQ( 0, str1[0] ); EXPECT_EQ( 0, str2[ string_length( str2 ) ] ); EXPECT_EQ( 0, str3[ string_length( str3 ) ] ); EXPECT_EQ( 0, str4[ string_length( str4 ) ] ); EXPECT_EQ( 0, str5[ string_length( str5 ) ] ); EXPECT_EQ( 0, str6[ string_length( str6 ) ] ); EXPECT_EQ( 0, str7[ string_length( str7 ) ] ); EXPECT_EQ( 0, str8[ string_length( str8 ) ] ); EXPECT_EQ( 0, str9[ string_length( str9 ) ] ); EXPECT_EQ( wcslen( teststr ), string_length( str1 ) ); EXPECT_EQ( wcslen( teststr2 ), string_length( str2 ) ); EXPECT_EQ( wcslen( teststr2 ), string_length( str3 ) ); EXPECT_EQ( wcslen( teststr3 ), string_length( str4 ) ); EXPECT_EQ( 10U, string_length( str5 ) ); EXPECT_EQ( wcslen( teststr3 ), string_length( str6 ) ); EXPECT_EQ( wcslen( teststr4 ), string_length( str7 ) ); EXPECT_EQ( 20U, string_length( str8 ) ); EXPECT_EQ( wcslen( teststr4 ), string_length( str9 ) ); string_deallocate( str1 ); string_deallocate( str2 ); string_deallocate( str3 ); string_deallocate( str4 ); string_deallocate( str5 ); string_deallocate( str6 ); string_deallocate( str7 ); string_deallocate( str8 ); string_deallocate( str9 ); } { char* emptystr = string_allocate( 0 ); char* shortstr = string_clone( "short string" ); char* longstr = string_clone( "testing utility string methods like finds, split, merge, explode and similar." ); { unsigned int find = string_find( longstr, ' ', 0 ); unsigned int find2 = string_find( longstr, 12, 0 ); unsigned int find3 = string_find( emptystr, ' ', 0 ); unsigned int find4 = string_find( shortstr, ' ', 0 ); unsigned int find5 = string_find( shortstr, 'z', 0 ); unsigned int findofs = string_find( longstr, ' ', find ); unsigned int findofs2 = string_find( longstr, ' ', find + 1 ); unsigned int findofs3 = string_find( longstr, 'z', 10 ); unsigned int findofs4 = string_find( emptystr, 'z', STRING_NPOS ); unsigned int findofs5 = string_find( shortstr, 's', 10 ); unsigned int findofs6 = string_find( shortstr, 's', findofs5 ); unsigned int findofs7 = string_find( shortstr, 't', 0 ); unsigned int findofs8 = string_find( shortstr, ' ', 5 ); unsigned int findofs9 = string_find( longstr, ' ', STRING_NPOS ); EXPECT_EQ( find, 7U ); EXPECT_EQ( find2, STRING_NPOS ); EXPECT_EQ( find3, STRING_NPOS ); EXPECT_EQ( find4, 5U ); EXPECT_EQ( find5, STRING_NPOS ); EXPECT_EQ( findofs, find ); EXPECT_EQ( findofs2, 15U ); EXPECT_EQ( findofs3, STRING_NPOS ); EXPECT_EQ( findofs4, STRING_NPOS ); EXPECT_EQ( findofs5, STRING_NPOS ); EXPECT_EQ( findofs6, STRING_NPOS ); EXPECT_EQ( findofs7, 4U ); EXPECT_EQ( findofs8, 5U ); EXPECT_EQ( findofs9, STRING_NPOS ); } { unsigned int rfind = string_rfind( longstr, ' ', STRING_NPOS ); unsigned int rfind2 = string_rfind( longstr, ';', STRING_NPOS ); unsigned int rfind3 = string_rfind( emptystr, ';', STRING_NPOS ); unsigned int rfind4 = string_rfind( shortstr, 's', STRING_NPOS ); unsigned int rfind5 = string_rfind( shortstr, 'z', STRING_NPOS ); unsigned int rfindofs = string_rfind( longstr, ' ', rfind ); unsigned int rfindofs2 = string_rfind( longstr, ' ', rfind - 1 ); unsigned int rfindofs3 = string_rfind( longstr, ' ', string_length( longstr ) - 1 ); unsigned int rfindofs4 = string_rfind( emptystr, ' ', 0 ); unsigned int rfindofs5 = string_rfind( longstr, ' ', 0 ); unsigned int rfindofs6 = string_rfind( shortstr, 's', 5 ); unsigned int rfindofs7 = string_rfind( shortstr, 's', 0 ); EXPECT_EQ( rfind, 68U ); EXPECT_EQ( rfind2, STRING_NPOS ); EXPECT_EQ( rfind3, STRING_NPOS ); EXPECT_EQ( rfind4, 6U ); EXPECT_EQ( rfind5, STRING_NPOS ); EXPECT_EQ( rfindofs, rfind ); EXPECT_EQ( rfindofs2, 64U ); EXPECT_EQ( rfindofs3, rfind ); EXPECT_EQ( rfindofs4, STRING_NPOS ); EXPECT_EQ( rfindofs5, STRING_NPOS ); EXPECT_EQ( rfindofs6, 0U ); EXPECT_EQ( rfindofs7, 0U ); } { unsigned int findstr = string_find_string( longstr, "st", 0 ); unsigned int findstr2 = string_find_string( longstr, "xwqz", 0 ); unsigned int findstr3 = string_find_string( emptystr, "xwqz", 0 ); unsigned int findstr4 = string_find_string( longstr, "", 0 ); unsigned int findstr5 = string_find_string( longstr, "dslike", 0 ); unsigned int findstr6 = string_find_string( shortstr, "rt", 0 ); unsigned int findstr7 = string_find_string( shortstr, "long key that does not exist", 0 ); unsigned int findstr8 = string_find_string( shortstr, "so", 0 ); unsigned int findstrofs = string_find_string( longstr, "st", findstr ); unsigned int findstrofs2 = string_find_string( longstr, "st", findstr + 1 ); unsigned int findstrofs3 = string_find_string( longstr, "xwqz", string_length( longstr ) ); unsigned int findstrofs4 = string_find_string( emptystr, "xwqz", string_length( emptystr ) ); unsigned int findstrofs5 = string_find_string( shortstr, "", 5 ); unsigned int findstrofs6 = string_find_string( shortstr, "string", 0 ); unsigned int findstrofs7 = string_find_string( shortstr, "string", 7 ); unsigned int findstrofs8 = string_find_string( longstr, "utility", 14 ); unsigned int findstrofs9 = string_find_string( longstr, "", string_length( longstr ) ); unsigned int findstrofs10 = string_find_string( longstr, "", STRING_NPOS ); unsigned int findstrofs11 = string_find_string( longstr, "string", STRING_NPOS ); EXPECT_EQ( findstr, 2U ); EXPECT_EQ( findstr2, STRING_NPOS ); EXPECT_EQ( findstr3, STRING_NPOS ); EXPECT_EQ( findstr4, 0U ); EXPECT_EQ( findstr5, STRING_NPOS ); EXPECT_EQ( findstr6, 3U ); EXPECT_EQ( findstr7, STRING_NPOS ); EXPECT_EQ( findstr8, STRING_NPOS ); EXPECT_EQ( findstrofs, findstr ); EXPECT_EQ( findstrofs2, 16U ); EXPECT_EQ( findstrofs3, STRING_NPOS ); EXPECT_EQ( findstrofs4, STRING_NPOS ); EXPECT_EQ( findstrofs5, 5U ); EXPECT_EQ( findstrofs6, 6U ); EXPECT_EQ( findstrofs7, STRING_NPOS ); EXPECT_EQ( findstrofs8, STRING_NPOS ); EXPECT_EQ( findstrofs9, strlen( longstr ) ); EXPECT_EQ( findstrofs10, STRING_NPOS ); EXPECT_EQ( findstrofs11, STRING_NPOS ); } { unsigned int rfindstr = string_rfind_string( longstr, ", ", STRING_NPOS ); unsigned int rfindstr2 = string_rfind_string( longstr, ":;", STRING_NPOS ); unsigned int rfindstr3 = string_rfind_string( emptystr, ":;", STRING_NPOS ); unsigned int rfindstr4 = string_rfind_string( longstr, "", STRING_NPOS ); unsigned int rfindstr5 = string_rfind_string( shortstr, "string", STRING_NPOS ); unsigned int rfindstr6 = string_rfind_string( shortstr, " tring", STRING_NPOS ); unsigned int rfindstrofs = string_rfind_string( longstr, ", ", rfindstr ); unsigned int rfindstrofs2 = string_rfind_string( longstr, ", ", rfindstr - 1 ); unsigned int rfindstrofs3 = string_rfind_string( longstr, ":;", 0 ); unsigned int rfindstrofs4 = string_rfind_string( emptystr, ":;", 0 ); unsigned int rfindstrofs5 = string_rfind_string( longstr, "", 5 ); unsigned int rfindstrofs6 = string_rfind_string( shortstr, "ort str", 6 ); unsigned int rfindstrofs7 = string_rfind_string( shortstr, "ort str", 1 ); EXPECT_EQ( rfindstr, 55U ); EXPECT_EQ( rfindstr2, STRING_NPOS ); EXPECT_EQ( rfindstr3, STRING_NPOS ); EXPECT_EQ( rfindstr4, strlen( longstr ) ); EXPECT_EQ( rfindstr5, 6U ); EXPECT_EQ( rfindstr6, STRING_NPOS ); EXPECT_EQ( rfindstrofs, rfindstr ); EXPECT_EQ( rfindstrofs2, 48U ); EXPECT_EQ( rfindstrofs3, STRING_NPOS ); EXPECT_EQ( rfindstrofs4, STRING_NPOS ); EXPECT_EQ( rfindstrofs5, 5U ); EXPECT_EQ( rfindstrofs6, 2U ); EXPECT_EQ( rfindstrofs7, STRING_NPOS ); } { unsigned int findof = string_find_first_of( longstr, "ui", 0 ); unsigned int findof2 = string_find_first_of( longstr, ";:", 0 ); unsigned int findof3 = string_find_first_of( emptystr, "", 0 ); unsigned int findof4 = string_find_first_of( emptystr, " ", 0 ); unsigned int findof5 = string_find_first_of( shortstr, "", 0 ); unsigned int findofofs = string_find_first_of( longstr, "ui", findof ); unsigned int findofofs2 = string_find_first_of( longstr, "ui", findof - 1 ); unsigned int findofofs3 = string_find_first_of( longstr, "ui", findof + 1 ); unsigned int findofofs4 = string_find_first_of( longstr, "ui", string_length( longstr ) ); unsigned int findofofs5 = string_find_first_of( emptystr, "", string_length( emptystr ) ); unsigned int findofofs6 = string_find_first_of( shortstr, "string", 6 ); unsigned int findofofs7 = string_find_first_of( shortstr, "", 6 ); unsigned int findofofs8 = string_find_first_of( longstr, "", 10 ); unsigned int findofofs9 = string_find_first_of( longstr, "", string_length( longstr ) ); EXPECT_EQ( findof, 4U ); EXPECT_EQ( findof2, STRING_NPOS ); EXPECT_EQ( findof3, STRING_NPOS ); EXPECT_EQ( findof4, STRING_NPOS ); EXPECT_EQ( findof5, STRING_NPOS ); EXPECT_EQ( findofofs, 4U ); EXPECT_EQ( findofofs2, 4U ); EXPECT_EQ( findofofs3, 8U ); EXPECT_EQ( findofofs4, STRING_NPOS ); EXPECT_EQ( findofofs5, STRING_NPOS ); EXPECT_EQ( findofofs6, 6U ); EXPECT_EQ( findofofs7, STRING_NPOS ); EXPECT_EQ( findofofs8, STRING_NPOS ); EXPECT_EQ( findofofs9, STRING_NPOS ); } { unsigned int findnotof = string_find_first_not_of( longstr, "testing ", 0 ); unsigned int findnotof2 = string_find_first_not_of( longstr, longstr, 0 ); unsigned int findnotof3 = string_find_first_not_of( shortstr, "", 0 ); unsigned int findnotofofs = string_find_first_not_of( longstr, "testing ", findnotof ); unsigned int findnotofofs2 = string_find_first_not_of( longstr, "testing ", findnotof + 1 ); unsigned int findnotofofs3 = string_find_first_not_of( longstr, "testing ", string_length( longstr ) ); unsigned int findnotofofs4 = string_find_first_not_of( shortstr, "", string_length( shortstr ) ); EXPECT_EQ( findnotof, 8U ); EXPECT_EQ( findnotof2, STRING_NPOS ); EXPECT_EQ( findnotof3, 0U ); EXPECT_EQ( findnotofofs, 8U ); EXPECT_EQ( findnotofofs2, 11U ); EXPECT_EQ( findnotofofs3, STRING_NPOS ); EXPECT_EQ( findnotofofs4, STRING_NPOS ); } { unsigned int findlastof = string_find_last_of( longstr, "xp", STRING_NPOS ); unsigned int findlastof2 = string_find_last_of( longstr, ";:", STRING_NPOS ); unsigned int findlastof3 = string_find_last_of( emptystr, "", STRING_NPOS ); unsigned int findlastof4 = string_find_last_of( shortstr, "", STRING_NPOS ); unsigned int findlastofofs = string_find_last_of( longstr, "xp", findlastof ); unsigned int findlastofofs2 = string_find_last_of( longstr, "xp", findlastof - 2 ); unsigned int findlastofofs3 = string_find_last_of( longstr, "xp", 0 ); unsigned int findlastofofs4 = string_find_last_of( emptystr, "", 0 ); unsigned int findlastofofs5 = string_find_last_of( shortstr, "", 5 ); unsigned int findlastofofs6 = string_find_last_of( shortstr, "", string_length( shortstr ) ); unsigned int findlastofofs7 = string_find_last_of( shortstr, "short", 5 ); EXPECT_EQ( findlastof, 59U ); EXPECT_EQ( findlastof2, STRING_NPOS ); EXPECT_EQ( findlastof3, STRING_NPOS ); EXPECT_EQ( findlastof4, STRING_NPOS ); EXPECT_EQ( findlastofofs, 59U ); EXPECT_EQ( findlastofofs2, 44U ); EXPECT_EQ( findlastofofs3, STRING_NPOS ); EXPECT_EQ( findlastofofs4, STRING_NPOS ); EXPECT_EQ( findlastofofs5, STRING_NPOS ); EXPECT_EQ( findlastofofs6, STRING_NPOS ); EXPECT_EQ( findlastofofs7, 4U ); } { unsigned int findlastnotof = string_find_last_not_of( longstr, " similar.", STRING_NPOS ); unsigned int findlastnotof2 = string_find_last_not_of( longstr, longstr, STRING_NPOS ); unsigned int findlastnotof3 = string_find_last_not_of( emptystr, "", STRING_NPOS ); unsigned int findlastnotof4 = string_find_last_not_of( shortstr, "", STRING_NPOS ); unsigned int findlastnotof5 = string_find_last_not_of( longstr, " similar", STRING_NPOS ); unsigned int findlastnotofofs = string_find_last_not_of( longstr, " similar.", findlastnotof ); unsigned int findlastnotofofs2 = string_find_last_not_of( longstr, " and similar.", findlastnotof - 1 ); unsigned int findlastnotofofs3 = string_find_last_not_of( longstr, longstr, 0 ); unsigned int findlastnotofofs4 = string_find_last_not_of( emptystr, "", 0 ); unsigned int findlastnotofofs5 = string_find_last_not_of( shortstr, "string", 5 ); unsigned int findlastnotofofs6 = string_find_last_not_of( shortstr, "string ", 5 ); unsigned int findlastnotofofs7 = string_find_last_not_of( shortstr, "", 5 ); unsigned int findlastnotofofs8 = string_find_last_not_of( longstr, "", string_length( longstr ) ); EXPECT_EQ( findlastnotof, 67U ); EXPECT_EQ( findlastnotof2, STRING_NPOS ); EXPECT_EQ( findlastnotof3, STRING_NPOS ); EXPECT_EQ( findlastnotof4, 11U ); EXPECT_EQ( findlastnotof5, 76U ); EXPECT_EQ( findlastnotofofs, 67U ); EXPECT_EQ( findlastnotofofs2, 63U ); EXPECT_EQ( findlastnotofofs3, STRING_NPOS ); EXPECT_EQ( findlastnotofofs4, STRING_NPOS ); EXPECT_EQ( findlastnotofofs5, 5U ); EXPECT_EQ( findlastnotofofs6, 2U ); EXPECT_EQ( findlastnotofofs7, 5U ); EXPECT_EQ( findlastnotofofs8, strlen( longstr ) - 1 ); } string_deallocate( emptystr ); string_deallocate( shortstr ); string_deallocate( longstr ); } return 0; }
String String::substr(int start, int length /* = 0x7FFFFFFF */) const { int len = size(); char *ret = string_substr(data(), len, start, length); return String(ret, len, AttachString); }
int process_spawn(process_t* proc) { static const string_const_t unescaped = { STRING_CONST("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.:/\\") }; size_t i, num_args; size_t size; #if FOUNDATION_PLATFORM_WINDOWS wchar_t* wcmdline; wchar_t* wwd; string_t cmdline; #endif #if !FOUNDATION_PLATFORM_POSIX size_t capacity; #endif proc->code = PROCESS_INVALID_ARGS; if (!proc->path.length) return proc->code; //Always escape path on Windows platforms #if FOUNDATION_PLATFORM_POSIX if (string_find_first_not_of(STRING_ARGS(proc->path), STRING_ARGS(unescaped), 0) != STRING_NPOS) #endif { bool preesc = (proc->path.str[0] != '"'); bool postesc = (proc->path.str[ proc->path.length - 1 ] != '"'); if (preesc || postesc) { char* buffer = memory_allocate(HASH_STRING, proc->path.length + 4, 0, MEMORY_PERSISTENT); string_t pathesc = string_concat_varg(buffer, proc->path.length + 4, "\"", (size_t)(preesc ? 1 : 0), STRING_ARGS(proc->path), "\"", (size_t)(postesc ? 1 : 0), nullptr); string_deallocate(proc->path.str); proc->path = pathesc; } } size = array_size(proc->args); for (i = 0, num_args = 0; i < size; ++i) { string_t arg = proc->args[i]; if (!arg.length) continue; ++num_args; #if !FOUNDATION_PLATFORM_POSIX if (string_find_first_not_of(arg.str, arg.length, unescaped.str, unescaped.length, 0) != STRING_NPOS) { if (arg.str[0] != '"') { //Check if we need to escape " characters string_t escarg; size_t pos = string_find(arg.str, arg.length, '"', 0); while (pos != STRING_NPOS) { if (arg.str[ pos - 1 ] != '\\') { string_const_t right = string_substr(STRING_ARGS(arg), 0, pos); string_const_t left = string_substr(STRING_ARGS(arg), pos, STRING_NPOS); capacity = arg.length + 2; escarg = string_allocate(0, capacity); escarg = string_concat(escarg.str, capacity, STRING_ARGS(right), STRING_CONST("\\")); escarg = string_append(STRING_ARGS(escarg), capacity, STRING_ARGS(left)); string_deallocate(arg.str); arg = escarg; } pos = string_find(STRING_ARGS(arg), '"', pos + 2); } escarg = string_allocate_concat_varg(STRING_CONST("\""), STRING_ARGS(arg), STRING_CONST("\""), nullptr); string_deallocate(arg.str); proc->args[i] = escarg; } } #endif } #if FOUNDATION_PLATFORM_WINDOWS # ifndef SEE_MASK_NOASYNC # define SEE_MASK_NOASYNC 0x00000100 # endif capacity = BUILD_MAX_PATHLEN; cmdline = string_allocate(0, capacity); //Don't prepend exe path to parameters if using ShellExecute if (!(proc->flags & PROCESS_WINDOWS_USE_SHELLEXECUTE)) cmdline = string_copy(cmdline.str, capacity, STRING_ARGS(proc->path)); //Build command line string for (i = 0; i < size; ++i) { string_t arg = proc->args[i]; if (!arg.length) continue; if (cmdline.length + arg.length + 2 >= capacity) { string_t newline; capacity *= 2; newline = string_allocate(0, capacity); newline = string_copy(newline.str, capacity, STRING_ARGS(cmdline)); } if (cmdline.length) cmdline = string_append(STRING_ARGS(cmdline), capacity, STRING_CONST(" ")); cmdline = string_append(STRING_ARGS(cmdline), capacity, STRING_ARGS(arg)); } if (!proc->wd.length) proc->wd = string_clone(STRING_ARGS(environment_current_working_directory())); wcmdline = wstring_allocate_from_string(STRING_ARGS(cmdline)); wwd = wstring_allocate_from_string(STRING_ARGS(proc->wd)); if (proc->flags & PROCESS_WINDOWS_USE_SHELLEXECUTE) { SHELLEXECUTEINFOW sei; wchar_t* wverb; wchar_t* wpath; wverb = (proc->verb.length ? wstring_allocate_from_string(STRING_ARGS(proc->verb)) : 0); wpath = wstring_allocate_from_string(STRING_ARGS(proc->path)); ZeroMemory(&sei, sizeof(sei)); sei.cbSize = sizeof(SHELLEXECUTEINFOW); sei.hwnd = 0; sei.fMask = SEE_MASK_NOASYNC | SEE_MASK_FLAG_NO_UI | SEE_MASK_NOCLOSEPROCESS; sei.lpVerb = wverb; sei.lpFile = wpath; sei.lpParameters = wcmdline; sei.lpDirectory = wwd; sei.nShow = SW_SHOWNORMAL; if (!(proc->flags & PROCESS_CONSOLE)) sei.fMask |= SEE_MASK_NO_CONSOLE; if (proc->flags & PROCESS_STDSTREAMS) log_warn(0, WARNING_UNSUPPORTED, STRING_CONST("Unable to redirect standard in/out" " through pipes when using ShellExecute for process spawning")); log_debugf(0, STRING_CONST("Spawn process (ShellExecute): %.*s %.*s"), STRING_FORMAT(proc->path), STRING_FORMAT(cmdline)); if (!ShellExecuteExW(&sei)) { string_const_t errstr = system_error_message(0); log_warnf(0, WARNING_SYSTEM_CALL_FAIL, STRING_CONST("Unable to spawn process (ShellExecute) for executable '%.*s': %s"), STRING_FORMAT(proc->path), STRING_FORMAT(errstr)); } else { proc->hp = sei.hProcess; proc->ht = 0; proc->code = 0; } wstring_deallocate(wverb); wstring_deallocate(wpath); } else { STARTUPINFOW si; PROCESS_INFORMATION pi; BOOL inherit_handles = FALSE; memset(&si, 0, sizeof(si)); memset(&pi, 0, sizeof(pi)); si.cb = sizeof(si); if (proc->flags & PROCESS_STDSTREAMS) { proc->pipeout = pipe_allocate(); proc->pipein = pipe_allocate(); si.dwFlags |= STARTF_USESTDHANDLES; si.hStdOutput = pipe_write_handle(proc->pipeout); si.hStdInput = pipe_read_handle(proc->pipein); si.hStdError = GetStdHandle(STD_ERROR_HANDLE); //Don't inherit wrong ends of pipes SetHandleInformation(pipe_read_handle(proc->pipeout), HANDLE_FLAG_INHERIT, 0); SetHandleInformation(pipe_write_handle(proc->pipein), HANDLE_FLAG_INHERIT, 0); inherit_handles = TRUE; } log_debugf(0, STRING_CONST("Spawn process (CreateProcess): %.*s %.*s"), STRING_FORMAT(proc->path), STRING_FORMAT(cmdline)); if (!CreateProcessW(0, wcmdline, 0, 0, inherit_handles, (proc->flags & PROCESS_CONSOLE) ? CREATE_NEW_CONSOLE : 0, 0, wwd, &si, &pi)) { string_const_t errstr = system_error_message(0); log_warnf(0, WARNING_SYSTEM_CALL_FAIL, STRING_CONST("Unable to spawn process (CreateProcess) for executable '%.*s': %.*s"), STRING_FORMAT(proc->path), STRING_FORMAT(errstr)); stream_deallocate(proc->pipeout); stream_deallocate(proc->pipein); proc->pipeout = 0; proc->pipein = 0; } else { proc->hp = pi.hProcess; proc->ht = pi.hThread; proc->code = 0; } if (proc->pipeout) pipe_close_write(proc->pipeout); if (proc->pipein) pipe_close_read(proc->pipein); } wstring_deallocate(wcmdline); wstring_deallocate(wwd); string_deallocate(cmdline.str); if (proc->code < 0) return proc->code; //Error #endif #if FOUNDATION_PLATFORM_MACOSX if (proc->flags & PROCESS_MACOSX_USE_OPENAPPLICATION) { proc->pid = 0; LSApplicationParameters params; ProcessSerialNumber psn; FSRef* fsref = memory_allocate(0, sizeof(FSRef), 0, MEMORY_TEMPORARY | MEMORY_ZERO_INITIALIZED); memset(¶ms, 0, sizeof(LSApplicationParameters)); memset(&psn, 0, sizeof(ProcessSerialNumber)); string_const_t pathstripped = string_strip(proc->path.str, proc->path.length, STRING_CONST("\"")); size_t localcap = pathstripped.length + 5; string_t localpath = string_allocate(0, localcap - 1); localpath = string_copy(localpath.str, localcap, STRING_ARGS(pathstripped)); //Need it zero terminated OSStatus status = 0; status = FSPathMakeRef((uint8_t*)localpath.str, fsref, 0); if (status < 0) { localpath = string_append(localpath.str, localpath.length, localcap, STRING_CONST(".app")); status = FSPathMakeRef((uint8_t*)localpath.str, fsref, 0); } CFStringRef* args = 0; for (i = 0, size = array_size(proc->args); i < size; ++i) //App gets executable path automatically, don't include array_push(args, CFStringCreateWithCString(0, proc->args[i].str, kCFStringEncodingUTF8)); CFArrayRef argvref = CFArrayCreate(0, (const void**)args, (CFIndex)array_size(args), 0); params.flags = kLSLaunchDefaults; params.application = fsref; params.argv = argvref; log_debugf(0, STRING_CONST("Spawn process (LSOpenApplication): %.*s"), STRING_FORMAT(localpath)); status = LSOpenApplication(¶ms, &psn); if (status != 0) { int err = status; string_const_t errmsg = system_error_message(err); proc->code = status; log_errorf(0, ERROR_SYSTEM_CALL_FAIL, STRING_CONST("Unable to spawn process for executable '%.*s': %.*s (%d)"), STRING_FORMAT(localpath), STRING_FORMAT(errmsg), err); } CFRelease(argvref); for (i = 0, size = array_size(args); i < size; ++i) CFRelease(args[i]); array_deallocate(args); memory_deallocate(fsref); string_deallocate(localpath.str); if (status == 0) { pid_t pid = 0; GetProcessPID(&psn, &pid); proc->pid = pid; //Always "detached" with LSOpenApplication, not a child process at all //Setup a kqueue to watch when process terminates so we can emulate a wait proc->kq = kqueue(); if (proc->kq < 0) { string_const_t errmsg = system_error_message(proc->kq); log_errorf(0, ERROR_SYSTEM_CALL_FAIL, STRING_CONST("Unable to create kqueue for process watch: %.*s (%d)"), STRING_FORMAT(errmsg), proc->kq); proc->kq = 0; } else { struct kevent changes; EV_SET(&changes, (pid_t)pid, EVFILT_PROC, EV_ADD | EV_RECEIPT, NOTE_EXIT, 0, 0); int ret = kevent(proc->kq, &changes, 1, &changes, 1, 0); if (ret != 1) { int err = errno; string_const_t errmsg = system_error_message(err); log_errorf(0, ERROR_SYSTEM_CALL_FAIL, STRING_CONST("Unable to setup kqueue for process watch, failed to add event to kqueue: %.*s (%d)"), STRING_FORMAT(errmsg), err); close(proc->kq); proc->kq = 0; } } } goto exit; } #endif #if FOUNDATION_PLATFORM_POSIX //Insert executable arg at start and null ptr at end size_t arg; size_t argc = array_size(proc->args) + 1; array_grow(proc->args, 2); for (arg = argc - 1; arg > 0; --arg) proc->args[arg] = proc->args[arg - 1]; proc->args[0] = string_clone(STRING_ARGS(proc->path)); proc->args[argc] = (string_t) { 0, 0 }; char** argv = memory_allocate(0, sizeof(char*) * (argc + 1), 0, MEMORY_PERSISTENT); for (arg = 0; arg < argc; ++arg) argv[arg] = proc->args[arg].str; argv[argc] = 0; if (proc->flags & PROCESS_STDSTREAMS) { proc->pipeout = pipe_allocate(); proc->pipein = pipe_allocate(); } proc->pid = 0; pid_t pid = fork(); if (pid == 0) { //Child if (proc->wd.length) { log_debugf(0, STRING_CONST("Spawned child process, setting working directory to %.*s"), STRING_FORMAT(proc->wd)); environment_set_current_working_directory(STRING_ARGS(proc->wd)); } log_debugf(0, STRING_CONST("Child process executing: %.*s"), STRING_FORMAT(proc->path)); if (proc->flags & PROCESS_STDSTREAMS) { pipe_close_read(proc->pipeout); dup2(pipe_write_handle(proc->pipeout), STDOUT_FILENO); pipe_close_write(proc->pipein); dup2(pipe_read_handle(proc->pipein), STDIN_FILENO); } int code = execv(proc->path.str, (char* const*)argv); //Error int err = errno; string_const_t errmsg = system_error_message(err); log_errorf(0, ERROR_SYSTEM_CALL_FAIL, STRING_CONST("Child process failed execve() '%.*s': %.*s (%d) (%d)"), STRING_FORMAT(proc->path), STRING_FORMAT(errmsg), err, code); process_exit(PROCESS_EXIT_FAILURE); FOUNDATION_UNUSED(code); } memory_deallocate(argv); if (pid > 0) { log_debugf(0, STRING_CONST("Child process forked, pid %d"), pid); proc->pid = pid; if (proc->pipeout) pipe_close_write(proc->pipeout); if (proc->pipein) pipe_close_read(proc->pipein); /*if (proc->flags & PROCESS_DETACHED) { int cstatus = 0; pid_t err = waitpid(pid, &cstatus, WNOHANG); if (err == 0) { //TODO: Ugly wait to make sure process spawned correctly thread_sleep(500); err = waitpid(pid, &cstatus, WNOHANG); } if (err > 0) { //Process exited, check code proc->pid = 0; proc->code = (int)((char)WEXITSTATUS(cstatus)); log_debugf(0, STRING_CONST("Child process returned: %d"), proc->code); return proc->code; } }*/ } else { //Error string_const_t errmsg; errmsg = system_error_message(proc->code); log_errorf(0, ERROR_SYSTEM_CALL_FAIL, STRING_CONST("Unable to spawn process '%.*s': %.*s (%d)"), STRING_FORMAT(proc->path), STRING_FORMAT(errmsg), proc->code); if (proc->pipeout) stream_deallocate(proc->pipeout); if (proc->pipein) stream_deallocate(proc->pipein); proc->pipeout = 0; proc->pipein = 0; proc->code = PROCESS_INVALID_ARGS; return proc->code; } #endif #if !FOUNDATION_PLATFORM_WINDOWS && !FOUNDATION_PLATFORM_POSIX FOUNDATION_ASSERT_FAIL("Process spawning not supported on platform"); #endif #if FOUNDATION_PLATFORM_MACOSX exit: #endif if (proc->flags & PROCESS_DETACHED) return PROCESS_STILL_ACTIVE; return process_wait(proc); }
void TokenStream::getNextStr(Value* value, int lookahead) { int startPos = next(lookahead).start; int length = next(lookahead).length(); string_substr(&_sourceText, startPos, length, value); }
int main(int argc, char *argv[]) { string *s = NULL; string *s2 = NULL; string *s3 = NULL; s = string_append(s, "Hello There"); test(s, "Hello There"); s = string_append(s, "123"); test(s, "Hello There123"); s = string_insert(s, 1, "<new>"); test(s, "H<new>ello There123"); s = string_insert(s, 23, "<new>"); test(s, "H<new>ello There123<new>"); s = string_remove(s, 11, 5); test(s, "H<new>ello 123<new>"); s = string_replace(s, "<new>", "<nothing>"); test(s, "H<nothing>ello 123<nothing>"); s = string_remove(s, 0, 30); test(s, ""); s = string_append(s, "H<nothing>ello 123<nothing>"); test(s, "H<nothing>ello 123<nothing>"); s = string_trunc(s); test(s, ""); string_free(&s); s = string_append_int(s, 1); test(s, "1"); s = string_append_int(s, 10); test(s, "110"); s = string_append_int(s, 100); test(s, "110100"); s = string_append_int(s, 1000000000); test(s, "1101001000000000"); s = string_append_int(s, -2); test(s, "1101001000000000-2"); s = string_append_int(s, -345); test(s, "1101001000000000-2-345"); s = string_append_int(s, -3.45); test(s, "1101001000000000-2-345-3"); s = string_trunc(s); test(s,""); s = string_prepend_int(s, 1); test(s, "1"); s = string_prepend_int(s, 10); test(s, "101"); s = string_prepend_int(s, 100); test(s, "100101"); s = string_prepend_int(s, 1000000000); test(s, "1000000000100101"); s = string_prepend_int(s, -2); test(s, "-21000000000100101"); s = string_prepend_int(s, -345); test(s, "-345-21000000000100101"); s = string_prepend_int(s, -3.45); test(s, "-3-345-21000000000100101"); s = string_trunc(s); test(s,""); string_free(&s); s = string_new("\"Quoted String\""); test(s, "\"Quoted String\""); s = string_replace(s, "\"", ""); test(s, "Quoted String"); string_free(&s); s = string_prepend(s, "Nothing"); test(s, "Nothing"); s = string_prepend(s, "12345678901234567890"); test(s, "12345678901234567890Nothing"); s = string_prepend(s, "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"); test(s, "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890Nothing"); string_free(&s); s = string_append(s, "Nothing"); test(s, "Nothing"); s = string_append(s, "12345678901234567890"); test(s, "Nothing12345678901234567890"); s = string_append(s, "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"); test(s, "Nothing12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"); string_free(&s); s = string_new("printf_append"); test(s, "printf_append"); s = string_printf_append(s, "%8s %3d %10.6f", "string", 20, 3.4); test(s, "printf_append string 20 3.400000"); string_free(&s); s = string_new(""); s = string_printf(s, "%8s %3d %10.6f", "string", 20, 3.4); test(s, " string 20 3.400000"); s2 = string_copy(s); test(s2, " string 20 3.400000"); testi(string_equal_char(s, string_string(s2)), 1); testi(string_equal(s, s2), 1); testi(string_equal_char(s, " string 20 3.40"), 0); s3 = string_new(" string 20 3.40"); testi(string_equal(s, s3), 0); string_free(&s2); string_free(&s3); s = string_remove(s, 100000, 20); test(s, " string 20 3.400000"); s = string_remove(s, 15, 20); test(s, " string 20 "); s = string_remove(s, 13, -1); test(s, " string 20 "); s = string_remove(s, 1, 1); test(s, " string 20 "); s = string_remove(s, 7, 2); test(s, " string20 "); s = string_remove(s, 9, 1); test(s, " string20"); s = string_remove(s, -1, -1); test(s, ""); s = string_insert(s, -1, " string20"); test(s, " string20"); s = string_insert(s, 9, " "); test(s, " string20 "); s = string_insert(s, 7, " "); test(s, " string 20 "); s = string_insert(s, 1, " "); test(s, " string 20 "); s = string_insert(s, 13, " "); test(s, " string 20 "); s = string_insert(s, 15, "3.400000"); test(s, " string 20 3.400000"); s = string_insert(s, 10000, " morestuff"); test(s, " string 20 3.400000 morestuff"); s = string_insert(s, -1, " morestuff"); test(s, " morestuff string 20 3.400000 morestuff"); s2 = string_substr(s, 1, 4); test(s2, "more"); string_free(&s2); s2 = string_substr(s, 5, 7); test(s2, "stuff "); string_free(&s2); string_free(&s); return retval; }
static string_const_t glsl_name_from_token(const string_const_t token) { size_t ofs = string_find_first_of(STRING_ARGS(token), STRING_CONST(GLSL_TOKEN_DELIM "[]"), 0); return string_substr(STRING_ARGS(token), 0, ofs); }
char* path_make_absolute( const char* path ) { unsigned int up, last, length, protocollen; char* abspath = string_clone( path ); if( !path_is_absolute( abspath ) ) { abspath = string_prepend( abspath, "/" ); abspath = string_prepend( abspath, environment_current_working_directory() ); abspath = path_clean( abspath, true ); } else { abspath = path_clean( abspath, true ); } protocollen = string_find_string( abspath, "://", 0 ); if( protocollen != STRING_NPOS ) protocollen += 3; //Also skip the "://" separator else protocollen = 0; //Deal with .. references while( ( up = string_find_string( abspath, "/../", 0 ) ) != STRING_NPOS ) { char* subpath; if( ( protocollen && ( up == ( protocollen - 1 ) ) ) || ( !protocollen && ( up == 0 ) ) ) { //This moves mem so "prot://../path" ends up as "prot://path" memmove( abspath + protocollen, abspath + 3 + protocollen, string_length( abspath ) + 1 - ( 3 + protocollen ) ); continue; } last = string_rfind( abspath, '/', up - 1 ); if( last == STRING_NPOS ) { //Must be a path like C:/../something since other absolute paths last = up; } subpath = string_substr( abspath, 0, last ); subpath = string_append( subpath, abspath + up + 3 ); // +3 will include the / of the later part of the path string_deallocate( abspath ); abspath = subpath; } length = string_length( abspath ); if( length >= 3 ) { while( ( length >= 3 ) && ( abspath[length-3] == '/' ) && ( abspath[length-2] == '.' ) && ( abspath[length-1] == L'.' ) ) { //Step up if( length == 3 ) { abspath[1] = 0; length = 1; } else { length = string_rfind( abspath, '/', length - 4 ); abspath[length] = 0; } } } return abspath; }
static int render_import_glsl_shader(stream_t* stream, const uuid_t uuid, const char* type, size_t type_length) { resource_source_t source; void* blob = 0; size_t size; size_t read; size_t begin; size_t next; hash_t checksum; tick_t timestamp; uint64_t platform; size_t maxtokens; size_t parameter; string_const_t* token = 0; string_const_t valstr; char buffer[128]; int ret = 0; resource_platform_t platformdecl = { -1, -1, RENDERAPIGROUP_OPENGL, -1, -1, -1}; resource_source_initialize(&source); resource_source_read(&source, uuid); read = 0; size = stream_size(stream); blob = memory_allocate(HASH_RESOURCE, size, 0, MEMORY_PERSISTENT); size = stream_read(stream, blob, size); platform = resource_platform(platformdecl); timestamp = time_system(); checksum = hash(blob, size); if (resource_source_write_blob(uuid, timestamp, HASH_SOURCE, platform, checksum, blob, size)) { resource_source_set_blob(&source, timestamp, HASH_SOURCE, platform, checksum, size); } else { ret = -1; goto finalize; } //Parse source and set parameters maxtokens = 256; token = memory_allocate(HASH_RESOURCE, sizeof(string_const_t) * maxtokens, 0, MEMORY_PERSISTENT); begin = 0; parameter = 0; do { string_const_t tokens[64], line; size_t itok, ntokens; next = string_find_first_of(blob, size, STRING_CONST("\n\r"), begin); line = string_substr(blob, size, begin, next - begin); ntokens = string_explode(STRING_ARGS(line), STRING_CONST(GLSL_TOKEN_DELIM), tokens, maxtokens, false); for (itok = 0; itok < ntokens; ++itok) { if ((string_equal(STRING_ARGS(tokens[itok]), STRING_CONST("attribute")) || string_equal(STRING_ARGS(tokens[itok]), STRING_CONST("uniform"))) && (itok + 2 < ntokens)) { char typebuf[16], dimbuf[16]; string_const_t typestr = tokens[itok + 1]; string_const_t namestr = tokens[itok + 2]; string_const_t dimstr; int parameter_type = glsl_type_to_parameter_type(typestr); if (parameter_type < 0) continue; int parameter_dim = glsl_dim_from_token(typestr); if (parameter_dim == 1) parameter_dim = glsl_dim_from_token(namestr); namestr = glsl_name_from_token(namestr); typestr = string_to_const(string_from_uint(typebuf, sizeof(typebuf), (unsigned int)parameter_type, false, 0, 0)); dimstr = string_to_const(string_from_uint(dimbuf, sizeof(dimbuf), (unsigned int)parameter_dim, false, 0, 0)); log_debugf(HASH_RESOURCE, STRING_CONST("parameter: %.*s type %.*s dim %.*s"), STRING_FORMAT(namestr), STRING_FORMAT(typestr), STRING_FORMAT(dimstr)); string_t param = string_format(buffer, sizeof(buffer), STRING_CONST("parameter_type_%" PRIsize), parameter); resource_source_set(&source, timestamp, hash(STRING_ARGS(param)), platform, STRING_ARGS(typestr)); param = string_format(buffer, sizeof(buffer), STRING_CONST("parameter_name_%" PRIsize), parameter); resource_source_set(&source, timestamp, hash(STRING_ARGS(param)), platform, STRING_ARGS(namestr)); param = string_format(buffer, sizeof(buffer), STRING_CONST("parameter_dim_%" PRIsize), parameter); resource_source_set(&source, timestamp, hash(STRING_ARGS(param)), platform, STRING_ARGS(dimstr)); ++parameter; } } begin = string_find_first_not_of(blob, size, STRING_CONST(STRING_WHITESPACE), next); } while (next != STRING_NPOS); valstr = string_from_uint_static(parameter, false, 0, 0); resource_source_set(&source, timestamp, HASH_PARAMETER_COUNT, platform, STRING_ARGS(valstr)); resource_source_set(&source, timestamp, HASH_RESOURCE_TYPE, 0, type, type_length); if (!resource_source_write(&source, uuid, false)) { string_const_t uuidstr = string_from_uuid_static(uuid); log_warnf(HASH_RESOURCE, WARNING_SUSPICIOUS, STRING_CONST("Failed writing imported GLSL shader: %.*s"), STRING_FORMAT(uuidstr)); ret = -1; goto finalize; } else { string_const_t uuidstr = string_from_uuid_static(uuid); log_infof(HASH_RESOURCE, STRING_CONST("Wrote imported GLSL shader: %.*s"), STRING_FORMAT(uuidstr)); } finalize: memory_deallocate(blob); memory_deallocate(token); resource_source_finalize(&source); return ret; }
int main_run( void* main_arg ) { #if !FOUNDATION_PLATFORM_IOS && !FOUNDATION_PLATFORM_ANDROID const char* pattern = 0; char** exe_paths = 0; unsigned int iexe, exesize; process_t* process = 0; char* process_path = 0; unsigned int* exe_flags = 0; #endif int process_result = 0; object_t thread = 0; log_set_suppress( HASH_TEST, ERRORLEVEL_DEBUG ); thread = thread_create( event_thread, "event_thread", THREAD_PRIORITY_NORMAL, 0 ); thread_start( thread, 0 ); while( !thread_is_running( thread ) ) thread_sleep( 10 ); #if FOUNDATION_PLATFORM_IOS || FOUNDATION_PLATFORM_ANDROID while( !_test_should_start ) thread_sleep( 10 ); test_run_fn tests[] = { //test_app_run test_array_run, test_atomic_run, test_base64_run, test_bitbuffer_run, test_blowfish_run, test_bufferstream_run, test_config_run, test_crash_run, test_environment_run, test_error_run, test_event_run, test_fs_run, test_hash_run, test_hashmap_run, test_hashtable_run, test_library_run, test_math_run, test_md5_run, test_mutex_run, test_objectmap_run, test_path_run, test_pipe_run, test_profile_run, test_radixsort_run, test_random_run, test_ringbuffer_run, test_semaphore_run, test_stacktrace_run, test_string_run, test_uuid_run, 0 }; #if FOUNDATION_PLATFORM_ANDROID object_t test_thread = thread_create( test_runner, "test_runner", THREAD_PRIORITY_NORMAL, 0 ); thread_start( test_thread, tests ); while( !thread_is_running( test_thread ) ) { system_process_events(); thread_sleep( 10 ); } while( thread_is_running( test_thread ) ) { system_process_events(); thread_sleep( 10 ); } process_result = (int)(intptr_t)thread_result( test_thread ); thread_destroy( test_thread ); while( thread_is_thread( test_thread ) ) { system_process_events(); thread_sleep( 10 ); } #else process_result = (int)(intptr_t)test_runner( 0, tests ); #endif if( process_result != 0 ) log_warnf( HASH_TEST, WARNING_SUSPICIOUS, "Tests failed with exit code %d", process_result ); while( !_test_should_terminate ) { system_process_events(); thread_sleep( 100 ); } log_debug( HASH_TEST, "Exiting main loop" ); #else //Find all test executables in the current executable directory #if FOUNDATION_PLATFORM_WINDOWS pattern = "test-*.exe"; #elif FOUNDATION_PLATFORM_MACOSX pattern = "test-*"; #elif FOUNDATION_PLATFORM_POSIX pattern = "test-*"; #else # error Not implemented #endif exe_paths = fs_matching_files( environment_executable_directory(), pattern, false ); array_resize( exe_flags, array_size( exe_paths ) ); memset( exe_flags, 0, sizeof( unsigned int ) * array_size( exe_flags ) ); #if FOUNDATION_PLATFORM_MACOSX //Also search for test-*.app const char* app_pattern = "test-*.app"; char** subdirs = fs_subdirs( environment_executable_directory() ); for( int idir = 0, dirsize = array_size( subdirs ); idir < dirsize; ++idir ) { if( string_match_pattern( subdirs[idir], app_pattern ) ) { array_push( exe_paths, string_substr( subdirs[idir], 0, string_length( subdirs[idir] ) - 4 ) ); array_push( exe_flags, PROCESS_OSX_USE_OPENAPPLICATION ); } } string_array_deallocate( subdirs ); #endif for( iexe = 0, exesize = array_size( exe_paths ); iexe < exesize; ++iexe ) { bool is_self = false; char* exe_file_name = path_base_file_name( exe_paths[iexe] ); if( string_equal( exe_file_name, environment_executable_name() ) ) is_self = true; string_deallocate( exe_file_name ); if( is_self ) continue; //Don't run self process_path = path_merge( environment_executable_directory(), exe_paths[iexe] ); process = process_allocate(); process_set_executable_path( process, process_path ); process_set_working_directory( process, environment_executable_directory() ); process_set_flags( process, PROCESS_ATTACHED | exe_flags[iexe] ); log_infof( HASH_TEST, "Running test executable: %s", exe_paths[iexe] ); process_result = process_spawn( process ); while( process_result == PROCESS_WAIT_INTERRUPTED ) { thread_sleep( 10 ); process_result = process_wait( process ); } process_deallocate( process ); string_deallocate( process_path ); if( process_result != 0 ) { if( process_result >= PROCESS_INVALID_ARGS ) log_warnf( HASH_TEST, WARNING_SUSPICIOUS, "Tests failed, process terminated with error %x", process_result ); else log_warnf( HASH_TEST, WARNING_SUSPICIOUS, "Tests failed with exit code %d", process_result ); process_set_exit_code( -1 ); goto exit; } log_infof( HASH_TEST, "All tests from %s passed (%d)", exe_paths[iexe], process_result ); } log_info( HASH_TEST, "All tests passed" ); exit: if( exe_paths ) string_array_deallocate( exe_paths ); array_deallocate( exe_flags ); #endif thread_terminate( thread ); thread_destroy( thread ); while( thread_is_running( thread ) ) thread_sleep( 10 ); while( thread_is_thread( thread ) ) thread_sleep( 10 ); return process_result; }