1
2 /*
3 * NIST STEP Core Class Library
4 * clstepcore/sdaiSelect.cc
5 * April 1997
6 * Dave Helfrick
7 * KC Morris
8
9 * Development of this software was funded by the United States Government,
10 * and is not subject to copyright.
11 */
12
13 #include <stdio.h> // to get the BUFSIZ #define
14 #include <ExpDict.h>
15 #include <sstream>
16 #include <string>
17 #include <sdai.h>
18 #include <STEPattribute.h>
19
20 #ifdef SC_LOGGING
21 #include <fstream.h>
22 extern ofstream * logStream;
23 #endif
24
25 /**********
26 (member) functions for the select class SDAI_Select
27 **********/
SDAI_Select(const SelectTypeDescriptor * s,const TypeDescriptor * td)28 SDAI_Select::SDAI_Select( const SelectTypeDescriptor * s,
29 const TypeDescriptor * td )
30 : _type( s ), underlying_type( td ) {
31 #ifdef SC_LOGGING
32 *logStream << "Exiting SDAI_Select constructor." << endl;
33 #endif
34 }
35
SDAI_Select(const SDAI_Select & other)36 SDAI_Select::SDAI_Select( const SDAI_Select & other ) {
37 underlying_type = other.underlying_type;
38 base_type = other.base_type;
39 _type = other._type;
40 #ifdef SC_LOGGING
41 *logStream << "Exiting SDAI_Select constructor." << endl;
42 #endif
43 }
44
~SDAI_Select()45 SDAI_Select::~SDAI_Select() {
46 }
47
operator =(const SDAI_Select & other)48 SDAI_Select & SDAI_Select::operator=( const SDAI_Select & other ) {
49 if( &other != this ) {
50 _error = other._error;
51 _type = other._type;
52 base_type = other.base_type;
53 underlying_type = other.underlying_type;
54 val = other.val;
55 }
56 return *this;
57 }
58
severity() const59 Severity SDAI_Select::severity() const {
60 return _error.severity();
61 }
62
severity(Severity s)63 Severity SDAI_Select::severity( Severity s ) {
64 return _error.severity( s );
65 }
66
Error()67 std::string SDAI_Select::Error() {
68 return _error.DetailMsg();
69 }
70
Error(const char * e)71 void SDAI_Select::Error( const char * e ) {
72 _error.DetailMsg( e );
73 }
74
ClearError()75 void SDAI_Select::ClearError() {
76 _error.ClearErrorMsg();
77 }
78
79 const TypeDescriptor *
CanBe(const char * n) const80 SDAI_Select::CanBe( const char * n ) const {
81 return _type -> CanBe( n );
82 }
83
84
85 const TypeDescriptor *
CanBe(BASE_TYPE bt) const86 SDAI_Select::CanBe( BASE_TYPE bt ) const {
87 const TypeDescLinkNode * tdn =
88 ( const TypeDescLinkNode * ) _type -> GetElements().GetHead();
89 const TypeDescriptor * td = tdn -> TypeDesc();
90 BASE_TYPE bt_thisnode;
91
92 while( tdn ) {
93 td = tdn -> TypeDesc();
94 if( ( ( bt_thisnode = td -> NonRefType() ) == bt ) ||
95 ( bt == AGGREGATE_TYPE && ( ( bt_thisnode == ARRAY_TYPE ) ||
96 ( bt_thisnode == LIST_TYPE ) ||
97 ( bt_thisnode == SET_TYPE ) ||
98 ( bt_thisnode == BAG_TYPE ) ) ) ) {
99 return td; // they are the same
100 }
101 tdn = ( TypeDescLinkNode * )( tdn -> NextNode() );
102 }
103 return 0;
104 }
105
106 const TypeDescriptor *
CanBe(const TypeDescriptor * td) const107 SDAI_Select::CanBe( const TypeDescriptor * td ) const {
108 return _type -> CanBe( td );
109 }
110
111 const TypeDescriptor *
CanBeSet(const char * n,const char * schnm) const112 SDAI_Select::CanBeSet( const char * n, const char * schnm ) const {
113 return _type -> CanBeSet( n, schnm );
114 }
115
116 int
IsUnique(const BASE_TYPE bt) const117 SDAI_Select::IsUnique( const BASE_TYPE bt ) const {
118 if( bt == ARRAY_TYPE ||
119 bt == LIST_TYPE ||
120 bt == BAG_TYPE ||
121 bt == SET_TYPE ) {
122 return ( ( _type->UniqueElements() ) & AGGREGATE_TYPE );
123 } else {
124 return ( ( _type->UniqueElements() ) & bt );
125 }
126 }
127
128
UnderlyingTypeName() const129 SDAI_String SDAI_Select::UnderlyingTypeName() const {
130 return underlying_type -> Name();
131 }
132
CurrentUnderlyingType() const133 const TypeDescriptor * SDAI_Select::CurrentUnderlyingType() const {
134 return underlying_type;
135 }
136
137 const TypeDescriptor *
SetUnderlyingType(const TypeDescriptor * td)138 SDAI_Select::SetUnderlyingType( const TypeDescriptor * td ) {
139 // don\'t do anything if the descriptor is bad
140 if( !td || !( _type -> CanBe( td ) ) ) {
141 return 0;
142 }
143
144 base_type = td -> NonRefType();
145
146 return underlying_type = td;
147 }
148
exists() const149 bool SDAI_Select::exists() const {
150 return underlying_type != NULL;
151 }
152
nullify()153 void SDAI_Select::nullify() {
154 underlying_type = 0;
155 }
156
SelectValidLevel(const char * attrValue,ErrorDescriptor * err,InstMgrBase * im)157 Severity SDAI_Select::SelectValidLevel( const char * attrValue, ErrorDescriptor * err,
158 InstMgrBase * im ) {
159 SDAI_Select * tmp = NewSelect();
160 Severity s = SEVERITY_NULL;
161
162 istringstream strtmp( attrValue );
163 s = tmp -> STEPread( strtmp, err, im );
164 delete tmp;
165 return s;
166 }
167
StrToVal(const char * Val,const char * selectType,ErrorDescriptor * err,InstMgrBase * instances)168 Severity SDAI_Select::StrToVal( const char * Val, const char * selectType,
169 ErrorDescriptor * err, InstMgrBase * instances ) {
170 severity( SEVERITY_NULL );
171 if( SetUnderlyingType( CanBe( selectType ) ) )
172
173 // the underlying type is set to a valid type
174 // call read on underlying type in subclass
175
176 switch( base_type ) {
177 case ENTITY_TYPE: {
178 STEPentity * tmp =
179 ReadEntityRef( Val, err, ",)", instances, 0 );
180 if( tmp && ( tmp != ENTITY_NULL ) ) {
181 AssignEntity( tmp );
182 return severity();
183 } else {
184 err->AppendToDetailMsg(
185 "Reference to entity that is not a valid type for SELECT.\n" );
186 nullify();
187 err->GreaterSeverity( SEVERITY_WARNING );
188 return SEVERITY_WARNING;
189 }
190 }
191
192 // call StrToVal on the contents
193 case STRING_TYPE:
194 case AGGREGATE_TYPE:
195 case ARRAY_TYPE: // DAS
196 case BAG_TYPE: // DAS
197 case SET_TYPE: // DAS
198 case LIST_TYPE: // DAS
199 case ENUM_TYPE:
200 case SELECT_TYPE:
201 case BOOLEAN_TYPE:
202 case LOGICAL_TYPE: {
203 err->GreaterSeverity( StrToVal_content( Val, instances ) );
204 if( _error.severity() != SEVERITY_NULL ) {
205 err->AppendFromErrorArg( &_error );
206 }
207 return err->severity();
208 }
209
210 // do the same as STEPread_content
211 case BINARY_TYPE:
212 case NUMBER_TYPE:
213 case REAL_TYPE:
214 case INTEGER_TYPE:
215 default: {
216 istringstream strtmp( Val );
217 err->GreaterSeverity( STEPread_content( strtmp ) );
218 if( _error.severity() != SEVERITY_NULL ) {
219 err->AppendFromErrorArg( &_error );
220 }
221 return err->severity();
222 }
223 }
224 return SEVERITY_INPUT_ERROR;
225 }
226
227 /** updated to Technical Corrigendum. DAS 2/4/97
228 * This function does the following:
229 */
STEPread(istream & in,ErrorDescriptor * err,InstMgrBase * instances,const char * utype,int addFileId,const char * currSch)230 Severity SDAI_Select::STEPread( istream & in, ErrorDescriptor * err,
231 InstMgrBase * instances, const char * utype,
232 int addFileId, const char * currSch ) {
233 char c = '\0';
234 std::string tmp;
235
236 #ifdef SC_LOGGING
237 // *logStream << "DAVE ERR Entering SDAI_Select::STEPread." << endl;
238 #endif
239 // find out what case we have
240 // NOTE case C falls out of recursive calls in cases A and B
241
242 /**
243 ** This section of code is used to read a value belonging to a select
244 ** contained in another select. If you have read the text part of the
245 ** TYPED_PARAMETER and it needs to fall down thru some levels of contained
246 ** select types, then the text is passed down to each select in the utype
247 ** parameter as STEPread is called on each contained select type.DAS 2/4/97
248 */
249 if( utype ) {
250 if( SetUnderlyingType( CanBeSet( utype, currSch ) ) ) {
251 // assign the value to the underlying type
252 in >> ws; // skip white space
253 if( ( underlying_type->Type() == REFERENCE_TYPE ) &&
254 ( underlying_type->NonRefType() == sdaiSELECT ) ) {
255 // See comments below for a similar code segment.
256 STEPread_content( in, instances, 0, addFileId, currSch );
257 } else {
258 STEPread_content( in, instances, utype, addFileId, currSch );
259 }
260 err->AppendToDetailMsg( Error() );
261 err->GreaterSeverity( severity() );
262 }
263 return err->severity();
264 }
265 in >> ws;
266 in >> c;
267
268 /**
269 ** the if part of this code reads a value according to the Technical
270 ** Corrigendum for Part 21 (except for Entity instance refs which are read
271 ** in the else part - everything else in the else stmt is invalid). The
272 ** idea here is to read text and find out if it is specifying the final
273 ** type or is a simple defined type which is typed to be a select some
274 ** number of levels down. The first case will cause the value to be read
275 ** directly by STEPread_content() or will cause STEPread_content() to pass
276 ** the text naming the type to the underlying Select containing it. When
277 ** the latter is the case, STEPread_content calls STEPread for the
278 ** contained select and passes in the text. The convoluted case is when
279 ** the text describes a simple defined type that translates directly into
280 ** a select some number of levels down. In this case there will be more
281 ** text inside the containing parens to indicate the type. Since the text
282 ** specifying the type still needs to be read utype is passed as null which
283 ** will cause the contained Select STEPread function to read it. DAS 2/4/97
284 */
285
286 if( isalpha( c ) ) { // case B
287 int eot = 0; // end of token flag
288 // token is a type name - get the type
289 while( ( c != '(' ) && in.good() ) {
290 if( !eot && !( eot = isspace( c ) ) )
291 // as long as eot hasn\'t been reached keep appending
292 {
293 tmp += c;
294 }
295 in >> c;
296 }
297
298 // check for valid type and set the underlying type
299 if( SetUnderlyingType( CanBeSet( tmp.c_str(), currSch ) ) ) {
300 /**
301 ** Assign the value to the underlying type. CanBeSet() is a
302 ** slightly modified CanBe(). It ensures that a renamed select
303 ** type (see big comment below) "CantBe" one of its member items.
304 ** This is because such a select type requires its own name to
305 ** appear first ("selX("), so even if we read a valid element of
306 ** selX, selX can't be the underlying type. That can only be the
307 ** case if "selX" appears first and is what we just read.
308 */
309 in >> ws; // skip white space
310 if( ( underlying_type->Type() == REFERENCE_TYPE ) &&
311 ( underlying_type->NonRefType() == sdaiSELECT ) ) {
312 /**
313 * This means (1) that the underlying type is itself a select
314 ** (cond 2), and (2) it's not defined in the EXPRESS as a
315 ** select, but as a renamed select. (E.g., TYPE sel2 = sel1.)
316 ** In such a case, according to the TC, "sel2(" must appear in
317 ** the text. (We must have found one for SetUnderlyingType()
318 ** above to set underlying_type to sel2.) If all of the above
319 ** is true, we read "sel2" but not the value of sel2. We
320 ** therefore do not pass down what we read to STEPread_content
321 ** below, so that we can still read the value of sel2. If,
322 ** however, under_type was a non-renamed select, no "sel1"
323 ** would appear (according to TC) and we already read the value
324 ** of sel1. If so, we pass the already-read value down.
325 */
326 STEPread_content( in, instances, 0, addFileId, currSch );
327 } else {
328 /**
329 ** In most cases (see above note), we've already read the value
330 ** we're interested in.
331 ** This also handles all other cases? other than the if part
332 ** above and elements of type entity ref?
333 */
334 STEPread_content( in, instances, tmp.c_str(), addFileId,
335 currSch );
336 // STEPread_content uses the ErrorDesc data member from the
337 // SDAI_Select class
338 }
339 err->AppendToDetailMsg( Error() );
340 err->GreaterSeverity( severity() );
341 in >> ws >> c;
342 if( c != ')' ) {
343 err->AppendToDetailMsg(
344 "Bad data or missing closing ')' for SELECT type.\n" );
345 err->GreaterSeverity( SEVERITY_WARNING );
346 in.putback( c );
347 #ifdef SC_LOGGING
348 // *logStream << "DAVE ERR Exiting SDAI_Select::STEPread for " << _type->Name() << endl;
349 #endif
350 return SEVERITY_WARNING;
351 }
352 #ifdef SC_LOGGING
353 // *logStream << "DAVE ERR Exiting SDAI_Select::STEPread for " << _type->Name() << endl;
354 #endif
355 return err->severity();
356 } else { // ERROR -- the type wasn't one of the choices
357 if( !in.good() ) {
358 err->GreaterSeverity( SEVERITY_INPUT_ERROR );
359 #ifdef SC_LOGGING
360 // *logStream << "DAVE ERR Exiting SDAI_Select::STEPread for " << _type->Name() << endl;
361 #endif
362 return SEVERITY_INPUT_ERROR;
363 } else {
364 err->AppendToDetailMsg(
365 "The type name for the SELECT type is not valid.\n" );
366 err->GreaterSeverity( SEVERITY_WARNING );
367 #ifdef SC_LOGGING
368 // *logStream << "DAVE ERR Exiting SDAI_Select::STEPread for " << _type->Name() << endl;
369 #endif
370 return SEVERITY_WARNING;
371 }
372 }
373 }
374 /**
375 ** NOTE **** anything that gets read below here is invalid according to the
376 ** Technical Corrigendum for Part 21 (except for reading an entity instance
377 ** where below is the only place they get read). I am leaving all of this
378 ** here since it is valuable to 'read what you can' and flag an error which
379 ** is what it does (for every type but entity instance refs). DAS 2/4/97
380 */
381
382 else { /// case A
383 switch( c ) {
384 case '$':
385 nullify();
386 err->GreaterSeverity( SEVERITY_INCOMPLETE );
387 #ifdef SC_LOGGING
388 // *logStream << "DAVE ERR Exiting SDAI_Select::STEPread for " << _type->Name() << endl;
389 #endif
390 return SEVERITY_INCOMPLETE;
391
392 case ',':
393 case '\0':
394 // ERROR IN INPUT
395 in.putback( c );
396 err->AppendToDetailMsg( "No value found for SELECT type.\n" );
397 err->GreaterSeverity( SEVERITY_WARNING );
398 #ifdef SC_LOGGING
399 // *logStream << "DAVE ERR Exiting SDAI_Select::STEPread for " << _type->Name() << endl;
400 #endif
401 return SEVERITY_WARNING;
402
403 case '.': // assign enum
404 base_type = ENUM_TYPE;
405 err->AppendToDetailMsg( "Invalid Enumeration, Logical, or Boolean value in SELECT type.\n" );
406 err->GreaterSeverity( SEVERITY_WARNING );
407 break;
408 // set the underlying type
409 // call STEPread
410 // return
411
412 case '\'': // assign string
413 base_type = STRING_TYPE;
414 err->AppendToDetailMsg( "Invalid String value in SELECT type.\n" );
415 err->GreaterSeverity( SEVERITY_WARNING );
416 break;
417
418 case '"': // assign string
419 base_type = BINARY_TYPE;
420 err->AppendToDetailMsg( "Invalid Binary value in SELECT type.\n" );
421 err->GreaterSeverity( SEVERITY_WARNING );
422 break;
423
424 case '#':
425 base_type = ENTITY_TYPE;
426 break;
427 // call STEPread_reference
428 // set the underlying type
429
430 // assign entity
431 // read the reference
432 // match type to underlying type
433 // assign the value
434 // set the underlying type
435
436 case '(': {
437 err->AppendToDetailMsg( "Invalid aggregate value in SELECT type.\n" );
438 err->GreaterSeverity( SEVERITY_WARNING );
439 char n;
440 in >> n;
441 in.putback( n );
442 if( isalpha( n ) ) {
443 base_type = SELECT_TYPE;
444 } else {
445 base_type = AGGREGATE_TYPE;
446 }
447 break;
448 }
449
450 case '0':
451 case '1':
452 case '2':
453 case '3':
454 case '4':
455 case '5':
456 case '6':
457 case '7':
458 case '8':
459 case '9':
460 case '-':
461 err->AppendToDetailMsg( "Invalid Integer or Real value in SELECT type.\n" );
462 err->GreaterSeverity( SEVERITY_WARNING );
463 if( CanBe( REAL_TYPE ) ) {
464 base_type = REAL_TYPE;
465 } else {
466 base_type = INTEGER_TYPE;
467 }
468 break;
469
470 default:
471 // ambiguous - ERROR: underlying type should have been set
472 err->AppendToDetailMsg(
473 "type for SELECT could not be determined from value.\n" );
474 nullify();
475 in.putback( c );
476 err->GreaterSeverity( SEVERITY_WARNING );
477 #ifdef SC_LOGGING
478 // *logStream << "DAVE ERR Exiting SDAI_Select::STEPread for " << _type->Name() << endl;
479 #endif
480 return SEVERITY_WARNING;
481 }
482
483 in.putback( c );
484
485 // now the type descriptor should be derivable from the base_type
486
487 // if it's not issue a warning
488 if( _type && !( IsUnique( base_type ) ) ) {
489 err->AppendToDetailMsg( "Value for SELECT will be assigned to first possible choice.\n" );
490 err->GreaterSeverity( SEVERITY_USERMSG );
491 }
492
493 if( base_type == ENTITY_TYPE ) {
494 // you don't know if this is an ENTITY or a SELECT
495 // have to do this here - not in STEPread_content
496 STEPentity * temp =
497 ReadEntityRef( in, err, ",)", instances, addFileId );
498 if( temp && ( temp != ENTITY_NULL ) && AssignEntity( temp ) ) {
499 #ifdef SC_LOGGING
500 // *logStream << "DAVE ERR Exiting SDAI_Select::STEPread for " << _type->Name() << endl;
501 #endif
502 return SEVERITY_NULL;
503 } else {
504 err->AppendToDetailMsg(
505 "Reference to entity that is not a valid type for SELECT.\n" );
506 nullify();
507 err->GreaterSeverity( SEVERITY_WARNING );
508 #ifdef SC_LOGGING
509 // *logStream << "DAVE ERR Exiting SDAI_Select::STEPread for " << _type->Name() << endl;
510 #endif
511 return SEVERITY_WARNING;
512 }
513 } else if( SetUnderlyingType( CanBe( base_type ) ) ) {
514 STEPread_content( in, instances, 0, addFileId );
515 }
516
517 else { // ERROR -- the type wasn\'t one of the choices
518 err->AppendToDetailMsg(
519 "The type of the SELECT type is not valid.\n" );
520 err->GreaterSeverity( SEVERITY_WARNING );
521 #ifdef SC_LOGGING
522 // *logStream << "DAVE ERR Exiting SDAI_Select::STEPread for " << _type->Name() << endl;
523 #endif
524 return SEVERITY_WARNING;
525 }
526 }
527 // if (!in.good()) severity (SEVERITY_INPUT_ERROR);
528 #ifdef SC_LOGGING
529 // *logStream << "DAVE ERR Exiting SDAI_Select::STEPread for " << _type->Name() << endl;
530 #endif
531 return err->severity();
532 }
533
534
535 /// updated to Technical Corrigendum DAS Feb 4, 1997
STEPwrite(ostream & out,const char * currSch) const536 void SDAI_Select::STEPwrite( ostream & out, const char * currSch ) const {
537 if( !exists() ) {
538 out << "$";
539 return;
540 }
541 switch( underlying_type->NonRefType() ) {
542 case sdaiINSTANCE: {
543 STEPwrite_content( out );
544 break;
545 }
546 case sdaiSELECT: { // The name of a select is never written DAS 1/31/97
547 if( underlying_type->Type() == REFERENCE_TYPE ) {
548 std::string s;
549 out << StrToUpper( underlying_type->Name( currSch ), s ) << "(";
550 STEPwrite_content( out, currSch );
551 out << ")";
552 } else {
553 STEPwrite_content( out, currSch );
554 }
555 break;
556 }
557 case sdaiNUMBER:
558 case sdaiREAL:
559 case sdaiINTEGER:
560 case sdaiSTRING:
561 case sdaiBOOLEAN:
562 case sdaiLOGICAL:
563 case sdaiBINARY:
564 case sdaiENUMERATION:
565 case sdaiAGGR:
566 case ARRAY_TYPE:
567 case BAG_TYPE:
568 case SET_TYPE:
569 case LIST_TYPE: {
570 STEPwrite_verbose( out, currSch );
571 break;
572 }
573 case REFERENCE_TYPE: // this should never happen? DAS
574 default:
575 out << "ERROR Should not have gone here in SDAI_Select::STEPwrite()"
576 << endl;
577 }
578 }
579
STEPwrite_verbose(ostream & out,const char * currSch) const580 void SDAI_Select::STEPwrite_verbose( ostream & out, const char * currSch ) const {
581 std::string tmp;
582 out << StrToUpper( CurrentUnderlyingType()->Name( currSch ), tmp ) << "(";
583 STEPwrite_content( out );
584 out << ")";
585 }
586
STEPwrite(std::string & s,const char * currSch) const587 const char * SDAI_Select::STEPwrite( std::string & s, const char * currSch ) const {
588 ostringstream buf;
589 STEPwrite( buf, currSch );
590 buf << ends; // add the terminating \0 char
591 s = buf.str();
592 return const_cast<char *>( s.c_str() );
593 }
594
set_null()595 int SDAI_Select::set_null() {
596 nullify();
597 return 1;
598 }
599
is_null()600 int SDAI_Select::is_null() {
601 return ( !exists() );
602 }
603