#define	    ident	    "1A09"

#ifdef __DECC
#pragma	    module	    asynsrv_test	ident
#endif
/*
** +--------------------------------------------------------------+
** |                  Paul Scherrer Institute                     |
** |                     SINQ Project				  |
** |                                                              |
** | 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.|
** +--------------------------------------------------------------+
**
** Link_options - Here is the Linker Option File
**!$	if p1 .eqs. "DEBUG" then dbg1 := /debug
**!$	if p1 .eqs. "DEBUG" then dbg2 := _dbg
**!$	link 'dbg1'/exe=asynsrv_test'dbg2'.exe sys$input/options
**!	    asynsrv_test
**!	    sinq_olb/lib
**!	    sys$share:decw$xmlibshr12/share
**!	    sys$share:decw$xtlibshrr5/share
**!	    sys$share:decw$xlibshr/share
**!$	purge/nolog asynsrv_test'dbg2'.exe
**!$	write sys$output "Exec file is asynsrv_test''DBG2'.exe
**!$	exit
**!!
**!! To build on LNSA01 ...
**!!	$ build_cc_select :== decc
**!!	$ import tasmad
**!!	$ define/job deltat_c_tlb sinq_c_tlb
**!!	$ set default ud0:[maden.scratch]
**!!	$ bui tasmad_disk:[mad.tests]asynsrv_test debug
**!!
** Link_options_end
**
**	Building on Alpha Digital Unix:
**
**	    setenv TAS_BASE ~maden/tasmad
**	    source $TAS_BASE/tasmad.setup
**	    rcp -p "lnsa09:tas_src:[utils]asynsrv_test.c" \
**			$TAS_SRC/utils/asynsrv_test.c
**	    cc -std -g -o $TAS_BIN/asynsrv_test    \
**			-I$TAS_INC		    \
**			$TAS_SRC/utils/asynsrv_test.c \
**			-L$TAS_LIB -lsinq -lXm -lXt -lX11
**
** Resources and Flags	    File:	decw$user_defaults:SinQ_rc.dat
** -------------------		    or	$HOME/SinQ_rc
**
**  Resource	    Flag    Default	  Description
**  --------	    ----    -------	  -----------
**  -		    -name   asynsrv_test  Name to use when looking up the
**						resources. The default is the
**						image file name.
**  *AsynSrvHelp    -help   -		  Generates help info.
**  *AsynSrvHost    -host   none	  The name of the host to which the
**						program wishes to connect.
**  *AsynSrvPort    -port   4000	  The TCP/IP port of the RS232C server.
**  *AsynSrvChan    -chan   none	  The number of the RS232C channel to
**						which the device is attached.
**  *AsynSrvTmo	    -tmo    2		  Time-out in secs for responses to
**  *AsynSrvTmoConn -tmoC   5		  Time-out in secs for connect.
**					    commands.
**  *AsynSrvDebug   -debug  		  If specified, selects debug mode (not
**					    yet implemented).
**  *AsynSrvLower   -lc     -		  If specified, causes conversion of
**					    input to lowercase before sending.
**  *AsynSrvUpper   -uc     -		  If specified, causes conversion of
**					    input to uppercase before sending.
**					    This is the default.
**  *AsynSrvNoCase  -ncc    -		  If specified, causes no case
**					    conversion of input before sending.
**  *AsynSrvTermOut -termout "\r"	  Specifies a string to be appended to
**					    anything sent to the server.
**  *AsynSrvTermIn  -termin  "\r"	  Specifies a string of up to 3 chars
**					    which will be recognised as 
**					    input response terminators.
**  A value given via -name will be converted to lowercase before being used.
**+
**---------------------------------------------------------------------------
** Module Name  . . . . . . . . : [...tests]asynsrv_test.c
**
** Author   . . . . . . . . . . : D. Maden
** Date of creation . . . . . . : Jan 1997
**
** Purpose
** =======
**	asynsrv_test is a TCP/IP server client which should make a TCP/IP
**	connection to an RS-232-C server and allow the user to transmit
**	commands from the keyboard to a device attached to an RS-232-C channel
**	on the server.
** Use:
** ===
**  1) Set up the host name, TCP/IP port number and RS-232-C channel of the
**	device in the resources file (see above). These can also
**	be supplied as options on the command line.
**
**  2) Run the program
**
**	    $ run cpt:[exe]asynsrv_test
**
**	or, to specify options on the command line, use a DCL foreign
**	command:
**
**	    $ asynsrv_test :== $cpt:[exe]asynsrv_test
**	    $ asynsrv_test -host <host> -port <port-number> -chan <chan>
**
** Updates:
**  1A01 20-Jan-1997 DM.	Initial version.
**  1A07  3-Apr-2000 DM.        Add fortify.h
**-
**====================================================================
*/
#include    <stdlib.h>
#include    <stdio.h>
#include    <signal.h>
#include    <ctype.h>

