void menu_file_selector::type_search_char(char32_t ch) { std::string const current(m_filename); if (input_character(m_filename, ch, uchar_is_printable)) { ui().popup_time(ERROR_MESSAGE_TIME, "%s", m_filename.c_str()); file_selector_entry const *const cur_selected(reinterpret_cast<file_selector_entry const *>(get_selection_ref())); // if it's a perfect match for the current selection, don't move it if (!cur_selected || core_strnicmp(cur_selected->basename.c_str(), m_filename.c_str(), m_filename.size())) { std::string::size_type bestmatch(0); file_selector_entry const *selected_entry(cur_selected); for (auto &entry : m_entrylist) { // TODO: more efficient "common prefix" code std::string::size_type match(0); for (std::string::size_type i = 1; m_filename.size() >= i; ++i) { if (!core_strnicmp(entry.basename.c_str(), m_filename.c_str(), i)) match = i; else break; } if (match > bestmatch) { bestmatch = match; selected_entry = &entry; } } if (selected_entry && (selected_entry != cur_selected)) { set_selection((void *)selected_entry); centre_selection(); } } } }
char* MyStrStrI(const char* pFirst, const char* pSrch) { char* cp = (char*)pFirst; char* s1; char* s2; while (*cp) { s1 = cp; s2 = (char*)pSrch; while (*s1 && *s2 && !core_strnicmp(s1, s2, 1)) s1++, s2++; if (!*s2) return cp; cp++; } return NULL; }
//------------------------------------------------- // create the menu index //------------------------------------------------- void datfile_manager::index_menuidx(const game_driver *drv, dataindex &idx, drvindex &index) { dataindex::iterator itemsiter = idx.find(drv); if (itemsiter == idx.end()) { int cloneof = driver_list::non_bios_clone(*drv); if (cloneof == -1) return; else { const game_driver *c_drv = &driver_list::driver(cloneof); itemsiter = idx.find(c_drv); if (itemsiter == idx.end()) return; } } // seek to correct point in datafile long s_offset = (*itemsiter).second; fseek(fp, s_offset, SEEK_SET); size_t tinfo = TAG_INFO.size(); char rbuf[64 * 1024]; std::string readbuf; while (fgets(rbuf, 64 * 1024, fp) != nullptr) { readbuf = chartrimcarriage(rbuf); if (!core_strnicmp(TAG_INFO.c_str(), readbuf.c_str(), tinfo)) break; // TAG_COMMAND identifies the driver if (readbuf == TAG_COMMAND) { fgets(rbuf, 64 * 1024, fp); chartrimcarriage(rbuf); index.emplace(rbuf, ftell(fp)); } } }
//------------------------------------------------- // create the menu index //------------------------------------------------- void datfile_manager::index_menuidx(fileptr &&fp, const game_driver *drv, dataindex const &idx, drvindex &index) { auto itemsiter = idx.find(drv); if (itemsiter == idx.end()) { auto const cloneof = driver_list::non_bios_clone(*drv); if (cloneof == -1) return; auto const c_drv = &driver_list::driver(cloneof); if ((itemsiter = idx.find(c_drv)) == idx.end()) return; } // seek to correct point in datafile auto const s_offset = itemsiter->second; std::fseek(fp.get(), s_offset, SEEK_SET); auto const tinfo = TAG_INFO.size(); char rbuf[64 * 1024]; std::string readbuf; while (std::fgets(rbuf, 64 * 1024, fp.get()) != nullptr) { readbuf = chartrimcarriage(rbuf); if (!core_strnicmp(TAG_INFO.c_str(), readbuf.c_str(), tinfo)) break; // TAG_COMMAND identifies the driver if (readbuf == TAG_COMMAND) { std::fgets(rbuf, 64 * 1024, fp.get()); chartrimcarriage(rbuf); index.emplace(rbuf, std::ftell(fp.get())); } } }
const osd_directory_entry *zippath_readdir(zippath_directory *directory) { const osd_directory_entry *result = NULL; const zip_file_header *header; const char *relpath; const char *separator; const char *s; zippath_returned_directory *rdent; if (!directory->returned_parent) { /* first thing's first - return parent directory */ directory->returned_parent = true; memset(&directory->returned_entry, 0, sizeof(directory->returned_entry)); directory->returned_entry.name = ".."; directory->returned_entry.type = ENTTYPE_DIR; result = &directory->returned_entry; } else if (directory->directory != NULL) { /* a normal directory read */ do { result = osd_readdir(directory->directory); } while((result != NULL) && (!strcmp(result->name, ".") || !strcmp(result->name, ".."))); /* special case - is this entry a ZIP file? if so we need to return it as a "directory" */ if ((result != NULL) && is_zip_file(result->name)) { /* copy; but change the entry type */ directory->returned_entry = *result; directory->returned_entry.type = ENTTYPE_DIR; result = &directory->returned_entry; } } else if (directory->zipfile != NULL) { do { /* a zip file read */ do { if (!directory->called_zip_first) header = zip_file_first_file(directory->zipfile); else header = zip_file_next_file(directory->zipfile); directory->called_zip_first = true; relpath = NULL; } while((header != NULL) && ((relpath = get_relative_path(directory, header)) == NULL)); if (relpath != NULL) { /* we've found a ZIP entry; but this may be an entry deep within the target directory */ for (s = relpath; *s && !is_zip_file_separator(*s); s++) ; separator = *s ? s : NULL; if (separator != NULL) { /* a nested entry; loop through returned_dirlist to see if we've returned the parent directory */ for (rdent = directory->returned_dirlist; rdent != NULL; rdent = rdent->next) { if (!core_strnicmp(rdent->name.c_str(), relpath, separator - relpath)) break; } if (rdent == NULL) { /* we've found a new directory; add this to returned_dirlist */ rdent = new zippath_returned_directory; rdent->next = directory->returned_dirlist; rdent->name.assign(relpath, separator - relpath); directory->returned_dirlist = rdent; /* ...and return it */ memset(&directory->returned_entry, 0, sizeof(directory->returned_entry)); directory->returned_entry.name = rdent->name.c_str(); directory->returned_entry.type = ENTTYPE_DIR; result = &directory->returned_entry; } } else { /* a real file */ memset(&directory->returned_entry, 0, sizeof(directory->returned_entry)); directory->returned_entry.name = relpath; directory->returned_entry.type = ENTTYPE_FILE; directory->returned_entry.size = header->uncompressed_length; result = &directory->returned_entry; } } } while((relpath != NULL) && (result == NULL)); } return result; }
void ui_menu_file_selector::handle() { file_error err; const file_selector_entry *entry; const file_selector_entry *selected_entry = NULL; int bestmatch = 0; // process the menu const ui_menu_event *event = process(0); if (event != NULL && event->itemref != NULL) { // handle selections if (event->iptkey == IPT_UI_SELECT) { entry = (const file_selector_entry *) event->itemref; switch(entry->type) { case SELECTOR_ENTRY_TYPE_EMPTY: // empty slot - unload *m_result = R_EMPTY; ui_menu::stack_pop(machine()); break; case SELECTOR_ENTRY_TYPE_CREATE: // create *m_result = R_CREATE; ui_menu::stack_pop(machine()); break; case SELECTOR_ENTRY_TYPE_SOFTWARE_LIST: *m_result = R_SOFTLIST; ui_menu::stack_pop(machine()); break; case SELECTOR_ENTRY_TYPE_DRIVE: case SELECTOR_ENTRY_TYPE_DIRECTORY: // drive/directory - first check the path err = zippath_opendir(entry->fullpath, NULL); if (err != FILERR_NONE) { // this path is problematic; present the user with an error and bail machine().ui().popup_time(1, "Error accessing %s", entry->fullpath); break; } m_current_directory.assign(entry->fullpath); reset((ui_menu_reset_options)0); break; case SELECTOR_ENTRY_TYPE_FILE: // file m_current_file.assign(entry->fullpath); *m_result = R_FILE; ui_menu::stack_pop(machine()); break; } // reset the char buffer when pressing IPT_UI_SELECT if (m_filename_buffer[0] != '\0') memset(m_filename_buffer, '\0', ARRAY_LENGTH(m_filename_buffer)); } else if (event->iptkey == IPT_SPECIAL) { int buflen = strlen(m_filename_buffer); bool update_selected = FALSE; // if it's a backspace and we can handle it, do so if ((event->unichar == 8 || event->unichar == 0x7f) && buflen > 0) { *(char *)utf8_previous_char(&m_filename_buffer[buflen]) = 0; update_selected = TRUE; if (ARRAY_LENGTH(m_filename_buffer) > 0) machine().ui().popup_time(ERROR_MESSAGE_TIME, "%s", m_filename_buffer); } // if it's any other key and we're not maxed out, update else if (event->unichar >= ' ' && event->unichar < 0x7f) { buflen += utf8_from_uchar(&m_filename_buffer[buflen], ARRAY_LENGTH(m_filename_buffer) - buflen, event->unichar); m_filename_buffer[buflen] = 0; update_selected = TRUE; if (ARRAY_LENGTH(m_filename_buffer) > 0) machine().ui().popup_time(ERROR_MESSAGE_TIME, "%s", m_filename_buffer); } if (update_selected) { const file_selector_entry *cur_selected = (const file_selector_entry *)get_selection(); // check for entries which matches our m_filename_buffer: // from current entry to the end for (entry = cur_selected; entry != NULL; entry = entry->next) { if (entry->basename != NULL && m_filename_buffer != NULL) { int match = 0; for (int i = 0; i < ARRAY_LENGTH(m_filename_buffer); i++) { if (core_strnicmp(entry->basename, m_filename_buffer, i) == 0) match = i; } if (match > bestmatch) { bestmatch = match; selected_entry = entry; } } } // and from the first entry to current one for (entry = m_entrylist; entry != cur_selected; entry = entry->next) { if (entry->basename != NULL && m_filename_buffer != NULL) { int match = 0; for (int i = 0; i < ARRAY_LENGTH(m_filename_buffer); i++) { if (core_strnicmp(entry->basename, m_filename_buffer, i) == 0) match = i; } if (match > bestmatch) { bestmatch = match; selected_entry = entry; } } } if (selected_entry != NULL && selected_entry != cur_selected) set_selection((void *) selected_entry); } } else if (event->iptkey == IPT_UI_CANCEL) { // reset the char buffer also in this case if (m_filename_buffer[0] != '\0') memset(m_filename_buffer, '\0', ARRAY_LENGTH(m_filename_buffer)); } } }
void menu_software_list::handle() { const entry_info *selected_entry = nullptr; int bestmatch = 0; // process the menu const event *event = process(0); if (event && event->itemref) { if ((uintptr_t)event->itemref == 1 && event->iptkey == IPT_UI_SELECT) { m_ordered_by_shortname = !m_ordered_by_shortname; // reset the char buffer if we change ordering criterion m_filename_buffer.clear(); // reload the menu with the new order reset(reset_options::REMEMBER_REF); machine().popmessage(_("Switched Order: entries now ordered by %s"), m_ordered_by_shortname ? _("shortname") : _("description")); } // handle selections else if (event->iptkey == IPT_UI_SELECT) { entry_info *info = (entry_info *) event->itemref; m_result = info->short_name; stack_pop(); } else if (event->iptkey == IPT_SPECIAL) { if (input_character(m_filename_buffer, event->unichar, &is_valid_softlist_part_char)) { // display the popup ui().popup_time(ERROR_MESSAGE_TIME, "%s", m_filename_buffer); // identify the selected entry entry_info const *const cur_selected = (uintptr_t(event->itemref) != 1) ? reinterpret_cast<entry_info const *>(get_selection_ref()) : nullptr; // loop through all entries for (auto &entry : m_entrylist) { // is this entry the selected entry? if (cur_selected != &entry) { auto &compare_name = m_ordered_by_shortname ? entry.short_name : entry.long_name; int match = 0; for (int i = 0; i < m_filename_buffer.size() + 1; i++) { if (core_strnicmp(compare_name.c_str(), m_filename_buffer.c_str(), i) == 0) match = i; } if (match > bestmatch) { bestmatch = match; selected_entry = &entry; } } } if (selected_entry != nullptr && selected_entry != cur_selected) { set_selection((void *)selected_entry); centre_selection(); } } } else if (event->iptkey == IPT_UI_CANCEL) { // reset the char buffer also in this case m_filename_buffer.clear(); m_result = m_filename_buffer; stack_pop(); } } }
/************************************************************************** * load_datafile_text * * Loads text field for a driver into the buffer specified. Specify the * driver, a pointer to the buffer, the buffer size, the index created by * index_datafile(), and the desired text field (e.g., DATAFILE_TAG_BIO). * * Returns 0 if successful. **************************************************************************/ static int load_datafile_text(const game_driver *drv, char *buffer, int bufsize, struct tDatafileIndex *idx, const char *tag, int source_file, int mameinfo) { char readbuf[16384]; *buffer = '\0'; if (!source_file) { /* find driver in datafile index */ while (idx->driver) { if (idx->driver == drv) break; idx++; } } else { /* find source file in datafile index */ while (idx->driver) { if (idx->driver->source_file == drv->source_file) break; idx++; } } if (idx->driver == 0) return 1; /* driver not found in index */ /* seek to correct point in datafile */ if (ParseSeek (idx->offset, SEEK_SET)) return 1; /* read text until buffer is full or end of entry is encountered */ while (fgets(readbuf, 16384, fp)) { if (!core_strnicmp(DATAFILE_TAG_END, readbuf, strlen(DATAFILE_TAG_END))) break; if (!core_strnicmp(tag, readbuf, strlen(tag))) continue; if (strlen(buffer) + strlen(readbuf) > bufsize) break; if (mameinfo) { char *temp = strtok(readbuf, "\r\n\r\n"); if (temp != nullptr) strcat(buffer, temp); else strcat(buffer, readbuf); } else strcat(buffer, readbuf); } return 0; }
/************************************************************************** * index_datafile * Create an index for the records in the currently open datafile. * * Returns 0 on error, or the number of index entries created. **************************************************************************/ static int index_datafile(struct tDatafileIndex **_index, int source) { struct tDatafileIndex *idx; int count = 0; char readbuf[512]; char name[40]; int num_games = driver_list::total(); /* rewind file */ if (ParseSeek (0L, SEEK_SET)) return 0; /* allocate index */ idx = *_index = global_alloc_array(tDatafileIndex, (num_games + 1) * sizeof (struct tDatafileIndex)); if (!idx) return 0; while (fgets(readbuf, 512, fp)) { /* DATAFILE_TAG_KEY identifies the driver */ if (!core_strnicmp(DATAFILE_TAG_KEY, readbuf, strlen(DATAFILE_TAG_KEY))) { int game_index = 0; char *curpoint = &readbuf[strlen(DATAFILE_TAG_KEY) + 1]; char *pch = NULL; char *ends = &readbuf[strlen(readbuf) - 1]; while (curpoint < ends) { // search for comma pch = strpbrk(curpoint, ","); // found it if (pch) { // copy data and validate driver int len = pch - curpoint; strncpy(name, curpoint, len); name[len] = '\0'; if (!source) game_index = GetGameNameIndex(name); else game_index = GetSrcDriverIndex(name); if (game_index >= 0) { idx->driver = &driver_list::driver(game_index); idx->offset = ftell(fp); idx++; count++; } // update current point curpoint = pch + 1; } // if comma not found, copy data while until reach the end of string else if (!pch && curpoint < ends) { int len = ends - curpoint; strncpy(name, curpoint, len); name[len] = '\0'; if (!source) game_index = GetGameNameIndex(name); else game_index = GetSrcDriverIndex(name); if (game_index >= 0) { idx->driver = &driver_list::driver(game_index); idx->offset = ftell(fp); idx++; count++; } // update current point curpoint = ends; } } } } /* mark end of index */ idx->offset = 0L; idx->driver = 0; return count; }
void menu_file_selector::handle() { osd_file::error err; const file_selector_entry *selected_entry = nullptr; int bestmatch = 0; // process the menu const event *event = process(0); if (event != nullptr && event->itemref != nullptr) { // handle selections if (event->iptkey == IPT_UI_SELECT) { auto entry = (const file_selector_entry *) event->itemref; switch (entry->type) { case SELECTOR_ENTRY_TYPE_EMPTY: // empty slot - unload m_result = result::EMPTY; stack_pop(); break; case SELECTOR_ENTRY_TYPE_CREATE: // create m_result = result::CREATE; stack_pop(); break; case SELECTOR_ENTRY_TYPE_SOFTWARE_LIST: m_result = result::SOFTLIST; stack_pop(); break; case SELECTOR_ENTRY_TYPE_DRIVE: case SELECTOR_ENTRY_TYPE_DIRECTORY: // drive/directory - first check the path err = util::zippath_opendir(entry->fullpath, nullptr); if (err != osd_file::error::NONE) { // this path is problematic; present the user with an error and bail ui().popup_time(1, "Error accessing %s", entry->fullpath); break; } m_current_directory.assign(entry->fullpath); reset(reset_options::SELECT_FIRST); break; case SELECTOR_ENTRY_TYPE_FILE: // file m_current_file.assign(entry->fullpath); m_result = result::FILE; stack_pop(); break; } // reset the char buffer when pressing IPT_UI_SELECT m_filename.clear(); } else if (event->iptkey == IPT_SPECIAL) { // if it's any other key and we're not maxed out, update if (input_character(m_filename, event->unichar, uchar_is_printable)) { ui().popup_time(ERROR_MESSAGE_TIME, "%s", m_filename.c_str()); file_selector_entry const *const cur_selected(reinterpret_cast<file_selector_entry const *>(get_selection_ref())); // check for entries which matches our m_filename_buffer: for (auto &entry : m_entrylist) { if (cur_selected != &entry) { int match = 0; for (int i = 0; i < m_filename.size() + 1; i++) { if (core_strnicmp(entry.basename.c_str(), m_filename.c_str(), i) == 0) match = i; } if (match > bestmatch) { bestmatch = match; selected_entry = &entry; } } } if (selected_entry != nullptr && selected_entry != cur_selected) { set_selection((void *)selected_entry); centre_selection(); } } } else if (event->iptkey == IPT_UI_CANCEL) { // reset the char buffer also in this case m_filename.clear(); } } }
void ui_menu_add_change_folder::handle() { // process the menu const ui_menu_event *m_event = process(0); if (m_event != nullptr && m_event->itemref != nullptr) { if (m_event->iptkey == IPT_UI_SELECT) { int index = (FPTR)m_event->itemref - 1; const ui_menu_item &pitem = item[index]; // go up to the parent path if (!strcmp(pitem.text, "..")) { size_t first_sep = m_current_path.find_first_of(PATH_SEPARATOR[0]); size_t last_sep = m_current_path.find_last_of(PATH_SEPARATOR[0]); if (first_sep != last_sep) m_current_path.erase(++last_sep); } else { // if isn't a drive, appends the directory if (strcmp(pitem.subtext, "[DRIVE]") != 0) { if (m_current_path[m_current_path.length() - 1] == PATH_SEPARATOR[0]) m_current_path.append(pitem.text); else m_current_path.append(PATH_SEPARATOR).append(pitem.text); } else m_current_path = pitem.text; } // reset the char buffer also in this case if (m_search[0] != 0) m_search[0] = '\0'; reset(UI_MENU_RESET_SELECT_FIRST); } else if (m_event->iptkey == IPT_SPECIAL) { int buflen = strlen(m_search); bool update_selected = FALSE; // if it's a backspace and we can handle it, do so if ((m_event->unichar == 8 || m_event->unichar == 0x7f) && buflen > 0) { *(char *)utf8_previous_char(&m_search[buflen]) = 0; update_selected = TRUE; } // if it's any other key and we're not maxed out, update else if (m_event->unichar >= ' ' && m_event->unichar < 0x7f) { buflen += utf8_from_uchar(&m_search[buflen], ARRAY_LENGTH(m_search) - buflen, m_event->unichar); m_search[buflen] = 0; update_selected = TRUE; } // Tab key, save current path else if (m_event->unichar == 0x09) { std::string error_string; if (m_change) { machine().options().set_value(s_folders_entry[m_ref].option, m_current_path.c_str(), OPTION_PRIORITY_CMDLINE, error_string); machine().datfile().reset_run(); } else { std::string tmppath = std::string(machine().options().value(s_folders_entry[m_ref].option)).append(";").append(m_current_path.c_str()); machine().options().set_value(s_folders_entry[m_ref].option, tmppath.c_str(), OPTION_PRIORITY_CMDLINE, error_string); } ui_menu::menu_stack->parent->reset(UI_MENU_RESET_SELECT_FIRST); ui_menu::stack_pop(machine()); } // check for entries which matches our search buffer if (update_selected) { const int cur_selected = selected; int entry, bestmatch = 0; // from current item to the end for (entry = cur_selected; entry < item.size(); entry++) if (item[entry].ref != nullptr && m_search[0] != 0) { int match = 0; for (int i = 0; i < ARRAY_LENGTH(m_search); i++) { if (core_strnicmp(item[entry].text, m_search, i) == 0) match = i; } if (match > bestmatch) { bestmatch = match; selected = entry; } } // and from the first item to current one for (entry = 0; entry < cur_selected; entry++) { if (item[entry].ref != nullptr && m_search[0] != 0) { int match = 0; for (int i = 0; i < ARRAY_LENGTH(m_search); i++) { if (core_strnicmp(item[entry].text, m_search, i) == 0) match = i; } if (match > bestmatch) { bestmatch = match; selected = entry; } } } } } else if (m_event->iptkey == IPT_UI_CANCEL) { // reset the char buffer also in this case if (m_search[0] != 0) m_search[0] = '\0'; } } }
void menu_add_change_folder::handle() { // process the menu const event *menu_event = process(0); if (menu_event != nullptr && menu_event->itemref != nullptr) { if (menu_event->iptkey == IPT_UI_SELECT) { int index = (uintptr_t)menu_event->itemref - 1; const menu_item &pitem = item[index]; // go up to the parent path if (!strcmp(pitem.text.c_str(), "..")) { size_t first_sep = m_current_path.find_first_of(PATH_SEPARATOR[0]); size_t last_sep = m_current_path.find_last_of(PATH_SEPARATOR[0]); if (first_sep != last_sep) m_current_path.erase(++last_sep); } else { // if isn't a drive, appends the directory if (strcmp(pitem.subtext.c_str(), "[DRIVE]") != 0) { if (m_current_path[m_current_path.length() - 1] == PATH_SEPARATOR[0]) m_current_path.append(pitem.text); else m_current_path.append(PATH_SEPARATOR).append(pitem.text); } else m_current_path = pitem.text; } // reset the char buffer also in this case m_search[0] = '\0'; reset(reset_options::SELECT_FIRST); } else if (menu_event->iptkey == IPT_SPECIAL) { bool update_selected = false; if (menu_event->unichar == 0x09) { // Tab key, save current path std::string error_string; if (m_change) { if (ui().options().exists(s_folders[m_ref].option)) ui().options().set_value(s_folders[m_ref].option, m_current_path.c_str(), OPTION_PRIORITY_CMDLINE, error_string); else if (strcmp(machine().options().value(s_folders[m_ref].option), m_current_path.c_str()) != 0) { machine().options().set_value(s_folders[m_ref].option, m_current_path.c_str(), OPTION_PRIORITY_CMDLINE, error_string); machine().options().mark_changed(s_folders[m_ref].option); } } else { m_folders.push_back(m_current_path); std::string tmppath; for (int x = 0; x < m_folders.size(); ++x) { tmppath.append(m_folders[x]); if (x != m_folders.size() - 1) tmppath.append(";"); } if (ui().options().exists(s_folders[m_ref].option)) ui().options().set_value(s_folders[m_ref].option, tmppath.c_str(), OPTION_PRIORITY_CMDLINE, error_string); else if (strcmp(machine().options().value(s_folders[m_ref].option), tmppath.c_str()) != 0) { machine().options().set_value(s_folders[m_ref].option, tmppath.c_str(), OPTION_PRIORITY_CMDLINE, error_string); machine().options().mark_changed(s_folders[m_ref].option); } } reset_parent(reset_options::SELECT_FIRST); stack_pop(); } else { // if it's any other key and we're not maxed out, update update_selected = input_character(m_search, menu_event->unichar, uchar_is_printable); } // check for entries which matches our search buffer if (update_selected) { const int cur_selected = selected_index(); int entry, bestmatch = 0; // from current item to the end for (entry = cur_selected; entry < item.size(); entry++) if (item[entry].ref != nullptr && !m_search.empty()) { int match = 0; for (int i = 0; i < m_search.size() + 1; i++) { if (core_strnicmp(item[entry].text.c_str(), m_search.data(), i) == 0) match = i; } if (match > bestmatch) { bestmatch = match; selected = entry; } } // and from the first item to current one for (entry = 0; entry < cur_selected; entry++) { if (item[entry].ref != nullptr && !m_search.empty()) { int match = 0; for (int i = 0; i < m_search.size() + 1; i++) { if (core_strnicmp(item[entry].text.c_str(), m_search.data(), i) == 0) match = i; } if (match > bestmatch) { bestmatch = match; selected = entry; } } } centre_selection(); } } else if (menu_event->iptkey == IPT_UI_CANCEL) { // reset the char buffer also in this case m_search.clear(); } } }
void menu_software_list::handle() { const entry_info *entry; const entry_info *selected_entry = nullptr; int bestmatch = 0; // process the menu const event *event = process(0); if (event && event->itemref) { if ((FPTR)event->itemref == 1 && event->iptkey == IPT_UI_SELECT) { m_ordered_by_shortname = !m_ordered_by_shortname; m_entrylist = nullptr; // reset the char buffer if we change ordering criterion memset(m_filename_buffer, '\0', ARRAY_LENGTH(m_filename_buffer)); // reload the menu with the new order reset(reset_options::REMEMBER_REF); machine().popmessage(_("Switched Order: entries now ordered by %s"), m_ordered_by_shortname ? _("shortname") : _("description")); } // handle selections else if (event->iptkey == IPT_UI_SELECT) { entry_info *info = (entry_info *) event->itemref; m_result = info->short_name; menu::stack_pop(machine()); } else if (event->iptkey == IPT_SPECIAL) { auto const buflen = std::strlen(m_filename_buffer); bool update_selected = false; if ((event->unichar == 8) || (event->unichar == 0x7f)) { // if it's a backspace and we can handle it, do so if (0 < buflen) { *const_cast<char *>(utf8_previous_char(&m_filename_buffer[buflen])) = 0; update_selected = true; ui().popup_time(ERROR_MESSAGE_TIME, "%s", m_filename_buffer); } } else if (event->is_char_printable()) { // if it's any other key and we're not maxed out, update if (event->append_char(m_filename_buffer, buflen)) { update_selected = true; ui().popup_time(ERROR_MESSAGE_TIME, "%s", m_filename_buffer); } } if (update_selected) { const entry_info *cur_selected; // if the current selection is a software entry, start search from here if ((FPTR)event->itemref != 1) cur_selected= (const entry_info *)get_selection(); // else (if we are on the 'Switch Order' entry) start from the beginning else cur_selected = m_entrylist; // check for entries which matches our filename_buffer: // from current entry to the end for (entry = cur_selected; entry != nullptr; entry = entry->next) { const char *compare_name = m_ordered_by_shortname ? entry->short_name : entry->long_name; if (compare_name != nullptr && m_filename_buffer != nullptr) { int match = 0; for (int i = 0; i < ARRAY_LENGTH(m_filename_buffer); i++) { if (core_strnicmp(compare_name, m_filename_buffer, i) == 0) match = i; } if (match > bestmatch) { bestmatch = match; selected_entry = entry; } } } // and from the first entry to current one for (entry = m_entrylist; entry != cur_selected; entry = entry->next) { const char *compare_name = m_ordered_by_shortname ? entry->short_name : entry->long_name; if (compare_name != nullptr && m_filename_buffer != nullptr) { int match = 0; for (int i = 0; i < ARRAY_LENGTH(m_filename_buffer); i++) { if (core_strnicmp(compare_name, m_filename_buffer, i) == 0) match = i; } if (match > bestmatch) { bestmatch = match; selected_entry = entry; } } } if (selected_entry != nullptr && selected_entry != cur_selected) { set_selection((void *)selected_entry); top_line = selected - (visible_lines / 2); } } } else if (event->iptkey == IPT_UI_CANCEL) { // reset the char buffer also in this case if (m_filename_buffer[0] != '\0') memset(m_filename_buffer, '\0', ARRAY_LENGTH(m_filename_buffer)); m_result = m_filename_buffer; menu::stack_pop(machine()); } } }