Example in C++


The AreaCompute application

The program AreaCompute is a small application which demonstrates some of the TDRP functionality.

AreaCompute computes the area of a shape of a given size. The size is set in the parameter file. The user may choose one of three shapes, a square, circle or equilateral triangle. The area is computed and the result is written to a file. The file path is also set in the parameter file.

All of the parameters may be overridden by command line arguments.


Paramdef file - paramdef.AreaCompute

/*********************************************************
 * parameter definitions for AreaCompute
 *
 * Mike Dixon, RAP, NCAR, Boulder, CO, USA, 80307-3000
 *
 * Sept 1998
 */

/*
 * AreaCompute is a small TDRP demonstration program.
 *
 * The program allows the user to compute the area of
 * a geometric shape of a given size.
 *
 * The result is printed to a file.
 */

//////////////////////////////////////////////////////////

paramdef boolean {
  p_default = FALSE;
  p_descr = "Option to print debugging messages";
} debug;

typedef enum {
  SQUARE, CIRCLE, EQ_TRIANGLE
} shape_t ;

paramdef enum shape_t {
  p_default = SQUARE;
  p_descr = "Shape type.";
  p_help = "The program will compute the area of a square,"
  "circle or equilateral triangle.";
} shape;

paramdef float {
  p_default = 1.0;
  p_min = 0.0;
  p_descr = "Size of the shape.";
} size;

paramdef string {
  p_default = "./AreaCompute.out";
  p_descr = "The path of the file to which the output is written.";
  p_help = "The directory which contains this path must exist.";
} output_path;


Parameter file - AreaCompute.params

The following was generated by running:
  AreaCompute -print_params > file
/**********************************************************************
 * TDRP params for AreaCompute
 **********************************************************************/

///////////// debug ///////////////////////////////////
//
// Option to print debugging messages.
// Type: boolean
//

debug = FALSE;

///////////// shape ///////////////////////////////////
//
// Shape type.
// The program will compute the area of a square, circle or equilateral 
//   triangle.
//
// Type: enum
// Options:
//   SQUARE, CIRCLE, EQ_TRIANGLE
//
//

shape = SQUARE;

///////////// size ////////////////////////////////////
//
// Size of the shape.
// Minimum val: 0
// Type: float
//

size = 1;

///////////// output_path /////////////////////////////
//
// The path of the file to which the output is written.
// The directory which contains this path must exist.
// Type: string
//

output_path = "./AreaCompute.out";

Main driver - Main.cc

#include "AreaCompute.hh"

// file scope

static void tidy_and_exit (int sig);
static AreaCompute *Prog;

// main

int main(int argc, char **argv)

{

  // create program object

  AreaCompute *Prog;
  Prog = new AreaCompute(argc, argv);
  if (!Prog->OK) {
    return(-1);
  }

  // run it

  int iret = Prog->Run();

  // clean up

  tidy_and_exit(iret);
  return (iret);
  
}

// tidy up on exit

static void tidy_and_exit (int sig)

{
  delete(Prog);
  exit(sig);
}

AreaCompute class header file - AreaCompute.hh

#include 

#include "Args.hh"
#include "Params.hh"

class AreaCompute {
  
public:

  // constructor

  AreaCompute (int argc, char **argv);

  // destructor
  
  ~AreaCompute();

  // run 

  int Run();

  // data members

  int OK;

protected:
  
private:

  char *_progName;
  char *_paramsPath;
  Args *_args;
  Params *_params;
  double _area;

  int AreaCompute::_writeResults();

};

AreaCompute class code file - AreaCompute.cc

#include "AreaCompute.hh"
#include 
#include 

// Constructor

AreaCompute::AreaCompute(int argc, char **argv)

{

  OK = TRUE;

  // set programe name

  _progName = strdup("AreaCompute");

  // get command line args
  
  _args = new Args(argc, argv, _progName);
  if (!_args->OK) {
    fprintf(stderr, "ERROR: %s\n", _progName);
    fprintf(stderr, "Problem with command line args\n");
    OK = FALSE;
    return;
  }

  // get TDRP params

  _params = new Params();
  _paramsPath = "unknown";
  if (_params->loadFromArgs(argc, argv,
			    _args->override.list,
			    &_paramsPath)) {
    fprintf(stderr, "ERROR: %s\n", _progName);
    fprintf(stderr, "Problem with TDRP parameters\n");
    OK = FALSE;
    return;
  }

  return;

}

// destructor

AreaCompute::~AreaCompute()

{

  // free up

  delete(_params);
  delete(_args);
  free(_progName);
  
}

//////////////////////////////////////////////////
// Run

