#include <stdlib.h>
#include <stddef.h>
#include <string.h>

//extern "C"
//{
//}

#include "complexSupport.h"
extern int corba_binding;

/*******************************************************************
** FedEx parser output module for generating C++  class definitions
** December  5, 1989
** release 2 17-Feb-1992
** release 3 March 1993
** release 4 December 1993
** K. C. Morris
**
** Development of FedEx was funded by the United States Government,
** and is not subject to copyright.

*******************************************************************
The conventions used in this binding follow the proposed specification
for the STEP Standard Data Access Interface as defined in document
N350 ( August 31, 1993 ) of ISO 10303 TC184/SC4/WG7.
*******************************************************************/

/*****************************************************************
***   The functions in this file drive the processing of an     **
***   EXPRESS file.                                             **
 **                             **/


void use_ref( Schema, Express, FILES * );

void
create_builtin_type_decl( FILES * files, char * name ) {
    fprintf( files->incall, "extern TypeDescriptor *%s%s_TYPE;\n",
             TD_PREFIX, name );
    /*  fprintf(files->initall,"TypeDescriptor *%s%s_TYPE;\n",*/
    /*      TD_PREFIX,name);*/
}

void
create_builtin_type_defn( FILES * files, char * name ) {
    fprintf( files->initall, "\t%s%s_TYPE = new TypeDescriptor (",
             TD_PREFIX, name );
    fprintf( files->initall, "\"%s\", %s_TYPE, \"%s\");\n",
             PrettyTmpName( name ), StrToUpper( name ), StrToLower( name ) );
}

/******************************************************************
 ** Procedure:  print_file_header
 ** Parameters: const Schema schema - top-level schema being printed
 **     FILE*        file   - file on which to print header
 ** Returns:
 ** Description:  handles file related tasks that need to be done once
 ** at the beginning of processing.
 ** In this case the file schema.h is initiated
 ** Status:  ok 1/15/91
 ******************************************************************/

/*ARGSUSED*/
void
print_file_header( Express express, FILES * files ) {
    FILE * corbafile = 0;
    /*  create file for user to #include the CORBA-generated header file in. */
    if( corba_binding ) {
        if( ( corbafile = fopen( "corbaSchema.h", "w" ) ) == NULL ) {
            printf( "**Error in print_file_header:  unable to create file corbaSchema.h ** \n" );
        }
        fprintf( corbafile,
                 "// #include the idl generated .hh C++ file that defines the code that \n" );
        fprintf( corbafile,
                 "// is turned off in the fedex_plus generated file using #ifdef PART26.\n" );
        fprintf( corbafile, "//#include <your-idl-generated-file.hh>\n\n" );
        fprintf( corbafile, "// #include the osdb_SdaiXX.h file that is generated from fedex_os if \n// you plan to use ObjectStore.\n" );
        fprintf( corbafile, "//#include <osdb_SdaiXX-file.h>\n" );
        fclose( corbafile );
    }

    /*  open file which unifies all schema specific header files
    of input Express source */
    files -> incall = FILEcreate( "schema.h" );

    /* prevent RCS from expanding this! */
    fprintf( files->incall, "/* %cId$ */\n", '$' );

    fprintf( files->incall, "#ifdef SCL_LOGGING\n" );
    fprintf( files->incall, "#include <sys/time.h>\n" );
    fprintf( files->incall, "#endif\n" );

    fprintf( files->incall, "#ifdef __O3DB__\n" );
    fprintf( files->incall, "#include <OpenOODB.h>\n" );
    fprintf( files->incall, "#endif\n\n" );
    fprintf( files->incall, "#include <sdai.h>\n\n" );
    fprintf( files->incall, "\n#include <Registry.h>\n" );
    fprintf( files->incall, "\n#include <STEPaggregate.h>\n" );
    fprintf( files->incall, "\n#include <STEPundefined.h>\n" );
    fprintf( files->incall, "\n#include <ExpDict.h>\n" );
    fprintf( files->incall, "\n#include <STEPattribute.h>\n" );

    fprintf( files->incall, "\n#include <Sdaiclasses.h>\n" );

    fprintf( files->incall, "extern void SchemaInit (Registry &);\n" );
    fprintf( files->incall, "extern void InitSchemasAndEnts (Registry &);\n" );

    files -> initall = FILEcreate( "schema.cc" );
    fprintf( files->initall, "/* %cId$  */ \n", '\044' );
    fprintf( files->initall, "#include <schema.h>\n" );
    fprintf( files-> initall, "class Registry;\n" );

    fprintf( files->initall, "\nvoid\nSchemaInit (Registry & reg)\n{\n" );
    fprintf( files->initall, "\t extern void InitSchemasAndEnts " );
    fprintf( files->initall, "(Registry & r);\n" );
    fprintf( files->initall, "\t InitSchemasAndEnts (reg);\n" );

    // This file will contain instantiation statements for all the schemas and
    // entities in the express file.  (They must all be in separate function
    // called first by SchemaInit() so that all entities will exist
    files -> create = FILEcreate( "SdaiAll.cc" );
    fprintf( files->create, "/* %cId$  */ \n", '\044' );
    fprintf( files->create, "#include <schema.h>\n" );
    fprintf( files->create, "\nvoid\nInitSchemasAndEnts (Registry & reg)\n{\n" );

    // This file declares all entity classes as incomplete types.  This will
    // allow all the .h files to reference all .h's.  We can then have e.g.,
    // entX from schemaA have attribute attr1 = entY from schemaB.
    files -> classes = FILEcreate( "Sdaiclasses.h" );
    fprintf( files->classes, "/* %cId$  */ \n", '$' );
    fprintf( files->classes, "#include <schema.h>\n" );

    /* create built-in types */
    /*  no need to generate
        create_builtin_type_decl(files,"INTEGER");
        create_builtin_type_decl(files,"REAL");
        create_builtin_type_decl(files,"STRING");
        create_builtin_type_decl(files,"BINARY");
        create_builtin_type_decl(files,"BOOLEAN");
        create_builtin_type_decl(files,"LOGICAL");
        create_builtin_type_decl(files,"NUMBER");
        create_builtin_type_decl(files,"GENERIC");
    */
    /* create built-in types */
    /*  no need to generate
        create_builtin_type_defn(files,"INTEGER");
        create_builtin_type_defn(files,"REAL");
        create_builtin_type_defn(files,"STRING");
        create_builtin_type_defn(files,"BINARY");
        create_builtin_type_defn(files,"BOOLEAN");
        create_builtin_type_defn(files,"LOGICAL");
        create_builtin_type_defn(files,"NUMBER");
        create_builtin_type_defn(files,"GENERIC");
    */

}

