{ -----------------------------------------------------------------------
Tcl Scripting Language Components (Tslc)
Copyright (C) 1996-2002 William Byrne

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

WilliamB@ByrneLitho.com
------------------------------------------------------------------------}
unit BdeMisc;

///////////////////////////////////////////////////////////////////////////////
//
//  TclDbTbl.pas
//	Copyright(c) 1996-1997 William Byrne
//		WilliamB@ByrneLitho.com
//		76262.13@CompuServe.com
//
//	All rights reserved.
//  	William Byrne makes no representations about the suitability of this
//    	software for any purpose.  It is provided "as is" without express or
//    	implied warranty.
//
//	Usage
//      I hereby grant to the legal purchasors of the source code contained
//      herein a non-exclusive license for the use of said source code in
//      developing compiled, executable software, and for the distribution of
//      said source code as part of said developed, compiled, executable software.
//
//  Purpose:
//		This file provides for Bde Table Manipulation using the
//		Tcl Scripting Language Components.
//
//	Editor:
//		Tab stops = 4
//		Page width = 132 characters
//		Font = Courier New, 8pt
//
//  Misc:
//      ??? = Note to self


interface
uses Windows, Bde, Db;

const
	CBRTypeStr: array[cbrUSEDEF..cbrRETRY] of string[15] =
    	('UseDef', 'Continue', 'Abort', 'ChkInput', 'Yes', 'No',
        'PartialAssist', 'Skip', 'Retry');

	cbrError = CBRType(-1);

	CROpStr: array[crNOOP..crDROPADD] of string[8] =
		('NoOp','Add','Copy','Modify','Drop','Redo',
        'Table','Group', 'Family','Done','DropAdd');

    crERROR = CROpType(-1);

    RINTTypeStr: array[rintMASTER..rintDEPENDENT] of string[10] =
    	('Master', 'Dependent');
    RINTQualStr: array[rintRESTRICT..rintCASCADE] of string[8] =
    	('Restrict', 'Cascade');

    PRVTypeStr: array[prvNONE..6] of string[8] =
    	('None', 'ReadOnly', 'Modify', 'Insert', 'InsDel', 'Full', 'Unknown');

	cHIGHFAMRIGHTS = 5;
	FAMTypeStr: array[NOFAMRIGHTS..cHIGHFAMRIGHTS] of string[12] =
    	('NoFamRights', 'FormRights', 'RptRights', 'ValRights', 'SetRights', 'AllFamRights');

	FLDRightsStr: array[fldrREADWRITE..fldrUNKNOWN] of string[10] =
    	('ReadWrite', 'ReadOnly', 'None', 'Unknown');

	FLDVchkStr: array[fldvNOCHECKS..fldvUNKNOWN] of string[10] =
    	('NoChecks', 'HasChecks', 'Unknown');

	BOOLTypeStr: array[False..True] of string[5] =
    	('False', 'True');

	BatchModeStr: array[batchAPPEND..batchCOPY] of string[10] =
    	('Append', 'Update', 'AppendUpdate', 'Subtract', 'Copy');

	batchERROR = eBATMode(-1);

	UpdateStatusStr: array[usUnmodified..usDeleted] of string[10] =
    	('Unmodified', 'Modified', 'Inserted', 'Deleted');

	updateStatusERROR = TUpdateStatus(-1);


// Borrowed from ?samples.pas?
	BDEFldTypes: array [fldUNKNOWN..fldLOCKINFO] of string [8] =
					('Unknown', 'ZString', 'Date', 'Blob', 'Bool', 'Int16',
					 'Int32', 'Float64', 'Decimal', 'Bytes', 'Time', 'DateTime',
					 'UInt16', 'UInt32', 'Float80', 'VarBytes', 'LockInfo');

	BDESubTypes: array [fldstMONEY..fldstAUTOINC] of string [14] =
						 ('Money', 'Memo', 'Binary', 'Formatted Memo', 'OLE',
							'Graphic', 'dBase OLE', 'User Typed', 'AutoInc');

type
		pDBIVCHK = ^DBIVCHK;
{$IFNDEF WIN32}
        pRINTDesc = ^RINTDesc;
{$ENDIF}
		UINT16 = Word;
		pSmallInt = ^SmallInt;
        pDouble = ^Double;


