#define INCL_DOSPROCESS
#define INCL_DOSERRORS
#define INCL_RXSHV
#define INCL_RXFUNC
#define INCL_PM
#define INCL_WIN

#include "vxrexx.h"
#include "vxfuncs.h"
#include "utility.h"

#include <bseerr.h>


/* ------------------------------------------------------------------------- *
 * WriteStemElement                                                          *
 *                                                                           *
 * Creates a stem element (compound variable) in the calling REXX program    *
 * using the REXX shared variable pool interface.                            *
 *                                                                           *
 * ARGUMENTS:                                                                *
 *   PSZ   pszStem  : The name of the stem (before the '.')                  *
 *   ULONG ulIndex  : The number of the stem element (after the '.')         *
 *   PSZ   pszValue : The value to write to the compound variable.           *
 *                                                                           *
 * RETURNS: BOOL                                                             *
 *   TRUE on success, FALSE on failure.                                      *
 * ------------------------------------------------------------------------- */
BOOL WriteStemElement( const PSZ pszStem, ULONG ulIndex, PSZ pszValue )
{
    SHVBLOCK shvVar;                   // REXX shared variable pool block
    ULONG    ulRc,
             ulBytes;
    CHAR     szCompoundName[ US_COMPOUND_MAXZ ];

    sprintf( szCompoundName, "%s.%d", pszStem, ulIndex );
    if ( pszValue == NULL ) {
        pszValue = "";
        ulBytes  = 0;
    } else {
        // 2015-06-03 SHL Was using DosAllocMem and leaking memory
        // REXX API does not free this kind of buffer
        ulBytes = strlen(pszValue);
    }
    MAKERXSTRING( shvVar.shvname, szCompoundName, strlen(szCompoundName) );
    shvVar.shvvalue.strptr    = (PCH)pszValue;
    shvVar.shvvalue.strlength = ulBytes;
    shvVar.shvnamelen  = RXSTRLEN( shvVar.shvname );
    shvVar.shvvaluelen = RXSTRLEN( shvVar.shvvalue );
    shvVar.shvcode     = RXSHV_SYSET;
    shvVar.shvnext     = NULL;
    ulRc = RexxVariablePool( &shvVar );
    if ( ulRc > 1 ) {
        WriteErrorCode( shvVar.shvret, "RexxVariablePool (SHVBLOCK.shvret)");
        return FALSE;
    }
    return TRUE;
}


/* ------------------------------------------------------------------------- *
 * WriteCompoundVariable                                                     *
 *                                                                           *
 * Creates a compound variable in the calling REXX program using the REXX    *
 * shared variable pool interface.                                           *
 *                                                                           *
 * ARGUMENTS:                                                                *
 *   PSZ   pszStem  : The name of the stem (before the '.')                  *
 *   PSZ   pszTail  : The name of the trailing portion (after the '.')       *
 *   PSZ   pszValue : The value to write to the compound variable.           *
 *                                                                           *
 * RETURNS: BOOL                                                             *
 *   TRUE on success, FALSE on failure.                                      *
 * ------------------------------------------------------------------------- */
BOOL WriteCompoundVariable( const PSZ pszStem, const PSZ pszTail, PSZ pszValue )
{
    SHVBLOCK shvVar;                   // REXX shared variable pool block
    ULONG    ulRc,
             ulBytes;
    CHAR     szCompoundName[ US_COMPOUND_MAXZ ];

    sprintf( szCompoundName, "%s.%s", pszStem, pszTail );
    if ( pszValue == NULL ) {
        pszValue = "";
        ulBytes  = 0;
    } else {
        ulBytes = strlen( pszValue );
    }
    MAKERXSTRING( shvVar.shvname, szCompoundName, strlen(szCompoundName) );
    shvVar.shvvalue.strptr    = (PCH)pszValue;
    shvVar.shvvalue.strlength = ulBytes;
    shvVar.shvnamelen  = RXSTRLEN( shvVar.shvname );
    shvVar.shvvaluelen = RXSTRLEN( shvVar.shvvalue );
    shvVar.shvcode     = RXSHV_SYSET;
    shvVar.shvnext     = NULL;
    ulRc = RexxVariablePool( &shvVar );
    if ( ulRc > 1 ) {
        WriteErrorCode( shvVar.shvret, "RexxVariablePool (SHVBLOCK.shvret)");
        return FALSE;
    }
    return TRUE;
}


/* ------------------------------------------------------------------------- *
 * WriteSimpleVariable                                                       *
 *                                                                           *
 * Creates a variable in the calling REXX program using the REXX shared      *
 * variable pool interface.                                                  *
 *                                                                           *
 * ARGUMENTS:                                                                *
 *   PSZ pszName  : The name of the variable to write.                       *
 *   PSZ pszValue : The value to write to the variable.                      *
 *                                                                           *
 * RETURNS: BOOL                                                             *
 * ------------------------------------------------------------------------- */
