Opts.cs :  » GIS » NetTopologySuite » RTools_NTS » Util » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » GIS » NetTopologySuite 
NetTopologySuite » RTools_NTS » Util » Opts.cs
// Opts.cs
// 
// Copyright (C) 2002-2004 Ryan Seghers
//
// This software is provided AS IS. No warranty is granted, 
// neither expressed nor implied. USE THIS SOFTWARE AT YOUR OWN RISK.
// NO REPRESENTATION OF MERCHANTABILITY or FITNESS FOR ANY 
// PURPOSE is given.
//
// License to use this software is limited by the following terms:
// 1) This code may be used in any program, including programs developed
//    for commercial purposes, provided that this notice is included verbatim.
//    
// Also, in return for using this code, please attempt to make your fixes and
// updates available in some way, such as by sending your updates to the
// author.
//
// To-do:
//    finish UsageSpec parse behavior
//    - optional and required args
//    - pipe operator
//    encode and report on addition information provided by usage-endCapStyle spec
//        such as mutually exclusive options.
//       - add this capability to parseSpec endCapStyle use also

using System;
using System.Collections;
using System.Text;

namespace RTools_NTS.Util{
  /// <summary>
  /// A command-line option parser similar to Perl's getopts. 
  /// This is for parsing command-line
  /// options like "-name foo -type theType -v -d".  This parses a string[]
  /// (like main usually takes) and collects argument information
  /// based on a parse specification.
  /// </summary>
  /// <remarks>
  /// <para>
  /// The UsageSpec endCapStyle parse is unfinished.  
  /// Basically the UsageSpec endCapStyle parse is more expressive than the
  /// ParseSpec endCapStyle parse (see below).  But in this current implementation,
  /// none of the additional expressiveness is used.  In other words
  /// this class does not currently do anything with the optional/required
  /// switches (-file [-help]) and does not do anything with the pipe
  /// operator.
  /// </para>
  /// <para>
  /// This takes two types of parse specifications, a perl getopts endCapStyle
  /// such as "file=s, type:s, v, d" (see the ParseSpec property), 
  /// or a unix usage endCapStyle such as
  /// "-file fileName -type [typeName] [-v|-d]" (see the UsageSpec property).
  /// </para>
  /// <para>
  /// For the ParseSpec property, the rules are as follows:
  /// 1) The string is comma-separated like "file=s, type:s, v, d"
  /// 2) = means must have an argument
  /// 3) : means may have an argument
  /// </para>
  /// <para>
  /// For the UsageSpec property, the rules are as follows:
  /// 1) Optional arguments must be enclosed in square brackets [].
  /// 2) Argument names must be all word characters (- is considered to be a 
  ///    word character).
  /// </para>
  /// <para>
  /// 
  /// </para>
  /// <para>
  /// Here's an example use:
  /// <code>
  /// Opts opts = new Opts();
  /// opts.ParseSpec = "file=s, type:s, v, d");
  ///  - or -
  /// opts.UsageSpec = "-file fileName -type [typeName] [-v|-d]";
  /// if (!opts.Parse(args, out errorMessage)) { // display error message and usage }
  /// if (opts.Options.ContainsKey("v")) // -v was specified
  /// if (!opts.Options.ContainsKey("file")) { error... // need -file specified }
  /// Console.WriteLine("-file specified is {0}", opts.Options["file"]);
  /// </code>
  /// </para>
  /// </remarks>
  public class Opts
  {
    // ----------------------------------------------------------------
    #region Private variables
    // ----------------------------------------------------------------

    /// <summary>
    /// Peer class for logging.
    /// </summary>
    private Logger log;

    /// <summary>
    /// Has all the info after the parse... presence, and arguments.
    /// </summary>
    private Hashtable options;

    /// <summary>
    /// After the parse, has the arguments which were unswitched
    /// (not after an option like -file).
    /// </summary>
    private ArrayList unswitchedArgs;

