/****************************************************************************
**
**  Name:  tfield.cpp
**
**  Description:
**     Source file for peripheral server tfield component.
**
**  $Log:   S:/tbird/mt2_186/peri/tfield.cpv  $
** 
**    Rev 1.0   16 Dec 1996 16:19:50   Judy
** Initial revision.
** 
**    Rev 1.0   11 Oct 1996 18:47:18   Judy
** Initial revision.
** 
**    Rev 1.14   11 Oct 1994 09:19:22   dennis
** Added ShiftValue method.
** 
**    Rev 1.13   03 May 1994 14:23:00   nghia
** Fixed typo ownsElements().
** 
**    Rev 1.12   03 May 1994 09:44:40   nghia
** Added TField destructor and initialize TField object correctly.
** 
**    Rev 1.11   19 Apr 1994 16:10:38   nghia
** Revised to follow coding standard.
** Used const char* instead of directly embeded string.
** 
**    Rev 1.10   23 Nov 1993 11:02:16   ron
** More U8->U16 conversions
** 
**    Rev 1.9   23 Nov 1993 10:27:20   ron
** 255 -> 256 buffer size problem
** 
**    Rev 1.8   23 Nov 1993 10:09:16   ron
** always use last enumeration value even if !anyvalue
** 
**    Rev 1.7   05 Nov 1993 10:04:40   ron
** removed unnecessary testfunc.h
** 
**    Rev 1.6   03 Nov 1993 13:47:08   ron
** ready for first build of 2.1
** 
**    Rev 1.5   18 Oct 1993 15:23:06   ron
** bug fix for field enumeration reader
** 
**    Rev 1.4   15 Oct 1993 11:14:46   ron
** ready to build and debug
** 
**    Rev 1.3   14 Oct 1993 12:41:26   ron
** checkpoint
** 
**    Rev 1.2   04 Oct 1993 16:37:50   marilyn
** Updated member functions.
** 
**    Rev 1.1   30 Sep 1993 16:44:14   ron
** bug fixes for reader
** 
**    Rev 1.0   30 Sep 1993 13:41:36   ron
** Initial revision.
** 
**  $Header:   S:/tbird/mt2_186/peri/tfield.cpv   1.0   16 Dec 1996 16:19:50   Judy  $
**
**  Copyright (C) 1993 Microtek International.  All rights reserved.
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/
#define STRICT
#define WIN31

#ifndef _PERISERV_
#include "periserv.h"
#endif

#ifndef _PERIPRES_
#include "peripres.h"
#endif

#ifndef _ADDR_
#include "addr.h"
#endif

#ifndef _TBIRDMEM_
#include "tbirdmem.h"
#endif

#ifndef _HEAP_
#include "heap.h"
#endif

#ifndef _ENLIB_
#include "enlib.h"
#endif

#ifndef _EVENTS_
#include "events.h"
#endif

#ifndef _SDNUM_
#include "sdnum.h"
#endif

#ifndef _SSHARED_
#include "sshared.h"
#endif


// BorlandC includes
#ifndef __CTYPE_H
#include <ctype.h>
#endif

#ifndef __STDIO_H
#include <stdio.h>
#endif

#ifndef __ASSOC_H
#include <assoc.h>
#endif

#ifndef __LIST_H
#include <list.h>
#endif

#ifndef __IO_H
#include <io.h>
#endif

#ifndef __STRING_H
#include <string.h>
#endif



                       /****************************
                        *                          *
                        *     LOCAL DEFINITIONS    *
                        *                          *
                        ****************************/

const CHAR *bField = "begin_f";
const CHAR *eField = "end_f";

                       /****************************
                        *                          *
                        *    EXTERNAL VARIABLES    *
                        *                          *
                        ****************************/

                       /****************************
                        *                          *
                        *     LOCAL PROTOTYPES     *
                        *                          *
                        ****************************/

                       /****************************
                        *                          *
                        *      EXECUTABLE CODE     *
                        *                          *
                        ****************************/
//****************************************************************************
//  TField
//
//  Description:
//     Field object used inside of register objects to contain field
//     specific information.
//****************************************************************************