/******************************************************************
 ** Procedure:  print_file_trailer
 ** Parameters: const Schema schema - top-level schema printed
 **     FILE*        file   - file on which to print trailer
 ** Returns:
 ** Description:  handles cleaning up things at end of processing
 ** Status:  ok 1/15/91
 ******************************************************************/

/*ARGSUSED*/
void
print_file_trailer( Express express, FILES * files ) {
    FILEclose( files->incall );
    FILEclose( files->initall );
    fprintf( files->create, "}\n\n" );
    FILEclose( files->create );
    fprintf( files->classes, "\n" );
    FILEclose( files->classes );
}

/******************************************************************
 **  SCHEMA SECTION                      **/

/******************************************************************
 ** Procedure:  SCOPEPrint
 ** Parameters: const Scope scope   - scope to print
 **     FILE*       file    - file on which to print
 ** Returns:
 ** Description:  cycles through the scopes of the input Express schema
 ** Side Effects:  calls functions for processing entities and types
 ** Status:  working 1/15/91
 ** --  it's still not clear how include files should be organized
 ** and what the relationship is between this organization and the
 ** organization of the schemas in the input Express
 ******************************************************************/

void
SCOPEPrint( Scope scope, FILES * files, Schema schema, Express model,
            ComplexCollect * col, int cnt ) {
    Linked_List list = SCOPEget_entities_superclass_order( scope );
    DictionaryEntry de;
    Type i;
    int redefs = 0, index = 0;

    if( cnt <= 1 ) {
        /* This will be the case if this is the first time we are generating a
        ** file for this schema.  (cnt = the file suffix.  If it = 1, it's the
        ** first of multiple; if it = 0, it's the only one.)  Basically, this
        ** if generates all the files which are not divided (into _1, _2 ...)
        ** during multiple passes.  This includes Sdaiclasses.h, SdaiAll.cc,
        ** and the Sdaixxx.init.cc files. */

        fprintf( files -> lib, "\nSchema *%s%s =0;\n",
                 SCHEMA_PREFIX, SCHEMAget_name( schema ) );

        /* Not sure why needed - DAR
            fprintf (files -> inc, "\nclass SdaiModel_contents_%s;\n",
             SCHEMAget_name(schema)); */

        /* Do \'new\'s for types descriptors (in SdaiAll.cc (files->create)),
           and the externs typedefs, and incomplete descriptors (in Sdai-
           classes.h (files->classes)). */
        fprintf( files->create, "\n\t//\t*****  Initialize the Types\n" );
        fprintf( files->classes, "\n// Types:\n" );
        SCOPEdo_types( scope, t, de )
        TYPEprint_new( t, files->create, schema );
        TYPEprint_typedefs( t, files->classes );
        SCOPEod;

        /* do \'new\'s for entity descriptors  */
        fprintf( files->create, "\n\t//\t*****  Initialize the Entities\n" );
        fprintf( files->classes, "\n// Entities:" );
        LISTdo( list, e, Entity );
        /* Print in include file: class forward prototype, class typedefs,
           and extern EntityDescriptor.  (ENTITYprint_new() combines the
           functionality of TYPEprint_new() & print_typedefs() above.) */
        ENTITYprint_new( e, files, schema,
                         col->externMapping( ENTITYget_name( e ) ) );
        LISTod;
        fprintf( files->create, "\n" );

        // Write the SdaixxxInit() fn (in .init.cc file):
        //    Do the types:
        SCOPEdo_types( scope, t, de )
        TYPEprint_init( t, files->init, schema );
        SCOPEod;
        //    (The entities are done as a part of ENTITYPrint() below.)
    }

    /* fill in the values for the type descriptors */
    /* and print the enumerations */
    fprintf( files -> inc, "\n/*\t**************  TYPES  \t*/\n" );
    fprintf( files -> lib, "\n/*\t**************  TYPES  \t*/\n" );
    SCOPEdo_types( scope, t, de )
    // First check for one exception:  Say enumeration type B is defined
    // to be a rename of enum A.  If A is in this schema but has not been
    // processed yet, we must wait till it's processed first.  The reason
    // is because B will basically be defined with a couple of typedefs to
    // the classes which represent A.  (To simplify, we wait even if A is
    // in another schema, so long as it's been processed.)
    if( ( t->search_id == CANPROCESS )
            && ( TYPEis_enumeration( t ) )
            && ( ( i = TYPEget_ancestor( t ) ) != NULL )
            && ( i->search_id >= CANPROCESS ) ) {
        redefs = 1;
    }
    SCOPEod

    SCOPEdo_types( scope, t, de )
    // Do the non-redefined enumerations:
    if( ( t->search_id == CANPROCESS )
            && !( TYPEis_enumeration( t ) && TYPEget_head( t ) ) ) {
        TYPEprint_descriptions( t, files, schema );
        if( !TYPEis_select( t ) ) {
            // Selects have a lot more processing and are done below.
            t->search_id = PROCESSED;
        }
    }
    SCOPEod;

    if( redefs ) {
        // Here we process redefined enumerations.  See note, 2 loops ago.
        fprintf( files->inc, "//    ***** Redefined Enumerations:\n" );
        SCOPEdo_types( scope, t, de )
        if( t->search_id == CANPROCESS && TYPEis_enumeration( t ) ) {
            TYPEprint_descriptions( t, files, schema );
            t->search_id = PROCESSED;
        }
        SCOPEod;
    }

    /*  do the select definitions next, since they depend on the others  */
    fprintf( files->inc, "\n//\t***** Build the SELECT Types  \t\n" );
    // Note - say we have sel B, rename of sel A (as above by enum's).  Here
    // we don't have to worry about printing B before A.  This is checked in
    // TYPEselect_print().
    SCOPEdo_types( scope, t, de )
    if( t->search_id == CANPROCESS ) {
        // Only selects haven't been processed yet and may still be set to
        // CANPROCESS.
        TYPEselect_print( t, files, schema );
        t->search_id = PROCESSED;
    }
    SCOPEod;

    fprintf( files -> inc, "\n/*\t**************  ENTITIES  \t*/\n" );
    fprintf( files -> lib, "\n/*\t**************  ENTITIES  \t*/\n" );

    fprintf( files->inc, "\n//\t***** Print Entity Classes  \t\n" );
    LISTdo( list, e, Entity );
    if( e->search_id == CANPROCESS ) {
        ENTITYPrint( e, files, schema );
        e->search_id = PROCESSED;
    }
    LISTod;

    if( cnt <= 1 ) {
        // Do the model stuff:
        fprintf( files->inc, "\n//\t***** generate Model related pieces\n" );
        fprintf( files->inc,
                 "\nclass SdaiModel_contents_%s : public SCLP23(Model_contents) {\n",
                 SCHEMAget_name( schema ) );
        fprintf( files -> inc, "\n  public:\n" );
        fprintf( files -> inc, "    SdaiModel_contents_%s();\n",
                 SCHEMAget_name( schema ) );
        LISTdo( list, e, Entity );
        MODELprint_new( e, files, schema );
        LISTod;

        fprintf( files->inc, "\n};\n" );

        fprintf( files->inc, "\n\ntypedef SdaiModel_contents_%s * SdaiModel_contents_%s_ptr;\n", SCHEMAget_name( schema ), SCHEMAget_name( schema ) );
        fprintf( files->inc, "typedef SdaiModel_contents_%s_ptr SdaiModel_contents_%s_var;\n", SCHEMAget_name( schema ), SCHEMAget_name( schema ) );

        fprintf( files -> inc,
                 "SCLP23(Model_contents_ptr) create_SdaiModel_contents_%s();\n",
                 SCHEMAget_name( schema ) );
        fprintf( files -> lib,
                 "\nSCLP23(Model_contents_ptr) create_SdaiModel_contents_%s()\n",
                 SCHEMAget_name( schema ) );
        fprintf( files -> lib, "{ return new SdaiModel_contents_%s ; }\n",
                 SCHEMAget_name( schema ) );

        fprintf( files -> lib, "\nSdaiModel_contents_%s::SdaiModel_contents_%s()\n",
                 SCHEMAget_name( schema ), SCHEMAget_name( schema ) );
        fprintf( files -> lib,
                 "{\n    SCLP23(Entity_extent_ptr) eep = (SCLP23(Entity_extent_ptr))0;\n\n" );
        LISTdo( list, e, Entity );
        MODELPrintConstructorBody( e, files, schema );
        LISTod;
        fprintf( files -> lib, "}\n" );
        index = 0;
        LISTdo( list, e, Entity );
        MODELPrint( e, files, schema, index );
        index++;
        LISTod;
    }

    LISTfree( list );

#if following_should_be_done_in_caller
    list = SCOPEget_schemata( scope );
    fprintf( files -> inc, "\n/*\t**************  SCOPE  \t*/\n" );
    fprintf( files -> lib, "\n/*\t**************  SCOPE  \t*/\n" );

    LISTdo( list, s, Schema )
    sprintf( nm, "%s%s", SCHEMA_PREFIX, SCHEMAget_name( s ) );
    fprintf( files->inc, "//	\t include definitions for %s \n", nm );
    fprintf( files->inc, "#include <%s.h> \n", nm );
#if 0
    l = SCOPEget_imports( s );
    fprintf( files -> inc, "/*  the following are *assumed* in the express schema  */\n" );
    LISTdo( l, s, Schema )
    fprintf( files -> inc, "/*  include definitions for %s  */\n",
             nm = ClassName( SCHEMAget_name( s ) ) );
    /*            fprintf (files -> inc, "#include <%s.h> \n", nm);*/
    LISTod;
#endif

    LISTod;
#endif

#if 0
    use_ref( schema, model, files );
#endif
}