    /// <summary>
    /// The specification.
    /// </summary>
    private string parseSpec;

    /// <summary>
    /// Set from the parseSpec. This is for options which require arguments.
    /// </summary>
    private ArrayList requireArg;

    /// <summary>
    /// Set from the parseSpec. This is for options which may have arguments.
    /// </summary>
    private ArrayList mayHaveArg;

    /// <summary>
    /// Set from the parseSpec. This is for options which do not have arguments.
    /// </summary>
    private ArrayList noArg;

    #endregion

    // ----------------------------------------------------------------------
    #region Properties
    // ----------------------------------------------------------------------

    /// <summary>
    /// The specification of what options to look for, which
    /// have arguments, etc.  This is the "name=s, type:s, v, d"
    /// endCapStyle.
    /// </summary>
    public string ParseSpec
    {
      get { return(parseSpec); }
      set 
      { 
        Initialize();
        string[] words = value.Split(',');
        char[] typeChars = {':', '='};
        foreach (string word in words)
        {
          int nameLen = word.IndexOfAny(typeChars);
          if (nameLen < 0) nameLen = word.Length;
          string name = word.Substring(0, nameLen).Trim();
          if (word.IndexOf(':') >= 0)
            mayHaveArg.Add(name);
          else if (word.IndexOf('=') >= 0)
            requireArg.Add(name);
          else noArg.Add(name);
        }
        parseSpec = value; 
      }
    }

    /// <summary>
    /// The specification of what options to look for, which
    /// have arguments, etc.  This is the "-name fileName [-v|-d]"
    /// endCapStyle.
    /// </summary>
    public string UsageSpec
    {
      get { return(parseSpec); }
      set 
      { 
        Initialize();
        StreamTokenizer tokenizer = new StreamTokenizer();
        tokenizer.Verbosity = VerbosityLevel.Warn;
        tokenizer.Settings.WordChar('-');
        ArrayList tokens = new ArrayList();
        tokenizer.TokenizeString(value, tokens);
        StringBuilder sb = new StringBuilder();

        for (int i = 0; i < tokens.Count; i++)
        {
          Token t = (Token)tokens[i];
          Token nextToken = null;
          if (i + 1 < tokens.Count) nextToken = (Token)tokens[i + 1];

          if ((t is WordToken) && (IsSwitch(t.StringValue)))
          {
            // it's a switch
            string name = t.StringValue.Substring(1); // drop the -
            if ((nextToken != null) && (nextToken is WordToken)
              && (!IsSwitch(nextToken.StringValue)))
            {
              requireArg.Add(name);
              if (sb.Length > 0) sb.Append(",");
              sb.Append(name + "=s");
            }
            else if ((nextToken == '[') && (i + 2 < tokens.Count))
            {
              Token twoAhead = (Token)tokens[i + 2];
              if ((twoAhead is WordToken) && (!IsSwitch(twoAhead.StringValue)))
              {
                // optional
                mayHaveArg.Add(name);
                if (sb.Length > 0) sb.Append(",");
                sb.Append(name + ":s");
              }
            }
            else
            {
              // switch with no arg
              noArg.Add(name);
              if (sb.Length > 0) sb.Append(",");
              sb.Append(name);
            }
          }
        }
        parseSpec = sb.ToString();
      }
    }

    /// <summary>
    /// This hashtable is built during Parse.  This contains the results
    /// of the parse for switches (options). Options which don't take
    /// arguments will map to bool True.  Options which may have arguments
    /// will map to the argument string if present, and null if not present.
    /// Options which must have arguments will map to the argument string
    /// if the Parse succeeds.
    /// </summary>
    public Hashtable Options 
    {
      get { return(options); }
    }

    /// <summary>
    /// These are the rest of the command line arguments which are
    /// not associated with options (switches like "-file").
    /// </summary>
    public ArrayList UnswitchedArgs
    {
      get { return(unswitchedArgs); }
    }

