#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#define  INCL_REXXSAA
#define  INCL_DOSMEMMGR
#include <rexx.h>

/*********************************************************************/
/* Numeric Return calls                                              */
/*********************************************************************/

#define  INVALID_ROUTINE 40            /* Raise Rexx error           */
#define  VALID_ROUTINE    0            /* Successful completion      */


/*********************************************************************/
/* AspiFncTable                                                      */
/*   Array of names of the REXXASPI functions.                       */
/*   This list is used for registration and deregistration.          */
/*********************************************************************/
static PSZ  AspiFncTable[] =
   {
      "Aspi_Exchange_Data",
      "AspiDeregFunc3",
      "Aspi_Read_All_Variables_From_REXX_VP",
      "Aspi_Read_All_Elements_Of_A_Specific_Stem_From_REXX_VP"
   };


/*************************************************************************
* Function:  AspiLoadFuncs                                               *
*                                                                        *
* Syntax:    call AspiLoadFuncs                                          *
*                                                                        *
* Params:    none                                                        *
*                                                                        *
* Return:    null string                                                 *
*************************************************************************/

LONG APIENTRY AspiLoadFuncs3(
  PSZ       name,                      /* Function name              */
  LONG      numargs,                   /* Number of arguments        */
  RXSTRING  args[],                    /* Argument array             */
  PSZ       queuename,                 /* Current queue              */
  PRXSTRING retstr )                   /* Return RXSTRING            */
{
  INT    entries;                      /* Num of entries             */
  INT    j;                            /* Counter                    */


  entries = sizeof(AspiFncTable)/sizeof(PSZ);

  for (j = 0; j < entries; j++)
  {
    RexxRegisterFunctionDll(AspiFncTable[j],
          "rexxasp3", AspiFncTable[j]);
  }
  return VALID_ROUTINE;
}


/*************************************************************************
* Function:  AspiDeregFunc                                               *
*                                                                        *
* Syntax:    call AspiDeregFuncs                                         *
*                                                                        *
* Params:    none                                                        *
*                                                                        *
* Return:    null string                                                 *
*************************************************************************/

LONG APIENTRY AspiDeregFunc3(
  PSZ       name,                      /* Function name              */
  LONG      numargs,                   /* Number of arguments        */
  RXSTRING  args[],                    /* Argument array             */
  PSZ       queuename,                 /* Current queue              */
  PRXSTRING retstr )                   /* Return RXSTRING            */
{
  INT    entries;                      /* Num of entries             */
  INT    j;                            /* Counter                    */

  retstr->strlength = 0;               /* set return value           */

  if (numargs > 0)
    return INVALID_ROUTINE;


  entries = sizeof(AspiFncTable)/sizeof(PSZ);

  for (j = 0; j < entries; j++)
  {
    RexxDeregisterFunction(AspiFncTable[j]);
  }
  return VALID_ROUTINE;
}

/*************************************************************************
* Function:  Aspi_Read_All_Variables_From_REXX_VP                        *
*                                                                        *
* Syntax:    call Aspi_Read_All_Variables_From_REXX_VP                   *
*                                                                        *
* Params:    No parameter required. The function is called by ASPITEST.  *
*            It uses a while loop to read all the variables in the active*
*            REXX-variable pool. The shared variable block request code  *
*            is RXSHV_NEXTV. Be aware that with this request code REXX   *
*            treads every Stem variable as a variable itself (not the    *
*            whole stem). This gives the calling C-routine a chance      *
*            to clear up memory which was previously allocated by REXX   *
*            for every returned variable. If you don't free memory the   *
*            system will get out of storage.                             *
*            Be aware that the returned variables are NOT in any spe-    *
*            cified order.                                               *
* Return:    0 - success, 1 - failure                                    *
*************************************************************************/

LONG APIENTRY Aspi_Read_All_Variables_From_REXX_VP(
  PSZ       name,                      /* Function name              */
  LONG      numargs,                   /* Number of arguments        */
  RXSTRING  args[],                    /* Argument array             */
  PSZ       queuename,                 /* Current queue              */
  PRXSTRING retstr )                   /* Return RXSTRING            */
{
   SHVBLOCK *prxshv, *prxshvtop;
   RXSTRING rxstrName, rxstrValue;
   APIRET rc;
   char *pch;
   int i = 1;

   strcpy(retstr->strptr, "0");
   retstr->strlength = strlen(retstr->strptr);

   prxshv = (PSHVBLOCK)malloc(sizeof(SHVBLOCK));
   if (!prxshv)
   {
      strcpy(retstr->strptr, "Allocation error occured");
      retstr->strlength = strlen(retstr->strptr);
      return VALID_ROUTINE;
   }
   prxshv->shvnext = NULL;
   prxshv->shvname.strlength = 0;
   prxshv->shvname.strptr = NULL;
   prxshv->shvvalue.strptr = NULL; /*** let rexx allocate for me ***/
   prxshv->shvcode = RXSHV_NEXTV;

/* Now reading all variables from the REXX-variable pool ***********/

   rc = RexxVariablePool(prxshv);
   if (rc)
   {
      if (rc != RXSHV_LVAR)
      {
      printf("ERROR: shvret is %x hex after var nr. %d \n",rc,i);
      }
   }

   printf("Name of the variable from the Variable Pool: %s, Value: %s \n", prxshv->shvname.strptr, prxshv->shvvalue.strptr);
   i++;

   while (!prxshv->shvret)
   {

      prxshv->shvnext = (PSHVBLOCK)malloc(sizeof(SHVBLOCK));
      prxshv = prxshv->shvnext;
      if (!prxshv)
      {
         strcpy(retstr->strptr, "Allocation error occured");
         retstr->strlength = strlen(retstr->strptr);
         return VALID_ROUTINE;
      }
      prxshv->shvnext = NULL;
      prxshv->shvname.strlength = 0;
      prxshv->shvname.strptr = NULL;
      prxshv->shvvalue.strptr = NULL; /*** let rexx allocate for me ***/
      prxshv->shvcode = RXSHV_NEXTV;
      rc = RexxVariablePool(prxshv);
      if (rc)
      {
         if (rc== RXSHV_MEMFL)
         {
           strcpy(retstr->strptr, "Allocation error occured");
           retstr->strlength = strlen(retstr->strptr);
           return VALID_ROUTINE;
         }
         else if (rc != RXSHV_LVAR)
         {
           printf("ERROR: shvret is %x hex after var nr. %d\n",rc,i);
           return INVALID_ROUTINE;
         }
      }
      i++;
      printf("Name of the variable from the Variable Pool: %s, Value: %s \n", prxshv->shvname.strptr, prxshv->shvvalue.strptr);
      free(prxshv->shvname.strptr);
      free(prxshv->shvvalue.strptr);
   }
  return VALID_ROUTINE;
}

