/*******************************************************************/
/*								   */
/* Module Name:	       DEVINFO.C				   */
/*								   */
/* Description:	       Provide access to system device		   */
/*		       device configuration information from REXX  */
/*		       programs.  The information is obtained from */
/*		       DosDevConfig.				   */
/*								   */
/* Function:	       Call DosDevConfig and store information	   */
/*		       in the REXX program through the REXX	   */
/*		       Variable Pool Interface (RexxVariablePool). */
/*								   */
/* Entry point:	       DevInfo					   */
/*								   */
/* Notes:							   */
/*								   */
/*   The entry point obeys the calling conventions for REXX	   */
/*   subcommand handlers.					   */
/*								   */
/*******************************************************************/

/*******************************************************************/
/*								   */
/* Include files.  We use the following:			   */
/*								   */
/*    REXXSAA.H		REXX specific type definitions and	   */
/*			function prototypes.			   */
/*								   */
/*    OS2.H		OS/2 specific type definitions and	   */
/*			function prototypes.			   */
/*								   */
/*    stdio.h		Standard C library I/O function prototypes.*/
/*								   */
/*    stdlib.h		Standard C library function prototypes.	   */
/*								   */
/*    string.h		Standard C library string function	   */
/*			prototypes.				   */
/*								   */
/*******************************************************************/


#define	    INCL_DOSDEVICES
#include    <os2.h>
#include    <stdio.h>
#include    <stdlib.h>
#include    <string.h>
#define	    INCL_RXSHV
#define	    INCL_RXSUBCOM
#include    <rexxsaa.h>



/*******************************************************************/
/*								   */
/* Function prototypes follow.					   */
/*								   */
/*******************************************************************/
RexxSubcomHandler DevInfo;

static APIRET QueryAndSet(
   PRXSTRING,
   PUCHAR,
   ULONG,
   PBOOL);

/*******************************************************************/
/*								   */
/* Devinfo							   */
/*								   */
/* This is the main function and entry point.			   */
/* This is a REXX subcommand handler, sometimes called an	   */
/* environment.							   */
/*								   */
/* A subroutine is called to check the input command against each  */
/* of the allowed commands, and handle the command if it is OK.	   */
/* After all the commands are done, this routine returns to REXX,  */
/* passing back the new value for the REXX special variable RC.	   */
/* This routine also sets the REXX error/failure flag.		   */
/*								   */
/* The possible exit values are as follows			   */
/*   REXX RC		Error flag	    Reason		   */
/*   ------------------------------------------------------------- */
/*   0			RXSUBCOM_OK	    success		   */
/*   non-zero number	RXSUBCOM_FAILURE    non-zero return from   */
/*					    DosDevConfig or	   */
/*					    RexxVariablePool	   */
/*   COMMAND TOO LONG	RXSUBCOM_ERROR	    command more than nine */
/*					    characters long	   */
/*   UNKNOWN COMMAND	RXSUBCOM_ERROR	    command not one of the */
/*					    following values	   */
/*					    (upper and lower case  */
/*					    are both OK):	   */
/*					      PARALLEL		   */
/*					      RS232		   */
/*					      DISKETTE		   */
/*					      MATH		   */
/*					      SUBMODEL		   */
/*					      MODEL		   */
/*					      DISPLAY		   */
/*					      ALL		   */
/*								   */
/*******************************************************************/

ULONG DevInfo(
   PRXSTRING cmd,		       /* command string (input)  */
   PUSHORT err_flag,		       /* ERROR/FAILURE	 (output) */
   PRXSTRING rv)		       /* string retcode (output) */
{
   APIRET rc,			       /* rc from function we call*/
	  maxrc,		       /* max value received in rc*/
	  finalrc;		       /* our 'return' value	  */
   BOOL FoundMatch;		       /* did we recognize command*/

   if (cmd->strlength > 9) {
      *err_flag = RXSUBCOM_ERROR;      /* this is REXX ERROR cond.*/
      strcpy(rv->strptr, "COMMAND TOO LONG");
      rv->strlength = strlen(rv->strptr);
      finalrc = 0;		       /* let string be the RC	  */

   } else {
      /* Now check for all possible commands, and do the	  */
      /* requested operation.					  */
      maxrc = 0;
      FoundMatch = 0;

      rc = QueryAndSet(cmd, "PARALLEL", DEVINFO_PRINTER,
	 &FoundMatch);
      if(rc > maxrc) maxrc = rc;

      rc = QueryAndSet(cmd, "RS232", DEVINFO_RS232,
	 &FoundMatch);
      if(rc > maxrc) maxrc = rc;

      rc = QueryAndSet(cmd, "DISKETTE", DEVINFO_FLOPPY,
	 &FoundMatch);
      if(rc > maxrc) maxrc = rc;

      rc = QueryAndSet(cmd, "MATH", DEVINFO_COPROCESSOR,
	 &FoundMatch);
      if(rc > maxrc) maxrc = rc;

      rc = QueryAndSet(cmd, "SUBMODEL", DEVINFO_SUBMODEL,
	 &FoundMatch);
      if(rc > maxrc) maxrc = rc;

      rc = QueryAndSet(cmd, "MODEL", DEVINFO_MODEL,
	 &FoundMatch);
      if(rc > maxrc) maxrc = rc;

      rc = QueryAndSet(cmd, "DISPLAY", DEVINFO_ADAPTER,
	 &FoundMatch);
      if(rc > maxrc) maxrc = rc;

      /* We've checked all the valid input commands and have done */
      /* the processing.  Now we set up our return values and exit*/
      if (!FoundMatch) {
	 *err_flag = RXSUBCOM_ERROR;   /* Raise ERROR in REXX pgm.*/
	 strcpy(rv->strptr, "UNKNOWN COMMAND");
	 rv->strlength = strlen(rv->strptr);
	 finalrc = 0;		       /* let the string be the RC*/
      } else {
	 if (maxrc != 0) {
	    *err_flag = RXSUBCOM_FAILURE;/* Raise FAILURE in REXX */
	    finalrc = maxrc;	       /* use integer as REXX RC  */
	 } else {
	    /* finally, the successful case is handled.		  */
	    /* We return with the RXSTRING set to all zeros, and  */
	    /* the return value set to 0.  This makes the REXX	  */
	    /* RC value "0".  We could also make the return value */
	    /* RXSTRING into the string "0", and again return 0.  */
	    /* That would also set the REXX RC value to "0".	  */
	    *err_flag = RXSUBCOM_OK;
	    finalrc = 0;
	    MAKERXSTRING(*rv, (PUCHAR) 0, 0);
	 } /* end successful case, return code is zero		  */

      } /* end Found a match					  */

   } /* endif cmd->strlength .....				  */

   return finalrc;
}

