/*static char *SCCSID = "@(#)cmputmsg.c	6.3 91/07/27";                                 */
/****************************************************************************/
/*									    */
/*			 IBM/Microsoft Confidential			    */
/*									    */
/*		   Copyright (c) IBM Corporation  1987, 1990		    */
/*		   Copyright (c) Microsoft Corp.  1987, 1990		    */
/*			     All Rights Reserved			    */
/*									    */
/****************************************************************************/
/******** START OF SPECIFICATIONS ****** IBM CONFIDENTIAL ************/
/*								     */
/* SOURCE FILE NAME: CMPUTMSG					     */
/*								     */
/* DESCRIPTIVE NAME: PRINT MESSAGE AND GET RESPONSE		     */
/*								     */
/* FUNCTION:							     */
/*								     */
/*     Print a message and optionally get a response the way	     */
/*     specified by response type parameter.			     */
/*     There are four response types. In response type 0, a message  */
/*     will be printed without waiting for any response.	     */
/*     In response type 1 to 5, the control does not return	     */
/*     to the caller until a proper response is received from the    */
/*     standard input device(stdin) after printing a message.	     */
/*								     */
/*	  +----------+-----------------+------------------------+    */
/*	  | resptype | operator action | content of "respdata"  |    */
/*	  |	     |		       | on return		|    */
/*	  +----------+-----------------+------------------------+    */
/*	  |    0     | none	       | none			|    */
/*	  |	     |		       |			|    */
/*	  |    1     | enter	       | none			|    */
/*	  |	     |		       |			|    */
/*	  |    2     | yes	       | 0			|    */
/*	  |	     | no	       | 1			|    */
/*	  |	     |		       |			|    */
/*	  |    3     | input character | null terminated input	|    */
/*	  |	     | string	       | character string	|    */
/*	  |	     |		       |			|    */
/*	  |    4     | any key	       | none			|    */
/*	  |	     |		       |			|    */
/*	  |    5     | abort	       | 2			|    */
/*	  |	     | retry	       | 3			|    */
/*	  |	     | ignore	       | 4			|    */
/*	  +----------+-----------------+------------------------+    */
/*								     */
/* NOTES:							     */
/*								     */
/*     1. If the 1st entered character is an invalid response	     */
/*	  character at response type 2, redisplay a prompt message   */
/*	  and enable another keyboard input.			     */
/*								     */
/*     2. devicetype:						     */
/*								     */
/*	  A file handle can be specified instead of devicetype,      */
/*	  if a filehandle enabling switch flag is set.		     */
/*	  ( char cm_flhandle_enable_sw : defined in comsub.h)	     */
/*								     */
/* ENTRY POINTS:						     */
/*								     */
/*	       COMPUMSG  - PRINT MESSAGE AND GET RESPONSE	     */
/*								     */
/* EXTERNAL REFERENCE:						     */
/*								     */
/*		  DOSALLOCSEG	 - allocate segment		     */
/*		  DOSREALLOCSEG  - reallocate segment		     */
/*		  DOSGETMESSAGE  - get system message		     */
/*		  DOSPUTMESSAGE  - put message text		     */
/*		  DOSREAD	 - read file			     */
/*		  DOSQHANDLETYPE - query file/device handle type     */
/*		  DOSGETMACHINEMODE - get processor mode	     */
/*		  KBDFLUSHBUFFER - flush keystroke buffer	     */
/*								     */
/*		  putchar	 - write character to stdout	     */
/*		  printf	 - write string to stdout	     */
/*		  com_strupr	 - convert string to upper case      */
/*		  kbhit 	 - check keyboard queque	     */
/*		  strncpy	 - string copy			     */
/* RELEASE:							     */
/*								     */
/*   VERSION	    DATE	      REASON			     */
/*								     */
/*     1.00	   03/10/1986	 initial version		     */
/*     1.01	   03/11/1986	 replace "printf" with "putc"        */
/*				 response type 4: any key	     */
/*				 (Lee's request)                     */
/*     1.02	   03/18/1986	 change level of "ivtable"           */
/*				  *ivtalbe -> **ivtable 	     */
/*     1.03	   03/24/1986  - use API function to read kbd input  */
/*			       - change "tolower" to "toupper"       */
/*			       - check yes,no response character     */
/*				 were loaded.			     */
/*			       - re-display a prompt message and     */
/*				 wait for a valid input at response  */
/*				 type 2.			     */
/*			       - at response 2 and 3, display	     */
/*				 a prompt message and retry to	     */
/*				 get a input when more than 10	     */
/*				 characters are entered.	     */
/*     1.04	   03/25/1986	 change: get yes,no response char    */
/*								     */
/*     2.00	   03/26/1986  - the first version for driver 1      */
/*			       - comment out unavailable API func.   */
/*				    KBDCHARIN, KDBSETECHOMODE	     */
/*				    KBDGETECHOMODE, KBDFUSHBUFFER    */
/*     2.01	   03/28/1986	 change system message filename      */
/*				  "OS0001.MSG" => "OSO001.MSG"       */
/*								     */
/*     2.02	   03/31/1986  - read response data from stdin at    */
/*				 response type 1 - 3.		     */
/*			       - delete KBDSETECHO, KBDGETECHO,      */
/*				 KBDSTRINGIN.			     */
/*			       - use "fgets" instead of KBDSTRINGIN. */
/*     2.03	   04/08/1986  - incude message id include file      */
/*			       - cast to far pointer array (ivtable) */
/*     2.04	   04/10/1986  - enable KBDFUSHBUFFER calling	     */
/*     2.05	   04/11/1986  - change (char far *)ivtable to	     */
/*					(char far **)ivtable	     */
/*			       - add one parm to KBDFLUSHBUFFER      */
/*     3.00	   04/15/1986  - the first intigration version	     */
/*     3.01	   05/01/1986  - add two more error include files.   */
/*				 <utlerror.h> and <error2.h>	     */
/*     3.02	   05/02/1986  - increase msg_buf size to 1k	     */
/*			       - fix far pointer conversion bug      */
/*				 for **ivtable			     */
/*     3.03	   05/03/1986  - add  char far **ivtable_far[]	     */
/*     3.04	   05/07/1986  - use "putchar" instead of "putc"     */
/*			       - delete NewLine code at resptype 3   */
/*			       - delete "KBDCHARIN", instead         */
/*				 read char from stdin by "getchar"   */
/*				 in raw-mode.			     */
/*     3.05	   05/17/1986  - add abnormal result handling for    */
/*				 DOSGETMESSAGE			     */
/*			       - use DBCS support common routines    */
/*				 ( call internal emulating func.)    */
/*     3.06	   05/19/1986  - define temporary response data      */
/*				 buffer ("workbuf") 241 bytes        */
/*     3.07	   05/23/1986  - call DBCS commom routine.	     */
/*     3.08	   06/16/1986  - enable standard error handle	     */
/*     3.09	   06/17/1986  - enable SCCSID tag		     */
/*     4.00	   06/19/1986  - specify msg_buf to get message      */
/*				 instead of workbuf.		     */
/*			       - delete temporary logic for	     */
/*				 resptype 4.			     */
/*     4.01	   06/20/1986  - fix bug in devicetype parm.	     */
/*     4.02	   06/24/1986  - delete temporary logic for default  */
/*				 response characters setting.	     */
/*     4.03	   06/26/1986  - fix bug in "ignore","retry" char    */
/*     4.04	   06/27/1986  - enable filehandle instead of	     */
/*				 devicetype.			     */
/*     4.05	   06/30/1986  - replace "doscall.h" with            */
/*				 "doscalls.h" and "subcalls.h".      */
/*     4.06	   07/14/1986  - delete abort,retry,ignore logic     */
/*     4.07	   07/24/1986  - disable stdout buffering	     */
/*     4.08	   07/31/1986  - add resptype 5 (support Abort/Retry */
/*				 /Ignore)			     */
/*     4.09	   08/14/1986  - CR ("\n" ) direction to either      */
/*				 stdout or stderr		     */
/*     5.00	   08/27/1986  - return memory allocation error if   */
/*				 occurrs			     */
/*     5.01	   08/28/1986  - directly refer to Keyboard in	     */
/*				 response type 4.		     */
/*     5.02	   10/20/1986  - replace fget with DOSREAD	     */
/*				 prevent bug in fget		     */
/*     5.03	   12/09/1986  - add debugging macro		     */
/*     5.04	   12/10/1986  - replace malloc, realloc C runtime   */
/*				 furnction with DOSALLOCSGE,	     */
/*				 DOSREALLOCSEG respectively	     */
/*     5.05	   01/13/1987  - Fix DOSREAD device handle,	     */
/*				 handle should be 0 (stdin).	     */
/*     5.06	   01/22/1987  - input redirection problem	     */
/*     5.07	   01/24/1987  - do not flush kbd buffer when input  */
/*				 redirection being done.	     */
/*     5.08	   01/30/1987  - fix bug in kbd buffer flushing      */
/*     5.09	   02/06/1987  - enable DBCS handling in CR(0x0d),   */
/*				 NL(0x0a) check.		     */
/*			       - Fix EOF bug.			     */
/*			       - check machine mode.		     */
/*     5.10	   02/06/1987  - eliminate compile warnings	     */
/*				 for option -W2 -DLINT_ARGS	     */
/*     5.11	   02/16/1987  - change global variable to static.   */
/*     5.12	   03/04/1987  - return ERROR_CM_EOF_REDIRECT when   */
/*				 EOF detected during reading input   */
/*				 file.				     */
/*     5.13	   03/19/1987  - DCR 74: DOSQHANDLETYPE returns      */
/*				 handle type 02 for pipe handle.     */
/*     5.14	   07/15/1987  - JMH - 1) changes from I2 review     */
/*				       2) code cleanup		     */
/*				       3) DOSQHANDTYPE upper byte    */
/*					  clearing		     */
/*				       4) comment clean up	     */
/*     5.15	   11/18/1987  - APJ - Remove extern int _flsbuf     */
/*				 for 5.0 compiler conversion	     */
/*								     */
/*     6.00   ##   06/01/1988  - Cora Yang			     */
/*				 When the INPUT is not redirected    */
/*				 but OUTPUT is redirected, needs to  */
/*				 read in from KEYBOARD. And either   */
/*				 INPUT or OUTPUT is redirected	     */
/*				 save characters in workbuf.	     */
/*     6.01   ##   06/27/1988  - Cora Yang  ptm2973		     */
/*				 When running out of memory, use     */
/*				 use static memory to put out	     */
/*				 message			     */
/*								     */
/*     6.02   ##   07/12/1988  - Cora Yang  ptm3135		     */
/*				 If input is NOT redirected or piped */
/*				 (means STDIN_HDL equals DEVICE      */
/*				  type).			     */
/*								     */
/*     6.012 ##NR1 12/04/1990  - ADDED #IFDEF for debugging	     */
/*								     */
/*     6.012 ##NR2 12/04/1990 - ptm b718509			     */
/*				compiler no longer needs special     */
/*				casting of pointers to _far16 pointer*/
/*				can now just pass the address as     */
/*				usual.	DOSGETMESSAGE casting was    */
/*				causing traps due to (char _far16 *) */
/*				being associated with a variable     */
/*				that was already defined as a pointer*/
/*								     */
/* B016 B725117 07/27/91 fgw Dasd reduction of Common Subroutines    */
/*			     [convert PRINTF and PUTC to DOSWRITEs]  */
/*********************************************************************/

