#define	    ident	"1A05"
#ifdef VAXC
#module	    C_INTERFACES	ident
#endif
#ifdef __DECC
#pragma	    module	    C_INTERFACES	ident
#endif
/*
** +--------------------------------------------------------------+
** |                  Paul Scherrer Institute                     |
** |                     Computing Section                        |
** |                                                              |
** | This software may be used freely by non-profit organizations.|
** | It may be copied provided that the name of P.S.I. and of the |
** | author is included. Neither P.S.I. nor the author assume any |
** | responsibility for the use of this software outside of P.S.I.|
** +--------------------------------------------------------------+
**
** Module Name  . . . . . . . . : [...LIB.SINQ]C_INTERFACES.C
**
** Author   . . . . . . . . . . : D. Maden
** Date of creation . . . . . . : Nov 1993
**
**  C_INTERFACES.C provides some routines which make it easier for C programs
**  to call some of the Fortran routines in SINQ.OLB.
**
**  To include this module in SINQ.OLB, use:

  $ import tasmad
  $ define/job sinq_c_tlb mad_lib:sinq_c_tlb.tlb
  $ define/job sinq_olb   mad_lib:sinq.olb
  $ @lnsa09::tasmad_disk:[mad.psi.lib.sinq]sinq_olb c_interfaces debug
  $
  $ define/job sinq_olb   mad_lib:sinq.olb
  $ @lnsa09::tasmad_disk:[mad.psi.lib.sinq]sinq_olb c_interfaces

**
** Updates:
**  1A01 16-Nov-1993 DM.	Initial version.
**  1A02 24-Nov-1994 DM.	Make compatible with DEC C (as opposed to VAX C)
**  1A03 28-Nov-1994 DM.	Add the TT_PORT_... entry points.
**====================================================================
** The following entry pointd are included:
**  C_log_arr_get	: interface routine from C to LOG_ARR_GET.
**  C_log_flt_get	: interface routine from C to LOG_FLT_GET.
**  C_log_int_get	: interface routine from C to LOG_INT_GET.
**  C_log_str_get	: interface routine from C to LOG_STR_GET.
**
**  C_str_edit		: interface routine to STR_EDIT.
**
**  C_tt_port_connect	: interface routine to TT_PORT_CONNECT.
**  C_tt_port_disconnect: interface routine to TT_PORT_DISCONNECT.
**  C_tt_port_io	: interface routine to TT_PORT_IO.
**  C_tt_port_config	: interface routine to TT_PORT_CONFIG.
**====================================================================
**			Global Definitions
*/
#ifdef VAXC
#include    stdio
#include    descrip
#include    string
#include    sinq_prototypes
#else
#include    <stdio.h>
#include    <sys/descrip.h>
#include    <sys/string.h>
#include    <sinq_prototypes.h>
#endif
/*--------------------------------------------------------------------------
**			Global Variables
*/
extern int C_gbl_status = 0;
extern struct dsc$descriptor_s C_name_desc = { 0,
  DSC$K_DTYPE_T,
  DSC$K_CLASS_S,
  0
};

/*--------------------------------------------------------------------------
**				Old-style prototypes of routines which we are
**				bridging to.
*/
int log_arr_get();
int log_int_get();
int log_flt_get();
int log_str_get();

int str_edit();

int tt_port_connect();
int tt_port_disconnect();
int tt_port_io();
int tt_port_config();
/*--------------------------------------------------------------------------*/
int C_log_arr_get(char *name, int arr_size, int *value, int indx)
{
/*    =============
**
**	    This routine is useful for calling LOG_ARR_GET from a C program.
**
**  Inputs:
**	name	    - a pointer to the zero-terminated logical name.
**	arr_size    - the number of elements in the array value.
**	indx	    - the index of the logical name.
**  Outputs:
**	value	    - an array of size arr_size set to the values converted
**			    to binary.
**  Return status:
**	the return status of the function is zero (false) if LOG_ARR_GET
**	    returns an error (even) condition code.
**  Global variables:
**	C_gbl_status  - set to the VAX/VMS return status of LOG_ARR_GET.
**	C_name_desc   - set up as a string descriptor for name. It can
**		    be used to generate an error message if return status == 0.
*/
  C_name_desc.dsc$w_length = strlen(name);
  C_name_desc.dsc$a_pointer = name;

  C_gbl_status = log_arr_get(&C_name_desc, &arr_size, value, &indx);

  return (C_gbl_status & 1);
}

