Example in C

The area_compute application

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

area_compute 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.area_compute

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

/*
 * area_compute 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 = "./area_compute.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 - area_compute.params

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

///////////// 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 = "./area_compute.out";

Main header file - area_compute.h

#include 
#include 
#include "_tdrp.h"

/*
 * function prototypes
 */

extern void parse_args(int argc,
		       char **argv,
		       char *prog_name,
		       tdrp_override_t *override);

extern int write_result(_tdrp_struct *params, double area);

Main c file - area_compute.c

#include "area_compute.h"

int main(int argc, char **argv)

{
  
  /*
   * basic declarations
   */

  char *prog_name;
  char *params_file_path = NULL;
  tdrp_override_t override;
  _tdrp_struct params;   /* parameter struct */
  double area;

  /*
   * set program name
   */
  
  prog_name = strrchr(argv[0], '/');
  if (prog_name == NULL) {
    prog_name = argv[0];
  }

  /*
   * initialize the override list
   */
  
  TDRP_init_override(&override);

  /*
   * parse command line arguments
   */
  
  parse_args(argc, argv, prog_name, &override);
  
  /*
   * load up parameters
   */
  
  if (_tdrp_load_from_args(argc, argv, ¶ms,
			   override.list, ¶ms_file_path)) {
    fprintf(stderr, "ERROR - %s:main\n", prog_name);
    if (params_file_path) {
      fprintf(stderr, "Problems with params file '%s'\n",
	      params_file_path);
    }
    exit(-1);
  }

  /*
   * free up override list
   */
  
  TDRP_free_override(&override);

  /*
   * 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
   */
  
  write_result(¶ms, area);

  /*
   * Free up
   */

  _tdrp_free_all();

  return(0);

}

Parsing the command line - parse_args.c

#include "area_compute.h"

static void 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);
  
}

void parse_args(int argc,
		char **argv,
		char *prog_name,
                tdrp_override_t *override)

{

  int error_flag = 0;
  int i;
  char tmp_str[BUFSIZ];
  
  /*
   * look for command options
   */

  for (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 {
	error_flag = TRUE;
      }
	
    } else if (!strcmp(argv[i], "-shape")) {
      
      if (i < argc - 1) {
        sprintf(tmp_str, "shape = %s;", argv[++i]);
	TDRP_add_override(override, tmp_str);
      } else {
	error_flag = TRUE;
      }
	
    } 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 {
	error_flag = TRUE;
      }
	
    } /* if */
    
  } /* i */
  
  /*
   * print message if error flag set
   */

  if(error_flag) {
    usage(prog_name, stderr);
    exit(-1);
  }

  return;

}

Writing out the results - write_result.c

#include "area_compute.h"

int write_result(_tdrp_struct *params, double area)

{

  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);

}

The Makefile

PROGNAME = area_compute

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

SRCS = \
	_tdrp.c \
	write_result.c \
	parse_args.c \
	area_compute.c

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

# link

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

# tdrp

_tdrp.c: paramdef.$(PROGNAME)
	tdrp_gen -f paramdef.$(PROGNAME) -prog $(PROGNAME)

clean_tdrp:
	$(RM) _tdrp.h _tdrp.c

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

clean_bin:
	$(RM) $(PROGNAME)

clean_all: clean clean_bin clean_tdrp

# suffix rules

.SUFFIXES: .c .o

.c.o:
	$(CC) -c $(CFLAGS) $(INCLUDES) $<

The TDRP header file - _tdrp.h

/*******************************************
 * _tdrp.h
 *
 * TDRP header file.
 *
 * Code for program area_compute
 *
 * This header file has been automatically
 * generated by TDRP, do not modify.
 *
 *******************************************/

#ifndef __tdrp_h
#define __tdrp_h

#ifdef __cplusplus
extern "C" {
#endif

#include 

/*
 * typedefs
 */

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

/*
 * typedef for main struct - _tdrp_struct
 */

typedef struct {

  size_t struct_size;

  /***** debug *****/

  tdrp_bool_t debug;

  /***** shape *****/

  _shape_t shape;

  /***** size *****/

  float size;

  /***** output_path *****/

  char* output_path;

} _tdrp_struct;

/*
 * function prototypes
 */

extern int _tdrp_load_from_args(int argc, char **argv,
                                _tdrp_struct *params,
                                char **override_list,
                                char **params_path_p);

extern int _tdrp_load(char *param_file_path,
                      _tdrp_struct *params,
                      char **override_list,
                      int expand_env, int debug);

extern int _tdrp_load_defaults(_tdrp_struct *params,
                               int expand_env);

extern void _tdrp_sync(void);

extern void _tdrp_print(FILE *out, tdrp_print_mode_t mode);

extern void _tdrp_free_all(void);

extern int _tdrp_check_all_set(FILE *out);

extern int _tdrp_array_realloc(char *param_name, int new_array_n);
 
extern int _tdrp_array2D_realloc(char *param_name,
                                 int new_array_n1,
                                 int new_array_n2);

extern TDRPtable *_tdrp_table(void);

extern TDRPtable *_tdrp_init(_tdrp_struct *params);

#ifdef __cplusplus
}
#endif