void
PrintModelContentsSchema( Scope scope, FILES * files, Schema schema,
                          Express model ) {
    Linked_List list;
    char nm[BUFSIZ];
    DictionaryEntry de;

    fprintf( files -> inc, "\n/*\t**************  TYPES  \t*/\n" );
    fprintf( files -> lib, "\n/*\t**************  TYPES  \t*/\n" );
    fprintf( files -> init, "\n/*\t**************  TYPES  \t*/\n" );

    /* do \'new\'s for types descriptors  */
    SCOPEdo_types( scope, t, de )
    TYPEprint_new( t, files->create, schema );
    SCOPEod;

    /* do \'new\'s for entity descriptors  */
    list = SCOPEget_entities_superclass_order( scope );
    fprintf( files->init, "\n\t//\t*****  Describe the Entities  \t*/\n" );
    fprintf( files->inc, "\n//\t***** Describe the Entities  \t\n" );
    LISTdo( list, e, Entity );
    ENTITYput_superclass( e ); /*  find supertype to use for single  */
    ENTITYprint_new( e, files, schema, 0 );         /*  inheritance  */
    LISTod;

    /*  fill in the values for the type descriptors */
    /*  and print the enumerations  */
    fprintf( files->inc, "\n//\t***** Describe the Other Types  \t\n" );
    SCOPEdo_types( scope, t, de )
    TYPEprint_descriptions( t, files, schema );
    if( TYPEis_select( t ) ) {
        /*   do the select aggregates here  */
        strncpy( nm, SelectName( TYPEget_name( t ) ), BUFSIZ );
        fprintf( files->inc, "class %s;\ntypedef %s * %sH;\n", nm, nm, nm );
        fprintf( files->inc,
                 "typedef %s * %s_ptr;\ntypedef %s_ptr %s_var;\n\n",
                 nm, nm, nm, nm );
        fprintf( files->inc, "class %ss;\ntypedef %ss * %ssH;\n", nm, nm, nm );
        fprintf( files->inc,
                 "typedef %ss * %ss_ptr;\ntypedef %ss_ptr %ss_var;\n\n",
                 nm, nm, nm, nm );
    }
    SCOPEod;

    /*  build the typedefs  */
    SCOPEdo_types( scope, t, de )
    if( !( TYPEis_select( t ) ) ) {
        TYPEprint_typedefs( t, files ->inc );
    }
    SCOPEod;

    /*  do the select definitions next, since they depend on the others  */
    fprintf( files->inc, "\n//\t***** Build the SELECT Types  \t\n" );
    fprintf( files->init, "\n//\t***** Add the TypeDescriptor's to the"
             " SELECT Types  \t\n" );
    SCOPEdo_types( scope, t, de )
    if( TYPEis_select( t ) ) {
        TYPEselect_print( t, files, schema );
    }
    SCOPEod;

    fprintf( files -> inc, "\n/*\t**************  ENTITIES  \t*/\n" );
    fprintf( files -> lib, "\n/*\t**************  ENTITIES  \t*/\n" );

    fprintf( files->inc, "\n//\t***** Print Entity Classes  \t\n" );
    LISTdo( list, e, Entity );
    ENTITYPrint( e, files, schema );
    LISTod;
    LISTfree( list );

#if following_should_be_done_in_caller
    list = SCOPEget_schemata( scope );
    fprintf( files -> inc, "\n/*\t**************  SCOPE  \t*/\n" );
    fprintf( files -> lib, "\n/*\t**************  SCOPE  \t*/\n" );

    LISTdo( list, s, Schema )
    sprintf( nm, "%s%s", SCHEMA_PREFIX, SCHEMAget_name( s ) );
    fprintf( files->inc, "//	\t include definitions for %s \n", nm );
    fprintf( files->inc, "#include <%s.h> \n", nm );
#if 0
    l = SCOPEget_imports( s );
    fprintf( files -> inc, "/*  the following are *assumed* in the express schema  */\n" );
    LISTdo( l, s, Schema )
    fprintf( files -> inc, "/*  include definitions for %s  */\n",
             nm = ClassName( SCHEMAget_name( s ) ) );
    /*            fprintf (files -> inc, "#include <%s.h> \n", nm);*/
    LISTod;
#endif

    LISTod;
#endif

}