#include    <time.h>

#ifdef  __VMS
  #include    <sys/unixio.h>
#else
  #include    <unistd.h>
  #ifdef FORTIFY
    #include    <fortify/fortify.h>
  #endif
#endif

#include    <X11/Intrinsic.h>
/*
**====================================================================
*/
#include    <sinq_prototypes.h>
#include    <asynsrv_def.h>
#include    <rs232c_def.h>
/*

**--------------------------------------------------------------------------
**			Define global structures and constants.
*/
/*-------------------------------------------------------------
**			Global Variables
*/
  static int	C_gbl_status;	    /*  Return status from C_... routines */
  static int	Ctrl_C_has_happened;
  void	       *Hndl = NULL;

  static XrmOptionDescRec OpTable[] = {
      {"-name",	    ".name",		XrmoptionSepArg, (XPointer) NULL},
      {"-help",	    ".AsynSrvHelp",	XrmoptionNoArg,	 (XPointer) "1"},
      {"-host",	    ".AsynSrvHost",	XrmoptionSepArg, (XPointer) NULL},
      {"-port",	    ".AsynSrvPort",	XrmoptionSepArg, (XPointer) NULL},
      {"-chan",	    ".AsynSrvChan",	XrmoptionSepArg, (XPointer) NULL},
      {"-tmoC",	    ".AsynSrvTmoConn",	XrmoptionSepArg, (XPointer) NULL},
      {"-tmoc",	    ".AsynSrvTmoConn",	XrmoptionSepArg, (XPointer) NULL},
      {"-tmo",	    ".AsynSrvTmo",	XrmoptionSepArg, (XPointer) NULL},
      {"-debug",    ".AsynSrvDebug",	XrmoptionNoArg,	 (XPointer) "1"},
      {"-lc",	    ".AsynSrvLower",	XrmoptionNoArg,  (XPointer) "1"},
      {"-uc",	    ".AsynSrvUpper",	XrmoptionNoArg,  (XPointer) "1"},
      {"-ncc",	    ".AsynSrvNoCase",	XrmoptionNoArg,  (XPointer) "1"},
      {"-termout",  ".AsynSrvTermOut",	XrmoptionSepArg, (XPointer) NULL},
      {"-termin",   ".AsynSrvTermIn",	XrmoptionSepArg, (XPointer) NULL},
    };
  struct AsynSrv__info	AsynSrv_info;
  int			Debug;
  float			TmoC;
  float			Tmo;
  int			DoLower, DoUpper;
  char			TermOut[16];
  char			TermIn[16];
  int			Do_help;

  char		    *Errstack;
  int		    Errcode, Errno, Vaxc_errno;
/*
**--------------------------------------------------------------------------
**		PrintErrInfo:  print out error information.
*/
  void	PrintErrInfo (char *text) {
/*      ============
*/

    AsynSrv_ErrInfo (&Errstack, &Errcode, &Errno, &Vaxc_errno);
    fprintf (stderr, "\n"
		"  Error return from %s.\n"
		"    Errstack = \"%s\".\n"
		"    Errcode = %d.  Errno = %d. Vaxc$errno = %d.\n",
		text, Errstack, Errcode, Errno, Vaxc_errno);
    switch (Errcode) {
     case ASYNSRV__BAD_BIND:
      fprintf (stderr, "ASYNSRV__BAD_BIND\n");
      break;
     case ASYNSRV__BAD_CONNECT:
      fprintf (stderr, "ASYNSRV__BAD_CONNECT\n");
      break;
     case ASYNSRV__BAD_HOST:
      fprintf (stderr, "ASYNSRV__BAD_HOST\n");
      break;
     case ASYNSRV__BAD_PAR:
      fprintf (stderr, "ASYNSRV__BAD_PAR\n");
      break;
     case ASYNSRV__BAD_SOCKET:
      fprintf (stderr, "ASYNSRV__BAD_SOCKET\n");
      break;
     case ASYNSRV__NO_ROOM:
      fprintf (stderr, "ASYNSRV__NO_ROOM\n");
      break;
     default:
      fprintf (stderr, "Unrecognised error code!\n");
      if ((Errno != 0) || (Vaxc_errno != 0)) perror (text);
    }
    return;
  }