//-----------------------------------------------------------------------------
// TField CTor
//-----------------------------------------------------------------------------
TField::TField(HFILE hFile, U16 startLine) : value(), fieldDict() {
   LPSTR lpTok;
   S32 lTmp;
   U32 uTmp;
   PTValue value;
   PString string;
   CHAR *endptr, linebuf[MAX_INFOSTR];

   fieldDict.ownsElements(1);
   errLine = startLine;
   errField = 0;
   status = ER_PP_READING_FIELD; // use this error if we return early...
   if (FindLine(hFile, (U16 FAR *) &errLine, (LPSTR) linebuf,
      MAX_INFOSTR) != GOOD) return;
   // find bField token
   lpTok = _fstrtok(linebuf, WhiteSpace);
   if (lpTok == NULL ||
      _fstrnicmp(lpTok, (LPSTR)bField, strlen(bField)) != 0) return;
   // find field attributes
   if (FindLine(hFile, (U16 FAR *) &errLine, (LPSTR) linebuf,
      MAX_INFOSTR) != GOOD) return;

   // find mnemonic
   errField = 0;
   lpTok = _fstrtok(linebuf, WhiteSpace);
   if (lpTok == NULL) return;
   _fstrncpy((LPSTR)name, lpTok, MAX_MNEMONIC - 1);
   name[MAX_MNEMONIC - 1] = '\0'; // make extra sure it's null terminated

   // find #bits
   errField = 1;
   lpTok = _fstrtok(NULL, WhiteSpace);
   if (lpTok == NULL) return;
   lTmp = strtol(lpTok, &endptr, 0);
   if (lTmp < 1 || lTmp > 256) return;
   size = (U8) lTmp;

   // find fieldLocation  (refers to high bit position)
   errField = 2;
   lpTok = _fstrtok(NULL, WhiteSpace);
   if (lpTok == NULL) return;
   lTmp = strtol(lpTok, &endptr, 0);
   if (lTmp < 0 || lTmp > 256) return;
   fieldLocation = (U8) lTmp;

   // find minValue
   errField = 3;
   lpTok = _fstrtok(NULL, WhiteSpace);
   if (lpTok == NULL) return;
   lTmp = strtol(lpTok, &endptr, 0);
   if (lTmp < 0) return;
   minValue = (U32) lTmp;

   // find maxValue
   errField = 4;
   lpTok = _fstrtok(NULL, WhiteSpace);
   if (lpTok == NULL) return;
   lTmp = strtol(lpTok, &endptr, 0);
   if (lTmp < 0) return;
   maxValue = (U32) lTmp;

   // find anyValueOk?
   errField = 5;
   lpTok = _fstrtok(NULL, WhiteSpace);
   if (lpTok == NULL) return;
   lTmp = strtol(lpTok, &endptr, 0);
   if (lTmp < 0) return;
   anyValue = (BOOLEAN) (lTmp != 0);

   // find multiWritesFlag
   errField = 6;
   lpTok = _fstrtok(NULL, WhiteSpace);
   if (lpTok == NULL) return;
   lTmp = strtol(lpTok, &endptr, 0);
   if (lTmp < 0) return;
   multiWrites = (BOOLEAN) (lTmp != 0);

   // find long name
   errField = 0;
   if (FindLine(hFile, (U16 FAR *) &errLine, (LPSTR) linebuf,
      MAX_INFOSTR) != GOOD) return;
   if (linebuf[0] == '"') {
     lpTok = _fstrtok(linebuf, "\"");
   }
   else {
     lpTok = _fstrtok(linebuf, "\"");
     if (lpTok == NULL) return;
     lpTok = _fstrtok(NULL, "\"");
   }
   if (lpTok == NULL) {
      long_name[0] = '\0'; // no name
   }
   else {
      _fstrncpy((LPSTR)long_name,lpTok, MAX_LONG_NAME - 1);
      // make extra sure it's null terminated
      long_name[MAX_LONG_NAME - 1] = '\0'; 
   }

   // find count of enumerations
   if (FindLine(hFile, (U16 FAR *) &errLine, (LPSTR) linebuf,
      MAX_INFOSTR) != GOOD) return;
   lpTok = _fstrtok(linebuf, WhiteSpace);
   if (lpTok == NULL) return;
   lTmp = strtol(lpTok, &endptr, 0);
   if (lTmp < 0) return;
   stringCnt = (U32) lTmp;

   // find enumerations
   for (lTmp = 0; lTmp < stringCnt; lTmp++) {
      errField = 0;
      if (FindLine(hFile, (U16 FAR *) &errLine, (LPSTR) linebuf,
         MAX_INFOSTR) != GOOD) return;
      lpTok = _fstrtok(linebuf, WhiteSpace);
      if (lpTok == NULL) return;
      uTmp = strtoul(lpTok, &endptr, 0);
      // if there's only one space, fstrtok returns the right string right
      // away, but otherwise returns leading blanks...
      errField = 1;
      lpTok = _fstrtok(NULL, "\"");
      if (lpTok == NULL) return;
      while((*lpTok) == ' ') lpTok++;
      if ((*lpTok) == '"' || (*lpTok) == '\0') {
         lpTok = _fstrtok(NULL, "\"");
      }
      string = new String((LPSTR)lpTok);
      value = new TValue(uTmp);
      this->AddFieldDesc(*(new Association(*value,*string)));
   }

   // find eField token
   errField = 0;
   if (FindLine(hFile, (U16 FAR *) &errLine, (LPSTR) linebuf,
      MAX_INFOSTR) != GOOD) return;
   lpTok = _fstrtok(linebuf, WhiteSpace);
   if (lpTok == NULL ||
      _fstrnicmp(lpTok, (LPSTR)eField, strlen(eField)) != 0) return;
   status = GOOD;
   return;
}

//-----------------------------------------------------------------------------
// ~TField - Dtor
//-----------------------------------------------------------------------------
TField::~TField() {
   // destroy the Field dictionary
   fieldDict.flush();
}