#if 0
/* simulate USE/REFERENCE by creating links */
/* assignments have to be done after all initializations above */
void
use_ref( Schema schema, Express model, FILES * files ) {
    DictionaryEntry de;
    Rename * r;

    DICTdo_init( schema->u.schema->usedict, &de );
    while( 0 != ( r = ( Rename * )DICTdo( &de ) ) ) {

    }

    DICTdo_init( schema->u.schema->refdict, &de );
    while( 0 != ( r = ( Rename * )DICTdo( &de ) ) ) {

    }

    LISTdo( schema->u.schema->uselist, r, Rename * )
    LISTod

    LISTdo( schema->u.schema->reflist, r, Rename * )
    LISTod
}
#endif

/******************************************************************
 ** Procedure:  SCHEMAprint
 ** Parameters: const Schema schema - schema to print
 **     FILES *file     - file on which to print
 **             Express model       - fedex rep of entire EXPRESS file
 **             ComplexCollect col  - all the complex entity info pertaining
 **                                   to this EXPRESS file
 **             int suffix          - suffix to use for generated cc files
 ** Returns:
 ** Description:  handles initialization of files specific to schemas
 ** Side Effects:
 ** Status:
 ******************************************************************/

void
SCHEMAprint( Schema schema, FILES * files, Express model, void * complexCol,
             int suffix ) {
    char schnm[MAX_LEN], sufnm[MAX_LEN], fnm[MAX_LEN], *np;
    /* sufnm = schema name + suffix */
    FILE * libfile,
         *incfile,
         *schemafile = files->incall,
          *schemainit = files->initall,
            *initfile,
            *createall = files->create;
    Rule r;
    Function f;
    Procedure p;
    DictionaryEntry de;
    char * tmpstr = 0;
    unsigned int tmpstr_size = 0;
    /**********  create files based on name of schema   ***********/
    /*  return if failure           */
    /*  1.  header file             */
    sprintf( schnm, "%s%s", SCHEMA_FILE_PREFIX,
             StrToUpper( SCHEMAget_name( schema ) ) );
    if( suffix == 0 ) {
        sprintf( sufnm, "%s", schnm );
    } else {
        sprintf( sufnm, "%s_%d", schnm, suffix );
    }
    sprintf( fnm, "%s.h", sufnm );

    if( !( incfile = ( files -> inc ) = FILEcreate( fnm ) ) ) {
        return;
    }
    fprintf( incfile, "/* %cId$  */\n", '\044' );

    fprintf( incfile, "#ifdef __O3DB__\n" );
    fprintf( incfile, "#include <OpenOODB.h>\n" );
    fprintf( incfile, "#endif\n\n" );
    fprintf( incfile,
             "#ifndef  SCHEMA_H\n"
             "#include <schema.h>\n"
             "#endif\n" );
    fprintf( incfile,
             "\n#ifdef PART26\n"
             "#include <corbaIncludes.h> \n"
             "// Create a corbaSchema.h file in this directory with a #include in \n"
             "// it for your IDL generated schema-specific .hh file.\n"
             "#include <corbaSchema.h> \n"
             "#endif \n" );

    /*    Generate local to SCHEMA.init.cc file  */
    /*    fprintf(incfile,"Schema *%s%s;\n",*/
    /*      SCHEMA_PREFIX,SCHEMAget_name(schema));*/

    /*    fprintf (incfile, "extern void %sInit (Registry & r);\n", schnm);*/
    /*    fprintf (incfile, "extern void SchemaInit (Registry & r);\n");*/

    np = fnm + strlen( fnm ) - 1; /*  point to end of constant part of string  */

    /*  2.  class source file            */
    sprintf( np, "cc" );
    if( !( libfile = ( files -> lib ) = FILEcreate( fnm ) ) ) {
        return;
    }
    fprintf( libfile, "/* %cId$  */ \n", '$' );
#ifdef SCHEMA_HANDLING
    sprintf( np, "h" );
    fprintf( libfile, "#ifndef  %s\n", StrToConstant( sufnm ) );
    fprintf( libfile, "#include <%s.h> \n", sufnm );
    fprintf( libfile, "#endif" );
#else
    fprintf( libfile,
             "#ifndef  SCHEMA_H \n"
             "#include <schema.h> \n"
             "#endif \n" );
#endif
    fprintf( libfile,
             "\n#ifdef  SCL_LOGGING \n"
             "#include <fstream.h>\n"
             "    extern ofstream *logStream;\n"
             "#define SCLLOGFILE \"scl.log\"\n"
             "#endif \n" );

    fprintf( libfile, "\nstatic int debug_access_hooks = 0;\n" );
    fprintf( libfile, "\n#ifdef PART26\n" );
    fprintf( libfile, "\nconst char * sclHostName = CORBA::Orbix.myHost(); // Default is local host\n" );
    fprintf( libfile, "#endif\n" );

    /*  3.  source code to initialize entity registry   */
    /*  prints header of file for input function    */

    if( suffix <= 1 ) {
        /* I.e., if this is our first pass with schema */
        sprintf( fnm, "%s.init.cc", schnm );
        /* Note - We use schnm (without the "_x" suffix sufnm has) since we
        ** only generate a single init.cc file. */
        if( !( initfile = ( files -> init ) = FILEcreate( fnm ) ) ) {
            return;
        }
        /* prevent RCS from expanding this! */
        fprintf( initfile, "/* $Id%c */\n", '$' );
#ifdef SCHEMA_HANDLING
        if( suffix == 0 ) {
            fprintf( initfile, "#include <%s.h>\n", schnm );
        } else {
            fprintf( initfile, "#include <%s_%d.h>\n", schnm, suffix );
        }
#else
        fprintf( initfile,
                 "#ifndef  SCHEMA_H\n"
                 "#include <schema.h>\n"
                 "#endif\n" );
#endif
        fprintf( initfile, "#include <Registry.h>\n" );

        fprintf( initfile, "void \n%sInit (Registry& reg)\n{\n", schnm );
        fprintf( createall, "\t// Schema:  %s\n", schnm );
        fprintf( createall,
                 "\t%s%s = new Schema(\"%s\");\n",
                 SCHEMA_PREFIX, SCHEMAget_name( schema ),
                 PrettyTmpName( SCHEMAget_name( schema ) ) );

        /* Add the SdaiModel_contents_<schema_name> class constructor to the
           schema descriptor create function for it */
        fprintf( createall,
                 "\t%s%s->AssignModelContentsCreator(\n\t\t\t"
                 "(ModelContentsCreator) create_SdaiModel_contents_%s);\n",
                 SCHEMA_PREFIX, SCHEMAget_name( schema ), SCHEMAget_name( schema ) );

        fprintf( createall, "\treg.AddSchema (*%s%s);\n",
                 SCHEMA_PREFIX, SCHEMAget_name( schema ) );
        /**************/
        /* add global RULEs to Schema dictionary entry */
        DICTdo_type_init( schema->symbol_table, &de, OBJ_RULE );
        while( 0 != ( r = ( Rule )DICTdo( &de ) ) ) {
            if( tmpstr_size < ( strlen( RULEto_string( r ) ) * 2 ) ) {
                if( tmpstr != 0 ) {
                    free( tmpstr );
                }
                tmpstr_size = strlen( RULEto_string( r ) ) * 2;
                tmpstr = ( char * )malloc( sizeof( char ) * tmpstr_size );
                tmpstr[0] = '\0';
                /*      printf("malloc'd: %d\n",tmpstr_size);*/
            }
            /*
            */
            fprintf( createall,
                     "\tgr = new Global_rule(\"%s\",%s%s,\"%s\");\n",
                     r->symbol.name,
                     SCHEMA_PREFIX, SCHEMAget_name( schema ),
                     format_for_stringout( RULEto_string( r ), tmpstr ) );
            fprintf( createall,
                     "\t%s%s->AddGlobal_rule(gr);\n",
                     SCHEMA_PREFIX, SCHEMAget_name( schema ) );
            fprintf( createall, "/*\n%s\n*/\n", RULEto_string( r ) );
#if 0
            fprintf( createall, "/*\n\"%s\"\n*/\n", format_for_stringout( RULEto_string( r ), tmpstr ) );
#endif
        }
        /**************/
        /* add FUNCTIONs to Schema dictionary entry */
        DICTdo_type_init( schema->symbol_table, &de, OBJ_FUNCTION );
        while( 0 != ( f = ( Function )DICTdo( &de ) ) ) {
            if( tmpstr_size < ( strlen( FUNCto_string( f ) ) * 2 ) ) {
                if( tmpstr != 0 ) {
                    free( tmpstr );
                }
                tmpstr_size = strlen( FUNCto_string( f ) ) * 2;
                tmpstr = ( char * )malloc( sizeof( char ) * tmpstr_size );
                /*      printf("malloc'd: %d\n",tmpstr_size);*/
            }
            /*      printf("tmpstr: %d\nfunc: %d\n",tmpstr_size,strlen(FUNCto_string(f)) );*/
            fprintf( createall,
                     "#ifndef MSWIN\n\t%s%s->AddFunction(\"%s\");\n#endif\n",
                     SCHEMA_PREFIX, SCHEMAget_name( schema ),
                     format_for_stringout( FUNCto_string( f ), tmpstr ) );
            fprintf( createall, "/*\n%s\n*/\n", FUNCto_string( f ) );
#if 0
            fprintf( createall, "/*\n\"%s\"\n*/\n", format_for_stringout( FUNCto_string( f ), tmpstr ) );
#endif
        }
        /*  if(tmpstr_size > 0) free(tmpstr); */

        /* add PROCEDUREs to Schema dictionary entry */
        DICTdo_type_init( schema->symbol_table, &de, OBJ_PROCEDURE );
        while( 0 != ( p = ( Procedure )DICTdo( &de ) ) ) {
            if( tmpstr_size < ( strlen( PROCto_string( p ) ) * 2 ) ) {
                if( tmpstr != 0 ) {
                    free( tmpstr );
                }
                tmpstr_size = strlen( PROCto_string( p ) ) * 2;
                tmpstr = ( char * )malloc( sizeof( char ) * tmpstr_size );
            }
            fprintf( createall,
                     "#ifndef MSWIN\n\t%s%s->AddProcedure(\"%s\");\n#endif\n",
                     SCHEMA_PREFIX, SCHEMAget_name( schema ),
                     format_for_stringout( PROCto_string( p ), tmpstr ) );
            fprintf( createall, "/*\n%s\n*/\n", PROCto_string( p ) );
        }
        if( tmpstr_size > 0 ) {
            free( tmpstr );
        }

        fprintf( files->classes, "\n// Schema:  %s", schnm );
        fprintf( files->classes,
                 "\nextern Schema *  %s%s;\n",
                 SCHEMA_PREFIX, SCHEMAget_name( schema ) );
    } else {
        /* Just reopen the .init.cc (in append mode): */
        sprintf( fnm, "%s.init.cc", schnm );
        initfile = files->init = fopen( fnm, "a" );
    }

    /**********  record in files relating to entire input   ***********/

    /*  add to schema's include and initialization file */
    fprintf( schemafile, "#include <%s.h> \n", sufnm );
    if( schema->search_id == PROCESSED ) {
        fprintf( schemafile, "extern void %sInit (Registry & r);\n", schnm );
        fprintf( schemainit, "\t extern void %sInit (Registry & r);\n", schnm );
        fprintf( schemainit, "\t %sInit (reg); \n", schnm );
    }

    /**********  do the schemas ***********/

    /* really, create calls for entity constructors */
    SCOPEPrint( schema, files, schema, model, ( ComplexCollect * )complexCol,
                suffix );

#if 0
    /* create calls for connecting sub/supertypes */
    STypePrint( schema, files, schema );
#endif

    /**********  close the files    ***********/
    FILEclose( libfile );
    FILEclose( incfile );
    if( schema->search_id == PROCESSED ) {
        fprintf( initfile, "\n}\n" );
        FILEclose( initfile );
    } else {
        fclose( initfile );
    }
}

