예제 #1
0
void FeRomList::get_tags_list( FeRomInfo &rom,
		std::vector< std::pair<std::string, bool> > &tags_list ) const
{
	std::string curr_tags = rom.get_info(FeRomInfo::Tags);

	std::set<std::string> my_set;
	size_t pos=0;
	do
	{
		std::string one_tag;
		const char sep[] = { FE_TAGS_SEP, 0 };
		token_helper( curr_tags, pos, one_tag, sep );
		if ( !one_tag.empty() )
		{
			my_set.insert( one_tag );
		}
	} while ( pos < curr_tags.size() );

	for ( std::map<std::string, bool>::const_iterator itr=m_tags.begin(); itr!=m_tags.end(); ++itr )
	{
		tags_list.push_back(
				std::pair<std::string, bool>((*itr).first,
						( my_set.find( (*itr).first ) != my_set.end() ) ) );
	}
}
예제 #2
0
void FeRomList::get_tags_list( int filter_index, int rom_index,
		std::vector< std::pair<std::string, bool> > &tags_list ) const
{
	if (( rom_index < 0 ) || ( rom_index >= filter_size( filter_index ) ))
		return;

	std::string curr_tags = (m_filtered_list[filter_index][rom_index])->get_info(FeRomInfo::Tags);

	std::set<std::string> my_set;
	size_t pos=0;
	do
	{
		std::string one_tag;
		const char sep[] = { FE_TAGS_SEP, 0 };
		token_helper( curr_tags, pos, one_tag, sep );
		if ( !one_tag.empty() )
		{
			my_set.insert( one_tag );
		}
	} while ( pos < curr_tags.size() );

	for ( std::map<std::string, bool>::const_iterator itr=m_tags.begin(); itr!=m_tags.end(); ++itr )
	{
		tags_list.push_back(
				std::pair<std::string, bool>((*itr).first,
						( my_set.find( (*itr).first ) != my_set.end() ) ) );
	}
}
예제 #3
0
void string_to_vector( const std::string &input,
	std::vector< std::string > &vec, bool allow_empty )
{
	size_t pos=0;
	do
	{
		std::string val;
		token_helper( input, pos, val );

		if ( ( !val.empty() ) || allow_empty )
			vec.push_back( val );

	} while ( pos < input.size() );
}
예제 #4
0
bool run_program( const std::string &prog,
	const::std::string &args,
	output_callback_fn callback,
	void *opaque,
	bool block,
	const std::string &exit_hotkey,
	int joy_thresh )
{
	const int POLL_FOR_EXIT_MS=100;

	std::string comstr( prog );
	comstr += " ";
	comstr += args;

#ifdef SFML_SYSTEM_WINDOWS
	HANDLE child_output_read=NULL;
	HANDLE child_output_write=NULL;

	SECURITY_ATTRIBUTES satts;
	satts.nLength = sizeof( SECURITY_ATTRIBUTES );
	satts.bInheritHandle = TRUE;
	satts.lpSecurityDescriptor = NULL;

	STARTUPINFO si;
	PROCESS_INFORMATION pi;
	MSG msg;

	ZeroMemory( &si, sizeof(si) );
	ZeroMemory( &pi, sizeof(pi) );
	si.cb = sizeof(si);

	if ( NULL != callback )
	{
		CreatePipe( &child_output_read, &child_output_write, &satts, 1024 );
		si.hStdOutput = child_output_write;
		si.dwFlags |= STARTF_USESTDHANDLES;
	}

	LPSTR cmdline = new char[ comstr.length() + 1 ];
	strncpy( cmdline, comstr.c_str(), comstr.length() + 1 );

	LPSTR path = NULL;
	size_t pos = prog.find_last_of( "/\\" );
	if ( pos != std::string::npos )
	{
		path = new char[ pos + 1 ];
		strncpy( path, prog.substr( 0, pos ).c_str(), pos + 1 );
	}

	bool ret = CreateProcess( NULL,
		cmdline,
		NULL,
		NULL,
		( NULL == callback ) ? FALSE : TRUE,
		0,
		NULL,
		path,
		&si,
		&pi );

	// Parent process - close the child write handle after child created
	if ( child_output_write )
		CloseHandle( child_output_write );

	//
	// Cleanup our allocated values now
	//
	if ( path )
		delete [] path;

	delete [] cmdline;

	if ( ret == false )
	{
		std::cerr << "Error executing command: '" << comstr << "'" << std::endl;
		return false;
	}

	if (( NULL != callback ) && ( block ))
	{
		char buffer[ 1024 ];
		buffer[1023]=0;
		DWORD bytes_read;
		while ( ReadFile( child_output_read, buffer, 1023, &bytes_read, NULL ) != 0 )
		{
			buffer[bytes_read]=0;
			if ( callback( buffer, opaque ) == false )
			{
				TerminateProcess( pi.hProcess, 0 );
				block=false;
				break;
			}
		}
	}

	if ( child_output_read )
		CloseHandle( child_output_read );

	DWORD timeout = exit_hotkey.empty() ? INFINITE : POLL_FOR_EXIT_MS;
	FeInputSource exit_is( exit_hotkey );

	bool keep_wait=block;
	while (keep_wait)
	{
		switch (MsgWaitForMultipleObjects(1, &pi.hProcess,
						FALSE, timeout, QS_ALLINPUT))
		{
		case WAIT_OBJECT_0:
			keep_wait=false;
			break;

		case WAIT_OBJECT_0 + 1:
			// we have a message - peek and dispatch it
			while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
			{
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
			break;

		case WAIT_TIMEOUT:
			// We should only ever get here if an exit_hotkey was provided
			//
			if ( exit_is.get_current_state( joy_thresh ) )
			{
				TerminateProcess( pi.hProcess, 0 );
				keep_wait=false;
			}
			break;

		default:
			std::cerr << "Unexpected failure waiting on process" << std::endl;
			keep_wait=false;
			break;
		}
	}

	CloseHandle( pi.hProcess );
	CloseHandle( pi.hThread );

#else

	std::vector < std::string > string_list;
	size_t pos=0;

	while ( pos < args.size() )
	{
		std::string val;
		token_helper( args, pos, val, FE_WHITESPACE );
		string_list.push_back( val );
	}

	char *arg_list[string_list.size() + 2];
	arg_list[0] = (char *)prog.c_str();
	for ( unsigned int i=0; i < string_list.size(); i++ )
		arg_list[i+1] = (char *)string_list[i].c_str();

	arg_list[string_list.size() + 1] = NULL;

	int mypipe[2] = { 0, 0 }; // mypipe[0] = read end, mypipe[1] = write end
	if (( NULL != callback ) && block && ( pipe( mypipe ) ))
		std::cerr << "Error, pipe() failed" << std::endl;

	pid_t pid = fork();
	switch (pid)
	{
	case -1:
		std::cerr << "Error, fork() failed" << std::endl;
		if ( mypipe[0] )
		{
			close( mypipe[0] );
			close( mypipe[1] );
		}
		return false;

	case 0: // child process
		if ( mypipe[0] )
		{
			dup2( mypipe[1], fileno(stdout) );
			close( mypipe[1] );
		}

		{
			size_t pos = prog.find_last_of( "/" );
			if ( pos != std::string::npos )
				chdir( prog.substr( 0, pos ).c_str() );
		}
		execvp( prog.c_str(), arg_list );

		// execvp doesn't return unless there is an error.
		std::cerr << "Error executing: " << prog << " " << args << std::endl;
		_exit(127);

	default: // parent process

		if ( mypipe[0] )
		{
			FILE *fp = fdopen( mypipe[0], "r" );
			close( mypipe[1] );

			char buffer[ 1024 ];

			while( fgets( buffer, 1024, fp ) != NULL )
			{
				if ( callback( buffer, opaque ) == false )
				{
					// User cancelled
					kill( pid, SIGTERM );
					block=false;
					break;
				}
			}

			fclose( fp );
			close( mypipe[0] );
		}

		if ( block )
		{
			int status;
			int opt = exit_hotkey.empty() ? 0 : WNOHANG; // option for waitpid.  0= wait for process to complete, WNOHANG=return right away
			FeInputSource exit_is( exit_hotkey );

			do
			{
				if ( waitpid( pid, &status, opt ) == 0 )
				{
					// waitpid should only return 0 if WNOHANG is used and the child is still running, so we
					// should only ever get here if there is an exit_hotkey provided
					//
					if ( exit_is.get_current_state( joy_thresh ) )
					{
						kill( pid, SIGTERM );
						break; // leave do/while loop
					}

					sf::sleep( sf::milliseconds( POLL_FOR_EXIT_MS ) );
				}
			} while ( !WIFEXITED( status ) && !WIFSIGNALED( status ) );
		}
	}
#endif // SFML_SYSTEM_WINDOWS
	return true;
}
예제 #5
0
void FeSettings::apply_xml_import( FeImporterContext &c )
{
	std::string source = c.emulator.get_info(
				FeEmulatorInfo::Info_source );

	if ( source.empty() )
		return;

	std::string base_command = clean_path( c.emulator.get_info(
				FeEmulatorInfo::Executable ) );

	if ( source.compare( "mame" ) == 0 )
	{
		std::cout << " - Obtaining -listxml info...";
		FeMameXMLParser mamep( c );
		if ( !mamep.parse( base_command ) )
			std::cout << "No XML output found, command: " << base_command << " -listxml" << std::endl;
	}
	else if ( source.compare( "mess" ) == 0 )
	{
		const std::vector < std::string > &system_names = c.emulator.get_systems();
		if ( system_names.empty() )
		{
			std::cout << "Note: No system configured for emulator: "
				<< c.emulator.get_info( FeEmulatorInfo::Name )
				<< ", unable to obtain -listsoftware info."
				<< std::endl;
			return;
		}

		FeMessXMLParser messp( c );
		messp.parse( base_command, system_names );
	}
	else if ( source.compare( "steam" ) == 0 )
	{
		const std::vector<std::string> &paths = c.emulator.get_paths();
		const std::vector<std::string> &exts = c.emulator.get_extensions();
		if ( paths.empty() || exts.empty() )
			return;

		std::string path = clean_path( paths.front(), true );
		const std::string &extension = exts.front();

		// A bit mislabelled: the steam import isn't really xml.
		for ( FeRomInfoListType::iterator itr = c.romlist.begin(); itr != c.romlist.end(); ++itr )
		{
			// We expect appmanifest_* entries in the romname field.  Open each of these files and
			// extract the data we can use in our list
			const std::string &n = (*itr).get_info( FeRomInfo::Romname );
			std::string fname = path + n + extension;

			//
			// First, Fix the Romname entry in case we don't find it in the manifest
			//
			size_t start_pos = n.find_last_of( "_" );
			if ( start_pos != std::string::npos )
				(*itr).set_info( FeRomInfo::Romname,
						n.substr( start_pos + 1 ) );

			std::ifstream myfile( fname.c_str() );

			int fields_left( 3 );

			if ( myfile.is_open() )
			{
				while ( myfile.good() && ( fields_left > 0 ) )
				{
					std::string line, val;
					size_t pos( 0 );

					getline( myfile, line );

					token_helper( line, pos, val, FE_WHITESPACE );

					if ( icompare( val, "appid" ) == 0 )
					{
						std::string id;
						token_helper( line, pos, id, FE_WHITESPACE );
						(*itr).set_info( FeRomInfo::Romname, id );
						fields_left--;
					}
					else if ( icompare( val, "name" ) == 0 )
					{
						std::string name;
						token_helper( line, pos, name, FE_WHITESPACE );
						(*itr).set_info( FeRomInfo::Title, name );
						fields_left--;
					}
					else if ( icompare( val, "installdir" ) == 0 )
					{
						std::string altname;
						token_helper( line, pos, altname, FE_WHITESPACE );
						(*itr).set_info( FeRomInfo::AltRomname, altname );
						fields_left--;
					}
				}

				ASSERT( !fields_left );
			}
			else
				std::cerr << "Error opening file: " << fname << std::endl;
		}
	}
	else if ( source.compare( "thegamesdb.net" ) == 0 )
		thegamesdb_scraper( c );
	else
	{
		std::cout << "Unrecognized import_source setting: " << source
					<< std::endl;
	}
}
예제 #6
0
void FeRomList::save_tags()
{
	if (( !m_tags_changed ) || ( m_user_path.empty() ) || ( m_romlist_name.empty() ))
		return;

	// First construct a mapping of tags to rom entries
	//
	std::multimap< std::string, const char * > tag_to_rom_map;

	for ( std::multimap< std::string, const char * >::const_iterator ite = m_extra_tags.begin(); ite != m_extra_tags.end(); ++ite )
	{
		tag_to_rom_map.insert(
				std::pair<std::string,const char *>(
						(*ite).second,
						(*ite).first.c_str() ) );
	}

	for ( FeRomInfoListType::const_iterator itr = m_list.begin(); itr != m_list.end(); ++itr )
	{
		const std::string &my_tags = (*itr).get_info( FeRomInfo::Tags );

		size_t pos=0;
		do
		{
			std::string one_tag;
			const char sep[] = { FE_TAGS_SEP, 0 };
			token_helper( my_tags, pos, one_tag, sep );

			if ( !one_tag.empty() )
			{
				tag_to_rom_map.insert(
						std::pair<std::string,const char *>(
								one_tag,
								((*itr).get_info( FeRomInfo::Romname )).c_str() ) );
			}
		} while ( pos < my_tags.size() );
	}

	confirm_directory( m_user_path, m_romlist_name );
	std::string my_path = m_user_path + m_romlist_name + "/";

	//
	// Now save the tags
	//
	std::map<std::string,bool>::const_iterator itt;
	for ( itt = m_tags.begin(); itt != m_tags.end(); ++itt )
	{
		if ( (*itt).second == false )
			continue;

		std::string file_name = my_path + (*itt).first + FE_FAVOURITE_FILE_EXTENSION;

		std::pair<std::multimap<std::string,const char *>::const_iterator,std::multimap<std::string,const char *>::const_iterator> ret;
		ret = tag_to_rom_map.equal_range( (*itt).first );
		if ( ret.first == ret.second )
		{
			delete_file( file_name );
		}
		else
		{
			std::ofstream outfile( file_name.c_str() );
			if ( !outfile.is_open() )
				continue;

			for ( std::multimap<std::string,const char *>::const_iterator ito = ret.first; ito != ret.second; ++ito )
				outfile << (*ito).second << std::endl;

			outfile.close();
		}
	}
}
예제 #7
0
bool FeRomList::load_romlist( const std::string &path,
			const std::string &romlist_name,
			const std::string &user_path,
			const std::string &stat_path,
			FeDisplayInfo &display )
{
	m_user_path = user_path;
	m_romlist_name = romlist_name;

	m_list.clear();
	m_filtered_list.clear();
	m_availability_checked = false;

	m_global_filter_ptr = NULL;
	m_global_filtered_out_count = 0;

	FeFilter *first_filter = display.get_global_filter();
	if ( first_filter )
	{
		first_filter->init();

		if ( !first_filter->test_for_target( FeRomInfo::FileIsAvailable )
			&& !first_filter->test_for_target( FeRomInfo::Favourite )
			&& !first_filter->test_for_target( FeRomInfo::Tags ) )
		{
			// If the global filter doesn't care about file availability,
			// favourites or tags then we can apply it right up front when we
			// load the romlist.  We signal this by setting m_global_filter_ptr
			m_global_filter_ptr = first_filter;
			first_filter = NULL;
		}
	}

	sf::Clock load_timer;

	bool retval = FeBaseConfigurable::load_from_file(
			path + m_romlist_name + FE_ROMLIST_FILE_EXTENSION, ";" );

	//
	// Create rom name to romlist entry lookup map
	//
	std::map < std::string, FeRomInfo * > rom_map;
	std::map < std::string, FeRomInfo * >::iterator rm_itr;
	for ( FeRomInfoListType::iterator itr = m_list.begin(); itr != m_list.end(); ++itr )
		rom_map[ (*itr).get_info( FeRomInfo::Romname ) ] = &(*itr);

	//
	// Load favourites
	//
	m_extra_favs.clear();
	m_fav_changed=false;

	std::string load_name( m_user_path + m_romlist_name + FE_FAVOURITE_FILE_EXTENSION );
	std::ifstream myfile( load_name.c_str() );

	if ( myfile.is_open() )
	{
		while ( myfile.good() )
		{
			size_t pos=0;
			std::string line, name;

			getline( myfile, line );
			token_helper( line, pos, name );

			if ( !name.empty() )
			{
				rm_itr = rom_map.find( name );
				if ( rm_itr != rom_map.end() )
					(*rm_itr).second->set_info( FeRomInfo::Favourite, "1" );
				else
					m_extra_favs.insert( name );
			}
		}

		myfile.close();
	}

	//
	// Load tags
	//
	m_tags.clear();
	m_extra_tags.clear();
	m_tags_changed=false;
	load_name = m_user_path + m_romlist_name + "/";

	if ( directory_exists( load_name ) )
	{
		std::vector<std::string> temp_tags;
		get_basename_from_extension( temp_tags, load_name, FE_FAVOURITE_FILE_EXTENSION );

		for ( std::vector<std::string>::iterator itr=temp_tags.begin(); itr!=temp_tags.end(); ++itr )
		{
			if ( (*itr).empty() )
				continue;

			std::ifstream myfile( std::string(load_name + (*itr) + FE_FAVOURITE_FILE_EXTENSION).c_str() );

			if ( !myfile.is_open() )
				continue;

			std::map<std::string, bool>::iterator itt = m_tags.begin();
			itt = m_tags.insert( itt, std::pair<std::string,bool>( (*itr), false ) );

			while ( myfile.good() )
			{
				size_t pos=0;
				std::string line, rname;

				getline( myfile, line );
				token_helper( line, pos, rname );

				if ( !rname.empty() )
				{
					rm_itr = rom_map.find( rname );
					if ( rm_itr != rom_map.end() )
						(*rm_itr).second->append_tag( (*itt).first.c_str() );
					else
						m_extra_tags.insert( std::pair<std::string,const char*>(rname, (*itt).first.c_str() ) );
				}
			}

			myfile.close();
		}
	}

	// Apply global filter if it hasn't been applied already
	if ( first_filter )
	{
		if ( first_filter->test_for_target( FeRomInfo::FileIsAvailable ) )
			get_file_availability();

		FeRomInfoListType::iterator last_it=m_list.begin();
		for ( FeRomInfoListType::iterator it=m_list.begin(); it!=m_list.end(); )
		{
			if ( first_filter->apply_filter( *it ) )
			{
				if ( last_it != it )
					it = m_list.erase( last_it, it );
				else
					++it;

				last_it = it;
			}
			else
			{
				//
				// This rom is being filtered out and we may need to keep track of a few things
				//
				// 1. Track if this is a favourite...
				//
				if ( !(*it).get_info( FeRomInfo::Favourite ).empty() )
					m_extra_favs.insert( (*it).get_info( FeRomInfo::Romname ) );

				//
				// 2. Track if this rom has tags we'll need to keep
				//
				if ( !(*it).get_info( FeRomInfo::Tags ).empty() )
				{
					const std::string &name = (*it).get_info( FeRomInfo::Romname );
					const std::string &tags = (*it).get_info( FeRomInfo::Tags );
					const char sep[] = { FE_TAGS_SEP, 0 };

					size_t pos=0;
					while ( pos < tags.size() )
					{
						std::string one_tag;
						token_helper( tags, pos, one_tag, sep );

						std::map<std::string, bool>::iterator itt = m_tags.find( one_tag );
						if ( itt != m_tags.end() )
							m_extra_tags.insert( std::pair<std::string,const char *>( name, (*itt).first.c_str() ) );
					}
				}

				m_global_filtered_out_count++;
				++it;
			}
		}

		if ( last_it != m_list.end() )
			m_list.erase( last_it, m_list.end() );
	}

	std::cout << " - Loaded master romlist '" << m_romlist_name
			<< "' in " << load_timer.getElapsedTime().asMilliseconds()
			<< " ms (" << m_list.size() << " entries kept, " << m_global_filtered_out_count
			<< " discarded)" << std::endl;

	load_timer.restart();

	//
	// Apply filters
	//
	int filters_count = display.get_filter_count();

	//
	// If the display doesn't have any filters configured, we create a single "filter" in the romlist object
	// with every romlist entry in it
	//
	if ( filters_count == 0 )
		filters_count = 1;

	m_filtered_list.reserve( filters_count );
	for ( int i=0; i<filters_count; i++ )
	{
		m_filtered_list.push_back( std::vector< FeRomInfo *>()  );

		FeFilter *f = display.get_filter( i );
		if ( f )
		{
			if ( f->get_size() > 0 ) // if this is non zero then we've loaded before and know how many to expect
				m_filtered_list[i].reserve( f->get_size() );

			if ( f->test_for_target( FeRomInfo::FileIsAvailable ) )
				get_file_availability();

			f->init();
			for ( FeRomInfoListType::iterator itr=m_list.begin(); itr!=m_list.end(); ++itr )
				if ( f->apply_filter( *itr ) )
					m_filtered_list[i].push_back( &( *itr ) );
		}
		else // no filter situation, so we just add the entire list...
		{
			m_filtered_list[i].reserve( m_list.size() );
			for ( FeRomInfoListType::iterator itr=m_list.begin(); itr!=m_list.end(); ++itr )
				m_filtered_list[i].push_back( &( *itr ) );
		}

		//
		// make sure stats are loaded for the roms we will be showing
		//
		if ( !stat_path.empty() )
		{
			for ( std::vector< FeRomInfo * >::iterator itf=m_filtered_list[i].begin();
						itf!=m_filtered_list[i].end();
						++itf )
				(*itf)->load_stats( stat_path ); // this will just return if stats are already loaded for the rom
		}

		if ( f )
		{
			// track the size of the filtered list in our filter info object
			f->set_size( m_filtered_list[i].size() );

			//
			// Sort and/or prune now if configured for this filter
			//
			FeRomInfo::Index sort_by=f->get_sort_by();
			bool rev = f->get_reverse_order();
			int list_limit = f->get_list_limit();

			if ( sort_by != FeRomInfo::LAST_INDEX )
			{
				std::stable_sort( m_filtered_list[i].begin(),
						m_filtered_list[i].end(),
						FeRomListSorter2( sort_by, rev ) );
			}
			else if ( rev != false )
				std::reverse( m_filtered_list[i].begin(), m_filtered_list[i].end() );

			if (( list_limit != 0 ) && ( (int)m_filtered_list[i].size() > abs( list_limit ) ))
			{
				if ( list_limit > 0 )
					m_filtered_list[i].erase( m_filtered_list[i].begin() + list_limit, m_filtered_list[i].end() );
				else
					m_filtered_list[i].erase( m_filtered_list[i].begin(), m_filtered_list[i].end() + list_limit );
			}
		}
	}

	std::cout << " - Constructed " << filters_count << " filters in "
			<< load_timer.getElapsedTime().asMilliseconds()
			<< " ms (" << filters_count * m_list.size() << " comparisons)" << std::endl;

	return retval;
}