////////////////////////////////////////////////////////////////////////////////
//
// 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
///
/// 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.
///
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.");
}
}
///
/// 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.
///
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 "";
}
///
/// This method shows a summary of all of the commands (actions) defined in
/// an application manifest.
///
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.");
}
///
/// Builds a
///
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();
}
///
/// 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.
///
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();
}
}
/**
This method shows detailed help for a specific command.
It shows the command syntax, and information on each
parameter.
*/
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;
}
}
}