/******************************************************************
 ** Procedure:  getMCPrint
 ** Parameters:
       Express express   - in memory representation of an express model
       FILE*   schema_h  - generated schema.h file
       FILE*   schema_cc - schema.cc file
 ** Returns:
 ** Description:  drives functions to generate code for all the schemas
 ** in an Express model into one set of files  -- works with
 **     print_schemas_combined
 ** Side Effects:  generates code
 ** Status:  24-Feb-1992 new -kcm
 ******************************************************************/
void
getMCPrint( Express express, FILE * schema_h, FILE * schema_cc ) {
    DictionaryEntry de;
    Schema schema;

    fprintf( schema_h,
             "\nSCLP23(Model_contents_ptr) GetModelContents(char *schemaName);\n" );
    fprintf( schema_cc, "%s%s%s%s",
             "// Generate a function to be called by Model to help it\n",
             "// create the necessary Model_contents without the\n",
             "// dictionary (Registry) handle since it doesn't have a\n",
             "// predetermined way to access to the handle.\n" );
    fprintf( schema_cc,
             "\nSCLP23(Model_contents_ptr) GetModelContents(char *schemaName)\n{\n" );
    DICTdo_type_init( express->symbol_table, &de, OBJ_SCHEMA );
    schema = ( Scope )DICTdo( &de );
    fprintf( schema_cc,
             "    if(!strcmp(schemaName, \"%s\"))\n",
             SCHEMAget_name( schema ) );
    fprintf( schema_cc,
             "        return (SCLP23(Model_contents_ptr)) new SdaiModel_contents_%s; \n",
             SCHEMAget_name( schema ) );
    while( ( schema = ( Scope )DICTdo( &de ) ) != 0 ) {
        fprintf( schema_cc,
                 "    else if(!strcmp(schemaName, \"%s\"))\n",
                 SCHEMAget_name( schema ) );
        fprintf( schema_cc,
                 "        return (SCLP23(Model_contents_ptr)) new SdaiModel_contents_%s; \n",
                 SCHEMAget_name( schema ) );
    }
    fprintf( schema_cc, "}\n" );
}