int AreaCompute::Run()
{

  // compute area

  switch (_params->shape) {
    
  case SQUARE:
    _area = _params->size * _params->size;
    break;

  case CIRCLE:
    _area = _params->size * _params->size * (3.14159 / 4.0);
    break;

  case EQ_TRIANGLE:
    _area = _params->size * _params->size * (0.866 / 2.0);
    break;

  } // switch

  // debug message

  if (_params->debug) {
    fprintf(stderr, "Size is: %g\n", _params->size);
    switch (_params->shape) {
    case SQUARE:
      fprintf(stderr, "Shape is SQUARE\n");
      break;
    case CIRCLE:
      fprintf(stderr, "Shape is CIRCLE\n");
      break;
    case EQ_TRIANGLE:
      fprintf(stderr, "Shape is EQ_TRIANGLE\n");
      break;
    } /* switch */
    fprintf(stderr, "Area is: %g\n", _area);
  }
  
  // write out the result
  
  _writeResults();

  return (0);

}

//////////////////////////////////////////////////
// writeResults

int AreaCompute::_writeResults()

{

  FILE *out;

  if ((out = fopen(_params->output_path, "w")) == NULL) {
    perror(_params->output_path);
    return (-1);
  }

  fprintf(out, "Size is: %g\n", _params->size);
  switch (_params->shape) {
  case SQUARE:
    fprintf(out, "Shape is SQUARE\n");
    break;
  case CIRCLE:
    fprintf(out, "Shape is CIRCLE\n");
    break;
  case EQ_TRIANGLE:
    fprintf(out, "Shape is EQ_TRIANGLE\n");
    break;
  } /* switch */
  fprintf(out, "Area is: %g\n", _area);

  fclose(out);

  return (0);

}

Parsing the command line - Args.hh

#include 
#include 

class Args {
  
public:

  // constructor

  Args (int argc, char **argv, char *prog_name);

  // Destructor

  ~Args();

  // public data

  int OK;
  tdrp_override_t override;

protected:
  
private:

  void _usage(char *prog_name, FILE *out);
  
};


Parsing the command line - Args.cc

#include "Args.hh"
#include 

// Constructor

Args::Args (int argc, char **argv, char *prog_name)

{

  char tmp_str[BUFSIZ];

  // intialize

  OK = TRUE;
  TDRP_init_override(&override);
  
  // loop through args
  
  for (int i =  1; i < argc; i++) {

    if (!strcmp(argv[i], "-h")) {
  
      _usage(prog_name, stdout);
      exit(0);
      
    } else if (!strcmp(argv[i], "-debug")) {
      
      sprintf(tmp_str, "debug = TRUE;");
      TDRP_add_override(&override, tmp_str);
      
    } else if (!strcmp(argv[i], "-size")) {
      
      if (i < argc - 1) {
        sprintf(tmp_str, "size = %s;", argv[++i]);
	TDRP_add_override(&override, tmp_str);
      } else {
	OK = FALSE;
      }
	
    } else if (!strcmp(argv[i], "-shape")) {
      
      if (i < argc - 1) {
        sprintf(tmp_str, "shape = %s;", argv[++i]);
	TDRP_add_override(&override, tmp_str);
      } else {
	OK = FALSE;
      }
	
    } else if (!strcmp(argv[i], "-output")) {
      
      if (i < argc - 1) {
        sprintf(tmp_str, "output_path = %s;", argv[++i]);
	TDRP_add_override(&override, tmp_str);
      } else {
	OK = FALSE;
      }
	
    } // if
    
  } // i
  
  if (!OK) {
    _usage(prog_name, stderr);
  }
    
}

// Destructor

Args::~Args ()

{

  TDRP_free_override(&override);

}
  
void Args::_usage(char *prog_name, FILE *out)
{

  fprintf(out, "%s%s%s%s",
	  "Usage: ", prog_name, " [options as below]\n",
	  "   [ -h] produce this list.\n"
	  "   [ -debug ] print debug messages\n"
	  "   [ -output ?] set output_path\n"
	  "   [ -size ?] set shape size\n"
	  "   [ -shape ?] set shape type\n"
	  "      options are SQUARE, CIRCLE and EQ_TRIANGLE\n");

  TDRP_usage(out);

}

The Makefile

PROGNAME = AreaCompute

CPPC = g++
RM = /bin/rm -f
INCLUDES = -I../include
CFLAGS = -g
LDFLAGS = -L.. -ltdrp

SRCS = \
	Params.cc \
	AreaCompute.cc \
	Args.cc \
	Main.cc

OBJS = $(SRCS:.cc=.o)

# link

$(PROGNAME): $(OBJS)
	$(CPPC) -o $(PROGNAME) $(OBJS) $(LDFLAGS)

# tdrp