/*
**--------------------------------------------------------------------------
**		ShowUsage:  A simple print-out routine.
*/
  void	ShowUsage (int full) {
/*      =========
*/
    if (!full) {
      if (Do_help) return;
      printf ("\n"
	"To get help on running the program issue the command:\n"
	"\n"
	"       asynsrv_test -help\n"
	"\n");
      return;
    }
    printf ("\n"
	"Usage:  asynsrv_test [options ...]\n"
	" \n"
	" Valid options are:             Equivalent resource name:\n"
	"    -help                           *AsynSrvHelp\n"
	"    -host     <host-name>           *AsynSrvHost\n"
	"    -port     <port-number>         *AsynSrvPort     Dflt=4000\n"
	"    -chan     <channel-number>      *AsynSrvChan\n"
	"    -debug                          *AsynSrvDebug\n"
	"    -tmo      <secs>                *AsynSrvTmo      Dflt=2\n"
	"    -tmoC     <secs>                *AsynSrvTmoConn  Dflt=5\n"
	"    -lc                             *AsynSrvLower\n"
	"    -uc                             *AsynSrvUpper\n"
	"    -ncc                            *AsynSrvNoCase\n"
	"    -termout  <term-out-string>     *AsynSrvTermOut  Dflt=\"\\r\"\n"
	"    -termin   <term-in-string>      *AsynSrvTermIn   Dflt=\"\\r\"\n"
	"    -termin\n"
	"\n"
	" No default is allowed for -host or -chan,"
					    " i.e. values for\n"
	" these parameters must be supplied either via a resource file or"
					    " on the\n"
	" command line.\n"
	"\n"
	" -tmo  is the time-out for responses to commands.\n"
	" -tmoC is the time-out for the initial connection to the server.\n"
	"\n"
	"To quit the program,    issue the command \"#q\".\n"
	"To send a null command, issue the command \"\\0\".\n"
	"Other special commands are:\n"
	"      #help\n"
	"      #close        - gets SerPortServer to close its serial ports.\n"
	"      #flush        - gets SerPortServer to flush its output.\n"
	"      #trace off    - turn off SerPortServer tracing.\n"
	"      #trace on     - turn on  SerPortServer tracing.\n"
	"      #trace write  - gets SerPortServer to write its trace buffer.\n"
	"To send a command starting with \"#\", start it with \"##\".\n"
	"\n");
    return;
  }
