Progress
External Program
Interfaces


Example HLC Application

This section explains how to use the Progress HLC tank demo application. This application is a prepackaged application that you can use to verify that your HLC environment is set up correctly. The C code and sample output for this example are provided in the $DLC/probuild/hlc/examples directory on UNIX, and in the %DLC%\probuild\hlc\examples directory in Windows.

Set up your environment and compile this example before you try to run it to verify that your compiler and the PROBUILD utility are working correctly. This also helps you learn how to use HLC in a controlled environment.

This sample application uses Progress to keep track of oil storage tanks. Your Progress procedure calls a C program, AVCALC, to calculate the available capacity for a given tank. Figure 2–6 shows that the tanks are cylindrical, with their axes parallel to the level ground.

Figure 2–6: Tank Positioning and Orientation

To calculate the available capacity (empty portion) of the tank, you need to know the tank’s diameter, length, and current level of oil. Use the variables in the following formula to calculate the available tank volume:

Where:

r
Radius of the tank
length
Length of the tank
level
Level of oil in the tank

For this example, assume there is a tank table for this application that contains the following decimal fields:

radius
Radius of tank
tlength
Length of tank
depth
Level of oil—must be between 0 and (2 . radius)
tavail
Available volume in tank

In addition to these fields, the tank-id character field is used as the primary index.

Figure 2–7 shows the Data Dictionary report for the tank table.

            Default field order: yes
09/10/93                Progress Data Dictionary Report                 Page   1
Database: tank
                                   tank File
                                   =========
                   (Flat file containing oil tank information)

Delete Validation
    Criterion:
      Message:
    Field        Type  Ext Dec Format                         Init
    ------------ ----- --- --- ------------------------------ ----------
*   tank-id      char          x(8)
    radius       dec         2 ->>,>>9.99                     0
    tlength      dec         2 ->>,>>9.99                     0
    depth        dec         2 ->>,>>9.99                     0
    tavail       dec         2 ->>,>>9.99  

Index Name   Unique Field Name   Seq Ascending abbreviate
  ------------ ------ ------------ --- --------- ----------
# tank         yes    tank-id        1 yes       yes

Field Validation Criteria, Validation Messages
------------------------------------------------------------------------
depth        :  depth le 2 * (input radius)
                Depth cannot exceed diameter of tank

Help Messages
------------------------------------------------------------------------
tank-id      :  Tank identification number
radius       :  Radius of oil tank
tlength      :  Length of oil Tank
depth        :  Depth of oil in tank.
tavail       :  Available Volume In Tank


                         Data Dictionary Report Legend
             * - Indicates that a field participates in an index
             # - Indicates the primary index for a database file
             M - Indicates that a field is mandatory 

Figure 2–7: Progress Data Dictionary Report For Tank Application

A C function calculates the tavail field from the other three decimal fields (radius, tlength, depth). Figure 2–8 shows the Progress procedure that invokes the C function by calling the HLC routine, AVCALC.

/* calculate available volume for each tank */
DEFINE NEW SHARED BUFFER tankbuf FOR tank.
FOR EACH tankbuf:
  DISPLAY
    radius SPACE(3) tlength SPACE(3) depth SPACE(3)
    tavail WITH CENTERED TITLE "Tank Table".
END.
PAUSE 0.
VIEW FRAME tank-before.
HIDE ALL.

FOR EACH tankbuf:
  DO TRANSACTION:
    CALL AVCALC.
  END.
  DISPLAY
    radius SPACE(3) tlength SPACE(3) depth SPACE(3)
    tavail WITH CENTERED TITLE "After Calculation".
END. 

Figure 2–8: Progress Procedure Calling HLC Routine AVCALC

Make a copy of the HLC dispatch routine, hlprodsp.c, and name it tankdsp.c. Modify the routine so that an entry appears for AVCALC, which calls the C subroutine hlvcalc.

Example hlprodsp.c shows the modifications to the tankdsp.c routine:

hlprodsp.c
#define FUNCTEST(nam, rout)  \
        if (strcmp(nam, pfunnam) == 0) \
            return rout(argc,argv);
/* PROGRAM: PRODSP
 * 
 *   This is the interface to all C routines that 
 *   Progress has associated ’call’ statements to. 
 */
