/* * * Copyright (C) 2000 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * Further, this software is distributed without any warranty that it is * free of the rightful claim of any third person regarding infringement * or the like. Any license provided herein, whether implied or * otherwise, applies only to this software file. Patent licenses, if * any, provided herein do not apply to combinations of this program with * other software, or any other product whatsoever. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, * Mountain View, CA 94043, or: * * http://www.sgi.com * * For further information regarding this notice, see: * * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Man.h" ///////////////////////////////////////////////////////////////////////////// // // Class: ClassDef // ///////////////////////////////////////////////////////////////////////////// const ClassDef * ClassDef::curClass = NULL; ClassDef::ClassDef() { parentClass = NULL; } ClassDef::~ClassDef() { if (type.isDerivedFrom(SoBase::getClassTypeId()) && instance != NULL) ((SoBase *) instance)->unref(); } void ClassDef::addInherit(ClassDef *def) { // FALSE = add to start of list inherits.add(new Inherit(def->name), FALSE); } SbBool ClassDef::read() { SbName nm; SbBool ok = TRUE; curClass = this; // Read statements while they exist while (ok && Reader::readName(nm)) { // See what kind of statement we have switch (getStatementType(nm)) { case NAME: ok = (Reader::readName(name) && Reader::readName(cPrefix) && Reader::readName(cEnumPrefix) && Reader::readBracketed(shortDescription)); if (! ok) Reader::error("NAME spec"); break; case DESCRIPTION: ok = Reader::readBracketed(longDescription); if (! ok) Reader::error("DESC"); break; case INCLUDE: ok = readItem(new Include, &includes); break; case TYPEDEF: ok = readItem(new Typedef, &typedefs); break; case DEFINE: ok = readItem(new Define, &defines); break; case ENUM: ok = readItem(new Enum, &enums); break; case FIELD: ok = readItem(new Field, &fields); break; case INPUT: ok = readItem(new Input, &inputs); break; case OUTPUT: ok = readItem(new Output, &outputs); break; case PART: ok = readItem(new Part, &parts); break; case METHOD: ok = readItem(new Method, &methods); break; case DRAGGER_RESOURCE: ok = readItem(new DraggerResource, &draggerResources); break; case MACRO: ok = readItem(new Macro, ¯os); break; case ACTION: ok = readItem(new Action, &actions); break; case MISC: ok = readItem(new Misc, &miscs); break; case ALSO: ok = readItem(new Also, &alsos); break; case BEGIN: { SbName langName; ok = Reader::readName(langName); if (ok) { if (langName == "C") Item::setCurLanguage(C); else if (langName == "C++") Item::setCurLanguage(C_PLUS_PLUS); else ok = FALSE; } if (! ok) Reader::error("BEGIN language name"); } break; case END: Item::setCurLanguage(ALL); break; default: Reader::error("statement keyword"); ok = FALSE; } } // If there's stuff left in the file, error if (Reader::get() != EOF) ok = FALSE; return ok; } SbBool ClassDef::readItem(Item *item, ItemList *list) { if (! item->read()) return FALSE; list->add(item); return TRUE; } ClassDef::StatementType ClassDef::getStatementType(const SbName &keyword) { static SbName *names = NULL; static const char *keywords[] = { "NAME", "DESC", "INCLUDE", "TYPEDEF", "DEFINE", "ENUM", "FIELD", "INPUT", "OUTPUT", "PART", "METHOD", "MACRO", "ACTION", "MISC", "ALSO", "BEGIN", "END", "DRAGGER_RESOURCE", }; #define NUM_KEY_WORDS (sizeof(keywords) / sizeof(keywords[0])) int i; if (names == NULL) { names = new SbName[NUM_KEY_WORDS]; for (i = 0; i < NUM_KEY_WORDS; i++) names[i] = keywords[i]; } for (i = 0; i < NUM_KEY_WORDS; i++) if (keyword == keywords[i]) return (StatementType) i; return UNKNOWN; } SbBool ClassDef::setUp(const ClassDef *mainDef) { curClass = this; // Find out the type of the class, if any. Remove the "So" from // the name, since the names don't contain the prefix. // But first check to see if the prefix is Sb. If so, don't setup // up the file format section. SbBool isSb = strncmp(name.getString(), "Sb", 2) ? FALSE : TRUE; type = SoType::fromName(name.getString() + 2); // Get an instance of the class, if possible. If this is not the // main ClassDef (mainDef is NULL), we will use an instance of the // main ClassDef for this class as well, rather than choosing one // randomly in getInstance(). if (mainDef != NULL) instance = mainDef->instance; else if (type.isBad() || isSb) instance = NULL; else { instance = getInstance(); // Ref instance if necessary to keep it around if (type.isDerivedFrom(SoBase::getClassTypeId()) && instance != NULL) ((SoBase *) instance)->ref(); } // Set the C prefix to the class name, unless it was specified if (Writer::getLanguage() == C && ! cPrefix) cPrefix = name; if (Writer::getLanguage() == C) setUpTypedefs(); if (! fields.isEmpty() && ! setUpFields()) return FALSE; if (! inputs.isEmpty() && ! setUpInputs()) return FALSE; if (! outputs.isEmpty() && ! setUpOutputs()) return FALSE; // Look up part types (if any) if (! parts.isEmpty() && ! setUpParts()) return FALSE; // Produce nodekit catalog and file format if necessary if (! isSb) { setUpCatalog(); setUpFileFormat(); } return TRUE; } SbBool ClassDef::setUpTypedefs() { // The C language version has a typedef for the class if the // prefix is not the same as the class name if (cPrefix != name) { Typedef *def = new Typedef; def->language = C; def->type = name.getString(); def->name = cPrefix; typedefs.add(def); } return TRUE; } SbBool ClassDef::setUpFields() { if (instance == NULL || ! type.isDerivedFrom(SoFieldContainer::getClassTypeId())) { fprintf(stderr, "Can't create a (non-abstract) field container from " "class \"%s\"\n", name.getString()); return FALSE; } SoFieldContainer *fc = (SoFieldContainer *) instance; for (Item *item = fields.first; item != NULL; item = item->next) { Field *f = (Field *) item; SoField *field = fc->getField(f->name); if (field == NULL) { fprintf(stderr, "No field \"%s\" in class \"%s\"\n", f->name.getString(), name.getString()); return FALSE; } SbString typeName = "So"; SoType fieldType = field->getTypeId(); if (fieldType == SoSFInt32::getClassTypeId()) { typeName += "SFInt32"; } else if (fieldType == SoMFInt32::getClassTypeId()) { typeName += "MFInt32"; } else if (fieldType == SoSFUInt32::getClassTypeId()) { typeName += "SFUInt32"; } else if (fieldType == SoMFUInt32::getClassTypeId()) { typeName += "MFUInt32"; } else typeName += fieldType.getName().getString(); f->type = typeName; } return TRUE; } SbBool ClassDef::setUpInputs() { if (instance == NULL || ! type.isDerivedFrom(SoEngine::getClassTypeId())) { fprintf(stderr, "Can't create a (non-abstract) engine from " "class \"%s\"\n", name.getString()); return FALSE; } SoEngine *eng = (SoEngine *) instance; for (Item *item = inputs.first; item != NULL; item = item->next) { Input *in = (Input *) item; SoField *input = eng->getField(in->name); if (input == NULL) { fprintf(stderr, "No input \"%s\" in class \"%s\"\n" "Assuming \n", in->name.getString(), name.getString()); SbString typeName = ""; in->type = typeName; } else { SbString typeName = "So"; SoType inputType = input->getTypeId(); if (inputType == SoSFInt32::getClassTypeId()) { typeName += "SFInt32"; } else if (inputType == SoMFInt32::getClassTypeId()) { typeName += "MFInt32"; } else if (inputType == SoSFUInt32::getClassTypeId()) { typeName += "SFUInt32"; } else if (inputType == SoMFUInt32::getClassTypeId()) { typeName += "MFUInt32"; } else typeName += inputType.getName().getString(); in->type = typeName; } } return TRUE; } SbBool ClassDef::setUpOutputs() { if (instance == NULL || ! type.isDerivedFrom(SoEngine::getClassTypeId())) { fprintf(stderr, "Can't create a (non-abstract) engine from " "class \"%s\"\n", name.getString()); return FALSE; } SoEngine *eng = (SoEngine *) instance; for (Item *item = outputs.first; item != NULL; item = item->next) { Output *out = (Output *) item; SoEngineOutput *output = eng->getOutput(out->name); if (output == NULL) { fprintf(stderr, "No output \"%s\" in class \"%s\"\n" "Assuming \n", out->name.getString(), name.getString()); SbString typeName = ""; out->type = typeName; } else { SbString typeName = "So"; SoType outputType = output->getConnectionType(); if (outputType == SoSFInt32::getClassTypeId()) { typeName += "SFInt32"; } else if (outputType == SoMFInt32::getClassTypeId()) { typeName += "MFInt32"; } else if (outputType == SoSFUInt32::getClassTypeId()) { typeName += "SFUInt32"; } else if (outputType == SoMFUInt32::getClassTypeId()) { typeName += "MFUInt32"; } else typeName += outputType.getName().getString(); out->type = typeName; } } return TRUE; } SbBool ClassDef::setUpParts() { if (instance == NULL || ! type.isDerivedFrom(SoBaseKit::getClassTypeId())) { fprintf(stderr, "Can't create a (non-abstract) node kit from " "class \"%s\"\n", name.getString()); return FALSE; } SoBaseKit *kit = (SoBaseKit *) instance; for (Item *item = parts.first; item != NULL; item = item->next) { Part *part = (Part *) item; const SoNodekitCatalog *cat = kit->getNodekitCatalog(); SoType type = cat->getType(part->name); if (type.isBad()) { fprintf(stderr,"No part \"%s\" in class \"%s\"\n", part->name.getString(), name.getString()); return FALSE; } SbString typeName = "So"; typeName += type.getName().getString(); part->type = typeName; } return TRUE; } SbBool ClassDef::setUpCatalog() { int i; if (instance == NULL || ! type.isDerivedFrom(SoBaseKit::getClassTypeId())) { return TRUE; } SoBaseKit *kit = (SoBaseKit *) instance; const SoNodekitCatalog *cat = kit->getNodekitCatalog(); // // Main catalog part table // // The .ne (need) request makes sure the smallest table fits on // the page. For some reason, tbl gets the wrong value for its own // .ne, so this hack fixes up some simple cases. // First, figure out how many entries are gonna be in the table: int numInPublicTable = 0; for (i = 0; i < cat->getNumEntries(); i++ ) if (cat->isPublic(i)) numInPublicTable++; // Next, print a .ne command to a string, adding our fudge number: #define PUBLIC_TBL_FUDGE_NUM 9 char nePublicString[20]; sprintf(nePublicString, ".ne %d\n", PUBLIC_TBL_FUDGE_NUM+numInPublicTable); catalog = nePublicString; catalog += ".TS\n" "box, tab(!);\n" "cb s s s\n" "lb lb lb lb\n" "lb lb lb lb\n" "l l l c.\n" "All parts\n" "!!!NULL by\n" "Part Name!Part Type!Default Type!Default\n" "\n"; for (i = 0; i < cat->getNumEntries(); i++ ) { if (cat->isPublic(i)) { // Part name catalog += cat->getName(i).getString(); // Part type catalog += "!"; catalog += cat->getType(i).getName().getString(); // Default type catalog += "!"; if (cat->getDefaultType(i) != cat->getType(i)) catalog += cat->getDefaultType(i).getName().getString(); else catalog += "--"; // NULL by default catalog += "!"; catalog += (cat->isNullByDefault(i) ? "yes" : "no"); catalog += "\n"; } } catalog += "\n.TE\n"; // // Catalog list part table // // Make sure there is at least one list first SbBool anyLists = FALSE; for (i = 0; i < cat->getNumEntries(); i++ ) { if (cat->isList(i) && cat->isPublic(i)) { anyLists = TRUE; break; } } if (anyLists) { // The .ne (need) request makes sure the smallest table fits on // the page. For some reason, tbl gets the wrong value for its own // .ne, so this hack fixes up some simple cases. // First, figure out how many entries are gonna be in the table: int numInListTable = 0; for (i = 0; i < cat->getNumEntries(); i++ ) if (cat->isList(i) && cat->isPublic(i)) numInListTable++; // Next, print a .ne command to a string, adding our fudge number: #define LIST_TBL_FUDGE_NUM 9 char neListSTring[20]; sprintf(neListSTring, ".ne %d\n", LIST_TBL_FUDGE_NUM+numInListTable); catalog += neListSTring; catalog += ".TS\n" "box, tab(!);\n" "cb s s\n" "lb lb lbw(30n)\n" "l l l.\n" "Extra information for list parts from above table\n" ".sp\n" "Part Name!Container Type!Permissible Types\n" "\n"; for (i = 0; i < cat->getNumEntries(); i++ ) { if (cat->isList(i) && cat->isPublic(i)) { // Part name catalog += cat->getName(i).getString(); // Container type catalog += "!"; catalog += cat->getListContainerType(i).getName().getString(); // Permissible types // Note: type names are entered within T{ and T} // blocks so that they can be formatted when necessary. catalog += "!T{\n"; const SoTypeList &permTypes = cat->getListItemTypes(i); for (int j = 0; j < permTypes.getLength(); j++) { catalog += permTypes[j].getName().getString(); if (j < permTypes.getLength() - 1) catalog += ", "; } catalog += "\nT}"; catalog += "\n"; } } catalog += "\n.TE\n"; } return TRUE; } SbBool ClassDef::setUpFileFormat() { hasFileFormat = FALSE; fileFormat.makeEmpty(); fileFormatTabLength = -1; // We need file format if the class is derived from SoNode or SoEngine if (type.isDerivedFrom(SoNode::getClassTypeId()) || type.isDerivedFrom(SoEngine::getClassTypeId())) { // Abstract class? if (isAbstract) { fileFormat = "This is an abstract class. See the reference page " "of a derived class for the format and default values.\n"; hasFileFormat = TRUE; } else if (type.isDerivedFrom(SoBaseKit::getClassTypeId())) { //////////////////////////////////////////////////////// // // Special case for nodekits. They print their fields in // a different order than they are defined. // if (instance == NULL) return TRUE; SoBaseKit *kit = (SoBaseKit *) instance; const SoNodekitCatalog *cat = kit->getNodekitCatalog(); SoFieldList list; kit->getFields(list); SoField *field; int partNum, i; SbString fieldVal; SbName fieldName; int len; // First, write out fields that are NOT parts... // Whatever they are, just write out the field value. for (i = 0; i < list.getLength(); i++) { field = list[i]; kit->getFieldName(field, fieldName); partNum = cat->getPartNumber(fieldName); if (partNum == SO_CATALOG_NAME_NOT_FOUND) { field->get(fieldVal); fileFormat += fieldName.getString(); fileFormat += "\t"; fileFormat += fieldVal; fileFormat += "\n"; len = fieldName.getLength(); if (len > fileFormatTabLength) fileFormatTabLength = len; } } // Note: we skip all of this for the BOOK version... if (! Writer::isForBook()) { // Second, write out fields that are PUBLIC PARTS. // Private parts do not get written in the man page. // When writing parts, we write <"resourcename" // resource> if the node is named in the global // database. Otherwise, we write out the scene graph. SoNode *partNode; for (i = 0; i < list.getLength(); i++) { field = list[i]; kit->getFieldName(field, fieldName); partNum = cat->getPartNumber(fieldName); if (partNum != SO_CATALOG_NAME_NOT_FOUND && cat->isPublic(partNum)) { partNode = ((SoSFNode *)field)->getValue(); if (partNode == NULL || !partNode->getName()) { // If the node has no name in the global dictionary // or is NULL, print out the value of the node. // This might turn out to be an entire scene graph! field->get(fieldVal); } else { // Just print out the name of the node. fieldVal = "<"; fieldVal += partNode->getName().getString(); fieldVal += " resource>"; } fileFormat += fieldName.getString(); fileFormat += "\t"; fileFormat += fieldVal; fileFormat += "\n"; len = fieldName.getLength(); if (len > fileFormatTabLength) fileFormatTabLength = len; } } // Finally, dragger resources may exist for parts that are in // nested draggers. Write out these nested partNames // and <"resourcename" resource> if (! draggerResources.isEmpty()) { Item *item; for (item = draggerResources.first; item != NULL; item = item->next ) { DraggerResource *res = (DraggerResource *) item; // Check if any of the parts that use this resource // do not simply match the partNames in the catalog. // If not, we write out the partName and resource. for (int j = 0; j < res->getNumPartDefs(); j++ ) { const SbName pDefName = res->getPartDefName(j); if ( cat->getPartNumber(pDefName) == SO_CATALOG_NAME_NOT_FOUND ) { // Write it all out... fieldVal = "<"; fieldVal += res->getResourceName().getString(); fieldVal += " resource>"; fileFormat += pDefName.getString(); fileFormat += "\t"; fileFormat += fieldVal; fileFormat += "\n"; len = pDefName.getLength(); if (len > fileFormatTabLength) fileFormatTabLength = len; } } } } } hasFileFormat = TRUE; // //////////////////////////////////////////////////////// } else { SoFieldContainer *fc = (SoFieldContainer *) instance; //////////////////////////////////////////////////////// // // Special case for engines whose constructor takes the // type of field to operate on // if (fc->isOfType(SoConcatenate::getClassTypeId())) fileFormat += "type\t\n" "input0\t[]\n" "input1\t[]\n" "input2\t[]\n" "input3\t[]\n" "input4\t[]\n" "input5\t[]\n" "input6\t[]\n" "input7\t[]\n" "input8\t[]\n" "input9\t[]\n"; else if (fc->isOfType(SoGate::getClassTypeId()) || fc->isOfType(SoSelectOne::getClassTypeId())) fileFormat += "type\t\ninput\t[]\n"; // //////////////////////////////////////////////////////// // Make sure each field does not have a default value SoFieldList list; fc->getFields(list); for (int i = 0; i < list.getLength(); i++) { SoField *field = list[i]; SbString fieldVal; SbName fieldName; int len; fc->getFieldName(field, fieldName); // Special case for time fields connected to the clock if (field->isConnected() && (field->isOfType(SoSFTime::getClassTypeId()) || field->isOfType(SoMFTime::getClassTypeId()))) fieldVal = ""; else field->get(fieldVal); fileFormat += fieldName.getString(); fileFormat += "\t"; fileFormat += fieldVal; fileFormat += "\n"; len = fieldName.getLength(); if (len > fileFormatTabLength) fileFormatTabLength = len; } hasFileFormat = TRUE; } } return TRUE; } void * ClassDef::getInstance() { void *inst; isAbstract = ! type.canCreateInstance(); // If the given class is not abstract, return an instance of it if (! isAbstract) inst = type.createInstance(); else { // Otherwise, find all classes derived from the class and // return the first one that is not abstract SoTypeList list; SoType::getAllDerivedFrom(type, list); inst = NULL; for (int i = 0; i < list.getLength(); i++) { if (list[i].canCreateInstance()) { inst = list[i].createInstance(); break; } } } // No non-abstract classes return inst; } void ClassDef::cullMethods() { //////////////////////////////////////////// // // This method is called on the main ClassDef - the one the man // page is for. It removes any method from an inherited class that: // (1) is a constructor, // or (2) has the same name as a method on a more derived class, // or (3) is a destructor and the language is C++. // // It also removes hidden methods from the main ClassDef and all // inherited ClassDefs. // //////////////////////////////////////////// ClassDef *cd, *inheritedCd; Method *meth, *inhMeth, *prevMeth; // // Pass 1: Mark all constructors and destructors // for (cd = parentClass; cd != NULL; cd = cd->parentClass) { for (meth = (Method *) cd->methods.first; meth != NULL; meth = (Method *) meth->next) { // Remove constructors if (meth->type == Method::CONSTRUCTOR) meth->skipThis = TRUE; // Remove destructors from C++ else if (meth->type == Method::DESTRUCTOR && Writer::getLanguage() == C_PLUS_PLUS) meth->skipThis = TRUE; } } // // Pass 2: Mark any method with the same name as in a more // derived class. This is a slow way to do this, but it shouldn't // be too bad in most cases. // for (cd = this; cd != NULL; cd = cd->parentClass) { for (meth = (Method *) cd->methods.first; meth != NULL; meth = (Method *) meth->next) { if (! meth->skipThis) { // Look through inherited classes for a method with // the same name for (inheritedCd = cd->parentClass; inheritedCd != NULL; inheritedCd = inheritedCd->parentClass) { if (Writer::getLanguage() == C) { for (inhMeth = (Method *) inheritedCd->methods.first; inhMeth != NULL; inhMeth = (Method *) inhMeth->next) { if (inhMeth->cName == meth->cName) inhMeth->skipThis = TRUE; } } else { for (inhMeth = (Method *) inheritedCd->methods.first; inhMeth != NULL; inhMeth = (Method *) inhMeth->next) { if (inhMeth->name == meth->name) inhMeth->skipThis = TRUE; } } } } } } // // Pass 3: Mark hidden methods // for (cd = this; cd != NULL; cd = cd->parentClass) { for (meth = (Method *) cd->methods.first; meth != NULL; meth = (Method *) meth->next) { if (meth->isHidden) meth->skipThis = TRUE; } } // // Pass 4: Actually remove marked methods from lists // for (cd = this; cd != NULL; cd = cd->parentClass) { prevMeth = NULL; for (meth = (Method *) cd->methods.first; meth != NULL; meth = (Method *) meth->next) { if (meth->skipThis) { if (prevMeth == NULL) cd->methods.first = meth->next; else prevMeth->next = meth->next; } else prevMeth = meth; } } } void ClassDef::write(SbBool) { curClass = this; Writer::writePreface(name); if (Writer::isForBook()) writeForBook(); else writeForNonBook(); } void ClassDef::writeForBook() { ClassDef *cd; SbBool anyItem; //////////////////////////////////////////////////////// // // NAME section // writeName(); //////////////////////////////////////////////////////// // // INHERITS FROM section // Writer::startSection("INHERITS FROM"); inherits.write(); //////////////////////////////////////////////////////// // // DESCRIPTION section // Writer::startSection("DESCRIPTION"); Writer::writeBracketed(longDescription); //////////////////////////////////////////////////////// // // FIELDS section // anyItem = FALSE; for (cd = this; cd != NULL; cd = cd->parentClass) { if (! cd->fields.isEmpty()) { anyItem = TRUE; break; } } if (anyItem) { Writer::startSection("FIELDS"); if (! fields.isEmpty()) fields.write(); for (cd = parentClass; cd != NULL; cd = cd->parentClass) if (! cd->fields.isEmpty()) cd->writeFromClass(&cd->fields, "Fields", TRUE); } //////////////////////////////////////////////////////// // // INPUTS section // anyItem = FALSE; for (cd = this; cd != NULL; cd = cd->parentClass) { if (! cd->inputs.isEmpty()) { anyItem = TRUE; break; } } if (anyItem) { Writer::startSection("INPUTS"); if (! inputs.isEmpty()) inputs.write(); for (cd = parentClass; cd != NULL; cd = cd->parentClass) if (! cd->inputs.isEmpty()) cd->writeFromClass(&cd->inputs, "Inputs", TRUE); } //////////////////////////////////////////////////////// // // OUTPUTS section // anyItem = FALSE; for (cd = this; cd != NULL; cd = cd->parentClass) { if (! cd->outputs.isEmpty()) { anyItem = TRUE; break; } } if (anyItem) { Writer::startSection("OUTPUTS"); if (! outputs.isEmpty()) outputs.write(); for (cd = parentClass; cd != NULL; cd = cd->parentClass) if (! cd->outputs.isEmpty()) cd->writeFromClass(&cd->outputs, "Outputs", TRUE); } //////////////////////////////////////////////////////// // // PARTS section // anyItem = FALSE; for (cd = this; cd != NULL; cd = cd->parentClass) { if (! cd->parts.isEmpty()) { anyItem = TRUE; break; } } if (anyItem) { Writer::startSection("PARTS"); if (! parts.isEmpty()) parts.write(); for (cd = parentClass; cd != NULL; cd = cd->parentClass) if (! cd->parts.isEmpty()) cd->writeFromClass(&cd->parts, "Parts", TRUE); } //////////////////////////////////////////////////////// // // METHODS section // anyItem = FALSE; for (cd = this; cd != NULL; cd = cd->parentClass) { if (! cd->methods.isEmpty()) { anyItem = TRUE; break; } } if (anyItem) { Writer::startSection(Writer::getLanguage() == C ? "FUNCTIONS" : "METHODS"); if (! methods.isEmpty()) methods.write(); for (cd = parentClass; cd != NULL; cd = cd->parentClass) if (! cd->methods.isEmpty()) cd->writeFromClass(&cd->methods, (Writer::getLanguage() == C ? "Functions" : "Methods"), TRUE); } //////////////////////////////////////////////////////// // // MACROS section // anyItem = FALSE; for (cd = this; cd != NULL; cd = cd->parentClass) { if (! cd->macros.isEmpty()) { anyItem = TRUE; break; } } if (anyItem) { Writer::startSection("MACROS"); if (! macros.isEmpty()) macros.write(); for (cd = parentClass; cd != NULL; cd = cd->parentClass) if (! cd->macros.isEmpty()) cd->writeFromClass(&cd->macros, "Macros", TRUE); } //////////////////////////////////////////////////////// // // ACTION BEHAVIOR section // if (! actions.isEmpty()) { Writer::startSection("ACTION BEHAVIOR"); actions.write(); } //////////////////////////////////////////////////////// // // CATALOG PARTS section // if (! ! catalog) { Writer::startSection("CATALOG PARTS"); Writer::write(catalog); } //////////////////////////////////////////////////////// // // FILE FORMAT section // writeFileFormat(); //////////////////////////////////////////////////////// // // Include files // if (! includes.isEmpty()) { Writer::startSection("INCLUDE FILE"); Writer::changeSize(-1); // Include files for this class includes.write(); // XXX we needed to list these things somewhere, // so here they are --AE // Typedefs for this class typedefs.write(); // Definitions for this class defines.write(); // Enums for this class enums.write(); } //////////////////////////////////////////////////////// // // Miscellaneous sections // if (! miscs.isEmpty()) miscs.write(); //////////////////////////////////////////////////////// // // SEE ALSO section // if (! alsos.isEmpty()) { Writer::startSection("SEE ALSO"); alsos.write(); } //////////////////////////////////////////////////////// Writer::finish(); } void ClassDef::writeForNonBook() { //////////////////////////////////////////////////////// // // NAME section // writeName(); //////////////////////////////////////////////////////// // // INHERITS FROM section // Writer::startSection("INHERITS FROM"); inherits.write(); //////////////////////////////////////////////////////// // // SYNOPSIS section // writeSynopsis(); //////////////////////////////////////////////////////// // // DESCRIPTION section // Writer::startSection("DESCRIPTION"); Writer::writeBracketed(longDescription); //////////////////////////////////////////////////////// // // FIELDS section // if (! fields.isEmpty()) { Writer::startSection("FIELDS"); fields.write(); } //////////////////////////////////////////////////////// // // INPUTS section // if (! inputs.isEmpty()) { Writer::startSection("INPUTS"); inputs.write(); } //////////////////////////////////////////////////////// // // OUTPUTS section // if (! outputs.isEmpty()) { Writer::startSection("OUTPUTS"); outputs.write(); } //////////////////////////////////////////////////////// // // PARTS section // if (! parts.isEmpty()) { Writer::startSection("PARTS"); parts.write(); } //////////////////////////////////////////////////////// // // METHODS section // if (! methods.isEmpty()) { Writer::startSection(Writer::getLanguage() == C ? "FUNCTIONS" : "METHODS"); methods.write(); } //////////////////////////////////////////////////////// // // MACROS section // if (! macros.isEmpty()) { Writer::startSection("MACROS"); macros.write(); } //////////////////////////////////////////////////////// // // ACTION BEHAVIOR section // if (! actions.isEmpty()) { Writer::startSection("ACTION BEHAVIOR"); actions.write(); } //////////////////////////////////////////////////////// // // CATALOG PARTS section // if (! ! catalog) { Writer::startSection("CATALOG PARTS"); Writer::write(catalog); } //////////////////////////////////////////////////////// // // DRAGGER RESOURCES section (for draggers) // if (! draggerResources.isEmpty()) { Writer::startSection("DRAGGER RESOURCES"); draggerResources.write(); } //////////////////////////////////////////////////////// // // FILE FORMAT section // writeFileFormat(); //////////////////////////////////////////////////////// // // Miscellaneous sections // if (! miscs.isEmpty()) miscs.write(); //////////////////////////////////////////////////////// // // SEE ALSO section // if (! alsos.isEmpty()) { Writer::startSection("SEE ALSO"); alsos.write(); } //////////////////////////////////////////////////////// Writer::finish(); } void ClassDef::writeName() { Writer::startSection("NAME"); Writer::write(name); if (Writer::getLanguage() == C) { Writer::write(" ("); Writer::write(cPrefix); Writer::write(") \\(em "); } else Writer::write(" \\(em "); Writer::writeBracketed(shortDescription); } void ClassDef::writeSynopsis() { ClassDef *cd; Writer::setInSynopsis(TRUE); Writer::startSection("SYNOPSIS"); Writer::changeSize(-1); // Include files for this class includes.write(); // Typedefs for this class typedefs.write(); // Definitions for this class defines.write(); // Enums for this class enums.write(); // Fields for this class, then all parent classes for (cd = this; cd != NULL; cd = cd->parentClass) if (! cd->fields.isEmpty()) cd->writeFromClass(&cd->fields, "Fields"); // Inputs for this class, then all parent classes for (cd = this; cd != NULL; cd = cd->parentClass) if (! cd->inputs.isEmpty()) cd->writeFromClass(&cd->inputs, "Inputs"); // Outputs for this class, then all parent classes for (cd = this; cd != NULL; cd = cd->parentClass) if (! cd->outputs.isEmpty()) cd->writeFromClass(&cd->outputs, "Outputs"); // Parts for this class, then all parent classes for (cd = this; cd != NULL; cd = cd->parentClass) if (! cd->parts.isEmpty()) cd->writeFromClass(&cd->parts, "Parts"); // Methods for this class, then all parent classes for (cd = this; cd != NULL; cd = cd->parentClass) if (! cd->methods.isEmpty()) cd->writeFromClass(&cd->methods, (Writer::getLanguage() == C ? "Functions" : "Methods")); // Macros for this class, then all parent classes for (cd = this; cd != NULL; cd = cd->parentClass) if (! cd->macros.isEmpty()) cd->writeFromClass(&cd->macros, "Macros"); Writer::setInSynopsis(FALSE); } void ClassDef::writeFileFormat() { // Paths have a special file format: if (type == SoPath::getClassTypeId()) { Writer::startSection("FILE FORMAT/DEFAULTS"); Writer::setFill(FALSE); Writer::setFont(Writer::FIXED_ROMAN); Writer::write("SoPath {\n"); Writer::setBaseIndent(0.5); Writer::write("[head node]\n" "[number of remaining indices]\n" "[index]\n" "\\&...\n" "[index]\n"); Writer::setBaseIndent(0.0); Writer::write("}\n\n"); Writer::setFill(TRUE); Writer::setFont(Writer::TEXT_ROMAN); Writer::write("Note that the indices in a written path are " "adjusted based on the nodes that are actually " "written to a file. Since nodes in the graph " "that have no effect on the path (such as some " "separator nodes) are not written, the siblings " "of such nodes must undergo index adjustment " "when written. The actual nodes in the graph " "remain unchanged.\n"); } else if (hasFileFormat) { Writer::startSection("FILE FORMAT/DEFAULTS"); if (isAbstract) Writer::write(fileFormat); else { Writer::setFill(FALSE); Writer::setFont(Writer::FIXED_ROMAN); // Remove "So" prefix from name Writer::write(name.getString() + 2); Writer::write(" {\n"); // Classes with no fields have an empty fileFormat string if (! ! fileFormat) { Writer::setBaseIndent(0.5); Writer::setTab(fileFormatTabLength + (fileFormatTabLength < 0 ? 0 : 2)); Writer::write(fileFormat); Writer::setBaseIndent(0.0); } Writer::write("}\n"); } } } void ClassDef::writeFromClass(ItemList *list, const char *whats, SbBool runIn) { if (Writer::isForBook()) { Writer::setBaseIndent(0.0); Writer::setFont(Writer::TEXT_BOLD); } else { Writer::setBaseIndent(0.5); Writer::setFont(Writer::TEXT_ROMAN); } Writer::write(whats); Writer::write(" from class "); Writer::write(name); Writer::write(":\n"); if (Writer::isForBook()) { Writer::setBaseIndent(0.5); Writer::space(.25); } else { Writer::setBaseIndent(0.0); Writer::space(); } list->write(runIn); }