/*
 *    GNU getprogname() for VMS.
 *
 *======================================================================
 *
 *       getprogname()
 *
 *    Get image name using SYS$GETJPI().
 *
 *    Return: Pointer (char *) to allocated storage.
 *
 * 2022-08-08 SMS.  New.
 */

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

#include <jpidef.h>
#include <starlet.h>
#include <stsdef.h>

#include "vms_rms.h"

/*--------------------------------------------------------------------*/

/* GETJPI item descriptor structure. */
typedef struct
  {
  short buf_len;
  short itm_cod;
  void *buf;
  int *ret_len;
  } jpi_item_t;

char const *getprogname( void)
{
  char *p = NULL;
  int sts = 0;

  struct FAB fab;                       /* FAB structure. */
  struct NAMX_STRUCT nam;               /* NAM[L] structure. */

  char exp_str[ NAMX_MAXRSS+ 1];        /* Expanded name storage. */

/* JPI item buffer. */
  int img_name_len;
  int img_name_siz = 10240;
  char *img_name_p;

/* GETJPI item descriptor set. */
  struct
  {
    jpi_item_t img_name_itm;
    int term;
  } jpi_itm_lst =
     /* buf_len  itm_cod   buf   ret_len */
     { { 0, JPI$_IMAGNAME, NULL, &img_name_len },
       0 /* Item-list terminator. */
     };

/*--------------------------------------------------------------------*/

/* Get process image name. */

  img_name_p = malloc( img_name_siz+ 1);
  if (img_name_p != NULL)   
  {
    jpi_itm_lst.img_name_itm.buf_len = img_name_siz;
    jpi_itm_lst.img_name_itm.buf = img_name_p;

    /* Get the image file spec. */
    sts = sys$getjpiw( 0, 0, 0, &jpi_itm_lst, 0, 0, 0);
    if ((sts& STS$M_SEVERITY) == STS$M_SUCCESS)
    {
      /* Parse the image file spec. */

      /* Initialize the FAB and NAM[L], and link the NAM[L] to the FAB. */
      fab = cc$rms_fab;
      nam = CC_RMS_NAMX;
      fab.FAB_NAMX = &nam;

      /* Point the FAB/NAM[L] fields to the actual name (null default name). */
      NAMX_DNA_FNA_SET( fab)
      FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNA = img_name_p;
      FAB_OR_NAML( fab, nam).FAB_OR_NAML_FNS = img_name_len;

      nam.NAMX_ESA = exp_str;           /* Expanded name (result) storage. */
      nam.NAMX_ESS = NAMX_MAXRSS;       /* Size of expanded name storage. */

      nam.NAMX_NOP = NAMX_M_SYNCHK;     /* Syntax-only analysis. */

      sts = sys$parse( &fab, 0, 0);     /* Parse the name. */

      if ((sts& STS$M_SEVERITY) == STS$M_SUCCESS)
      {
#ifdef GETPROGNAME_VMS_NAME_ONLY
        /* Pluck out the name segment. */

        /* Truncate/NUL-terminate the resulting file spec after the name. */
        /* (There's always a type, even if it's only ".".) */
        *(nam.NAMX_L_TYPE) = '\0';

        /* Allocate storage for returned name, and copy in the name. */
        p = malloc( nam.NAMX_B_NAME+ 1);
        if (p != NULL)
        {
          strncpy( p, nam.NAMX_L_NAME, nam.NAMX_B_NAME+ 1);
        }
#else /* def GETPROGNAME_VMS_NAME_ONLY */
        /* Keep the whole file spec. */

        size_t n_len;           /* Resulting file spec length (+1). */

        /* Truncate (NUL-terminate) the resulting file spec. */
        *(nam.NAMX_L_VER+ nam.NAMX_B_VER) = '\0';

        /* Allocate storage for returned spec, and copy in the spec. */
        n_len = strlen( exp_str)+ 1;
        p = malloc( n_len);
        if (p != NULL)
        {
          strncpy( p, exp_str, n_len);
        }
#endif /* def GETPROGNAME_VMS_NAME_ONLY [else] */

        /* Discard/hide the VMS system-service success status. */
        sts = 0;
      }
    }
    free( img_name_p);          /* Free $GETJPI image-name storage. */
  }
  if (p == NULL)
  {
    /* If no real name is available, try to return the no-name error
     * string ("?").  (Who designs this stuff?)
     * If a VMS system service failed, set the errno's accordingly.
     */
    if (sts != 0)
    {
      errno = EVMSERR;
      vaxc$errno = sts;
    }
    p = strdup( "?");           /* No-name error string (or NULL). */
  }

  return p;                     /* Return allocated image name. */
}

/*--------------------------------------------------------------------*/

/* Test main program.  (Doesn't really test errors.) */

#ifdef TEST_GETPROGNAME

int main( int argc, char **argv)
{
    char *i_n;

    fprintf( stdout, " Name: >%s<.\n", getprogname());

    return 0;
}

#endif /* def TEST_GETPROGNAME */
