text: #pragma ident "$Id$"
  
  
  
  //============================================================================
  //
  //  This file is part of GPSTk, the GPS Toolkit.
  //
  //  The GPSTk is free software; you can redistribute it and/or modify
  //  it under the terms of the GNU Lesser General Public License as published
  //  by the Free Software Foundation; either version 2.1 of the License, or
  //  any later version.
  //
  //  The GPSTk 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 Lesser General Public License for more details.
  //
  //  You should have received a copy of the GNU Lesser General Public
  //  License along with GPSTk; if not, write to the Free Software Foundation,
  //  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
  //  
  //  Copyright 2004, The University of Texas at Austin
  //
  //============================================================================
  
  //============================================================================
  //
  //This software developed by Applied Research Laboratories at the University of
  //Texas at Austin, under contract to an agency or agencies within the U.S. 
  //Department of Defense. The U.S. Government retains all rights to use,
  //duplicate, distribute, disclose, or release this software. 
  //
  //Pursuant to DoD Directive 523024 
  //
  // DISTRIBUTION STATEMENT A: This software has been approved for public 
  //                           release, distribution is unlimited.
  //
  //=============================================================================
  
  
  
  
  
  
  /**
   * @file CommandOption.cpp
   * Command line options
   */
  
  #include "CommandOption.hpp"
  #include "StringUtils.hpp"
  
  #include <sstream>
  
  using namespace std;
  using namespace gpstk::StringUtils;
  
  namespace gpstk
  {
     CommandOptionVec defaultCommandOptionList;
  
        // Prints out short options with a leading '-' and long ones with '--'.
        // Puts a '|' between them if it has both.
     string CommandOption::getOptionString() const
     {
        string toReturn;
        if (shortOpt != 0)
        {
           toReturn += string("-") + string(1, shortOpt);
           if (!longOpt.empty())
              toReturn += string(" | --") + longOpt;
        }
        else
        {
           toReturn += string("--") + longOpt;
        }
        return toReturn;
     }
  
        // Prints out short options with a leading '-' and long ones with '--'.
        // Puts a ',' between them if it has both.
     string CommandOption::getFullOptionString() const
     {
        string toReturn("  ");
        if (shortOpt != 0)
        {
           toReturn += string("-") + string(1, shortOpt);
           if (!longOpt.empty())
           {
              toReturn += string(", --") + longOpt;
              if (optFlag == hasArgument)
                 toReturn += "=" + getArgString();
           }
        }
        else
        {
           toReturn += string("    --") + longOpt;
           if (optFlag == hasArgument)
              toReturn += "=" + getArgString();
        }
        return toReturn;
     }
  
        // creates the struct option for getopt_long
     struct option CommandOption::toGetoptLongOption() const
     { 
        struct option o = {longOpt.c_str(), optFlag, NULL, 0};
        return o;
     }
  
        // makes the string for getopt
     std::string CommandOption::toGetoptShortOption() const
     { 
        std::string opt(1, shortOpt);
        if (optFlag == hasArgument) opt += ":";
        return opt;
     }
  
        // writes out the vector of values for this command option
     std::ostream& CommandOption::dumpValue(std::ostream& out) const
     {
        std::vector<std::string>::const_iterator itr = value.begin();
        while(itr != value.end()) 
        {
           out << *itr << std::endl; 
           itr++;
        }
        return out;
     }
  
        // returns a string like this:
        //
        //   -f | --foo  <arg>
        //        this is the description
        //
     std::string CommandOption::getDescription() const
     {
        ostringstream out;
           // do the option itself first
        out << '\t';
        if (shortOpt != 0)
        {
           out << '-' << shortOpt;
           if (!longOpt.empty())
              out << " | ";
           else
              out << '\t';        
        }
        if (! longOpt.empty())
        {
           out << "--" << longOpt;
        }
        if (optFlag == hasArgument)
        {
           out << " " << getArgString();
        }
           // and the description goes on a new line
        out << endl << prettyPrint(description, 
                                   "\n",
                                   "                  ", 
                                   "               ");
        if (maxCount != 0)
        {
           out << "\t\tUp to " << maxCount << " may be used on the command line."
               << endl;
        }
        return out.str();
     }
  
        // this checks if it expects number or string type arguments.
        // it returns a string describing the error, if any.
     string CommandOption::checkArguments()
     {
        if (required && (count == 0))
           return "Required option " + getOptionString() + " was not found.";
  
        return string();
     }
  
     string CommandOptionRest::checkArguments()
     {
        if (required && (count == 0))
           return "Required trailing argument was not found.";
  
        return string();
     }
  
     string CommandOptionWithNumberArg::checkArguments()
     {
        string errstr = CommandOption::checkArguments();
  
        if (!errstr.empty())
           return errstr;
  
        vector<string>::size_type vecindex;
        for(vecindex = 0; vecindex < value.size(); vecindex++)
        {
           if (!isDigitString(value[vecindex]))
           {
              string errstr("Argument for ");
              errstr += getOptionString();
              errstr += string(" should be a digit string.");
              return errstr;
           }
        }
  
        return string();
     }
  
     string CommandOptionWithStringArg::checkArguments()
     {
        string errstr = CommandOption::checkArguments();
  
        if (!errstr.empty())
           return errstr;
  
        vector<string>::size_type vecindex;
        for(vecindex = 0; vecindex < value.size(); vecindex++)
        {
           if (!isAlphaString(value[vecindex]))
           {
              string errstr("Argument for ");
              errstr += getOptionString();
              errstr += string(" should be an alphabetic string.");
              return errstr;
           }
        }
        return errstr;
     }
  
     string CommandOptionMutex::checkArguments()
     {
        if (doOneOfChecking)
        {
           string oo = CommandOptionOneOf::checkArguments();
           if (oo != string())
              return oo;
        }
  
           // mutex doesn't call CommandOption::checkArguments because
           // it uses "required" differently
        string errstr("Only one of the following options may be specified: ");
        int firstSpec = -1;
        bool touched = false;
  
        for (size_t i = 0; i < optionVec.size(); i++)
        {
           CommandOption *opt = optionVec[i];
  
           if (i)
              errstr += ", ";
           errstr += opt->getOptionString();
           if (opt->getCount())
           {
              if (firstSpec != -1)
                 touched = true;
              else
                 firstSpec = i;
           }
        }
  
        if (touched)
           return errstr;
  
        return string();
     }
  
     string CommandOptionOneOf::checkArguments()
     {
           // one-of doesn't call CommandOption::checkArguments because
           // it doesn't use "required"
        string errstr("One of the following options must be specified: ");
        bool found = false;
  
        for (size_t i = 0; i < optionVec.size(); i++)
        {
           if (optionVec[i]->getCount())
              found = true;
           if (i > 0)
              errstr += ", ";
           errstr += optionVec[i]->getOptionString();
        }
  
        if (!found)
           return errstr;
  
        return string();
     }
  
     CommandOption* CommandOptionOneOf::whichOne() const
     {
        CommandOption *rv = NULL;
  
        for (size_t i = 0; i < optionVec.size(); i++)
        {
           if (optionVec[i]->getCount())
           {
              rv = optionVec[i];
              break;
           }
        }
  
        return rv;
     }
  
     string CommandOptionAllOf::checkArguments()
     {
        string errstr("The following options must be used together: ");
        bool found = false, notFound = false;
  
        for (size_t i = 0; i < optionVec.size(); i++)
        {
           if (optionVec[i]->getCount())
              found = true;
           else
              notFound = true;
           if (i > 0)
              errstr += ", ";
           errstr += optionVec[i]->getOptionString();
        }
  
        if (found && notFound)
           return errstr;
  
        return string();
     }
  
     unsigned long CommandOptionAllOf::getCount() const
     {
        unsigned long rv = 0;
        for (size_t i = 0; i < optionVec.size(); i++)
        {
           if (optionVec[i]->getCount() == 0)
              return 0;
           rv += optionVec[i]->getCount();
        }
        return rv;
     }
  
     string CommandOptionDependent::checkArguments()
     {
           // dependent doesn't call CommandOption::checkArguments because
           // it doesn't use "required"
        string errstr;
  
        if (!requiree)
           errstr = "Null requiree (parent) for CommandOptionDependent";
        if (!requirer)
           errstr = "Null requirer (child) for CommandOptionDependent";
  
        if (requirer->getCount() && !requiree->getCount())
           errstr = "Option " + requirer->getOptionString() + " requires " +
              requiree->getOptionString();
  
        return errstr;
     }
  
     string CommandOptionGroupOr::getOptionString() const
     {
        string rv;
        if (optionVec.size() > 1)
           rv += "(";
        for (size_t i = 0; i < optionVec.size(); i++)
        {
           if (i) rv += ",";
           rv += optionVec[i]->getOptionString();
        }
        if (optionVec.size() > 1)
           rv += ")";
  
        return rv;
     }
  
     unsigned long CommandOptionGroupOr::getCount() const
     {
        unsigned long rv = 0;
        for (size_t i = 0; i < optionVec.size(); i++)
           rv += optionVec[i]->getCount();
  
        return rv;
     }
  
     unsigned long CommandOptionGroupAnd::getCount() const
     {
        unsigned long rv = 0;
        for (size_t i = 0; i < optionVec.size(); i++)
        {
           if (optionVec[i]->getCount() == 0)
              return 0;
           rv += optionVec[i]->getCount();
        }
        return rv;
     }
  
  } // namespace gpstk
  