/*******************************************************************/
/*								   */
/* QueryAndSet							   */
/*								   */
/* This routine will check the data passed to it, and make at most */
/* one call to DosDevConfig.  It that call is OK, it calls	   */
/* RexxVariablePool to put the returned data into a REXX variable. */
/*								   */
/*******************************************************************/

static APIRET QueryAndSet(
   PRXSTRING cmd,		    /* User's command              */
   PUCHAR name,			    /* Command name to compare with*/
   ULONG DeviceType,		    /* code for DosDevConfig	   */
   PBOOL FoundMatch)		    /* we indicate if name matches */
{
   SHVBLOCK block;		    /* block to pass to REXX	   */
   BYTE DeviceInfoByte;		    /* area to hold BYTE size info */
   LONG DeviceInfoDword;	    /* area to hold DWORD size info*/
   UCHAR ValueBuffer [12];	    /* buffer to hold convered info*/
   PVOID DeviceInfoPointer;	    /* pointer to output area	   */
   APIRET rc;			    /* return code from calls	   */

/* First we compare the user's command with the command name       */
/* we are trying for, and ALL.	If either matches we go on and	   */
/* call DosDevConfig.						   */
   if (!stricmp(cmd->strptr, name) || !stricmp(cmd->strptr, "ALL")) {
      *FoundMatch = 1;		       /* record that we got match */
      if (DeviceType <= 6) {
	 DeviceInfoPointer = (PVOID) &DeviceInfoByte;
      } else {
	 DeviceInfoPointer = (PVOID) &DeviceInfoDword;
      } /* endif */

      rc = DosDevConfig(DeviceInfoPointer, DeviceType);
      if (!rc) {
	 /* Now turn the returned value into a string in decimal.  */
	 if (DeviceType <= 6) {
	    sprintf(ValueBuffer, "%d", (int) DeviceInfoByte);
	 } else {
	    sprintf(ValueBuffer, "%d", (int) DeviceInfoDword);
	 } /* endif */

	 /* Build the Shared Variable Block that defines our	   */
	 /* request.  The shvnext pointer is null because we only  */
	 /* are doing one request.				   */
	 /* The shvname RXSTRING is the name passed to this routine*/
	 /* The shvvalue RXSTRING is constructed from the string   */
	 /* we just created above.				   */
	 /* The shvnamelen and shvvaluelen duplicate the lengths   */
	 /* from the RXSTRINGS for simple variable-setting	   */
	 /* operations such as we are doing here.		   */
	 /* The shvcode is set to RXSHV_SET, which means to set	   */
	 /* the variable, using its name as-is.	 This means the	   */
	 /* name must be a valid REXX symbol, in upper case.	   */
	 /* The shvret byte is not set--it is an output value.	   */

	 block.shvnext = (PSHVBLOCK) NULL;
	 block.shvname.strptr = name;
	 block.shvname.strlength = strlen(name);
	 MAKERXSTRING(block.shvvalue, ValueBuffer,
		      strlen(ValueBuffer));
	 block.shvnamelen = block.shvname.strlength;
	 block.shvvaluelen = block.shvvalue.strlength;
	 block.shvcode = RXSHV_SET;

	 /* Call the REXX variable pool.  We use an AND operation  */
	 /* to turn off the low-order bit in the return code,	   */
	 /* because that bit indicates "new variable created", and */
	 /* we do not care about that.	Other return values	   */
	 /* indicate an error.					   */
	 rc = RexxVariablePool(&block) & 0xFFFFFFFE;

      } /* endif rc from DosDevConfig was zero			   */
   }  /* End if we got a match */
   else
      {
	 rc = 0;
      }	 /* End we did not get a match */

   return rc; /* rc from DosDeviceConfig or RexxVariablePool, or 0 */
}

