/*----------------------------------------------------------------------------*/
/*                                                                            */
/* Copyright (c) 1995, 2004 IBM Corporation. All rights reserved.             */
/* Copyright (c) 2005-2021 Rexx Language Association. All rights reserved.    */
/*                                                                            */
/* This program and the accompanying materials are made available under       */
/* the terms of the Common Public License v1.0 which accompanies this         */
/* distribution. A copy is also available at the following address:           */
/* https://www.oorexx.org/license.html                         */
/*                                                                            */
/* Redistribution and use in source and binary forms, with or                 */
/* without modification, are permitted provided that the following            */
/* conditions are met:                                                        */
/*                                                                            */
/* Redistributions of source code must retain the above copyright             */
/* notice, this list of conditions and the following disclaimer.              */
/* Redistributions in binary form must reproduce the above copyright          */
/* notice, this list of conditions and the following disclaimer in            */
/* the documentation and/or other materials provided with the distribution.   */
/*                                                                            */
/* Neither the name of Rexx Language Association nor the names                */
/* of its contributors may be used to endorse or promote products             */
/* derived from this software without specific prior written permission.      */
/*                                                                            */
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS        */
/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT          */
/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS          */
/* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT   */
/* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,      */
/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED   */
/* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,        */
/* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY     */
/* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING    */
/* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS         */
/* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.               */
/*                                                                            */
/*----------------------------------------------------------------------------*/
/*********************************************************************/
/*                                                                   */
/*  File Name:          CALLREXX2.C                                  */
/*                                                                   */
/* ----------------------------------------------------------------- */
/*                                                                   */
/*  Description:        Samples of how to invoke the Open Object Rexx*/
/*                      interpreter. It loads the Rexx library at    */
/*                      runtime.                                     */
/*                                                                   */
/*  Entry Points:       main - main entry point                      */
/*                                                                   */
/*  Input:              None                                         */
/*                                                                   */
/*  Output:             returns from the Open Object Rexx programs   */
/*                                                                   */
/*********************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <dlfcn.h>
#include <sys/stat.h>
#include <errno.h>

#include "rexx.h"

char   *pcharTemp;

int main(int argc, char **argv)
{
    CONSTRXSTRING arg[4];                   /* argument string for Rexx  */
    RXSTRING rexxretval;                    /* return value from Rexx    */
    RXSTRING instore[2];                    /* in storage parms          */
    PFNREXXSTART FuncAddress;
    void    *pLibHandle = NULL;             /* Library handle             */
    RexxReturnCode   rc = 0;                        /* return code from Rexx      */
    short    rexxrc = 0;                    /* return code from function  */
#ifdef __APPLE__
    const char *pszLibraryName = "librexx.dylib"; /* define the library name    */
#else
    const char *pszLibraryName = "librexx.so"; /* define the library name    */