    /// <summary>
    /// The verbosity level for this object's Logger.
    /// </summary>
    public VerbosityLevel Verbosity 
    { 
      get { return(log.Verbosity); } 
      set { log.Verbosity = value; } 
    }

    #endregion

    // ---------------------------------------------------------------------
    #region Constructors/Destructor
    // ---------------------------------------------------------------------

    /// <summary>
    /// Default constructor.
    /// </summary>
    public Opts()
    {
      Initialize();
    }

    /// <summary>
    /// Utility function, things common to constructors.
    /// </summary>
    void Initialize()
    {
      log = new Logger("Opts");
      options = new Hashtable();
      unswitchedArgs = new ArrayList();
      requireArg = new ArrayList();
      mayHaveArg = new ArrayList();
      noArg = new ArrayList();
    }

    #endregion

    // ---------------------------------------------------------------------
    #region Standard Methods
    // ---------------------------------------------------------------------

    /// <summary>
    /// Display the state of this object.
    /// </summary>
    public void Display()
    {
      Display(String.Empty);
    }

    /// <summary>
    /// Display the state of this object, with a per-line prefix.
    /// </summary>
    /// <param name="prefix">The pre-line prefix.</param>
    public void Display(string prefix)
    {
      log.WriteLine(prefix + "Opts display:");
      log.WriteLine(prefix + "    parseSpec: {0}", parseSpec);
      log.WriteLine(prefix + "    options: ");
      foreach(DictionaryEntry entry in options)
      {
        log.WriteLine(prefix + "         {0} -> {1}", entry.Key, entry.Value);
      }
      log.WriteLine(prefix + "    unswitched args: ");
      foreach(string s in unswitchedArgs)
      {
        log.WriteLine(prefix + "         {0}", s);
      }
    }

    /// <summary>
    /// Display the information gained from the parseSpec.
    /// </summary>
    public void DisplayParseSpec()
    {
      Display(String.Empty);
    }

    /// <summary>
    /// Display the information gained from the parseSpec.
    /// </summary>
    /// <param name="prefix">A prefix to prepend to each line.</param>
    public void DisplayParseSpec(string prefix)
    {
      log.WriteLine(prefix + "parseSpec: {0}", parseSpec);
      log.WriteLine(prefix + "    mayHaveArg: ");
      foreach(string s in mayHaveArg)
        log.WriteLine(prefix + "         {0}", s);
      log.WriteLine(prefix + "    requireArg: ");
      foreach(string s in requireArg)
        log.WriteLine(prefix + "         {0}", s);
      log.WriteLine(prefix + "    noArg: ");
      foreach(string s in noArg)
        log.WriteLine(prefix + "         {0}", s);
    }

    #endregion

    // ---------------------------------------------------------------------
    #region main Methods
    // ---------------------------------------------------------------------

    /// <summary>
    /// Utility method to determine whether a string is a switch or not.
    /// This currently just checks if it starts with a - which is not
    /// followed by a digit.
    /// </summary>
    /// <param name="s">The string to test.</param>
    /// <returns>bool - true for yes it's a switch</returns>
    private bool IsSwitch(string s)
    {
      if ((s == null) || (s.Length < 2)) return(false);
      if ((s[0] == '-') && (!Char.IsDigit(s[1]))) return(true);
      return(false);
    }

