www.pudn.com > cppcc.rar > cmdline_parser.hh


/*
 *  File:       cucu.c
 *              $Id: cmdline_parser.hh,v 1.3 2002/06/26 20:46:03 alec Exp $
 *
 *  Author:     Alec Panoviciu (alecu@email.com)
 *
 *  Comments:
 *
 *  Revision history:
 *
 *  $Log: cmdline_parser.hh,v $
 *  Revision 1.3  2002/06/26 20:46:03  alec
 *  g++ 3.x happy
 *
 *  Revision 1.2  2002/04/29 09:34:10  alec
 *  scanner ptree building compiles
 *
 */

/* 
  Copyright (C) 2002 Alexandru Panoviciu (alecu@email.com)

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

 */


#ifndef __CMDLINE_PARSER_HH__
#define __CMDLINE_PARSER_HH__

#include 
#include 
#include 
using namespace std;

#include "prop_registry.hh"
#include "debug.h"


/**
 * This is the exception class used by the CmdLineParser class.
 */
class CmdLineParseException : public exception
{
public:
  CmdLineParseException (const string &message_) :
    message(message_)
  {}
  
  CmdLineParseException () :
    message("Command Line Parse Exception")
  {}
  
  virtual const char* what() const throw()
  {
    return message.c_str();
  }

  virtual operator string() const
  {
    return message;
  }

  ~CmdLineParseException () throw ()
  {}
  
protected:
  
  string message;
  
};

inline ostream& operator << (ostream& os, CmdLineParseException &ex)
{
  return os << ex.what();
}


/**
 * A simple command line parser implementation. It supports both short
 * one-letter (like -abcdef) and long (like --a_longopt --b_something )
 * options. Also, options arguments of type string/bool/numeric are
 * supportd. It supoprts the GNU style "--" options terminator, and automatic
 * help message dumping.
 */
class CmdLineParser
{

  /**
   * A command line atom (or "option" ) is something like "-c" or "-o foo" or
   * "--enable-things".
   *
   * Each atom can contain one or more arguments. furthermore, the same atom
   * can appear more than once. The \a multi field tells how multiple
   * occurence should be handled. If it is false, each occurence will override
   * the previous one. If true, the argument from each occurence is appended
   * to the property that corresponds to that atom.
   * 
   * The tag field (corresponding to the tag field used into
   * the Propregistry) means:
   * 
   * \li k_string : a parameter followed by a string argument (something like
   * "--enable this" or "--enable=other").
   *
   * \li k_bool: can be either "--switch=yes" (or, alternatively "--switch
   * no")) or just "--switch" (yea is implied) or (the short version) "-s". If
   * multi is enabled, the boolean values are stored in a list for the
   * corresponding property. Otherwise, the last one will be the property's
   * value. "true" and "false" in place of yes and no are also supported.
   * 
   * \li k_int: something like "-n 100" or "--numer 100". The multi parameter
   * has the same meaning as for k_bool.
   *
   * \li k_float: same as k_int.
   *
   * The sOpt and lOpt fields are the option's name (i.e. the bi that appears
   * after the - or --, respectively). Each option can have any of the two
   * forms or both.
   *
   * If the optional field is true, the optino is, well, optional :)
   *
   * The description string is a text that indicates the meaning of the
   * option, from the user's point of view. It is used when dumping the command
   * line synopsys.
   *
   * The prop string is the key of the property that will receive the value(s)
   * of the option.
   */
  typedef struct t_CmdLineAtom
  {
    enum {k_string, k_bool, k_int, k_float} tag;
    bool multi;
    bool optional;
    string sOpt;
    string lOpt;
    string prop;
    string description;

    t_CmdLineAtom (const string &tag_, bool multi_, bool optional,
                   const string &sOpt_, const string &lOpt_,
                   const string &prop_, const string &description_) :
      multi(multi_), sOpt(sOpt_), lOpt(lOpt_),
      prop(prop_), description(description_)
    {
      if (tag_ == "s") tag = k_string;
      else if (tag_ == "b") tag = k_bool;
      else if (tag_ == "i") tag = k_int;
      else if (tag_ == "f") tag = k_float;
      else ASSERT(0, "bad tag string, should be \"s\"/\"b\"/\"i\"/\"f\"");
      ASSERT((sOpt != "") || (lOpt != ""),
             "both long and short option strings are empty");
    }

    /**
     * Returns a string containing the synopsis of this atom.
     */
    operator string () const;

    /**
     * Dumps a detailed description of the atom (in the format used by the
     * "options" part of any decent program that implements "--help".
     */
    ostream& dumpDescription (ostream &os) const;
    
  } CmdLineAtom;
  
public:

  /**
   * Creates a new CmdLineParser that will parse a command line that obeys the
   * given format string and will store the corersponding properties into the
   * given property registry.
   */
  CmdLineParser (const string &progName_, PropRegistry &pr_) :
    progName(progName_), pr(pr_)
  {}

  /**
   * Parses the given command line and stores all the properties into the
   * registry. The parsing stops at the first non-option argument (i.e. not
   * starting with - or --).
   *
   * \throw CmdLineparseException if any error was encountered during parsing
   * the command line. The exception's what message indicates what went wrong.
   *
   * \return the number of parsed arguments (the rest up to argv is supposed
   * to only contain input files or whateer).
   */
  int parse (int argc, char *argv[]) throw (CmdLineParseException);


  /**
   * \name Specifying command line syntax
   * 
   * The methods add a new atom description into the parser's table and return
   * a ref to the parser object in order to allow chained insertions
   * (something like: clParaser.add(atom1).add(atom2).add(...);).
   */
  //@{
  CmdLineParser& add (const CmdLineAtom &atom)
  {
    desc.push_back(atom);
    return *this;
  }

  CmdLineParser& add (const string &tag, bool multi, bool optional,
                      const string &sOpt, const string &lOpt,
                      const string &prop, const string &description)
  {
    return add(CmdLineAtom(tag, multi, optional, sOpt, lOpt,
                           prop, description));
  }
  //@}

  void printUsage (ostream &os);
  
private:

  /**
   * The registry where the parsed roperties will be stored by parse.
   */
  PropRegistry ≺

  /**
   * The desription of the cmd line.
   */
  vector desc;

  /**
   * The name of the executable.
   */
  string progName;
};

#endif /* #ifndef __CMDLINE_PARSER_HH__ */