/* #include <doscalls.h>	  /* DOS function external	  */
/* #include <subcalls.h>	  /* other API calls		  */
#include <basedef.h>		  /* rename of far to FAR	  */
#include "tmpdos16.h"             /* 16 bit dos calls             */
#include "tmpdos32.h"             /* 32 bit dos calls             */
#include <bsememf.h>
#include <comsub.h>	       /* common subroutine exteranl   */

#include <error.h>	       /* error code		       */
#include <error2.h>
#include <utlerror.h>

#include <utilmids.h>		/* message id			*/
#include <basemid.h>

#include <stdio.h>	       /* C run time function	       */
/* #include <stdlib.h>						  */
#include <string.h>
#include <conio.h>
#include <dos.h>

#include "cmdebug.h"           /* macro for debugging          */

extern unsigned long DOSWRITE(unsigned long, void *,		/*;BN016;*/
			      unsigned long, unsigned long *);	/*;BN016;*/


/*************************************/
/*				     */
/*  internal routine		     */
/*				     */
/*************************************/

unsigned readinput(int);		  /* read input data from stdin.  */
unsigned getmessage(char **, unsigned,	  /* write specified message to   */
		    unsigned, char *);	  /*  stdout or stderr. 	  */

/*************************************/
/*				     */
/*   constant definition	     */
/*				     */
/*************************************/

