1153 lines
42 KiB
Plaintext
1153 lines
42 KiB
Plaintext
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Microsoft Research Singularity
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//
|
||
|
// File: Parameter.cs
|
||
|
//
|
||
|
// Note:
|
||
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
using System;
|
||
|
using System.Text;
|
||
|
using System.Collections;
|
||
|
|
||
|
using Microsoft.SingSharp;
|
||
|
using Microsoft.Singularity;
|
||
|
using Microsoft.Singularity.Xml;
|
||
|
using Microsoft.Singularity.V1.Services;
|
||
|
using System.Globalization;
|
||
|
|
||
|
namespace Microsoft.Singularity.Applications
|
||
|
{
|
||
|
[CLSCompliant(false)]
|
||
|
public class ParameterProcessor
|
||
|
{
|
||
|
private Parameter[] parameterSet;
|
||
|
private Parameter[] positionSet;
|
||
|
private bool havePositional;
|
||
|
private string appName;
|
||
|
private int totalCount;
|
||
|
private string helpMsg;
|
||
|
private int boolCount, longCount, stringCount, stringArrayCount;
|
||
|
|
||
|
public ParameterProcessor()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
private enum pType {
|
||
|
boolType,
|
||
|
longType,
|
||
|
stringType,
|
||
|
stringArrayType
|
||
|
}
|
||
|
|
||
|
private class Parameter
|
||
|
{
|
||
|
public string Name;
|
||
|
public bool Mandatory;
|
||
|
public string Default;
|
||
|
public int Position;
|
||
|
public int Index;
|
||
|
public pType Kind;
|
||
|
public bool Resolved;
|
||
|
public string HelpMsg;
|
||
|
|
||
|
public Parameter(pType kind) {
|
||
|
Resolved = false;
|
||
|
Name = null;
|
||
|
Kind = kind;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private string CodeToString(ParameterCode code)
|
||
|
{
|
||
|
switch (code) {
|
||
|
case ParameterCode.Success:
|
||
|
return "Success";
|
||
|
break;
|
||
|
case ParameterCode.OutOfRange:
|
||
|
return "OutOfRange";
|
||
|
break;
|
||
|
case ParameterCode.NotSet:
|
||
|
return "NotSet";
|
||
|
break;
|
||
|
case ParameterCode.Retrieved:
|
||
|
return "Retrieved";
|
||
|
break;
|
||
|
case ParameterCode.Undefined:
|
||
|
return "Undefined";
|
||
|
break;
|
||
|
default:
|
||
|
return "This should never happen";
|
||
|
break;
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
private bool StringToBool (string arg, out bool value)
|
||
|
{
|
||
|
|
||
|
value = false;
|
||
|
bool ok = false;
|
||
|
if (arg == null) return false;
|
||
|
|
||
|
string s = arg.ToLower();
|
||
|
|
||
|
if (s == "true") {
|
||
|
value = true;
|
||
|
ok = true;
|
||
|
}
|
||
|
|
||
|
if (s == "false") {
|
||
|
value = false;
|
||
|
ok = true;
|
||
|
}
|
||
|
|
||
|
return ok;
|
||
|
}
|
||
|
|
||
|
private bool StringToLong (string arg, out long value)
|
||
|
{
|
||
|
value = -1;
|
||
|
int start = 0;
|
||
|
bool doHex = false;
|
||
|
|
||
|
if (arg == null) return false;
|
||
|
if (arg.StartsWith("0x") || arg.StartsWith("0X")) {
|
||
|
if (arg.Length == 2) return false;
|
||
|
doHex = true;
|
||
|
start = 2;
|
||
|
}
|
||
|
else {
|
||
|
for (int i=start; i < arg.Length; i++) {
|
||
|
if (!Char.IsNumber(arg[i]) && arg[i] != '-' ) return false;
|
||
|
}
|
||
|
}
|
||
|
try {
|
||
|
if (doHex) value = System.Int64.Parse(arg, NumberStyles.AllowHexSpecifier);
|
||
|
else value = System.Int64.Parse(arg);
|
||
|
}
|
||
|
catch (Exception e) {
|
||
|
Console.WriteLine("Exception: converting {0} to Long. error={1}",arg,e.Message);
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
private Parameter! GetXmlAttributes(XmlNode! p, pType t)
|
||
|
{
|
||
|
|
||
|
Parameter a = new Parameter(t);
|
||
|
assert a != null;
|
||
|
|
||
|
a.Position = p.GetAttribute("Position", -1);
|
||
|
a.Index = p.GetAttribute("id", -1);
|
||
|
a.Mandatory = p.GetAttribute("Mandatory", false);
|
||
|
a.Name = p.GetAttribute("Name",null);
|
||
|
a.Default = p.GetAttribute("Default",null);
|
||
|
a.HelpMsg = p.GetAttribute("HelpMessage",null);
|
||
|
|
||
|
//Console.WriteLine("name=({0}), Mandatory={1}, id={2}, position={3}",
|
||
|
// a.Name, a.Mandatory, a.Index, a.Position);
|
||
|
return a;
|
||
|
}
|
||
|
|
||
|
private static bool InSeparators(char c, char []! separators)
|
||
|
{
|
||
|
for (int i = 0; i < separators.Length; i++)
|
||
|
{
|
||
|
if (separators[i] == c)
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
private static ArrayList! Tokenize(string! input, int last,
|
||
|
char []! separators)
|
||
|
{
|
||
|
ArrayList tokens = new ArrayList();
|
||
|
|
||
|
for (int i = 0; i <= last;)
|
||
|
{
|
||
|
// Skip separators
|
||
|
while (i <= last && InSeparators(input[i], separators))
|
||
|
{
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
if (i > last)
|
||
|
break;
|
||
|
|
||
|
// Try to slurp word
|
||
|
int start = i;
|
||
|
while (i <= last &&
|
||
|
!InSeparators(input[i], separators) &&
|
||
|
input[i] != '\'')
|
||
|
{
|
||
|
i++;
|
||
|
}
|
||
|
if (i != start)
|
||
|
{
|
||
|
tokens.Add(input.Substring(start, i - start));
|
||
|
}
|
||
|
|
||
|
// Skip separators
|
||
|
while (i <= last && InSeparators(input[i], separators))
|
||
|
{
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
if (i > last)
|
||
|
break;
|
||
|
|
||
|
// Try to quoted slurp word
|
||
|
if (input[i] == '\'')
|
||
|
{
|
||
|
start = i;
|
||
|
i++;
|
||
|
while (i <= last && input[i] != '\'')
|
||
|
{
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
if (i <= last && input[i] == '\'')
|
||
|
{
|
||
|
tokens.Add(input.Substring(start + 1, i - start - 1));
|
||
|
i++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
tokens.Add(input.Substring(start, i - start));
|
||
|
i++;
|
||
|
}
|
||
|
}
|
||
|
} // end for
|
||
|
|
||
|
return tokens;
|
||
|
}
|
||
|
|
||
|
private Parameter FindParameter(string name)
|
||
|
{
|
||
|
if (parameterSet != null) {
|
||
|
for (int i=0; i < parameterSet.Length; i++) {
|
||
|
Parameter a = parameterSet[i];
|
||
|
if (a == null) continue;
|
||
|
assert a.Name != null;
|
||
|
if ( a.Name == name) return parameterSet[i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
return null;
|
||
|
|
||
|
}
|
||
|
|
||
|
private bool ParseAndSetParameter(Process! p, Parameter! a, string! value)
|
||
|
{
|
||
|
bool ok;
|
||
|
ParameterCode code;
|
||
|
bool boolValue;
|
||
|
long longValue;
|
||
|
|
||
|
switch (a.Kind) {
|
||
|
case pType.boolType:
|
||
|
ok = StringToBool(value, out boolValue);
|
||
|
if (!ok) {
|
||
|
Console.WriteLine("{0} for {1} is not a bool value.", value, a.Name);
|
||
|
}
|
||
|
else {
|
||
|
code = p.SetStartupBoolArg(a.Index, boolValue);
|
||
|
if (code != ParameterCode.Success){
|
||
|
Console.WriteLine("unable to set bool index {0} to {1} for arg {2}. error={3}",
|
||
|
a.Index, boolValue, a.Name, CodeToString(code) );
|
||
|
return false;
|
||
|
}
|
||
|
a.Resolved = true;
|
||
|
return true;
|
||
|
}
|
||
|
break;
|
||
|
case pType.longType:
|
||
|
ok = StringToLong(value, out longValue);
|
||
|
if (!ok) {
|
||
|
Console.WriteLine("{0} for {1} is not a integer value.", value, a.Name);
|
||
|
}
|
||
|
else {
|
||
|
code = p.SetStartupLongArg(a.Index, longValue);
|
||
|
if (code != ParameterCode.Success){
|
||
|
Console.WriteLine("unable to set string. index {0} to {1} for arg {2}. error={3}",
|
||
|
a.Index, longValue, a.Name, CodeToString(code));
|
||
|
return false;
|
||
|
}
|
||
|
a.Resolved = true;
|
||
|
return true;
|
||
|
}
|
||
|
break;
|
||
|
case pType.stringType:
|
||
|
code = p.SetStartupStringArg(a.Index, value);
|
||
|
if (code != ParameterCode.Success){
|
||
|
Console.WriteLine("unable to set string. index {0} to {1} for arg {2}. error={3}",
|
||
|
a.Index, value, a.Name, CodeToString(code));
|
||
|
return false;
|
||
|
}
|
||
|
a.Resolved = true;
|
||
|
return true;
|
||
|
break;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
private string! KindToString(pType t)
|
||
|
{
|
||
|
switch (t) {
|
||
|
case pType.boolType:
|
||
|
return "bool";
|
||
|
case pType.longType:
|
||
|
return "int";
|
||
|
case pType.stringType:
|
||
|
return "string";
|
||
|
case pType.stringArrayType:
|
||
|
return "strings";
|
||
|
default:
|
||
|
return "???";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#if false
|
||
|
public void Show(string action, Manifest! manifest, bool verbose)
|
||
|
{
|
||
|
if (action != null) {
|
||
|
Console.Write("\n {0} @{1} ", appName, action);
|
||
|
InitializeParameters(action, manifest);
|
||
|
ShowArgs(action, manifest);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
XmlNode catNode = manifest.GetCategoriesNode();
|
||
|
if (catNode == null ) {
|
||
|
Console.WriteLine(" unable to find categories node!");
|
||
|
return;
|
||
|
}
|
||
|
ArrayList actions = new ArrayList();
|
||
|
|
||
|
assert catNode != null;
|
||
|
foreach ( XmlNode n in catNode.Children) {
|
||
|
assert n != null;
|
||
|
string s = n.GetAttribute("Action", null);
|
||
|
actions.Add(s);
|
||
|
}
|
||
|
|
||
|
if (actions.Count > 0 ) {
|
||
|
Console.Write("\n {0} Actions: ", appName);
|
||
|
for (int i=0; i < actions.Count; i++) {
|
||
|
Console.Write("{0} ",actions[i]);
|
||
|
}
|
||
|
Console.WriteLine("\n");
|
||
|
}
|
||
|
|
||
|
if (verbose) {
|
||
|
for (int i=0; i < actions.Count; i++) {
|
||
|
string a = (string) actions[i];
|
||
|
if (a != null ) Console.Write("\n Configuration Parameters for action @{0}",a);
|
||
|
InitializeParameters(a, manifest);
|
||
|
ShowArgs(action, manifest);
|
||
|
}
|
||
|
} else {
|
||
|
// Show a reasonably-short list of commands.
|
||
|
ShowCommandsSummary(manifest);
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/// <summary>
|
||
|
/// This method shows a list of all of the commands (actions) that an
|
||
|
/// application provides, as defined in its manifest. The list simply
|
||
|
/// shows the names of each command, and the helptext for each.
|
||
|
/// </summary>
|
||
|
void ShowCommandsSummary(Manifest! manifest)
|
||
|
{
|
||
|
XmlNode catNode = manifest.GetCategoriesNode();
|
||
|
if (catNode == null ) {
|
||
|
Console.WriteLine(" unable to find categories node!");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
const string format = "{0,-16} {1}";
|
||
|
|
||
|
bool any = false;
|
||
|
|
||
|
foreach ( XmlNode node in catNode.Children) {
|
||
|
assert node != null;
|
||
|
|
||
|
if (node.Name != "category")
|
||
|
continue;
|
||
|
|
||
|
string action;
|
||
|
string actionWithAt;
|
||
|
|
||
|
// Is it the default action?
|
||
|
string value = node.GetAttribute("DefaultAction", null);
|
||
|
bool isDefault = value != null && value.Length != 0;
|
||
|
if (isDefault) {
|
||
|
action = "";
|
||
|
actionWithAt = "";
|
||
|
} else {
|
||
|
action = node.GetAttribute("Action", null);
|
||
|
if (action == null)
|
||
|
continue;
|
||
|
actionWithAt = "@" + action;
|
||
|
}
|
||
|
|
||
|
string! help = GetHelpMessage(node);
|
||
|
|
||
|
if (!any) {
|
||
|
any = true;
|
||
|
Console.WriteLine("The program supports the following actions:");
|
||
|
Console.WriteLine();
|
||
|
}
|
||
|
|
||
|
actionWithAt = this.appName + " " + actionWithAt;
|
||
|
|
||
|
const int max_help_length = 60;
|
||
|
|
||
|
if (help.Length > max_help_length) {
|
||
|
string[]! help_lines = BreakLineAtWords(help, max_help_length);
|
||
|
bool first = true;
|
||
|
foreach (string! help_line in help_lines) {
|
||
|
if (first) {
|
||
|
Console.WriteLine(format, actionWithAt, help_line);
|
||
|
first = false;
|
||
|
} else {
|
||
|
Console.WriteLine(format, "", help_line);
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
Console.WriteLine(format, actionWithAt, help);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!any) {
|
||
|
Console.WriteLine("The program does not support any commands.");
|
||
|
} else {
|
||
|
Console.WriteLine();
|
||
|
// Console.WriteLine("Use -?? for verbose info on all actions.");
|
||
|
Console.WriteLine("Use '@cmd -?' for detailed help on a particular command.");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// This method breaks a string into a list of strings, each of which is at most 'maxlength'
|
||
|
/// in length, if possible. The method tries to break the string at whitespace boundaries.
|
||
|
/// Note that it is possible for entries returned to be longer than 'maxlength', so don't
|
||
|
/// rely on that behavior.
|
||
|
/// </summary>
|
||
|
string[]! BreakLineAtWords(string! line, int maxlength)
|
||
|
{
|
||
|
if (line.Length < maxlength)
|
||
|
return new string[] { line };
|
||
|
|
||
|
ArrayList list = new ArrayList();
|
||
|
|
||
|
int pos = 0;
|
||
|
for (;;) {
|
||
|
if (pos >= line.Length)
|
||
|
break;
|
||
|
|
||
|
int remaining = line.Length - pos;
|
||
|
if (remaining <= maxlength) {
|
||
|
// No need to break anymore.
|
||
|
list.Add(line.Substring(pos, remaining));
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
int len = maxlength;
|
||
|
assert len < remaining;
|
||
|
|
||
|
// Move backward and find the first whitespace char.
|
||
|
while (len > 0 && !Char.IsWhiteSpace(line[pos + len - 1]))
|
||
|
len--;
|
||
|
|
||
|
// Remove whitespace from the end of the current line.
|
||
|
while (len > 0 && Char.IsWhiteSpace(line[pos + len - 1]))
|
||
|
len--;
|
||
|
|
||
|
if (len == 0) {
|
||
|
// Uh oh. The current line is one big long non-breaking string.
|
||
|
// Just break it at maxlength. Ugly.
|
||
|
len = maxlength;
|
||
|
}
|
||
|
|
||
|
list.Add(line.Substring(pos, len));
|
||
|
|
||
|
pos += len;
|
||
|
|
||
|
// Skip whitespace.
|
||
|
while (pos < line.Length && Char.IsWhiteSpace(line[pos]))
|
||
|
pos++;
|
||
|
}
|
||
|
|
||
|
Array obj_array = list.ToArray(typeof(string));
|
||
|
return (string[])obj_array;
|
||
|
}
|
||
|
|
||
|
string! GetHelpMessage(XmlNode! actionNode)
|
||
|
{
|
||
|
string value = actionNode.GetAttribute("HelpMessage", null);
|
||
|
if (value != null)
|
||
|
return value;
|
||
|
else
|
||
|
return "";
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// This method shows a summary of all of the commands (actions) defined in
|
||
|
/// an application manifest.
|
||
|
/// </summary>
|
||
|
void ShowCommandsSummaryWithArgs(Manifest! manifest)
|
||
|
{
|
||
|
// Show a reasonably-short list of commands.
|
||
|
|
||
|
string[] actions = GetAllActions(manifest);
|
||
|
|
||
|
if (actions.Length > 0 ) {
|
||
|
foreach (string action in actions) {
|
||
|
InitializeParameters(action, manifest);
|
||
|
|
||
|
string! line = GetParameterSyntaxSummary(manifest, action);
|
||
|
Console.WriteLine(line);
|
||
|
|
||
|
if (this.helpMsg != null) {
|
||
|
string! help = this.helpMsg;
|
||
|
const int max_length = 70;
|
||
|
if (help.Length > max_length) {
|
||
|
string[]! help_lines = BreakLineAtWords(help, max_length);
|
||
|
for (int i = 0; i < help_lines.Length; i++) {
|
||
|
Console.WriteLine(" " + help_lines[i]);
|
||
|
}
|
||
|
} else {
|
||
|
Console.WriteLine(" " + this.helpMsg);
|
||
|
}
|
||
|
Console.WriteLine();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Console.WriteLine("Use '" + this.appName + " @cmd -?' for detailed help on a particular command.");
|
||
|
Console.WriteLine("Use '" + this.appName + " -??' for detailed help on all commands.");
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Builds a
|
||
|
/// </summary>
|
||
|
string! GetParameterSyntaxSummary(Manifest! manifest, string action)
|
||
|
{
|
||
|
StringBuilder buffer = new StringBuilder();
|
||
|
|
||
|
if (action != null) {
|
||
|
buffer.Append(appName);
|
||
|
buffer.Append(" @");
|
||
|
buffer.Append(action);
|
||
|
} else {
|
||
|
buffer.Append(appName);
|
||
|
}
|
||
|
|
||
|
// First pass, show positional arguments.
|
||
|
|
||
|
if (positionSet != null)
|
||
|
{
|
||
|
foreach (Parameter p in positionSet) {
|
||
|
if (p == null)
|
||
|
continue;
|
||
|
|
||
|
buffer.Append(' ');
|
||
|
|
||
|
if (!p.Mandatory)
|
||
|
buffer.Append('[');
|
||
|
|
||
|
buffer.Append('<');
|
||
|
buffer.Append(p.Name);
|
||
|
buffer.Append('>');
|
||
|
|
||
|
if (!p.Mandatory)
|
||
|
buffer.Append(']');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Next, show non-positional arguments (-foo=x)
|
||
|
if (parameterSet != null) {
|
||
|
foreach (Parameter p in parameterSet) {
|
||
|
if (p == null)
|
||
|
continue;
|
||
|
|
||
|
// Positional parameters are apparently in both lists.
|
||
|
// Screen them out.
|
||
|
bool skip = false;
|
||
|
if (positionSet != null) {
|
||
|
foreach (Parameter positional in positionSet) {
|
||
|
if (positional == p) {
|
||
|
skip = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (skip)
|
||
|
continue;
|
||
|
|
||
|
buffer.Append(' ');
|
||
|
|
||
|
if (!p.Mandatory)
|
||
|
buffer.Append('[');
|
||
|
|
||
|
buffer.Append('-');
|
||
|
buffer.Append(p.Name);
|
||
|
|
||
|
switch (p.Kind) {
|
||
|
case pType.boolType:
|
||
|
break;
|
||
|
|
||
|
case pType.longType:
|
||
|
buffer.Append("=nn");
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
buffer.Append("=...");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (!p.Mandatory)
|
||
|
buffer.Append(']');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return buffer.ToString();
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Builds a list of all of the actions (commands) defined in a manifest.
|
||
|
/// Note: This CAN return a null entry (an array containing a null entry),
|
||
|
/// if the program has a default action, and most do.
|
||
|
/// </summary>
|
||
|
string[]! GetAllActions(Manifest! manifest)
|
||
|
{
|
||
|
XmlNode catNode = manifest.GetCategoriesNode();
|
||
|
if (catNode == null ) {
|
||
|
Console.WriteLine(" unable to find categories node!");
|
||
|
return new string[0];
|
||
|
}
|
||
|
ArrayList actions = new ArrayList();
|
||
|
|
||
|
foreach ( XmlNode n in catNode.Children) {
|
||
|
assert n != null;
|
||
|
string s = n.GetAttribute("Action", null);
|
||
|
actions.Add(s);
|
||
|
}
|
||
|
|
||
|
Array actions_array = actions.ToArray(typeof(string));
|
||
|
return (string[])actions_array;
|
||
|
}
|
||
|
|
||
|
void ShowVerboseCommandHelpAll(Manifest! manifest)
|
||
|
{
|
||
|
string[]! actions = GetAllActions(manifest);
|
||
|
|
||
|
foreach (string action in actions) {
|
||
|
InitializeParameters(action, manifest);
|
||
|
ShowVerboseCommandHelp(manifest, action);
|
||
|
Console.WriteLine();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
<summary>
|
||
|
This method shows detailed help for a specific command.
|
||
|
It shows the command syntax, and information on each
|
||
|
parameter.
|
||
|
</summary>
|
||
|
*/
|
||
|
void ShowVerboseCommandHelp(Manifest! manifest, string action)
|
||
|
{
|
||
|
Console.WriteLine("Help for command: " + action);
|
||
|
|
||
|
InitializeParameters(action, manifest);
|
||
|
|
||
|
if (this.helpMsg != null) {
|
||
|
Console.WriteLine();
|
||
|
string[]! lines = BreakLineAtWords(this.helpMsg, 70);
|
||
|
foreach (string line in lines) {
|
||
|
Console.WriteLine(" " + line);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Console.WriteLine();
|
||
|
Console.WriteLine("Usage:");
|
||
|
string! syntax_summary = GetParameterSyntaxSummary(manifest, action);
|
||
|
Console.WriteLine(" " + syntax_summary);
|
||
|
|
||
|
Console.WriteLine();
|
||
|
|
||
|
// Now show parameter details.
|
||
|
|
||
|
if (parameterSet != null && parameterSet.Length != 0) {
|
||
|
Console.WriteLine("Parameters:");
|
||
|
Console.WriteLine();
|
||
|
|
||
|
// 0 = parameter name
|
||
|
// 1 = parameter type
|
||
|
// 2 = mandatory?
|
||
|
// 3 = help text
|
||
|
const string parameter_format = "{0,-10} {1,-8} {2,-6} {3}";
|
||
|
|
||
|
Console.WriteLine(parameter_format, "Name", "Type", "Req'd?", "Description");
|
||
|
Console.WriteLine(parameter_format, "====", "====", "======", "===========");
|
||
|
|
||
|
if (parameterSet != null) {
|
||
|
foreach (Parameter a in parameterSet) {
|
||
|
if (a == null)
|
||
|
continue;
|
||
|
|
||
|
string! typestring = KindToString(a.Kind);
|
||
|
const int max_length = 40;
|
||
|
string! help = a.HelpMsg != null ? a.HelpMsg : "";
|
||
|
if (help.Length > max_length) {
|
||
|
string[]! help_lines = BreakLineAtWords(help, max_length);
|
||
|
for (int i = 0; i < help_lines.Length; i++) {
|
||
|
if (i == 0)
|
||
|
Console.WriteLine(parameter_format, a.Name, typestring, a.Mandatory ? "yes" : "no", help_lines[i]);
|
||
|
else
|
||
|
Console.WriteLine(parameter_format, "", "", "", help_lines[i]);
|
||
|
}
|
||
|
} else {
|
||
|
Console.WriteLine(parameter_format, a.Name, typestring, a.Mandatory ? "yes" : "no", a.HelpMsg != null ? a.HelpMsg : "");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Console.WriteLine("\nExternal Channels needed:");
|
||
|
// manifest.SetEndpoints(null, action, true);
|
||
|
}
|
||
|
|
||
|
private bool Parse(String[]! cmd, Manifest! manifest, out Process process, out string action)
|
||
|
{
|
||
|
string name;
|
||
|
action = null;
|
||
|
process = null;
|
||
|
String[] args = cmd;
|
||
|
|
||
|
// see if we have an action verb. If so determine if it is valid.
|
||
|
// if it is valid prime the parameter set based on it.
|
||
|
if (cmd.Length > 1 && cmd[1] != null) {
|
||
|
assert cmd[1] != null;
|
||
|
string! s = (!)cmd[1];
|
||
|
if ( s[0] == '@'){
|
||
|
// we have an action.
|
||
|
action = s.Substring(1);
|
||
|
//Console.WriteLine("Action encountered action={0}",action);
|
||
|
if (!InitializeParameters(action, manifest)) {
|
||
|
Console.WriteLine("action init failed");
|
||
|
return false;
|
||
|
}
|
||
|
args = new String[cmd.Length -1];
|
||
|
Array.Copy(cmd, 1, args, 0, cmd.Length-1);
|
||
|
}
|
||
|
else {
|
||
|
if (!InitializeParameters(null, manifest)) {
|
||
|
Console.WriteLine("parameter init failed");
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (!InitializeParameters(null, manifest)) {
|
||
|
Console.WriteLine("parameter init failed");
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//if ( cmd.Length == 1 ) return false;
|
||
|
|
||
|
appName = cmd[0];
|
||
|
assert appName != null;
|
||
|
|
||
|
if (args.Length > 1 && args[1] != null && args[1] == "-?") {
|
||
|
if (action != null) {
|
||
|
ShowVerboseCommandHelp(manifest, action);
|
||
|
} else {
|
||
|
ShowCommandsSummaryWithArgs(manifest);
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (args.Length > 1 && args[1] != null && args[1] == "-??"){
|
||
|
ShowVerboseCommandHelpAll(manifest);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// FIXFIX: should really parse and validate all the args and cache values
|
||
|
// BEFORE creating the process. Need to change data structures
|
||
|
//DebugStub.WriteLine("parameters.Parse creating new process");
|
||
|
process = new Process(appName, action, null);
|
||
|
if (process == null) {
|
||
|
Console.WriteLine("Unable to create process {0} with action={1}",appName,action);
|
||
|
}
|
||
|
|
||
|
ArrayList extras = new ArrayList();
|
||
|
|
||
|
bool seenPositional = false;
|
||
|
int positionalBase = 0;
|
||
|
|
||
|
Parameter a;
|
||
|
for (int i=1; i < args.Length ; i++){
|
||
|
string p = args[i];
|
||
|
assert p != null;
|
||
|
//Console.WriteLine("processing {0}", p);
|
||
|
if (p[0] == '-') {
|
||
|
// this is an optional arg
|
||
|
p = p.Substring(1);
|
||
|
if ( p== null || p == "") {
|
||
|
Console.WriteLine("'-' with no parameter name is invalid");
|
||
|
return false;
|
||
|
}
|
||
|
ArrayList tokens = Tokenize(p, p.Length - 1, new char[] {'=', ':'});
|
||
|
name = (string) tokens[0];
|
||
|
a = FindParameter(name);
|
||
|
if (a != null) {
|
||
|
//Console.WriteLine("found a match name={0}, rest={1} ",
|
||
|
// a.Name, tokens.Count >=2 ? tokens[1]: "empty");
|
||
|
|
||
|
if (tokens.Count == 1) {
|
||
|
//this is potentially a bool parameter with no value
|
||
|
if (a.Kind == pType.boolType) {
|
||
|
// set to opposite of default
|
||
|
string val = a.Default == "False" ? "True" : "False";
|
||
|
bool ok = ParseAndSetParameter(process, a, val);
|
||
|
if (!ok) return false;
|
||
|
//Console.WriteLine("Setting {0} to {1}", a.Name, val);
|
||
|
|
||
|
}
|
||
|
else {
|
||
|
Console.WriteLine("invalid parameter assignment");
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
if (tokens.Count == 2) {
|
||
|
bool ok = ParseAndSetParameter(process, a, (string)(!) tokens[1]);
|
||
|
if (!ok) return false;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
//unknown parameter
|
||
|
Console.WriteLine("Unknown parameter not set");
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
a = null;
|
||
|
if (!seenPositional) {
|
||
|
seenPositional = true;
|
||
|
positionalBase = i;
|
||
|
}
|
||
|
assert i-positionalBase >= 0;
|
||
|
if (positionSet != null && (i-positionalBase) < positionSet.Length ) {
|
||
|
a = positionSet[i-positionalBase];
|
||
|
}
|
||
|
if (a != null) {
|
||
|
//Console.WriteLine("Positional match: for {0} at {1} arrayIdx={2}",
|
||
|
// a.Name, a.Position, i);
|
||
|
bool ok = ParseAndSetParameter(process, a, (string)(!) args[i]);
|
||
|
if (!ok) return false;
|
||
|
|
||
|
}
|
||
|
else {
|
||
|
if (stringArrayCount != 1) {
|
||
|
Console.WriteLine("{0} is not a known parameter.", p);
|
||
|
}
|
||
|
// add it to the Array List
|
||
|
// After processing all the tokens the list will be
|
||
|
// converted to StringArray parameter if present
|
||
|
extras.Add(args[i]);
|
||
|
//return false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// check to see if all positional args were resolved
|
||
|
bool status = true;
|
||
|
if (positionSet != null) {
|
||
|
for (int i=0; i < positionSet.Length; i++ ){
|
||
|
Parameter p = positionSet[i];
|
||
|
if (p != null) {
|
||
|
assert p.Name != null;
|
||
|
if (p.Resolved != true){
|
||
|
if (p.Mandatory) {
|
||
|
Console.WriteLine("Mandatory positional Parameter {0} at {1} not set.",
|
||
|
p.Name, i);
|
||
|
status = false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// check to see if all mandatory args were resolved
|
||
|
if (status == true) {
|
||
|
if (parameterSet != null) {
|
||
|
for (int i=0; i < parameterSet.Length; i++ ){
|
||
|
Parameter p = parameterSet[i];
|
||
|
assert p != null;
|
||
|
assert p.Name != null;
|
||
|
|
||
|
if (p.Mandatory == true){
|
||
|
if (p.Resolved != true){
|
||
|
Console.WriteLine("Mandatory Parameter {0} not set.", p.Name);
|
||
|
status = false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// Set default values if needed on non mandatory parameters
|
||
|
if (status == true) {
|
||
|
if (parameterSet != null) {
|
||
|
for (int i=0; i < parameterSet.Length; i++ ){
|
||
|
Parameter p = parameterSet[i];
|
||
|
assert p != null;
|
||
|
assert p.Name != null;
|
||
|
if (p.Kind == pType.stringArrayType) {
|
||
|
// ignore defaults for string type..
|
||
|
continue;
|
||
|
}
|
||
|
if (p.Resolved != true && p.Default != null){
|
||
|
//Console.WriteLine("setting default: {0}={1}", p.Name, p.Default);
|
||
|
ParseAndSetParameter(process, p, p.Default);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// see if there were any extra args. If so pass them on to the process
|
||
|
// if the manifest defined a StringArrayParameter
|
||
|
string[] strings = null;
|
||
|
if (extras.Count > 0) {
|
||
|
// is there 1 ArrayParameter defined in the manifest?
|
||
|
//Console.WriteLine("extras={0}, arrayCount={1}", extras.Count, stringArrayCount);
|
||
|
if (stringArrayCount == 1) {
|
||
|
// Always send in if app requests is, even if 0 extra args
|
||
|
strings = new string[extras.Count];
|
||
|
for (int i=0; i < extras.Count; i++) {
|
||
|
strings[i] = (string) extras[i];
|
||
|
//Console.WriteLine(" strings[{0}]={1}",i,strings[i]);
|
||
|
}
|
||
|
Console.WriteLine("Setting Strings to {0}", strings);
|
||
|
process.SetStartupStringArrayArg(0, strings);
|
||
|
}
|
||
|
else {
|
||
|
Console.WriteLine("There is not exactly ONE StringArray parameter.\n " +
|
||
|
"Unsure where to place strings.\n" +
|
||
|
"#of String Array parameters={0}",stringArrayCount);
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return status ;
|
||
|
}
|
||
|
|
||
|
public bool ProcessParameters( String[] commandLine, Manifest manifest, out Process p, out string action)
|
||
|
{
|
||
|
ParameterCode code;
|
||
|
long longValue;
|
||
|
string stringValue;
|
||
|
bool boolValue;
|
||
|
|
||
|
action = null;
|
||
|
p = null;
|
||
|
|
||
|
if (manifest == null) return false;
|
||
|
if (commandLine == null) return false;
|
||
|
|
||
|
return Parse( commandLine, manifest, out p, out action);
|
||
|
}
|
||
|
|
||
|
private bool SetPosition(Parameter! p)
|
||
|
{
|
||
|
bool result = true;
|
||
|
if (p != null) {
|
||
|
if (p.Position != -1) {
|
||
|
if (p.Position < 0 || p.Position > totalCount-1) {
|
||
|
Console.WriteLine("{0} position index out of range ({1})",
|
||
|
p.Name, p.Position);
|
||
|
result = false;
|
||
|
}
|
||
|
else {
|
||
|
if (positionSet != null) {
|
||
|
positionSet[p.Position] = p;
|
||
|
}
|
||
|
result = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
public bool InitializeParameters(string actionName, Manifest! manifest)
|
||
|
{
|
||
|
XmlNode bools;
|
||
|
XmlNode strings;
|
||
|
XmlNode stringArrays;
|
||
|
XmlNode longs;
|
||
|
XmlNode ActionNode;
|
||
|
int pIndex;
|
||
|
|
||
|
longCount = 0;
|
||
|
boolCount = 0;
|
||
|
stringCount = 0;
|
||
|
stringArrayCount = 0;
|
||
|
|
||
|
bools = null;
|
||
|
longs = null;
|
||
|
strings = null;
|
||
|
stringArrays = null;
|
||
|
parameterSet = null;
|
||
|
positionSet = null;
|
||
|
|
||
|
// Use Action to determine which set of parameters are going to be used.
|
||
|
// If action is null we need to ensure there is 1 Parameter configuration
|
||
|
// and its DefaultAction parameter is set to true.
|
||
|
XmlNode actionNode = manifest.GetCategoryNode(actionName);
|
||
|
if (actionNode == null) {
|
||
|
if (actionName != null) {
|
||
|
Console.WriteLine("Unknown action {0} recognized", actionName);
|
||
|
}
|
||
|
else {
|
||
|
Console.WriteLine("Unable to find default action");
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
string categoryName = actionNode.GetAttribute("name","");
|
||
|
|
||
|
#if VERBOSE
|
||
|
Console.WriteLine(" using category {0}, action={1}, default={2}",
|
||
|
categoryName,
|
||
|
actionNode.GetAttribute("Action",""),
|
||
|
actionNode.GetAttribute("DefaultAction",false));
|
||
|
#endif
|
||
|
if (categoryName != "console") {
|
||
|
Console.WriteLine("This manifest's category is not 'console': ({0})", categoryName);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bools = manifest.GetBoolParameterNode(actionNode);
|
||
|
longs = manifest.GetLongParameterNode(actionNode);
|
||
|
strings = manifest.GetStringParameterNode(actionNode);
|
||
|
stringArrays = manifest.GetStringArrayParameterNode(actionNode);
|
||
|
helpMsg = manifest.GetHelpMessage(actionNode);
|
||
|
|
||
|
if ( bools == null && longs == null && strings == null && stringArrays == null) {
|
||
|
parameterSet = new Parameter[0];
|
||
|
positionSet = new Parameter[0];
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if ( bools != null ) {
|
||
|
boolCount = bools.GetAttribute("length", 0);
|
||
|
}
|
||
|
|
||
|
if ( longs != null ) {
|
||
|
longCount = longs.GetAttribute("length", 0);
|
||
|
}
|
||
|
|
||
|
if ( strings != null ) {
|
||
|
stringCount = strings.GetAttribute("length", 0);
|
||
|
}
|
||
|
|
||
|
if ( stringArrays != null ) {
|
||
|
stringArrayCount = stringArrays.GetAttribute("length", 0);
|
||
|
}
|
||
|
|
||
|
totalCount = stringCount + stringArrayCount + longCount + boolCount;
|
||
|
|
||
|
parameterSet = new Parameter[totalCount];
|
||
|
positionSet = new Parameter[totalCount];
|
||
|
if (totalCount == 0 ) return true;
|
||
|
|
||
|
assert positionSet != null;
|
||
|
assert parameterSet != null;
|
||
|
|
||
|
pIndex = 0;
|
||
|
if ( bools != null ) {
|
||
|
if (boolCount > 0 ) {
|
||
|
foreach (XmlNode! bp in bools.Children) {
|
||
|
if ( bp.Name == "BoolParameter") {
|
||
|
Parameter p = GetXmlAttributes(bp, pType.boolType);
|
||
|
if (!SetPosition(p)) return false;
|
||
|
parameterSet[pIndex++] = p;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( longs != null ) {
|
||
|
if (longCount > 0 ) {
|
||
|
foreach (XmlNode! lp in longs.Children) {
|
||
|
if ( lp.Name == "LongParameter") {
|
||
|
Parameter p = GetXmlAttributes(lp, pType.longType);
|
||
|
if (!SetPosition(p)) return false;
|
||
|
parameterSet[pIndex++] = p;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( strings != null ) {
|
||
|
if (stringCount > 0 ) {
|
||
|
foreach (XmlNode! sp in strings.Children) {
|
||
|
if ( sp.Name == "StringParameter") {
|
||
|
Parameter p = GetXmlAttributes(sp, pType.stringType);
|
||
|
if (!SetPosition(p)) return false;
|
||
|
parameterSet[pIndex++] = p;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( stringArrays != null ) {
|
||
|
if (stringArrayCount > 0 ) {
|
||
|
foreach (XmlNode! sp in stringArrays.Children) {
|
||
|
if ( sp.Name == "StringArrayParameter") {
|
||
|
Parameter p = GetXmlAttributes(sp, pType.stringArrayType);
|
||
|
if (!SetPosition(p)) return false;
|
||
|
parameterSet[pIndex++] = p;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( positionSet != null && positionSet[0] != null) {
|
||
|
havePositional = true;
|
||
|
bool seenNull = false;
|
||
|
for (int i=0; i < positionSet.Length; i++) {
|
||
|
if ( positionSet[i] == null ) {
|
||
|
seenNull = true;
|
||
|
continue;
|
||
|
}
|
||
|
if (seenNull) {
|
||
|
Console.Write("Positional indices not contiguous!");
|
||
|
for (int j=0; j < positionSet.Length; j++) {
|
||
|
Parameter p = positionSet[j];
|
||
|
if ( p != null ) {
|
||
|
Console.Write("{0}({1}) ",j, p.Name);
|
||
|
}
|
||
|
}
|
||
|
Console.WriteLine();
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|