/***********************************************************************
                   B P   A M E R I C A  
           PROPRIETARY - TO BE MAINTAINED IN CONFIDENCE 
                         COPYRIGHTED 2006
 ***********************************************************************

                           TEMPLATE 2

     FORTRAN TEMPLATE DEMONSTRATING THE USE OF DDS CONVENIENCE 
     ROUTINES FOR A SIMPLE TRACE-TO-TRACE PROCESSING SCHEME 
     WITHOUT USING OR PASSING ANY TRACE HEADERS.

     Use a file extension of ".F" instead of ".f" to pull in the 
     compiler preprocessor.

     Written by Jerry Ehlers November 2006

 **********************************************************************/

#define _POSIX_SOURCE 1    /* Check POSIX Standard            */
#define ANSI               /* Turn on prototyping from cdds.h */

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <math.h>
/*
   INCLUDE THE DDS API (Application Program Interface)
 */
#include <cdds.h>           /* "C" dds include */

#define RCSID "$Id: c_template2.html 1 2009-01-06 00:31:13Z ehlersjw $"
#define TITLE "template2: C template using DDS convenience routines"

void doit(int, int, int, float, float*);

/***********************************************************************
 *
 * main
 *
 **********************************************************************/
int main(int argc, char **argv)
{
   BIN_TAG in_bin=-1, out_bin=-1;
   int ier, ns;
   float scale, *buf;
   char *prog;

   /***********************************************************************
    *    initialize
    **********************************************************************/
   /*
    * get the program name
    */
   prog = strrchr(argv[0], '/');
   if (prog) prog++;
   else prog = argv[0];

   /*
    * pass the command line arguments on to DDS
    */
   setargcv(argc, argv);
   /*
      OPEN THE PRINT FILE & CHECK FOR HELP 
      'cdds_openpr' function:
           Open a printfile using the information automatically 
           generated by RCS in '$Id: c_template2.html 1 2009-01-06 00:31:13Z ehlersjw $'.  If the user specifies some
           form of help (-h help= HELP=...) on the command line,
           then the return value will be < 0.
    */
   ier = cdds_openpr(prog, RCSID);
   if (ier > 0) help();

   /***********************************************************************
    *    open input data file
    **********************************************************************/
   /*    
      OPEN THE INPUT DATASET 
      'cddx_in' function:
           This function opens the input file, with data Samples only 
           as real values (unless input is complex).
    */
   in_bin = cddx_in("in", "stdin:", TITLE);
   /*
      PRINT ERROR MESSAGE
      'cdds_prterr' function:
           Print an error message to the console (& printfile if 
           exists). Error count is kept by DDS.  Check for errors later,  
           before processing to check for as many things as possible first.
    */
   if (in_bin < 0) {
      cdds_prterr("Unable to open input data\n");
   }
   /*
      RETRIEVE DATASET DEFINITIONS NEEDED BY APPLICATION 
      'cdds_scanf' function:
           Default values are assigned prior to definition retrieval.
           A variable are unchanged, if it is not specified.

           NOTE: What's special about the "size.axis(1)" definition?
           'axis(N)' is automatically converted to the Nth axis name.
           This allows hyper cube attributes to be retrieved by axis
           number, instead of axis name.  For example, "size.axis(1)"
           becomes "size.t" (assuming "axis=  t x y").

           WARNING: Do NOT use %i, use %d to scan for integers because
                    %i will interpret a value with a leading "0" as 
                    octal instead decimal (eg. 010 would be read as
                    8 instead of 10).
    */
   /*
    *    Get input data parameters
    */
   cdds_scanf("size.axis(1)", "%d", &ns);

   /***********************************************************************
    *    read parameters
    **********************************************************************/
   /*
      RETRIEVE COMMAND LINE PARAMETERS
      'cdds_dict' function:
           'cdds_dict' selects the 'par:' dictionary for scanning.
           This dictionary only contains definitions from the command
           line, and parameter dictionaries ("par=  fn1  fn2 ...").
           Parameters ("in= ", "out_format= ", etc.) for the current
           process can be read, without ambiguity from the input history 
           (ie. local parameters only).
    */
   cdds_dict("par:", "scan");

   /*
    * get scale parameter (default 1.0)
    */
   scale = 1.0;
   cdds_scanf("scale", "%f", &scale);

   /***********************************************************************
    *    print user parameters
    **********************************************************************/
   /*
      PRINT MESSAGES 
      'cdds_prtmsg' function:
           This function prints a formatted message to the print file
           opened by "cdds_openpr"; otherwise to the console (stderr).

      'cdds_prtcon' function:
           This function prints a formatted message to the console and
           to the print file if opened.
   
      'cdds_prtmsg' function:
           This function prints a formatted error message to the console 
           and to the print file if opened.  It also keeps track of the
           number of error messages printed for "cdds_closepr".
    */
   cdds_prtmsg("\n*** USER PARAMETERS ***\n\n");
   cdds_prtmsg("\tscale = %g\n", scale);
   cdds_prtmsg("\n");

   /*
    * Check parameters
    */
   if (scale < 0.0) {
      cdds_prtcon("WARNING: \"scale\" is negative!\n");
   }

   /***********************************************************************
    *    allocate dynamic arrays
    **********************************************************************/
   /*
      Don't allocate arrays if there are already any errors; 
      we could have bad array sizes
    */ 
   if (cdds_errors()) goto finish;
   /*
      ALLOCATE DYNAMIC ARRAYS 
      'cdds_malloc' function:
           This function allocates memory or reports an error & aborts.
           Storage can be released by calling "cdds_free".  Use 
           "dds_debug= dbg_call" will cause DDS to check memory at
           each api call.
   */
   /*
    * Allocate memory for a single trace 
    */
   buf = cdds_malloc(ns * sizeof(float));

   /***********************************************************************
    *    open output dataset
    **********************************************************************/
   /*
      CHECK FOR ERRORS BEFORE PROCEEDING ANY FURTHER 
      'cdds_errors' function:
           This function returns the number of errors reported using
           "cdds_prterr".  No reason to create a new output if there
           have been any errors.
    */
   if (cdds_errors()) goto finish;
   /*
      CREATE OUTPUT FROM INPUT DICTIONARY 
      'cddx_out' function:
           This function will create an output dataset from the input
           binary, passing all it's history information along.  
           The user can override the output format and binary data by 
           defining "out_format=" or "out_data=" since the first
           argument is 'out'.

           With the output convenience routines, the binaries are not 
           actually opened until the binary tag is first used for I/O. 
           This way the internal buffer definitions for the output file
           can be redefined (eg. axis, size, delta, origin...).  So no
           need to check out_bin until after it really gets opened.
    */
   out_bin = cddx_out("out", "stdout:", TITLE, in_bin);
   /*
      FORCE OPEN THE OUTPUT BINARIES
      'cdds_lseek' function:
          This function seeks to a specific trace position.  It is used 
          here simply to force open the internal and output binaries.
          Now we can check if it was really opened.
    */
   ier = cdds_lseek(out_bin, 0, 0, SEEK_SET);
   if (ier < 0) {
      cdds_prterr("Unable to open output dataset!\n");
   }

   /***********************************************************************
    *    process the data
    **********************************************************************/

   if (cdds_errors()) goto finish;

   doit(in_bin, out_bin, ns, scale, buf);

   /***********************************************************************
    *    close files, clean-up, & exit
    **********************************************************************/
   /*
      CLOSE OUT
      'cdds_close' function:
           This function closes a dataset if the binary tag is >= 0
           including all underlying dictionaries and data structures.
           This will also flush out all DDS data buffers out to the
           kernel.

      'cdds_closepr' function:
           This function will close out the print file (if opened)
           adding diagnosti  information, unread command line 
           parameters and termination status.  It will also exit
           the program giving a usable status code.
    */
finish:
   cdds_close(in_bin);
   cdds_close(out_bin);

   cdds_closepr();
}