function SafeFAMTypeStr(value: integer): string;
function FLDDescToStr(const FDesc : FLDDesc) : string;
function StrToBDEField(const fType : string):UINT16;
function StrToCBRType(str: string): CBRType;
function StrToCROp(str: string): CROpType;
procedure StrToVCHK(locale: pointer; const val : string; pVChk : pDBIVCHK; fType : integer);
function VCHKDescToStr(locale: pointer; pVChk : pDBIVCHK; fType : integer):string;
function BdeDateToD2(d: DbiDate): TDateTime;
function BdeTimeToD2(t: Bde.Time): TDateTime;
function BdeTimeStampToD2(ts: TimeStamp): TDateTime;
function D2DateToBde(dt: TDateTime): DbiDate;
function D2TimeToBde(dt: TDateTime): Bde.Time;
function D2TimeStampToBde(dt: TDateTime): TimeStamp;
function StrToRINTType(str: string): RINTType;
function StrToRINTQual(str: string): RINTQual;
function StrToPRVType(str: string): PRVType;
function StrToFAMType(str: string): UINT16;
function StrToFLDVchk(str: string): FLDVchk;
function StrToFLDRights(str: string): FLDRights;
function StrToBatchMode(str: string): eBATMode;
function StrToUpdateStatus(str: string): TUpdateStatus;

implementation
uses SysUtils, TslcHash, DbTables;

function StrToUpdateStatus(str: string): TUpdateStatus;
var
	u: TUpdateStatus;
begin
	for u:= usUnmodified to usDeleted do
    	if CompareText(UpdateStatusStr[u], str) = 0 then
    	begin
        	result := u;
            exit;
        end;
	result := updateStatusERROR;
end;

function StrToBatchMode(str: string): eBatMode;
var
	b: eBATMode;
begin
	for b:= batchAPPEND to batchCOPY do
    	if CompareText(BatchModeStr[b], str) = 0 then
        begin
        	result := b;
            exit;
        end;
    result := batchERROR;
end;

function StrToFLDRights(str: string): FLDRights;
var
	r: FLDRights;
begin
	for r:= fldrREADWRITE to fldrUNKNOWN do
    	if CompareText(FLDRightsStr[r], str) = 0 then
        begin
        	result := r;
            exit;
        end;
    result := fldrUNKNOWN;
end;

function StrToFLDVchk(str: string): FLDVchk;
var
	v: FLDVchk;
begin
	for v:= fldvNOCHECKS to fldvUNKNOWN do
    	if CompareText(FLDVchkStr[v], str) = 0 then
        begin
        	result := v;
            exit;
        end;
    result := fldvUNKNOWN;
end;

function SafeFAMTypeStr(value: integer): string;
begin
	if ( value < NOFAMRIGHTS ) or ( value > cHIGHFAMRIGHTS ) then
    	value := NOFAMRIGHTS;
   	result := FAMTypeStr[value];
end;

function StrToCROp(str: string): CROpType;
var
	o: CROpType;
begin
	for o:= crNOOP to crDROPADD do
    	if CompareText(CROpStr[o], str) = 0 then
        begin
        	result := o;
            exit;
        end;
    result := crERROR;
end;


function StrToRINTType(str: string): RINTType;
begin
	if CompareText(str, 'MASTER') = 0 then
    	result := rintMASTER
    else if CompareText(str, 'DEPENDENT') = 0 then
    	result := rintDEPENDENT
    else
    	result := RINTType(-1);
end;

function StrToRINTQual(str: string): RINTQual;
begin
	if CompareText(str, 'RESTRICT') = 0 then
    	result := rintRESTRICT
    else if CompareText(str, 'CASCADE') = 0 then
    	result := rintCASCADE
    else
    	result := RINTQual(-1);
end;


