OpenCores
URL https://opencores.org/ocsvn/w11/w11/trunk

Subversion Repositories w11

[/] [w11/] [tags/] [w11a_V0.6/] [tools/] [src/] [librtcltools/] [RtclArgs.cpp] - Rev 40

Go to most recent revision | Compare with Previous | Blame | View Log

// $Id: RtclArgs.cpp 521 2013-05-20 22:16:45Z mueller $
//
// Copyright 2011-2013 by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
//
// This program is free software; you may redistribute and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 2, 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 complete details.
// 
// Revision History: 
// Date         Rev Version  Comment
// 2013-05-19   521   1.0.7  add NextSubOpt() method, pass optset's as const
// 2013-02-12   487   1.0.6  add CurrentArg() method
// 2013-02-03   481   1.0.5  use Rexception
// 2011-03-26   373   1.0.4  add GetArg(float/double)
// 2011-03-13   369   1.0.3  add GetArg(vector<unit8_t>); NextOpt clear NOptMiss
// 2011-03-06   367   1.0.2  add Config() methods;
// 2011-03-05   366   1.0.1  fObjc,fNDone now size_t; add NDone(), SetResult();
//                           add GetArg(Tcl_Obj), PeekArgString();
// 2011-02-26   364   1.0    Initial version
// 2011-02-11   360   0.1    First draft
// ---------------------------------------------------------------------------
 
/*!
  \file
  \version $Id: RtclArgs.cpp 521 2013-05-20 22:16:45Z mueller $
  \brief   Implemenation of RtclArgs.
*/
 
//debug
#include <iostream>
 
#include <ctype.h>
#include <stdarg.h>
 
#include "RtclArgs.hpp"
 
#include "Rtcl.hpp"
#include "librtools/Rexception.hpp"
 
using namespace std;
 
/*!
  \class Retro::RtclArgs
  \brief FIXME_docs
*/
 