#define OK   0
#define FALSE		  0

					  /* response types		  */
#define NO_RESPONSE	  0		  /*   no response		  */
#define CR_RESPONSE	  1		  /*   carriage 		  */
#define YES_NO_RESPONSE   2		  /*   yes/no			  */
#define STRING_RESPONSE   3		  /*   string input		  */
#define ANY_KEY_RESPONSE  4		  /*   any key			  */
#define ARI_RESPONSE	  5		  /*   abort/retry/ignore	  */

#define YES_ANS    0			  /*	Yes			  */
#define NO_ANS	   1			  /*	No			  */
#define ABORT_ANS  2			  /*	Abort			  */
#define RETRY_ANS  3			  /*	Retry			  */
#define IGNORE_ANS 4			  /*	Ignore			  */
					  /* flag control		  */
#define ON     1			  /*	on			  */
#define OFF    0			  /*	off			  */
					  /* standard device handle	  */
#define STDIN_HDL  0			  /*	stdin			  */
#define STDOUT_HDL 1			  /*	stdout			  */
#define STDERR_HDL 2			  /*	stderr			  */

#define INIT_MSG_BUF_SIZE  200		  /* initial msg buffer size	  */
#define MSGFILENAME "OSO001.MSG"          /* system message filename      */
#define MAX_IVCOUNT	9		  /* maximun no of ivcount ( 9 )  */

#define KBDHANDLE	0		  /* keyboard handle = 0	  */
					  /* reponse char define related  */
#define RESPCHAR_NUM	5		  /*   number of resp char	  */
#define YES_RS		0		  /*   pointer - yes		  */
#define NO_RS		1		  /*		 no		  */
#define ABORT_RS	2		  /*		 abort		  */
#define RETRY_RS	3		  /*		 retry		  */
#define IGNORE_RS	4		  /*		 ignore 	  */

#define NOT_SHARED	0		  /* not shared option		  */
#define WORKBUF_SIZE   241		  /* temporary work buffer to	  */
					  /* read response data 	  */
/*************************************/
/*				     */
/* external variable		     */
/*				     */
/*************************************/

char cm_flhandle_enable_sw = OFF;	  /* filehandle enabling switch   */

/*************************************/
/*				     */
/*  define static variable	     */
/*				     */
/*************************************/

/***PEN*** to call 16 bit DOSGETMESSAGE, use local array to copy converted */
/***	   string pointers inside getmessage				   */
/***static***/
/*char FAR *ivtable_far[MAX_IVCOUNT];	  /* ivtable copy (converted far) */

/***PEN*** this will use msg_buft as static msg buffer to allow the */
/*	   conversion to 16 bit segmented pointers		    */
#define   BUFT_SIZE    512
static
char	  msg_buft[BUFT_SIZE];		   /* message buffer pointer	   */

static
char FAR *msg_buf;			   /* message buffer pointer	   */
static
unsigned short msg_buf_size = INIT_MSG_BUF_SIZE; /* initial msg buffer size */
static char static_buf[INIT_MSG_BUF_SIZE]; /* ## see ptm 2973		   */
static
unsigned short msglength;		   /* message length returned from */
					   /*  DOSGETMESSAGE		   */
static
unsigned short msg_buf_sel;		   /* message buffer selector	   */
static
char respchar[RESPCHAR_NUM+1];		   /* response characters	   */
					   /*  [0] - yes		   */
					   /*  [1] - no 		   */
					   /*  [2] - abort		   */
					   /*  [3] - retry		   */
					   /*  [4] - ignore		   */


#define REAL_MODE      0		   /* machine mode		   */
#define PROTECT_MODE   1

/*************************************/
/*				     */
/*  control flag		     */
/*				     */
/*************************************/

static
char init_req = ON;			   /* ON:allocate msg buffer	   */

/*************************************/
/*				     */
/*  DOSREAD related		     */
/*				     */
/*************************************/

static
  char	workbuf[WORKBUF_SIZE];		   /* temporary work buffer	   */
static
  unsigned short bytes_read;		   /* number of bytes from DOSREAD */

/*************************************/
/*				     */
/*  for DOSWRITE		     */
/*				     */
/*************************************/
  unsigned long byteswritten;		  /*;BN016; byteswritten	   */

/*
 *  DOSGETMACHINEMODE related
 */
