1
2 /*
3 * NIST STEP Core Class Library
4 * clstepcore/sdaiApplication_instance.cc
5 * July, 1997
6 * K. C. Morris
7 * David Sauder
8
9 * Development of this software was funded by the United States Government,
10 * and is not subject to copyright.
11 */
12
13 #include <map>
14 #include <sdai.h>
15 #include <instmgr.h>
16 #include <STEPcomplex.h>
17 #include <STEPattribute.h>
18 #include <read_func.h> //for ReadTokenSeparator, used when comments are inside entities
19
20 #include "sdaiApplication_instance.h"
21 #include "superInvAttrIter.h"
22
23 SDAI_Application_instance NilSTEPentity;
24
25 /**************************************************************//**
26 ** \file sdaiApplication_instance.cc Functions for manipulating entities
27 **
28 ** KNOWN BUGs: the SDAI_Application_instance is not aware of the STEPfile;
29 ** therefore it can not read comments which may be embedded in the instance.
30 ** The following are known problems:
31 ** -- does not handle comments embedded in an instance ==> bombs
32 ** -- ignores embedded entities ==> does not bomb
33 ** -- error reporting does not include line number information
34 */
35
SDAI_Application_instance()36 SDAI_Application_instance::SDAI_Application_instance()
37 : _cur( 0 ),
38 eDesc( NULL ),
39 _complex( false ),
40 STEPfile_id( 0 ),
41 p21Comment( std::string( "" ) ),
42 headMiEntity( 0 ),
43 nextMiEntity( 0 ) {
44 }
45
SDAI_Application_instance(int fileid,int complex)46 SDAI_Application_instance::SDAI_Application_instance( int fileid, int complex )
47 : _cur( 0 ),
48 eDesc( NULL ),
49 _complex( complex ),
50 STEPfile_id( fileid ),
51 p21Comment( std::string( "" ) ),
52 headMiEntity( 0 ),
53 nextMiEntity( 0 ) {
54 }
55
~SDAI_Application_instance()56 SDAI_Application_instance::~SDAI_Application_instance() {
57 STEPattribute * attr;
58
59 ResetAttributes();
60 do {
61 attr = NextAttribute();
62 if( attr ) {
63 attr->refCount --;
64 if( attr->refCount <= 0 ) {
65 delete attr;
66 }
67 }
68 } while( attr );
69
70
71 if( MultipleInheritance() ) {
72 delete nextMiEntity;
73 }
74 }
75
76
77 /// initialize inverse attrs
78 /// eDesc->InitIAttrs() must have been called previously
79 /// call once per instance (*not* once per class)
InitIAttrs()80 void SDAI_Application_instance::InitIAttrs() {
81 assert( eDesc && "eDesc must be set; please report this bug." );
82 InverseAItr iai( &( eDesc->InverseAttr() ) );
83 const Inverse_attribute * ia;
84 iAstruct s;
85 memset( &s, 0, sizeof s );
86 while( 0 != ( ia = iai.NextInverse_attribute() ) ) {
87 iAMap.insert( iAMap_t::value_type( ia, s ) );
88 }
89 superInvAttrIter siai( eDesc );
90 while( !siai.empty() ) {
91 ia = siai.next();
92 assert( ia && "Null inverse attr!" );
93 iAMap.insert( iAMap_t::value_type( ia, s ) );
94 }
95 }
96
Replicate()97 SDAI_Application_instance * SDAI_Application_instance::Replicate() {
98 char errStr[BUFSIZ];
99 if( IsComplex() ) {
100 cerr << "STEPcomplex::Replicate() should be called: " << __FILE__
101 << __LINE__ << "\n" << _POC_ "\n";
102 sprintf( errStr,
103 "SDAI_Application_instance::Replicate(): %s - entity #%d.\n",
104 "Programming ERROR - STEPcomplex::Replicate() should be called",
105 STEPfile_id );
106 _error.AppendToDetailMsg( errStr );
107 _error.AppendToUserMsg( errStr );
108 _error.GreaterSeverity( SEVERITY_BUG );
109 return S_ENTITY_NULL;
110 } else {
111 if( !eDesc ) {
112 return S_ENTITY_NULL;
113 }
114
115 SDAI_Application_instance * seNew = eDesc->NewSTEPentity();
116 seNew -> CopyAs( this );
117 return seNew;
118 }
119 }
120
AddP21Comment(const char * s,bool replace)121 void SDAI_Application_instance::AddP21Comment( const char * s, bool replace ) {
122 if( replace ) {
123 p21Comment.clear();
124 }
125 if( s ) {
126 p21Comment += s;
127 }
128 }
129
AddP21Comment(const std::string & s,bool replace)130 void SDAI_Application_instance::AddP21Comment( const std::string & s, bool replace ) {
131 if( replace ) {
132 p21Comment.clear();
133 }
134 p21Comment += s;
135 }
136
PrependP21Comment(const std::string & s)137 void SDAI_Application_instance::PrependP21Comment( const std::string & s ) {
138 p21Comment.insert( 0, s );
139 }
140
STEPwrite_reference(ostream & out)141 void SDAI_Application_instance::STEPwrite_reference( ostream & out ) {
142 out << "#" << STEPfile_id;
143 }
144
STEPwrite_reference(std::string & buf)145 const char * SDAI_Application_instance::STEPwrite_reference( std::string & buf ) {
146 char tmp[64];
147 sprintf( tmp, "#%d", STEPfile_id );
148 buf = tmp;
149 return const_cast<char *>( buf.c_str() );
150 }
151
AppendMultInstance(SDAI_Application_instance * se)152 void SDAI_Application_instance::AppendMultInstance( SDAI_Application_instance * se ) {
153 if( nextMiEntity == 0 ) {
154 nextMiEntity = se;
155 } else {
156 SDAI_Application_instance * link = nextMiEntity;
157 SDAI_Application_instance * linkTrailing = 0;
158 while( link ) {
159 linkTrailing = link;
160 link = link->nextMiEntity;
161 }
162 linkTrailing->nextMiEntity = se;
163 }
164 }
165
166 // BUG implement this -- FIXME function is never used
167
GetMiEntity(char * entName)168 SDAI_Application_instance * SDAI_Application_instance::GetMiEntity( char * entName ) {
169 std::string s1, s2;
170
171 const EntityDescLinkNode * edln = 0;
172 const EntityDescriptor * ed = eDesc;
173
174 // compare up the *leftmost* parent path
175 while( ed ) {
176 if( !strcmp( StrToLower( ed->Name(), s1 ), StrToLower( entName, s2 ) ) ) {
177 return this; // return this parent path
178 }
179 edln = ( EntityDescLinkNode * )( ed->Supertypes().GetHead() );
180 if( edln ) {
181 ed = edln->EntityDesc();
182 } else {
183 ed = 0;
184 }
185 }
186 // search alternate parent path since didn't find it in this one.
187 if( nextMiEntity ) {
188 return nextMiEntity->GetMiEntity( entName );
189 }
190 return 0;
191 }
192
193
194 /**
195 * Returns a STEPattribute or NULL
196 * \param nm The name to search for.
197 * \param entity If not null, check that the attribute comes from this entity. When MakeDerived is called from generated code, this is used to ensure that the correct attr is marked as derived. Issue #232
198 */
GetSTEPattribute(const char * nm,const char * entity)199 STEPattribute * SDAI_Application_instance::GetSTEPattribute( const char * nm, const char * entity ) {
200 if( !nm ) {
201 return 0;
202 }
203 STEPattribute * a = 0;
204
205 ResetAttributes();
206 // keep going until no more attributes, or attribute is found
207 while( ( a = NextAttribute() ) ) {
208 if( 0 == strcmp( nm, a ->Name() ) &&
209 //if entity isn't null, check for a match. NOTE: should we use IsA(), CanBe(), or Name()?
210 ( entity ? ( 0 != a->aDesc->Owner().IsA( entity ) ) : true ) ) {
211 break;
212 }
213 }
214
215 return a;
216 }
217
MakeRedefined(STEPattribute * redefiningAttr,const char * nm)218 STEPattribute * SDAI_Application_instance::MakeRedefined( STEPattribute * redefiningAttr, const char * nm ) {
219 // find the attribute being redefined
220 STEPattribute * a = GetSTEPattribute( nm );
221
222 // assign its pointer to the redefining attribute
223 if( a ) {
224 a->RedefiningAttr( redefiningAttr );
225 }
226 return a;
227 }
228
229 /**
230 * Returns a STEPattribute or NULL. If found, marks as derived.
231 * \param nm The name to search for.
232 * \param entity If not null, check that the attribute comes from this entity. When called from generated code, this is used to ensure that the correct attr is marked as derived. Issue #232
233 */
MakeDerived(const char * nm,const char * entity)234 STEPattribute * SDAI_Application_instance::MakeDerived( const char * nm, const char * entity ) {
235 STEPattribute * a = GetSTEPattribute( nm, entity );
236 if( a ) {
237 a ->Derive();
238 }
239 return a;
240 }
241
CopyAs(SDAI_Application_instance * other)242 void SDAI_Application_instance::CopyAs( SDAI_Application_instance * other ) {
243 int numAttrs = AttributeCount();
244 ResetAttributes();
245 other -> ResetAttributes();
246
247 STEPattribute * this_attr = 0;
248 STEPattribute * other_attr = 0;
249 while( ( this_attr = NextAttribute() ) && numAttrs ) {
250 other_attr = other -> NextAttribute();
251 this_attr -> ShallowCopy( other_attr );
252 numAttrs--;
253 }
254 }
255
256
EntityName(const char * schnm) const257 const char * SDAI_Application_instance::EntityName( const char * schnm ) const {
258 if( !eDesc ) {
259 return NULL;
260 }
261 return eDesc->Name( schnm );
262 }
263
264 /**
265 * Checks if a given SDAI_Application_instance is the same
266 * type as this one
267 */
IsA(const EntityDescriptor * ed) const268 const EntityDescriptor * SDAI_Application_instance::IsA( const EntityDescriptor * ed ) const {
269 if( !eDesc ) {
270 return NULL;
271 }
272 return ( eDesc->IsA( ed ) );
273 }
274
275 /**
276 * Checks the validity of the current attribute values for the entity
277 */
ValidLevel(ErrorDescriptor * error,InstMgrBase * im,int clearError)278 Severity SDAI_Application_instance::ValidLevel( ErrorDescriptor * error, InstMgrBase * im,
279 int clearError ) {
280 ErrorDescriptor err;
281 if( clearError ) {
282 ClearError();
283 }
284 int n = attributes.list_length();
285 for( int i = 0 ; i < n; i++ ) {
286 if( !( attributes[i].aDesc->AttrType() == AttrType_Redefining ) )
287 error->GreaterSeverity( attributes[i].ValidLevel(
288 attributes[i].asStr().c_str(), &err, im, 0 ) );
289 }
290 return error->severity();
291 }
292
293 /**
294 * clears all attr's errors
295 */
ClearAttrError()296 void SDAI_Application_instance::ClearAttrError() {
297 int n = attributes.list_length();
298 for( int i = 0 ; i < n; i++ ) {
299 attributes[i].Error().ClearErrorMsg();
300 }
301 }
302
303 /**
304 * clears entity's error and optionally all attr's errors
305 */
ClearError(int clearAttrs)306 void SDAI_Application_instance::ClearError( int clearAttrs ) {
307 _error.ClearErrorMsg();
308 if( clearAttrs ) {
309 ClearAttrError();
310 }
311 }
312
313 /**************************************************************//**
314 ** \param out -- stream to write to
315 ** \details
316 ** Side Effects: writes out the SCOPE section for an entity
317 ** Status: stub FIXME
318 *******************************************************************/
beginSTEPwrite(ostream & out)319 void SDAI_Application_instance::beginSTEPwrite( ostream & out ) {
320 out << "begin STEPwrite ... \n" ;
321 out.flush();
322
323 int n = attributes.list_length();
324 for( int i = 0 ; i < n; i++ ) {
325 if( attributes[i].Type() == ENTITY_TYPE
326 && *( attributes[i].ptr.c ) != S_ENTITY_NULL ) {
327 ( *( attributes[i].ptr.c ) ) -> STEPwrite();
328 }
329 }
330 }
331
332 /**************************************************************//**
333 ** \param out -- stream to write to
334 ** \details
335 ** Side Effects: writes out the data associated with an instance
336 ** in STEP format
337 ** Problems: does not print out the SCOPE section of an entity
338 **
339 *******************************************************************/
STEPwrite(ostream & out,const char * currSch,int writeComments)340 void SDAI_Application_instance::STEPwrite( ostream & out, const char * currSch,
341 int writeComments ) {
342 std::string tmp;
343 if( writeComments && !p21Comment.empty() ) {
344 out << p21Comment;
345 }
346 out << "#" << STEPfile_id << "=" << StrToUpper( EntityName( currSch ), tmp )
347 << "(";
348 int n = attributes.list_length();
349
350 for( int i = 0 ; i < n; i++ ) {
351 if( !( attributes[i].aDesc->AttrType() == AttrType_Redefining ) ) {
352 if( i > 0 ) {
353 out << ",";
354 }
355 ( attributes[i] ).STEPwrite( out, currSch );
356 }
357 }
358 out << ");\n";
359 }
360
endSTEPwrite(ostream & out)361 void SDAI_Application_instance::endSTEPwrite( ostream & out ) {
362 out << "end STEPwrite ... \n" ;
363 out.flush();
364 }
365
WriteValuePairs(ostream & out,const char * currSch,int writeComments,int mixedCase)366 void SDAI_Application_instance::WriteValuePairs( ostream & out,
367 const char * currSch,
368 int writeComments, int mixedCase ) {
369 std::string s, tmp, tmp2;
370
371 if( writeComments && !p21Comment.empty() ) {
372 out << p21Comment;
373 }
374
375 if( eDesc ) {
376 if( mixedCase ) {
377 out << "#" << STEPfile_id << " "
378 << eDesc->QualifiedName( s ) << endl;
379 } else {
380 out << "#" << STEPfile_id << " "
381 << StrToUpper( eDesc->QualifiedName( s ), tmp ) << endl;
382 }
383 }
384
385 int n = attributes.list_length();
386
387 for( int i = 0 ; i < n; i++ ) {
388 if( !( attributes[i].aDesc->AttrType() == AttrType_Redefining ) ) {
389 if( mixedCase ) {
390 out << "\t"
391 << attributes[i].aDesc->Owner().Name( s.c_str() )
392 << "." << attributes[i].aDesc->Name() << " ";
393 } else {
394 out << "\t"
395 << StrToUpper( attributes[i].aDesc->Owner().Name( s.c_str() ), tmp )
396 << "." << StrToUpper( attributes[i].aDesc->Name(), tmp2 ) << " ";
397 }
398 ( attributes[i] ).STEPwrite( out, currSch );
399 out << endl;
400 }
401 }
402 out << endl;
403 }
404
405
406 /******************************************************************
407 ** Procedure: STEPwrite
408 ** Problems: does not print out the SCOPE section of an entity
409 ******************************************************************/
STEPwrite(std::string & buf,const char * currSch)410 const char * SDAI_Application_instance::STEPwrite( std::string & buf, const char * currSch ) {
411 buf.clear();
412
413 char instanceInfo[BUFSIZ];
414
415 std::string tmp;
416 sprintf( instanceInfo, "#%d=%s(", STEPfile_id, StrToUpper( EntityName( currSch ), tmp ) );
417 buf.append( instanceInfo );
418
419 int n = attributes.list_length();
420
421 for( int i = 0 ; i < n; i++ ) {
422 if( !( attributes[i].aDesc->AttrType() == AttrType_Redefining ) ) {
423 if( i > 0 ) {
424 buf.append( "," );
425 }
426 tmp = attributes[i].asStr( currSch ) ;
427 buf.append( tmp );
428 }
429 }
430 buf.append( ");" );
431 return const_cast<char *>( buf.c_str() );
432 }
433
PrependEntityErrMsg()434 void SDAI_Application_instance::PrependEntityErrMsg() {
435 char errStr[BUFSIZ];
436 errStr[0] = '\0';
437
438 if( _error.severity() == SEVERITY_NULL ) {
439 // if there is not an error already
440 sprintf( errStr, "\nERROR: ENTITY #%d %s\n", GetFileId(),
441 EntityName() );
442 _error.PrependToDetailMsg( errStr );
443 }
444 }
445
446 /**************************************************************//**
447 ** \param c -- character which caused error
448 ** \param i -- index of attribute which caused error
449 ** \param in -- (used in STEPcomplex) input stream for recovery
450 ** Reports the error found, reads until it finds the end of an
451 ** instance. i.e. a close quote followed by a semicolon optionally
452 ** having whitespace between them.
453 ******************************************************************/
STEPread_error(char c,int i,istream & in,const char * schnm)454 void SDAI_Application_instance::STEPread_error( char c, int i, istream & in, const char * schnm ) {
455 (void) in;
456 char errStr[BUFSIZ];
457 errStr[0] = '\0';
458
459 if( _error.severity() == SEVERITY_NULL ) {
460 // if there is not an error already
461 sprintf( errStr, "\nERROR: ENTITY #%d %s\n", GetFileId(),
462 EntityName() );
463 _error.PrependToDetailMsg( errStr );
464 }
465
466 if( ( i >= 0 ) && ( i < attributes.list_length() ) ) { // i is an attribute
467 Error().GreaterSeverity( SEVERITY_WARNING );
468 sprintf( errStr, " invalid data before type \'%s\'\n",
469 attributes[i].TypeName() );
470 _error.AppendToDetailMsg( errStr );
471 } else {
472 Error().GreaterSeverity( SEVERITY_INPUT_ERROR );
473 _error.AppendToDetailMsg( " No more attributes were expected.\n" );
474 }
475
476 std::string tmp;
477 STEPwrite( tmp, schnm ); // STEPwrite writes to a static buffer inside function
478 _error.AppendToDetailMsg( " The invalid instance to this point looks like :\n" );
479 _error.AppendToDetailMsg( tmp );
480 _error.AppendToDetailMsg( "\nUnexpected character: " );
481 _error.AppendToDetailMsg( c );
482 _error.AppendToDetailMsg( '\n' );
483
484 sprintf( errStr, "\nfinished reading #%d\n", STEPfile_id );
485 _error.AppendToDetailMsg( errStr );
486 return;
487 }
488
489 /**************************************************************//**
490 ** \returns Severity, error information
491 ** SEVERITY_NULL - no errors
492 ** SEVERITY_USERMSG - checked as much as possible, could still
493 ** be error - e.g. entity didn't match base entity type.
494 ** SEVERITY_INCOMPLETE - data is missing and required.
495 ** SEVERITY_WARNING - errors, but can recover
496 ** <= SEVERITY_INPUT_ERROR - fatal error, can't recover
497 ** \details reads the values for an entity from an input stream
498 ** in STEP file format starting at the open paren and
499 ** ending with the semi-colon
500 ** Side Effects: gobbles up input stream
501 ** Status:
502 ******************************************************************/
STEPread(int id,int idIncr,InstMgrBase * instance_set,istream & in,const char * currSch,bool useTechCor,bool strict)503 Severity SDAI_Application_instance::STEPread( int id, int idIncr,
504 InstMgrBase * instance_set, istream & in,
505 const char * currSch, bool useTechCor, bool strict ) {
506 STEPfile_id = id;
507 char c = '\0';
508 char errStr[BUFSIZ];
509 errStr[0] = '\0';
510 Severity severe;
511 int i = 0;
512
513 ClearError( 1 );
514
515 in >> ws;
516 in >> c; // read the open paren
517 if( c != '(' ) {
518 PrependEntityErrMsg();
519 _error.AppendToDetailMsg(
520 " Missing initial open paren... Trying to recover.\n" );
521 in.putback( c ); // assume you can recover by reading 1st attr value
522 }
523 ReadTokenSeparator( in, &p21Comment );
524
525 int n = attributes.list_length();
526 if( n == 0 ) { // no attributes
527 in >> c; // look for the close paren
528 if( c == ')' ) {
529 return _error.severity();
530 }
531 }
532
533 for( i = 0 ; i < n; i++ ) {
534 ReadTokenSeparator( in, &p21Comment );
535 if( attributes[i].aDesc->AttrType() == AttrType_Redefining ) {
536 in >> ws;
537 c = in.peek();
538 if( !useTechCor ) { // i.e. use pre-technical corrigendum encoding
539 in >> c; // read what should be the '*'
540 in >> ws;
541 if( c == '*' ) {
542 in >> c; // read the delimiter i.e. ',' or ')'
543 } else {
544 severe = SEVERITY_INCOMPLETE;
545 PrependEntityErrMsg(); // adds entity info if necessary
546
547 // set the severity for this entity
548 _error.GreaterSeverity( severe );
549 sprintf( errStr, " %s : ", attributes[i].Name() );
550 _error.AppendToDetailMsg( errStr ); // add attr name
551 _error.AppendToDetailMsg(
552 "Since using pre-technical corrigendum... missing asterisk for redefined attr.\n" );
553 _error.AppendToUserMsg(
554 "Since using pre-technical corrigendum... missing asterisk for redefined attr. " );
555 }
556 } else { // using technical corrigendum
557 // should be nothing to do except loop again unless...
558 // if at end need to have read the closing paren.
559 if( c == ')' ) { // assume you are at the end so read last char
560 in >> c;
561 }
562 cout << "Entity #" << STEPfile_id
563 << " skipping redefined attribute "
564 << attributes[i].aDesc->Name() << endl << endl << flush;
565 }
566 // increment counter to read following attr since these attrs
567 // aren't written or read => there won't be a delimiter either
568 } else {
569 attributes[i].STEPread( in, instance_set, idIncr, currSch, strict );
570 in >> c; // read the , or ) following the attr read
571
572 severe = attributes[i].Error().severity();
573
574 if( severe <= SEVERITY_USERMSG ) {
575 // if there is some type of error
576 PrependEntityErrMsg();
577
578 // set the severity for this entity
579 _error.GreaterSeverity( severe );
580 sprintf( errStr, " %s : ", attributes[i].Name() );
581 _error.AppendToDetailMsg( errStr ); // add attr name
582 _error.AppendToDetailMsg( attributes[i].Error().DetailMsg() ); // add attr error
583 _error.AppendToUserMsg( attributes[i].Error().UserMsg() );
584 }
585 }
586
587 // if technical corrigendum redefined, input is at next attribute value
588 // if pre-technical corrigendum redefined, don't process
589 if( ( !( attributes[i].aDesc->AttrType() == AttrType_Redefining ) ||
590 !useTechCor ) &&
591 !( ( c == ',' ) || ( c == ')' ) ) ) { // input is not a delimiter
592 PrependEntityErrMsg();
593
594 _error.AppendToDetailMsg(
595 "Delimiter expected after attribute value.\n" );
596 if( !useTechCor ) {
597 _error.AppendToDetailMsg(
598 "I.e. since using pre-technical corrigendum, redefined " );
599 _error.AppendToDetailMsg(
600 "attribute is mapped as an asterisk so needs delimiter.\n" );
601 }
602 CheckRemainingInput( in, &_error, "ENTITY", ",)" );
603 if( !in.good() ) {
604 return _error.severity();
605 }
606 if( _error.severity() <= SEVERITY_INPUT_ERROR ) {
607 return _error.severity();
608 }
609 } else if( c == ')' ) {
610 while( i < n - 1 ) {
611 i++; // check if following attributes are redefined
612 if( !( attributes[i].aDesc->AttrType() == AttrType_Redefining ) ) {
613 PrependEntityErrMsg();
614 _error.AppendToDetailMsg( "Missing attribute value[s].\n" );
615 // recoverable error
616 _error.GreaterSeverity( SEVERITY_WARNING );
617 return _error.severity();
618 }
619 i++;
620 }
621 return _error.severity();
622 }
623 }
624 STEPread_error( c, i, in, currSch );
625 // code fragment imported from STEPread_error
626 // for some currently unknown reason it was commented out of STEPread_error
627 errStr[0] = '\0';
628 in.clear();
629 int foundEnd = 0;
630 std::string tmp;
631 tmp = "";
632
633 // Search until a close paren is found followed by (skipping optional
634 // whitespace) a semicolon
635 while( in.good() && !foundEnd ) {
636 while( in.good() && ( c != ')' ) ) {
637 in.get( c );
638 tmp += c;
639 }
640 if( in.good() && ( c == ')' ) ) {
641 in >> ws; // skip whitespace
642 in.get( c );
643 tmp += c;
644 if( c == ';' ) {
645 foundEnd = 1;
646 }
647 }
648 }
649 _error.AppendToDetailMsg( tmp.c_str() );
650 sprintf( errStr, "\nfinished reading #%d\n", STEPfile_id );
651 _error.AppendToDetailMsg( errStr );
652 // end of imported code
653 return _error.severity();
654 }
655
656 /// read an entity reference and return a pointer to the SDAI_Application_instance
ReadEntityRef(istream & in,ErrorDescriptor * err,const char * tokenList,InstMgrBase * instances,int addFileId)657 SDAI_Application_instance * ReadEntityRef( istream & in, ErrorDescriptor * err, const char * tokenList,
658 InstMgrBase * instances, int addFileId ) {
659 char c;
660 char errStr[BUFSIZ];
661 errStr[0] = '\0';
662
663 in >> ws;
664 in >> c;
665 switch( c ) {
666 case '@':
667 err->AppendToDetailMsg( "Use of @ instead of # to identify entity.\n" );
668 err->GreaterSeverity( SEVERITY_WARNING );
669 // no break statement here on purpose
670 case '#': {
671 int id = -1;
672 in >> id;
673 if( in.fail() ) { // there's been an error in input
674 sprintf( errStr, "Invalid entity reference value.\n" );
675 err->AppendToDetailMsg( errStr );
676 err->AppendToUserMsg( errStr );
677 err->GreaterSeverity( SEVERITY_WARNING );
678 CheckRemainingInput( in, err, "Entity Reference", tokenList );
679 return S_ENTITY_NULL;
680 } else { // found an entity id
681 // check to make sure garbage does not follow the id
682 CheckRemainingInput( in, err, "Entity Reference", tokenList );
683
684 id += addFileId;
685 if( !instances ) {
686 cerr << "Internal error: " << __FILE__ << __LINE__
687 << "\n" << _POC_ "\n";
688 sprintf( errStr,
689 "STEPread_reference(): %s - entity #%d %s.\n",
690 "BUG - cannot read reference without the InstMgr",
691 id, "is unknown" );
692 err->AppendToDetailMsg( errStr );
693 err->AppendToUserMsg( errStr );
694 err->GreaterSeverity( SEVERITY_BUG );
695 return S_ENTITY_NULL;
696 }
697
698 // lookup which object has id as its instance id
699 SDAI_Application_instance * inst;
700 /* If there is a ManagerNode it should have a SDAI_Application_instance */
701 MgrNodeBase * mn = 0;
702 mn = instances->FindFileId( id );
703 if( mn ) {
704 inst = mn->GetSTEPentity() ;
705 if( inst ) {
706 return ( inst );
707 } else {
708 cerr << "Internal error: " << __FILE__ << __LINE__
709 << "\n" << _POC_ "\n";
710 sprintf( errStr,
711 "STEPread_reference(): %s - entity #%d %s.\n",
712 "BUG - MgrNode::GetSTEPentity returned NULL pointer",
713 id, "is unknown" );
714 err->AppendToDetailMsg( errStr );
715 err->AppendToUserMsg( errStr );
716 err->GreaterSeverity( SEVERITY_BUG );
717 return S_ENTITY_NULL;
718 }
719 } else {
720 sprintf( errStr, "Reference to non-existent ENTITY #%d.\n",
721 id );
722 err->AppendToDetailMsg( errStr );
723 err->AppendToUserMsg( errStr );
724 err->GreaterSeverity( SEVERITY_WARNING );
725 return S_ENTITY_NULL;
726 }
727 }
728 }
729 default: {
730 in.putback( c );
731 // read past garbage up to delim in tokenList
732 // if tokenList is null it will not read anything
733 CheckRemainingInput( in, err, "Entity Reference", tokenList );
734 return S_ENTITY_NULL;
735 }
736 }
737 }
738
739 /// read an entity reference and return a pointer to the SDAI_Application_instance
ReadEntityRef(const char * s,ErrorDescriptor * err,const char * tokenList,InstMgrBase * instances,int addFileId)740 SDAI_Application_instance * ReadEntityRef( const char * s, ErrorDescriptor * err, const char * tokenList,
741 InstMgrBase * instances, int addFileId ) {
742 istringstream in( ( char * )s );
743 return ReadEntityRef( in, err, tokenList, instances, addFileId );
744 }
745
746 /// return SEVERITY_NULL if se's entity type matches the supplied entity type
EntityValidLevel(SDAI_Application_instance * se,const TypeDescriptor * ed,ErrorDescriptor * err)747 Severity EntityValidLevel( SDAI_Application_instance * se,
748 const TypeDescriptor * ed, // entity type that entity se needs
749 // to match. (this must be an
750 // EntityDescriptor)
751 ErrorDescriptor * err ) {
752 char messageBuf [BUFSIZ];
753 messageBuf[0] = '\0';
754
755 if( !ed || ( ed->NonRefType() != ENTITY_TYPE ) ) {
756 err->GreaterSeverity( SEVERITY_BUG );
757 sprintf( messageBuf,
758 " BUG: EntityValidLevel() called with %s",
759 "missing or invalid EntityDescriptor\n" );
760 err->AppendToUserMsg( messageBuf );
761 err->AppendToDetailMsg( messageBuf );
762 cerr << "Internal error: " << __FILE__ << ":" << __LINE__
763 << "\n" << _POC_ "\n";
764 return SEVERITY_BUG;
765 }
766 if( !se || ( se == S_ENTITY_NULL ) ) {
767 err->GreaterSeverity( SEVERITY_BUG );
768 sprintf( messageBuf,
769 " BUG: EntityValidLevel() called with null pointer %s\n",
770 "for SDAI_Application_instance argument." );
771 err->AppendToUserMsg( messageBuf );
772 err->AppendToDetailMsg( messageBuf );
773 cerr << "Internal error: " << __FILE__ << ":" << __LINE__
774 << "\n" << _POC_ "\n";
775 return SEVERITY_BUG;
776 }
777
778 // DAVE: Can an entity be used in an Express TYPE so that this
779 // EntityDescriptor would have type REFERENCE_TYPE -- it looks like NO
780
781 else if( se->getEDesc() ) {
782 // is se a descendant of ed?
783 if( se->getEDesc()->IsA( ed ) ) {
784 return SEVERITY_NULL;
785 } else {
786 if( se->IsComplex() ) {
787 // This way assumes that the complex has all it's parts i.e. the
788 // complete hierarchy so it should be able to find ed's part if
789 // it is an ed.
790 STEPcomplex * sc = ( ( STEPcomplex * )se )->sc;
791 if( sc->EntityExists( ed->Name() ) ) {
792 return SEVERITY_NULL;
793 }
794 }
795 err->GreaterSeverity( SEVERITY_WARNING );
796 sprintf( messageBuf,
797 " Entity #%d exists but is not a %s or descendant.\n",
798 se->STEPfile_id, ed->Name() );
799 err->AppendToUserMsg( messageBuf );
800 err->AppendToDetailMsg( messageBuf );
801 return SEVERITY_WARNING;
802 }
803 } else {
804 err->GreaterSeverity( SEVERITY_BUG );
805 sprintf( messageBuf,
806 " BUG: EntityValidLevel(): SDAI_Application_instance #%d has a %s",
807 se->STEPfile_id, "missing or invalid EntityDescriptor\n" );
808 err->AppendToUserMsg( messageBuf );
809 err->AppendToDetailMsg( messageBuf );
810 cerr << "Internal error: " << __FILE__ << __LINE__
811 << "\n" << _POC_ "\n";
812 return SEVERITY_BUG;
813 }
814 }
815
816 /**
817 * return 1 if attrValue has the equivalent of a null value.
818 * DAVE: Is this needed will sscanf return 1 if assignment suppression is used?
819 */
SetErrOnNull(const char * attrValue,ErrorDescriptor * error)820 int SetErrOnNull( const char * attrValue, ErrorDescriptor * error ) {
821 char scanBuf[BUFSIZ];
822 scanBuf[0] = '\0';
823
824 std::stringstream fmtstr;
825 fmtstr << " %" << BUFSIZ -1 << "s ";
826 //fmtstr contains " %ns " where n is BUFSIZ -1
827
828 int numFound = sscanf( ( char * )attrValue , fmtstr.str().c_str() , scanBuf );
829
830 if( numFound == EOF ) {
831 error->GreaterSeverity( SEVERITY_INCOMPLETE );
832 return 1;
833 }
834 return 0;
835 }
836
837 /**
838 ** return SEVERITY_NULL if attrValue has a valid entity reference
839 ** This function accepts an entity reference in two forms that is with or
840 ** without the # sign: e.g. either #23 or 23 will be read.
841 ** If non-whitespace characters follow the entity reference an error is set.
842 */
EntityValidLevel(const char * attrValue,const TypeDescriptor * ed,ErrorDescriptor * err,InstMgrBase * im,int clearError)843 Severity EntityValidLevel( const char * attrValue, // string contain entity ref
844 const TypeDescriptor * ed, // entity type that entity in
845 // attrValue (if it exists) needs
846 // to match. (this must be an
847 // EntityDescriptor)
848 ErrorDescriptor * err, InstMgrBase * im, int clearError ) {
849 char tmp [BUFSIZ];
850 tmp[0] = '\0';
851 char messageBuf [BUFSIZ];
852 messageBuf[0] = '\0';
853 std::stringstream fmtstr1, fmtstr2;
854
855 if( clearError ) {
856 err->ClearErrorMsg();
857 }
858
859 int fileId;
860 MgrNodeBase * mn = 0;
861
862 // fmtstr1 contains "#%d %ns" where n is BUFSIZ-1
863 fmtstr1 << " #%d %" << BUFSIZ - 1 << "s ";
864
865 // fmtstr2 contains "%d %ns" where n is BUFSIZ-1
866 fmtstr2 << " %d %" << BUFSIZ - 1 << "s ";
867
868 // check for both forms: #id or id
869 int found1 = sscanf( ( char * )attrValue, fmtstr1.str().c_str() , &fileId, tmp );
870 int found2 = sscanf( ( char * )attrValue, fmtstr2.str().c_str() , &fileId, tmp );
871
872 if( ( found1 > 0 ) || ( found2 > 0 ) ) {
873 if( ( found1 == 2 ) || ( found2 == 2 ) ) {
874 sprintf( messageBuf,
875 " Attribute's Entity Reference %s is %s data \'%s\'.\n",
876 attrValue, "followed by invalid", tmp );
877 err->AppendToUserMsg( messageBuf );
878 err->AppendToDetailMsg( messageBuf );
879 err->GreaterSeverity( SEVERITY_WARNING );
880 }
881 mn = im->FindFileId( fileId );
882 if( mn ) {
883 SDAI_Application_instance * se = mn->GetSTEPentity();
884 return EntityValidLevel( se, ed, err );
885 } else {
886 sprintf( messageBuf,
887 " Attribute's Entity Reference %s does not exist.\n",
888 attrValue );
889 err->AppendToUserMsg( messageBuf );
890 err->AppendToDetailMsg( messageBuf );
891 err->GreaterSeverity( SEVERITY_WARNING );
892 return SEVERITY_WARNING;
893 }
894 }
895
896 // if the attrValue contains no value return
897 if( SetErrOnNull( attrValue, err ) ) {
898 return err->severity();
899 }
900
901 sprintf( messageBuf, "Invalid attribute entity reference value: '%s'.\n",
902 attrValue );
903 err->AppendToUserMsg( messageBuf );
904 err->AppendToDetailMsg( messageBuf );
905 err->GreaterSeverity( SEVERITY_WARNING );
906 return SEVERITY_WARNING;
907 }
908
909 /**************************************************************//**
910 ** Description: used to cycle through the list of attributes
911 ** Side Effects: increments the current position in the attribute list
912 ** Status: untested 7/31/90
913 ** \Returns reference to an attribute pointer
914 ******************************************************************/
NextAttribute()915 STEPattribute * SDAI_Application_instance::NextAttribute() {
916 int i = AttributeCount();
917 ++_cur;
918 if( i < _cur ) {
919 return 0;
920 }
921 return &attributes [_cur - 1];
922 }
923
AttributeCount()924 int SDAI_Application_instance::AttributeCount() {
925 return attributes.list_length();
926 }
927
getInvAttr(const Inverse_attribute * const ia) const928 const iAstruct SDAI_Application_instance::getInvAttr( const Inverse_attribute * const ia ) const {
929 iAstruct ias;
930 memset( &ias, 0, sizeof ias );
931 iAMap_t::const_iterator it = iAMap.find( ia );
932 if( it != iAMap.end() ) {
933 ias = (*it).second;
934 }
935 return ias;
936 }
937
getInvAttr(const char * name) const938 const SDAI_Application_instance::iAMap_t::value_type SDAI_Application_instance::getInvAttr( const char * name ) const {
939 iAMap_t::const_iterator it = iAMap.begin();
940 for( ; it != iAMap.end(); ++it ) {
941 if( 0 == strcmp( it->first->Name(), name) ) {
942 return *it;
943 }
944 }
945 iAstruct z;
946 memset( &z, 0, sizeof z );
947 iAMap_t::value_type nil( NULL, z );
948 return nil;
949 }
950
setInvAttr(const Inverse_attribute * const ia,const iAstruct ias)951 void SDAI_Application_instance::setInvAttr( const Inverse_attribute * const ia, const iAstruct ias ) {
952 iAMap_t::iterator it = iAMap.find(ia);
953 if( it != iAMap.end() ) {
954 it->second = ias;
955 } else {
956 iAMap.insert( iAMap_t::value_type( ia, ias ) );
957 }
958 }
959