#endif
    char returnBuffer[100];
    int ignore; // avoid warning: ignoring return value of 'system'
                // avoid warning: ignoring return value of 'scanf'

    char    val;
    const char *str1 = "Arg number one";                   /* text to swap   */
    const char *str2 = "Arg number two";                   /* text to swap   */
    const char *str3 = "Arg number three";                 /* text to swap   */
    const char *str4 = "Arg number four";                  /* text to swap   */

    const char *sync_tst = "call time 'Reset';" \
                        "object1 = .example~new;" \
                        "object2 = .example~new;" \
                        "object3 = .example~new;" \
                        "a.1 = object1~start('REPEAT', 4 , 'Object 1 running');" \
                        "say a.1~result;" \
                        "say 'The result method waits until the START message has completed:';" \
                        "a.2 = object2~start('REPEAT', 2, 'Object 2 running');" \
                        "a.3 = object3~start('REPEAT', 2, 'Object 3 running');" \
                        "say a.2~result;" \
                        "say a.3~result;" \
                        "say 'main ended';" \
                        "say 'Elapsed time: ' time('E');" \
                        "exit;" \
                        "::REQUIRES 'example.rex'";

    if (!(pLibHandle = dlopen(pszLibraryName, RTLD_LAZY )))
    {                            /* Load and resolve symbols immediately  */
      fprintf(stderr, " *** Unable to load library %s !\nError message: %s\n",
               pszLibraryName, dlerror());
      return 99;
    }

    if(!(FuncAddress = (PFNREXXSTART) dlsym(pLibHandle, "RexxStart")))
    {
      rc = 1;                               /* could not resolve          */
      fprintf(stderr, " *** Unable to load function %s !\nError message: %s\n",
                                            "RexxStart", dlerror());
      return 99;
    }


    /* By setting the strlength of the Rexx output to zero, the           */
    /* interpreter allocates memory.                                      */
    /* We can provide a buffer for the interpreter to use instead.        */
    /* If the returned value does not fit into the buffer,                */
    /* Open Object Rexx creates a new one.                                */

    ignore = system("clear");

    rexxretval.strptr = NULL;       /* initialize return-pointer to empty */
    rexxretval.strlength = 0;       /* initialize return-length to zero   */

    printf("This is an easy sample of how to invoke the Rexx interpreter. \n");
    printf("The Rexx commandfile which is started is named: startrx1.rex\n");

    printf("Press Enter to continue\n");
    ignore = scanf("%c", &val);


    /* This is the interpreter invocation. ------------------------------ */

    rc =    (*FuncAddress)(
            0,                       /* number of arguments   */
             NULL,                   /* array of arguments    */
             "startrx1.rex",         /* name of Rexx file     */
             NULL,                   /* No INSTORE used       */
             "ksh",                  /* Command env. name     */
             RXCOMMAND,              /* Code for how invoked  */
             NULL,                   /* No EXITs on this call */
             &rexxrc,                /* Rexx program output   */
             &rexxretval );          /* Rexx program output   */

    printf("CALLREXX2 - Back from REXXSTART:  Return Code: %d\n", rc);
    printf("CALLREXX2 - RESULT-LENGTH:           %zd\n", rexxretval.strlength);
    printf("CALLREXX2 - RESULT-Value:            %s\n", rexxretval.strptr);

    if (rexxretval.strptr != NULL)
    {
        RexxFreeMemory(rexxretval.strptr);
    }

    printf("Press Enter to continue\n");
    ignore = scanf("%c", &val);

    ignore = system("clear");

    printf("In this case a previously defined Resultstring is \n");
    printf("delivered to Open Object Rexx, which is large enough to \n");
    printf("hold the Return Value of the Rexx commandfile.\n");

    printf("Press Enter to continue\n");
    ignore = scanf("%c", &val);

    rexxretval.strptr = returnBuffer;
    rexxretval.strlength = sizeof(returnBuffer);

    rc = (*FuncAddress)(
             0,                      /* number of arguments   */
             NULL,                   /* array of arguments    */
             "startrx1.rex",         /* name of Rexx file     */
             NULL,                   /* No INSTORE used       */
             "ksh",                  /* Command env. name     */
             RXCOMMAND,              /* Code for how invoked  */
             NULL,                   /* No EXITs on this call */
             &rexxrc,                /* Rexx program output   */
             &rexxretval );          /* Rexx program output   */

    printf("CALLREXX2 - Back from REXXSTART:  Return Code: %d\n", rc);
    printf("rexxretval.strptr contains %s\n", rexxretval.strptr);
    printf("CALLREXX2 - RESULT-LENGTH:           %zd\n", rexxretval.strlength);
    printf("CALLREXX2 - RESULT-Value:            %s\n", rexxretval.strptr);
    /* if Rexx needed to allocate a new buffer, release that one */
    if (rexxretval.strptr != returnBuffer)
    {
        RexxFreeMemory(rexxretval.strptr);
    }

    printf("Press Enter to continue\n");
    ignore = scanf("%c", &val);

    ignore = system("clear");

    printf("In this case a previously defined Resultstring is \n");
    printf("delivered to Open Object Rexx, which is too small to\n");
    printf("hold the Return Value of the Rexx commandfile.\n");
    printf("Rexx reallocates the buffer which needs to be freed.\n");
    printf("in the calling program\n");

    printf("Press Enter to continue\n");
    ignore = scanf("%c", &val);

    rexxretval.strptr = (char *)returnBuffer;
    rexxretval.strlength = 2;

    printf("The length of the Resultstring is %zd\n", rexxretval.strlength);

    rc = (*FuncAddress)(
             0,                      /* number of arguments   */
             NULL,                   /* array of arguments    */
             "startrx1.rex",         /* name of Rexx file     */
             NULL,                   /* No INSTORE used       */
             "ksh",                  /* Command env. name     */
             RXCOMMAND,              /* Code for how invoked  */
             NULL,                   /* No EXITs on this call */
             &rexxrc,                /* Rexx program output   */
             &rexxretval );          /* Rexx program output   */

    printf("CALLREXX2 - Back from REXXSTART:  Return Code: %d\n", rc);
    printf("The ResultString contains %s after call\n", rexxretval.strptr);
    printf("The length is now %zd\n", rexxretval.strlength);

    /* if Rexx needed to allocate a new buffer, release that one */
    if (rexxretval.strptr != returnBuffer)
    {
        RexxFreeMemory(rexxretval.strptr);
    }

    printf("Press Enter to continue\n");
    ignore = scanf("%c", &val);

    ignore = system("clear");

    rexxretval.strptr = NULL;       /* initialize return-pointer to empty */
    rexxretval.strlength = 0;       /* initialize return-length to zero   */

    printf("This is a sample with 4 arguments delivered to  \n");
    printf("REXXSTART\n");
    printf("The Rexx commandfile which is started is named: startrx2.rex\n");

    printf("Press Enter to continue\n");
    ignore = scanf("%c", &val);

    MAKERXSTRING(arg[0], str1, strlen(str1));  /* create input argument 1 */
    MAKERXSTRING(arg[1], str2, strlen(str2));  /* create input argument 2 */
    MAKERXSTRING(arg[2], str3, strlen(str3));  /* create input argument 3 */
    MAKERXSTRING(arg[3], str4, strlen(str4));  /* create input argument 4 */

    rc = (*FuncAddress)(
             4,                      /* number of arguments   */
             arg,                    /* array of arguments    */
             "startrx2.rex",         /* name of Rexx file     */
             NULL,                   /* No INSTORE used       */
             "ksh",                  /* Command env. name     */
             RXCOMMAND,              /* Code for how invoked  */
             NULL,                   /* No EXITs on this call */
             &rexxrc,                /* Rexx program output   */
             &rexxretval );          /* Rexx program output   */

    printf("CALLREXX2 - Back from REXXSTART:  Return Code: %d\n", rc);
    printf("CALLREXX2 - RESULT-LENGTH:           %zd\n", rexxretval.strlength);
    printf("CALLREXX2 - RESULT-Value:            %s\n", rexxretval.strptr);

    RexxFreeMemory(rexxretval.strptr);

    printf("Press Enter to continue\n");
    ignore = scanf("%c", &val);

    ignore = system("clear");

    printf("This is a sample with 2 arguments delivered to  \n");
    printf("REXXSTART\n");
    printf("The Rexx commandfile which is started is named: startrx2.rex\n");

    printf("Press Enter to continue\n");
    ignore = scanf("%c", &val);

    rexxretval.strptr = NULL;       /* initialize return-pointer to empty */
    rexxretval.strlength = 0;       /* initialize return-length to zero   */

    rc = (*FuncAddress)(
             2,                      /* number of arguments   */
             arg,                    /* array of arguments    */
             "startrx2.rex",         /* name of Rexx file     */
             NULL,                   /* No INSTORE used       */
             "ksh",                  /* Command env. name     */
             RXCOMMAND,              /* Code for how invoked  */
             NULL,                   /* No EXITs on this call */
             &rexxrc,                /* Rexx program output   */
             &rexxretval );          /* Rexx program output   */

    printf("CALLREXX2 - Back from REXXSTART:  Return Code: %d\n", rc);
    printf("CALLREXX2 - RESULT-LENGTH:           %zd\n", rexxretval.strlength);
    printf("CALLREXX2 - RESULT-Value:            %s\n", rexxretval.strptr);

    RexxFreeMemory(rexxretval.strptr);

    printf("Press Enter to continue\n");
    ignore = scanf("%c", &val);

    ignore = system("clear");

    printf("This is a sample where the directory listing of the   \n");
    printf("actual directory is returned by the Rexx program. The \n");
    printf("returned ResultString is displayed\n");
    printf("The Rexx commandfile which is started is named: startrx3.rex\n");

    printf("Press Enter to continue\n");
    ignore = scanf("%c", &val);

    rexxretval.strptr = NULL;       /* initialize return-pointer to empty */
    rexxretval.strlength = 0;       /* initialize return-length to zero   */

    rc = (*FuncAddress)(
             0,                      /* number of arguments   */
             NULL,                   /* array of arguments    */
             "startrx3.rex",         /* name of Rexx file     */
             NULL,                   /* No INSTORE used       */
             "ksh",                  /* Command env. name     */
             RXCOMMAND,              /* Code for how invoked  */
             NULL,                   /* No EXITs on this call */
             &rexxrc,                /* Rexx program output   */
             &rexxretval );          /* Rexx program output   */

    printf("CALLREXX2 - Back from REXXSTART:  Return Code: %d\n", rc);
    printf("CALLREXX2 - RESULT-LENGTH:           %zd\n", rexxretval.strlength);
    printf("CALLREXX2 - RESULT-Value:            %s\n", rexxretval.strptr);

    RexxFreeMemory(rexxretval.strptr);

    printf("Press Enter to continue\n");
    ignore = scanf("%c", &val);

    ignore = system("clear");

    printf("This is a sample where the instore parameter [0] is \n");
    printf("tested. Instore parameter [0] is loaded with \n");
    printf("a small Open Object Rexx script showing the concurrency feature.\n");

    printf("Press Enter to continue\n");
    ignore = scanf("%c", &val);

    instore[0].strptr = (char *)sync_tst;
    instore[0].strlength = strlen(instore[0].strptr);
    instore[1].strptr = NULL;
    instore[1].strlength = 0;

    rexxretval.strptr = NULL;       /* initialize return-pointer to empty */
    rexxretval.strlength = 0;       /* initialize return-length to zero   */

    rc = (*FuncAddress)(
             0,                       /* number of arguments   */
             NULL,                   /* array of arguments    */
             NULL,                   /* no name for Rexx file */
             instore,                /* INSTORE used          */
             "ksh",                  /* Command env. name     */
             RXCOMMAND,              /* Code for how invoked  */
             NULL,                   /* No EXITs on this call */
             &rexxrc,                /* Rexx program output   */
             &rexxretval );          /* Rexx program output   */

    printf("CALLREXX2 - Back from REXXSTART:  Return Code: %d\n", rc);
    printf("CALLREXX2 - RESULT-LENGTH:           %zd\n", rexxretval.strlength);
    printf("CALLREXX2 - RESULT-Value:            %s\n", rexxretval.strptr);

    RexxFreeMemory(rexxretval.strptr);

    printf("Press Enter to continue\n");
    ignore = scanf("%c", &val);

    ignore = system("clear");

    printf("Now instore[1] is loaded with the content of instore[0]. \n");
    printf("It can be used on subsequent calls. instore[0] is set to NULL \n");

    printf("Press Enter to continue\n");
    ignore = scanf("%c", &val);

    instore[0].strptr = NULL;
    instore[0].strlength = 0;

    rexxretval.strptr = NULL;       /* initialize return-pointer to empty */
    rexxretval.strlength = 0;       /* initialize return-length to zero   */

    rc = (*FuncAddress)(
             0,                      /* number of arguments   */
             NULL,                   /* array of arguments    */
             NULL,                   /* no name for Rexx file */
             instore,                /* INSTORE used          */
             "ksh",                  /* Command env. name     */
             RXCOMMAND,              /* Code for how invoked  */
             NULL,                   /* No EXITs on this call */
             &rexxrc,                /* Rexx program output   */
             &rexxretval );          /* Rexx program output   */

    printf("CALLREXX2 - Back from REXXSTART:  Return Code: %d\n", rc);
    printf("CALLREXX2 - RESULT-LENGTH:           %zd\n", rexxretval.strlength);
    printf("CALLREXX2 - RESULT-Value:            %s\n", rexxretval.strptr);

    RexxFreeMemory(rexxretval.strptr);

    free(instore[1].strptr);

    printf("Press Enter to continue\n");
    ignore = scanf("%c", &val);

    ignore = system("clear");

    printf("This is a sample to show how to use the Rexx MacroSpace facility. \n");
    printf("First of all load_macro.rex is called to load \n");
    printf("the Rexx script macros.rex into Macrospace. The Macrospace- \n");
    printf("name is upload.rex. \n");

    printf("Press Enter to continue\n");
    ignore = scanf("%c", &val);

    rexxretval.strptr = NULL;       /* initialize return-pointer to empty */
    rexxretval.strlength = 0;       /* initialize return-length to zero   */

    rc = (*FuncAddress)(
             0,                      /* number of arguments   */
             NULL,                   /* array of arguments    */
             "load_macro.rex", /* name for Rexx macrospacefile*/
             NULL,                   /* INSTORE not used      */
             "ksh",                  /* Command env. name     */
             RXCOMMAND,              /* Code for how invoked  */
             NULL,                   /* No EXITs on this call */
             &rexxrc,                /* Rexx program output   */
             &rexxretval );          /* Rexx program output   */

    printf("CALLREXX2 - Back from REXXSTART:  Return Code: %d\n", rc);
    printf("CALLREXX2 - RESULT-LENGTH:           %zd\n", rexxretval.strlength);
    printf("CALLREXX2 - RESULT-Value:            %s\n", rexxretval.strptr);

    RexxFreeMemory(rexxretval.strptr);

    printf("Press Enter to continue\n");
    ignore = scanf("%c", &val);

    ignore = system("clear");

    printf("Now the Open Object Rexx script macros.rex (named upload.rex) has been loaded\n");
    printf("into Macrospace. It is now used in the name option of\n");
    printf("the REXXSTART command. \n");
    printf("It is very important that instore paramenter [0] and [1] are\n");
    printf("initialized to NULL rsp. 0 and used as REXXSTART parameters\n");

    printf("Press Enter to continue\n");
    ignore = scanf("%c", &val);

    rexxretval.strptr = NULL;       /* initialize return-pointer to empty */
    rexxretval.strlength = 0;       /* initialize return-length to zero   */

    instore[1].strptr = NULL;
    instore[1].strlength = 0;
    instore[0].strptr = NULL;
    instore[0].strlength = 0;

    rc = (*FuncAddress)(
             0,                      /* number of arguments   */
             NULL,                   /* array of arguments    */
             "upload.rex",           /* name for Rexx macrospacefile */
             instore,                /* INSTORE used          */
             "ksh",                  /* Command env. name     */
             RXCOMMAND,              /* Code for how invoked  */
             NULL,                   /* No EXITs on this call */
             &rexxrc,                /* Rexx program output   */
             &rexxretval );          /* Rexx program output   */

    printf("CALLREXX2 - Back from REXXSTART:  Return Code: %d\n", rc);
    printf("CALLREXX2 - RESULT-LENGTH:           %zd\n", rexxretval.strlength);
    printf("CALLREXX2 - RESULT-Value:            %s\n", rexxretval.strptr);

    RexxFreeMemory(rexxretval.strptr);

    free(rexxretval.strptr);

    printf("Press Enter to continue\n");
    ignore = scanf("%c", &val);

    ignore = system("clear");

    printf("Finally del_macro.rex is called to delete macros.rex (named upload.rex)\n");
    printf("out of the Open Object Rexx Macrospace.\n");

    printf("Press Enter to continue\n");
    ignore = scanf("%c", &val);

    rc = (*FuncAddress)(
             0,                      /* number of arguments   */
             NULL,                   /* array of arguments    */
             "del_macro.rex",        /* name for Rexx macrospacefile */
             NULL,                   /* INSTORE not used      */
             "ksh",                  /* Command env. name     */
             RXCOMMAND,              /* Code for how invoked  */
             NULL,                   /* No EXITs on this call */
             &rexxrc,                /* Rexx program output   */
             &rexxretval );          /* Rexx program output   */

    printf("CALLREXX2 - Back from REXXSTART:  Return Code: %d\n", rc);
    printf("CALLREXX2 - RESULT-LENGTH:           %zd\n", rexxretval.strlength);
    printf("CALLREXX2 - RESULT-Value:            %s\n", rexxretval.strptr);

    RexxFreeMemory(rexxretval.strptr);

    printf("Press Enter to continue\n");
    ignore = scanf("%c", &val);

    ignore = system("clear");
    return 0;
}