static
  unsigned char machine_mode;		   /* processor mode.		  */
					   /*	0:real, 1:proctect	  */
/*************************************/
/*				     */
/*  STRUCTURES			     */
/*				     */
/*************************************/

struct	KeyData  KeyBuf;

/******************** START OF SPECIFICATION *************************/
/*								     */
/* SUBROUTINE NAME:  COMPUTMSG					     */
/*								     */
/* DESCRIPTIVE NAME:  PRINT A MESSAGE AND GET RESPONSE		     */
/*								     */
/* FUNCTION:							     */
/*								     */
/*     Print a message and optionally get a response the way	     */
/*     specified by response type parameter.			     */
/*     There are four response types. In response type 0, a message  */
/*     will be printed without waiting for any response.	     */
/*     In response type 1 to 4, the control does not return	     */
/*     to the caller until a proper response is received after	     */
/*     printing a message.					     */
/*								     */
/* NOTES:							     */
/*								     */
/* ENTRY POINT:  computmsg					     */
/*   LINKAGE  :  call near					     */
/*								     */
/* INPUT:   char						     */
/*	      **ivtable   - table of variables to insett	     */
/*			    argument.				     */
/*	    unsigned						     */
/*		 ivcount  - number of variables 		     */
/*								     */
/*	    unsigned						     */
/*		 msgid	  - id of the message			     */
/*								     */
/*	    char						     */
/*	      *filename   - message filename			     */
/*								     */
/*	    unsigned						     */
/*	      devicetype  - output device type			     */
/*	    char						     */
/*	      *respdata   - response data area			     */
/*								     */
/*	    unsigned						     */
/*	    respdata_size - size of response data area		     */
/*								     */
/* EXIT-NORMAL: 						     */
/*   RETURN CODE SYMBOL:  OK					     */
/*								     */
/* EXIT-ERROR:							     */
/*   RETURN CODE SYMBOL:					     */
/*								     */
/*	  ERROR_INVALID_PARAMETER : invalid response type	     */
/*	  API function error code				     */
/*								     */
/* EFFECTS:							     */
/*								     */
/* INTERNAL REFERENCES: 					     */
/*   ROUTINES:							     */
/*								     */
/*		  getmessage	 - get a message, error handling     */
/*		  readinput	 - get input from standard input     */
/******************* END OF SPECIFICATIONS ***************************/
unsigned
computmsg(ivtable, ivcount, msgid, filename,
	  devicetype, resptype, respdata, respdata_size)