/*--------------------------------------------------------------------------*/
int C_log_int_get(char *name, long int *value, int indx)
{
/*    =============
**
**	    This routine is useful for calling LOG_INT_GET from a C program.
**
**  Inputs:
**	name	    - a pointer to the zero-terminated logical name.
**	indx	    - the index of the logical name.
**  Outputs:
**	value	    - the value of the logical converted to binary.
**  Return status:
**	the return status of the function is zero (false) if LOG_INT_GET
**	    returns an error (even) condition code.
**  Global variables:
**	C_gbl_status  - set to the VAX/VMS return status of LOG_INT_GET.
**	C_name_desc   - set up as a string descriptor for name. It can
**		    be used to generate an error message if return status == 0.
*/
  C_name_desc.dsc$w_length = strlen(name);
  C_name_desc.dsc$a_pointer = name;

  C_gbl_status = log_int_get(&C_name_desc, value, &indx);

  return (C_gbl_status & 1);
}

/*--------------------------------------------------------------------------*/
int C_log_flt_get(char *name, float *value, int indx)
{
/*    =============
**
**	    This routine is useful for calling LOG_FLT_GET from a C program.
**
**  Inputs:
**	name	    - a pointer to the zero-terminated logical name.
**	indx	    - the index of the logical name.
**  Outputs:
**	value	    - the value of the logical converted to binary.
**  Return status:
**	the return status of the function is zero (false) if LOG_FLT_GET
**	    returns an error (even) condition code.
**  Global variables:
**	C_gbl_status  - set to the VAX/VMS return status of LOG_FLT_GET.
**	C_name_desc   - set up as a string descriptor for name. It can
**		    be used to generate an error message if return status == 0.
*/
  C_name_desc.dsc$w_length = strlen(name);
  C_name_desc.dsc$a_pointer = name;

  C_gbl_status = log_flt_get(&C_name_desc, value, &indx);

  return (C_gbl_status & 1);
}

/*--------------------------------------------------------------------------*/
int C_log_str_get(char *name, char *value, int val_size, int indx)
{
/*    =============
**
**	    This routine is useful for calling LOG_STR_GET from a C program.
**
**  Inputs:
**	name	    - a pointer to the zero-terminated logical name.
**	val_size    - the size of the value string.
**	indx	    - the index of the logical name.
**  Outputs:
**	value	    - zero-terminated string giving the value of the logical.
**			Trailing space characters will have been stripped.
**  Return status:
**	the return status of the function is zero (false) if LOG_STR_GET
**	    returns an error (even) condition code.
**  Global variables:
**	C_gbl_status  - set to the VAX/VMS return status of LOG_STR_GET.
**	C_name_desc   - set up as a string descriptor for name. It can
**		    be used to generate an error message if return status == 0.
*/
  struct dsc$descriptor_s my_val_desc = { 0,
    DSC$K_DTYPE_T,
    DSC$K_CLASS_S,
    0
  };

  C_name_desc.dsc$w_length = strlen(name);
  C_name_desc.dsc$a_pointer = name;

  my_val_desc.dsc$w_length = val_size - 1;
  my_val_desc.dsc$a_pointer = value;

  C_gbl_status = log_str_get(&C_name_desc, &my_val_desc, &indx);
  value[val_size - 1] = 0;      /* Zero-terminate the string */

  if (C_gbl_status & 1) {       /* If success, strip trailing spaces */
    while ((strlen(value) > 0) && (value[strlen(value) - 1] == ' ')) {
      value[strlen(value) - 1] = 0;
    }
  }
  return (C_gbl_status & 1);
}

/*--------------------------------------------------------------------------*/
int C_str_edit(char *out, char *in, char *ctrl, int *length)
{
/*    ==========
**
**	    This routine is useful for calling STR_EDIT from a C program.
**
**  Inputs:
**	in	    - the string to be edited.
**	ctrl	    - the string specifying what editing is to be done.
**  Outputs:
**	out	    - the edited string. The maximum size of this string must
**			be specified as input parameter *length. The string
**			will be zero terminated on return.
**  Modified:
**	*length	    - an integer specifying, on input, the length of "out" in
**		      bytes. This must include room for the zero termination.
**		      On return, length will be set to the number of characters
**		      copied to "out" (not counting the zero termination byte).
**  Return status:
**	the return status of the function is zero (false) if STR_EDIT
**	    returns an error (even) condition code.
**  Global variables:
**	C_gbl_status  - set to the VAX/VMS return status of STR_EDIT.
*/
  struct dsc$descriptor_s out_desc = { 0,
    DSC$K_DTYPE_T,
    DSC$K_CLASS_S,
    0
  };
  struct dsc$descriptor_s in_desc = { 0,
    DSC$K_DTYPE_T,
    DSC$K_CLASS_S,
    0
  };
  struct dsc$descriptor_s ctrl_desc = { 0,
    DSC$K_DTYPE_T,
    DSC$K_CLASS_S,
    0
  };

  out_desc.dsc$w_length = *length - 1;
  out_desc.dsc$a_pointer = out;

  in_desc.dsc$w_length = strlen(in);
  in_desc.dsc$a_pointer = in;

  ctrl_desc.dsc$w_length = strlen(ctrl);
  ctrl_desc.dsc$a_pointer = ctrl;

  C_gbl_status = str_edit(&out_desc, &in_desc, &ctrl_desc, length);
  if (*length >= 0) {           /* zero-terminate the output string */
    out[*length] = '\0';
  } else {
    out[0] = '\0';
  }

  return (C_gbl_status & 1);
}