/*
**--------------------------------------------------------------------------
**		DoInteract:  Interact with the RS-232-C Device
*/
  int	DoInteract () {
/*      ==========
*/
    int	    status, go_on, no_errors, no_restore, i, j, len, act_len, tok_len;

    FILE    *lun;
    char    recd[132], buff[132], cmnd[132], cmnd_prnt[512];
    char    eot_save[4], tmo_save[4], term;
    char    *rptr, *tok;

    struct RS__MsgStruct    send_buff;
    struct RS__RespStruct   rcve_buff;

    lun = stdin;			    /* Use standard input */

    go_on = True;
    no_errors  = True;

    if (lun == stdin) {
      printf ("Issue the command \"#h\" for help and \"#q\" to quit.\n> ");
      fflush (NULL);
    }
    while (go_on && (fgets (recd, sizeof (recd), lun) != NULL)) {
      len = strlen (recd);
      if (len <= 1) {
	if (lun == stdin) {printf ("> "); fflush (NULL);}
        continue;
      }
      if (recd[len-1] != '\n') {
	recd[20] = '\0';
        printf ("   Record not terminated by \"\\n\". "
			    "It is probably too long!\n"
		"   The record starts thus: %s ...\n"
		"   It has been skipped.\n", recd);
	if (lun == stdin) {printf ("> "); fflush (NULL);}
	continue;
      }
      recd[len-1] = '\0';	/* Remove the terminating "\n" */
	    /*
	    ** Strip off any trailing stuff (but keep it around so that we
	    ** can print it out). "Trailing stuff" is anything after a "!".
	    */
      act_len = strcspn (recd, "!");
      len = sizeof (buff);
      if (DoLower) {
	StrEdit (buff, recd, "trim uncomment lowercase", &len);
      }else if (DoUpper) {
	StrEdit (buff, recd, "trim uncomment upcase", &len);
      }else {
	StrEdit (buff, recd, "trim uncomment", &len);
      }

      len = sizeof (cmnd);
      StrEdit (cmnd, buff, "lowercase", &len);

      if (strncmp (buff, "##", 2) == 0) {   /* "##" at start gets compressed
					    ** to "#" */
        len = sizeof (buff);
	StrEdit (buff, &buff[1], "trim", &len);
      }

      tok = strtok (cmnd, " ");
      tok_len = (tok != NULL) ? strlen (tok) : 0;
      if ((tok_len >= 2) &&
	  (strncmp (tok, "#exit", tok_len) == 0)) {
        go_on = False;
      }else if ((tok_len >= 2) &&
		(strncmp (tok, "#quit", tok_len) == 0)) {
        go_on = False;
      }else if ((tok_len >= 2) &&
		(strncmp (tok, "#trace", tok_len) == 0)) {
        tok = strtok (NULL, " ");
	tok_len = (tok != NULL) ? strlen (tok) : 0;
	if ((tok_len >= 2) &&
	    (strncmp (tok, "on", tok_len) == 0)) {
	  printf ("Requesting server to turn tracing on ..."); fflush (NULL);
          status = AsynSrv_Trace (&AsynSrv_info, True);
	  if (status) {
	    printf (" done.\n");
	  }else {
	    printf ("\nError detected!\n");
	  }
	}else if ((tok_len >= 2) &&
		  (strncmp (tok, "off", tok_len) == 0)) {
	  printf ("Requesting server to turn tracing off ..."); fflush (NULL);
          status = AsynSrv_Trace (&AsynSrv_info, False);
	  if (status) {
	    printf (" done.\n");
	  }else {
	    printf ("\nError detected!\n");
	  }
	}else if ((tok_len >= 1) &&
		  (strncmp (tok, "write", tok_len) == 0)) {
	  printf ("Requesting server to write trace ..."); fflush (NULL);
          status = AsynSrv_Trace_Write (&AsynSrv_info);
	  if (status) {
	    printf (" done.\n");
	  }else {
	    printf ("\nError detected!\n");
	  }
	}else {
          printf ("Illegal \"#trace\" command! You must "
		    "specify \"on\" or \"off\" or \"write\".\n");
	}
      }else if ((tok_len >= 2) &&
		(strncmp (tok, "#flush", tok_len) == 0)) {
	printf ("Requesting server to flush ..."); fflush (NULL);
        status = AsynSrv_Flush (&AsynSrv_info);
	if (status) {
	  printf (" done.\n");
	}else {
	  printf ("\nError detected!\n");
	}
      }else if ((tok_len >= 2) &&
		(strncmp (tok, "#close", tok_len) == 0)) {
	printf ("Requesting server to close its serial channels ..."); fflush (NULL);
        status = AsynSrv_ChanClose (&AsynSrv_info);
	if (status) {
	  printf (" done.\n");
	}else {
	  printf ("\nError detected!\n");
	}
      }else if ((tok_len >= 2) &&
		(strncmp (tok, "#help", tok_len) == 0)) {
	ShowUsage (True);
      }else if ((cmnd[0] == '#') && (cmnd[1] != '#')) {
        printf ("Illegal command! If you really want to start a command\n"
		"                 with a \"#\" character, you should use\n"
		"                 \"##\" instead!\n");
      }else {
	if (strlen (buff) > 0) {
	  StrJoin (buff, sizeof (buff), buff, TermOut);	/* Append terminator */
	}
		    /*
		    ** Show user what's getting sent
		    */
	MakePrintable (cmnd_prnt, sizeof (cmnd_prnt), buff);
        printf ("Sending  \"%s\" ... ", cmnd_prnt); fflush (NULL);

	status = AsynSrv_SendCmnds (&AsynSrv_info, &send_buff, &rcve_buff,
					buff, NULL);
	if (!status) {
	  go_on = no_errors = False;
	  continue;
	}else {
	  rptr = AsynSrv_GetReply (&AsynSrv_info, &rcve_buff, NULL);
	  if (rptr == NULL) {
	    printf ("No response from server!\n");
	    go_on = no_errors = False;
	    continue;
	  }else {
	    AsynSrv_GetLenTerm (&AsynSrv_info, &rcve_buff, rptr, &len, &term);
	    MakeMemPrintable (cmnd_prnt, sizeof (cmnd_prnt), rptr, len);
	    MakeMemPrintable (recd, sizeof (recd), &term, 1);
	    j = strlen (cmnd_prnt);
	    printf ("\nResponse length = %d. Terminator = \"%s\".\n", len, recd);
	    for (i = 0; i < (j/70); i++)
	      printf ("   \"%.70s\"\\...\n", &cmnd_prnt[i*70]);
	    printf ("   \"%s\"\n", &cmnd_prnt[i*70]);
	  }
	}
      }
      if (lun == stdin) {printf ("> "); fflush (NULL);}
    }

    if (no_errors) {
      printf ("\"Interaction\" completed.\n");
    }else {
      printf ("Interaction failed.\n");
    }
    return no_errors;
  }
