/*
* scl2html.cc
*
* Ian Soboroff, NIST
* June, 1994
*
* scl2html is a program to lay out a given schema in HTML, suitable for
* hypertext browsing using Mosaic or any other HTML viewer/WWW surfboard.
* While this particular code as designed is linked to the Example schema
* (via tests.h), it can be "fed" any exp2cxx-compiled schema and give
* appropriate output.
*
* The Makefile defaults to building the app to use the example schema. To
* link to another schema, build the appropriate libraries for it and
* 'make SCHEMA_NAME=my-schema'. See the Makefile for more details.
*
* The executable is named after the schema you use, e.g., scl2html.example.
* This can be renamed to whatever you want.
*
* This program works by using the registry to walk through each entity type.
* At each entity, the supertypes, subtypes, and attributes are probed out
* and mapped into a relatively nifty-looking HTML format.
*
* This code was heavily inspired by the original scltest program,
* distributed with the DataProbe, v2.0.x.
*/
/* Since scl2html doesn't use any schema-specific things except the init
function, we don't need to include the schema's header file inside
tests.h */
#define DONT_NEED_HEADER
#include "../tests.h"
/* STEPentity* Iterator class definition */
#include "../SEarritr.h"
// PrintAttrTypeWithAnchor()
// Given an attribute, print out its immediate type (not fundamental).
// Ah, but if life were so simple. If this attribute is _not_ of a
// fundamental type, put in an anchor to somewhere with info on the type.
// This could be either the index page Type list, or an entity's page if
// the attribute is an entity.
// BUGS: (sort of) IMHO, the handling of aggregates here is a kludge, but
// it's a kludge without a solution I can see. While the dictionary has
// ways to show you what kinds of things an aggregate holds, it won't tell
// you what kind of _aggragation_ (no pun intended) you have, as in giving
// you a code or "Bag" or something by itself. It probably doesn't work
// aesthetically for compound aggregates (i.e., a list of lists).
void PrintAttrTypeWithAnchor( const TypeDescriptor * typeDesc, ofstream & outhtml ) {
std::string buf;
// The type. See clstepcore/baseType.h for info
PrimitiveType base = typeDesc->Type();
// the type descriptor for the "referent type," if any.
// This is NULL if the attribute is a fundamental type.
// All we use it for now is checking for NULL.
const TypeDescriptor * reference = typeDesc->ReferentType();
// Do we need an anchor?
int anchor = 0;
// First, figure out if we need an anchor...
if( reference ) { // if this has a referent type (i.e., is a non-base type)
if( base != sdaiAGGR ) { // anchor all non-bases except for aggregates
anchor = 1; // which we'll take care of recursively
}
} else {
// entities and enumerations show up as base, but we want to
// anchor them anyway
if( base == sdaiENUMERATION || base == sdaiINSTANCE ) {
anchor = 1;
}
}
// Now, print type, with anchor if necessary
if( anchor && base != sdaiINSTANCE ) {
// for regular TYPEs, anchor to the index at that definition
outhtml << "Name() << "\">";
} else if( anchor && base == sdaiINSTANCE ) {
// for entities, anchor to that entity's page
outhtml << "Name();
outhtml << ".html\">";
}
typeDesc->AttrTypeName( buf );
outhtml << buf;
if( base == sdaiAGGR ) {
outhtml << " (contains elements of type ";
PrintAttrTypeWithAnchor( typeDesc->AggrElemTypeDescriptor(), outhtml );
outhtml << ")" << endl;
}
if( anchor ) {
outhtml << "";
}
}
// PrintAttrsHTML()
// Given an entity, print out to the HTML file an unordered list of
// the entity's attributes and their types. It returns the number of
// explicit attributes that the entity has.
int PrintAttrsHTML( const EntityDescriptor * ent, ofstream & outhtml ) {
int attrCount = 0;
// To traverse the attributes of the entity, we're going to use
// an iterator native to the class library. This could also have
// been done using GetHead() and NextNode() of the entity's attribute
// list (nearly identical to how the entity lists are traversed), see
// PrintParentAttrsHTML() and also main() below.
AttrDescItr aditr( ent->ExplicitAttr() );
const AttrDescriptor * attrDesc = aditr.NextAttrDesc();
if( attrDesc != 0 ) {
outhtml << "\nName() << " >\n\n";
outhtml << "
" << endl;
while( attrDesc != 0 ) {
attrCount++;
outhtml << "- " << attrDesc->Name() << " : ";
if( ( attrDesc->Optional() ) == SDAI_LOGICAL( LTrue ) ) {
outhtml << "optional ";
}
PrintAttrTypeWithAnchor( attrDesc->ReferentType(), outhtml );
outhtml << endl;
attrDesc = aditr.NextAttrDesc();
}
outhtml << "
" << endl;
}
return attrCount;
}
// PrintParentAttrsHTML()
// This function, given an entity and its parent, recursively travels up
// the inheritance tree of the entity, printing to the HTML file a
// description-list structure showing all ancestors. For each ancestor,
// the attributes are printed using the PrintAttrsHTML() function above.
void PrintParentAttrsHTML( const EntityDescriptor * ent,
const EntityDescriptor * parent, ofstream & outhtml ) {
// Passing this function the pointer to ent is really cosmetic, so
// we can easily print out this 'header' information.
outhtml << "\nName() << ">\n\n";
outhtml << "" << endl;
outhtml << "- " << ent->Name() << " inherits from ";
outhtml << "Name() << ".html\">";
outhtml << parent->Name() << "" << endl;
// Here we're going to traverse the list of supertypes of the parent
// using the EntityDescriptorList
const EntityDescriptorList * grandpaList = &( parent->Supertypes() );
EntityDescLinkNode * grandpaNode =
( EntityDescLinkNode * )grandpaList->GetHead();
while( grandpaNode ) {
// for each "grandparent" of ent, inside a descriptor body (
- )
// recursively call this function... the 'while' takes care of
// multiple inheritance: for each grandparent, trace back.
outhtml << "
- " << endl;
const EntityDescriptor * grandpa = grandpaNode->EntityDesc();
PrintParentAttrsHTML( parent, grandpa, outhtml );
grandpaNode = ( EntityDescLinkNode * )grandpaNode->NextNode();
}
// Now print the parent's attributes. This calls PrintAttrsHTML() to
// actually print any existing attributes, but to see if there are
// any, we'll check to see if the head of the attribute descriptor list
// exists. Conversely, once grabbing the head we could print out
// the attributes by following the list (attrNode->NextNode()).
const AttrDescriptorList * attrList = &( parent->ExplicitAttr() );
AttrDescLinkNode * attrNode = ( AttrDescLinkNode * )attrList->GetHead();
if( attrNode ) {
outhtml << "
- " << parent->Name();
outhtml << " has the following attributes" << endl;
outhtml << "
- " << endl;
if( PrintAttrsHTML( parent, outhtml ) == 0 ) {
outhtml << "none" << endl;
}
}
outhtml << "
" << endl;
}
/******************** main() ****************************/
main() {
// This has to be done before anything else. This initializes
// all of the registry information for the schema you are using.
// The SchemaInit() function is generated by exp2cxx... see
// extern statement above.
Registry * registry = new Registry( SchemaInit );
// Rather than using the standard Registry class here, as in the treg
// example, we are using MyRegistry, which is derived from the original.
// Registry doesn`t contain a facility for browsing the types, as it
// does schemas and entities... so I added it. See the file
// MyRegistry.h for details on how this was done.
// "Reset" has tables for browsing
registry->ResetEntities();
registry->ResetSchemas();
registry->ResetTypes();
const SchemaDescriptor * schema = registry->NextSchema();
int num_ents = registry->GetEntityCnt();
cout << "Processing schema " << schema->Name();
cout << " with " << num_ents << " entities." << endl;
// Set up root-level index of the schema, in a file called
// "index.html". In this document are links to all objects in
// the schema.
cout << "Creating 'index.html'" << endl;
ofstream root( "index.html" );
root << "" << schema->Name() << "" << endl;
root << "Schema: " << schema->Name() << "
" << endl;
// Do Type-list
cout << "Processing types ";
root << "
" << endl;
root << "Types
" << endl;
root << "" << endl;
const TypeDescriptor * type;
type = registry->NextType();
root << "\n";
root << "\n";
while( type != 0 ) {
cout << ".";
root << "- Name() << "\">";
root << type->Name() << ": ";
root << type->Description() << endl;
type = registry->NextType();
}
root << "
" << endl;
cout << endl;
// Do entity root-section and pages
root << "
" << endl;
root << "Entities
" << endl;
root << "" << endl;
root << "\n";
// These are all pointers we need to wander around the registry
// information. We'll want to not only look at the current entity
// and its attributes, but also which entities are super- and subclasses
// of the current entity. Here, supers isn't really used beyond checking
// for ancestors, but we'll use subs to list subclasses and make links
// to them.
const EntityDescriptor * ent;
const EntityDescriptorList * supers;
const EntityDescriptorList * subs;
EntityDescLinkNode * entNode;
for( int i = 0; i < num_ents; i++ ) {
ent = registry->NextEntity();
cout << "Processing " << ent->Name() << endl;
// add anchor to root page
root << "- Name() << ".html\">";
root << ent->Name() << "" << endl;
// construct page for entity
char * tmpstr = new char[strlen( ent->Name() ) + 6];
ofstream entout( strcat( strcpy( tmpstr, ent->Name() ), ".html" ) );
delete [] tmpstr;
entout << "Entity " << ent->Name() << "" << endl;
entout << "
" << ent->Name() << "
" << endl;
// supertypes
entout << "
\nInherited Attributes
" << endl;
entout << "Name() << ">\n";
supers = &( ent->Supertypes() );
entNode = ( EntityDescLinkNode * )supers->GetHead();
if( !entNode ) {
entout << "none" << endl;
}
while( entNode ) {
// call PrintParentAttrsHTML to explore the parents
// of the entity, for each parent.
const EntityDescriptor * parent = entNode->EntityDesc();
PrintParentAttrsHTML( ent, parent, entout );
entNode = ( EntityDescLinkNode * )entNode->NextNode();
}
// local attributes
entout << "
\nLocal Attributes
" << endl;
if( PrintAttrsHTML( ent, entout ) == 0 ) {
entout << "none" << endl;
}
// subtypes
// We're going to traverse the subtypes by using the subtype list
// of the entity, a little more simply than in PrintParentAttrsHTML()
entout << "
\nSubtypes
" << endl;
entout << "\n";
subs = &( ent->Subtypes() );
entNode = ( EntityDescLinkNode * )subs->GetHead();
if( entNode ) {
entout << "" << endl;
} else {
entout << "none" << endl;
}
entout << "
" << endl;
entout << "Click here to ";
entout << "return to the index." << endl;
}
root << "
" << endl;
cout << "Done!" << endl;
}