/*--------------------------------------------------------------------------*/
int C_tt_port_connect(int *hndl, int *chan, char *lognam, char *pwd)
{
/*    =================
**
**	    This routine is useful for calling TT_PORT_CONNECT from a C program.
**
**  Inputs:
**	lognam	    - a zero-terminated string specifying a logical name which
**		      defines the RS-232-C port to be connected. See description
**		      of TT_PORT_CONNECT for full details.
**	pwd	    - a zero-terminated string specifying an optional password.
**		      This is the password associated with a terminal server
**		      service. See description of TT_PORT_CONNECT for full
**		      details. Specify NULL if no password.
**  Outputs:
**	hndl	    - an integer handle identifying the connection. It will be
**		      the address of a dynamically allocated data structure.
**	chan	    - an integer (actually only 16 bit) giving the I/O channel
**		      associated with the connection. This can be used in QIO
**		      system calls to the terminal driver.
**  Return status:
**	the return status of the function is zero (false) if TT_PORT_CONNECT
**	    returns an error (even) condition code.
**  Global variables:
**	C_gbl_status  - set to the VAX/VMS return status of TT_PORT_CONNECT.
*/
  struct dsc$descriptor_s lognam_desc = { 0,
    DSC$K_DTYPE_T,
    DSC$K_CLASS_S,
    0
  };
  struct dsc$descriptor_s pwd_desc = { 0,
    DSC$K_DTYPE_T,
    DSC$K_CLASS_S,
    0
  };
  lognam_desc.dsc$w_length = strlen(lognam);
  lognam_desc.dsc$a_pointer = lognam;

  if (pwd != NULL) {
    pwd_desc.dsc$w_length = strlen(pwd);
    pwd_desc.dsc$a_pointer = pwd;
    C_gbl_status = tt_port_connect(hndl, chan, &lognam_desc, &pwd_desc);
  } else {
    C_gbl_status = tt_port_connect(hndl, chan, &lognam_desc, NULL);
  }

  return (C_gbl_status & 1);
}

/*--------------------------------------------------------------------------*/
int C_tt_port_disconnect(int *hndl)
{
/*    ====================
**
**	 This routine is useful for calling TT_PORT_DISCONNECT from a C program.
**
**  Inputs:
**	hndl	    - the integer handle identifying the connection as returned
**		      by C_tt_port_connect. It is the address of a dynamically
**		      allocated data structure which will also be released
**		      after the connection has been closed.
**  Return status:
**	the return status of the function is zero (false) if TT_PORT_DISCONNECT
**	    returns an error (even) condition code.
**  Global variables:
**	C_gbl_status  - set to the VAX/VMS return status of TT_PORT_DISCONNECT.
*/
  C_gbl_status = tt_port_disconnect(hndl);

  return (C_gbl_status & 1);
}