    /// <summary>
    /// Parse the options string[], determine if the parse spec
    /// requirements are met, and provide an error message string
    /// if not.
    /// </summary>
    /// <param name="args">The string[] to parse.</param>
    /// <param name="errorMessage">Output error message. This
    /// is set if the input options don't have all the pieces
    /// required by the parseSpec string.</param>
    /// <returns>bool - true if parseSpec requirements are met, 
    /// false otherwise.</returns>
    public bool Parse(string[] args, out string errorMessage)
    {
      errorMessage = null;
      for (int i = 0; i < args.Length; i++)
      {
        string s = args[i].Trim();
        if (IsSwitch(s))
        {
          // it's a switch
          string name = s.Substring(1);
          if (requireArg.Contains(name))
          {
            if (i + 1 < args.Length)
            {
              if (!IsSwitch(args[i + 1]))
              {
                options[name] = args[i + 1].Trim();
                i++;
              }
              else
              {
                errorMessage = String.Format("Option '{0}' requires an argument, but next word is {1}",
                  name, args[i + 1]);
                return(false);
              }
            }
            else
            {
              errorMessage = String.Format("Option '{0}' requires an argument, but "
                + "there are no words after it", name);
              return(false);
            }
          }
          else if (mayHaveArg.Contains(name))
          {
            options[name] = null;
            if (i + 1 < args.Length)
            {
              if (args[i + 1].Trim()[0] != '-')
              {
                options[name] = args[i + 1].Trim();
                i++;
              }
            }
          }
          else if (noArg.Contains(name))
          {
            options[name] = true;
          }
          else
          {
            // it's a switch, but wasn't in parse spec
            errorMessage = String.Format("Option '{0}' isn't a recognized switch.", name);
            return(false);
          }
        }
        else
        {
          // not a switch
          unswitchedArgs.Add(s);
        }
      }
      return(true);
    }

    #endregion

    // ---------------------------------------------------------------------
    #region TestSelf
    // ---------------------------------------------------------------------
    /// <summary>
    /// Simple self test.
    /// </summary>
    /// <returns>bool - true for success, false for failure.</returns>
    public static bool TestSelf()
    {
      Logger log = new Logger("testSelf");
      log.Verbosity = VerbosityLevel.Debug;
      log.Info("Starting...");

      //
      // try parseSpec endCapStyle
      //
      string parseSpec = "file=s, type:s, v, d, number=s";
      string[] testArgs = {"-file", "fileName", "-type", "-v", "hello", 
        "-number", "-3.2"};
      string errorMessage = null;

      Opts opts = new Opts();
      opts.ParseSpec = parseSpec;
      log.Info("ParseSpec:");
      opts.DisplayParseSpec("    ");

      if (!opts.Parse(testArgs, out errorMessage))
      {
        log.Error("Unable to parse test string.");
        log.Error("Error message is '{0}'", errorMessage);
        return(false);
      }

      log.Info("After parse:");
      opts.Display("    ");

      // check results
      if (opts.Options["file"] == null)
      {
        log.Error("Parse didn't get -file option");
        return(false);
      }
      log.Info("-file argument was {0}", opts.Options["file"]);

      if (opts.Options.ContainsKey("v")) log.Info("-v option was found");
      else
      {
        log.Error("Parse didn't find -v option");
        return(false);
      }
      
      if (opts.Options.ContainsKey("type"))
      {
        log.Info("-type arg was '{0}'", opts.Options["type"]);
      }
      else
      {
        log.Error("Parse didn't find -type option");
        return(false);
      }

      //
      // try usageSpec endCapStyle
      //
      log.Info("----------------------------------------------------------");
      log.Info("UsageSpec style of use.");
      string usageSpec = "cmd -file fileName -type [typeName] [-v|-d] [-number num] file ...";
      log.Info("Input usage: {0}", usageSpec);
      opts.UsageSpec = usageSpec;
      log.Info("UsageSpec:");
      opts.DisplayParseSpec("    ");

      if (!opts.Parse(testArgs, out errorMessage))
      {
        log.Error("Unable to parse test string.");
        log.Error("Error message is '{0}'", errorMessage);
        return(false);
      }

      if (opts.Options.ContainsKey("v"))
      {
        log.Info("-v was specified");
      }

      log.Info("After parse:");
      opts.Display("    ");

      // done
      log.Info("Done.");
      return(true);
    }
    #endregion
  }
}


www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.