/*************************************************************************
* Function:  Aspi_Read_All_Elements_Of_A_Specific_Stem_From_REXX_VP      *
*                                                                        *
* Syntax:    call Aspi_Read_All_Elements_Of_A_Specific_Stem_From_REXX_VP *
*            with the stem variable the values should be returned        *
*                                                                        *
* Params:    A stem where all values of the stem variables should be     *
             returned.                                                   *
*            The shared variable block request code  is RXSHV_SYFET.     *
*            Only ONE call is necessary. If the stem contains to many    *
*            variables the memory resources are exhausted and REXX       *
*            should return RXSHV_MEMFL. There is no change for the       *
*            calling routine to handle the problem with DosFreeMem       *
*            because it doesn't get any control before REXX terminates.  *
*            The problem is during allocating memory for the values of   *
*            the stem-variables by DosAllocMem which allocates on 64k    *
*            boundary.                                                   *
* Return:    0 - success, 1 - failure                                    *
*************************************************************************/

LONG APIENTRY Aspi_Read_All_Elements_Of_A_Specific_Stem_From_REXX_VP(
  PSZ       name,                      /* Function name              */
  LONG      numargs,                   /* Number of arguments        */
  RXSTRING  args[],                    /* Argument array             */
  PSZ       queuename,                 /* Current queue              */
  PRXSTRING retstr )                   /* Return RXSTRING            */
{
   SHVBLOCK *prxshv, *temp, *interim, rxshv;
   RXSTRING rxstrName, rxstrValue;
   APIRET rc;
   char array[20], value[10];
   char *pch, *result;
   int chars;
   int j, k = 0;
   prxshv = &rxshv;

   if (numargs != 1 )                    /* validate arg count         */
    return INVALID_ROUTINE;
   strcpy(retstr->strptr, "0");
   retstr->strlength = strlen(retstr->strptr);

   pch = malloc(strlen(args[0].strptr) +1);
   strcpy(pch, args[0].strptr);

   prxshv->shvnext = NULL;
   prxshv->shvname.strlength = strlen(pch);
   prxshv->shvname.strptr = pch;
   prxshv->shvvalue.strptr = NULL; /*** let rexx allocate for me ***/
   prxshv->shvcode = RXSHV_SYFET;

   rc = RexxVariablePool(prxshv);
   if (rc)
   {
      strcpy(retstr->strptr, "ASPIFETCH failed \n");
      retstr->strlength = strlen(retstr->strptr);
      return VALID_ROUTINE;
   }

   j = atoi(prxshv->shvvalue.strptr);
   chars = '.';
   result = strrchr(pch, chars);
   result++;
   *result = 0x00;

   temp = prxshv;

   memset(array, 0x00, sizeof(array));
   memset(value, 0x00, sizeof(value));
   for (k = 1;k <= j; k++)
   {
      temp->shvnext = (PSHVBLOCK)malloc(sizeof(SHVBLOCK));
      temp = temp->shvnext;
      if (!temp)
      {
         strcpy(retstr->strptr, "Allocation error occured");
         retstr->strlength = strlen(retstr->strptr);
         return VALID_ROUTINE;
      }
      strcpy(array, pch);
      sprintf(value, "%d", k);
      strcat(array, value);
      temp->shvnext = NULL;
      temp->shvname.strlength = strlen(array);
      temp->shvname.strptr = malloc(strlen(array)+1);
      strcpy(temp->shvname.strptr, array);
      temp->shvvalue.strptr = NULL; /*** let rexx allocate for me ***/
      temp->shvcode = RXSHV_SYFET;
   }
   rc = RexxVariablePool(prxshv->shvnext);
   if (rc)
   {
      if (rc== RXSHV_MEMFL)
      {
         strcpy(retstr->strptr, "Allocation error occured");
         retstr->strlength = strlen(retstr->strptr);
         return VALID_ROUTINE;
      }
      else if (rc != RXSHV_LVAR)
      {
         printf("ERROR: shvret is %x hex \n",rc);
         return INVALID_ROUTINE;
      }
   }
   temp = prxshv->shvnext;

   for (k = 1;k <= j; k++)
   {
      printf("Name of the Stem-variable from the REXX Variable Pool: %s, Value: %s \n", temp->shvname.strptr, temp->shvvalue.strptr);
      interim = temp;
      free(temp->shvname.strptr);
      free(temp->shvvalue.strptr);
      temp = temp->shvnext;
      free(interim);
   }

   free(prxshv->shvvalue.strptr);
   free(pch);

   return VALID_ROUTINE;
}