/*
**---------------------------------------------------------------------------
**			SetupXrmDatabase    - setup Resource Manager Database
*/
  int	SetupXrmDatabase (
/*	================
*/			XrmDatabase	*db,
			char		*name[],
			int		*argc,
			char		*argv[]) {

    static char	our_name[80]  = "Unknown";  /* This holds the program name */
    static char lkup_name[80] = "Unknown";  /* Name for looking in database */

    int		status, i, first = True;
    char	text[80];
    char	full_nm0[80];
    char	full_nm1[80];
    char	*p_fil[] = {0,0,0,0,0,0,0,0,0,0};
    char	*my_name;
    char	*my_name_last;

    char	*name_type;
    XrmValue	name_value;

    XrmDatabase cmnd_line_db = NULL;
    XrmDatabase	lcl_db	     = NULL;
  /*-----------------------------------------------------
  ** This routine merges some resource databases with options specified on
  ** the command line. Resources can then be looked up using XrmGetResource.
  ** This is a bit like the X-toolkit routine XtAppInitialize does for the
  ** extraction of resources by XtGetApplicationResources.
  ** 
  ** I can't help but think that there's a simpler way of doing this but I
  ** can't find it in the X manuals. Basically, the problem arises with wanting
  ** to avoid the calling program being associated with an X-display, i.e. it
  ** is intended for use by "command-line oriented" programs. All the nice,
  ** easy-to-use resource/command-line setup routines in Xlib or Xtlib seem to
  ** assume one is going to use a display -- not surprising, I suppose,
  ** since the concept of Xlib is for writing window based applications!
  **
  ** Anyway, the point is that the following way turn out to be lacking
  ** when it gets tested in anger.
  */
    status = True;		/* Assume success	*/

    our_name[0] = '\0';
	/*
	** Make a list of the databases to be merged, highest priority first.
	*/
#ifdef  __VMS
    p_fil[0] = "decw$user_defaults:SinQ_rc.dat";
    p_fil[1] = "decw$group_defaults:SinQ_rc.dat";
    p_fil[2] = "decw$system_defaults:SinQ_rc.dat";
    p_fil[3] = "decw$user_defaults:decw$xdefaults.dat";
    p_fil[4] = "decw$group_defaults:decw$xdefaults.dat";
    p_fil[5] = "decw$system_defaults:decw$xdefaults.dat";
    p_fil[6] = NULL;
    if (*argc > 0) {	     /* Find out what we are called - parse file nm */
      my_name = strstr (argv[0], "]");	/* Find end of directory, i.e. "]" */
      my_name++;			/* Skip over "]" */
      if (my_name[0] == '[') {		/* Handle possible concealed device */
        my_name = strstr (my_name, "]");
	my_name++;
      }
      i = sizeof (our_name);
      StrEdit (our_name, my_name, "lowercase", &i);	    /* Copy the rest */
      strtok (our_name, ".");		/* Close it off at "." */
    }
#else
    p_fil[0] = StrJoin (full_nm0, sizeof (full_nm0),
			    getenv ("HOME"), "/SinQ_rc");
    p_fil[1] = "/usr/lib/X11/app-defaults/SinQ_rc";
    p_fil[2] = StrJoin (full_nm1, sizeof (full_nm1),
			    getenv ("HOME"), "/.Xdefaults");
    p_fil[3] = "/usr/lib/X11/app-defaults/Xdefaults";
    p_fil[4] = NULL;
    if (*argc > 0) {	      /* Find out what we are called - parse file nm  */
			      /* Find end of directories */
      my_name = argv[0] - 1;
      while (my_name != NULL) {
        my_name_last = my_name;
	my_name_last++;
	my_name = strstr (my_name_last, "/");
      }
      StrJoin (our_name, sizeof (our_name), my_name_last, "");
    }
#endif
    printf ("My name is \"%s\"\n", our_name);
	/*
	**  Initialise and combine all databases
	*/
    XrmInitialize ();
    for (i = 0; i < XtNumber (p_fil); i++) {
      if (p_fil[i] == NULL) break;
      status = XrmCombineFileDatabase (p_fil[i], &lcl_db, False);
      if (status != 0) {
        if (first) {
	  printf ("Resource database created from file %s.\n", p_fil[i]);
	}else {
	  printf ("File %s merged into resource database.\n", p_fil[i]);
	}
	first = False;
      }
    }
	/*
	**  See if there's anything specified on cmnd line, incl "name".
	*/
    XrmParseCommand (&cmnd_line_db,
			OpTable, XtNumber(OpTable), our_name, argc, argv);
    if (cmnd_line_db != NULL) {
	    /*
	    ** There was at least 1 item on cmnd line. Process the line.
	    ** If -name was specified, adopt it.
	    */
      status = XrmGetResource (cmnd_line_db,  /* See if a name was specified  */
			    StrJoin (text, sizeof (text), our_name, ".name"),
			    "ProgramName.Values",
			    &name_type, &name_value);
      if (status) {
	i = sizeof (lkup_name);
	StrEdit (lkup_name, name_value.addr, "lowercase", &i);
	printf ("Option list name is \"%s\"\n", lkup_name);
      }else {
        strcpy (lkup_name, our_name);
      }
	    /*
	    ** Loop over all items in OpTable and merge them into database,
	    ** taking care of any possible name changes.
	    */
      for (i = 0; i < XtNumber (OpTable); i++) {
	if (strcmp (OpTable[i].option, "-name") == 0) continue;
        status = XrmGetResource (cmnd_line_db,
				StrJoin (text, sizeof (text),
				    our_name, OpTable[i].specifier),
				"ProgramName.Values",
				&name_type, &name_value);
	if (status) {
	  StrJoin (text, sizeof (text), lkup_name, OpTable[i].specifier);
	  XrmPutResource (&lcl_db, text, "String", &name_value);
	}
      }
    }
    *name = lkup_name;
    *db = lcl_db;
    if (lcl_db == NULL) printf ("Warning -- no resource database found.\n");

    XrmDestroyDatabase (cmnd_line_db);
/*
**    XrmPutFileDatabase (lcl_db, "asynsrv_test.db");
*/
    return status;
  }
