Example #1
0
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 );
			}	
		}
	}
}
Example #2
0
static real _config_string_to_real( const char* str )
{
	unsigned int length = string_length( str );
	unsigned int first_nonnumeric;
	unsigned int dot_position;
	if( length < 2 )
		return string_to_real( str );

	first_nonnumeric = string_find_first_not_of( str, "0123456789.", 0 );
	if( ( first_nonnumeric == ( length - 1 ) ) && ( ( str[ first_nonnumeric ] == 'm' ) || ( str[ first_nonnumeric ] == 'M' ) ) )
	{
		dot_position = string_find( str, '.', 0 );
		if( dot_position != STRING_NPOS )
		{
			if( string_find( str, '.', dot_position + 1 ) != STRING_NPOS )
				return string_to_real( str ); //More than one dot
		}
		return string_to_real( str ) * ( REAL_C( 1024.0 ) * REAL_C( 1024.0 ) );
	}
	if( ( first_nonnumeric == ( length - 1 ) ) && ( ( str[ first_nonnumeric ] == 'k' ) || ( str[ first_nonnumeric ] == 'K' ) ) )
	{
		dot_position = string_find( str, '.', 0 );
		if( dot_position != STRING_NPOS )
		{
			if( string_find( str, '.', dot_position + 1 ) != STRING_NPOS )
				return string_to_real( str ); //More than one dot
		}
		return string_to_real( str ) * REAL_C( 1024.0 );
	}

	return string_to_real( str );
}
Example #3
0
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;
}
Example #4
0
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( &params, 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( &params, &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 );
}
Example #5
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;
}
Example #6
0
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(&params, 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(&params, &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);
}
Example #7
0
void config_parse( stream_t* stream, hash_t filter_section, bool overwrite )
{
	char* buffer;
	hash_t section = 0;
	hash_t key = 0;
	unsigned int line = 0;

#if BUILD_ENABLE_DEBUG_CONFIG
	log_debugf( HASH_CONFIG, "Parsing config stream: %s", stream_path( stream ) );
#endif
	buffer = memory_allocate_zero( 1024ULL, 0, MEMORY_TEMPORARY );
	while( !stream_eos( stream ) )
	{
		++line;
		stream_read_line_buffer( stream, buffer, 1024, '\n' );
		string_strip( buffer, " \t\n\r" );
		if( !string_length( buffer ) || ( buffer[0] == ';' ) || ( buffer[0] == '#' ) )
			continue;
		if( buffer[0] == '[' )
		{
			//Section declaration
			unsigned int endpos = string_rfind( buffer, ']', string_length( buffer ) - 1 );
			if( ( endpos == STRING_NPOS ) || ( endpos < 1 ) )
			{
				log_warnf( HASH_CONFIG, WARNING_BAD_DATA, "Invalid section declaration on line %d in config stream '%s'", line, stream_path( stream ) );
				continue;
			}
			buffer[endpos] = 0;
			section = hash( buffer + 1, endpos - 1 );
#if BUILD_ENABLE_DEBUG_CONFIG
			log_debugf( HASH_CONFIG, "  config: section set to '%s' (0x%llx)", buffer + 1, section );
#endif
		}
		else if( !filter_section || ( filter_section == section ) )
		{
			//name=value declaration
			char* name;
			char* value;
			unsigned int separator = string_find( buffer, '=', 0 );
			if( separator == STRING_NPOS )
			{
				log_warnf( HASH_CONFIG, WARNING_BAD_DATA, "Invalid value declaration on line %d in config stream '%s', missing assignment operator '=': %s", line, stream_path( stream ), buffer );
				continue;
			}
			
			name = string_strip_substr( buffer, " \t", separator );
			value = string_strip( buffer + separator + 1, " \t" );
			if( !string_length( name ) )
			{
				log_warnf( HASH_CONFIG, WARNING_BAD_DATA, "Invalid value declaration on line %d in config stream '%s', empty name string", line, stream_path( stream ) );
				continue;
			}

			key = hash( name, string_length( name ) );

			if( overwrite || !config_key( section, key, false ) )
			{
#if BUILD_ENABLE_DEBUG_CONFIG
				log_debugf( HASH_CONFIG, "  config: %s (0x%llx) = %s", name, key, value );
#endif

				if( !string_length( value ) )
					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
					config_set_string( section, key, value );
			}
		}
	}
	memory_deallocate( buffer );
}