Logo Search packages:      
Sourcecode: passepartout version File versions  Download package

cmdline.cc

///
// Copyright (C) 2003, 2004, Fredrik Arnerup & Rasmus Kaj, See COPYING
///
#include "cmdline.h"
#include <algorithm>

00007 CmdLine::CmdLine(int argc, char **argv) : seen_double_dash(false)
{
  for(int i = 1; i < argc; i++)
    arguments.push_back(argv[i]);
  argi = arguments.begin();
}

00014 int CmdLine::add_option(Option option) {
  int i = options.size() + 1;
  option.id = i;
  options.push_back(option);
  return i;
}

namespace {
  struct match {
    match(char sname) : c(sname), l("-") {}
    match(const std::string& lname) : c(1) /* 1 is not printable */, l(lname) 
    {}
    bool operator() (const CmdLine::Option &option) {
      return option.short_opt == c || option.long_opt == l;
    }
    char c;
    const std::string l;
  };
}

00034 CmdLine::ParsedOptions CmdLine::parse() {
  ParsedOptions tmp;
  while(true) {
    Arg arg = parse_next();
    if(!arg.first && arg.second.empty())
      return tmp;
    tmp.push_back(arg);
  }
}

00044 void CmdLine::print_usage(std::ostream &out) {
  // const int term_width = 80;
  /// \todo Wrap lines if they exceed the term_width
  using namespace std;
  vector<string> name_col;
  for(Options::const_iterator
      opt = options.begin(); opt != options.end(); opt++) {
    std::string name = "  ";
    if(opt->short_opt) {
      name += "-";
      name += opt->short_opt;
      if(opt->param_mode == Option::REQ_PARAM)
      name += " " + opt->param_name;
    }
    if(!opt->long_opt.empty()) {
      if(opt->short_opt)
      name += ", ";
      name += "--" + opt->long_opt;
      if(opt->param_mode == Option::OPT_PARAM)
      name += "[=" + opt->param_name + "]";
      else if(opt->param_mode == Option::REQ_PARAM && !opt->short_opt)
      name + "=" + opt->param_name;
    }
    name_col.push_back(name);
  }

  int name_col_width = 0;
  for(vector<string>::const_iterator name = name_col.begin();
      name != name_col.end(); name++) {
    if(name->length() > name_col_width)
      name_col_width = name->length();
  }

  vector<string>::const_iterator name = name_col.begin();
  for(Options::const_iterator opt = options.begin();
      opt != options.end();
      opt++, name++) {
    out << *name;
    int padding = 4 + name_col_width - name->length();
    for(int i = 0; i < padding; i++)
      out << " ";
    out << opt->desc << endl;
  }
}

CmdLine::Arg CmdLine::parse_next() {
  // anything in the queue?
  if(!arg_queue.empty()) {
    Arg tmp = arg_queue.front();
    arg_queue.pop();
    return tmp;
  }

  int null_option = 0;

  // end of arguments
  if(argi == arguments.end())
    return std::make_pair(null_option, "");

  // not an option
  if(argi->at(0) != '-' || seen_double_dash || *argi == "-")
    return std::make_pair(null_option, *argi++);

  // --
  if(!seen_double_dash && *argi == "--") {
    seen_double_dash = true;
    argi++;
    return parse_next();
  }

  // long?
  if(argi->at(1) == '-') {
    std::string tmp = argi->substr(2);
    unsigned int eq = tmp.find('=');
    //     if(eq == argi->npos)
    //       eq = argi->length();
    std::string lname = tmp.substr(0, eq);
    bool has_value = false;
    std::string value;
    if(eq != tmp.npos) {
      value = tmp.substr(eq + 1);
      has_value = true;
    }
    argi++;
    Options::const_iterator
      option = std::find_if(options.begin(), options.end(), match(lname));
    if(option == options.end())
      throw UnknownOptionError("--" + lname);

    // check for argument errors
    switch(option->param_mode) {
    case Option::REQ_PARAM:
      if(!has_value)
      throw ArgumentError("--" + lname);
      break;
    case Option::NO_PARAM:
      if(has_value)
      throw ArgumentError("--" + lname, true);
      break;
    default:
      break;
    }

    return std::make_pair(option->id, value);
  }

  // short?
  for(unsigned int i = 1; i < argi->length(); i++) {
    char c = argi->at(i);
    Options::const_iterator
      option = std::find_if(options.begin(), options.end(), match(c));
    if(option == options.end())
      throw UnknownOptionError(std::string("-") + c);

    // push options on a queue, so we can parse this arg in one go
    if(option->param_mode == Option::REQ_PARAM) {
      // no optional parameters for short options
      if(i == argi->length() - 1) {
      argi++;
      if(argi == arguments.end())
        throw ArgumentError(std::string("-") + c);
      arg_queue.push(std::make_pair(option->id, *argi));
      break;
      } else {
      arg_queue.push(std::make_pair(option->id, argi->substr(i + 1)));
      break;
      }
    } else { // not REQ_PARAM
      arg_queue.push(std::make_pair(option->id, ""));
    }
  }
  argi++;
  return parse_next();
}

// g++ -Wall -g -o cmdline -DCMDLINE_STANDALONE cmdline.cc
#ifdef CMDLINE_STANDALONE
int main(int argc, char **argv) {
  CmdLine cmdline(argc, argv);
  const int p = cmdline.add_option(CmdLine::Option('p', "", 
                                       CmdLine::Option::NO_PARAM, 
                                       "Frobnicate it."));
  const int f = cmdline.add_option(CmdLine::Option('f', "foo",
                                       CmdLine::Option::REQ_PARAM,
                                       "Set foo", "FOO"));
  const int b = cmdline.add_option(CmdLine::Option('b', "bar",
                                       CmdLine::Option::OPT_PARAM,
                                       "Maybe set bar", "BAR"));
  const int n = cmdline.add_option(CmdLine::Option('n', "nisse",
                                       CmdLine::Option::NO_PARAM,
                                       "Don't set Nisse"));
  const int lisa =
    cmdline.add_option(CmdLine::Option(0, "lisa",
                               CmdLine::Option::NO_PARAM,
                               "Don't set Lisa"));
  using namespace std;
  try {
    CmdLine::ParsedOptions opts = cmdline.parse();
    for(CmdLine::ParsedOptions::const_iterator
        arg = opts.begin(); arg != opts.end(); arg++) {
      if(!arg->first)
      cout << arg->second << endl;
      else 
      cout << arg->first << ": "
           << arg->second << endl;
    }
  }
  catch(const CmdLine::Error& e) {
    cerr << e.what() << endl;
    cmdline.print_usage(cerr);
  }
}
#endif

Generated by  Doxygen 1.6.0   Back to index