/*
**---------------------------------------------------------------------------
**			GetCheckResources - get and check our resources
*/
  int	GetCheckResources (
/*	=================
*/			    XrmDatabase	*db,
			    char	*appName) {

    int			i, status;
    char		buff[80];
    char		*type;
    XrmValue		value;
    time_t		time_now;
    float		tmp_secs;

    status = XrmGetResource (*db,
			     StrJoin (buff, sizeof (buff),
				      appName, ".AsynSrvHelp"),
			     "ProgramName.Values",
			     &type, &value);
    Do_help = (status) ? True : False;
    if (Do_help) {
      ShowUsage (True);
      exit (EXIT_SUCCESS);
    }

    status = XrmGetResource (*db,
			     StrJoin (buff, sizeof (buff),
				      appName, ".AsynSrvDebug"),
			     "ProgramName.Values",
			     &type, &value);
    Debug = (status) ? True : False;

    status = XrmGetResource (*db,
			     StrJoin (buff, sizeof (buff),
				      appName, ".AsynSrvNoCase"),
			     "ProgramName.Values",
			     &type, &value);
    if (status) {
      DoLower = False; DoUpper = False;
    }else {
      DoLower = False; DoUpper = True;
    }

    status = XrmGetResource (*db,
			     StrJoin (buff, sizeof (buff),
				      appName, ".AsynSrvLower"),
			     "ProgramName.Values",
			     &type, &value);
    if (status) DoLower = True;
    if (DoLower) DoUpper = False;

    status = XrmGetResource (*db,
			     StrJoin (buff, sizeof (buff),
				      appName, ".AsynSrvUpper"),
			     "ProgramName.Values",
			     &type, &value);
    if (status) DoUpper = True;
    if (DoUpper) DoLower = False;

    status = XrmGetResource (*db,
			     StrJoin (buff, sizeof (buff),
				      appName, ".AsynSrvHost"),
			     "ProgramName.Values",
			     &type, &value);
    if (!status) {
      printf ("No server specified via the -host option. "
			"No default allowed!\n");
      ShowUsage (False);
      return False;
    }else {
      StrJoin (AsynSrv_info.host, sizeof (AsynSrv_info.host), value.addr, "");
      printf ("Using Internet host \"%s\".\n", AsynSrv_info.host);
    }

    status = XrmGetResource (*db,
			     StrJoin (buff, sizeof (buff),
				      appName, ".AsynSrvPort"),
			     "ProgramName.Values",
			     &type, &value);
    if (!status || (sscanf (value.addr, "%d", &AsynSrv_info.port) != 1)) {
      AsynSrv_info.port = 4000;
      printf ("Using the default TCP/IP port number of %d.\n",
			    AsynSrv_info.port);
    }else {
      printf ("TCP/IP  port  number = %d\n", AsynSrv_info.port);
    }

    status = XrmGetResource (*db,
			     StrJoin (buff, sizeof (buff),
				      appName, ".AsynSrvChan"),
			     "ProgramName.Values",
			     &type, &value);
    if (!status || (sscanf (value.addr, "%d", &AsynSrv_info.chan) != 1)) {
      printf ("No RS-232-C channel specified via the -chan option. "
			"No default allowed!\n");
      ShowUsage (False);
      return False;
    }else {
      printf ("RS-232-C channel number = %d\n", AsynSrv_info.chan);
    }

    status = XrmGetResource (*db,
			     StrJoin (buff, sizeof (buff),
				      appName, ".AsynSrvTmo"),
			     "ProgramName.Values",
			     &type, &value);
    if (!status || (sscanf (value.addr, "%f", &Tmo) != 1)) {
      Tmo = 2.0;
    }else {
      printf ("Response time-out = %d msec.\n", (int) ((Tmo + 0.0001) * 1000));
    }

    status = XrmGetResource (*db,
			     StrJoin (buff, sizeof (buff),
				      appName, ".AsynSrvTmoConn"),
			     "ProgramName.Values",
			     &type, &value);
    if (!status || (sscanf (value.addr, "%f", &TmoC) != 1)) {
      TmoC = 5.0;
    }else {
      printf ("Connection time-out = %d secs.\n", (int) (TmoC + 0.0001));
    }

    status = XrmGetResource (*db,
			     StrJoin (buff, sizeof (buff),
				      appName, ".AsynSrvTermOut"),
			     "ProgramName.Values",
			     &type, &value);
    if (!status) {
      printf ("Output terminator is \"\\r\"\n");
      strcpy (TermOut, "\r");
    }else {
      printf ("Output terminator is \"%s\"\n", value.addr);
      i = sizeof (TermOut);
      if (StrEdit (TermOut, value.addr, "trim", &i) == NULL) {
	printf ("Bad output terminator!\n");
	ShowUsage (False);
	return False;
      }
    }

    status = XrmGetResource (*db,
			     StrJoin (buff, sizeof (buff),
				      appName, ".AsynSrvTermIn"),
			     "ProgramName.Values",
			     &type, &value);
    if (!status) {
      printf ("Input  terminator is \"\\r\"\n");
      memcpy (TermIn, "1\r\0\0", 4);
    }else {
      printf ("Input  terminator is \"%s\"\n", value.addr);
      i = sizeof (TermIn) - 1;
      if (StrEdit (&TermIn[1], value.addr, "trim", &i) == NULL) {
	printf ("Bad input terminator!\n");
	ShowUsage (False);
	return False;
      }
      switch (strlen (&TermIn[1])) {
       case 0: strcpy (TermIn, "0\0\0\0"); break;
       case 1: TermIn[0] = '1'; TermIn[2] = TermIn[3] = '\0'; break;
       case 2: TermIn[0] = '2'; TermIn[3] = '\0'; break;
       case 3: TermIn[0] = '3'; break;
       default:
	printf ("Input terminator string is too long!\n");
	return False;
      }
    }
    return True;
  }