Params.cc: paramdef.$(PROGNAME)
	tdrp_gen -f paramdef.$(PROGNAME) -c++ -prog $(PROGNAME)

clean_tdrp:
	$(RM) Params.hh Params.cc

clean:
	$(RM) core a.out
	$(RM) *.i *.o  *.ln *~

clean_bin:
	$(RM) $(PROGNAME)

clean_all: clean clean_bin

# suffix rules

.SUFFIXES: .c .o

.cc.o:
	$(CPPC) -c $(CFLAGS) $(INCLUDES) $<


The TDRP Params class header file - Params.hh

#include 
#include 

// typedefs

// Class definition

class Params {

public:

  // enum typedefs

  typedef enum {
    SQUARE = 0,
    CIRCLE = 1,
    EQ_TRIANGLE = 2
  } shape_t;

  // Member functions

  Params() { _init(); }

  ~Params() { freeAll(); }

  int loadFromArgs(int argc, char **argv,
                   char **override_list,
                   char **params_path_p);

  int load(char *param_file_path,
           char **override_list,
           int expand_env, int debug);

  int loadDefaults(int expand_env);

  void sync();

  void print(FILE *out, tdrp_print_mode_t mode);

  int checkAllSet(FILE *out);

  int arrayRealloc(char *param_name,
                   int new_array_n);

  int array2DRealloc(char *param_name,
                     int new_array_n1,
                     int new_array_n2);

  void freeAll(void);

  // Data members

  char _start_; // start of data region
                // needed for zeroing out data
                // and computing offsets

  tdrp_bool_t debug;

  shape_t shape;

  float size;

  char* output_path;

  char _end_; // end of data region
              // needed for zeroing out data

private:

  void _init();

  TDRPtable _table[5];

  char *_className;
};

The TDRP Params class code - Params.cc

#include "Params.hh"
#include 

//////////////////////////////////////////////////////////////
// loadFromArgs()
//
// Loads up TDRP using the command line args.
//
// Check TDRP_usage() for command line actions associated with
// this function.
//
//   argc, argv: command line args
//
//   char **override_list: A null-terminated list of overrides
//     to the parameter file.
//     An override string has exactly the format of an entry
//     in the parameter file itself.
//
//   char **params_path_p: if non-NULL, this is set to point to
//                         the path of the params file used.
//
//  Returns 0 on success, -1 on failure.
//

int Params::loadFromArgs(int argc, char **argv,
                         char **override_list,
                         char **params_path_p)
{
  if (tdrpLoadFromArgs(argc, argv,
                       _table, &_start_,
                       override_list, params_path_p)) {
    return (-1);
  } else {
    return (0);
  }
}

//////////////////////////////////////////////////////////////
// load()
//
// Loads up TDRP for a given class.
//
// This version of load gives the programmer the option to load
// up more than one class for a single application. It is a
// lower-level routine than loadFromArgs,
// and hence more flexible, but the programmer must do more work.
//
//   char *param_file_path: the parameter file to be read in.
//
//   char **override_list: A null-terminated list of overrides
//     to the parameter file.
//     An override string has exactly the format of an entry
//     in the parameter file itself.
//
//  expand_env: flag to control environment variable
//                expansion during tokenization.
//              If TRUE, environment expansion is set on.
//              If FALSE, environment expansion is set off.
//
//  Returns 0 on success, -1 on failure.
//

int Params::load(char *param_file_path,
                 char **override_list,
                 int expand_env, int debug)
{
  if (tdrpLoad(param_file_path,
               _table, &_start_,
               override_list,
               expand_env, debug)) {
    return (-1);
  } else {
    return (0);
  }
}

//////////////////////////////////////////////////////////////
// loadDefaults()
//
// Loads up default params for a given class.
//
// See load() for more detailed info.
//
//  Returns 0 on success, -1 on failure.
//

int Params::loadDefaults(int expand_env)
{
  if (tdrpLoad(NULL,
               _table, &_start_,
               NULL, expand_env, FALSE)) {
    return (-1);
  } else {
    return (0);
  }
}

//////////////////////////////////////////////////////////////
// sync()
//
// Syncs the user struct data back into the parameter table,
// in preparation for printing.
//

void Params::sync(void)
{
  tdrpUser2Table(_table, &_start_);
}

//////////////////////////////////////////////////////////////
// print()
// 
// Print params file
//
// The modes supported are:
//
//   PRINT_SHORT:   main comments only, no help or descriptions
//                  structs and arrays on a single line
//   PRINT_NORM:    short + descriptions and help
//   PRINT_LONG:    norm  + arrays and structs expanded
//   PRINT_VERBOSE: long  + private params included
//

void Params::print(FILE *out, tdrp_print_mode_t mode)
{
  tdrpPrint(out, _table, _className, mode);
}

