// license:BSD-3-Clause
// copyright-holders:Maurizio Petrarota
/***************************************************************************
ui/inifile.cpp
UI INIs file manager.
***************************************************************************/
#include "emu.h"
#include "ui/moptions.h"
#include "ui/inifile.h"
#include "softlist.h"
#include "drivenum.h"
//-------------------------------------------------
// GLOBAL VARIABLES
//-------------------------------------------------
UINT16 inifile_manager::c_cat = 0;
UINT16 inifile_manager::c_file = 0;
//-------------------------------------------------
// ctor
//-------------------------------------------------
inifile_manager::inifile_manager(running_machine &machine, ui_options &moptions)
: m_machine(machine)
, m_options(moptions)
{
ini_index.clear();
directory_scan();
}
//-------------------------------------------------
// scan directories and create index
//-------------------------------------------------
void inifile_manager::directory_scan()
{
file_enumerator path(m_options.extraini_path());
const osd::directory::entry *dir;
while ((dir = path.next()) != nullptr)
if (core_filename_ends_with(dir->name, ".ini") && parseopen(dir->name))
{
init_category(std::string(dir->name));
parseclose();
}
// sort
std::stable_sort(ini_index.begin(), ini_index.end());
}
//-------------------------------------------------
// initialize category
//-------------------------------------------------
void inifile_manager::init_category(std::string filename)
{
categoryindex index;
char rbuf[MAX_CHAR_INFO];
std::string readbuf;
while (fgets(rbuf, MAX_CHAR_INFO, fp) != nullptr)
if (rbuf[0] == '[')
{
readbuf = rbuf;
auto name = readbuf.substr(1, readbuf.find("]") - 1);
if (name == "FOLDER_SETTINGS") continue;
index.emplace_back(name, ftell(fp));
}
// sort
std::stable_sort(index.begin(), index.end());
if (!index.empty())
ini_index.emplace_back(strmakelower(filename), index);
}
//-------------------------------------------------
// load and indexing ini files
//-------------------------------------------------
void inifile_manager::load_ini_category(std::vector<int> &temp_filter)
{
if (ini_index.empty())
return;
auto search_clones = false;
std::string filename(ini_index[c_file].first);
auto offset = ini_index[c_file].second[c_cat].second;
if (filename == "category.ini" || filename == "alltime.ini")
search_clones = true;
if (parseopen(filename.c_str()))
{
fseek(fp, offset, SEEK_SET);
char rbuf[MAX_CHAR_INFO];
std::string readbuf;
while (fgets(rbuf, MAX_CHAR_INFO, fp) != nullptr)
{
readbuf = chartrimcarriage(rbuf);
if (readbuf.empty() || readbuf[0] == '[')
break;
auto dfind = driver_list::find(readbuf.c_str());
if (dfind != -1)
{
temp_filter.push_back(dfind);
if (search_clones && driver_list::non_bios_clone(dfind) == -1)
for (int x = 0; x < driver_list::total(); x++)
if (readbuf == driver_list::driver(x).parent && readbuf != driver_list::driver(x).name)
temp_filter.push_back(x);
}
}
parseclose();
}
}
//---------------------------------------------------------
// parseopen - Open up file for reading
//---------------------------------------------------------
bool inifile_manager::parseopen(const char *filename)
{
emu_file file(m_options.extraini_path(), OPEN_FLAG_READ);
if (file.open(filename) != osd_file::error::NONE)
return false;
m_fullpath = file.fullpath();
file.close();
fp = fopen(m_fullpath.c_str(), "r");
fgetc(fp);
fseek(fp, 0, SEEK_SET);
return true;
}
/**************************************************************************
FAVORITE MANAGER
**************************************************************************/
//-------------------------------------------------
// ctor
//-------------------------------------------------
favorite_manager::favorite_manager(running_machine &machine, ui_options &moptions)
: m_machine(machine)
, m_options(moptions)
{
m_current = -1;
parse_favorite();
}
//-------------------------------------------------
// add a game
//-------------------------------------------------
void favorite_manager::add_favorite_game(const game_driver *driver)
{
m_list.emplace_back(driver->name, driver->description, "", "", "", 0, "", driver, "", "", "", 1, "", "", "", true);
save_favorite_games();
}
//-------------------------------------------------
// add a system
//-------------------------------------------------
void favorite_manager::add_favorite_game(ui_software_info &swinfo)
{
m_list.push_back(swinfo);
save_favorite_games();
}
//-------------------------------------------------
// add a game / system
//-------------------------------------------------
void favorite_manager::add_favorite_game()
{
if ((machine().system().flags & MACHINE_TYPE_ARCADE) != 0)
{
add_favorite_game(&machine().system());
return;
}
auto software_avail = false;
for (device_image_interface &image : image_interface_iterator(machine().root_device()))
{
if (image.exists() && image.software_entry())
{
auto swinfo = image.software_entry();
auto part = image.part_entry();
ui_software_info tmpmatches;
tmpmatches.shortname = strensure(swinfo->shortname());
tmpmatches.longname = strensure(image.longname());
tmpmatches.parentname = strensure(swinfo->parentname());
tmpmatches.year = strensure(image.year());
tmpmatches.publisher = strensure(image.manufacturer());
tmpmatches.supported = image.supported();
tmpmatches.part = strensure(part->name());
tmpmatches.driver = &machine().system();
tmpmatches.listname = strensure(image.software_list_name());
tmpmatches.interface = strensure(part->interface());
tmpmatches.instance = strensure(image.instance_name());
tmpmatches.startempty = 0;
tmpmatches.parentlongname.clear();
if (swinfo->parentname())
{
auto swlist = software_list_device::find_by_name(machine().config(), image.software_list_name());
for (software_info &c_swinfo : swlist->get_info())
{
std::string c_parent(c_swinfo.parentname());
if (!c_parent.empty() && c_parent == swinfo->shortname())
{
tmpmatches.parentlongname = c_swinfo.longname();
break;
}
}
}
tmpmatches.usage.clear();
for (feature_list_item &flist : swinfo->other_info())
if (!strcmp(flist.name(), "usage"))
tmpmatches.usage = flist.value();
tmpmatches.devicetype = strensure(image.image_type_name());
tmpmatches.available = true;
software_avail = true;
m_list.push_back(tmpmatches);
save_favorite_games();
}
}
if (!software_avail)
add_favorite_game(&machine().system());
}
//-------------------------------------------------
// remove a favorite from list
//-------------------------------------------------
void favorite_manager::remove_favorite_game(ui_software_info &swinfo)
{
m_list.erase(std::remove(m_list.begin(), m_list.end(), swinfo), m_list.end());
save_favorite_games();
}
//-------------------------------------------------
// remove a favorite from list
//-------------------------------------------------
void favorite_manager::remove_favorite_game()
{
m_list.erase(m_list.begin() + m_current);
save_favorite_games();
}
//-------------------------------------------------
// check if game is already in favorite list
//-------------------------------------------------
bool favorite_manager::isgame_favorite()
{
if ((machine().system().flags & MACHINE_TYPE_ARCADE) != 0)
return isgame_favorite(&machine().system());
auto image_loaded = false;
for (device_image_interface &image : image_interface_iterator(machine().root_device()))
{
const software_info *swinfo = image.software_entry();
if (image.exists() && swinfo != nullptr)
{
image_loaded = true;
for (size_t current = 0; current < m_list.size(); current++)
if (m_list[current].shortname == swinfo->shortname() &&
m_list[current].listname == image.software_list_name())
{
m_current = current;
return true;
}
}
}
if (!image_loaded)
return isgame_favorite(&machine().system());
m_current = -1;
return false;
}
//-------------------------------------------------
// check if game is already in favorite list
//-------------------------------------------------
bool favorite_manager::isgame_favorite(const game_driver *driver)
{
for (size_t x = 0; x < m_list.size(); x++)
if (m_list[x].driver == driver && m_list[x].shortname == driver->name)
{
m_current = x;
return true;
}
m_current = -1;
return false;
}
//-------------------------------------------------
// check if game is already in favorite list
//-------------------------------------------------
bool favorite_manager::isgame_favorite(ui_software_info &swinfo)
{
for (size_t x = 0; x < m_list.size(); x++)
if (m_list[x] == swinfo)
{
m_current = x;
return true;
}
m_current = -1;
return false;
}
//-------------------------------------------------
// parse favorite file
//-------------------------------------------------
void favorite_manager::parse_favorite()
{
emu_file file(m_options.ui_path(), OPEN_FLAG_READ);
if (file.open(favorite_filename) == osd_file::error::NONE)
{
char readbuf[1024];
file.gets(readbuf, 1024);
while (readbuf[0] == '[')
file.gets(readbuf, 1024);
while (file.gets(readbuf, 1024))
{
ui_software_info tmpmatches;
tmpmatches.shortname = chartrimcarriage(readbuf);
file.gets(readbuf, 1024);
tmpmatches.longname = chartrimcarriage(readbuf);
file.gets(readbuf, 1024);
tmpmatches.parentname = chartrimcarriage(readbuf);
file.gets(readbuf, 1024);
tmpmatches.year = chartrimcarriage(readbuf);
file.gets(readbuf, 1024);
tmpmatches.publisher = chartrimcarriage(readbuf);
file.gets(readbuf, 1024);
tmpmatches.supported = atoi(readbuf);
file.gets(readbuf, 1024);
tmpmatches.part = chartrimcarriage(readbuf);
file.gets(readbuf, 1024);
chartrimcarriage(readbuf);
auto dx = driver_list::find(readbuf);
if (dx == -1) continue;
tmpmatches.driver = &driver_list::driver(dx);
file.gets(readbuf, 1024);
tmpmatches.listname = chartrimcarriage(readbuf);
file.gets(readbuf, 1024);
tmpmatches.interface = chartrimcarriage(readbuf);
file.gets(readbuf, 1024);
tmpmatches.instance = chartrimcarriage(readbuf);
file.gets(readbuf, 1024);
tmpmatches.startempty = atoi(readbuf);
file.gets(readbuf, 1024);
tmpmatches.parentlongname = chartrimcarriage(readbuf);
file.gets(readbuf, 1024);
tmpmatches.usage = chartrimcarriage(readbuf);
file.gets(readbuf, 1024);
tmpmatches.devicetype = chartrimcarriage(readbuf);
file.gets(readbuf, 1024);
tmpmatches.available = atoi(readbuf);
m_list.push_back(tmpmatches);
}
file.close();
}
}
//-------------------------------------------------
// save favorite
//-------------------------------------------------
void favorite_manager::save_favorite_games()
{
// attempt to open the output file
emu_file file(m_options.ui_path(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
if (file.open(favorite_filename) == osd_file::error::NONE)
{
if (m_list.empty())
{
file.remove_on_close();
file.close();
return;
}
// generate the favorite INI
std::ostringstream text;
text << "[ROOT_FOLDER]\n[Favorite]\n\n";
for (auto & elem : m_list)
{
text << elem.shortname << '\n';
text << elem.longname << '\n';
text << elem.parentname << '\n';
text << elem.year << '\n';
text << elem.publisher << '\n';
util::stream_format(text, "%d\n", elem.supported);
text << elem.part << '\n';
util::stream_format(text, "%s\n", elem.driver->name);
text << elem.listname << '\n';
text << elem.interface << '\n';
text << elem.instance << '\n';
util::stream_format(text, "%d\n", elem.startempty);
text << elem.parentlongname << '\n';
text << elem.usage << '\n';
text << elem.devicetype << '\n';
util::stream_format(text, "%d\n", elem.available);
}
file.puts(text.str().c_str());
file.close();
}
}