/*
**--------------------------------------------------------------------------
**		CtrlC_Handler:  Signal handler to detect <Ctrl-C> on keyboard.
*/
  void	CtrlC_Handler (int sigint) {
/*      =============
*/
    Ctrl_C_has_happened = True;
  }
/*
**==========================================================================
**			Main line program
**			------------------
*/
  int	main (int argc, char **argv) {
/*      ============================
*/
    char	    buff[80], text0[80], text1[80];
    int		    buff_len;
    int		    status, errcode, errno, vaxc_errno, i;
    char	    *errName;
    time_t	    time_now;
    int		    sec_tmoC, msec_tmo;

    XrmDatabase		my_db;
    char		*appName;
/*-----------------------------------------------------------------------*/
    time_now = time (NULL);
    printf ("RS-232-C Device Test Program, Ident %s.\n", ident);
    printf ("Started at %s", asctime (localtime (&time_now)));
	/*-------------------------------------------------------------
	**	Setup the resource database and look up the resources.
	*/
    SetupXrmDatabase (&my_db, &appName, &argc, argv);
    if (argc > 1) {
      if (argc > 2) {
	printf ("\nThe following arguments were not used:\n\n     ");
	for (i = 1; i < argc; i++) {
	  printf ("\"%s\" ", argv[i]);
	}
      }else {
        printf ("\nArgument \"%s\" was not used.", argv[1]);
      }
      printf ("\n");
      ShowUsage (False);
      return False;
    }
    status = GetCheckResources (&my_db, appName);
    if (!status) return False;
		    /*
		    ** Declare a signal handler to catch <Ctrl-C> so that we
		    ** can exit cleanly.
		    */
    Ctrl_C_has_happened = False;
    signal (SIGINT, CtrlC_Handler);

    sec_tmoC = (int) (TmoC + 0.0001);
    msec_tmo = (int) ((Tmo + 0.0001) * 1000);
    status = AsynSrv_ConfigDflt (
		"tmoC",    sec_tmoC,  /* Specify the connection time-out */
		"msecTmo", msec_tmo,  /* Specify the response time-out */
		"eot",     TermIn,    /* Specify the terminators */
		NULL);
    if (!status) {
      printf ("Error setting default configuration of server connection.\n");
      PrintErrInfo ("AsynSrv_ConfigDflt");
      return False;
    }

    status = AsynSrv_Open (&AsynSrv_info);
    if (!status) {
      printf ("Error opening connection to server.\n");
      PrintErrInfo ("AsynSrv_Open");
      return False;
    }else {

      status = DoInteract ();
      if (!status) {
	PrintErrInfo ("DoInteract");
	AsynSrv_Close (&AsynSrv_info, 0);
	return False;
      }

      status = AsynSrv_Close (&AsynSrv_info, 0);
    }
    return True;
  }
/*------------------------------------------------- End of asynsrv_test.c */