char **ivtable; 			 /* table of varbs to insert	*/
unsigned ivcount;			 /* number of variables 	*/
unsigned msgid; 			 /* id of the message		*/
char *filename; 			 /* message filename strig	*/
unsigned devicetype;			 /* output device type		*/
unsigned resptype;			 /* type of response		*/
char *respdata; 			 /* response data area		*/
unsigned respdata_size; 		 /* response data area size	*/
{
  int rc = OK;				 /* function return code	*/
  unsigned drc = 0;			 /* extra return code varb	*/
  int i, j;				 /* work			*/

/******************************************************************************/
/*   initialization:							      */
/*		  -   allocate memory for buffers. Also read a message in     */
/*		      which response characters are defined, and set	      */
/*		      them in "respchar[]" buffer.                            */
/*		  -   get processor mode, this value is referred later	      */
/*		      in routine readinput.				      */
/*									      */
/*		      This process is executed only once.		      */
/*									      */
/******************************************************************************/

  if (cm_flhandle_enable_sw == OFF) {	 /* if filehandle not specified,*/
     if (devicetype == 0)		 /*  set stdout, stderr device	*/
	devicetype = STDOUT_HDL;
     else
	devicetype = STDERR_HDL;
  }

  if (init_req == ON)	      { 	 /* initilization required?	*/

     /***PEN*** this was using DOSALLOCSEG, now use static buffer msg_buft */
     /***PEN***  DCALL(DOSALLOCSEG); ***/

  #ifdef DEBUG		    /* ##NR1*/
     printf ("initializing computmsg\n");
  #endif

     if ((rc =
	 getmessage(ivtable,		  /*   read response characters  */
		    0,			  /*   defined in a message 0th  */
	  (unsigned)MSG_RESPONSE_DATA,
		    MSGFILENAME)) != OK)   {
	 /* deallocate the message buffer space    */
	 /***PEN*** using static msg_buft ***/
	   #ifdef DEBUG 	   /* ##NR1 */
	      printf ("get message failed on read response char\n");
	      printf ("rc = %d\n");
	   #endif
	return(rc);
     }

     i = j = 0;
     while (i < RESPCHAR_NUM)  {	  /*  set gotten response char	 */
	respchar[i] = msg_buft[j];	   /*  in a buffer.		  */
	i++;
	j += 2;
     }

     DCALL(DOSGETMACHINEMODE);
     #ifdef DEBUG /* ##NR1 */
       printf ("start of dosgetmachine mode call\n");
     #endif
     if ((rc=DOSGETMACHINEMODE( 	  /* get processor mode.	 */
	  (unsigned char _far16 *)
	    &machine_mode)) != OK)   {
	  DRETCD;
	 /* deallocate the message buffer space    */
	 /***PEN*** using static msg_buft ****/
	 #ifdef DEBUG	/* ##NR1 */
	    printf ("getting processor mode failed\n");
	 #endif
	return(rc);
     }
     DRETCD;

     init_req = OFF;			  /*  reset init request	 */
   }

/*************************************/
/*				     */
/* get a message from a message file */
/*				     */
/*************************************/

  #ifdef DEBUG	  /* ##NR1 */
     printf ("prior to get msg from file\n");
  #endif
  if ((rc = getmessage(ivtable, 	   /* get a message from the	  */
		 ivcount,		   /* message file.		  */
		 msgid,
		 filename)) != OK)  {
	#ifdef DEBUG  /* ##NR1 */
	   printf ("get message failed on getting msg from msg. file\n");
	   printf ("rc = %d \n", rc);
	#endif
     return(rc);
  }
/*************************************/
/*				     */
/*   display a gotten message	     */
/*				     */
/*************************************/

  DCALL(DOSPUTMESSAGE);
  #ifdef DEBUG	/* ##NR1 */
     printf ("start of put msg call\n");
  #endif
  if ((rc =
       DOSPUTMESSAGE(			   /* display a message 	  */
	 (unsigned short)devicetype,
	 msglength,
	 (char _far16 *)msg_buft)) != OK)    {
     DRETCD;
     #ifdef DEBUG /* ##NR1 */
       printf ("put msg failed, rc = %d\n",rc);
     #endif
     return(rc);
  }
  DRETCD;

/*************************************/
/*				     */
/*   get a specified response	     */
/*				     */
/*************************************/


  switch (resptype)			   /* 0: no response required	  */
    {
     #ifdef DEBUG /* ##NR1 */
       printf ("In response case statement\n");
       printf ("resptype = %d\n",resptype);
     #endif
     case NO_RESPONSE:
       break;

     case CR_RESPONSE:			   /* 1. wait for enter key	  */
       if ((rc=readinput(resptype)) != OK)
	   return(rc);
       workbuf[bytes_read - 2] = '\0';
       break;
     case YES_NO_RESPONSE:		   /* 2 or 5:			  */
     case ARI_RESPONSE: 		   /*	wait for Y/N or A/R/I	  */
get_respchar:
       if ((rc=readinput(resptype))!= OK)
	   return(rc);
       workbuf[bytes_read - 2] = '\0';

       DCALL(COM_STRUPR);
       com_strupr(workbuf);		   /* convert input to uppercase  */
       DRET;
       if (resptype == YES_NO_RESPONSE) {  /* yes/no required?		  */
	  if (*workbuf == respchar[YES_RS])  {
	     respdata[0] = YES_ANS;	   /*  "yes" -> set 0 at respdata */
	     break;
	  }
	  if (*workbuf == respchar[NO_RS])   {
	     respdata[0] = NO_ANS;	     /*  "no" -> set 1 at respdata  */
	     break;
	  }
       }  else	{			  /* abort/ignore/retyr:	 */
	  if (*workbuf == respchar[ABORT_RS])  {    /*	"abort"    */
	     respdata[0] = ABORT_ANS;	     /*      -> set 2 at respdata   */
	     break;
	  }
	  if (*workbuf == respchar[RETRY_RS])  {   /*  "retry"    */
	     respdata[0] = RETRY_ANS;	      /*      -> set 3 at respdata   */
	     break;
	  }
	  if (*workbuf == respchar[IGNORE_RS])	{   /*	"ignore" */
	     respdata[0] = IGNORE_ANS;	      /*      -> set 4 at respdata   */
	     break;
	  }
       }
       DCALL(DOSPUTMESSAGE);
       if ((rc =			      /* unexpected response	     */
	    DOSPUTMESSAGE(		      /* -> prompt again	     */
	      (unsigned short)devicetype,
	      msglength,
	      (char FAR *)msg_buft)) != OK)    {
	  DRETCD;
	  #ifdef DEBUG	/* ##NR1 */
	     printf ("Dos Put message failed in unexpected response\n");
	     printf("rc = %d\n",rc);
	  #endif
	  return(rc);
       }
       DRETCD;
       goto get_respchar;
     case STRING_RESPONSE:		      /* 3: wait for character string*/
       if ((rc=readinput(resptype)) != OK)
	  return(rc);
       workbuf[bytes_read - 2] = '\0';
       DCALL(STRNCPY);
       strncpy(respdata,		      /*  set read data to user      */
	       workbuf, 		      /*  data area.		     */
	       respdata_size);
       DRET;
       respdata[respdata_size - 1] = '\0';
       break;
     case ANY_KEY_RESPONSE:
       DCALL(KBDFLUSHBUFFER);
       if ((rc = KBDFLUSHBUFFER(KBDHANDLE))   /* flush kbd buffer	     */
				!= OK)	       {
	  DRETCD;
	  return(rc);
       }
       DRETCD;

/*     wait_anykey:    ##NR took out because of W3 warning  */

       DCALL(KBHIT);			      /* Wait for hiting any key     */
       /***PEN*** using kbdcharin because kbhit not in libc386.lib ***/
       rc = KBDCHARIN (
	  (struct KeyData _far16 *) &KeyBuf,
	  (unsigned short)  0,
	  (unsigned short)  0 );
       /***PEN*** taken out, using kbdcharin routine***/
       /***if (kbhit() == OFF)		 {
       /***   DRET;
       /***   goto wait_anykey;
       /***}			***/
       DRET;
       DCALL(PUTC);
       /* if (devicetype != 0)		    * stdout is specified?     ;BD016;*/
       /*     putc('\n', stderr);           *  no-> write CR to stderr ;BD016;*/
       /* else				    *  yes-> write CR to sdout ;BD016;*/
       /*     putc('\n', stdout);                                      ;BD016;*/
       DOSWRITE( (devicetype != 0) ? 2:1,			     /*;BN016;*/
		       "\r\n", 2, &byteswritten);                    /*;BN016;*/

       DRET;
       break;

     default:
       return(ERROR_INVALID_PARAMETER);       /* invalid response type.      */
    }
    #ifdef DEBUG  /* ##NR1 */
       printf ("Leaving computmsg\n");
    #endif
  return(OK);				      /* normal return		     */
}
/******************** START OF SPECIFICATION *************************/
/*								     */
/* SUBROUTINE NAME:  GETMESSAGE 				     */
/*								     */
/* DESCRIPTIVE NAME:  GET A MESSAGE FROM A MESSAGE FILE 	     */
/*								     */
/* FUNCTION:							     */
/*								     */
/*     This routine get a message text into a buffer by calling      */
/*     DOSGETMESSAGE. If DOSGETMESSAGE detectes some error	     */
/*     condition, this routine handles it.			     */
/*								     */
/*     DOGETMESSGAE set a special message text in a buffer with      */
/*     the following error codes.				     */
/*								     */
/*	return code		  action to be taken		     */
/*	of DOSGETMESSAGE					     */
/*								     */
/*     ERROR_MR_MSG_TOO_LONG	  reallocate message buffer	     */
/*								     */
/*     any other return codes	  display a filled message text      */
/*				  and return error code.	     */
/*								     */
/*								     */
/* NOTES:							     */
/*								     */
/*     the error message is always displayed in the monitor.	     */
/*								     */
/* ENTRY POINT:  getmessage					     */
/*   LINKAGE  : 						     */
/*								     */
/* INPUT:   char						     */
/*	      **ivtable   - table of variables to insett	     */
/*			    argument.				     */
/*	    unsigned						     */
/*	      ivcount  - number of variables			     */
/*								     */
/*	    unsigned						     */
/*	      msgid    - id of the message			     */
/*								     */
/*	    char						     */
/*	      *filename   - message filename			     */
/*								     */
/* EXIT-NORMAL: 						     */
/*   RETURN CODE SYMBOL:  OK					     */
/*								     */
/* EXIT-ERROR:							     */
/*   RETURN CODE SYMBOL:					     */
/*								     */
/*	  API function error code				     */
/*								     */
/* EFFECTS:							     */
/*								     */
/* INTERNAL REFERENCES: none					     */
/*   ROUTINES:							     */
/*								     */
/* EXTERNAL REFERENCES: 					     */
/*   ROUTINES:							     */
/*		  DOSGETMESSAGE  - get system message		     */
/*		  DOSPUTMESSAGE  - put message text		     */
/*		  DOSREALLOC	 - reallocate segment		     */
/******************* END OF SPECIFICATIONS ***************************/