const
	hash_:			integer = 0;
	hashZSTRING:	integer = 0;
    hashDATE:       integer = 0;
    hashBLOB:		integer = 0;
    hashBOOL:		integer = 0;
    hashBOOLEAN:	integer = 0;
    hashINT32:		integer = 0;
    hashINT16:		integer = 0;
    hashFLOAT:		integer = 0;
    hashFLOAT64:	integer = 0;
    hashBCD:		integer = 0;
    hashBYTES:		integer = 0;
    hashTIME:		integer = 0;
    hashTIMESTAMP:	integer = 0;
    hashUINT16:		integer = 0;
    hashUINT32:		integer = 0;
    hashFLOATIEEE:	integer = 0;
    hashFLOAT80:	integer = 0;
    hashVARBYTES:	integer = 0;
    hashLOCKINFO:	integer = 0;
    hashMONEY:		integer = 0;
    hashBINARY:		integer = 0;
    hashMEMO:		integer = 0;
    hashFMTMEMO:	integer = 0;
    hashOLEOBJ:		integer = 0;
    hashDBSOLEOBJ:	integer = 0;
    hashGRAPHIC:	integer	= 0;
    hashTYPEDBINARY:integer = 0;
    hashPASSWORD:	integer = 0;
    hashAUTOINC:	integer = 0;

    hashNOOP:		integer = 0;
    hashADD:		integer = 0;
    hashCOPY:		integer = 0;
    hashMODIFY:		integer = 0;
    hashDROP:		integer = 0;
    hashREDO:		integer = 0;
    hashTABLE:		integer = 0;
    hashGROUP:		integer = 0;
    hashFAMILY:		integer = 0;
    hashDONE:		integer = 0;
    hashDROPADD:	integer = 0;

    hashMASTER:		integer = 0;
    hashDEPENDENT:	integer = 0;
    hashRESTRICT:	integer = 0;
    hashCASCADE:	integer = 0;

    hashNONE:		integer = 0;
	hashREADONLY:	integer = 0;
//    hashMODIFY:		integer = 0;
    hashINSERT:		integer = 0;
    hashINSDEL:		integer = 0;
    hashFULL:		integer = 0;
    hashUNKNOWN:	integer = 0;

	hashNOFAMRIGHTS:	integer = 0;
    hashFORMRIGHTS:		integer = 0;
    hashRPTRIGHTS:		integer = 0;
    hashVALRIGHTS:		integer = 0;
    hashSETRIGHTS:		integer = 0;
    hashALLFAMRIGHTS:	integer = 0;

    hashUSEDEF: 	integer = 0;
    hashCONTINUE:	integer = 0;
    hashABORT:		integer = 0;
    hashCHKINPUT:	integer = 0;
    hashYES:		integer = 0;
    hashNO:			integer = 0;
    hashPARTIALASSIST:	integer = 0;
    hashSKIP:		integer = 0;
    hashRETRY:		integer = 0;


function StrToCBRType(str: string): CBRType;
var
	hash: integer;
begin
	hash := TslcHash.Hash(pChar(UpperCase(str)));
    if hash = hashUSEDEF then			Result := cbrUSEDEF
    else if hash = hashCONTINUE then	Result := cbrCONTINUE
    else if hash = hashABORT then		Result := cbrABORT
    else if hash = hashCHKINPUT then	Result := cbrCHKINPUT
    else if hash = hashYES then			Result := cbrYES
    else if hash = hashNO then			Result := cbrNO
    else if hash = hashPARTIALASSIST then	Result := cbrPARTIALASSIST
    else if hash = hashSKIP then		Result := cbrSKIP
    else if hash = hashRETRY then		Result := cbrRETRY
    else Result := cbrERROR;
end;

function StrToFAMType(str: string): UINT16;
var
	hash: integer;
begin
	hash := TslcHash.Hash(pChar(UpperCase(str)));
//    if hash = hashNOFAMRIGHTS then		Result := NOFAMRIGHTS else
    if hash = hashFORMRIGHTS then 		Result := FORMRIGHTS
    else if hash = hashRPTRIGHTS then	Result := RPTRIGHTS
    else if hash = hashVALRIGHTS then	Result := VALRIGHTS
    else if hash = hashSETRIGHTS then 	Result := SETRIGHTS
    else if hash = hashALLFAMRIGHTS then Result := ALLFAMRIGHTS
    else Result := NOFAMRIGHTS;
end;

function StrToPRVType(str: string): PRVType;
var
	hash: integer;
begin
	hash := TslcHash.Hash(pChar(UpperCase(str)));
    if hash = hashNONE then				Result := prvNONE
    else if hash = hashREADONLY then    Result := prvREADONLY
    else if hash = hashMODIFY then		Result := prvMODIFY
    else if hash = hashINSERT then		Result := prvINSERT
    else if hash = hashINSDEL then		Result := prvINSDEL
    else if hash = hashFULL then		Result := prvFULL
    else 								Result := prvUNKNOWN;
end;