long
PRODSP(pfunnam, argc, argv)     
    char   *pfunnam;   
    /* Name of function to call */
    int     argc;
    char   *argv[];{
    /* Interface to ’tank’ example  */
    FUNCTEST ("AVCALC", hlvcalc);  

    return 1;
} 

The following procedure shows the code for the demo program, hlvcalc.c. The program extracts the radius, length, and level fields from the shared buffer tank, calculates the available volume, and updates the tavail field in the shared buffer tank with the number calculated:

hlvcalc.c
 *    Obtains the height, radius and oil level for the tank
 *    from the shared buffer "tankbuf".
 *    
 *    Calculates the remaining available volume
 *
 *    Update the avail field in the shared buffer "tankbuf" with the
 *    number calculated.
 */
#define  BUFLEN   100
#include <math.h>
#include "hlc.h"
/*NOTE: M_PI_2 is pi/2 constant which may be defined in math.h */
#ifndef M_PI_2
#define M_PI_2   1.570796327
#endif

extern double asin();

char *fieldnm[] = { "tlength", "depth", "radius"};
char message[80];
int
hlvcalc()
{
   char     buffer[BUFLEN];
   int      unknown = 0, index = 0, varlen = BUFLEN, actlen;
   int      ret;
   double   length, depth, radius, avail;
   int      i;
   int      fldpos;
   double   temp1, temp2;  /* used to simplify calculation */
   /* first, obtain the length, depth and radius from */
   /* the shared buffer "tankbuf".                */
   for (i = 0; i < 3; ++i)
   {
      fldpos = profldix("tankbuf", fieldnm[i]);
      if (fldpos < 0) 
      {
        sprintf(message, "profldix failed on %s for field %s",
                "tankbuf", fieldnm[i]);
        promsgd(message);
        return 1;
       } 
      ret = prordbn("tankbuf", fldpos, index,     
                      buffer, &unknown, varlen, &actlen);
      if (ret)
      {
         sprintf(message, "prordbn failed accessing %s . %s",
                  "tankbuf", fieldnm[i]);
         promsgd(message);
         return 1;
      }      
      /* if one of the fields is unknown, set avail field */
      /* to the unknown value                             */
      if (unknown)
      {
         fldpos = profldix("tankbuf", "tavail");
         if (fldpos < 0) 
         {
            sprintf(message, "profldix failed on %s for field %s",
                    "tankbuf", "tavail");
            promsgd(message);
            return 1;
         }         
         ret = prowtbn("tankbuf", fldpos, index, buffer, unknown);
         if (ret)
         {
            sprintf(message, "prowtbn failed, ret = %d", ret);
            promsgd(message); 
            return 1;
         }
         return 0;
      }

      /* convert the character string obtained from */
      /* Progress into a decimal number             */
      buffer[actlen] = ’\0’;

      switch (i)
      {
         case 0: 
                  length = atof(buffer); break;
         case 1:
                  depth  = atof(buffer); break;
         case 2: 
                  radius = atof(buffer); break;
         
         default:
                  break;
      } 

/* Now, calculate the available volume                  */
/* NOTE: M_PI_2 is pi/2 constant defined in math.h */
#ifndef M_PI_2
#define M_PI_2 1.57
#endif
temp1 = 1.0 - depth/radius;
temp2 = temp1 * sqrt(1.0 - temp1 * temp1) + asin(temp1);
avail = length * radius * radius * (temp2 + M_PI_2);

/* Now, put this value in the tavail field in the */
/* "tankbuf" shared buffer                        */
/* get the double into character format */
sprintf(buffer, "%.2f", avail);
fldpos = profldix("tankbuf", "tavail");
if (fldpos < 0) 
{
       sprintf(message, "profldix failed on %s for field %s",
                                      "tankbuf", fieldnm[i]);
       promsgd(message);
       return 1;
}
ret = prowtbn("tankbuf", fldpos, index, buffer, unknown);
if (ret)
       {
           sprintf(message, "prowtbn failed, ret = %d", ret);
           promsgd(message);
           return 1;
       }
return 0; 


Copyright © 2004 Progress Software Corporation
www.progress.com
Voice: (781) 280-4000
Fax: (781) 280-4095