/******************************************************************
 ** Procedure:  EXPRESSPrint
 ** Parameters:
       Express express -- in memory representation of an express model
       FILES* files  -- set of output files to print to
 ** Returns:
 ** Description:  drives functions to generate code for all the schemas
 ** in an Express model into one set of files  -- works with
 **     print_schemas_combined
 ** Side Effects:  generates code
 ** Status:  24-Feb-1992 new -kcm
 ******************************************************************/
void
EXPRESSPrint( Express express, ComplexCollect & col, FILES * files ) {
    char fnm [MAX_LEN], *np;
    const char  * schnm;  /* schnm is really "express name" */
    FILE * libfile;
    FILE * incfile;
    FILE * schemafile = files -> incall;
    FILE * schemainit = files -> initall;
    FILE * initfile;
    /* new */
    Schema schema;
    DictionaryEntry de;


    /**********  create files based on name of schema   ***********/
    /*  return if failure           */
    /*  1.  header file             */
    sprintf( fnm, "%s.h", schnm = ClassName( EXPRESSget_basename( express ) ) );
    if( !( incfile = ( files -> inc ) = FILEcreate( fnm ) ) ) {
        return;
    }
    fprintf( incfile, "/* %cId$ */\n", '$' );

    fprintf( incfile, "#ifdef __O3DB__\n" );
    fprintf( incfile, "#include <OpenOODB.h>\n" );
    fprintf( incfile, "#endif\n\n" );
    fprintf( incfile, "#include <sdai.h> \n" );
    /*    fprintf (incfile, "#include <schema.h> \n");*/
    /*    fprintf (incfile, "extern void %sInit (Registry & r);\n", schnm);*/

    np = fnm + strlen( fnm ) - 1; /*  point to end of constant part of string  */

    /*  2.  class source file            */
    sprintf( np, "cc" );
    if( !( libfile = ( files -> lib ) = FILEcreate( fnm ) ) ) {
        return;
    }
    fprintf( libfile, "/* %cId$ */\n", '$' );
    fprintf( libfile, "#include <%s.h> n", schnm );

    /*  3.  source code to initialize entity registry   */
    /*  prints header of file for input function    */

    sprintf( np, "init.cc" );
    if( !( initfile = ( files -> init ) = FILEcreate( fnm ) ) ) {
        return;
    }
    fprintf( initfile, "/* $Id%d */\n", '$' );
    fprintf( initfile, "#include <%s.h>\n\n", schnm );
    fprintf( initfile, "void \n%sInit (Registry& reg)\n{\n", schnm );

    /**********  record in files relating to entire input   ***********/

    /*  add to schema's include and initialization file */
    fprintf( schemafile, "#include <%s.h>\n\n", schnm );
    fprintf( schemafile, "extern void %sInit (Registry & r);\n", schnm );
    fprintf( schemainit, "\t extern void %sInit (Registry & r);\n", schnm );
    fprintf( schemainit, "\t %sInit (reg);\n", schnm );

    /**********  do all schemas ***********/
    DICTdo_init( express->symbol_table, &de );
    while( 0 != ( schema = ( Scope )DICTdo( &de ) ) ) {
        SCOPEPrint( schema, files, schema, express, &col, 0 );
    }


    /**********  close the files    ***********/
    FILEclose( libfile );
    FILEclose( incfile );
    fprintf( initfile, "\n}\n" );
    FILEclose( initfile );

}