function StrToBDEField(const fType : string):UINT16;
var
    hash: integer;
begin

	hash := TslcHash.Hash(pChar(UpperCase(fType)));
	if hash = hashZSTRING then	 		Result := fldZSTRING        { Null terminated string }
	else if hash = hashDATE then		Result := fldDATE           { Date     (32 bit) }
	else if hash = hashBLOB	then		Result := fldBLOB           { Blob }
	else if hash = hashBOOL then		Result := fldBOOL           { Boolean  (16 bit) }
    else if hash = hashBOOLEAN then		Result := fldBOOL
    else if hash = hashINT16 then		Result := fldINT16          { 16 bit signed number }
	else if hash = hashINT32 then		Result := fldINT32          { 32 bit signed number }
	else if hash = hashFLOAT then		Result := fldFLOAT          { 64 bit floating point }
	else if hash = hashFLOAT64 then		Result := fldFLOAT			{ 64 bit floating point }
	else if hash = hashBCD then			Result := fldBCD           	{ BCD }
	else if hash = hashBYTES then		Result := fldBYTES          { Fixed number of bytes }
	else if hash = hashTIME then		Result := fldTIME			{ Time        (32 bit) }
	else if hash = hashTIMESTAMP then	Result := fldTIMESTAMP		{ Time-stamp  (64 bit) }
	else if hash = hashUINT16 then		Result := fldUINT16        	{ Unsigned 16 bit integer }
	else if hash = hashUINT32 then		Result := fldUINT32        	{ Unsigned 32 bit integer }
	else if hash = hashFLOATIEEE then	Result := fldFLOATIEEE		{ 80-bit IEEE float }
	else if hash = hashFLOAT80 then		Result := fldFLOATIEEE    	{ 80-bit IEEE float }
	else if hash = hashVARBYTES then	Result := fldVARBYTES		{ Length prefixed var bytes }
    else if hash = hashLOCKINFO then	Result := fldLOCKINFO

	else if hash = hashMONEY then		Result := fldstMONEY       { Money }

{ fldBLOB subtypes }

	else if hash = hashMEMO then		Result := fldstMEMO          { Text Memo }
	else if hash = hashBINARY then		Result := fldstBINARY      { Binary data }
	else if hash = hashFMTMEMO then		Result := fldstFMTMEMO    { Formatted Text }
	else if hash = hashOLEOBJ then		Result := fldstOLEOBJ      { OLE object (Paradox) }
	else if hash = hashGRAPHIC then		Result := fldstGRAPHIC    { Graphics object }
	else if hash = hashDBSOLEOBJ then	Result := fldstDBSOLEOBJ{ dBASE OLE object }
	else if hash = hashTYPEDBINARY then Result := fldstTYPEDBINARY   { Typed Binary data }

{ fldZSTRING subtype }

	else if hash = hashPASSWORD then	Result := fldstPASSWORD   { Password }

{ fldINT32 subtype }

	else if hash = hashAUTOINC then		Result := fldstAUTOINC
	else Result := fldUNKNOWN;
end;

// borrowed from ?samples.pas?
function FLDDescToStr(const FDesc : FLDDesc) : string;
var
	 FType, FSubtype, FUnits1, FUnits2, FLen: Word;
begin
	with FDesc do
	begin
		FType := iFldType;
		FSubType := iSubType;
		FUnits1 := iUnits1;
		FUnits2 := iUnits2;
		FLen := iLen;
	end;
			if FType < Low (BDEFldTypes)  then FType := Low (BDEFldTypes) else
			if FType > High (BDEFldTypes) then FType := Low (BDEFldTypes);

			if FSubtype < Low (BDESubtypes)  then FSubtype := 0 else
			if FSubtype > High (BDESubtypes) then FSubtype := 0;

			case FType of
				 fldDATE,
				 fldTIME,
				 fldTIMESTAMP,
				 fldBOOL,
				 fldINT16,
				 fldINT32,
				 fldUINT16,
				 fldUINT32,
				 fldLOCKINFO:
						begin
							Result := BDEFldTypes [FType];
							 if FSubtype > 0 then
									Result := Format ('%s:%s', [Result, BDESubtypes [FSubtype]]);
						end;

				 fldZSTRING,
				 fldBYTES,
				 fldVARBYTES:
						Result := Format ('%s(%d)', [BDEFldTypes [FType], FUnits1]);

				 fldFLOATIEEE,
				 fldFLOAT,
				 fldBCD,
				 fldBLOB:
						begin
							 Result := BDEFldTypes [FType];
							 if FSubtype > 0 then
									Result := Format ('%s:%s', [Result, BDESubTypes [FSubtype]]);
							 if (FUnits1 > 1) or (FUnits2 > 0) then
									Result := Format ('%s(%d,%d)', [Result, FUnits1, FUnits2])
						end;
			else
				 Result := Format ('%s(%d)', [BDEFldTypes [FType], FLen]);
			end