//-----------------------------------------------------------------------------
// GetValue
//-----------------------------------------------------------------------------
U32 TField::GetValue() { return value.GetValue(); }

//-----------------------------------------------------------------------------
// SetValue
//-----------------------------------------------------------------------------
VOID TField::SetValue(U32 newValue) { value.SetValue(newValue); }

//-----------------------------------------------------------------------------
// GetSize
//-----------------------------------------------------------------------------
U16 TField::GetSize() { return size; }

//-----------------------------------------------------------------------------
// GetName
//-----------------------------------------------------------------------------
LPSTR TField::GetName(LPSTR buffer) const {
   if (buffer != NULL)
      strcpy(buffer,name);
   return ((LPSTR)name);
}

//-----------------------------------------------------------------------------
// GetLongName
//-----------------------------------------------------------------------------
LPSTR TField::GetLongName(LPSTR buffer) const {
   if (long_name[0] == '\0')
      strcpy((LPSTR) long_name, (LPSTR) name);
   if (buffer != NULL)
      strcpy(buffer,(LPSTR) long_name);
   return ((LPSTR)long_name);
}

//-----------------------------------------------------------------------------
// GetFielLocation
//-----------------------------------------------------------------------------
U8 TField::GetFieldLocation() { return fieldLocation; }

//-----------------------------------------------------------------------------
// GetMinValue
//-----------------------------------------------------------------------------
U32 TField::GetMinValue() { return minValue; }

//-----------------------------------------------------------------------------
// GetMaxValue
//-----------------------------------------------------------------------------
U32 TField::GetMaxValue() { return maxValue; }

//-----------------------------------------------------------------------------
// DontCareValue
//-----------------------------------------------------------------------------
BOOLEAN TField::DontCareValue() { return anyValue; }

//-----------------------------------------------------------------------------
// GetStringCnt
//-----------------------------------------------------------------------------
U32 TField::GetStringCnt() {return stringCnt; }


static U32 fieldmasks[33] = { 0x0, 0x1, 0x3, 0x7, 
                            0x0F, 0x1F, 0x3F, 0x7F, 
                            0xFF, 0x1FF, 0x3FF, 0x7FF,
                            0xFFF, 0x1FFF, 0x3FFF, 0x7FFF,
                            0xFFFF, 0x1FFFF, 0x3FFFF, 0x7FFFF,
                            0xFFFFF, 0x1FFFFF, 0x3FFFFF, 0x7FFFFF,
                            0xFFFFFF };

//-----------------------------------------------------------------------------
// MaskOutValue
//-----------------------------------------------------------------------------
U32 TField::MaskOutValue(U32 regValue) {
   U32 fieldMask;
   U32 fieldVal;
   U16 lowPos = fieldLocation - size + 1;

   fieldMask = (fieldmasks[size] << lowPos);
   fieldVal = (regValue & fieldMask) >> lowPos;
   SetValue(fieldVal);
   return (fieldVal);
}

//-----------------------------------------------------------------------------
// ShiftValue
//-----------------------------------------------------------------------------
U32 TField::ShiftValue(U32 regValue) {
   U32 fieldVal;
   U16 lowPos = fieldLocation - size + 1;

   fieldVal = regValue << lowPos;
   return (fieldVal);
}

//-----------------------------------------------------------------------------
// AddFieldDesc
//-----------------------------------------------------------------------------
VOID TField::AddFieldDesc(Object& association) {
   fieldDict.add(association);
}

//-----------------------------------------------------------------------------
// LookupFieldDesc
//-----------------------------------------------------------------------------
LPSTR TField::LookupFieldDesc(LPSTR buffer,PTValue fieldValue) {

   if (buffer == NULL)
      return NULL;
   strcpy(buffer,"\0");
   if (!fieldDict.isEmpty()) {
      if (fieldValue == NULL) 
         fieldValue = &value;
      Association& found = fieldDict.lookup(*fieldValue);
      if (found == NOOBJECT || found.value() == NOOBJECT)  {
         // no match so then use the default string if
         // it is a don't care value
         // if (anyValue) {  // do this in all cases Ron 11/23
            TValue thisValue(maxValue);
            Association& found = fieldDict.lookup(thisValue);
            if (found != NOOBJECT && found.value() != NOOBJECT) {
               String &foundString = (String &) (found.value());
               const char _FAR * tmpStr = (const char _FAR *) foundString;
               strcpy(buffer, tmpStr);
            }
         // }
      }
      else {
         // we found it
         strcpy(buffer,(const char *)((String&)(found.value())));
      }
   }
   return (buffer);
}

//-----------------------------------------------------------------------------
// isEqual
//-----------------------------------------------------------------------------
int TField::isEqual( const Object _FAR & other) const {
   PTField that = (PTField) &((TField&)other);
   if (*that == NOOBJECT || *this == NOOBJECT) {
      return (this == that);
   }
   return (strcmp(this->GetName(), that->GetName()) == 0);
};

/********************************** E O F ********************************/