unsigned getmessage(ivtable, ivcount, msgid, filename)
  char **ivtable;			     /* table of variables to insert */
  unsigned ivcount;			     /* number of variables	     */
  unsigned msgid;			     /* id of the message	     */
  char *filename;			     /* message filename strig	     */
    {
     unsigned i;
     int rc,rc_s;
     unsigned char _far16 *ptr16;	     /* ##NR2 */
     unsigned char	  *ptr32;	     /* ##NR2 */
     char _far16 * ivtable_16[MAX_IVCOUNT];  /* ##NR2 */

     /***PEN*** added for 16 bit conversion of ivtable */
     /***	arg_array cannot be char _far16 *arg_array[MAX_IVCOUNT] ***/
     /***	because the compiler makes each element 8 bytes long	***/
     /***	when defined that way.					***/
/*   char _far16 *far_insert_str;  WAS ##NR2 */
/*   unsigned long arg_array[MAX_IVCOUNT]; WAS ##NR2 */
/*   char _far16 *arg_array[MAX_IVCOUNT];  /* ##NR2 */
/*   char _far16 * _far16 *far_array_ptr;  ##NR2 */

/*************************************/
/*				     */
/* convert ivtable to far ptr array  */
/*				     */
/*************************************/
     #ifdef DEBUG /* ##NR1 */
       printf ("beginning of getmessage function\n");
     #endif

     i = 0;				     /* convert to _far16 pointer  */
     while (i < ivcount && i < MAX_IVCOUNT)
       {
/*WAS	far_insert_str = ivtable[i];  ##NR2 */
/*WAS	arg_array[i] = (unsigned long)far_insert_str; ##NR2 */
	ptr32 = ivtable[i];	  /* ##NR2 */
	ptr16 = ptr32;		  /* ##NR2 */
	ivtable_16[i] = ptr16;	  /* ##NR2 */
	i++;
       }

/*   far_array_ptr = (char _far16 * _far16 *)&arg_array[0]; WAS ##NR2 */
/*   far_array_ptr = (char _far16 * _far16 *)arg_array;   /* ##NR2 */

/*************************************/
/*				     */
/* get a message from a file	     */
/*  by using DOSGETMESSAGE	     */
/*				     */
/*************************************/

/* ##NR2 mess_buf     = msg_buft; took out because compiler changed */

/*Do_DOSGETMESSAGE:  took out because of W3 warning ##NR */
     DCALL(DOSGETMESSAGE);
     rc_s =				      /* execute DOSGETMESSGE	      */
     rc = DOSGETMESSAGE(		      /* and copy return code to rc_s */
	       (char _far16 * _far16 *)ivtable_16,
	       (unsigned short)ivcount,
 /* WAS ##NR2  (char _far16 *)mess_buf, */
	       (char _far16 *)msg_buft,
	       (unsigned short)BUFT_SIZE,
	       (unsigned short)msgid,
	       (char _far16 *)filename,
	       (unsigned short _far16 *)&msglength);

     #ifdef DEBUG /* ##NR1 */
	printf("DOSGETMESSAGE Passed!!\n");
	printf("RC = %d\n",rc);
     #endif

     DRETCD;
     switch(rc_s)			      /* Check return code:	  */
       {
	case OK:			      /* No Error:		  */
	  if (msglength == msg_buf_size)      /* If at end of buffer.	  */
	     msg_buft[msglength-1] = NULL;     /*  terminate a got message */
	  else
	     msg_buft[msglength] = NULL;       /*  terminate a got message */
	  return(rc_s); 		      /*  with null, return.	  */
	case ERROR_MR_MSG_TOO_LONG:	      /* MSG Buffer is small:	  */
	  /***PEN*** using static msg_buft now***/
	  DRETCD;
	  return(rc);
	default:			     /* * * * * * * * * * * * * * *  */
	  DCALL(DOSPUTMESSAGE);
	  if ((rc =			     /* unreconverble error:	     */
	       DOSPUTMESSAGE(
		 STDERR_HDL,		     /*   display special error      */
		 msglength,		     /*   message and return error   */
/** WAS ##NR2	 (char _far16 *)mess_buf)) != OK) /*   code.			 */
/** ##NR2 */	 (char _far16 *)msg_buft)) != OK) /*   code.			 */
	    {
	     DRETCD;
	     return(rc);
	    }
	  DRETCD;
	  return(rc_s); 		    /* return Error Code from	    */
       }				    /* DOSGETMESSAGE.		    */
    }