//////////////////////////////////////////////////////////////
// checkAllSet()
//
// Return TRUE if all set, FALSE if not.
//
// If out is non-NULL, prints out warning messages for those
// parameters which are not set.
//

int Params::checkAllSet(FILE *out)
{
  return (tdrpCheckAllSet(out, _table, &_start_));
}

//////////////////////////////////////////////////////////////
// freeAll()
//
// Frees up all TDRP dynamic memory.
//

void Params::freeAll(void)
{
  tdrpFreeAll(_table, &_start_);
}

//////////////////////////////////////////////////////////////
// arrayRealloc()
//
// Realloc 1D array.
//
// If size is increased, the values from the last array entry is
// copied into the new space.
//
// Returns 0 on success, -1 on error.
//

int Params::arrayRealloc(char *param_name, int new_array_n)
{
  if (tdrpArrayRealloc(_table, &_start_,
                       param_name, new_array_n)) {
    return (-1);
  } else {
    return (0);
  }
}

//////////////////////////////////////////////////////////////
// array2DRealloc()
//
// Realloc 2D array.
//
// If size is increased, the values from the last array entry is
// copied into the new space.
//
// Returns 0 on success, -1 on error.
//

int Params::array2DRealloc(char *param_name,
                           int new_array_n1,
                           int new_array_n2)
{
  if (tdrpArray2DRealloc(_table, &_start_, param_name,
                         new_array_n1, new_array_n2)) {
    return (-1);
  } else {
    return (0);
  }
}

//////////////////////////////////////////////////////////////
// _init()
//
// Class table initialization function.
//
//

void Params::_init()

{

  TDRPtable *tt = _table;

  // zero out table

  memset(_table, 0, sizeof(_table));

  // zero out members

  memset(&_start_, 0, &_end_ - &_start_);

  _className = "Params";
  // Parameter 'debug'
  // ctype is 'tdrp_bool_t'
  
  memset(tt, 0, sizeof(TDRPtable));
  tt->ptype = BOOL_TYPE;
  tt->param_name = tdrpStrDup("debug");
  tt->descr = tdrpStrDup("Option to print debugging messages");
  tt->help = tdrpStrDup("");
  tt->val_offset = (char *) &debug - &_start_;
  tt->single_val.b = pFALSE;
  tt++;
  
  // Parameter 'shape'
  // ctype is '_shape_t'
  
  memset(tt, 0, sizeof(TDRPtable));
  tt->ptype = ENUM_TYPE;
  tt->param_name = tdrpStrDup("shape");
  tt->descr = tdrpStrDup("Shape type.");
  tt->help = tdrpStrDup("The program will compute the area of a square, circle or equilateral triangle.");
  tt->val_offset = (char *) &shape - &_start_;
  tt->enum_def.name = tdrpStrDup("shape_t");
  tt->enum_def.nfields = 3;
  tt->enum_def.fields = (enum_field_t *)
      tdrpMalloc(tt->enum_def.nfields * sizeof(enum_field_t));
    tt->enum_def.fields[0].name = tdrpStrDup("SQUARE");
    tt->enum_def.fields[0].val = SQUARE;
    tt->enum_def.fields[1].name = tdrpStrDup("CIRCLE");
    tt->enum_def.fields[1].val = CIRCLE;
    tt->enum_def.fields[2].name = tdrpStrDup("EQ_TRIANGLE");
    tt->enum_def.fields[2].val = EQ_TRIANGLE;
  tt->single_val.e = SQUARE;
  tt++;
  
  // Parameter 'size'
  // ctype is 'float'
  
  memset(tt, 0, sizeof(TDRPtable));
  tt->ptype = FLOAT_TYPE;
  tt->param_name = tdrpStrDup("size");
  tt->descr = tdrpStrDup("Size of the shape.");
  tt->help = tdrpStrDup("");
  tt->val_offset = (char *) &size - &_start_;
  tt->has_min = TRUE;
  tt->min_val.f = 0;
  tt->max_val.f = 1e+33;
  tt->single_val.f = 1;
  tt++;
  
  // Parameter 'output_path'
  // ctype is 'string'
  
  memset(tt, 0, sizeof(TDRPtable));
  tt->ptype = STRING_TYPE;
  tt->param_name = tdrpStrDup("output_path");
  tt->descr = tdrpStrDup("The path of the file to which the output is written.");
  tt->help = tdrpStrDup("The directory which contains this path must exist.");
  tt->val_offset = (char *) &output_path - &_start_;
  tt->single_val.s = tdrpStrDup("./AreaCompute.out");
  tt++;
  
  // trailing entry has param_name set to NULL
  
  tt->param_name = NULL;
  
  return;

}