BOOL WriteSimpleVariable( const PSZ pszName, PSZ pszValue )
{
    SHVBLOCK shvVar;                   // REXX shared variable pool block
    ULONG    ulRc;
    CHAR     szText[ US_COMPOUND_MAXZ ];

    strncpy( szText, pszValue, US_COMPOUND_MAXZ-1 );
    MAKERXSTRING( shvVar.shvname,  pszName, strlen(pszName) );
    MAKERXSTRING( shvVar.shvvalue, szText,  strlen(szText) );
    shvVar.shvnamelen  = RXSTRLEN( shvVar.shvname );
    shvVar.shvvaluelen = RXSTRLEN( shvVar.shvvalue );
    shvVar.shvcode     = RXSHV_SYSET;
    shvVar.shvret      = 0;
    shvVar.shvnext     = NULL;
    ulRc = RexxVariablePool( &shvVar );
    if ( shvVar.shvret > 1 ) {
        WriteErrorCode( shvVar.shvret, "RexxVariablePool (SHVBLOCK.shvret)");
        return FALSE;
    }
    return TRUE;
}


/* ------------------------------------------------------------------------- *
 * WriteErrorCode                                                            *
 *                                                                           *
 * Writes an error code to a special variable in the calling REXX program    *
 * using the REXX shared variable pool interface.  This is used to return    *
 * API error codes to the REXX program, since the REXX functions themselves  *
 * normally return string values.                                            *
 *                                                                           *
 * ARGUMENTS:                                                                *
 *   ULONG ulError   : The error code returned by the failing API call.      *
 *   PSZ   pszContext: A string describing the API call that failed.         *
 *                                                                           *
 * RETURNS: N/A                                                              *
 * ------------------------------------------------------------------------- */
void WriteErrorCode( ULONG ulError, PSZ pszContext )
{
    SHVBLOCK shvVar;                   // REXX shared variable pool block
    ULONG    ulRc;
    CHAR     szErrorText[ US_ERRSTR_MAXZ ];

    if ( pszContext == NULL )
        sprintf( szErrorText, "%X", ulError );
    else
        sprintf( szErrorText, "%X: %s", ulError, pszContext );
    MAKERXSTRING( shvVar.shvname,  SZ_ERROR_NAME, strlen(SZ_ERROR_NAME) );
    MAKERXSTRING( shvVar.shvvalue, szErrorText,   strlen(szErrorText) );
    shvVar.shvnamelen  = RXSTRLEN( shvVar.shvname );
    shvVar.shvvaluelen = RXSTRLEN( shvVar.shvvalue );
    shvVar.shvcode     = RXSHV_SYSET;
    shvVar.shvret      = 0;
    shvVar.shvnext     = NULL;
    ulRc = RexxVariablePool( &shvVar );
    if ( shvVar.shvret > 1 )
        printf("Unable to set %s: rc = %d\n", shvVar.shvname.strptr, shvVar.shvret );
}


/* ------------------------------------------------------------------------- *
 * CB_WriteStemElement                                                       *
 *                                                                           *
 * Callback version of WriteStemElement, required for use with the           *
 * VRCallFunctionClient() function.  Sets a stem element in the calling      *
 * VX-REXX program's client thread's variable pool.                          *
 *                                                                           *
 * ARGUMENTS:                                                                *
 *   PCBSTEMDATA pData: Pointer to structure containing parameters.          *
 *                                                                           *
 * RETURNS: N/A                                                              *
 * ------------------------------------------------------------------------- */
void _System CB_WriteStemElement( PCBSTEMDATA pData )
{
    SHVBLOCK shvVar;
    ULONG    ulBytes;
    CHAR     szCompoundName[ US_COMPOUND_MAXZ ];
    PCHAR    pchValue;

    sprintf( szCompoundName, "%s.%d", pData->pszName, pData->ulIndex );
    if ( pData->pszValue == NULL ) {
        pchValue = "";
        ulBytes  = 0;
    }
    else {
        ulBytes = strlen( pData->pszValue );
        pchValue = (PCHAR) VRMemAlloc( ulBytes + 1 );
        if ( pchValue == NULL ) {
            pData->rc = ERROR_NOT_ENOUGH_MEMORY;
            return;
        }
        memcpy( pchValue, pData->pszValue, ulBytes );
    }
    MAKERXSTRING( shvVar.shvname, szCompoundName, strlen( szCompoundName ));
    shvVar.shvvalue.strptr    = pchValue;
    shvVar.shvvalue.strlength = ulBytes;
    shvVar.shvnamelen  = RXSTRLEN( shvVar.shvname );
    shvVar.shvvaluelen = RXSTRLEN( shvVar.shvvalue );
    shvVar.shvcode     = RXSHV_SYSET;
    shvVar.shvret      = 0;
    shvVar.shvnext     = NULL;
    RexxVariablePool( &shvVar );
    pData->rc = shvVar.shvret;
}


