/**************************************************************************
 *
 * SOURCE FILE NAME = TDICINIT.C
 *
 * DESCRIPTIVE NAME = Initialisation code
 *
 * Copyright : COPYRIGHT IBM CORPORATION, 1991, 1992
 *             LICENSED MATERIAL - PROGRAM PROPERTY OF IBM
 *             REFER TO COPYRIGHT INSTRUCTION FORM#G120-2083
 *             RESTRICTED MATERIALS OF IBM
 *             IBM CONFIDENTIAL
 *
 * VERSION = V2.0
 *
 * DATE        09/09/91
 *
 * DESCRIPTION
 *
 *
 * FUNCTIONS      ReqInit,          GetPutMsg,        ParseParms,
 *                FindToken,        GetArgs,          GetNextToken,
 *                SkipWhiteSpaces,  SkipBlackSpaces.
 *
 * ENTRY POINTS:
 *
 * DEPENDENCIES:
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
 * CHANGE ACTIVITY =
 *  DATE      FLAG        APAR   CHANGE DESCRIPTION
 *  --------  ----------  -----  --------------------------------------
 *  mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
 ****************************************************************************/

#define  INCL_OS2STD
#define  INCL_DOSINFOSEG
#define  INCL_DOSSESMGR
#define  INCL_DOSMISC
#define  INCL_KBD
#define  INCL_DOSPROCESS
#include <os2.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "toudefs.h"
#include "reqblk.h"
#include "toutypes.h"
#include "devhlp.h"
#include "touasm.h"
#include "tdierr.h"

/*
** External global data in DGROUP
*/

extern VOID(FAR PASCAL *NEAR DevHlp_Entry)();

extern EVENT NEAR DfltEQs[];
extern PGINFOSEG NEAR pGlobalInfoSeg;
extern UCHAR NEAR NumSess;
extern IDC NEAR DD_Idc;
extern USHORT NEAR InitStage;
extern SGCB NEAR InitSgcb;
extern SGCB NEAR ShellSgcb;
extern SGCB NEAR PopupSgcb;
extern USHORT NEAR MaxEQLen;
extern TDISELMETHOD NEAR DefSelm;
extern USHORT NEAR DefQSize;

/*
** dummy variables to pick up end of main code & data segments
*/
extern BYTE NEAR last_code;
extern BYTE NEAR last_data;
/* extern VOID FAR PASCAL        c_init(VOID);                               */

/*
** Defines
*/
#define  HKBD          0
#define  SYS_MSG       SysMsgName
#define  TDI_MSG       TdiMsgName
#define  MSG_SIGNON    1
#define  MSG_ERR_INIT  2
#define  MSG_NO_TYPE   3
#define  MSG_SYNTAX    4
#define  MSG_BAD_ARGS  5
#define  MSG_GENERAL   2
#define  MSG_DUP_TOK   7
#define  MSG_PARMS_BAD 8
#define  MSG_PRESS_RET 1726

/*
** External global data in INIT_GROUP. Will be discarded after init
*/

extern UCHAR FAR OurName[];
extern UCHAR FAR SysMsgName[];
extern UCHAR FAR TdiMsgName[];
extern UCHAR FAR StrSize[];
extern UCHAR FAR StrType[];
extern IDC FAR dd_idc_temp;           /* Must be same seg as dd_name for -   */
extern UCHAR FAR DD_Name[];           /* dev help attach call                */
extern REGISTERDATA FAR SmData;
extern TOKENS Tokens[];

/*
** Prototypes
*/

VOID FAR ReqInit(PREQBLK);
STATIC VOID NEAR CDECL GetPutMsg(PCHAR msg_file,USHORT msg_num,USHORT num_parms
                                  ,...);
STATIC USHORT NEAR PASCAL ParseParms(PCHAR conf_parms);
STATIC SHORT NEAR FindToken(PCHAR Line,PTOKENS pTokens,PCHAR *pArgs);
STATIC USHORT NEAR GetArgs(PCHAR ArgPtr,USHORT NumArgs,PUSHORT Args,
                            USHORT MaxArgs);
STATIC PCHAR NEAR GetNextToken(PCHAR pChar);
PCHAR SkipWhiteSpaces(PCHAR pChar);
PCHAR SkipBlackSpaces(PCHAR pChar);

extern VOID FAR PASCAL InitFsCb(PSGCB,NPEVENT);

USHORT XXXXXXXX;