/******************** START OF SPECIFICATION *************************/
/*								     */
/* SUBROUTINE NAME:  READINPUT					     */
/*								     */
/* DESCRIPTIVE NAME:  GET INPUT FROM STANDARD INPUT DEVICE	     */
/*								     */
/* FUNCTION:							     */
/*								     */
/*     This routine is called by main routine of this moudle	     */
/*     COMPUTMSG and read input data from the standard input	     */
/*     device by calling DOSREAD with file handle 0.		     */
/*								     */
/*     Early version of COMPUTMSG did not read data corretly when    */
/*     input is redirected to a file. Because data terminating	     */
/*     code hex 0D,0A (carriage return, line feed) were not checked. */
/*     This routine replaces DOSREAD calls which used to be called   */
/*     in COMPUTMSG and it provides the following functions.	     */
/*								     */
/*	  1) when a character set of hex 0D,0A is found, terminate   */
/*	     data reading and return read data to calling routine.   */
/*								     */
/*	  2) check status of standard input redirection, if it is    */
/*	     redirected to a file, write read data to the standard   */
/*	     output device to echo them.			     */
/*								     */
/* NOTES:							     */
/*								     */
/* ENTRY POINT:  readinput					     */
/*   LINKAGE  : 						     */
/*								     */
/* INPUT:   resptype - required response type			     */
/*								     */
/* EXIT-NORMAL: 						     */
/*   RETURN CODE SYMBOL:  OK					     */
/*								     */
/* EXIT-ERROR:							     */
/*   RETURN CODE SYMBOL:					     */
/*								     */
/*	  API function error code				     */
/*								     */
/* EFFECTS:							     */
/*								     */
/* INTERNAL REFERENCES: none					     */
/*   ROUTINES:							     */
/*								     */
/* EXTERNAL REFERENCES: 					     */
/*   ROUTINES:							     */
/*		  DOSREAD	 - read file			     */
/******************* END OF SPECIFICATIONS ***************************/

