// Sets properties from command line args. May set ErrorMessage. private static void ParseArgs() { string[] args = ArgParserTX.GetArgs(keepQuotes: false); foreach (string arg in args) { Log.Debug("Got argument: ", arg); // Arguments that start with - or / are switches. // Others are "non-switches". char switchFlag = arg[0]; if (switchFlag == '-' || switchFlag == '/') { // The arg is a switch. // Switches can be bare such as "-switchpart" or have values such as "-switchpart:valuepart". // ParseSwitch() checks the syntax of the switch argument and sets switchPart // and valuePart. If the syntax is incorrect, ParseSwitch() returns false and sets // msg to an error message. string switchPart; string valuePart; string msg; if (ArgParserTX.ParseSwitch(arg, out switchPart, out valuePart, out msg)) { switch (switchPart.ToLower()) { case "?": case "h": case "help": SetBool(ref _isHelpWanted, switchPart, valuePart); break; case "i": case "install": SetBool(ref _isInstall, switchPart, valuePart); break; case "u": case "uninstall": SetBool(ref _isUninstall, switchPart, valuePart); break; case "c": case "console": SetBool(ref _isConsoleApp, switchPart, valuePart); break; case "impersonate": SetBool(ref _isImpersonate, switchPart, valuePart); break; case "p": case "port": SetInt(ref _port, switchPart, valuePart); break; case "r": case "retry": SetInt(ref _retryInterval, switchPart, valuePart); break; default: SetError("Unrecognized switch: {0}{1}".Fmt(switchFlag, switchPart)); break; } // switch (switchPart) } // Valid switch format else { // Some fundamental error in the format of a "-switch:value" pair // such as the presence of "-switch:" with no value. SetError(msg); } } // Found switch arg else { // It's a non-switch. SetError("The following argument is not a switch and is therefore invalid.\n{0}".Fmt(arg)); } } // foreach arg }
// Parses the command line and sets public fields/properties including IsHelpWanted and ErrorMessage. // If canDisplayMsg is true, a message box will be displayed if an error is found or the -help switch is found. // Otherwise, the caller should display any error found and/or call ShowHelp(). // Returns true if no error was found, false if the ErrorMessage property was set. public static bool ParseCommandLine(bool canDisplayMsg) { using (Log.InfoCall()) { string[] args = ArgParserTX.GetArgs(keepQuotes: false); foreach (string arg in args) { Log.Debug("Got argument: ", arg); // Arguments that start with - or / are switches. // Others are "non-switches". char switchFlag = arg[0]; if (switchFlag == '-' || switchFlag == '/') { // It's a switch. // In general switches can have optional values, like "-switch:value". ParseSwitch() sets switchPart // and valuePart. If the syntax is incorrect, ParseSwitch() returns false and sets // msg to an error message. string switchPart; string valuePart; string msg; if (ArgParserTX.ParseSwitch(arg, out switchPart, out valuePart, out msg)) { switch (switchPart.ToLower()) { case "?": case "h": case "help": IsHelpWanted = true; break; case "s": case "server": if (valuePart.NullOrWhiteSpace()) { SetError("The '{0}{1}' switch requires a value (i.e. the server name).".Fmt(switchFlag, switchPart)); } else if (ServerName == null) { if (System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed) { ServerName = ArgParserTX.PercentDecode(valuePart); } else { ServerName = valuePart; } } else { SetError("Two or more server names have been specified: '{0}' and '{1}'.".Fmt(ServerName, valuePart)); } break; case "ff": case "filefilter": if (valuePart.NullOrWhiteSpace()) { SetError("The '{0}{1}' switch requires a value (i.e. a file name filter).".Fmt(switchFlag, switchPart)); } else if (FileFilter == null) { if (System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed) { FileFilter = ArgParserTX.PercentDecode(valuePart); } else { FileFilter = valuePart; } } else { SetError("Two or more file filters have been specified: '{0}' and '{1}'.".Fmt(FileFilter, valuePart)); } break; default: SetError("Unrecognized switch: {0}{1}".Fmt(switchFlag, switchPart)); break; } // switch (switchPart) } // Valid switch format else { // Some fundamental error in the format of a "-switch:value" pair // such as the presence of "-switch:" with no value. SetError(msg); } } // Found switch arg else { // It's a non-switch. This program allows a single non-switch to specify the file to view. if (FilePath == null) { FilePath = arg; } else { SetError("More than one <FilePath> argument was specfied. Are quotes needed?\n\n First: {0}\n Second: {1}".Fmt(FilePath, arg)); } } } // foreach arg if (FilePath != null) { if (FilePath.EndsWith(".application", StringComparison.OrdinalIgnoreCase)) { // Assume this means we were launched via our own TracerX-Viewer.application file, when means don't actually have a file arg. FilePath = null; } else { // If this app is installed as a ClickOnce app and the user double-clicks a // file, the FilePath argument will be a URI such as // "file:///c:\logs\may%20have%20blanks.tx1". That is, any blanks will be // percent-encoded. We can construct a Uri object from the string and get the // Url.LocalPath property. Uri uri; string localPath = FilePath; if (Uri.TryCreate(FilePath, UriKind.Absolute, out uri)) { localPath = uri.LocalPath; } // Constructing a FileInfo is the best way I know // to check if the file path syntax is valid. try { FileInfo test = new FileInfo(localPath); FilePath = localPath; } catch (Exception ex) { // Use the original argument in the error message. SetError("Invalid file path syntax:\n\n {0}".Fmt(FilePath)); } } } if (IsHelpWanted || ErrorMessage != null) { // Clear any args that were found so they are not acted on. ServerName = null; FilePath = null; if (canDisplayMsg) { ShowHelp(ErrorMessage); } } else { Log.Info("AppArgs.FilePath = ", FilePath); Log.Info("AppArgs.ServerName = ", ServerName); } return(ErrorMessage == null); } // using Log }
// Parses the command line and sets public fields/properties including IsHelpWanted and ErrorMessage. // If canDisplayMsg is true, a message box will be displayed if an error is found or the -help switch is found. // Otherwise, the caller should display any error found and/or call ShowHelp(). // Returns true if no error was found, false if the ErrorMessage property was set. public static bool ParseCommandLine(bool canDisplayMsg) { using (Log.InfoCall()) { string[] args = ArgParserTX.GetArgs(keepQuotes: false); foreach (string arg in args) { Log.Debug("Got argument: ", arg); // Arguments that start with - or / are switches. // Others are "non-switches". char switchFlag = arg[0]; if (switchFlag == '-' || switchFlag == '/') { // It's a switch. // In general switches can have optional values, like "-switch:value". ParseSwitch() sets switchPart // and valuePart. If the syntax is incorrect, ParseSwitch() returns false and sets // msg to an error message. string switchPart; string valuePart; string msg; if (ArgParserTX.ParseSwitch(arg, out switchPart, out valuePart, out msg)) { switch (switchPart.ToLower()) { case "?": case "h": case "help": IsHelpWanted = true; break; case "s": case "server": if (valuePart.NullOrWhiteSpace()) { SetError("The '{0}{1}' switch requires a value (i.e. the server name).".Fmt(switchFlag, switchPart)); } else if (ServerName == null) { if (System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed) { ServerName = ArgParserTX.PercentDecode(valuePart); } else { ServerName = valuePart; } } else { SetError("Two or more server names have been specified: '{0}' and '{1}'.".Fmt(ServerName, valuePart)); } break; case "ff": case "filefilter": if (valuePart.NullOrWhiteSpace()) { SetError("The '{0}{1}' switch requires a value (i.e. a file name filter).".Fmt(switchFlag, switchPart)); } else if (FileFilter == null) { if (System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed) { FileFilter = ArgParserTX.PercentDecode(valuePart); } else { FileFilter = valuePart; } } else { SetError("Two or more file filters have been specified: '{0}' and '{1}'.".Fmt(FileFilter, valuePart)); } break; default: SetError("Unrecognized switch: {0}{1}".Fmt(switchFlag, switchPart)); break; } // switch (switchPart) } // Valid switch format else { // Some fundamental error in the format of a "-switch:value" pair // such as the presence of "-switch:" with no value. SetError(msg); } } // Found switch arg else { // It's a non-switch. This program allows a single non-switch to specify the file to view. if (FilePath == null) { FilePath = arg; } else { SetError("More than one <FilePath> argument was specfied. Are quotes needed?\n\n First: {0}\n Second: {1}".Fmt(FilePath, arg)); } } } // foreach arg if (FilePath != null) { if (FilePath.EndsWith(".application", StringComparison.OrdinalIgnoreCase)) { // Assume this means we were launched via our own TracerX-Viewer.application file, which means we don't actually have a file arg. FilePath = null; } else { // If this app is installed as a ClickOnce app and the user double-clicks a // file, the FilePath argument will be a URI such as // "file:///c:\logs\may%20have%20spaces.tx1" // or // "file://server/share/has%20space%20and%20%25.tx1". // That is, it will be percent-encoded. However, we want a regular // file path that is NOT percent-encoded. // We can construct a Uri object from the string and get the // Url.LocalPath property to do that. If FilePath is not a valid URI // we may need to percent-decode it ourselves but we must not // percent-decode it twice because the original file name may contain the % char. Uri uri; string localPath = null; if (FilePath.StartsWith("file://", StringComparison.InvariantCultureIgnoreCase) && Uri.TryCreate(FilePath, UriKind.Absolute, out uri)) { localPath = uri.LocalPath; Log.Debug("Converted URI '", FilePath, "' to\n", localPath); } else if (System.Deployment.Application.ApplicationDeployment.IsNetworkDeployed) { // This is a ClickOnce app. It was probably invoked via the command line or Process.Start() using the .appref-ms file. // In that scenario we require the file path to be percent-encoded (also the switch arguments). localPath = ArgParserTX.PercentDecode(FilePath); Log.Debug("PercentDecode(\"", FilePath, "\") returned\n", localPath); } else { // Since this is not a ClickOnce app, regular command line syntax applies. The FilePath // need not be percent-encoded, though the user should have enclosed it in quotes, that are // gone now, if it contains blanks. localPath = FilePath; Log.Debug("Using FilePath as is: ", FilePath); } // Constructing a FileInfo is the best way I know // to check if the file path syntax is valid. try { FileInfo test = new FileInfo(localPath); // If no exception we have a valid path (syntax). FilePath = localPath; } catch (Exception ex) { // Use the original argument in the error message. SetError("Invalid file path syntax:\n\n {0}".Fmt(FilePath)); } } } if (IsHelpWanted || ErrorMessage != null) { // Clear any args that were found so they are not acted on. ServerName = null; FilePath = null; if (canDisplayMsg) { ShowHelp(ErrorMessage); } } else { Log.Info("AppArgs.FilePath = ", FilePath); Log.Info("AppArgs.ServerName = ", ServerName); } return(ErrorMessage == null); } // using Log }