end;

function VCHKDescToStr(locale: pointer; pVChk : pDBIVCHK; fType : integer):string;
begin
	case fType of
		fldZSTRING: NativeToAnsi(locale, pChar(pVChk), result); //result := strpas(pChar(pVChk));
		fldUINT32,
		fldINT32 : result := inttostr(pInteger(pVChk)^);
        fldUINT16,
		fldINT16 : result := inttostr(pInteger(pVChk)^);
//		fldINT16 : result := inttostr(pSmallInt(pVChk)^);
		fldBOOL	 : result := BOOLTypeStr[pSmallInt(pVChk)^ <> 0]; // ??? Is sizeof(fldBOOL) == sizeof(Int16)
		fldFLOAT : result := floattostrf(pDouble(pVChk)^, ffGeneral, 15, 0);
	else Result := '?'; // ??? finish this function
	end;
end;

procedure StrToVCHK(locale: pointer; const val : string; pVChk : pDBIVCHK; fType : integer);
var
	l: longInt;
	i: integer;
    s: smallint;
	d: double;
    g: single;
    e: extended;
	dat: DbiDate;
    tim: Bde.Time;
begin
	try
		case fType of
			fldZSTRING:
            	begin
					AnsiToNative(locale, val, pChar(pVChk), DBIMAXVCHKLEN);
//                    l := length(val);
//                    if l > DBIMAXVCHKLEN then
//                    	l := DBIMAXVCHKLEN;
//                    Move(pChar(val)^, vChk, l + 1);
                end;
			fldUINT32,
			fldINT32 :
				begin
					l := strtoint(val);
					Move(l, pVChk^, sizeof(longInt));
				end;
            fldUINT16,
			fldINT16 :
				begin
					i := strtoint(val); // 16 or 32 ok for intel
					Move(i, pVChk^, sizeof(integer));
				end;
			fldFLOAT :
				begin
					d := strtofloat(val);
					Move(d, pVChk^, sizeof(double));
				end;
			fldBOOL :
				begin
					i := integer(pos(copy(val,1,1), 'NnFf0') = 0); // eh ???
					Move(i, pVChk^, sizeof(integer));
				end;
		else // incomplete...
        	raise EDBEngineError.create(DBIERR_INVALIDVCHKSTRUCT);
		end;
	except
		on Exception do raise EDBEngineError.create(DBIERR_INVALIDVCHKSTRUCT);
	end;
end;


function BdeDateToD2(d: DbiDate): TDateTime;
var
	day, mon: word;
    yr: smallInt;
begin
	Check(DbiDateDecode(d, mon, day, yr));
    result := EncodeDate(yr, mon, day);
end;

function BdeTimeToD2(t: Bde.Time): TDateTime;
var
	hr, min, mil: word;
begin
	Check(DbiTimeDecode(t, hr, min, mil));
    result := EncodeTime(hr, min, mil div 1000, mil mod 1000 )
end;

function BdeTimeStampToD2(ts: TimeStamp): TDateTime;
var
	d: DbiDate;
    t: Bde.Time;
begin
	Check(DbiTimeStampDecode(ts, d, t));
    result := BdeDateToD2(d) + BdeTimeToD2(t);
end;

function D2DateToBde(dt: TDateTime): DbiDate;
var
	yr, mon, day: word;
begin
	DecodeDate(dt, yr, mon, day);
    Check(DbiDateEncode(mon, day, yr, result));
end;

function D2TimeToBde(dt: TDateTime): Bde.Time;
var
	hr, min, sec, mil: word;
begin
	DecodeTime(dt, hr, min, sec, mil);
    Check(DbiTimeEncode(hr, min, sec * 1000 + mil, Result));
end;

function D2TimeStampToBde(dt: TDateTime): TimeStamp;
var
	d: DbiDate;
    t: Bde.Time;