/****************************************************************************
 *
 * FUNCTION NAME = ReqInit
 *
 * DESCRIPTION   =
 *    Called from:
 *        StratEntry (seg2)
 *
 *
 * INPUT         = (PREQBLK pReqBlk)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

extern VOID FAR ReqInit(PREQBLK pReqBlk)
{
  SEL TempSel;                        /* result not used                     */
  CHAR AscErr[16];
  NPEVENT pDfltEQs = DfltEQs;
  USHORT ErrNum;
  USHORT pause_required = 0;
  CHAR OpBuff;
  STRINGINBUF StrInBuf =
  {
    1,0
  } ;

#ifdef   INST_ABORT
  KBDKEYINFO kbci;
  USHORT i;
#endif

#ifdef   INST_ABORT
  /* abort install if hit <ESC> quickly after signon message                 */
  /* break if hit <.>                                                        */
  KbdPeek(&kbci, 0);                  /* init kb!                            */
  for (i = 0; i < 10; ++i)
  {
    DosSleep(100l);
    if ((KbdCharIn(&kbci, IO_NOWAIT, 0) == 0) && kbci.fbStatus & 0x40)
      break;
  }
  if (kbci.chChar == '.')
    _asm int 3
  else
    if (kbci.chChar == '\033')
    {
      pReqBlk->status |= REQE_ABORT;
      goto ReqInit_error;
    }
#endif

  DevHlp_Entry = pReqBlk->init_in.dev_hlp;
  OFFSETOF(pGlobalInfoSeg) = 0;       /* init offset part                    */
  if (DosGetInfoSeg((PSEL)&SELECTOROF(pGlobalInfoSeg), &TempSel))
  {
    ErrNum = TDIERR_DosGetInfoSeg;
    goto ReqInit_abort;
  }
  NumSess = pGlobalInfoSeg->sgMax;    /* get max number of sessions          */

  /* update info seg with ring0 selector                                     */
  if ((SELECTOROF(pGlobalInfoSeg) = *(PSEL)DHGetDOSVar(GDV_GlobalInfoSeg)) ==
     NULL)
  {
    ErrNum = TDIERR_DHGetDosVar;
    goto ReqInit_abort;
  }

  /* extract config parms                                                    */
  /* setup DD_Name from 'TYPE=<name>', 'QSIZE=' & 'SEL='                     */
  pause_required = ParseParms(pReqBlk->init_in.init_args);

  /* Attach to device dependant device driver                                */
  /* (name & idc must be in same segment)                                    */
  if (DHAttachDD(DD_Name, &dd_idc_temp))
  {
    ErrNum = TDIERR_DHAttachDD;
    goto ReqInit_abort;
  }

  /* Copy from init data seg to dgroup                                       */
  _fmemmove(&DD_Idc, &dd_idc_temp, sizeof(IDC));
  if (DHRegisterPDD(OurName, PddEntry))
  {
    ErrNum = TDIERR_DHRegisterPDD;
    goto ReqInit_abort;
  }
  if (DosSMRegisterDD(&SmData))
  {
    ErrNum = TDIERR_DosSmRegisterDD;
    goto ReqInit_abort;
  }

  InitFsCb(&InitSgcb, pDfltEQs);
  pDfltEQs += MaxEQLen;

  InitFsCb(&ShellSgcb, pDfltEQs);
  pDfltEQs += MaxEQLen;

  InitFsCb(&PopupSgcb, pDfltEQs);
  pDfltEQs += MaxEQLen;

  /* ??? should use pDfltEQs not last_data                                   */
  pReqBlk->init_out.code_end = (VOID NEAR *)&last_code;
  pReqBlk->init_out.data_end = (VOID NEAR *)&last_data;
  InitStage = 1;
  if (pause_required)
  { /* wait for a <CR/LF> as there has been a warning msg                    */
    /* drw 1/8/91                                                            */
    GetPutMsg(TDI_MSG, MSG_SIGNON, 1, VERSION); /* signon message            */
    KbdFlushBuffer(HKBD);
    GetPutMsg(SYS_MSG, MSG_PRESS_RET, 0);
    KbdStringIn(&OpBuff, &StrInBuf, IO_WAIT, HKBD);
  }
  return ;

ReqInit_abort:

  /* drw 1/8/91                                                              */
  GetPutMsg(TDI_MSG, MSG_SIGNON, 1, VERSION);  /* signon message             */
  itoa(ErrNum, AscErr, 10);
  GetPutMsg(TDI_MSG, MSG_ERR_INIT, 1, AscErr); /* init error                 */
  pReqBlk->status |= REQE_ABORT;

