39 #if COMPONENT_LASERDISC
65 virtual void parseOption(
const string& option, deque<string>& cmdLine);
75 virtual void parseOption(
const string& option, deque<string>& cmdLine);
85 virtual void parseOption(
const string& option, deque<string>& cmdLine);
95 virtual void parseOption(
const string& option, deque<string>& cmdLine);
97 virtual void parseFileType(
const std::string& filename,
98 std::deque<std::string>& cmdLine);
109 virtual void parseOption(
const string& option, deque<string>& cmdLine);
119 virtual void parseOption(
const string& option, deque<string>& cmdLine);
128 virtual void parseOption(
const string& option, deque<string>& cmdLine);
134 virtual void parseOption(
const string& option, deque<string>& cmdLine);
140 virtual void parseOption(
const string& option, deque<string>& cmdLine);
146 virtual void parseOption(
const string& option, deque<string>& cmdLine);
154 virtual void parseOption(
const string& option, deque<string>& cmdLine);
164 virtual void parseOption(
const string& option, deque<string>& cmdLine);
173 CommandLineParser::CommandLineParser(
Reactor& reactor_)
198 , parseStatus(UNPARSED)
201 haveSettings =
false;
236 temp.option = &cliOption;
238 temp.length = length;
239 optionMap[str] = temp;
245 fileClassMap[str] = &cliFileType;
248 void CommandLineParser::registerFileTypes()
250 map<string, string> fileExtMap;
251 fileExtMap[
"rom"] =
"romimage";
252 fileExtMap[
"ri"] =
"romimage";
253 fileExtMap[
"dsk"] =
"diskimage";
254 fileExtMap[
"dmk"] =
"diskimage";
255 fileExtMap[
"di1"] =
"diskimage";
256 fileExtMap[
"di2"] =
"diskimage";
257 fileExtMap[
"xsa"] =
"diskimage";
258 fileExtMap[
"wav"] =
"cassetteimage";
259 fileExtMap[
"cas"] =
"cassetteimage";
260 fileExtMap[
"ogv"] =
"laserdiscimage";
261 fileExtMap[
"omr"] =
"openMSX replay";
262 fileExtMap[
"oms"] =
"openMSX savestate";
263 fileExtMap[
"tcl"] =
"Tcl script";
264 for (
auto& p : fileExtMap) {
265 auto i = fileClassMap.find(p.second);
266 if (i != fileClassMap.end()) {
267 fileTypeMap[p.first] = i->second;
272 bool CommandLineParser::parseOption(
273 const string& arg, deque<string>& cmdLine, ParsePhase phase)
275 auto it1 = optionMap.find(arg);
276 if (it1 != optionMap.end()) {
278 if (it1->second.phase <= phase) {
280 it1->second.option->parseOption(arg, cmdLine);
282 }
catch (MSXException& e) {
283 throw FatalError(e.getMessage());
290 bool CommandLineParser::parseFileName(
const string& arg, deque<string>& cmdLine)
297 bool processed = parseFileNameInner(arg, arg, cmdLine);
300 File file(UserFileContext().resolve(arg));
301 string originalName = file.getOriginalName();
302 processed = parseFileNameInner(originalName, arg, cmdLine);
303 }
catch (FileException&) {
310 bool CommandLineParser::parseFileNameInner(
const string& name,
const string& originalPath, deque<string>& cmdLine)
313 if (!extension.
empty()) {
315 auto it = fileTypeMap.find(extension.
str());
316 if (it != fileTypeMap.end()) {
319 it->second->parseFileType(originalPath, cmdLine);
321 }
catch (MSXException& e) {
322 throw FatalError(e.getMessage());
333 deque<string> cmdLine;
334 deque<string> backupCmdLine;
335 for (
auto i :
xrange(1, argc)) {
356 auto& settingsConfig =
361 string filename =
"settings.xml";
363 settingsConfig.loadSetting(context, filename);
366 "Loading of settings failed: " +
368 "Reverting to default settings.");
372 throw FatalError(
"Error in default settings: "
379 settingsConfig.setSaveFilename(context, filename);
385 const auto& machine =
391 "Failed to initialize default machine: " + e.
getMessage());
393 const auto& fallbackMachine =
409 while (!cmdLine.empty()) {
410 string arg = std::move(cmdLine.front());
413 if (!parseOption(arg, cmdLine, phase)) {
416 !parseFileName(arg, cmdLine)) {
418 backupCmdLine.push_back(arg);
419 auto it1 = optionMap.find(arg);
420 if (it1 != optionMap.end()) {
421 for (
unsigned i = 0; i < it1->second.length - 1; ++i) {
422 if (!cmdLine.empty()) {
423 backupCmdLine.push_back(std::move(cmdLine.front()));
431 cmdLine = backupCmdLine;
432 backupCmdLine.clear();
436 if (!cmdLine.empty() && (parseStatus !=
EXIT)) {
438 "Error parsing command line: " + cmdLine.front() +
"\n" +
439 "Use \"openmsx -h\" to see a list of available options" );
442 hiddenStartup = (parseStatus ==
CONTROL || parseStatus ==
TEST );
447 return hiddenStartup;
458 return scriptOption->getScripts();
481 const auto& fullType =
getArgument(option, cmdLine);
488 std::unique_ptr<CliListener> connection;
489 if (type ==
"stdio") {
490 connection = make_unique<StdioConnection>(
491 controller, distributor);
493 }
else if (type ==
"pipe") {
495 info.dwOSVersionInfoSize =
sizeof(info);
497 if (info.dwPlatformId == VER_PLATFORM_WIN32_NT) {
498 connection = make_unique<PipeConnection>(
499 controller, distributor, arguments);
501 throw FatalError(
"Pipes are not supported on this "
502 "version of Windows");
506 throw FatalError(
"Unknown control type: '" + type +
'\'');
508 cliComm.addListener(connection.release());
515 return "Enable external control of openMSX process";
533 return "Run extra startup script";
537 deque<std::string>& )
539 scripts.push_back(filename);
544 return "Extra Tcl script to run at startup";
549 static string formatSet(
const set<string>& inputSet, string::size_type columns)
552 string::size_type totalLength = 0;
553 for (
auto& temp : inputSet) {
554 if (totalLength == 0) {
556 outString <<
" " << temp;
557 totalLength = temp.size();
560 if ((totalLength + temp.size()) > columns) {
561 outString <<
"\n " << temp;
562 totalLength = temp.size();
565 totalLength += 2 + temp.size();
569 if (totalLength < columns) {
570 outString << string(columns - totalLength,
' ');
575 static string formatHelptext(
string_ref helpText,
576 unsigned maxLength,
unsigned indent)
580 while (helpText.
substr(index).
size() > maxLength) {
581 auto pos = helpText.
substr(index, maxLength).
rfind(
' ');
588 outText += helpText.
substr(index, index + pos) +
'\n' +
597 static void printItemMap(
const StringMap<set<string>>& itemMap)
599 set<string> printSet;
600 for (
auto& p : itemMap) {
601 printSet.insert(formatSet(p.second, 15) +
' ' +
602 formatHelptext(p.first(), 50, 20));
604 for (
auto& s : printSet) {
618 cout << fullVersion << endl;
619 cout << string(fullVersion.size(),
'=') << endl;
621 cout <<
"usage: openmsx [arguments]" << endl;
622 cout <<
" an argument is either an option or a filename" << endl;
624 cout <<
" this is the list of supported options:" << endl;
627 for (
auto& p : parser.optionMap) {
628 const auto& helpText = p.second.option->optionHelp();
629 if (!helpText.
empty()) {
630 optionMap[helpText].
insert(p.first);
633 printItemMap(optionMap);
636 cout <<
" this is the list of supported file types:" << endl;
639 for (
auto& p : parser.fileTypeMap) {
640 extMap[p.second->fileTypeHelp()].
insert(p.first);
642 printItemMap(extMap);
649 return "Shows this text";
664 cout <<
"flavour: " << BUILD_FLAVOUR << endl;
665 cout <<
"components: " << BUILD_COMPONENTS << endl;
671 return "Prints openMSX version and exits";
684 if (parser.haveConfig) {
685 throw FatalError(
"Only one machine option allowed");
692 parser.haveConfig =
true;
696 return "Use machine specified in argument";
709 if (parser.haveSettings) {
710 throw FatalError(
"Only one setting option allowed");
716 parser.haveSettings =
true;
726 return "Load an alternative settings file";
735 cout <<
"Disabling MMX" << endl;
741 return "Disables usage of MMX, SSE and SSE2 (for debugging)";
750 cout <<
"Disabling SSE" << endl;
756 return "Disables usage of SSE and SSE2 (for debugging)";
765 cout <<
"Disabling SSE2" << endl;
771 return "Disables usage of SSE2 (for debugging)";
781 cout <<
"Disabling PBO" << endl;
788 return "Disables usage of openGL PBO (for debugging)";
807 return "Test if the specified config works and exit";
818 deque<string>& cmdLine)
820 string last = cmdLine.empty() ?
"" : cmdLine.front();
823 vector<string> items;
824 if (last ==
"-machine") {
826 }
else if (last ==
"-ext") {
828 }
else if (last ==
"-romtype") {
831 for (
auto& p : parser.optionMap) {
832 items.push_back(p.first);
835 for (
auto& s : items) {