/////////////////////////////////////////////////////////////////////////////////////////////// public IStringList ToList( string pattern, bool noCase ) { IStringList list = new StringPairList(); foreach (KeyValuePair <string, ScriptLocationIntDictionary> pair in this) { if ((pattern == null) || StringOps.Match(null, MatchMode.Glob, pair.Key, pattern, noCase)) { list.Add("Name", pair.Key); if (pair.Value != null) { // // HACK: This is a bit clumsy. // IEnumerable <IPair <string> > collection = pair.Value.ToList() as IEnumerable <IPair <string> >; if (collection != null) { foreach (IPair <string> item in collection) { list.Add(item.X, item.Y); } } } } } return(list); }
/////////////////////////////////////////////////////////////////////////////////////////////// #region IComparer<string> Members // // NOTE: This comparer tests for matching only. If the text does not match the sub-string // pattern, a non-zero value will be returned; however, callers should NOT rely // on the exact non-match value because it is meaningless. // public int Compare( string left, string right ) { ListOps.GetElementsToCompare( interpreter, ascending, indexText, leftOnly, true, cultureInfo, ref left, ref right); /* throw */ bool match = false; Result error = null; if (StringOps.Match( interpreter, MatchMode.SubString, left, right, noCase, ref match, ref error) == ReturnCode.Ok) { int result = ConversionOps.ToInt(!match); ListOps.UpdateDuplicateCount(this, duplicates, left, right, unique, result, ref levels); /* throw */ return(result); } if (error != null) { throw new ScriptException(error); } else { throw new ScriptException(); } }
/////////////////////////////////////////////////////////////////////// internal StringList GetDefined( Interpreter interpreter, string pattern ) { StringList result = new StringList(); foreach (KeyValuePair <string, IVariable> pair in this) { IVariable variable = pair.Value; if (variable == null) { continue; } if (EntityOps.IsUndefined(variable)) { continue; } string name = variable.Name; if ((pattern == null) || StringOps.Match( interpreter, StringOps.DefaultMatchMode, name, pattern, false)) { result.Add(name); } } return(result); }
/////////////////////////////////////////////////////////////////////// public virtual ReturnCode ToDictionary( string pattern, bool noCase, ref ObjectDictionary dictionary, ref Result error ) { if (dictionary == null) { dictionary = new ObjectDictionary(); } foreach (KeyValuePair <TKey, TValue> pair in this) { string key = StringOps.GetStringFromObject(pair.Key); if ((pattern == null) || StringOps.Match(null, MatchMode.Glob, key, pattern, noCase)) { dictionary[key] = pair.Value; /* MERGE */ } } return(ReturnCode.Ok); }
/////////////////////////////////////////////////////////////////////// internal StringList GetLocals( Interpreter interpreter, string pattern ) { if (pattern != null) { pattern = ScriptOps.MakeVariableName(pattern); } StringList result = new StringList(); foreach (KeyValuePair <string, IVariable> pair in this) { IVariable variable = pair.Value; if (variable == null) { continue; } if (EntityOps.IsUndefined(variable) || EntityOps.IsLink(variable)) { continue; } ICallFrame frame = CallFrameOps.FollowNext(variable.Frame); if (interpreter != null) { if (interpreter.IsGlobalCallFrame(frame)) { continue; } if (Interpreter.IsNamespaceCallFrame(frame)) { continue; } } string name = variable.Name; if ((pattern == null) || StringOps.Match( interpreter, StringOps.DefaultMatchMode, name, pattern, false)) { result.Add(name); } } return(result); }
/////////////////////////////////////////////////////////////////////// #region Private Constructors internal ElementDictionary( EventWaitHandle variableEvent, IDictionary dictionary, MatchMode mode, string pattern, bool noCase, bool matchKey, bool matchValue ) : this(variableEvent, DefaultCapacity) { foreach (DictionaryEntry entry in dictionary) { string key = entry.Key.ToString(); object value = entry.Value; if (pattern == null) { this.Add(key, value); continue; } string text; if (matchKey) { if (matchValue) { text = StringList.MakeList(key, value); } else { text = key; } } else if (matchValue) { text = StringOps.GetStringFromObject(value); } else { // // NOTE: Nothing to match against, just skip it. // continue; } if (StringOps.Match(null, mode, text, pattern, noCase)) { this.Add(key, value); } } }
/////////////////////////////////////////////////////////////////////// internal int SetUndefined( Interpreter interpreter, string pattern, bool undefined ) { int result = 0; foreach (KeyValuePair <string, IVariable> pair in this) { IVariable variable = pair.Value; if (variable == null) { continue; } // // NOTE: This method is EXEMPT from the normal requirement // that all the variables operated on must be defined. // // if (EntityOps.IsUndefined(variable)) // continue; string name = variable.Name; if ((pattern == null) || StringOps.Match( interpreter, StringOps.DefaultMatchMode, name, pattern, false)) { if (EntityOps.IsUndefined(variable) == undefined) { continue; } if (EntityOps.SetUndefined(variable, undefined)) { result++; } } } return(result); }
/////////////////////////////////////////////////////////////////////// #region Private Methods internal int SetReadOnly( Interpreter interpreter, string pattern, bool readOnly ) { int result = 0; foreach (KeyValuePair <string, IVariable> pair in this) { IVariable variable = pair.Value; if (variable == null) { continue; } if (EntityOps.IsUndefined(variable)) { continue; } string name = variable.Name; if ((pattern == null) || StringOps.Match( interpreter, StringOps.DefaultMatchMode, name, pattern, false)) { if (EntityOps.IsReadOnly(variable) == readOnly) { continue; } if (EntityOps.SetReadOnly(variable, readOnly)) { result++; } } } return(result); }
/////////////////////////////////////////////////////////////////////////////////////////////// public static bool MatchFileName( Interpreter interpreter, string path1, string path2 ) { // // BUGBUG: This might be too slow? // if (PathOps.HasPathWildcard(path2)) { return(StringOps.Match( interpreter, StringOps.DefaultMatchMode, path1, path2, PathOps.NoCase)); } else { return(PathOps.IsSameFile(interpreter, path1, path2)); } }
/////////////////////////////////////////////////////////////////////////////////////////////// #region IComparer<string> Members // // NOTE: This comparer tests for matching only. If the text does not match the pattern, a // non-zero value will be returned; however, callers should NOT rely on the exact // non-match value because it is meaningless. // public int Compare( string left, string right ) { bool match = false; Result error = null; if (StringOps.Match( null, mode, left, right, noCase, this, regExOptions, ref match, ref error) == ReturnCode.Ok) { return(ConversionOps.ToInt(!match)); } if (error != null) { throw new ScriptException(error); } else { throw new ScriptException(); } }
public override ReturnCode Execute( Interpreter interpreter, IClientData clientData, ArgumentList arguments, ref Result result ) { ReturnCode code = ReturnCode.Ok; if (interpreter != null) { if (arguments != null) { OptionDictionary options = new OptionDictionary( new IOption[] { new Option(null, OptionFlags.None, 1, Index.Invalid, "-exact", null), new Option(null, OptionFlags.None, 3, Index.Invalid, "-integer", null), new Option(null, OptionFlags.None, 3, Index.Invalid, "-substring", null), new Option(null, OptionFlags.None, 1, Index.Invalid, "-glob", null), new Option(null, OptionFlags.None, 1, Index.Invalid, "-regexp", null), new Option(null, OptionFlags.None, 2, Index.Invalid, "-subst", null), new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-nocase", null), new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, Option.EndOfOptions, null) }); int argumentIndex = Index.Invalid; if (arguments.Count > 1) { code = interpreter.GetOptions(options, arguments, 0, 1, Index.Invalid, false, ref argumentIndex, ref result); } else { code = ReturnCode.Ok; } if (code == ReturnCode.Ok) { if ((argumentIndex != Index.Invalid) && ((argumentIndex + 1) < arguments.Count)) { MatchMode mode = StringOps.DefaultSwitchMatchMode; if (options.IsPresent("-integer")) { mode = MatchMode.Integer; } else if (options.IsPresent("-regexp")) { mode = MatchMode.RegExp; } else if (options.IsPresent("-glob")) { mode = MatchMode.Glob; } else if (options.IsPresent("-substring")) { mode = MatchMode.SubString; } else if (options.IsPresent("-exact")) { mode = MatchMode.Exact; } if (options.IsPresent("-subst")) { mode |= MatchMode.Substitute; } bool noCase = false; if (options.IsPresent("-nocase")) { noCase = true; } bool splitList = false; StringList list = null; IScriptLocation location = null; // // NOTE: Is there only one argument following the string to match? // if ((argumentIndex + 2) == arguments.Count) { code = Parser.SplitList( interpreter, arguments[argumentIndex + 1], 0, Length.Invalid, true, ref list); if (code == ReturnCode.Ok) { if (list.Count > 0) { location = arguments[argumentIndex + 1]; splitList = true; } else { result = "wrong # args: should be \"switch ?switches? string {pattern body ... ?default body?}\""; code = ReturnCode.Error; } } } else { // // TODO: Make sure this is always accurate. // code = ScriptOps.GetLocation( interpreter, arguments, argumentIndex + 1, ref location, ref result); if (code == ReturnCode.Ok) { list = ArgumentList.GetRangeAsStringList(arguments, argumentIndex + 1); } } // // NOTE: Ok, now we should have a list of patterns and bodies // if everything went Ok above. // if (code == ReturnCode.Ok) { // // NOTE: Complain if there is an odd number of words in the // list of patterns and bodies. // if ((list.Count % 2) == 0) { // // NOTE: Complain if the last body is a continuation. // if (String.Compare(list[list.Count - 1], Characters.MinusSign.ToString(), StringOps.SystemStringComparisonType) != 0) { // // NOTE: Get the text to match against. // string input = arguments[argumentIndex]; // // NOTE: We need to return an empty string if we do not // match anything. // result = String.Empty; // // NOTE: Search the patterns for a match. // for (int index = 0; index < list.Count; index += 2) { Result pattern = list[index]; bool match = false; if ((index == (list.Count - 2)) && (String.Compare(pattern, Switch.Default, StringOps.SystemStringComparisonType) == 0)) { // // NOTE: Default pattern at end always matches. // match = true; } else { if ((mode & MatchMode.Substitute) == MatchMode.Substitute) { code = interpreter.SubstituteString(pattern, ref pattern); } if (code != ReturnCode.Ok) { result = pattern; break; } code = StringOps.Match( interpreter, mode, input, pattern, noCase, ref match, ref result); if (code != ReturnCode.Ok) { break; } } if (!match) { continue; } // // NOTE: We've got a match. Find a body to execute, skipping // bodies that are "-". // for (int index2 = index + 1; ; index2 += 2) { if (index2 >= list.Count) { result = "fall-out when searching for body to match pattern"; code = ReturnCode.Error; goto switch_done; } if (String.Compare(list[index2], Characters.MinusSign.ToString(), StringOps.SystemStringComparisonType) != 0) { code = interpreter.EvaluateScript(list[index2], location, ref result); if (code == ReturnCode.Error) { Engine.AddErrorInformation(interpreter, result, String.Format("{0} (\"{1}\" arm line {2})", Environment.NewLine, FormatOps.Ellipsis(pattern), Interpreter.GetErrorLine(interpreter))); } goto switch_done; } } } switch_done: ; } else { result = String.Format( "no body specified for pattern \"{0}\"", list[list.Count - 2]); code = ReturnCode.Error; } } else { result = "extra switch pattern with no body"; code = ReturnCode.Error; if (splitList) { /* * Check if this can be due to a badly placed comment * in the switch block. * * The following is an heuristic to detect the infamous * "comment in switch" error: just check if a pattern * begins with '#'. */ for (int index = 0; index < list.Count; index++) { if (!String.IsNullOrEmpty(list[index]) && (list[index][0] == Characters.NumberSign)) { result += ", this may be due to a comment incorrectly placed " + "outside of a switch body - see the \"switch\" documentation"; break; } } } } } } else { if ((argumentIndex != Index.Invalid) && Option.LooksLikeOption(arguments[argumentIndex])) { result = OptionDictionary.BadOption(options, arguments[argumentIndex]); } else { result = "wrong # args: should be \"switch ?switches? string pattern body ... ?default body?\""; } code = ReturnCode.Error; } } } else { result = "invalid argument list"; code = ReturnCode.Error; } } else { result = "invalid interpreter"; code = ReturnCode.Error; } return(code); }
/////////////////////////////////////////////////////////////////////// public StringList GetImportNames( string pattern, bool keys, bool tailOnly ) { CheckDisposed(); StringList list = new StringList(); if (imports == null) { return(list); } if (pattern != null) { pattern = ScriptOps.MakeCommandName(pattern); } foreach (KeyValuePair <string, object> pair in imports) { IAlias alias = pair.Value as IAlias; if (alias == null) { continue; } if (keys) { string importName = pair.Key; string importNameTailOnly = NamespaceOps.TailOnly( importName); if ((pattern == null) || StringOps.Match( interpreter, MatchMode.Glob, importNameTailOnly, pattern, false)) { list.Add(tailOnly ? importNameTailOnly : importName); } } else { string aliasName = NamespaceOps.GetAliasName(alias); string aliasNameTailOnly = NamespaceOps.TailOnly( aliasName); if ((pattern == null) || StringOps.Match( interpreter, MatchMode.Glob, aliasNameTailOnly, pattern, false)) { list.Add(tailOnly ? aliasNameTailOnly : aliasName); } } } return(list); }
/////////////////////////////////////////////////////////////////////// public ReturnCode RemoveImports( string qualifiedPattern, bool strict, ref Result error ) { CheckDisposed(); if (imports == null) { error = String.Format( "imports not available in namespace \"{0}\"", GetDisplayName()); return(ReturnCode.Error); } INamespace patternNamespace = null; if ((qualifiedPattern != null) && (interpreter != null)) { patternNamespace = NamespaceOps.LookupParent( interpreter, qualifiedPattern, false, true, false, ref error); if (patternNamespace == null) { return(ReturnCode.Error); } } int count = 0; ObjectDictionary localImports = new ObjectDictionary( (IDictionary <string, object>)imports); foreach (KeyValuePair <string, object> pair in localImports) { IAlias alias = pair.Value as IAlias; string aliasName = NamespaceOps.GetAliasName(alias); string originName = GetOriginName(aliasName); if ((qualifiedPattern == null) || StringOps.Match(interpreter, MatchMode.Glob, aliasName, ScriptOps.MakeCommandName(qualifiedPattern), false) || ((originName != null) && StringOps.Match(interpreter, MatchMode.Glob, originName, ScriptOps.MakeCommandName(qualifiedPattern), false))) { INamespace originNamespace = null; if (originName != null) { originNamespace = NamespaceOps.LookupParent( interpreter, originName, false, true, false, ref error); if (originNamespace == null) { return(ReturnCode.Error); } } if ((patternNamespace == null) || ((alias != null) && (NamespaceOps.IsSame( alias.TargetNamespace, patternNamespace) || NamespaceOps.IsSame( originNamespace, patternNamespace)))) { if ((alias != null) && (interpreter != null)) { string nameToken = alias.NameToken; if ((nameToken != null) && interpreter.RemoveAliasAndCommand( alias.NameToken, null, false, ref error) != ReturnCode.Ok) { return(ReturnCode.Error); } } count += imports.Remove(pair.Key) ? 1 : 0; } } } if (strict && (count == 0)) { error = String.Format( "no imports matched pattern \"{0}\" in namespace \"{1}\"", qualifiedPattern, GetDisplayName()); return(ReturnCode.Error); } return(ReturnCode.Ok); }
public override ReturnCode Execute( Interpreter interpreter, IClientData clientData, ArgumentList arguments, ref Result result ) { ReturnCode code; if (interpreter != null) { if (arguments != null) { if (arguments.Count >= 2) { OptionDictionary options = new OptionDictionary( new IOption[] { new Option(null, OptionFlags.MustHaveObjectValue, Index.Invalid, Index.Invalid, "-clientdata", null), new Option(null, OptionFlags.MustHaveObjectValue, Index.Invalid, Index.Invalid, "-data", null), new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-nocase", null), new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-keeplibrary", null), new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-nocomplain", null), new Option(null, OptionFlags.MustHaveMatchModeValue, Index.Invalid, Index.Invalid, "-match", new Variant(StringOps.DefaultUnloadMatchMode)), new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, Option.EndOfOptions, null) }); int argumentIndex = Index.Invalid; code = interpreter.GetOptions(options, arguments, 0, 1, Index.Invalid, false, ref argumentIndex, ref result); if (code == ReturnCode.Ok) { // // NOTE: There should be a minimum of one and a maximum // of three arguments after the final option. // if ((argumentIndex != Index.Invalid) && ((argumentIndex + 3) >= arguments.Count)) { string path = ((argumentIndex + 2) < arguments.Count) ? (string)arguments[argumentIndex + 2] : String.Empty; Interpreter slaveInterpreter = null; code = interpreter.GetNestedSlaveInterpreter( path, LookupFlags.Interpreter, false, ref slaveInterpreter, ref result); if (code == ReturnCode.Ok) { Variant value = null; IClientData localClientData = clientData; if (options.IsPresent("-clientdata", ref value)) { IObject @object = (IObject)value.Value; if ((@object.Value == null) || (@object.Value is IClientData)) { localClientData = (IClientData)@object.Value; } else { result = "option value has invalid clientData"; code = ReturnCode.Error; } } if (code == ReturnCode.Ok) { if (options.IsPresent("-data", ref value)) { IObject @object = (IObject)value.Value; localClientData = _Public.ClientData.WrapOrReplace( localClientData, @object.Value); } MatchMode mode = StringOps.DefaultUnloadMatchMode; if (options.IsPresent("-match", ref value)) { mode = (MatchMode)value.Value; } bool noCase = false; if (options.IsPresent("-nocase")) { noCase = true; } if (slaveInterpreter.HasPlugins(ref result)) { string fileName = PathOps.ResolveFullPath( interpreter, arguments[argumentIndex]); if (!String.IsNullOrEmpty(fileName)) { string typeName = null; if ((argumentIndex + 1) < arguments.Count) { typeName = arguments[argumentIndex + 1]; } // // NOTE: Grab the plugin flags to match from the target // interpreter and add the Demand flag to them. // PluginFlags pluginFlags = slaveInterpreter.PluginFlags | PluginFlags.Demand; // // FIXME: PRI 4: Threading. // bool unload = false; StringList list = slaveInterpreter.CopyPluginKeys(); foreach (string name in list) { IPluginData pluginData = slaveInterpreter.GetPluginData(name); // // NOTE: Check that this plugin represents a loaded // assembly. // if (pluginData != null) { if ((pluginData.FileName != null) && PathOps.IsSameFile(interpreter, pluginData.FileName, fileName)) { if (String.IsNullOrEmpty(typeName) || StringOps.Match(interpreter, mode, pluginData.TypeName, typeName, noCase) || StringOps.Match(interpreter, mode, pluginData.Name, typeName, noCase)) { code = slaveInterpreter.UnloadPlugin( name, localClientData, pluginFlags, ref result); if (code == ReturnCode.Ok) { unload = true; } // // NOTE: Stop as soon as we match and // attempt to unload a plugin, // whether or not we actually // unloaded it. We always halt // on errors and since we only // support unloading a single // plugin at a time (even if // there are multiple plugins // contained in a particular // assembly file), we know it // is safe to stop now. // break; } } } } if ((code == ReturnCode.Ok) && !unload) { if (typeName != null) { result = String.Format( "type \"{0}\" and file \"{1}\" have never been loaded", typeName, fileName); } else { result = String.Format( "file \"{0}\" has never been loaded", fileName); } code = ReturnCode.Error; } } else { result = "invalid file name"; code = ReturnCode.Error; } } else { code = ReturnCode.Error; } } } } else { if ((argumentIndex != Index.Invalid) && Option.LooksLikeOption(arguments[argumentIndex])) { result = OptionDictionary.BadOption(options, arguments[argumentIndex]); } else { result = "wrong # args: should be \"unload ?options? fileName ?packageName? ?interp?\""; } code = ReturnCode.Error; } } } else { result = "wrong # args: should be \"unload ?options? fileName ?packageName? ?interp?\""; code = ReturnCode.Error; } } else { result = "invalid argument list"; code = ReturnCode.Error; } } else { result = "invalid interpreter"; code = ReturnCode.Error; } return(code); }
/////////////////////////////////////////////////////////////////////// private IDictionary <string, INamespace> PrivateGetChildren( string pattern, bool deleted ) /* CANNOT RETURN NULL */ { IDictionary <string, INamespace> dictionary = new Dictionary <string, INamespace>(); if (children != null) { if (pattern != null) { bool qualified = NamespaceOps.IsQualifiedName(pattern); foreach (KeyValuePair <string, INamespace> pair in children) { INamespace child = pair.Value; if (child == null) { continue; } if (!deleted && child.Deleted) { continue; } if (qualified) { if (!StringOps.Match( interpreter, MatchMode.Glob, child.QualifiedName, pattern, false)) { continue; } } else { if (!StringOps.Match( interpreter, MatchMode.Glob, pair.Key, pattern, false)) { continue; } } dictionary.Add(pair.Key, child); } } else { foreach (KeyValuePair <string, INamespace> pair in children) { INamespace child = pair.Value; if (child == null) { continue; } if (!deleted && child.Deleted) { continue; } dictionary.Add(pair.Key, child); } } } return(dictionary); }
/////////////////////////////////////////////////////////////////////// public ReturnCode RenameImport( string oldQualifiedName, string newQualifiedName, bool strict, ref Result error ) { CheckDisposed(); if (imports == null) { error = String.Format( "imports not available in namespace \"{0}\"", GetDisplayName()); return(ReturnCode.Error); } INamespace oldNamespace = NamespaceOps.LookupParent( interpreter, oldQualifiedName, false, true, false, ref error); if (oldNamespace == null) { return(ReturnCode.Error); } INamespace newNamespace = NamespaceOps.LookupParent( interpreter, newQualifiedName, false, true, false, ref error); if (newNamespace == null) { return(ReturnCode.Error); } int count = 0; ObjectDictionary localImports = new ObjectDictionary( (IDictionary <string, object>)imports); foreach (KeyValuePair <string, object> pair in localImports) { IAlias alias = pair.Value as IAlias; if (alias == null) { continue; } string aliasName = NamespaceOps.GetAliasName(alias); if (NamespaceOps.IsSame( alias.TargetNamespace, oldNamespace) && StringOps.Match(interpreter, MatchMode.Glob, aliasName, ScriptOps.MakeCommandName(oldQualifiedName), false)) { alias.TargetNamespace = newNamespace; NamespaceOps.SetAliasName(alias, newQualifiedName); return(ReturnCode.Ok); } else if (strict) { error = String.Format( "import \"{0}\" is not an alias in namespace \"{1}\"", oldQualifiedName, GetDisplayName()); return(ReturnCode.Error); } } if (strict && (count == 0)) { error = String.Format( "no imports matched name \"{0}\" in namespace \"{1}\"", oldQualifiedName, GetDisplayName()); return(ReturnCode.Error); } return(ReturnCode.Ok); }
public override ReturnCode Execute( Interpreter interpreter, IClientData clientData, ArgumentList arguments, ref Result result ) { ReturnCode code = ReturnCode.Ok; if (interpreter != null) { if (arguments != null) { if (arguments.Count >= 2) { OptionDictionary options = new OptionDictionary( new IOption[] { new Option(null, OptionFlags.None, 1, Index.Invalid, "-ascii", null), new Option(null, OptionFlags.None, 1, Index.Invalid, "-dictionary", null), new Option(null, OptionFlags.None, 1, Index.Invalid, "-integer", null), new Option(null, OptionFlags.None, 1, Index.Invalid, "-real", null), new Option(null, OptionFlags.None, 2, Index.Invalid, "-decreasing", null), new Option(null, OptionFlags.None, 2, Index.Invalid, "-increasing", null), new Option(null, OptionFlags.None, 3, Index.Invalid, "-exact", null), new Option(null, OptionFlags.None, 3, Index.Invalid, "-substring", null), new Option(null, OptionFlags.None, 3, Index.Invalid, "-glob", null), new Option(null, OptionFlags.None, 3, Index.Invalid, "-regexp", null), new Option(null, OptionFlags.None, 3, Index.Invalid, "-sorted", null), // NOTE: Implies "-exact" new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-variable", null), new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-inverse", null), new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-subindices", null), new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-all", null), new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-inline", null), new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-nocase", null), new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, "-not", null), new Option(null, OptionFlags.MustHaveValue, Index.Invalid, Index.Invalid, "-start", null), new Option(null, OptionFlags.MustHaveValue, Index.Invalid, Index.Invalid, "-index", null), new Option(null, OptionFlags.None, Index.Invalid, Index.Invalid, Option.EndOfOptions, null) }); int argumentIndex = Index.Invalid; code = interpreter.GetOptions(options, arguments, 0, 1, Index.Invalid, false, ref argumentIndex, ref result); if (code == ReturnCode.Ok) { if ((argumentIndex != Index.Invalid) && ((argumentIndex + 2) == arguments.Count)) { StringList list = null; /////////////////////////////////////////////////////////////////////// // // HACK: *PERF* This option enables an optimization that allows us to // use the cached list representation for a particular script // variable, if any, instead of re-parsing the string. If this // option is enabled, the first non-option argument is NOT the // list to search; rather, it is the variable name containing // the list to search. // bool isVariable = false; if (options.IsPresent("-variable")) { isVariable = true; } if (isVariable) { /* IGNORED */ interpreter.GetListVariableValue( VariableFlags.None, arguments[argumentIndex], false, true, true, ref list); } /////////////////////////////////////////////////////////////////////// // // NOTE: If no list representation is available, then parse the first // non-option argument string into a list. // if (list == null) { code = Parser.SplitList( interpreter, arguments[argumentIndex], 0, Length.Invalid, true, ref list, ref result); } if (code == ReturnCode.Ok) { Variant value = null; string indexText = null; if (options.IsPresent("-index", ref value)) { indexText = value.ToString(); } bool inverse = false; if (options.IsPresent("-inverse")) { inverse = true; } bool subIndexes = false; if (options.IsPresent("-subindices")) { subIndexes = true; } if ((indexText != null) || !subIndexes) { string start = null; if (options.IsPresent("-start", ref value)) { start = value.ToString(); } int startIndex = Index.Invalid; if (start != null) { code = Value.GetIndex( start, list.Count, ValueFlags.AnyIndex, interpreter.CultureInfo, ref startIndex, ref result); } if (code == ReturnCode.Ok) { bool all = false; if (options.IsPresent("-all")) { all = true; } bool inline = false; if (options.IsPresent("-inline")) { inline = true; } if (startIndex < list.Count) { if (startIndex < 0) { startIndex = 0; } bool ascending = true; // FIXME: PRI 5: Default handling. if (options.IsPresent("-decreasing")) { ascending = false; } else if (options.IsPresent("-increasing")) { ascending = true; } MatchMode mode = StringOps.DefaultMatchMode; bool sorted = false; if (options.IsPresent("-sorted")) { mode = MatchMode.Exact; sorted = true; } else if (options.IsPresent("-exact")) { mode = MatchMode.Exact; } else if (options.IsPresent("-substring")) { mode = MatchMode.SubString; } else if (options.IsPresent("-regexp")) { mode = MatchMode.RegExp; } else if (options.IsPresent("-glob")) { mode = MatchMode.Glob; } bool noCase = false; if (options.IsPresent("-nocase")) { noCase = true; } bool not = false; if (options.IsPresent("-not")) { not = true; } IntDictionary duplicates = null; IComparer <string> comparer = null; if (options.IsPresent("-exact") || options.IsPresent("-sorted")) { if (options.IsPresent("-dictionary")) { comparer = new _Comparers.StringDictionaryComparer( interpreter, ascending, indexText, true, false, interpreter.CultureInfo, ref duplicates); } else if (options.IsPresent("-integer")) { comparer = new _Comparers.StringIntegerComparer( interpreter, ascending, indexText, true, false, interpreter.CultureInfo, ref duplicates); } else if (options.IsPresent("-real")) { comparer = new _Comparers.StringRealComparer( interpreter, ascending, indexText, true, false, interpreter.CultureInfo, ref duplicates); } else if (options.IsPresent("-ascii") || true) // FIXME: PRI 5: Default handling. { // // NOTE: Check for things that the .NET Framework will not do by // default (via String.Compare). // if (!ascending || (indexText != null) || noCase) { comparer = new _Comparers.StringAsciiComparer( interpreter, ascending, indexText, true, noCase, false, interpreter.CultureInfo, ref duplicates); } } } else if (options.IsPresent("-regexp")) { comparer = new _Comparers.StringRegexpComparer( interpreter, ascending, indexText, true, noCase, false, interpreter.CultureInfo, ref duplicates); } else if (options.IsPresent("-substring")) { comparer = new _Comparers.StringSubStringComparer( interpreter, ascending, indexText, true, noCase, false, interpreter.CultureInfo, ref duplicates); } else if (options.IsPresent("-glob") || true) // FIXME: PRI 5: Default handling. { comparer = new _Comparers.StringGlobComparer( interpreter, ascending, indexText, true, noCase, false, interpreter.CultureInfo, ref duplicates); } try { string pattern = arguments[argumentIndex + 1]; int listIndex = Index.Invalid; StringList matches = all ? new StringList() : null; if (sorted && ((indexText == null) || (comparer != null)) && !all && !not && !inverse) { // // NOTE: Use the built-in binary search with the selected comparer. // listIndex = list.BinarySearch(startIndex, list.Count - startIndex, pattern, comparer); if (listIndex < 0) { listIndex = Index.Invalid; } } else if ((comparer != null) || all || not || inverse) { // // NOTE: Some custom handling is required, use the selected comparer // and options. // for (int searchIndex = startIndex; searchIndex < list.Count; searchIndex++) { // // NOTE: If we have a comparer object, use it; otherwise, use our // fallback matching routine. // bool match; if (inverse) { if (comparer != null) { match = (comparer.Compare(pattern, list[searchIndex]) == 0); } else { match = StringOps.Match(interpreter, mode, pattern, list[searchIndex], noCase); } } else { if (comparer != null) { match = (comparer.Compare(list[searchIndex], pattern) == 0); } else { match = StringOps.Match(interpreter, mode, list[searchIndex], pattern, noCase); } } // // NOTE: Do we want to consider this to be a match? // if ((match && !not) || (!match && not)) { if (all) { if (inline) { if (subIndexes) { string subValue = null; code = ListOps.SelectFromSubList( interpreter, list[searchIndex], indexText, false, interpreter.CultureInfo, ref subValue, ref result); if (code != ReturnCode.Ok) { break; } matches.Add(subValue); } else { matches.Add(list[searchIndex]); } } else { if (subIndexes) { IntList indexList = new IntList(new int[] { searchIndex }); code = ListOps.SelectFromSubList( interpreter, list[searchIndex], indexText, false, interpreter.CultureInfo, ref indexList, ref result); if (code != ReturnCode.Ok) { break; } matches.Add(indexList.ToString()); } else { matches.Add(searchIndex.ToString()); } } } else { listIndex = searchIndex; break; } } } } else { // // NOTE: No special handling required, use built-in find routine. // listIndex = list.IndexOf(pattern, startIndex); } // // NOTE: Make sure nothing in the search loop failed. // if (code == ReturnCode.Ok) { // // NOTE: Handle the result(s) of the search and build the result. // if (all) { // // NOTE: This may be an empty list. // result = matches; } else { if (listIndex != Index.Invalid) { // // NOTE: Match found, returning index or value, based on // "-inline" option. // if (inline) { result = list[listIndex]; } else { if (subIndexes) { IntList indexList = new IntList(new int[] { listIndex }); code = ListOps.SelectFromSubList( interpreter, list[listIndex], indexText, false, interpreter.CultureInfo, ref indexList, ref result); if (code == ReturnCode.Ok) { result = indexList.ToString(); } } else { result = listIndex; } } } else { // // NOTE: Match not found, returning invalid index or empty // value, based on "-inline" option. // if (inline) { result = String.Empty; } else { result = Index.Invalid; } } } } } catch (Exception e) { Engine.SetExceptionErrorCode(interpreter, e); if (e.InnerException != null) { result = e.InnerException.Message; } else if (e is ScriptException) { result = e.Message; } else { result = e; } code = ReturnCode.Error; } } else { if (all || inline) { result = String.Empty; } else { result = Index.Invalid; } } } } else { result = "-subindices cannot be used without -index option"; code = ReturnCode.Error; } } } else { if ((argumentIndex != Index.Invalid) && Option.LooksLikeOption(arguments[argumentIndex])) { result = OptionDictionary.BadOption(options, arguments[argumentIndex]); } else { result = "wrong # args: should be \"lsearch ?options? list pattern\""; } code = ReturnCode.Error; } } } else { result = "wrong # args: should be \"lsearch ?options? list pattern\""; code = ReturnCode.Error; } } else { result = "invalid argument list"; code = ReturnCode.Error; } } else { result = "invalid interpreter"; code = ReturnCode.Error; } return(code); }