/*****************************************************************************
* multpass.c *
* *
* Description: *
* Adds multi-schema support enhancement to exp2python parser. Allows the *
* generation of C++ representations for multiple EXPRESS schemas without *
* creating conflicting header files. Previously, exp2python would gene- *
* rate a single set of files (.h, .cc, .init.cc) for each schema found in *
* the processed EXPRESS file. A number of problem situations occurred: *
* *
* (1) Two schemas which USE or REFERENCE entities from one another. If *
* e.g. schema A USEs entity 1 from schema B and defines ent 2 subtype *
* of 1, and schema B USEs ent 2 from A and defines ents 1 and 3 sub- *
* type of 2, neither include file could be compiled first. *
* (2) An entity which has a select or enumeration attribute which is de- *
* fined in another schema. *
* (3) A select type which has a select or enum member item which is de- *
* fined in another schema.
* (4) An enumeration type which is a redefinition of an enum defined in *
* another schema. *
* *
* The functions in multpass.c provide for the processing of each schema *
* in multiple passes. At each pass, only entities and types which are *
* not dependent on undefined objects are processed. With each pass, more *
* entities and types become defined and more dependent entities and types *
* will become processable. At each state of processing, a separate set *
* of C++ files is generated. Lastly, multpass processes certain aggre- *
* gate and redefined objects after all the fundamental types are defined. *
* *
* Created by: David Rosenfeld *
* Date: 04/09/97 *
*****************************************************************************/
#include
#include "classes.h"
#define FALSE 0
#define TRUE 1
int isAggregateType( const Type t );
/* Local function prototypes: */
static void initializeMarks( Express );
static void unsetObjs( Schema );
static int checkTypes( Schema );
static int checkEnts( Schema );
static void markDescs( Entity );
static int checkItem( Type, Scope, Schema, int *, int );
static int ENUMcanBeProcessed( Type, Schema );
static int inSchema( Scope, Scope );
/* static void addRenameTypedefs( Schema, FILE * ); */
static void addAggrTypedefs( Schema schema );
static void addUseRefNames( Schema, FILE * );
void print_schemas_separate( Express express, FILES * files )
/*
* Generates the C++ files corresponding to a list of schemas. Does so in
* multiple passes through the schemas. In each pass it checks for enti-
* ties which are subtypes of entities in other schemas which have not yet
* been processed. Such entities cannot be processed in that pass until
* their supertypes have been defined. It also checks for entities which
* have enum or select attributes which have not been processed, and for
* select types which have enum or select items (or entities containing
* enums) which have not been processed.
*/
{
int complete = FALSE, val1, val2, suffix;
DictionaryEntry de;
Schema schema;
/* First set all marks we'll be using to UNPROCESSED/NOTKNOWN: */
initializeMarks( express );
/* FIXME SdaiAll.cc:12:24: warning: unused variable âisâ [-Wunused-variable] (also for ui & ri) */
/* fprintf( files->create, " Interface_spec_ptr is;\n Used_item_ptr ui;\n Referenced_item_ptr ri;\n Uniqueness_rule_ptr ur;\n Where_rule_ptr wr;\n Global_rule_ptr gr;\n" ); */
while( !complete ) {
complete = TRUE;
DICTdo_type_init( express->symbol_table, &de, OBJ_SCHEMA );
while( ( schema = ( Scope )DICTdo( &de ) ) != 0 ) {
if( schema->search_id == UNPROCESSED ) {
/* i.e., if the schema has more ents/types to process in it */
unsetObjs( schema );
/* Unset the ones which had search_id = CANTPROCESS. We're
// going to check that again since things may have changed by
// this pass. The ones with search_id = PROCESSED do not
// change since we're done with them. */
schema->search_id = PROCESSED;
/* We assume this is the case unless something goes wrong. */
val1 = checkTypes( schema );
val2 = checkEnts( schema );
/* The check functions recheck all the ents, types, USEd, and
// REFs which are still NOTKNOWN to see if we can process any
// more this pass. If any returns TRUE, we'll process again
// this round. */
if( val1 || val2 ) {
if( schema->search_id == UNPROCESSED ||
*( int * )schema->clientData > 0 ) {
/* What we're trying to determine here is if we will
// need to print multiple files for this schema. If
// we're already beyond a first file (2nd condition)
// or we're at the first but there are more entities
// which couldn't be processed yet (and thus search_id
// was still set to UNPROCESSED), this schema will be
// printed in multiple files. If so, SCHEMAprint()
// will create files with the suffixes "_1", "_2", etc.
// If not, no file suffix will be added. */
suffix = ++*( int * )schema->clientData;
SCHEMAprint( schema, files, suffix );
} else {
SCHEMAprint( schema, files, 0 );
}
}
complete = complete && ( schema->search_id == PROCESSED );
/* Job's not complete so long as schema still has entities it
// had to skip. */
}
}
}
/*
DICTdo_type_init( express->symbol_table, &de, OBJ_SCHEMA );
while( ( schema = ( Scope )DICTdo( &de ) ) != 0 ) {
//fprintf( files->create,
// "\t//////////////// USE statements\n" );
//USEREFout( schema, schema->u.schema->usedict, schema->u.schema->use_schemas, "USE", files->create );
//fprintf( files->create,
// "\t//////////////// REFERENCE statements\n" );
//USEREFout( schema, schema->u.schema->refdict, schema->u.schema->ref_schemas, "REFERENCE", files->create );
}
*/
/* Before closing, we have three more situations to deal with (i.e., three
// types of declarations etc. which could only be printed at the end).
// Each is explained in the header section of its respective function. */
DICTdo_type_init( express->symbol_table, &de, OBJ_SCHEMA );
while( ( schema = ( Scope )DICTdo( &de ) ) != 0 ) {
/* (These two tasks are totally unrelated but are done in the same loop
// for efficiency.) */
addUseRefNames( schema, files->create );
}
/* Third situation: (Must be dealt with after first, see header comments
// of addAggrTypedefs.) */
DICTdo_type_init( express->symbol_table, &de, OBJ_SCHEMA );
while( ( schema = ( Scope )DICTdo( &de ) ) != 0 ) {
/* addAggrTypedefs( schema, files->classes ); */
addAggrTypedefs( schema );
}
/* On our way out, print the necessary statements to add support for
// complex entities. (The 1st line below is a part of SchemaInit(),
// which hasn't been closed yet. (That's done on 2nd line below.)) * /
//fprintf( files->initall, "\t reg.SetCompCollect( gencomplex() );\n" );
//fprintf( files->initall, "}\n\n" );
//fprintf( files->incall, "\n#include \"core/complexSupport.h\"\n" );
//fprintf( files->incall, "ComplexCollect *gencomplex();\n" ); */
/* Function GetModelContents() is printed at the end of the schema.xx
// files. This is done in a separate loop through the schemas, in function
// below. * /
//getMCPrint( express, files->incall, files->initall ); */
}
/**
* Set all schema->search_id's to UNPROCESSED, meaning we haven't processed
* all the ents and types in it yet. Also, put an int=0 in each schema's
* clientData field. We'll use it to record what # file we're generating
* for each schema. Set all entity and type search_id's to NOTKNOWN mean-
* we don't know if we can process it yet. (An ent & select type may have
* an attribute/item which comes from another schema. All other types can
* be processed the first time, but that will be caught in checkTypes().)
*/
static void initializeMarks( Express express ) {
DictionaryEntry de_sch, de_ent, de_type;
Schema schema;
DICTdo_type_init( express->symbol_table, &de_sch, OBJ_SCHEMA );
while( ( schema = ( Scope )DICTdo( &de_sch ) ) != 0 ) {
schema->search_id = UNPROCESSED;
schema->clientData = ( int * )malloc( sizeof( int ) );
*( int * )schema->clientData = 0;
SCOPEdo_entities( schema, ent, de_ent )
ent->search_id = NOTKNOWN;
SCOPEod
SCOPEdo_types( schema, t, de_type )
t->search_id = NOTKNOWN;
SCOPEod
}
}
/**
* Resets all the ents & types of schema which had been set to CANTPROCRSS
* to NOTKNOWN. This function is called every time print_schemas_separate
* iterates through the schemas, printing to file what can be printed. At
* each pass we re-examine what ents/types can be processed. Ones which
* couldn't be processed at the last pass may be processable now. Ents/
* types which have already been marked PROCESSED will not have to be
* revisited, and are not changed.
*/
static void unsetObjs( Schema schema ) {
DictionaryEntry de;
SCOPEdo_types( schema, t, de )
if( t->search_id == CANTPROCESS ) {
t->search_id = NOTKNOWN;
}
SCOPEod
SCOPEdo_entities( schema, ent, de )
if( ent->search_id == CANTPROCESS ) {
ent->search_id = NOTKNOWN;
}
SCOPEod
}
/**
* Goes through the types contained in this schema checking for ones which
* can't be processed. This may be the case if: (1) We have a select type
* which has enumeration or select items which have not yet been defined
* (are defined in a different schema we haven't processed yet). (2) We
* have a select which has an entity item which contains unprocessed enums.
* (Unproc'ed selects, however, do not pose a problem here for reasons
* beyond the scope.) (3) We have an enum type which is a redefinition of
* an enum not yet defined. If we find any such type, we set its mark to
* CANTPROCESS. If some types in schema *can* be processed now, we return
* TRUE. (See relevant header comments of checkEnts() below.)
*/
static int checkTypes( Schema schema ) {
DictionaryEntry de;
int retval = FALSE, unknowncnt;
Type i;
Entity ent;
Linked_List attribs;
do {
unknowncnt = 0;
SCOPEdo_types( schema, type, de )
if( type->search_id != NOTKNOWN ) {
continue;
}
/* We're only interested in the ones which haven't been processed
// already or accepted (set to CANPROCESS in a previous pass thru
// the do loop) already. */
type->search_id = CANPROCESS;
/* Assume this until disproven. */
if( TYPEis_enumeration( type ) && TYPEget_head( type ) ) {
i = TYPEget_ancestor( type );
if( !sameSchema( i, type ) && i->search_id != PROCESSED ) {
/* Note - if, however, i is in same schema, we're safe: We
// know it'll be processed this pass because enum's are
// always processed on the first pass. (We do have to take
// care to process the original enum before the redefined.
// This is done in SCOPEPrint, in classes_wrapper.cc.) */
type->search_id = CANTPROCESS;
schema->search_id = UNPROCESSED;
}
} else if( TYPEis_select( type ) ) {
LISTdo( SEL_TYPEget_items( type ), ii, Type ) {
if( !TYPEis_entity( ii ) ) {
if( checkItem( ii, type, schema, &unknowncnt, 0 ) ) {
break;
}
/* checkItem does most of the work of determining if
// an item of a select will make the select type un-
// processable. It checks for conditions which would
// make this true and sets values in type, schema, and
// unknowncnt accordingly. (See checkItem's commenting
// below.) It also return TRUE if ii has made type un-
// processable. If so, we break - there's no point
// checking the other items of type any more. */
} else {
/* Check if our select has an entity item which itself
// has unprocessed selects or enums. */
ent = ENT_TYPEget_entity( ii );
if( ent->search_id == PROCESSED ) {
continue;
}
/* If entity has been processed already, things must be
// okay. (Note - but if it hasn't been processed yet we
// may still be able to process type. This is because
// a sel type will only contain a pointer to an entity-
// item (and we can create a pointer to a not-yet-pro-
// cessed object), while it will contain actual objects
// for the enum and select attributes of ent.) */
attribs = ENTITYget_all_attributes( ent );
LISTdo_n( attribs, attr, Variable, b ) {
if( checkItem( attr->type, type, schema,
&unknowncnt, 1 ) ) {
break;
}
} LISTod
LISTfree( attribs );
}
} LISTod
/* One more condition - if we're a select which is a rename of
// another select - we must also make sure the original select
// is in this schema or has been processed. Since a rename-
// select is defined with typedef's to the original, we can't
// do that if the original hasn't been defined. */
if( ( type->search_id == CANPROCESS )
&& ( ( i = TYPEget_ancestor( type ) ) != NULL )
&& ( !sameSchema( i, type ) )
&& ( i->search_id != PROCESSED ) ) {
type->search_id = CANTPROCESS;
schema->search_id = UNPROCESSED;
}
}
if( type->search_id == CANPROCESS ) {
/* NOTE - This condition will be met if type isn't a select or
// enum at all and above if was never entered (and it's our
// first pass so type hasn't been processed). So for non-enums
// and selects, checkTypes() will simply check the type off and
// go on. */
retval = TRUE;
}
SCOPEod
} while( unknowncnt > 0 );
/* We loop to deal with the following situation: Say sel A contains enum B
// as an item, but A appears earlier in the EXPRESS file than B. In such a
// case, we really can process A now since it doesn't depend on anything
// which won't be processed till later. But when we first reach A, item B
// will have value NOTKNOWN, and at the time we won't know if B will be set
// to CANPROCESS when we get to it. To deal with this, checkItem() below
// increments unknowncnt for every item which is in this schema and still
// has search_id = NOTKNOWN. (Not if id = CANTPROCESS, which means we've
// tried already this pass and B still can't be processed.) Here, we keep
// looping until all the unknowns are resolved. (It may take may passes if
// selX has item selY which has item selZ.) (I take all the trouble with
// this so as not to generate mult files in unnecessary cases where e.g.
// the EXPRESS is in a single schema.) */
return retval;
}
static int checkEnts( Schema schema )
/*
* Goes through the entities contained in this schema checking for ones
* which can't be processed. It checks for two situations: (1) If we find
* an entity which is a subtype of a not-yet-processed entity in another
* schema. (2) If an entity has an attribute which is an enumeration or
* select type (which is implemented by exp2python as a C++ class), and the
* enum or select class has not yet been defined. For each entity which
* satisfies one of the above conditions, we set its mark and the marks of
* all its subtype descendents to CANTPROCESS. Later, when C++ files are
* generated for this schema, the ents marked CANTPROCESS will be skipped.
* checkEnts() will return TRUE if there are some ents/types which *can* be
* processed now. This will tell later functions that there are some pro-
* cessable entities at this pass and C++ files should be generated. (Some
* of the inline commenting of checkTypes() is applicable here and is not
* repeated.)
*/
{
DictionaryEntry de;
int retval = FALSE, ignore = 0;
/* Loop through schema's entities: */
SCOPEdo_entities( schema, ent, de )
if( ent->search_id != NOTKNOWN ) {
continue;
}
/* ent->search_id may = CANTPROCESS signifying we've already determined
// that this ent is dependent on an undefined external one. (It got
// its mark already because it was the descendent of a parent entity we
// already checked and rejected.) ent->search_id may = PROCESSED. In
// such a case there of course is also nothing to check now. */
ent->search_id = CANPROCESS;
/* First traverse ent's supertypes. If any is from a different schema
// and is not yet defined, ent will have to wait. */
LISTdo( ENTITYget_supertypes( ent ), super, Entity )
if( ( !sameSchema( ent, super ) )
&& ( super->search_id != PROCESSED ) ) {
markDescs( ent );
schema->search_id = UNPROCESSED;
break;
/* Exit the LISTdo loop. Since we found an unprocessed
// parent, we're done with this entity. */
}
LISTod
/* Next traverse ent's attributes, looking for attributes which are
// not yet defined (more explanation in checkItem()). */
if( ent->search_id == CANPROCESS ) {
/* Only do next test if ent hasn't already failed the 1st. */
LISTdo( ENTITYget_attributes( ent ), attr, Variable )
if( checkItem( attr->type, ent, schema, &ignore, 0 ) ) {
markDescs( ent );
break;
}
LISTod
}
if( ent->search_id == CANPROCESS ) {
/* If ent's mark still = CANPROCESS and not CANTPROCESS, it
// must still be processable. Set retval to TRUE signifying
// that there are ent's we'll be able to process. */
retval = TRUE;
}
SCOPEod
/* NOTE - We don't have to loop here as in checkTypes() (see long comment
// there). It was necessary there because we may have processed type
// sel1 before its member enum1. Whereas here, since all types are done
// before selects (checkTypes() is called before checkEnts()), there is
// no such concern. */
return retval;
}
static void markDescs( Entity ent )
/*
* Sets the mark value of ent and all its subtypes to CANTPROCESS. This
* function is called if we've determined that ent is a subtype of an
* entity defined in a different schema which has not yet been processed.
*/
{
ent->search_id = CANTPROCESS;
LISTdo( ENTITYget_subtypes( ent ), sub, Entity )
markDescs( sub );
LISTod
}
static int checkItem( Type t, Scope parent, Schema schema, int * unknowncnt,
int noSel )
/*
* Function with a lot of side effects: Checks if type t, a member of
* `parent' makes parent unprocessable. parent may be an entity and t is
* its attribute. parent may be a select type and t is one of its items.
* parent may be a select type and t an attribute of one of its entity
* items. Lastly, parent may be an aggregate and t its base type. t will
* make parent unprocessable if it is an enum or sel which hasn't been
* processed yet, see inline commenting. If so, parent->search_id is set
* to CANTPROCESS, and schema->search_id is set to UNPROCESSED (i.e., we're
* not done yet). Also, if one of parent's items is still NOTKNOWN (caused
* if it's in our schema and we haven't gotten to it yet - see comment, end
* of checkTypes()), parent is set to NOTKNOWN and unknowncnt is incremen-
* ted to tell us that we'll have to try parent again after its item has
* been processed (i.e., we have to repeat the do-loop in checkTypes()).
* checkItem returns TRUE if parent became unprocessable; FALSE otherwise.
*
* NOTE: noSel deals with the following: Say selA has member entX. If
* entX has attribute enumP, it creates a problem, while if entX has attr
* selB, it is not. When using checkItem for an ent member of a select,
* noSel is set to 1 to tell it to worry about t if it's an enum but not
* if it's a select.
*/
{
Type i = t;
if( isAggregateType( t ) ) {
i = TYPEget_base_type( t );
/* NOTE - If t is a 2D aggregate or higher, we do not go down to its
// lowest base type. An item which is a higher dimension aggregates
// does not make its parent unprocessable. All an e.g. entity needs
// defined to have a 2D aggr attribute is GenericAggregate (built in)
// and a typedef for a pointer to the type name, which is declared in
// Sdaiclasses.h. */
}
if( TYPEis_enumeration( i ) && !ENUMcanBeProcessed( i, schema ) ) {
/* Enum's are usually processed on the first try. ENUMcanBeProcessed()
// checks for cases of renamed enum's, which must wait for the enum i
// is a rename of. */
if( parent->search_id == NOTKNOWN ) {
/* We had thought parent's val was going to be NOTKNOWN - i.e.,
// dependent on other selects in this schema which haven't been
// processed. When we set it to NOTKNOWN we also incremented
// unknowncnt. Now we see it's not going to be unknown so we
// decrement the count: */
( *unknowncnt )--;
}
parent->search_id = CANTPROCESS;
schema->search_id = UNPROCESSED;
return TRUE;
} else if( TYPEis_select( i ) && !noSel ) {
if( !sameSchema( i, parent ) ) {
if( i->search_id != PROCESSED ) {
if( parent->search_id == NOTKNOWN ) {
( *unknowncnt )--;
}
parent->search_id = CANTPROCESS;
schema->search_id = UNPROCESSED;
return TRUE;
}
} else {
/* We have another sel in the same schema. This gets complicated -
// it may be processable but we just haven't gotten to it yet. So
// we may have to wait on parent. */
if( i->search_id == CANTPROCESS ) {
/* We *have* checked i already and it can't be processed. */
if( parent->search_id == NOTKNOWN ) {
( *unknowncnt )--;
}
parent->search_id = CANTPROCESS;
schema->search_id = UNPROCESSED;
return TRUE;
} else if( i->search_id == NOTKNOWN ) {
/* We haven't processed i this pass. */
if( parent->search_id != NOTKNOWN ) {
parent->search_id = NOTKNOWN;
/* We lower parent's value. But don't return TRUE. That
// would tell checkTypes() that there's nothing more to
// check. But checkTypes should keep looping through the re-
// maining items of parent - maybe one of them will tell us
// that parent definitely can't be processed this pass. */
( *unknowncnt )++;
}
}
}
}
return FALSE;
}
static int ENUMcanBeProcessed( Type e, Schema s )
/*
* Tells us if an enumeration type has been processed already, or if not
* will be processed this pass through schema s. As always, I take great
* pains to avoid breaking up a schema into >1 file unnecessarily. In
* cases where a user is building a library based on a single schema, we
* shouldn't cause him to suffer side-effects of the mult schema support,
* because of a case that "looks like" it may require multiple files.
*/
{
Type a;
if( !inSchema( e, s ) ) {
/* If e is not in s - the schema we're processing now - things are
// fairly simple. Nothing is going to change by the time we finish
// with this schema. Base the return val on whether or not e *was*
// processed already. */
return ( e->search_id == PROCESSED );
}
if( e->search_id != NOTKNOWN ) {
/* Next case: e is in our schema, but either it's been processed
// already, or we've determined that it can or can't be processed.
// This case is also relatively simple - we have nothing more to
// figure out here. */
return ( e->search_id >= CANPROCESS );
/* PROC/CANPROC - TRUE; UNPROC'ED/CANTPROC - FALSE */
}
/* Remaining case: e is in our schema and still = NOTKNOWN. I.e., we
// haven't gotten to e this pass and don't yet know whether it'll be
// processable. Figure that out now: */
if( ( a = TYPEget_ancestor( e ) ) == NULL ) {
/* If e is not a rename of anything, it should be processed now. */
return TRUE;
}
if( inSchema( a, s ) || a->search_id == PROCESSED ) {
/* If e's ancestor (the one it's a rename of) is in our schema it will
// be processed now. If not, it must have been processed already. */
return TRUE;
}
return FALSE;
}
int sameSchema( Scope sc1, Scope sc2 )
/*
* Checks if sc1 and sc2 are in the same superscope. Normally called for
* two types to see if they're in the same schema.
*/
{
return ( !strcmp( SCOPEget_name( sc1->superscope ),
SCOPEget_name( sc2->superscope ) ) );
}
static int inSchema( Scope scope, Scope super )
/*
* Checks if scope is contained in super's scope.
*/
{
return ( !strcmp( SCOPEget_name( scope->superscope ),
SCOPEget_name( super ) ) );
}
static void addAggrTypedefs( Schema schema )
/*
* Print typedefs at the end of Sdiaclasses.h for aggregates of enum's and
* selects. Since the underlying enum/sel may appear in any schema, this
* must be done at the end of all the schemas. Note that this function is
* called after addRenameTypedefs() since an aggregate may also be based on
* one of the renamed enum/sel's defined there.
*/
{
DictionaryEntry de;
Type i;
SCOPEdo_types( schema, t, de )
if( TYPEis_aggregate( t ) ) {
i = TYPEget_base_type( t );
if( TYPEis_enumeration( i ) || TYPEis_select( i ) ) {
/* This if will pass if t was a 1D aggregate only. They are
// the only types which had to wait for their underlying type.
// 2D aggr's and higher only need type GenericAggr defined
// which is built-in. */
printf( "in addAggrTypedefs. %s is enum or select.\n", TYPEget_name( t ) );
/* strncpy( nm, ClassName( TYPEget_name( t ) ), BUFSIZ );
//printf("%s;%s",nm,TYPEget_ctype( t ));
//if( firsttime ) {
// fprintf( classes, "The first TIME\n" );
// firsttime = FALSE;
//}
//fprintf(classes,"in addAggrTypedefs. %s is enum or select.\n",TYPEget_name(t));
//strncpy( nm, ClassName( TYPEget_name( t ) ), BUFSIZ );
//fprintf( classes, "typedef %s\t%s;\n",
// TYPEget_ctype( t ), nm );
//fprintf( classes, "typedef %s *\t%sH;\n", nm, nm );
//fprintf( classes, "typedef %s *\t%s_ptr;\n", nm, nm ); */
}
}
SCOPEod
}
static void addUseRefNames( Schema schema, FILE * create )
/*
* Checks the USE and REFERENCE dicts contained in schema. If either dict
* contains items (types or entities) which are renamed in this schema,
* code is written to add another member to the "altNames" list of the
* corresponding TypeDescriptor or EntityDescriptor object in the SCL. The
* list will be used in the SCL to use the correct name of this type or
* entity when reading and writing files.
*/
{
Dictionary useRefDict;
DictionaryEntry de;
Rename * rnm;
char * oldnm, schNm[BUFSIZ+1];
static int firsttime = TRUE;
if( ( useRefDict = schema->u.schema->usedict ) != NULL ) {
DICTdo_init( useRefDict, &de );
while( ( rnm = ( Rename * )DICTdo( &de ) ) != 0 ) {
oldnm = ( ( Scope )rnm->object )->symbol.name;
if( ( strcmp( oldnm, rnm->nnew->name ) ) ) {
/* strcmp != 0, so old and new names different.
// Note: can't just check if nnew != old. That wouldn't
// catch following: schema C USEs obj Y from schema B
// (not renamed). B USEd it from schema A and renamed it
// from X. nnew would = old, but name would not be same
// as rnm->object's name. */
if( firsttime ) {
fprintf( create, "\t// Alternate names for types and " );
fprintf( create, "entities when used in other schemas:\n" );
firsttime = FALSE;
}
if( rnm->type == OBJ_TYPE ) {
fprintf( create, "\t%s", TYPEtd_name( ( Type )rnm->object ) );
} else {
/* must be an entity */
fprintf( create, "\t%s%s%s",
SCOPEget_name( ( ( Entity )rnm->object )->superscope ),
ENT_PREFIX, ENTITYget_name( ( Entity )rnm->object ) );
}
strcpy( schNm, PrettyTmpName( SCHEMAget_name( schema ) ) );
fprintf( create, "->addAltName( \"%s\", \"%s\" );\n",
schNm, PrettyTmpName( rnm->nnew->name ) );
}
}
}
if( ( useRefDict = schema->u.schema->refdict ) != NULL ) {
DICTdo_init( useRefDict, &de );
while( ( rnm = ( Rename * )DICTdo( &de ) ) != 0 ) {
oldnm = ( ( Scope )rnm->object )->symbol.name;
if( ( strcmp( oldnm, rnm->nnew->name ) ) ) {
if( firsttime ) {
fprintf( create, "\t// Alternate names for types and " );
fprintf( create, "entities when used in other schemas:\n" );
firsttime = FALSE;
}
if( rnm->type == OBJ_TYPE ) {
fprintf( create, "\t%s", TYPEtd_name( ( Type )rnm->object ) );
} else {
fprintf( create, "\t%s%s%s",
SCOPEget_name( ( ( Entity )rnm->object )->superscope ),
ENT_PREFIX, ENTITYget_name( ( Entity )rnm->object ) );
}
strcpy( schNm, PrettyTmpName( SCHEMAget_name( schema ) ) );
fprintf( create, "->addAltName( \"%s\", \"%s\" );\n",
schNm, PrettyTmpName( rnm->nnew->name ) );
}
}
}
}