#ifdef   INST_ABORT
ReqInit_error:
#endif

  pReqBlk->init_out.code_end = 0;
  pReqBlk->init_out.data_end = 0;
}                                     /* ReqInit                             */


/****************************************************************************
 *
 * FUNCTION NAME = GetPutMsg
 *
 * DESCRIPTION   =
 *
 *
 * INPUT         = (PCHAR msg_file,USHORT msg_num,USHORT num_parms,...)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

STATIC VOID NEAR CDECL GetPutMsg(PCHAR msg_file,USHORT msg_num,USHORT num_parms
                                  ,...)
{
  va_list arg_ptr;
  PCHAR parms_table[9];
  CHAR data_area[160];
  USHORT msg_len;
  USHORT ret;
  USHORT parms_idx;
  /*      PCHAR           msg_file = "TDI.MSG";                              */

#define  STDOUT        1
  va_start(arg_ptr, num_parms);

  /* build parameter list array                                              */
  for (parms_idx = 0;
       parms_idx < num_parms && parms_idx < sizeof(parms_table) / sizeof(PCHAR);
       ++parms_idx)
    parms_table[parms_idx] = va_arg(arg_ptr, PCHAR);


  ret = DosGetMessage(parms_table,
                      num_parms,
                      (PCHAR)data_area,
                      sizeof(data_area),
                      msg_num,
                      (PCHAR)msg_file,
                      (PUSHORT)&msg_len);

  ret = DosPutMessage(STDOUT, msg_len, (PCHAR)data_area);
  va_end(arg_ptr);
}                                     /* GetPutMsg                           */


/****************************************************************************
 *
 * FUNCTION NAME = ParseParms
 *
 * DESCRIPTION   =
 *
 *
 * INPUT         = (PCHAR parms)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

STATIC USHORT NEAR PASCAL ParseParms(PCHAR parms)
{
  /* #define MAX_ARGS      (sizeof(Tokens)/sizeof(Tokens[0])-1)              */
#define  MAX_ARGS      4

  USHORT type_found = 0;              /* type token found flag               */
  PCHAR arg_ptr;
  USHORT idx;
  USHORT args[MAX_ARGS];
  CHAR lbuff[1024];
  USHORT pause_required = 0;          /* need to pause before exit           */
  PCHAR Tok;

  /* Check local buffer is big enough                                        */
  if (_fstrlen(parms) >= sizeof(lbuff))
  {
    GetPutMsg(TDI_MSG, MSG_GENERAL, 0);
    pause_required = 1;
  }

  _fstrcpy(lbuff, parms);             /* make local copy of parms            */

  if ((Tok = GetNextToken(lbuff)) != NULL) /* remove file name               */
    for (; Tok = GetNextToken(NULL); )
    {
      if ((idx = FindToken(Tok, Tokens, &arg_ptr)) == TOK_ILLEGAL)
      {                               /* token not found                     */
        GetPutMsg(TDI_MSG, MSG_SYNTAX, 1, Tok);
        pause_required = 1;
        continue;                     /* skip to next token                  */
      }

      if (Tokens[idx].idx == TOK_TYPE)
        type_found = 1;

      if (GetArgs(arg_ptr, Tokens[idx].nargs, args, MAX_ARGS))
      {                               /* illegal number of args or bad       */
        GetPutMsg(TDI_MSG, MSG_PARMS_BAD, 1, Tok);
        pause_required = 1;
        continue;                     /* skip to next token                  */
      }

      if (Tokens[idx].fUsed)
      {                               /* Token already found                 */
        GetPutMsg(TDI_MSG, MSG_DUP_TOK, 1, Tok);
        pause_required = 1;
        continue;                     /* skip to next token                  */
      }

      switch (Tokens[idx].idx)
      {
        case  TOK_TYPE :
          if (_fstrlen(arg_ptr) > _fstrlen(DD_Name))
            break;
          _fstrupr(arg_ptr);
          _fstrncpy(DD_Name, arg_ptr, _fstrlen(arg_ptr));
          Tokens[idx].fUsed = 1;
          continue;                   /* ok                                  */

        case  TOK_QSIZE :
          if (args[0] > 100 || args[0] == 0)
            break;
          DefQSize = args[0];
          Tokens[idx].fUsed = 1;
          continue;                   /* ok                                  */

        case  TOK_SEL :
          if (args[0] > 5 || args[0] > 1 && (args[1] > 40 || args[2] > 4095) ||
              args[0] > 3 && args[3] > 40)
            break;
          DefSelm.Type = args[0];
          DefSelm.NumPoints = args[1];
          DefSelm.Tolerance = args[2];
          DefSelm.SearchLimit = args[3];
          Tokens[idx].fUsed = 1;
          continue;                   /* ok                                  */
      }                               /* switch                              */

      /* Come here if args bad, from a 'break' in above switch               */
      /* use continue for good args                                          */
      GetPutMsg(TDI_MSG, MSG_BAD_ARGS, 1, Tok);/* parms out of range         */
      pause_required = 1;
    }                                 /* for                                 */

  if (!type_found)
  {                                   /* no 'type=' found                    */
    GetPutMsg(TDI_MSG, MSG_NO_TYPE, 0);
    pause_required = 1;
  }

  return (pause_required);
}                                     /* ParseParms                          */