unsigned
readinput(resptype)
int resptype;
{
  int rc;				   /* return code		   */
  char	char_avail_flag;		   /* relate to KBDCHARIN	   */
  char	kbdin_flag = OFF;		   /* relate to KBDCHARIN	   */
/*************************************/
/*				     */
/*  for DOSQHANDLETYPE		     */
/*				     */
/*************************************/
  unsigned handletype;	     /* stdin handletype for DOSQHANDTYPE  */
  unsigned out_handletype;   /* stdout handletype for DOSQHANDTYPE  */
  unsigned flagword;	     /* flagword   for DOSQHANDTYPE  */
  #define FILEHANDLE	 0   /* file systme handle type      */
  #define DEVICEHANDLE	 1   /* device handle type	     */
  #define PIPEHANDLE	 2   /* pipe handle type      DCR74  */

/*************************************/
/*				     */
/*  for DOSREAD 		     */
/*				     */
/*************************************/
  char inputchar;		    /* char input from DOSREAD	    */
  unsigned short num_read_byte;     /* num. of actually read bytes  */
  #define ONE_BYTE  1		    /* number of bytes to read at   */
				    /*	 one time		    */
  char carriage_detect = OFF;	    /* when CR is detected	    */
				    /*	 set to ON		    */
  #define CR_CHAR  0x0d 	    /* Carriage Return Code	    */
  #define NL_CHAR  0x0a 	    /* New Line (line feed) Code    */

/*************************************/
/*				     */
/* for DBCS char checking	     */
/*				     */
/*************************************/

  #define DBCS_LEAD_BYTE   1
  char dbcs_being_processed = OFF;    /* DBCS process flag (init OFF) */

/*************************************/
/*				     */
/* If in Protect mode, get handletype*/
/* of current Standard Input	     */
/* (handle 0).			     */
/*				     */
/* In real mode, DOSQHANDLETYPE is   */
/* is not supported. Set handletype  */
/* to DEVICEHANDLE (= 1)	     */
/*				     */
/*************************************/

    DCALL(DOSQHANDLETYPE);
    if ((rc = DOSQHANDTYPE(	       /* get the handle type	       */
	    (unsigned short )STDIN_HDL,
	    (unsigned short _far16 *)&handletype,
	    (unsigned short _far16 *)&flagword))
			      != OK)	   {
       DRETCD;
       return(rc);
    }
    DRETCD;
    if ((rc = DOSQHANDTYPE(	       /* get the handle type	       */
	    (unsigned short)STDOUT_HDL,
	    (unsigned short _far16 *)&out_handletype,
	    (unsigned short _far16 *)&flagword))
			      != OK)
       return(rc);
    bytes_read = 0;		       /* reset number of read bytes   */
				       /* to be returned	       */
/*************************************/
/*				     */
/* In protect mode,  if input being  */
/* redirected to a file, kbd buffer  */
/* is not flushed. In real mode, kbd */
/* buffer is always flushed even     */
/* if input being redirected.	     */
/*				     */
/*************************************/

    handletype = handletype & 0x00FF;	      /*   and off high byte	    */
    out_handletype = out_handletype & 0x00FF;
    if (handletype == DEVICEHANDLE)    {      /*  DCR74      if device	    */
       DCALL(KBDFLUSHBUFFER);		      /* then			    */
       if ((rc =			      /*     flush keyboard buffer  */
	    KBDFLUSHBUFFER(KBDHANDLE)) != OK)	{
	  DRETCD;
	  return(rc);
       }
       DRETCD;
    }

/*************************************/
/*				     */
/* read one byte from std input dev  */
/*				     */
/*************************************/

DO_DOSREAD:
	 /* if stdin is not redirected AND stdout is redirected p3135 */
  if ((handletype == DEVICEHANDLE) && (out_handletype == FILEHANDLE)) {
     kbdin_flag = ON;
     rc = KBDCHARIN (
	(struct KeyData _far16 *) &KeyBuf,
	(unsigned short)  0,
	(unsigned short)  0 );
     if ( rc != OK)
       return(rc);
    char_avail_flag = (unsigned char)(KeyBuf.status & 0x40); /* select bit 6 */
    if (char_avail_flag == FALSE)	 /* if EOF, return  ??????????	 */
	return(ERROR_CM_EOF_REDIRECT);	  /* error code.		  */

    bytes_read ++;			  /* update accumu num of bytes   */
    workbuf[bytes_read-1] = KeyBuf.char_code; /* put input char in buffer */

  } else {
    DCALL(DOSREAD);
    if ((rc = DOSREAD((unsigned short) STDIN_HDL,  /* read one byte from	   */
	   (char _far16 *)&inputchar,		/* standard input.		*/
	   (unsigned short) ONE_BYTE,
	   (unsigned short _far16 *) &num_read_byte))
				      != OK)	 {
       DRETCD;
       return(rc);
    }
    DRETCD;
  if (num_read_byte == 0)		     /* if EOF, return		     */
      return(ERROR_CM_EOF_REDIRECT);	     /* error code.		     */

  bytes_read +=num_read_byte;		     /* update accumu num of bytes   */
  workbuf[bytes_read-1] = inputchar;	     /* put input char in buffer     */
  }
  /**********************************************************************/
  /* DBCS handling -  examine if DBCS process flag			*/
  /* which is set when DBCS lead byte is detected. If it's ON, do not   */
  /* check CR,NL check. If OFF, then go to CR,NL checking process.	*/
  /**********************************************************************/

  if (dbcs_being_processed == OFF)  {	     /* DBCS being processed?	     */
     if (check_dbcs(inputchar)		     /*  Is it DBCS lead byte?	     */
	   == DBCS_LEAD_BYTE)  {	     /*  Yes-> set DBCS process flag */
	dbcs_being_processed = ON;	     /*    get tailing character.    */
	goto DO_DOSREAD;
     }
     /*****************************************************************/
     /* Check if input is Carriage return(0D) or New line (0A)	      */
     /* or EOF(1A).  if 0D, 0A are received, terminate reading data.  */
     /* if EOF (1A) is received and requested response type is Yes/No,*/
     /* return No response as default.				      */
     /*****************************************************************/
     if (kbdin_flag)	{		   /* ## */
       switch(KeyBuf.char_code) 	   /* ## */
	{				   /* ## */
	 case CR_CHAR:			   /* ## */
	   carriage_detect = ON;       /* ## Carriage Return (0D) is found,*/
	     if ((handletype==FILEHANDLE) || (out_handletype==FILEHANDLE))
	     {				       /* stdin redirected to a file */
		 workbuf[bytes_read++] = NL_CHAR;  /* add NL	      ;BC016;*/
		 workbuf[bytes_read]   = 0;	   /* & echo to stdout;BC016;*/
		 DOSWRITE(STDOUT_HDL, workbuf, bytes_read,	    /*;BC016;*/
					    &byteswritten);	    /*;BC016;*/
	     }				     /*   echo input data.  ##	    */
	      return(OK);		     /* normal return	    ##	    */
	 default:			     /* ##			    */
	   carriage_detect = OFF;	 /* ##	other char -> reset CR flag */
	}
     }	else   {
       switch(inputchar)
	{
	 case CR_CHAR:
	   carriage_detect = ON;	   /* Carriage Return (0D) is found,*/
	   if (!kbdin_flag)
	      break;
	 case NL_CHAR:
	  /*******************************************************************/
	  /* CR(0x0d),NL(0x0a) character sets are found, terminate reading   */
	  /* data and return normally. If input is redirected to file,	     */
	  /* write input data to standard output.  (only for protect mode).  */
	  /*******************************************************************/
	  if (carriage_detect == ON)   {    /* 0D,0A sequence is dected?   */
	    if ((handletype==FILEHANDLE) || (out_handletype==FILEHANDLE))
	    {				       /* stdin redirected to a file */
		workbuf[bytes_read] = 0;	   /* echo to stdout  ;BC016;*/
		DOSWRITE(STDOUT_HDL, workbuf, bytes_read,	    /*;BC016;*/
					   &byteswritten);	    /*;BC016;*/
	    }				    /*	 echo input data.	   */
	     return(OK);		    /* normal return		   */
	  }
	default:
	  carriage_detect = OFF;	    /* other char -> reset CR flag */
       }
     }
  } else
     dbcs_being_processed = OFF; /* DBCS tail byte is received. reset DBCS process flag. */
  goto DO_DOSREAD;		 /* read next data until 0D,0A fnd*/
  /*   The next line is  here to get rid of W3 compile warning	##NR */
  resptype;	/* ##NR */
}