/*--------------------------------------------------------------------------*/
int C_tt_port_io(
/*    ============
*/ int *hndl,
                  char *rqst, char *term, char *answ, int *answ_len,    /* Attention -- Read/Write argument!! */
                  int flush, int tmo)
{
/*
**	    This routine is useful for calling TT_PORT_IO from a C program.
**	    Refer to the DELTAT.OLB description of TT_PORT_IO to clarify any
**	    uncertainties in the following description. Note that all arguments
**	    must be present (there is no portable method in C of getting the
**	    number of arguments in the call!).
**  Inputs:
**	hndl	    - the integer handle identifying the connection as returned
**		      by C_tt_port_connect.
**	rqst	    - an optional zero-terminated string specifying a character
**		      string to be sent to the port. Specify NULL to not send
**		      any characters to the port.
**	term	    - an optional zero-terminated string specifying a list of
**		      terminating characters for input read from the port.
**		      Specify NULL to terminate input on an exact character cnt.
**	flush	    - an integer specifying if the type-ahead buffer should be
**		      flushed before the operation. If non-zero, the buffer
**		      is flushed.
**	tmo	    - an integer (recommended value = 2) specifying a read
**		      time-out in seconds. Zero or negative indicates infinity.
**  Outputs:
**	answ	    - an optional string buffer to receive characters read from
**		      the port. If answ is not NULL, answ_len must also be
**		      not NULL. On return, answ will be zero terminated. The
**		      terminating character, if any (there is no terminating
**		      char if the buffer overflows) and if there is room in
**		      the buffer, will follow the zero character. No padding is
**		      done. If answ is NULL, no characters are read from the
**		      port.
**  Modify:
**	answ_len    - an integer specifying, on input, the length of answ in
**		      bytes. This must include room for the zero termination.
**		      On return, answ_len will be set to the number of
**		      characters read (not counting the zero termination byte or
**		      any terminating character).
**  Return status:
**	the return status of the function is zero (false) if TT_PORT_IO
**	    returns an error (even) condition code.
**  Global variables:
**	C_gbl_status  - set to the VAX/VMS return status of TT_PORT_IO.
*/
  struct dsc$descriptor_s rqst_desc = { 0,
    DSC$K_DTYPE_T,
    DSC$K_CLASS_S,
    0
  };
  struct dsc$descriptor_s term_desc = { 0,
    DSC$K_DTYPE_T,
    DSC$K_CLASS_S,
    0
  };
  struct dsc$descriptor_s answ_desc = { 0,
    DSC$K_DTYPE_T,
    DSC$K_CLASS_S,
    0
  };
  char *my_rqst = NULL;
  char *my_term = NULL;
  char *my_answ = NULL;

  int my_answ_len = 0;
  int my_flush = 1;
  int my_tmo = 2;

  my_tmo = tmo;
  if (my_tmo < 0)
    my_tmo = 0;
  my_flush = flush;
  if (my_flush != 0)
    my_flush = 1;
  if (answ != NULL) {
    if (answ_len == 0) {
      printf("C_tt_port_io -- argument error.\n");
      printf("                %s\n",
             "answ_len must be present if answ is present.");
      C_gbl_status = FALSE;
      return FALSE;
    }
    answ_desc.dsc$w_length = *answ_len - 1;
    answ_desc.dsc$a_pointer = answ;
  }
  if (term != NULL) {
    term_desc.dsc$w_length = strlen(term);
    term_desc.dsc$a_pointer = term;
  }
  if (rqst != NULL) {
    rqst_desc.dsc$w_length = strlen(rqst);
    rqst_desc.dsc$a_pointer = rqst;
  }
  C_gbl_status = tt_port_io(hndl, &rqst_desc, &term_desc,
                            &answ_desc, &my_answ_len, &my_flush, &my_tmo);
  if (answ_desc.dsc$w_length > 0) {     /* Process any input string */
    if (answ_desc.dsc$w_length > my_answ_len) { /* Room for terminator? */
      answ[my_answ_len + 1] = answ[my_answ_len];        /* Yes, so move it. */
    }
    answ[my_answ_len] = '\0';   /* Put in null terminator */
    *answ_len = my_answ_len;    /* Return value to caller */
  }

  return (C_gbl_status & 1);
}

/*--------------------------------------------------------------------------*/
int C_tt_port_config(
/*    ================
*/ int *hndl,
                      int mask)
{
/*
**	    This routine is useful for calling TT_PORT_CONFIG from a C program.
**	    Refer to the DELTAT.OLB description of TT_PORT_CONFIG to clarify any
**	    uncertainties in the following description.
**  Inputs:
**	hndl	    - the integer handle identifying the connection as returned
**		      by C_tt_port_connect.
**	mask	    - an integer specifying the configuration options. Set bits
**			TT_PORT__NO_RETRY = 0x0001 to suppress retries on error
**			TT_PORT__NO_SIG   = 0x0002 to suppress signals on error
**  Outputs:
**	None
**  Modify:
**	None
**  Return status:
**	always non-zero (true).
**  Global variables:
**	C_gbl_status  - set to the VAX/VMS return status of TT_PORT_CONFIG.
*/
  C_gbl_status = tt_port_config(hndl, &mask);

  return (C_gbl_status & 1);
}

/*=========================================== End of C_INTERFACES.C ========*/