// all method definitions in namespace Retro
namespace Retro {
 
//------------------------------------------+-----------------------------------
//! Default constructor
 
RtclArgs::RtclArgs()
  : fpInterp(0),
    fObjc(0),
    fObjv(0),
    fNDone(0),
    fNOptMiss(0),
    fNConfigRead(0),
    fOptErr(false),
    fArgErr(false)
{}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
RtclArgs::RtclArgs(Tcl_Interp* interp, int objc, Tcl_Obj* const objv[],
                   size_t nskip)
  : fpInterp(interp),
    fObjc((size_t)objc),
    fObjv(objv),
    fNDone((nskip<=(size_t)objc) ? nskip : (size_t)objc),
    fNOptMiss(0),
    fNConfigRead(0),
    fOptErr(false),
    fArgErr(false)
{
  if (objc < 0)
    throw Rexception("RtclArgs::<ctor>","Bad args: objc must be >= 0");
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
RtclArgs::RtclArgs(const RtclArgs& rhs)
  : fpInterp(rhs.fpInterp),
    fObjc(rhs.fObjc),
    fObjv(rhs.fObjv),
    fNDone(rhs.fNDone),
    fNOptMiss(rhs.fNOptMiss),
    fOptErr(rhs.fOptErr),
    fArgErr(rhs.fArgErr)
{}
 
//------------------------------------------+-----------------------------------
//! Destructor
 
RtclArgs::~RtclArgs()
{}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
Tcl_Obj* RtclArgs::Objv(size_t ind) const
{
  if (ind >= (size_t)fObjc)
    throw Rexception("RtclArgs::Objv()","Bad args: index out-of-range");
  return fObjv[ind];
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
bool RtclArgs::GetArg(const char* name, Tcl_Obj*& pval)
{
  Tcl_Obj* pobj;
  if (!NextArg(name, pobj)) return false;
  if (pobj==0) return true;
  pval = pobj;
  return true;
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
bool RtclArgs::GetArg(const char* name, const char*& val)
{
  Tcl_Obj* pobj;
  if (!NextArg(name, pobj)) return false;
  if (pobj==0) return true;
  val = Tcl_GetString(pobj);
  return true;
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
bool RtclArgs::GetArg(const char* name, std::string& val)
{
  Tcl_Obj* pobj;
  if (!NextArg(name, pobj)) return false;
  if (pobj==0) return true;
  val = Tcl_GetString(pobj);
  return true;
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
bool RtclArgs::GetArg(const char* name, int8_t& val, int8_t min, int8_t max)
{
  int32_t val32 = (int32_t)val;
  bool ret = GetArg(name, val32, (int32_t)min, (int32_t)max);
  val = (int8_t) val32;
  return ret;
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
bool RtclArgs::GetArg(const char* name, uint8_t& val, uint8_t max, uint8_t min)
{
  uint32_t val32 = (uint32_t)val;
  bool ret = GetArg(name, val32, (uint32_t)max, (uint32_t)min);
  val = (uint8_t) val32;
  return ret;
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
bool RtclArgs::GetArg(const char* name, int16_t& val, int16_t min, int16_t max)
{
  int32_t val32 = (int32_t)val;
  bool ret = GetArg(name, val32, (int32_t)min, (int32_t)max);
  val = (int16_t) val32;
  return ret;
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
bool RtclArgs::GetArg(const char* name, uint16_t& val, uint16_t max, 
                      uint16_t min)
{
  uint32_t val32 = (uint32_t)val;
  bool ret = GetArg(name, val32, (uint32_t)max, (uint32_t)min);
  val = (uint16_t) val32;
  return ret;
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
bool RtclArgs::GetArg(const char* name, int32_t& val, int32_t min, int32_t max)
{
  Tcl_Obj* pobj;
  if (!NextArg(name, pobj)) return false;
  if (pobj==0) return true;
  int objval;
  if (Tcl_GetIntFromObj(fpInterp, pobj, &objval) != TCL_OK) return false;
  if (objval < min || objval > max) {
    ostringstream sos;
    sos << "-E: value '" << objval << "' for '" << name << "' out of range "
        << min << "..." << max;
    AppendResult(sos);
    return false;
  }
  val = (int32_t) objval;
  return true;
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
bool RtclArgs::GetArg(const char* name, uint32_t& val, uint32_t max,
                      uint32_t min)
{
  Tcl_Obj* pobj;
  if (!NextArg(name, pobj)) return false;
  if (pobj==0) return true;
  int objval;
  if (Tcl_GetIntFromObj(fpInterp, pobj, &objval) != TCL_OK) return false;
  unsigned int objuval = objval;
  if (objuval < min || objuval > max) {
    ostringstream sos;
    sos << "-E: value '" << objuval << "' for '" << name << "' out of range "
        << min << "..." << max;
    AppendResult(sos);
    return false;
  }
  val = (uint32_t) objval;
  return true;
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
bool RtclArgs::GetArg(const char* name, float& val, float min, float max)
{
  double vald = (double)val;
  bool ret = GetArg(name, vald, (double)max, (double)min);
  val = (float) vald;
  return ret;
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
bool RtclArgs::GetArg(const char* name, double& val, double min, double max)
{
  Tcl_Obj* pobj;
  if (!NextArg(name, pobj)) return false;
  if (pobj==0) return true;
  double objval;
  if (Tcl_GetDoubleFromObj(fpInterp, pobj, &objval) != TCL_OK) return false;
  if (objval < min || objval > max) {
    ostringstream sos;
    sos << "-E: value '" << objval << "' for '" << name << "' out of range "
        << min << "..." << max;
    AppendResult(sos);
    return false;
  }
  val = objval;
  return true;
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
bool RtclArgs::GetArg(const char* name, std::vector<uint8_t>& val,
                      size_t lmin, size_t lmax)
{
  int objc = 0;
  Tcl_Obj** objv = 0;
  if (!NextArgList(name, objc, objv, lmin, lmax)) return false;
  if (objv==0) return true;
 
  val.clear();
  val.reserve(objc);
 
  for (int i=0; i<objc; i++) {
    int ival;
    if (Tcl_GetIntFromObj(fpInterp, objv[i], &ival) != TCL_OK) return false;
    int ivalmsb = ival>>8;
    if (ivalmsb != 0 && ivalmsb != -1) {
      ostringstream sos;
      sos << "-E: list element '" << Tcl_GetString(objv[i]) 
          << "' for '" << name 
          << "' out of range " << "0...0xff";
      AppendResult(sos);
      return false;
    }
    val.push_back((uint8_t)ival);
  }
  return true;
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
bool RtclArgs::GetArg(const char* name, std::vector<uint16_t>& val,
                      size_t lmin, size_t lmax)
{
  int objc = 0;
  Tcl_Obj** objv = 0;
  if (!NextArgList(name, objc, objv, lmin, lmax)) return false;
  if (objv==0) return true;
 
  val.clear();
  val.reserve(objc);
 
  for (int i=0; i<objc; i++) {
    int ival;
    if (Tcl_GetIntFromObj(fpInterp, objv[i], &ival) != TCL_OK) return false;
    int ivalmsb = ival>>16;
    if (ivalmsb != 0 && ivalmsb != -1) {
      ostringstream sos;
      sos << "-E: list element '" << Tcl_GetString(objv[i]) 
          << "' for '" << name 
          << "' out of range " << "0...0xffff";
      AppendResult(sos);
      return false;
    }
    val.push_back((uint16_t)ival);
  }
  return true;
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
bool RtclArgs::Config(const char* name, std::string& val)
{
  ConfigNameCheck(name);
  string tmp = val;
  if (!GetArg(name, tmp)) return false;
  if (fNOptMiss == 0) {                     // config write
    val = tmp;
  } else {                                  // config read
    if (!ConfigReadCheck()) return false;
    SetResult(Tcl_NewStringObj(val.data(), val.length()));
  }
  return true;
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
bool RtclArgs::Config(const char* name, uint32_t& val, uint32_t max, 
                      uint32_t min)
{
  ConfigNameCheck(name);
  uint32_t tmp = val;
  if (!GetArg(name, tmp, max, min)) return false;
  if (fNOptMiss == 0) {                     // config write
    val = tmp;
  } else {                                  // config read
    if (!ConfigReadCheck()) return false;
    SetResult(Tcl_NewIntObj((int)val));
  }
  return true;
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
bool RtclArgs::NextOpt(std::string& val)
{
  fNOptMiss = 0;
  val.clear();
  fOptErr = false;
 
  if (fNDone == fObjc) return false;
 
  const char* str = PeekArgString(0);
 
  if (str[0]=='-' && str[1] && !isdigit(str[1])) {
    fNDone += 1;
    // '--' seen (eat it, and say no Opt's found)
    if (str[1]=='-' && str[2]==0) {
      return false;
    }
    val = str;
    return true;
  }
  return false;
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
bool RtclArgs::NextOpt(std::string& val, const RtclNameSet& optset)
{
  val.clear();
  string opt;
  if (!NextOpt(opt) || opt.empty()) return false;
 
  fOptErr = !optset.Check(fpInterp, val, opt);
  return !fOptErr;
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
//  irc = 1 -> match
//        0 -> ambiguous match  --> tcl err
//       -1 -> no match         --> no tcl err
 
int RtclArgs::NextSubOpt(std::string& val, const RtclNameSet& optset)
{
  val.clear();
  fNOptMiss = 0;
  fOptErr = false;
 
  if (fNDone == fObjc) return -1;
 
  const char* str = PeekArgString(0);
 
  // does next arg look like an option
  if (str[0]=='-' && str[1]  && str[1]!='-' && !isdigit(str[1])) {
    // and matches one of optset
    int irc = optset.CheckMatch(fpInterp, val, string(str), false);
    if (irc >= 0) {
      fNDone += 1;
      fOptErr = (irc == 0);
      return irc;
    }
  }
  return -1;
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
Tcl_Obj* RtclArgs::CurrentArg() const
{
  if (fNDone == 0)
    throw Rexception("RtclArgs::CurrentArg()",
                     "Bad state: no argument processed yet");
 
  return fObjv[fNDone-1];
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
bool RtclArgs::AllDone()
{
  if (fArgErr || fOptErr) return false;
  if (fNDone < fObjc) {
    AppendResult("-E: superfluous arguments, first one '",
                 Tcl_GetString(fObjv[fNDone]), "'", NULL);
    return false;
  }
  return true;
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
const char* RtclArgs::PeekArgString(int rind) const
{
  int ind = fNDone + rind;
  if (ind < 0 || ind >= (int)fObjc) return "";
  return Tcl_GetString(fObjv[ind]);
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
void RtclArgs::AppendResult(const char* str, ...)
{
  Tcl_AppendResult(fpInterp, str, NULL);
  va_list ap;
  va_start (ap, str);
  Tcl_AppendResultVA(fpInterp, ap);
  va_end (ap);
  return;
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
void RtclArgs::AppendResultLines(const std::string& str)
{
  Rtcl::AppendResultNewLines(fpInterp);
 
  if (str.length()>0 && str[str.length()-1]=='\n') {
    Tcl_AppendResult(fpInterp, str.substr(0,str.length()-1).c_str(), NULL);
  } else {
    Tcl_AppendResult(fpInterp, str.c_str(), NULL);
  }
  return;
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
bool RtclArgs::NextArg(const char* name, Tcl_Obj*& pobj)
{
  pobj = 0;
 
  bool isopt    = name[0] == '?';
  bool isoptopt = isopt && (name[1] == '?');
 
  if (!isopt) fNOptMiss = 0;
 
  if (fNDone == fObjc) {
    if (!isopt) {
      AppendResult("-E: required argument '", name, "' missing", NULL);
      fArgErr = true;
      return false;
    }
    fNOptMiss += 1;
    return true;
  }
 
  // if %% arg peek in next arg and check that it's not an option
  if (isoptopt) {
    const char* nval = Tcl_GetString(fObjv[fNDone]);
    if (nval[0]=='-' && nval[1] && isalpha(nval[1])) {
      fNOptMiss += 1;
      return true;
    }
  }
 
  pobj = fObjv[fNDone++];
 
  return true;
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
bool RtclArgs::NextArgList(const char* name, int& objc, Tcl_Obj**& objv,
                           size_t lmin, size_t lmax)
{
  objc = 0;
  objv = 0;
  Tcl_Obj* pobj = 0;
  if (!NextArg(name, pobj)) return false;
  if (pobj==0) return true;
 
  if (Tcl_ListObjGetElements(fpInterp, pobj, &objc, &objv) != TCL_OK) {
    return false;
  }
 
  if ((size_t)objc < lmin || (size_t)objc > lmax) {
    ostringstream sos;
    sos << "-E: list length '" << objc << "' for '" << name << "' out of range "
        << lmin << "..." << lmax;
    AppendResult(sos);
    return false;
  }
  return true;
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
void RtclArgs::ConfigNameCheck(const char* name)
{
  if (name==0 || name[0]!='?' || name[1]!='?')
    throw Rexception("RtclArgs::Config()","Bad args: name must start with ??");
  return;
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
bool RtclArgs::ConfigReadCheck()
{
  if (fNConfigRead != 0) {
    SetResult(Tcl_NewObj());
    AppendResult("-E: only one config read allowed per command, '", 
                 PeekArgString(-1), "' is second", NULL);
    return false;
  }
  fNConfigRead += 1;
  return true;
}
 
} // end namespace Retro
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.