/***********************************************************************
 * 
 *		doit
 *
 **********************************************************************/
void doit(int in_bin, int out_bin, int ns, float scale, float* buf)
{
   int ier, i;

   /*
    * loop over each trace
    */
   /*
         READ DATA
         'cddx_read' function:
              This function reads a specified number of traces mapping
              each into the input buffer.  
              Check the number read in case of any problems.
    */
   ier = cddx_read(in_bin, buf, 1);
   while(ier == 1) {
      /*
       * process the trace
       */
      for(i=0;i<ns;i++) buf[i] = scale * buf[i];
  
      /*
       * write the trace
       */
      /*
            WRITE DATA
            'cddx_write' function:
                 This function maps a specified number of traces from the
                 buffer and writes them out.  
                 Check the number written in case of any problems.
       */
      ier = cddx_write(out_bin, buf, 1);
      if (ier != 1) {
         cdds_prterr("writing output\n");
         return;
      }

      /*
       *  read the next trace
       */
      ier = cddx_read(in_bin, buf, 1);
   }
   
   return;
}
      
/***********************************************************************
 * 
 *		help
 *
 **********************************************************************/
void help()
{
   fprintf(stderr, "Template program demonstrating the simple use of DDS\n");
   fprintf(stderr, "convenience routines for a simple trace-to-trace processing\n");
   fprintf(stderr, "scheme without using or passing any trace headers.\n");
   fprintf(stderr, "\n");
   fprintf(stderr, "usage:\n");
   fprintf(stderr, "   c_template2 [in=dat] [in_data=bin] [in_format=fmt] \\\n");
   fprintf(stderr, "   [out=dat] [out_data=bin] [out_format=fmt] \\\n");
   fprintf(stderr, "   [scale=f]\n");
   fprintf(stderr, "   \n");
   fprintf(stderr, "where:\n");
   fprintf(stderr, "   in=        input dataset\n");
   fprintf(stderr, "   in_data=   input binary\n");
   fprintf(stderr, "   in_format= input format\n");
   fprintf(stderr, "   out=       output dictionary\n");
   fprintf(stderr, "   out_data=  output binary\n");
   fprintf(stderr, "   out_format=output format\n");
   fprintf(stderr, "   scale=     scale factor (dflt=1.0)\n");
   fprintf(stderr, "\n");

   exit(0);
}