// <s> can be: // * "loadonly" // * description of page ranges e.g. "1", "1-5", "2-3,6,8-10" bool IsBenchPagesInfo(const TCHAR *s) { return str::EqI(s, _T("loadonly")) || IsValidPageRange(s); }
/* parse argument list. we assume that all unrecognized arguments are file names. */ void CommandLineInfo::ParseCommandLine(const WCHAR* cmdLine) { WStrVec argList; ParseCmdLine(cmdLine, argList); size_t argCount = argList.size(); #define is_arg_with_param(_argNo) (param && _argNo == arg) #define additional_param() argList.at(n + 1) #define has_additional_param() ((argCount > n + 1) && ('-' != additional_param()[0])) #define handle_string_param(name) name.SetCopy(argList.at(++n)) #define handle_int_param(name) name = _wtoi(argList.at(++n)) for (size_t n = 1; n < argCount; n++) { WCHAR* argName = argList.at(n); int arg = GetArgNo(argName); WCHAR* param = nullptr; if (argCount > n + 1) { param = argList.at(n + 1); } if (RegisterForPdf == arg) { makeDefault = true; exitImmediately = true; return; } else if (Silent == arg) { // silences errors happening during -print-to and -print-to-default silent = true; } else if (PrintToDefault == arg) { printerName.Set(GetDefaultPrinterName()); if (!printerName) printDialog = true; exitWhenDone = true; } else if (is_arg_with_param(PrintTo)) { handle_string_param(printerName); exitWhenDone = true; } else if (PrintDialog == arg) { printDialog = true; } else if (is_arg_with_param(PrintSettings)) { // argument is a comma separated list of page ranges and // advanced options [even|odd], [noscale|shrink|fit] and [autorotation|portrait|landscape] // e.g. -print-settings "1-3,5,10-8,odd,fit" handle_string_param(printSettings); str::RemoveChars(printSettings, L" "); str::TransChars(printSettings, L";", L","); } else if (ExitWhenDone == arg || ExitOnPrint == arg) { // only affects -print-dialog (-print-to and -print-to-default // always exit on print) and -stress-test (useful for profiling) exitWhenDone = true; } else if (is_arg_with_param(InverseSearch)) { inverseSearchCmdLine.SetCopy(argList.at(++n)); } else if ((is_arg_with_param(ForwardSearch) || is_arg_with_param(FwdSearch)) && argCount > n + 2) { // -forward-search is for consistency with -inverse-search // -fwdsearch is for consistency with -fwdsearch-* handle_string_param(forwardSearchOrigin); handle_int_param(forwardSearchLine); } else if (is_arg_with_param(NamedDest) || is_arg_with_param(NamedDest2)) { // -nameddest is for backwards compat (was used pre-1.3) // -named-dest is for consistency handle_string_param(destName); } else if (is_arg_with_param(Page)) { handle_int_param(pageNumber); } else if (Restrict == arg) { restrictedUse = true; } else if (InvertColors1 == arg || InvertColors2 == arg) { // -invertcolors is for backwards compat (was used pre-1.3) // -invert-colors is for consistency // -invert-colors used to be a shortcut for -set-color-range 0xFFFFFF 0x000000 // now it non-permanently swaps textColor and backgroundColor invertColors = true; } else if (Presentation == arg) { enterPresentation = true; } else if (Fullscreen == arg) { enterFullScreen = true; } else if (is_arg_with_param(View)) { ParseViewMode(&startView, param); ++n; } else if (is_arg_with_param(Zoom)) { ParseZoomValue(&startZoom, param); ++n; } else if (is_arg_with_param(Scroll)) { ParseScrollValue(&startScroll, param); ++n; } else if (Console == arg) { showConsole = true; } else if (is_arg_with_param(AppData)) { appdataDir.SetCopy(param); ++n; } else if (is_arg_with_param(Plugin)) { // -plugin [<URL>] <parent HWND> if (argCount > n + 2 && !str::IsDigit(*argList.at(n + 1)) && *argList.at(n + 2) != '-') handle_string_param(pluginURL); // the argument is a (numeric) window handle to // become the parent of a frameless SumatraPDF // (used e.g. for embedding it into a browser plugin) hwndPluginParent = (HWND)(INT_PTR)_wtol(argList.at(++n)); } else if (is_arg_with_param(StressTest)) { // -stress-test <file or dir path> [<file filter>] [<page/file range(s)>] [<cycle // count>x] // e.g. -stress-test file.pdf 25x for rendering file.pdf 25 times // -stress-test file.pdf 1-3 render only pages 1, 2 and 3 of file.pdf // -stress-test dir 301- 2x render all files in dir twice, skipping first 300 // -stress-test dir *.pdf;*.xps render all files in dir that are either PDF or XPS handle_string_param(stressTestPath); int num; if (has_additional_param() && str::FindChar(additional_param(), '*')) handle_string_param(stressTestFilter); if (has_additional_param() && IsValidPageRange(additional_param())) handle_string_param(stressTestRanges); if (has_additional_param() && str::Parse(additional_param(), L"%dx%$", &num) && num > 0) { stressTestCycles = num; n++; } } else if (is_arg_with_param(ArgN)) { handle_int_param(stressParallelCount); } else if (is_arg_with_param(Render)) { handle_int_param(pageNumber); testRenderPage = true; } else if (is_arg_with_param(ExtractText)) { handle_int_param(pageNumber); testExtractPage = true; } else if (Rand == arg) { stressRandomizeFiles = true; } else if (is_arg_with_param(Bench)) { WCHAR* s = str::Dup(param); ++n; pathsToBenchmark.Push(s); s = nullptr; if (has_additional_param() && IsBenchPagesInfo(additional_param())) { s = str::Dup(argList.at(++n)); } pathsToBenchmark.Push(s); exitImmediately = true; } else if (CrashOnOpen == arg) { // to make testing of crash reporting system in pre-release/release // builds possible crashOnOpen = true; } else if (ReuseInstance == arg) { // for backwards compatibility, -reuse-instance reuses whatever // instance has registered as DDE server reuseDdeInstance = true; } // TODO: remove the following deprecated options within a release or two else if (is_arg_with_param(Lang)) { auto tmp = str::conv::ToAnsi(param); lang.Set(tmp.StealData()); ++n; } else if (EscToExit == arg) { globalPrefArgs.Append(str::Dup(argList.at(n))); } else if (is_arg_with_param(BgColor) || is_arg_with_param(BgColor2) || is_arg_with_param(FwdSearchOffset) || is_arg_with_param(FwdSearchWidth) || is_arg_with_param(FwdSearchColor) || is_arg_with_param(FwdSearchPermanent) || is_arg_with_param(MangaMode)) { globalPrefArgs.Append(str::Dup(argList.at(n))); globalPrefArgs.Append(str::Dup(argList.at(++n))); } else if (SetColorRange == arg && argCount > n + 2) { globalPrefArgs.Append(str::Dup(argList.at(n))); globalPrefArgs.Append(str::Dup(argList.at(++n))); globalPrefArgs.Append(str::Dup(argList.at(++n))); } #ifdef DEBUG else if (ArgEnumPrinters == arg) { EnumeratePrinters(); /* this is for testing only, exit immediately */ exitImmediately = true; return; } #endif // this should have been handled already by AutoUpdateMain else if (is_arg_with_param(AutoUpdate)) { n++; } else { // Remember this argument as a filename to open WCHAR* filePath = nullptr; if (str::EndsWithI(argName, L".lnk")) filePath = ResolveLnk(argName); if (!filePath) filePath = str::Dup(argName); fileNames.Push(filePath); } } #undef is_arg_with_param #undef additional_param #undef has_additional_param #undef handle_string_param #undef handle_int_param }
/* parse argument list. we assume that all unrecognized arguments are file names. */ void CommandLineInfo::ParseCommandLine(const WCHAR *cmdLine) { WStrVec argList; ParseCmdLine(cmdLine, argList); size_t argCount = argList.Count(); #define is_arg(txt) str::EqI(TEXT(txt), argument) #define is_arg_with_param(txt) (is_arg(txt) && (argCount > n + 1)) #define additional_param() argList.At(n + 1) #define has_additional_param() ((argCount > n + 1) && ('-' != additional_param()[0])) #define handle_string_param(name) name.Set(str::Dup(argList.At(++n))) #define handle_int_param(name) name = _wtoi(argList.At(++n)) for (size_t n = 1; n < argCount; n++) { WCHAR *argument = argList.At(n); if (is_arg("-register-for-pdf")) { makeDefault = true; exitImmediately = true; return; } else if (is_arg("-silent")) { // silences errors happening during -print-to and -print-to-default silent = true; } else if (is_arg("-print-to-default")) { printerName.Set(GetDefaultPrinterName()); if (!printerName) printDialog = true; exitWhenDone = true; } else if (is_arg_with_param("-print-to")) { handle_string_param(printerName); exitWhenDone = true; } else if (is_arg("-print-dialog")) { printDialog = true; } else if (is_arg_with_param("-print-settings")) { // argument is a comma separated list of page ranges and // advanced options [even|odd] and [noscale|shrink|fit] // e.g. -print-settings "1-3,5,10-8,odd,fit" handle_string_param(printSettings); str::RemoveChars(printSettings, L" "); str::TransChars(printSettings, L";", L","); } else if (is_arg("-exit-when-done") || is_arg("-exit-on-print")) { // only affects -print-dialog (-print-to and -print-to-default // always exit on print) and -stress-test (useful for profiling) exitWhenDone = true; } else if (is_arg_with_param("-inverse-search")) { str::ReplacePtr(&gGlobalPrefs->inverseSearchCmdLine, argList.At(++n)); gGlobalPrefs->enableTeXEnhancements = true; } else if ((is_arg_with_param("-forward-search") || is_arg_with_param("-fwdsearch")) && argCount > n + 2) { // -forward-search is for consistency with -inverse-search // -fwdsearch is for consistency with -fwdsearch-* handle_string_param(forwardSearchOrigin); handle_int_param(forwardSearchLine); } else if (is_arg_with_param("-nameddest") || is_arg_with_param("-named-dest")) { // -nameddest is for backwards compat (was used pre-1.3) // -named-dest is for consistency handle_string_param(destName); } else if (is_arg_with_param("-page")) { handle_int_param(pageNumber); } else if (is_arg("-restrict")) { restrictedUse = true; } else if (is_arg("-invertcolors") || is_arg("-invert-colors")) { // -invertcolors is for backwards compat (was used pre-1.3) // -invert-colors is for consistency // -invert-colors used to be a shortcut for -set-color-range 0xFFFFFF 0x000000 // now it non-permanently swaps textColor and backgroundColor gGlobalPrefs->fixedPageUI.invertColors = true; } else if (is_arg("-presentation")) { enterPresentation = true; } else if (is_arg("-fullscreen")) { enterFullScreen = true; } else if (is_arg_with_param("-view")) { ParseViewMode(&startView, argList.At(++n)); } else if (is_arg_with_param("-zoom")) { ParseZoomValue(&startZoom, argList.At(++n)); } else if (is_arg_with_param("-scroll")) { ParseScrollValue(&startScroll, argList.At(++n)); } else if (is_arg("-console")) { showConsole = true; } else if (is_arg_with_param("-plugin")) { // -plugin [<URL>] <parent HWND> if (argCount > n + 2 && !str::IsDigit(*argList.At(n + 1)) && *argList.At(n + 2) != '-') handle_string_param(pluginURL); // the argument is a (numeric) window handle to // become the parent of a frameless SumatraPDF // (used e.g. for embedding it into a browser plugin) hwndPluginParent = (HWND)_wtol(argList.At(++n)); } else if (is_arg_with_param("-stress-test")) { // -stress-test <file or dir path> [<file filter>] [<page/file range(s)>] [<cycle count>x] // e.g. -stress-test file.pdf 25x for rendering file.pdf 25 times // -stress-test file.pdf 1-3 render only pages 1, 2 and 3 of file.pdf // -stress-test dir 301- 2x render all files in dir twice, skipping first 300 // -stress-test dir *.pdf;*.xps render all files in dir that are either PDF or XPS handle_string_param(stressTestPath); int num; if (has_additional_param() && str::FindChar(additional_param(), '*')) handle_string_param(stressTestFilter); if (has_additional_param() && IsValidPageRange(additional_param())) handle_string_param(stressTestRanges); if (has_additional_param() && str::Parse(additional_param(), L"%dx%$", &num) && num > 0) { stressTestCycles = num; n++; } } else if (is_arg_with_param("-n")) { handle_int_param(stressParallelCount); } else if (is_arg("-rand")) { stressRandomizeFiles = true; } else if (is_arg_with_param("-bench")) { WCHAR *s = str::Dup(argList.At(++n)); pathsToBenchmark.Push(s); s = NULL; if (has_additional_param() && IsBenchPagesInfo(additional_param())) { s = str::Dup(argList.At(++n)); } pathsToBenchmark.Push(s); exitImmediately = true; } else if (is_arg("-crash-on-open")) { // to make testing of crash reporting system in pre-release/release // builds possible crashOnOpen = true; } else if (is_arg("-reuse-instance")) { // for backwards compatibility, -reuse-instance reuses whatever // instance has registered as DDE server reuseDdeInstance = true; } // TODO: remove the following deprecated options within a release or two else if (is_arg("-esc-to-exit")) { gGlobalPrefs->escToExit = true; } else if (is_arg_with_param("-bgcolor") || is_arg_with_param("-bg-color")) { // -bgcolor is for backwards compat (was used pre-1.3) // -bg-color is for consistency ParseColor(&gGlobalPrefs->mainWindowBackground, argList.At(++n)); } else if (is_arg_with_param("-lang")) { lang.Set(str::conv::ToAnsi(argList.At(++n))); } else if (is_arg("-set-color-range") && argCount > n + 2) { ParseColor(&gGlobalPrefs->fixedPageUI.textColor, argList.At(++n)); ParseColor(&gGlobalPrefs->fixedPageUI.backgroundColor, argList.At(++n)); } else if (is_arg_with_param("-fwdsearch-offset")) { handle_int_param(gGlobalPrefs->forwardSearch.highlightOffset); gGlobalPrefs->enableTeXEnhancements = true; } else if (is_arg_with_param("-fwdsearch-width")) { handle_int_param(gGlobalPrefs->forwardSearch.highlightWidth); gGlobalPrefs->enableTeXEnhancements = true; } else if (is_arg_with_param("-fwdsearch-color")) { ParseColor(&gGlobalPrefs->forwardSearch.highlightColor, argList.At(++n)); gGlobalPrefs->enableTeXEnhancements = true; } else if (is_arg_with_param("-fwdsearch-permanent")) { handle_int_param(gGlobalPrefs->forwardSearch.highlightPermanent); gGlobalPrefs->enableTeXEnhancements = true; } else if (is_arg_with_param("-manga-mode")) { const WCHAR *s = argList.At(++n); gGlobalPrefs->comicBookUI.cbxMangaMode = str::EqI(L"true", s) || str::Eq(L"1", s); } #if defined(SUPPORTS_AUTO_UPDATE) || defined(DEBUG) else if (is_arg_with_param("-autoupdate")) { n++; // this should have been handled already by AutoUpdateMain } #endif #ifdef DEBUG else if (is_arg("-enum-printers")) { EnumeratePrinters(); /* this is for testing only, exit immediately */ exitImmediately = true; return; } #endif else { // Remember this argument as a filename to open WCHAR *filePath = NULL; if (str::EndsWithI(argList.At(n), L".lnk")) filePath = ResolveLnk(argList.At(n)); if (!filePath) filePath = str::Dup(argList.At(n)); fileNames.Push(filePath); } } #undef is_arg #undef is_arg_with_param #undef additional_param #undef has_additional_param #undef handle_string_param #undef handle_int_param }
/* parse argument list. we assume that all unrecognized arguments are file names. */ void CommandLineInfo::ParseCommandLine(WCHAR *cmdLine) { WStrVec argList; ParseCmdLine(cmdLine, argList); size_t argCount = argList.Count(); #define is_arg(txt) str::EqI(TEXT(txt), argument) #define is_arg_with_param(txt) (is_arg(txt) && param != NULL) #define additional_param() argList.At(n + 1) #define has_additional_param() ((argCount > n + 1) && ('-' != additional_param()[0])) for (size_t n = 1; n < argCount; n++) { WCHAR *argument = argList.At(n); WCHAR *param = NULL; if (argCount > n + 1) param = argList.At(n + 1); if (is_arg("-register-for-pdf")) { makeDefault = true; exitImmediately = true; return; } else if (is_arg("-silent")) { // silences errors happening during -print-to and -print-to-default silent = true; } else if (is_arg("-print-to-default")) { WCHAR *name = GetDefaultPrinterName(); if (name) { str::ReplacePtr(&printerName, name); free(name); } exitWhenDone = true; } else if (is_arg_with_param("-print-to")) { str::ReplacePtr(&printerName, argList.At(++n)); exitWhenDone = true; } else if (is_arg("-print-dialog")) { printDialog = true; } else if (is_arg_with_param("-print-settings")) { // argument is a comma separated list of page ranges and // advanced options [even|odd] and [noscale|shrink|fit] // e.g. -print-settings "1-3,5,10-8,odd,fit" str::ReplacePtr(&printSettings, argList.At(++n)); str::RemoveChars(printSettings, L" "); } else if (is_arg("-exit-when-done") || is_arg("-exit-on-print")) { // only affects -print-dialog (-print-to and -print-to-default // always exit on print) and -stress-test (useful for profiling) exitWhenDone = true; } else if (is_arg_with_param("-bgcolor") || is_arg_with_param("-bg-color")) { // -bgcolor is for backwards compat (was used pre-1.3) // -bg-color is for consistency ParseColor(&bgColor, argList.At(++n)); } else if (is_arg_with_param("-inverse-search")) { str::ReplacePtr(&inverseSearchCmdLine, argList.At(++n)); } else if ((is_arg_with_param("-forward-search") || is_arg_with_param("-fwdsearch")) && argCount > n + 2) { // -forward-search is for consistency with -inverse-search // -fwdsearch is for consistency with -fwdsearch-* str::ReplacePtr(&forwardSearchOrigin, argList.At(++n)); forwardSearchLine = _wtoi(argList.At(++n)); } else if (is_arg_with_param("-fwdsearch-offset")) { fwdSearch.offset = _wtoi(argList.At(++n)); } else if (is_arg_with_param("-fwdsearch-width")) { fwdSearch.width = _wtoi(argList.At(++n)); } else if (is_arg_with_param("-fwdsearch-color")) { ParseColor(&fwdSearch.color, argList.At(++n)); } else if (is_arg_with_param("-fwdsearch-permanent")) { fwdSearch.permanent = _wtoi(argList.At(++n)); } else if (is_arg("-esc-to-exit")) { escToExit = true; } else if (is_arg("-reuse-instance")) { // find the window handle of a running instance of SumatraPDF // TODO: there should be a mutex here to reduce possibility of // race condition and having more than one copy launch because // FindWindow() in one process is called before a window is created // in another process reuseInstance = (FindWindow(FRAME_CLASS_NAME, 0) != NULL); } else if (is_arg_with_param("-lang")) { free(lang); lang = str::conv::ToAnsi(argList.At(++n)); } else if (is_arg_with_param("-nameddest") || is_arg_with_param("-named-dest")) { // -nameddest is for backwards compat (was used pre-1.3) // -named-dest is for consistency str::ReplacePtr(&destName, argList.At(++n)); } else if (is_arg_with_param("-page")) { pageNumber = _wtoi(argList.At(++n)); } else if (is_arg("-restrict")) { restrictedUse = true; } // TODO: remove -invert-colors and -set-color-range in favor // of the UI settable gGlobalPrefs.useSysColors(?) else if (is_arg("-invertcolors") || is_arg("-invert-colors")) { // -invertcolors is for backwards compat (was used pre-1.3) // -invert-colors is for consistency // -invert-colors is a shortcut for -set-color-range 0xFFFFFF 0x000000 // (i.e. it sets white as foreground color and black as background color) colorRange[0] = WIN_COL_WHITE; colorRange[1] = WIN_COL_BLACK; } else if (is_arg("-set-color-range") && argCount > n + 2) { STATIC_ASSERT(sizeof(colorRange[0]) == sizeof(int), colorref_as_int); ParseColor((int *)&colorRange[0], argList.At(++n)); ParseColor((int *)&colorRange[1], argList.At(++n)); } else if (is_arg("-presentation")) { enterPresentation = true; } else if (is_arg("-fullscreen")) { enterFullscreen = true; } else if (is_arg_with_param("-view")) { ParseViewMode(&startView, argList.At(++n)); } else if (is_arg_with_param("-zoom")) { ParseZoomValue(&startZoom, argList.At(++n)); } else if (is_arg_with_param("-scroll")) { ParseScrollValue(&startScroll, argList.At(++n)); } else if (is_arg("-console")) { showConsole = true; } else if (is_arg_with_param("-plugin")) { // -plugin [<URL>] <parent HWND> if (!str::IsDigit(*param) && has_additional_param()) str::ReplacePtr(&pluginURL, argList.At(++n)); // the argument is a (numeric) window handle to // become the parent of a frameless SumatraPDF // (used e.g. for embedding it into a browser plugin) hwndPluginParent = (HWND)_wtol(argList.At(++n)); } else if (is_arg_with_param("-stress-test")) { // -stress-test <file or dir path> [<file filter>] [<page/file range(s)>] [<cycle count>x] // e.g. -stress-test file.pdf 25x for rendering file.pdf 25 times // -stress-test file.pdf 1-3 render only pages 1, 2 and 3 of file.pdf // -stress-test dir 301- 2x render all files in dir twice, skipping first 300 // -stress-test dir *.pdf;*.xps render all files in dir that are either PDF or XPS str::ReplacePtr(&stressTestPath, argList.At(++n)); int num; if (has_additional_param() && str::FindChar(additional_param(), '*')) { str::ReplacePtr(&stressTestFilter, additional_param()); n++; } if (has_additional_param() && IsValidPageRange(additional_param())) { str::ReplacePtr(&stressTestRanges, additional_param()); n++; } if (has_additional_param() && str::Parse(additional_param(), L"%dx%$", &num) && num > 0) { stressTestCycles = num; n++; } } else if (is_arg_with_param("-n")) { stressParallelCount = _wtoi(argList.At(++n)); } else if (is_arg("-rand")) { stressRandomizeFiles = true; } else if (is_arg_with_param("-bench")) { WCHAR *s = str::Dup(argList.At(++n)); pathsToBenchmark.Push(s); s = NULL; if (has_additional_param() && IsBenchPagesInfo(additional_param())) { s = str::Dup(additional_param()); n++; } pathsToBenchmark.Push(s); exitImmediately = true; } else if (is_arg("-crash-on-open")) { // to make testing of crash reporting system in pre-release/release // builds possible crashOnOpen = true; } else if (is_arg_with_param("-manga-mode")) { // TODO: we should have a ui for this instead of remembering it globally // in prefs WCHAR *s = argList.At(++n); cbxR2L = str::EqI(L"true", s) || str::Eq(L"1", s); } #if defined(SUPPORTS_AUTO_UPDATE) || defined(DEBUG) else if (is_arg_with_param("-autoupdate")) { n++; // this should have been handled already by AutoUpdateMain } #endif #ifdef DEBUG else if (is_arg("-enum-printers")) { EnumeratePrinters(); /* this is for testing only, exit immediately */ exitImmediately = true; return; } #endif else { // Remember this argument as a filename to open WCHAR *filePath = NULL; if (str::EndsWithI(argList.At(n), L".lnk")) filePath = ResolveLnk(argList.At(n)); if (!filePath) filePath = str::Dup(argList.At(n)); fileNames.Push(filePath); } } #undef is_arg #undef is_arg_with_param #undef additional_param #undef has_additional_param }