begin
	d := D2DateToBde(dt);
    t := D2TimeToBde(dt);
    Check(DbiTimeStampEncode(d, t, result));
end;

const
	HashArray: pHashArray = nil; // for hash values in this module only.

	cCountHashValues = 66;
    _HashCount_: integer = cCountHashValues;

	cHashValues: array[0..cCountHashValues, 0..1] of pChar = (
    (@_HashCount_, 		''),	// not counted. Used to store array size. See HashCount()
    (@hash_, 			''),
	(@hashZSTRING,		'ZSTRING'),
    (@hashDATE,			'DATE'),
    (@hashBLOB,			'BLOB'),
    (@hashBOOL,			'BOOL'),
    (@hashBOOLEAN,		'BOOLEAN'),
    (@hashINT32,		'INT32'),
    (@hashINT16,		'INT16'),
    (@hashFLOAT,		'FLOAT'),
    (@hashFLOAT64,		'FLOAT64'),
    (@hashBCD,			'BCD'),
    (@hashBYTES,		'BYTES'),
    (@hashTIME,			'TIME'),
    (@hashTIMESTAMP,	'TIMESTAMP'),
    (@hashUINT16,		'UINT16'),
    (@hashUINT32,		'UINT32'),
    (@hashFLOATIEEE,  	'FLOATIEEE'),
    (@hashFLOAT80,		'FLOAT80'),
    (@hashVARBYTES,		'VARBYTES'),
    (@hashLOCKINFO,		'LOCKINFO'),
    (@hashMONEY,		'MONEY'),
    (@hashBINARY,		'BINARY'),
    (@hashMEMO,			'MEMO'),
    (@hashFMTMEMO,		'FMTMEMO'),
    (@hashOLEOBJ,		'OLEOBJ'),
    (@hashDBSOLEOBJ,	'DBSOLEOBJ'),
    (@hashGRAPHIC,		'GRAPHIC'),
    (@hashTYPEDBINARY,	'TYPEDBINARY'),
    (@hashPASSWORD,		'PASSWORD'),
    (@hashAUTOINC,		'AUTOINC'),
    (@hashNOOP,			'NOOP'),
    (@hashADD,			'ADD'),
    (@hashCOPY,			'COPY'),
    (@hashMODIFY,		'MODIFY'),
    (@hashDROP,			'DROP'),
    (@hashREDO,			'REDO'),
    (@hashTABLE,		'TABLE'),
    (@hashGROUP,		'GROUP'),
    (@hashFAMILY,		'FAMILY'),
    (@hashDONE,			'DONE'),
    (@hashDROPADD,		'DROPADD'),
    (@hashMASTER,		'MASTER'),
    (@hashDEPENDENT,	'DEPENDENT'),
    (@hashRESTRICT,		'RESTRICT'),
    (@hashCASCADE,		'CASCADE'),
    (@hashNONE,			'NONE'),
    (@hashREADONLY,		'READONLY'),
    (@hashINSERT,		'INSERT'),
    (@hashINSDEL,		'INSDEL'),
    (@hashFULL,			'FULL'),
    (@hashUNKNOWN,		'UNKNOWN'),
    (@hashNOFAMRIGHTS, 	'NOFAMRIGHTS'),
    (@hashFORMRIGHTS,  	'FORMRIGHTS'),
    (@hashRPTRIGHTS,   	'RPTRIGHTS'),
    (@hashVALRIGHTS,   	'VALRIGHTS'),
    (@hashSETRIGHTS,   	'SETRIGHTS'),
    (@hashALLFAMRIGHTS,	'ALLFAMRIGHTS'),
    (@hashUSEDEF,		'USEDEF'),
    (@hashCONTINUE,		'CONTINUE'),
    (@hashABORT,		'ABORT'),
    (@hashCHKINPUT,		'CHKINPUT'),
    (@hashYES,			'YES'),
    (@hashNO,			'NO'),
    (@hashPARTIALASSIST,'PARTIALASSIST'),
    (@hashSKIP,			'SKIP'),
    (@hashRETRY,		'RETRY'));

initialization

	InitializeHashValues(HashArray, pHashArray(@cHashValues), True);

//////////////////////////////////////////////////////////////////////////
//  Uncomment next line to check for any hash collisions
//	CheckHashCollisions(HashArray);

end.