/******************************************************************
 ** Procedure:  print_schemas_combined
 ** Parameters:
       Express express -- in memory representation of an express model
       FILES* files  -- set of output files to print to
 ** Returns:
 ** Description:  drives functions to generate code for all the schemas
 ** in an Express model into one set of files  -- works with EXPRESSPrint
 ** Side Effects:  generates code
 ** Status:  24-Feb-1992 new -kcm
 ******************************************************************/

void
print_schemas_combined( Express express, ComplexCollect & col, FILES * files ) {

    EXPRESSPrint( express, col, files );
}

/*
** Procedure:   print_file
** Parameters:  const Schema schema - top-level schema to print
**      FILE*        file   - file on which to print
** Returns: void
** Description:  this function calls one of two different functions
**  depending on whether the output should be combined into a single
**  set of files or a separate set for each schema
**
*/

void
print_file( Express express ) {
    extern void RESOLUTIONsucceed( void );
    int separate_schemas = 1;
    ComplexCollect col( express );

    File_holder files;

    resolution_success();

    print_file_header( express, &files );
    if( separate_schemas ) {
        print_schemas_separate( express, ( void * )&col, &files );
    } else {
        print_schemas_combined( express, col, &files );
    }
    print_file_trailer( express, &files );
    print_complex( col, ( const char * )"compstructs.cc" );
}