/****************************************************************************
 *
 * FUNCTION NAME = FindToken
 *
 * DESCRIPTION   = Serach list of tokens for a match
 *
 *
 * INPUT         = (PCHAR Line,PTOKENS pTokens,PCHAR *pArgs)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

STATIC SHORT NEAR FindToken(PCHAR Line,PTOKENS pTokens,PCHAR *pArgs)
{
  SHORT idx;                          /* index into token array              */
  PCHAR pTok;                         /* ptr to current token                */
  USHORT lenTok;                      /* length of current token             */

  for (idx = 0; pTok = pTokens[idx].name; ++idx)
  {                                   /* search list of tokens, ignore case  */
    lenTok = _fstrlen(pTok);
    if (!_fstrnicmp(pTok, Line, lenTok))
      break;
  }                                   /* for                                 */

  if (pTok)
  {                                   /* token found                         */
    *pArgs = &Line[lenTok];           /* start of args after token           */
    return (idx);
  }
  else
    return (TOK_ILLEGAL);             /* not found                           */
}                                     /* FindToken                           */


/****************************************************************************
 *
 * FUNCTION NAME = GetArgs
 *
 * DESCRIPTION   = Extract args sepparated by commas
 *
 *
 * INPUT         = (PCHAR ArgPtr,USHORT NumArgs,PUSHORT Args,USHORT
 *                    MaxArgs)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

STATIC USHORT NEAR GetArgs(PCHAR ArgPtr,USHORT NumArgs,PUSHORT Args,
                            USHORT MaxArgs)
{
  if (NumArgs > MaxArgs)
    return (1);                       /* not enough space for all arguments  */
  for (; NumArgs != 0 && ArgPtr != NULL;
         ArgPtr = _fstrpbrk(ArgPtr, ","), --NumArgs)
  {
    if (*ArgPtr == ',')
      ++ArgPtr;                       /* skip over current comma             */
    *Args++ = atoi(ArgPtr);
  }

  if (NumArgs != 0 || ArgPtr != NULL)
    return (1);                       /* incorrect number of args supplied   */

  return (0);                         /* no error                            */
}                                     /* GetArgs                             */


/****************************************************************************
 *
 * FUNCTION NAME = GetNextToken
 *
 * DESCRIPTION   =
 *
 *
 * INPUT         = (PCHAR pChar)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

STATIC PCHAR NEAR GetNextToken(PCHAR pChar)
{
  return (_fstrtok(pChar, " \t"));
}                                     /* GetNextToken                        */


/****************************************************************************
 *
 * FUNCTION NAME = SkipWhiteSpaces
 *
 * DESCRIPTION   =
 *
 *
 * INPUT         = (PCHAR pChar)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

PCHAR SkipWhiteSpaces(PCHAR pChar)
{
  while (*pChar && (*pChar == ' ' || *pChar == '\t'))
    ++pChar;

  return (pChar);
}                                     /* SkipWhiteSpaces                     */


/****************************************************************************
 *
 * FUNCTION NAME = SkipBlackSpaces
 *
 * DESCRIPTION   =
 *
 *
 * INPUT         = (PCHAR pChar)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

PCHAR SkipBlackSpaces(PCHAR pChar)
{
  while (*pChar && !(*pChar == ' ' || *pChar == '\t'))
    ++pChar;

  return (pChar);
}                                     /* SkipBlackSpaces                     */

/*
** end
*/
