Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1636 lines
37 KiB

/*****************************************************************************/
/** Microsoft LAN Manager **/
/** Copyright(c) Microsoft Corp., 1987-1990 **/
/*****************************************************************************/
/*****************************************************************************
File : attrnode.cxx
Title : attribute node routines
History :
04-Aug-1991 VibhasC Created
*****************************************************************************/
/****************************************************************************
local defines and includes
****************************************************************************/
#include "nulldefs.h"
extern "C"
{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
}
#include "nodeskl.hxx"
#include "miscnode.hxx"
#include "compnode.hxx"
#include "ptrarray.hxx"
#include "basetype.hxx"
#include "attrnode.hxx"
#include "newexpr.hxx"
#include "ctxt.hxx"
#include "baduse.hxx"
#include "cmdana.hxx"
#include "buffer.hxx"
#include "procnode.hxx"
#include "pickle.hxx"
extern PickleManager * pPicControlBlock;
#define W_CHAR_T_STRLEN_NAME ("MIDL_wchar_strlen")
#define CHAR_STRLEN_NAME ("MIDL_ascii_strlen")
typedef struct _endptpair
{
char * pString1;
char * pString2;
} ENDPT_PAIR;
/****************************************************************************
external data
****************************************************************************/
extern CTXTMGR * pGlobalContext;
extern CMD_ARG * pCommand;
extern SymTable * pBaseSymTbl;
/****************************************************************************
external procedures
****************************************************************************/
extern void CheckSizeAndLengthTypeMismatch( node_skl *);
extern void ParseError( STATUS_T, char *);
extern int HexCheck(char *);
extern void SetLocalAllocState( node_state );
extern BOOL IsIntegralType( ETYPE );
extern node_skl * pBaseImplicitHandle;
/****************************************************************************/
/****************************************************************************
node_base_attr:
the constructor
****************************************************************************/
node_base_attr::node_base_attr(
ATTR_T A )
{
AttrID = A;
pSymName = GetNodeNameString();
}
char *
node_base_attr::GetNodeNameString()
{
char * AttrNodeNameArray[] =
{
"[none]"
,"[ptr (internal)]" /* attr_temp_ptr */
,"[unique (internal)]" /* attr_temp_unique */
,"[ref (internal)]" /* attr_temp_ref */
,"[ptr]"
,"[unique]"
,"[ref]"
,"[string]"
,"[v1_string]"
,"[bstring]"
,"[uuid]"
,"[version]"
,"[endpoint]"
,"[local]"
,"[object]"
,"[transmit]"
,"[handle]"
,"[align]"
,"[unaligned]"
,"[switch_type]"
,"[represent_as]"
,"[first_is]"
,"[iid_is]"
,"[last_is]"
,"[length_is]"
,"[min_is]"
,"[max_is]"
,"[size_is]"
,"[v1_array]"
,"[switch_is]"
,"[ignore]"
,"[internal_size]"
,"[internal_min]"
,"[internal_max]"
,"[internal_first]"
,"[internal_last]"
,"[internal_length]"
,"[internal_implicit]"
,"[idempotent]"
,"[broadcast]"
,"[maybe]"
,"[byte_count]"
,"[callback]"
,"[datagram]"
,"[no_listen]"
,"[no_nocode]"
,"[in]"
,"[out]"
,"[shape]"
,"[unsigned]"
,"[signed]"
,"[case]"
,"[default]"
,"[context_handle]"
,"[code]"
,"[nocode]"
,"[in_line]"
,"[out_of_line]"
,"[interpret]"
,"[nointerpret]"
,"[encode]"
,"[decode]"
,"[offline]"
,"[comm_status]"
,"[fault_status]"
,"[manual]"
,"[allocate]"
,"[heap]"
,"[implicit_handle]"
,"[explicit_handle]"
,"[auto_handle]"
,"[ptrsize]"
,"[callquota]"
,"[callbackquota]"
,"[clientquota]"
,"[serverquota]"
,"[notify]"
,"[short_enum]"
,"[long_enum]"
,"[enable_allocate]"
,"[usr_marshall]"
,"extern"
,"static"
,"automatic"
,"register"
,"far"
,"far16"
,"near"
,"__unaligned"
,"huge"
,"pascal"
,"fortran"
,"cdecl"
,"stdcall"
,"loadds"
,"saveregs"
,"fastcall"
,"segment"
,"interrupt"
,"self"
,"export"
,"const"
,"volatile"
,"base"
,"pcode_native"
,"pcode_csconst"
,"pcode_sys"
,"pcode_nsys"
,"pcode_uop"
,"pcode_nuop"
,"pcode_tlbx"
,"const" /* proc const */
,"_inline"
};
int At = (int) GetAttrID();
assert ( At < sizeof(AttrNodeNameArray)/sizeof(char *) );
return AttrNodeNameArray[ (int) At ];
}
/****************************************************************************
IsAttrID:
return true if the attribute id matches the given one
****************************************************************************/
BOOL
node_base_attr::IsAttrID(
ATTR_T A )
{
return (BOOL) (AttrID == A );
}
/****************************************************************************
size related attributes
sa:
the contructor
****************************************************************************/
sa::sa(
class expr_node * pE,
ATTR_T A ) : nbattr( A )
{
pExpr = pE;
}
node_state
sa::SCheck()
{
node_state NState = NODE_STATE_OK;
node_skl * pParent = pGlobalContext->GetCurrentNode();
node_skl * pParamNode = pGlobalContext->GetLastContext(C_PARAM);
char * pName = GetNodeNameString();
ATTR_T AttrID = GetAttrID();
BOOL fSizeAttribute = ( AttrID == ATTR_SIZE ||
AttrID == ATTR_MAX ||
AttrID == ATTR_MIN );
BOOL fLengthAttribute= ( AttrID == ATTR_FIRST ||
AttrID == ATTR_LAST ||
AttrID == ATTR_LENGTH );
BOOL fLengthAttrMustBeIn;
// if the length attr is applied on a param, then the param must be an
// in param.
fLengthAttrMustBeIn = (pParamNode && pParamNode->FInSummary( ATTR_IN ));
/**
** the size attributes cannot be on an array of fixed size.
**/
if( fSizeAttribute )
{
if( pParent->IsFixedSizedArray() )
ParseError( INAPPLICABLE_ATTRIBUTE, pName );
}
if( fLengthAttribute )
{
pParent->SetNodeState( NODE_STATE_VARYING_ARRAY );
}
/**
** the expressions must be of integral type
**/
pExpr->SCheck( pGlobalContext->GetCurrentSymbolTable() );
if( !pExpr->IsResolved() )
{
ParseError( ATTRIBUTE_ID_UNRESOLVED, pName );
}
else if( !pExpr->IsExprInt() )
{
ParseError( ATTR_MUST_BE_INT, pName );
}
else
{
//
// it is resolved and it is int.! Check for the expression to be
// either a variable or a pointer. Nothing else is allowed in
// osf mode.
//
BOOL fExprIsNOTAPureVariable = !pExpr->IsAPureVariable();
BOOL fExprIsNOTAPurePointer = !pExpr->IsAPointerExpr();
BOOL fExprHasOutOnlyParam = pExpr->ExprHasOutOnlyParam();
BOOL fExprDerivesFromUniqueOrFull = pExpr->DerivesUniqueFull();
if( fExprIsNOTAPureVariable && fExprIsNOTAPurePointer )
{
ParseError( ATTRIBUTE_ID_MUST_BE_VAR, pName );
}
if( fExprHasOutOnlyParam )
{
if( fSizeAttribute )
ParseError( SIZE_SPECIFIER_CANT_BE_OUT, pName );
if( fLengthAttribute && fLengthAttrMustBeIn )
ParseError( LENGTH_SPECIFIER_CANT_BE_OUT, pName );
}
//
// the expression must not derive from a unique or a full pointer,
// because of the possibility of the pointer being null. However, this
// must not be reported as an error, since the user may specify a unique
// pointer, but in his app, may always use a valid pointer. At best this
// is a warning.
if( fExprDerivesFromUniqueOrFull )
{
ParseError( SIZE_LENGTH_SW_UNIQUE_OR_FULL, pName );
}
//
// if it is a constant expression, just send an evaluate message
// in order to verify that he did not do things like divide by zero.
//
if( pExpr->IsConstant() )
pExpr->Evaluate();
}
/*********************************************************
** hack for node-state-size and length
*********************************************************
if( fSizeAttribute )
SetLocalAllocState( NODE_STATE_SIZE );
else
SetLocalAllocState( NODE_STATE_LENGTH );
***************** end of hack ***************************/
if( fSizeAttribute )
NState |= NODE_STATE_SIZE;
else
NState |= NODE_STATE_LENGTH;
return NState;
}
node_size_is::node_size_is(
class expr_node * pE ) : sa( pE, ATTR_SIZE )
{
}
node_state
node_size_is::SCheck()
{
node_state NState = sa::SCheck();
return NState;
}
node_int_size_is::node_int_size_is(
class expr_node * pE ) : sa( pE, ATTR_INT_SIZE )
{
}
node_min_is::node_min_is(
class expr_node * pE) : sa( pE, ATTR_MIN )
{
}
node_max_is::node_max_is(
class expr_node * pE ) : sa( pE, ATTR_MAX )
{
}
node_state
node_max_is::SCheck()
{
node_state NState = sa::SCheck();
return NState;
}
node_length_is::node_length_is(
class expr_node * pE ) : sa( pE, ATTR_LENGTH )
{
}
node_state
node_length_is::SCheck()
{
node_state NState = sa::SCheck();
return NState; // | NODE_STATE_VARYING_ARRAY;
}
node_int_length_is::node_int_length_is(
class expr_node * pE ) : sa( pE, ATTR_INT_LENGTH )
{
}
node_first_is::node_first_is(
class expr_node * pE ) : sa( pE, ATTR_FIRST )
{
}
node_state
node_first_is::SCheck()
{
node_state NState = sa::SCheck();
return NState; // | NODE_STATE_VARYING_ARRAY;
}
node_iid_is::node_iid_is(
class expr_node * pE ) : sa( pE, ATTR_IID )
{
}
node_state
node_iid_is::SCheck()
{
node_state NState = NODE_STATE_OK;
return NState;
}
node_last_is::node_last_is(
class expr_node * pE ) : sa( pE, ATTR_LAST )
{
}
node_state
node_last_is::SCheck()
{
node_state NState = sa::SCheck();
return NState; // | NODE_STATE_VARYING_ARRAY;
}
/****************************************************************************
type based attributes
****************************************************************************/
ta::ta(
node_skl * pT,
ATTR_T A ) : nbattr( A )
{
pType = pT;
}
node_transmit::node_transmit(
node_skl * pTransmitAs ) : ta( pTransmitAs, ATTR_TRANSMIT )
{
}
node_state
node_transmit::SCheck()
{
/**
** . The transmitted type cannot be a context handle.
** . The transmitted type cannot be a pointer or contain a pointer
** . The transmitted type cannot be non-rpcable (derive from int or void)
**/
node_state NState = NODE_STATE_TRANSMIT_AS;
node_skl * pNode = GetType();
BadUseInfo BU;
pNode->SCheck( &BU );
if( pNode->GetNodeState() & NODE_STATE_CONTEXT_HANDLE )
ParseError( TRANSMIT_AS_CTXT_HANDLE , (char *)NULL );
if( pNode->GetNodeState() & NODE_STATE_POINTER )
ParseError( TRANSMIT_AS_POINTER, (char *)NULL );
if( TRULY_NON_RPCABLE( (&BU) ) ||
BU.NonRPCAbleBecause( NR_PRIMITIVE_HANDLE ) ||
BU.NonRPCAbleBecause( NR_PTR_TO_PRIMITIVE_HANDLE )
)
ParseError( TRANSMIT_AS_NON_RPCABLE, (char *)NULL );
if( BU.BadConstructBecause( BC_DERIVES_FROM_E_STAT_T ) )
ParseError( TRANSMIT_AS_ON_E_STAT_T , (char *)0 );
if( BU.BadConstructBecause( BC_DERIVES_FROM_UNSIZED_ARRAY ) )
ParseError( UNSIZED_ARRAY, pNode->GetSymName() );
if( pNode->NeedsUseProcessing() )
NState |= NODE_STATE_NEEDS_USE_PROCESSING;
if( (pNode->GetNodeState() & NODE_STATE_CONF_ARRAY )
== NODE_STATE_CONF_ARRAY)
NState |= NODE_STATE_CONF_ARRAY;
return NState;
}
node_switch_type::node_switch_type(
node_skl * pSwitchType) : ta( pSwitchType, ATTR_SWITCH_TYPE )
{
}
node_state
node_switch_type::SCheck()
{
node_skl * pUnion = pGlobalContext->GetLastContext( C_COMP );
node_skl * pNode;
NODE_T NT;
/**
** We need not check if the last context was a union, because it WILL be.
** The switch_type could not have been applied otherwise and we would
** not have got this message at all.
** If the union to which this is applied is a non-rpc union, then
** this attribute is not applicable
**/
if( pUnion->IsNonRPCAble() )
ParseError( BAD_ATTR_NON_RPC_UNION, GetNodeNameString() );
//
// check if the switch type is of the proper type.
//
if( (pNode = GetSwitchType())->NodeKind() == NODE_DEF )
pNode = pNode->GetBasicType();
NT = pNode->NodeKind();
if( !IsIntegralType(pNode) &&
(NT != NODE_BOOLEAN) &&
// (NT != NODE_BYTE) &&
(NT != NODE_WCHAR_T) &&
(NT != NODE_CHAR) )
{
ParseError( SWITCH_TYPE_TYPE_BAD, (char *)0 );
}
/**
** The union to which this was applied, needs use processing to ensure
** that the switch_type matches the switch_is
**/
return NODE_STATE_NEEDS_USE_PROCESSING;
}
node_represent::node_represent(
node_skl * pRepresentAs ) : ta( pRepresentAs, ATTR_REPRESENT_AS )
{
}
/****************************************************************************
miscellaneous attributes
****************************************************************************/
node_string::node_string() : sa( (expr_node * )NULL, ATTR_STRING )
{
}
node_string::node_string( ATTR_T A ) : sa( (expr_node *)0, A )
{
}
node_base_attr *
node_string::Clone()
{
return new node_string();
}
node_state
node_string::SCheck()
{
node_skl * pParent = pGlobalContext->GetCurrentNode();
node_state NState = NODE_STATE_OK;
BOOL fParentHasAnySizeAttr = pParent->HasAnySizeAttributes();
node_skl * pFType;
NODE_T NT;
/**
** The string attribute can only be applied to a node whose fundamental
** type is byte or char or wchar_t. Note that we do not support
** stringable structs yet, we must report an explicit error message on
** that.
**/
NT = (pFType = pParent->GetFundamentalType())->NodeKind();
if(!( (NT == NODE_WCHAR_T) || (NT == NODE_CHAR) || (NT == NODE_BYTE) ) )
{
if( ( NT == NODE_STRUCT ) &&
((node_struct *)pFType)->IsStringableStruct() )
ParseError( STRINGABLE_STRUCT_NOT_SUPPORTED, (char *)0 );
else
ParseError( STRING_NOT_ON_BYTE_CHAR, (char *)NULL );
}
/**
** string attributes cannot be applied to a type which already has
** some transmission attribute
**/
if( pParent->HasAnyLengthAttributes() )
ParseError( INVALID_SIZE_ATTR_ON_STRING, (char *)NULL );
/**
** The backend wants to get a node-state-varying array if there is
** it is an array of fixed size or has any size attributes and a string
** attribute on it.
**/
if( pParent->FInSummary( ATTR_SIZE ) ||
pParent->FInSummary( ATTR_MAX ) ||
( (pParent->NodeKind() == NODE_ARRAY ) &&
pParent->FInSummary( ATTR_INT_SIZE )
)
)
NState |= NODE_STATE_VARYING_ARRAY;
/**
** We want that when the string attribute is present, the string length
** expression be set up by the user, field/param node. so we set the
** node state to indicate a use processing needed
**/
/*********************************************************
** hack for node-state-size and length
*********************************************************
SetLocalAllocState( NODE_STATE_SIZE | NODE_STATE_LENGTH );
**************** end of hack ***************************/
NState |= NODE_STATE_LENGTH;
if( !fParentHasAnySizeAttr )
NState |= NODE_STATE_SIZE;
return (NState | NODE_STATE_NEEDS_USE_PROCESSING);
}
void
node_string::UseProcessingAction()
{
char * pFunctionName;
char * pName;
expr_node * pExprSoFar;
node_skl * pNode,
* pTempNode,
* pTempNode1;
unsigned short EffectiveIndLevel;
NODE_T FundamentalKind;
EnCtxt ContextCode;
/**
** Get the ind level of the last context
**/
if( pNode = pGlobalContext->GetLastContext( C_FIELD ) )
ContextCode = C_FIELD;
else if( pNode = pGlobalContext->GetLastContext( C_PARAM ) )
ContextCode = C_PARAM;
else if( pNode = pGlobalContext->GetLastContext( C_PROC ) )
ContextCode = C_PROC;
else
ContextCode = C_DONTKNOW;
assert( ContextCode != C_DONTKNOW );
if( ContextCode == C_PROC )
pName = RET_VAL;
else
pName = pNode->GetSymName();
EffectiveIndLevel =
pGlobalContext->GetCurrentIndirectionLevel() -
pGlobalContext->GetIndLevelOfLastContext( ContextCode );
/**
** now generate the string expression for the back end. If the param was
** specified like [string] char *p, then the expression generated is
** strlen( p ). If it is [string] char **p, then the expression is
** strlen( *p ) and so on.
**/
pNode = pGlobalContext->GetLastContext( ContextCode );
pExprSoFar = new expr_variable(pName,pNode->GetBasicType());
/**
** Create pointer expressions for one less than the number of pointers
** between the param / field node and the node on which the string was
** applied.
**/
if( EffectiveIndLevel > 1 )
{
while( --EffectiveIndLevel )
pExprSoFar = new expr_op_unary( OP_UNARY_INDIRECTION, pExprSoFar);
}
/**
** we have the pointer expression with us. Set up the expression fully
** with function name as strlen / wchar_strlen etc
**/
FundamentalKind = pNode->GetFundamentalType()->NodeKind();
//
// The backend wants a cast in the parameter expression for strlen to be
// output as const char *. Create a cast type for this.
//
if( FundamentalKind == NODE_WCHAR_T )
{
pTempNode1 = new node_wchar_t;
// pTempNode1->SetAttribute( ATTR_CONST );
}
else
{
pTempNode1 = new node_base_type( NODE_CHAR, ATTR_CONST );
pTempNode1->SetSymName( "char" );
}
if ( pPicControlBlock && pPicControlBlock->GetUseProcessing() )
pTempNode = new node_pointer( ATTR_REF );
else
pTempNode = new node_pointer;
pTempNode->SetAttribute( ATTR_RPC_FAR );
pTempNode->SetBasicType( pTempNode1 );
//
// now create a cast expression.
//
pExprSoFar = new expr_cast(pTempNode, pExprSoFar );
pFunctionName = ( FundamentalKind == NODE_WCHAR_T ) ?
W_CHAR_T_STRLEN_NAME :
CHAR_STRLEN_NAME;
pExprSoFar = new expr_fn_param( pExprSoFar );
pExprSoFar = new expr_fn( pExprSoFar, pFunctionName );
if ( pPicControlBlock && pPicControlBlock->GetUseProcessing() )
{
//.. When pickling, essentially a strlen(PICKLE_OBJECT_NAME)
//.. is generated. So, skip checking if the PICKLE_OBJECT_NAME
//.. is defined. This may be part of pExprSoFar being checked
//.. here only when a the object type has [string] on it.
}
else
pExprSoFar->Resolve( pGlobalContext->GetCurrentSymbolTable() );
SetExpr( pExprSoFar );
//
// This is a bug with expression. If string is applied to a parameter,
// then the expression evaluator treats it as if it is used in expression
// and the backend goofs. There is no easy way to tell the expression
// evaluator that this should not be done in case string is applied
// on a param/field. So, we patch this by resetting this node state.
//
pNode->ResetNodeState( NODE_STATE_USED_IN_EXPRESSION );
#ifdef RPCDEBUG
printf("\n**********************************************************\n");
BufferManager * pOutput = new BufferManager( 10 );
pExprSoFar->PrintExpr( (BufferManager *)NULL, (BufferManager *)NULL, pOutput );
pOutput->Print( stdout );
printf("\n**********************************************************\n");
#endif // RPCDEBUG
}
node_base_attr *
node_bstring::Clone()
{
return new node_bstring();
}
node_guid::node_guid(
char * pIn ) : ma( ATTR_GUID )
{
char * p1 = pIn,
* p2 = (p1) ? (strchr( p1+1 , '-')) : 0,
* p3 = (p2) ? (strchr( p2+1 , '-')) : 0,
* p4 = (p3) ? (strchr( p3+1 , '-')) : 0,
* p5 = (p4) ? (strchr( p4+1 , '-')) : 0;
if( p1 && p2 && p3 && p4 && p5 )
{
*p2++ = *p3++ = *p4++ = *p5++ = '\0';
CheckAndSetGuid( p1, p2, p3, p4, p5 );
}
else
ParseError( UUID_FORMAT, (char *)0 );
}
node_guid::node_guid (
char * pStr1,
char * pStr2,
char * pStr3,
char * pStr4,
char * pStr5 ) : ma( ATTR_GUID )
{
CheckAndSetGuid( pStr1, pStr2, pStr3, pStr4, pStr5 );
}
void
node_guid::CheckAndSetGuid(
char * pStr1,
char * pStr2,
char * pStr3,
char * pStr4,
char * pStr5 )
{
int Len1 = strlen(str1 = pStr1);
int Len2 = strlen(str2 = pStr2);
int Len3 = strlen(str3 = pStr3);
int Len4 = strlen(str4 = pStr4);
int Len5 = strlen(str5 = pStr5);
if( (Len1 == 8) && (HexCheck(str1)) &&
(Len2 == 4) && (HexCheck(str1)) &&
(Len3 == 4) && (HexCheck(str1)) &&
(Len4 == 4) && (HexCheck(str1)) &&
(Len5 == 12) && (HexCheck(str1)) )
{
if( !HexCheck(str1) ||
!HexCheck(str2) ||
!HexCheck(str3) ||
!HexCheck(str4) ||
!HexCheck(str5) )
{
ParseError(UUID_NOT_HEX, (char *)NULL);
}
else
{
guidstr = new char[ Len1 + Len2 + Len3 + Len4 + Len5 + 5 ];
strcpy(guidstr, str1);
strcat(guidstr, "-");
strcat(guidstr, str2);
strcat(guidstr, "-");
strcat(guidstr, str3);
strcat(guidstr, "-");
strcat(guidstr, str4);
strcat(guidstr, "-");
strcat(guidstr, str5);
}
}
else
{
ParseError(UUID_FORMAT, (char *)NULL);
}
}
node_version::node_version(
unsigned long vMajor,
unsigned long vMinor ) : nbattr( ATTR_VERSION )
{
major = vMajor;
minor = vMinor;
if( (major > 0x0000ffff ) || (minor > 0x0000ffff))
ParseError( VERSION_FORMAT, (char *)0);
}
node_version::node_version(
char * pV ) : nbattr(ATTR_VERSION)
{
char * pMinor;
char * pMajor = pV;
BOOL fError = TRUE;
major = minor = 0;
if( pMajor && *pMajor )
{
if( pMinor = strchr( pMajor, '.' ) )
{
fError = TRUE;
if( *(++pMinor) )
{
minor = strtoul( pMinor, &pMinor, 10 );
if( ! *pMinor )
fError = FALSE;
}
}
else
fError = FALSE;
if( fError == FALSE )
{
//use pMinor to save pMajor value;
major = strtoul( pMinor = pMajor, &pMajor, 10 );
if( (*pMajor && (*pMajor != '.' )) || (pMajor == pMinor) )
fError = TRUE;
}
}
if( (fError == TRUE ) ||
(major > (unsigned long )0x0000ffff) ||
(minor > (unsigned long )0x0000ffff)
)
{
ParseError( VERSION_FORMAT, (char *)0 );
}
}
STATUS_T
node_version::GetVersion(
unsigned short *pMajor,
unsigned short *pMinor )
{
*pMajor = (unsigned short) major;
*pMinor = (unsigned short) minor;
return STATUS_OK;
}
node_endpoint::node_endpoint(
char * pEndPointString ) : nbattr( ATTR_ENDPOINT )
{
pEndPointStringList = new gplistmgr;
SetEndPointString( pEndPointString );
}
void
node_endpoint::SetEndPointString(
char * pString )
{
ENDPT_PAIR * pEntry = new ENDPT_PAIR;
char * p1 = pString;
char * p2;
char * pTemp;
short Len;
STATUS_T Status = ENDPOINT_SYNTAX;
//
// Parse the string. Note that we can assume that the string is at least
// a null string, because it came from the parser. If it wasnt a string,
// the parser would have barfed anyhow.
//
// Firstly, the string must have a ':' separator. Also, it must have
// at least 1 character before the :.
//
if( pString &&
(pTemp = strchr( pString , ':' ) ) &&
((pTemp - pString) > 0) )
{
//
// pick up the first part of the string.
//
Len = pTemp - pString;
p1 = new char [ Len + 1 ]; // one for null.
strncpy( p1, pString, Len );
p1[ Len ] = '\0';
//
// pick up the last part of the string. Skip beyond the :. There can be
// some characters after the : and before the '['. This is the server
// name. Then follows the port within the []. The actual string will
// not have the [].
//
// skip the :
pTemp += 1;
// find out the total length of the string. Allocate 2 less than that
// 'cause we dont need the '[' and ']'. The string must be more than
// 2 characters 'cause it must have the brackets anyhow.
Len = strlen( pTemp );
if( (Len > 2 ) &&
(strchr( pTemp, '[' )) &&
(pTemp[ Len - 1] == ']'))
{
char *p2Cur;
while( *pTemp != '[' )
{
pTemp++;
Len--;
}
//
// in the second half of the parse, just get the whole string till
// the null. Now the user could be perverted, he could have a
// ] embedded within the string, in addition to the last ]. To
// ensure that he gets what he deserves, transfer till the end
// except the last character which must be ']'.
pTemp++; Len--;
p2Cur = p2 = new char[ Len ]; // Yes, not Len + 1 'cause we are
// going to re-use the last char
// which is ] for the null.
strncpy( p2Cur, pTemp, --Len );
p2Cur[ Len ] = '\0';
Status = STATUS_OK;
}
else
{
delete p1;
}
}
if( Status != STATUS_OK )
{
ParseError( Status, pString );
p1 = p2 = 0;
}
//
// set up the pair.
//
pEntry->pString1 = p1;
pEntry->pString2 = p2;
pEndPointStringList->Insert( pEntry );
#if 0
GetEndPointString( &p1, &p2 );
fprintf( stderr, "Endpoint is %s: %s\n", p1 ? p1 : "" , p2 ? p2 : "" );
#endif // 0
}
#if 0 //////////////////////////////// old implementations ///////////////////
void
node_endpoint::SetEndPointString(
char * pString )
{
ENDPT_PAIR * pEntry = new ENDPT_PAIR;
char * p1 = pString;
char * p2;
char * pTemp;
short Len;
STATUS_T Status = ENDPOINT_SYNTAX;
//
// Parse the string. Note that we can assume that the string is at least
// a null string, because it came from the parser. If it wasnt a string,
// the parser would have barfed anyhow.
//
// Firstly, the string must have a ':' separator.
//
if( pString && (pTemp = strchr( pString , ':' ) ) && (*(pTemp+1) == '[' ) )
{
//
// pick up the first part of the string.
//
Len = pTemp - pString;
p1 = new char [ Len + 1 ]; // one for null.
strncpy( p1, pString, Len );
p1[ Len ] = '\0';
//
// pick up the last part of the string. Skip beyond the : and [. We know
// that he did have a : and a [, because thats why we came into this
// block. So skipping by 2 is safe. The worst case is when he does not
// have anything beyond the :[. The strlen below will catch it properly.
//
pTemp += 2;
Len = strlen( pTemp );
//
// the last character MUST be a ].
//
if( (Len > 1) && (pTemp[ --Len ] == ']' ))
{
p2 = new char [ Len + 1 ];
strncpy( p2, pTemp, Len );
p2[ Len ] = '\0';
Status = STATUS_OK;
}
else
delete p1;
}
if( Status != STATUS_OK )
{
ParseError( Status, pString );
p1 = p2 = 0;
}
//
// set up the pair.
//
pEntry->pString1 = p1;
pEntry->pString2 = p2;
pEndPointStringList->Insert( pEntry );
#if 0
GetEndPointString( &p1, &p2 );
fprintf( stderr, "Endpoint is %s: %s\n", p1 ? p1 : "" , p2 ? p2 : "" );
#endif // 0
}
void
node_endpoint::SetEndPointString(
char * pString )
{
int cCount = 0;
char *pStr = pString;
char *pDest;
char *pStrSave, *pDestSave;
pStrSave = pString;
while(pStrSave = strchr(pStrSave,'\\'))
{
cCount++;
pStrSave++;
}
// we pre-allocate the final string up front.
// the 3 extra characters are for a possible "\\" to be added
// for name. Otherwise it is a waste all right, but this makes it
// easier to handle.
// syntax analyse the endpoint string
// the format should be FAMILY_STRING ':' '[' ENDPOINT_STRING ']'
// where family string is just an id
pDestSave = pDest = new char[ strlen(pString) + cCount + 1 ];
// ignore any lead white space
while(isspace(*pStr)) pStr++;
// skip the family string, but check for length to be at least one
while( isalpha(*pStr) || (*pStr == '_' ) ) pStr++;
if(pStr - pString )
{
// family string is ok, must see a colon
if(*pStr++ == ':')
{
if(*pStr++ == '[')
{
// now the imp part. the string has to have a valid file
// name. the name called "pipe" is a little different, it
// must have the syntax \\pipe\foo. all other strings are
// passed unchecked
pStrSave = pStr;
while( (*pStr) && (*pStr != ']') ) pStr++;
if(*pStr++ == ']')
{
int len;
strncpy(pDest, pString, (len = pStrSave-pString));
pDest += len;
#if 0
if(strncmp(pStrSave, "\\\\pipe", 6) == 0)
{
strcpy(pDest,"\\\\\\\\pipe");
pDest += 8;
pStrSave += 6;
}
#endif // 0
while(pStrSave < pStr)
{
if(*pStrSave == '\\') *pDest++ = '\\';
*pDest++ = *pStrSave++;
}
while(*pStr) *pDest++ = *pStr++;
*pDest = '\0';
pEndPointStringList->Insert( pDestSave );
return;
}
}
}
}
ParseError(ENDPOINT_SYNTAX, (char *)NULL );
}
#endif // 0///////// end of old implementations ////////////////////////////
STATUS_T
node_endpoint::GetEndPointString(
char ** pDestination )
{
ENDPT_PAIR * p;
STATUS_T Status = pEndPointStringList->GetNext( (void **)&p );
if( Status == STATUS_OK )
{
*pDestination = p->pString1;
}
return Status;
}
STATUS_T
node_endpoint::GetEndPointString(
char ** pDest1,
char ** pDest2 )
{
ENDPT_PAIR * p;
STATUS_T Status = pEndPointStringList->GetNext( (void **)&p );
if( Status == STATUS_OK )
{
*pDest1 = p->pString1;
*pDest2 = p->pString2;
}
return Status;
}
node_switch_is::node_switch_is(
expr_node * pE ) : nbattr( ATTR_SWITCH_IS )
{
pExpr = pE;
}
node_state
node_switch_is::SCheck()
{
node_skl * pUse,
* pBSaved,
* pBasicTypeOfUseNode;
NODE_T BasicNodeKind = NODE_ILLEGAL;
char * pName = GetNodeNameString();
BOOL fOk = FALSE;
if( !(pUse = pGlobalContext->GetLastContext( C_FIELD ) ) )
pUse = pGlobalContext->GetLastContext( C_PARAM );
assert( pUse != NULL );
/**
** we just have to ensure that the switch_is is applied only to a
** field which as a union underneath. This means we must look past
** pointers too. For type like structs/unions, get basictype returns
** this, so we must guard against infinite loop by ensuring that if
** getbasictype returns the same node, we must break
**/
pBSaved = (node_skl *)0;
pBasicTypeOfUseNode = pUse;
while( (pBasicTypeOfUseNode = pBasicTypeOfUseNode->GetBasicType()) &&
( pBasicTypeOfUseNode != pBSaved ) )
{
BasicNodeKind = pBasicTypeOfUseNode->NodeKind();
if( (BasicNodeKind == NODE_UNION ) || (BasicNodeKind == NODE_FORWARD))
{
fOk = TRUE;
break;
}
pBSaved = pBasicTypeOfUseNode;
}
if( !fOk )
ParseError( SWITCH_IS_ON_NON_UNION, (char *)0 );
/**
** check for the expression associated with the switch_is.
** It must be resolved, and of integral type.
**/
pExpr->SCheck( pGlobalContext->GetCurrentSymbolTable() );
if( !pExpr->IsResolved() )
{
ParseError( ATTRIBUTE_ID_UNRESOLVED, pName );
}
else
{
NODE_T NT = pExpr->GetType()->NodeKind();
BOOL fExprDerivesFromUniqueOrFull= pExpr->DerivesUniqueFull();
BOOL fDerivesFromIgnore = pExpr->DerivesFromIgnore();
BOOL fExprIsNOTAPureVariable = !pExpr->IsAPureVariable();
BOOL fExprIsNOTAPurePointer = !pExpr->IsAPointerExpr();
if( (!pExpr->IsExprInt()) &&
( NT != NODE_BOOLEAN) &&
// (NT != NODE_BYTE) &&
(NT != NODE_WCHAR_T) &&
(NT != NODE_CHAR ) )
{
ParseError( SWITCH_IS_TYPE_IS_WRONG, pName );
}
if( fExprDerivesFromUniqueOrFull )
ParseError( SIZE_LENGTH_SW_UNIQUE_OR_FULL, pName );
if( fDerivesFromIgnore )
ParseError( IGNORE_ON_DISCRIMINANT, (char *)0 );
if( fExprIsNOTAPureVariable && fExprIsNOTAPurePointer )
ParseError( ATTRIBUTE_ID_MUST_BE_VAR, pName );
}
return NODE_STATE_OK;
}
node_context::node_context() : nbattr( ATTR_CONTEXT )
{
}
node_state
node_context::SCheck()
{
node_state NState = NODE_STATE_OK;
EnCtxt LastCtxt;
/**
** we need not explicitly verify here that the context was applied to a
** param or a typedef. We wont be here if it was not. Assert for a null
** of the last context anyway
**/
node_skl * pLastContext;
node_skl * pBasicType;
BOOL fReportError;
if( !(pLastContext = pGlobalContext->GetLastContext( LastCtxt = C_DEF ) ) )
if( !(pLastContext = pGlobalContext->GetLastContext( LastCtxt = C_PARAM ) ) )
pLastContext = pGlobalContext->GetLastContext( LastCtxt = C_PROC );
if( pLastContext )
{
/**
** the context handle MUST be a pointer in OSF mode,
** and must be a void pointer
**/
pBasicType = pLastContext->GetBasicType();
//
// dont report error if the context_handle was applied on a typedef
// node and the typedef node is not the original node, since the
// error would be reported on the original node in any case. This
// would prevent a useless cascade of errors.
//
fReportError = TRUE;
if( (LastCtxt == C_DEF ) && pLastContext->IsClonedNode() )
fReportError = FALSE;
if( fReportError )
{
BOOL fBasicTypeIsAPointer =
pBasicType->NodeKind() == NODE_POINTER;
NODE_T NType =
pBasicType->GetFundamentalType()->NodeKind();
if( !fBasicTypeIsAPointer )
{
ParseError( CTXT_HDL_NON_PTR, (char *)0 );
}
if(NType != NODE_VOID )
ParseError( CONTEXT_HANDLE_VOID_PTR, (char *)NULL );
if( NType == NODE_HANDLE_T )
ParseError( CTXT_HDL_HANDLE_T, (char *)0 );
if( LastCtxt == C_PROC )
{
if( pBasicType->NodeKind() == NODE_VOID )
ParseError( INAPPLICABLE_ATTRIBUTE, GetNodeNameString() );
if( pLastContext->FInSummary( ATTR_CALLBACK ) )
ParseError( HANDLES_WITH_CALLBACK, (char *)0 );
}
#if 0
if( pBasicType->NodeKind() == NODE_POINTER )
{
if( pBasicType->FInSummary( ATTR_UNIQUE ) ||
pBasicType->FInSummary( ATTR_PTR ) )
ParseError( CONTEXT_HANDLE_UNIQUE_PTR, (char *)0 );
}
#endif // 0
}
//
// check if the context_handle has been used as the implicit handle
// of the base interface
//
if( (LastCtxt == C_DEF) && pBaseImplicitHandle )
{
if( strcmp(
pBaseImplicitHandle->GetSymName(),
pLastContext->GetSymName()
) == 0
)
{
ParseError( CTXT_HANDLE_USED_AS_IMPLICIT,
pLastContext->GetSymName() );
}
}
NState = NODE_STATE_HANDLE | NODE_STATE_CONTEXT_HANDLE;
}
else
{
ParseError( INAPPLICABLE_ATTRIBUTE, GetNodeNameString() );
}
return NState;
}
node_case::node_case(
class expr_list * pL ) : nbattr( ATTR_CASE )
{
pExprList = pL;
}
node_state
node_case::SCheck()
{
expr_node * pMyExpr;
NODE_T NT;
while( pExprList->GetPeer( &pMyExpr ) == STATUS_OK )
{
assert( pMyExpr != (expr_node *)NULL );
NT = (pMyExpr->GetType())->NodeKind();
if( !pMyExpr->IsConstant() )
ParseError( CASE_EXPR_NOT_CONST, (char *)NULL );
if( !pMyExpr->IsExprInt() &&
(NT != NODE_BOOLEAN) &&
(NT != NODE_CHAR) )
ParseError( CASE_EXPR_NOT_INT, (char *)NULL );
}
return NODE_STATE_OK;
}
/****************************************************************************
utility routines
****************************************************************************/
void
CheckSizeAndLengthTypeMismatch(
node_skl * pTypeNode )
{
sa * pSizeNode = (sa *)NULL;
sa * pLengthNode = (sa *)NULL;
node_skl * pSizeType,
* pLengthType;
BOOL fSizeExprConstant;
BOOL fLengthExprConstant;
expr_node * pSizeExpr;
expr_node * pLengthExpr;
if( pTypeNode->FInSummary( ATTR_SIZE ) )
pSizeNode = (sa *)pTypeNode->GetAttribute( ATTR_SIZE );
else if( pTypeNode->FInSummary( ATTR_MAX ) )
pSizeNode = (sa *)pTypeNode->GetAttribute( ATTR_MAX );
if( pTypeNode->FInSummary( ATTR_LENGTH ) )
pLengthNode = (sa *)pTypeNode->GetAttribute( ATTR_LENGTH );
else if( pTypeNode->FInSummary( ATTR_LAST ) )
pLengthNode = (sa *)pTypeNode->GetAttribute( ATTR_LAST );
if( pSizeNode && pLengthNode )
{
pSizeExpr = pSizeNode->GetExpr();
pLengthExpr = pLengthNode->GetExpr();
pSizeType = pSizeExpr->GetType();
pLengthType = pLengthExpr->GetType();
fSizeExprConstant = pSizeExpr->IsConstant();
fLengthExprConstant = pLengthExpr->IsConstant();
if( (pSizeType->NodeKind() != NODE_ERROR) &&
(pLengthType->NodeKind() != NODE_ERROR) &&
!(fSizeExprConstant || fLengthExprConstant ) &&
(pSizeType != pLengthType ) )
{
ParseError(SIZE_LENGTH_TYPE_MISMATCH, (char *)NULL );
}
}
}
BOOL
IsValueInRangeOfType(
node_skl * pType,
expr_node * pExpr )
{
//
// some expression nodes are really not constant expression nodes. Like
// variable nodes.
//
pExpr = pExpr->GetExpr();
if( pExpr && pExpr->IsConstant() )
{
expr_constant * pC = new expr_constant( pExpr->GetValue() );
BOOL fResult;
fResult = pC->IsAValidConstantOfType( pType );
delete pC;
return fResult;
}
else
return FALSE;
}
int
HexCheck(
char *pStr)
{
if(pStr && *pStr)
{
while(*pStr)
{
if(! isxdigit(*pStr)) return 0;
pStr++;
}
return 1;
}
return 0;
}
/*****************************************************************************
These virtual functions can be inlined, but they are here because the MIPS
compiler does not like virtual inlined functions.
*****************************************************************************/
BOOL
node_base_attr::IsBitAttr()
{
return FALSE;
}
node_state
node_base_attr::AcfSCheck()
{
return NODE_STATE_OK;
}
class expr_node*
node_base_attr::GetExpr()
{
return (class expr_node *)NULL ;
}
node_state
node_base_attr::SCheck()
{
return NODE_STATE_OK;
}
/*****************************************************************************/
BOOL
battr::IsBitAttr()
{
return TRUE;
}
/*****************************************************************************/
class expr_node *
sa::GetExpr()
{
return pExpr;
}
/*****************************************************************************/
node_state
node_int_size_is::SCheck()
{
return NODE_STATE_OK;
}
node_state
node_min_is::SCheck()
{
ParseError( IGNORE_UNIMPLEMENTED_ATTRIBUTE, GetNodeNameString() );
return NODE_STATE_OK;
}
node_state
node_int_length_is::SCheck()
{
return NODE_STATE_OK;
}
/*****************************************************************************/
node_state
ma::SCheck()
{
return NODE_STATE_OK;
}
/*****************************************************************************/
node_state
node_handle::SCheck()
{
return NODE_STATE_HANDLE;
}
node_state
node_callback::SCheck()
{
ParseError( INVALID_OSF_ATTRIBUTE, GetNodeNameString() );
return NODE_STATE_OK;
}
node_state
node_broadcast::SCheck()
{
// if( !pCommand->IsSwitchDefined( SWITCH_INTERNAL ) )
// ParseError( IGNORE_UNIMPLEMENTED_ATTRIBUTE, GetNodeNameString() );
return NODE_STATE_OK;
}
node_state
node_idempotent::SCheck()
{
// if( !pCommand->IsSwitchDefined( SWITCH_INTERNAL ) )
// ParseError( IGNORE_UNIMPLEMENTED_ATTRIBUTE, GetNodeNameString() );
return NODE_STATE_OK;
}
node_state
node_maybe::SCheck()
{
// if( !pCommand->IsSwitchDefined( SWITCH_INTERNAL ) )
// ParseError( IGNORE_UNIMPLEMENTED_ATTRIBUTE, GetNodeNameString() );
return NODE_STATE_OK;
}