#endif

The TDRP C code - _tdrp.c

/*******************************************
 * _tdrp.c
 *
 * TDRP C code file.
 *
 * Code for program area_compute
 *
 * This file has been automatically
 * generated by TDRP, do not modify.
 *
 *******************************************/

#include "_tdrp.h"
#include 

/*
 * file scope variables
 */

static TDRPtable Table[5];
static _tdrp_struct *Params;
static char *Module = "";

/*************************************************************
 * _tdrp_load_from_args()
 *
 * Loads up TDRP using the command line args.
 *
 * Check TDRP_usage() for command line actions associated with
 * this function.
 *
 *   argc, argv: command line args
 *
 *   _tdrp_struct *params: loads up this struct
 * 
 *   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 _tdrp_load_from_args(int argc, char **argv,
                         _tdrp_struct *params,
                         char **override_list,
                         char **params_path_p)
{
  Params = params;
  _tdrp_init(Params);
  if (tdrpLoadFromArgs(argc, argv,
                       Table, Params,
                       override_list, params_path_p)) {
    return (-1);
  } else {
    return (0);
  }
}

/*************************************************************
 * _tdrp_load()
 *
 * Loads up TDRP for a given module.
 *
 * This version of load gives the programmer the option to load
 * up more than one module for a single application. It is a
 * lower-level routine than _tdrp_load_from_args,
 * and hence more flexible, but the programmer must do more work.
 *
 *   char *param_file_path: the parameter file to be read in.
 *
 *   _tdrp_struct *params: loads up this struct
 *
 *   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 _tdrp_load(char *param_file_path,
               _tdrp_struct *params,
               char **override_list,
               int expand_env, int debug)
{
  Params = params;
  _tdrp_init(Params);
  if (tdrpLoad(param_file_path, Table,
               params, override_list,
               expand_env, debug)) {
    return (-1);
  } else {
    return (0);
  }
}

/*************************************************************
 * _tdrp_load_defaults()
 *
 * Loads up defaults for a given module.
 *
 * See _tdrp_load() for more details.
 *
 *  Returns 0 on success, -1 on failure.
 */

int _tdrp_load_defaults(_tdrp_struct *params,
                        int expand_env)
{
  Params = params;
  _tdrp_init(Params);
  if (tdrpLoad(NULL, Table,
               params, NULL,
               expand_env, FALSE)) {
    return (-1);
  } else {
    return (0);
  }
}

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

void _tdrp_sync(void)
{
  tdrpUser2Table(Table, Params);
}

/*************************************************************
 * _tdrp_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 _tdrp_print(FILE *out, tdrp_print_mode_t mode)
{
  tdrpPrint(out, Table, Module, mode);
}

/*************************************************************
 * _tdrp_check_all_set()
 *
 * 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 _tdrp_check_all_set(FILE *out)
{
  return (tdrpCheckAllSet(out, Table, Params));
}

/*************************************************************
 * _tdrp_free_all()
 *
 * Frees up all TDRP dynamic memory.
 */

void _tdrp_free_all(void)
{
  tdrpFreeAll(Table, Params);
}

/*************************************************************
 * _tdrp_array_realloc()
 *
 * 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 _tdrp_array_realloc(char *param_name, int new_array_n)
{
  if (tdrpArrayRealloc(Table, Params, param_name, new_array_n)) {
    return (-1);
  } else {
    return (0);
  }
}

/*************************************************************
 * _tdrp_array2D_realloc()
 *
 * 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 _tdrp_array2D_realloc(char *param_name,
                          int new_array_n1,
                          int new_array_n2)
{
  if (tdrpArray2DRealloc(Table, Params, param_name,
			 new_array_n1, new_array_n2)) {
    return (-1);
  } else {
    return (0);
  }
}

/*************************************************************
 * _tdrp_table()
 *
 * Returns pointer to static Table for this module.
 */

TDRPtable *_tdrp_table(void)
{
  return (Table);
}

/*************************************************************
 * _tdrp_init()
 *
 * Module table initialization function.
 *
 *
 * Returns pointer to static Table for this module.
 */

TDRPtable *_tdrp_init(_tdrp_struct *params)

{

  TDRPtable *tt = Table;

  _tdrp_struct pp; /* for computing byte_offsets */

  /* zero out struct, and store size */

  memset(params, 0, sizeof(_tdrp_struct));
  params->struct_size = sizeof(_tdrp_struct);

  /* 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 *) &(pp.debug) - (char *) &pp;
  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 *) &(pp.shape) - (char *) &pp;
  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 *) &(pp.size) - (char *) &pp;
  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 *) &(pp.output_path) - (char *) &pp;
  tt->single_val.s = tdrpStrDup("./area_compute.out");
  tt++;
  
  /* trailing entry has param_name set to NULL */
  
  tt->param_name = NULL;
  
  return (Table);

}