/*
 * VMS Perl system() helper.
 * 2010-05-03 SMS.
 */

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <descrip.h>
#include <lib$routines.h>
#include <stsdef.h>

/* Temporary command procedure file name parts, format, size. */
#define FILE_COM_NAME_NAME "VMS_PSH_"
#define FILE_COM_NAME_TYPE ".COM"
#define FILE_COM_NAME_FMT "%s%08x%s"
#define FILE_COM_NAME_SIZE ((sizeof( FILE_COM_NAME_NAME)- 1)+ 8+ \
 (sizeof( FILE_COM_NAME_TYPE)- 1)+ 1)


/* Main program. */
int main( int argc, char **argv)
{
    char *angle;                        /* Pointer to "<" or ">". */
    int argn;                           /* Argument counter. */
    int *argvv;                         /* Redirect file descriptors. */
    char **argva;                       /* Redirect file name pointers. */
    char file_com_cmd[ 2+ FILE_COM_NAME_SIZE] = "@ ";
    $DESCRIPTOR( file_com_cmd_dscr, file_com_cmd);
    char *file_com_name;
    FILE *file_com;
    int flags = 0;                      /* lib$spawn() flags. */
    int sts;                            /* lib$spawn() initial status. */
    int sts_cmpl = 0;                   /* lib$spawn() completion status. */

    char *stds[ 3] = { "SYS$INPUT", "SYS$OUTPUT", "SYS$ERROR" };

    file_com_name = file_com_cmd+ 2;

    /* Allocate storage for argc-size arrays. */
    argva = malloc( argc* sizeof( argva[ 0]));
    if (argva == NULL)
    {
        exit( errno);
    }

    argvv = malloc( argc* sizeof( argvv[ 0]));
    if (argvv == NULL)
    {
        exit( errno);
    }

    /* Scan args for redirections, and record their details. */
    argn = 1;
    for (argn = 1; argn < argc; argn++)
    {
        /* Look for "n<xxxx" or "n>xxxx" form. */
        angle = strchr( argv[ argn], '<');
        if (angle != NULL)
        {
            argva[ argn] = angle+ 1;
            if (angle == argv[ argn])
            {
                argvv[ argn] = 0;       /* Bare "<" = stdin. */
            }
            else
            {
                argvv[ argn] = atoi( argv[ argn]);
            }
        }
        else
        {
            angle = strchr( argv[ argn], '>');
            if (angle != NULL)
            {
                argva[ argn] = angle+ 1;
                if (angle == argv[ argn])
                {
                    argvv[ argn] = 1;   /* Bare ">" = stdout. */
                }
                else
                {
                    argvv[ argn] = atoi( argv[ argn]);
                }
                if ((argvv[ argn] == 1) || (argvv[ argn] == 2))
                {
                    argva[ argn] = angle+ 1;
                }
            }
            else
            {
                argvv[ argn] = -1;              /* Normal argument. */
            }
        }
    }

    /* Form the (temporary) helper command procedure name. */
    sprintf( file_com_name, FILE_COM_NAME_FMT,
     FILE_COM_NAME_NAME, getpid(), FILE_COM_NAME_TYPE);

    /* Open/create the (temporary) helper command procedure file. */
    file_com = fopen( file_com_name, "w", "rfm = stmlf");
    if (file_com == NULL)
    {
        exit( errno);
    }

    /* Put out a brief descriptive comment. */
    fprintf( file_com, "%s\n", "$! VMS Perl Helper Procedure.");

    /* Put out logical name definitions for I/O redirects. */
    for (argn = 1; argn < argc; argn++)
    {
        if (argvv[ argn] >= 0)
        {
            if ((argvv[ argn] >= 0) && (argvv[ argn] < 3))
            {
                fprintf( file_com,
                 "$ define /user_mode %s %s\n",
                 stds[ argvv[ argn]], argva[ argn]);
            }
            else
            {
                fprintf( file_com,
                 "$! Unexpected redirect: %d %s\n",
                 argvv[ argn], argva[ argn]);
            }
        }
    }

    /* Put out the "openssl" command with its arguments. */
    fprintf( file_com, "$ mcr sslexe:openssl.exe");
    for (argn = 1; argn < argc; argn++)
    {
        if (argvv[ argn] < 0)
        {
            fprintf( file_com, " %s", argv[ argn]);
        }
    }
    fprintf( file_com, "\n");

    /* Put out the conditional self-destruct command. */
    fprintf( file_com,
     "$ if (f$trnlnm( \"OPENSSL_KEEP_HELPER\") .eqs. \"\") then -\n");
    fprintf( file_com,
     "$  delete 'f$environment( \"PROCEDURE\")'\n");

    fprintf( file_com, "$!\n");

    /* Close the file. */
    fclose( file_com);

    /* Execute the (temporary) helper command procedure file. */
    sts = lib$spawn( &file_com_cmd_dscr,        /* Command. */
                     NULL,                      /* SYS$INPUT. */
                     NULL,                      /* SYS$OUTPUT. */
                     &flags,                    /* Flags. */
                     NULL,                      /* Process name. */
                     NULL,                      /* Process ID, */
                     &sts_cmpl,                 /* Completion ststus. */
                     NULL,                      /* Event flag. */
                     NULL,                      /* AST address. */
                     NULL,                      /* AST argument. */
                     NULL,                      /* Prompt string. */
                     NULL,                      /* CLI. */
                     NULL);                     /* Command table. */

    /* Return an appropriate status value. */
    if ((sts& STS$M_SEVERITY) == STS$K_SUCCESS)
    {
        sts = sts_cmpl;
    }

    return sts;
}

/* Steal DECC initialization code. */

#include "../apps/vms_decc_init.c"

/* End. */
