/* nodegen.c: generates C code with interface description and * field value defaults for each VRML node. The data is read from * the node catalog file nodes.catalog. */ // // 21-feb-2001 // . output in the 'xrml' namespace. // . "vrml" renamed into "xrml" // // 09-feb-2001 // . assign member functions now also update timestamp // (timestamp was not updated when directly assigning) // // 20-dec-2000: // . typeId also initialised for non-leaf node classes // // 14-dec-2000 // . validate_[exposed]field functions replaced: // . synchronize_ member function for [M|S}FNode valued fields // . assign_ member functions check value range, do proper // assignement, and call synchronize() for [M|F]SNode valued fields // . static assign__ functions that check whter SFNode* // node argument is of proper type and call assign_ member // . previous "do-all" synchronize() member omitted // . eventOut value is now also member of the class + there are now // two post_() member functions replacing previous () function: // one with and one without value argument // . value argument of post_eventOut, set_[exposed]field and process_ // functions are now const references, except for SFNode*. // . instantiate() returns 'this' for named nodes without enclosing proto and // calls synchronize() for [S|M}FNode values. // . [exposed]fields, eventIns, eventOuts declared at the highest level where // they are defined: post_, assign<[exposed]field>, and // set_ at base classes declared virtual and prints error message. // True implementation only for leaf classes (since only there the complete // interface is available). // . status bits indicate what fields/eventOuts have been updated since // last inspection. They are declared only for leaf classes. Manipulation by // a user is through xxx_is_updated() and xxx_clear_update() member functions, // which for base classes are declared virtual and print a "stub called" error // message. // . Can also handle nodes without interface members now // . Better handling of utility data in constructor/destructor by means of // new util_[init|clone|destruct]() member functions. // . new comment delimiters in header file indicate where manual editing // should be restricted, so the headers can be updated automatically later // on without tedious manual merging. // . major refactoring of the nodegen program itself. // #include #include #include #include #include "vrml.H" #include "nodeCatalog.H" #include "parser.H" #include "error.H" #include "version.H" /* catalog of known node types */ static array nodeCatalog(10); // prints values in C++ syntax static void cpr(FILE *fp, SFBool& v) { fprintf(fp, "%d", (bool)v ? 1 : 0); } static void cpr(FILE *fp, SFString& v) { fprintf(fp, "\"%s\"", (char *)v); } static void cpr(FILE *fp, SFInt32& v) { fprintf(fp, "%d", (int)v); } static void cpr(FILE *fp, SFFloat& v) { fprintf(fp, "%g", (float)v); } static void cpr(FILE *fp, SFTime& v) { fprintf(fp, "%g", (double)v); } static void cpr(FILE *fp, SFVec2f& v) { fprintf(fp, "SFVec2f(%g,%g)", v.s, v.t); } static void cpr(FILE *fp, SFVec3f& v) { fprintf(fp, "SFVec3f(%g,%g,%g)", v.x, v.y, v.z); } static void cpr(FILE *fp, SFColor& v) { fprintf(fp, "SFColor(%g,%g,%g)", v.r, v.g, v.b); } static void cpr(FILE *fp, SFRotation& v){ fprintf(fp, "SFRotation(%g,%g,%g,%g)", v.x, v.y, v.z, v.radians); } static void cpr(FILE *fp, SFImage& v) { fprintf(fp, "SFImage(%d,%d,%d)", v.width, v.height, v.num_components); if (v.width * v.height > 0) fprintf(stderr, "num. pixels in image > 0!!!\n"); } static void cpr(FILE *fp, interfaceDeclaration* decl) { fprintf(fp, "\t%-12.12s %-10.10s %-12s\t", interfaceKindName(decl->kind), fieldTypeName(decl->type), decl->Id); if (decl->kind==kfield || decl->kind==kexposedField) { char buf[1000]; ostrstream ost(buf,1000); fieldValue val(decl->type, (void *)decl->value); ost << val; fprintf(fp, "%s", buf); } fprintf(fp, "\n"); } // Generates C++ code for initialising a value with the default value // in the interfaceDeclaration. // Limitations: // . doesn't handle non-nil SFNode or MFNode default values. // . doens't handle SFImage type values with non-empty image static void GenerateDefaultValueCode(FILE *fp, interfaceDeclaration *decl) { // prints array in C++ syntax #define CPRARRAY(type, typestr, stypestr) \ { \ type *p = (type *)decl->value; \ if (p->size == 0) \ fprintf(fp, " %s = %s(0);\n", decl->Id, typestr); \ else { \ fprintf(fp, " const %s _%s[%d] = {", stypestr, decl->Id, p->size); \ for (int i=0; isize; i++) { \ if (i>0) fprintf(fp, ", "); \ cpr(fp, (*p)[i]); \ } \ fprintf(fp, "};\n %s = %s(%d,(%s *)_%s);\n", \ decl->Id, typestr, p->size, stypestr, decl->Id); \ } \ } #define CPRSIMPLE(type) \ { \ fprintf(fp, " %s = ", decl->Id); \ cpr(fp, *((type *)(decl->value))); \ fprintf(fp, ";\n"); \ } switch (decl->type) { case tSFFloat: CPRSIMPLE(SFFloat); break; case tSFInt32: CPRSIMPLE(SFInt32); break; case tSFTime: CPRSIMPLE(SFTime); break; case tSFString: CPRSIMPLE(SFString); break; case tSFBool: CPRSIMPLE(SFBool); break; case tSFColor: CPRSIMPLE(SFColor); break; case tSFImage: CPRSIMPLE(SFImage); break; case tSFNode: if (decl->kind != keventOut) { fprintf(fp, " %s = (%s *)0; \t_%s = (SFNode *)0;\n", decl->Id, decl->nodeClassId ? decl->nodeClassId : "SFNode", decl->Id); } else { fprintf(fp, " %s = (SFNode *)0;\n", decl->Id); } if ((SFNode *)(decl->value)) { cpr(fp, decl); fprintf(stderr, "non-null default SFNode * value !!!\n"); } break; case tSFRotation: CPRSIMPLE(SFRotation); break; case tSFVec2f: CPRSIMPLE(SFVec2f); break; case tSFVec3f: CPRSIMPLE(SFVec3f); break; case tMFColor: CPRARRAY(MFColor, "MFColor", "SFColor"); break; case tMFFloat: CPRARRAY(MFFloat, "MFFloat", "SFFloat"); break; case tMFInt32: CPRARRAY(MFInt32, "MFInt32", "SFInt32"); break; case tMFRotation: CPRARRAY(MFRotation, "MFRotation", "SFRotation"); break; case tMFString: CPRARRAY(MFString, "MFString", "SFString"); break; case tMFTime: CPRARRAY(MFTime, "MFTime", "SFTime"); break; case tMFVec2f: CPRARRAY(MFVec2f, "MFVec2f", "SFVec2f"); break; case tMFVec3f: CPRARRAY(MFVec3f, "MFVec3f", "SFVec3f"); break; case tMFNode: { MFNode *p = (MFNode *)decl->value; if (p->size > 0) { cpr(fp, decl); fprintf(stderr, "non-empty default MFNode value !!!\n"); } else { if (decl->kind != keventOut) { fprintf(fp, " %s = array<%s*>(0); \t_%s = MFNode(0);\n", decl->Id, decl->nodeClassId ? decl->nodeClassId : "SFNode", decl->Id); } else { fprintf(fp, " %s = MFNode(0);\n", decl->Id); } } break; } default: Fatal(-1, "GenerateDefaultValueCode", "invalid type '%d'", decl->type); } } // returns true if node has a member with Id 'id'. static bool IsMemberOfNode(char *id, SFNode *node) { for (int i=0; inrInterfaceDeclarations; i++) { interfaceDeclaration *decl = &node->interface[i]; if (strcmp(decl->Id, id) == 0) return true; } return false; } // returns true if node has a parent with 'id'.member. static bool IsAncestorMember(char *id, SFNode *node) { for (int i=0; iparentNodes.size; i++) if (IsMemberOfNode(id, node->parentNodes[i]) || IsAncestorMember(id, node->parentNodes[i])) return true; return false; } // inserts the file src into dest static void InsertFile(FILE *dest, FILE *src) { int c; while ((c = getc(src)) != EOF) putc(c, dest); } static void GenerateParentNodeDecl(FILE *fp, SFNode *node) { // produce parent node class declaration: we assume that node superclasses have only // one common ancestor: SFNode. 'public virtual SFNode' is required for // top node superclasses and for the leaf node classes but not for // the intermediate node superclasses. int count = 0; if (!node->isParent || node->parentNodes.size == 0) { fprintf(fp, " public virtual SFNode"); count++; } for (int i=0; iparentNodes.size; i++) { fprintf(fp, "%c public %s", count>0 ? ',' : ' ', node->parentNodes[i]->typeId); count++; } } static void GenerateStatusBitDecl(FILE *fp, SFNode *node) { if (node->isParent) // status bits are only declared for leaf node classes, where the // full interface is known return; interfaceDeclaration *decl; int i; int count=0; for (i=0, decl=node->interface; inrInterfaceDeclarations; i++, decl++) { if (decl->kind == kfield || decl->kind == kexposedField || decl->kind == keventOut) count++; } // Update status: bits are set by assign_xxx and post_xxx member functions // of leaf node classes. if (count > 0) { fprintf(fp, " // field/eventOut update status bits\n // Use xxx_is_updated() and xxx_clear_update() to inspect/reset.\n"); fprintf(fp, " enum status_bits {\n"); int n = 0; for (i=0, decl=node->interface; inrInterfaceDeclarations; i++, decl++) { if (decl->kind == kfield || decl->kind == kexposedField || decl->kind == keventOut) { fprintf(fp, " %s_updated = 0x%x%c\n", decl->Id, 1<isParent) return; // no private members for base classes fprintf(fp, "private:\n"); // clone() for a leaf node class calls SFNode::clone() (see SFNode.C), // ensures that the interfaceMembers of a newly created node // point to its own values, copies src field and eventOut values, // and calls clone_util() ember functions for the leaf node class // and all parents. // Only leaf nodes have such a clone() function because only leaf // nodes have the interface defined with them. fprintf(fp, " //\n"); fprintf(fp, " void clone_here(const %s&);\n", node->typeId); fprintf(fp, " void destruct(void);\n"); fprintf(fp, " \n"); GenerateStatusBitDecl(fp, node); } // Wee keep two copies of [S|M]Node values: raw and "resolved": // Raw children node values directly correspond to what is read from the VRML // file. They may be PROTO interface declaration nodes for instance. // synchronize() methods "resolve" them: produce node points and arrays of // the proper node type (e.g. Material for nodes in a Appearance.material field). // (synchronize_xxx() basically calls the raw nodes "firstnode()" method and casts to // the requested SFNode sub-class). static void GenerateRawStateDecl(FILE *fp, SFNode *node) { interfaceDeclaration *decl; int i; fprintf(fp, " // raw children nodes (can be PROTO) + synchronize methods:\n"); for (i=0, decl=node->interface; inrInterfaceDeclarations; i++, decl++) { if (decl->kind == kfield || decl->kind == kexposedField) { if (decl->type == tSFNode || decl->type == tMFNode) { char *comment = ""; if (IsAncestorMember(decl->Id, node)) comment = "// "; if (decl->type == tSFNode) fprintf(fp, " %s%s \t_%s;\n", comment, "SFNode*", decl->Id); else if (decl->type == tMFNode) fprintf(fp, " %s%s \t_%s;\n", comment, "MFNode", decl->Id); fprintf(fp, " %svoid \tsynchronize_%s(void);\n", comment, decl->Id); } } } fprintf(fp, "\n"); } static void GenerateProtectedEventOutDecl(FILE *fp, SFNode *node) { interfaceDeclaration *decl; int i; fprintf(fp, " // raw eventOut posting:\n"); for (i=0, decl=node->interface; inrInterfaceDeclarations; i++, decl++) { if (decl->kind == keventOut) { fprintf(fp, " void post_%s(void);\n", decl->Id); } } fprintf(fp, "\n"); } static void GenerateProtectedHeader(FILE *fp, SFNode *node) { interfaceDeclaration *decl; int i; int nrrawstatevals = 0; int nreventouts = 0; for (i=0, decl=node->interface; inrInterfaceDeclarations; i++, decl++) { if (decl->kind == kfield || decl->kind == kexposedField) { if (IsAncestorMember(decl->Id, node)) continue; if (decl->type == tSFNode || decl->type == tMFNode) nrrawstatevals++; } if (decl->kind == keventOut) if (!node->isParent) nreventouts++; } if (nrrawstatevals + nreventouts == 0) return; // no protected members fprintf(fp, "protected:\n"); if (nrrawstatevals > 0) GenerateRawStateDecl(fp, node); if (nreventouts > 0) GenerateProtectedEventOutDecl(fp, node); } static void GenerateStateValueDecl(FILE *fp, SFNode *node) { interfaceDeclaration *decl; int i; // Resolved children nodes and other state values: this is what the user // needs: everything of the same type and classes as described in the // VRML standard. int numfields = 0; for (i=0, decl=node->interface; inrInterfaceDeclarations; i++, decl++) { if (decl->kind == kfield || decl->kind == kexposedField) { numfields ++; } } if (numfields <= 0) return; fprintf(fp, " // state values:\n // Do not assign directly unless you know very well what you are doing.\n"); for (i=0, decl=node->interface; inrInterfaceDeclarations; i++, decl++) { if (decl->kind == kfield || decl->kind == kexposedField) { if (IsAncestorMember(decl->Id, node)) fprintf(fp, " //"); if (decl->type == tSFNode) { char buf[100]; sprintf(buf, "%s*", decl->nodeClassId ? decl->nodeClassId : "SFNode"); fprintf(fp, " %-16s \t%s;\n", buf, decl->Id); } else if (decl->type == tMFNode) fprintf(fp, " array<%s*> \t%s;\n", (decl->nodeClassId ? decl->nodeClassId : "SFNode"), decl->Id); else fprintf(fp, " %-16.16s \t%s;\n", fieldTypeName(decl->type), decl->Id); } } fprintf(fp, " \n"); } static void GenerateEventInDecl(FILE *fp, SFNode *node) { interfaceDeclaration *decl; int i; // eventIn functions: call these to update the state of the node. They // corresond to eventIns as described in the VRML standard + set_.... // eventIns for each exposedField. int count = 0; for (i=0, decl=node->interface; inrInterfaceDeclarations; i++, decl++) { if (decl->kind == keventIn) count++; } if (count <= 0) return; fprintf(fp, " // eventIns:\n"); for (i=0, decl=node->interface; inrInterfaceDeclarations; i++, decl++) { if (decl->kind == keventIn) { // can be overriden in subclasses char buf[100]; sprintf(buf, "%svoid", node->isParent ? "virtual " : ""); fprintf(fp, " %-16s \t%s(%s%s%s);\n", buf, decl->Id, decl->type==tSFNode ? "" : "const ", fieldTypeName(decl->type), decl->type==tSFNode ? "*" : "&"); } } fprintf(fp, " \n"); } static void GenerateSetExposedFieldDecl(FILE *fp, SFNode *node) { interfaceDeclaration *decl; int i; // set_() eventIns: need the interfaceMembers, so // can only be implemented for leaf node classes. int count = 0; for (i=0, decl=node->interface; inrInterfaceDeclarations; i++, decl++) { if (decl->kind == kexposedField) count++; } if (count <= 0) return; fprintf(fp, " // set_ eventIns: with forwarding and eventOut generation\n"); for (i=0, decl=node->interface; inrInterfaceDeclarations; i++, decl++) { if (decl->kind == kexposedField) { char buf[100]; sprintf(buf, "%svoid", node->isParent ? "virtual " : ""); fprintf(fp, " %-16s \tset_%s(%s%s%s);\n", buf, decl->Id, decl->type==tSFNode ? "" : "const ", fieldTypeName(decl->type), decl->type==tSFNode ? "*" : "&"); } } fprintf(fp, " \n"); } static void GenerateFieldAssignDecl(FILE *fp, SFNode *node) { interfaceDeclaration *decl; int i; int numfields = 0; for (i=0, decl=node->interface; inrInterfaceDeclarations; i++, decl++) { if (decl->kind == kfield || decl->kind == kexposedField) numfields ++; } if (numfields <= 0) return; fprintf(fp, " // field assignement: no forwarding or eventOut generation!\n"); for (i=0, decl=node->interface; inrInterfaceDeclarations; i++, decl++) { if (decl->kind == kfield || decl->kind == kexposedField) { char buf[100]; sprintf(buf, "%sbool", node->isParent ? "virtual " : ""); fprintf(fp, " %-16s \tassign_%s(%s%s%s);\n", buf, decl->Id, decl->type==tSFNode ? "" : "const ", fieldTypeName(decl->type), decl->type==tSFNode ? "*" : "&"); } } fprintf(fp, " \n"); } static void GeneratePublicEventOutDecl(FILE *fp, SFNode *node) { interfaceDeclaration *decl; int i; // eventOuts: call these to let the node generate an eventOut. // implementation needs the interfaceMembers, so can only be done // for leaf nodes. int nreventOuts = 0; for (i=0, decl=node->interface; inrInterfaceDeclarations; i++, decl++) { if (decl->kind == keventOut) nreventOuts++; } if (nreventOuts <= 0) return; fprintf(fp, " // eventOuts:\n"); for (i=0, decl=node->interface; inrInterfaceDeclarations; i++, decl++) { if (decl->kind == keventOut) { if (IsAncestorMember(decl->Id, node)) fprintf(fp, " //"); fprintf(fp, " %s%s \t%s;\n", fieldTypeName(decl->type), decl->type==tSFNode ? "*" : "", decl->Id); char buf[100]; sprintf(buf, "%svoid", node->isParent ? "virtual " : ""); fprintf(fp, " %-16s \tpost_%s(%s%s%s val);\n", buf, decl->Id, decl->type==tSFNode ? "" : "const ", fieldTypeName(decl->type), decl->type==tSFNode ? "*" : "&"); } } fprintf(fp, " \n"); } static void GenerateUpdateStatusDecl(FILE *fp, SFNode *node) { interfaceDeclaration *decl; int i; // update status inspection and reset int count=0; for (i=0, decl=node->interface; inrInterfaceDeclarations; i++, decl++) { if (decl->kind == kfield || decl->kind == kexposedField || decl->kind == keventOut) count++; } if (count <= 0) return; fprintf(fp, " // update status\n"); for (i=0, decl=node->interface; inrInterfaceDeclarations; i++, decl++) { if (decl->kind == kfield || decl->kind == kexposedField || decl->kind == keventOut) { if (node->isParent) { fprintf(fp, " %-16s \t%s_is_updated(void);\n", "virtual bool", decl->Id); fprintf(fp, " %-16s \t%s_clear_update(void);\n", "virtual void", decl->Id); } else { fprintf(fp, " %-16s \t%s_is_updated(void) { return (status & %s_updated); }\n", "inline bool", decl->Id, decl->Id); fprintf(fp, " %-16s \t%s_clear_update(void) { status &= ~%s_updated; }\n", "inline void", decl->Id, decl->Id); } } } fprintf(fp, " \n"); } static void GeneratePublicHeader(FILE *fp, SFNode *node) { fprintf(fp, "public:\n"); // constructors and destructor fprintf(fp, " //\n"); fprintf(fp, " %sint major_version(void), minor_version(void);\n", node->isParent ? "virtual " : ""); fprintf(fp, " %sbool is_leaf_class(void);\n", node->isParent ? "virtual " : ""); // fprintf(fp, " PoolDecl(%s, \"%s\")\n", node->typeId, node->typeId); fprintf(fp, " \n"); fprintf(fp, " %s();\n", node->typeId); if (!node->isParent) { fprintf(fp, " %s(const %s&);\n", node->typeId, node->typeId); fprintf(fp, " %s& operator=(const %s&);\n", node->typeId, node->typeId); fprintf(fp, " virtual ~%s();\n", node->typeId); } fprintf(fp, " \n"); fprintf(fp, " //\n"); // see vrml.H if (!node->isParent) { fprintf(fp, " %-16s \tinstantiate(Proto * =0);\n", "SFNode*"); // no "do-all" synchronize() member function needed anymore since 12-dec-2000 // fprintf(fp, " virtual double \tsynchronize(void);\n"); } char buf[100]; sprintf(buf, "%svoid", node->isParent? "virtual " : ""); fprintf(fp, " %-16s \trender(void);\n", buf); fprintf(fp, " \n"); GenerateStateValueDecl(fp, node); GenerateEventInDecl(fp, node); GenerateSetExposedFieldDecl(fp, node); GenerateFieldAssignDecl(fp, node); GeneratePublicEventOutDecl(fp, node); GenerateUpdateStatusDecl(fp, node); } // marks start and end of utility includes and utility member declaration sections // in header. static char* UtilityIncludesStartDelim(SFNode *node) { return "// utility includes"; } static char* UtilityIncludesEndDelim(SFNode *node) { return "// end of utility includes"; } static char* UtilityMembersStartDelim(SFNode *node) { return " // utility members"; } static char* UtilityMembersEndDelim(SFNode *node) { static char buf[100]; sprintf(buf, "// end of utility members"); return buf; } static void GenerateHeader(FILE *fp, SFNode *node, FILE *util_includes =0, FILE *util_members =0) { // The header file for a node class implementation contains declarations // of both automatically generated members and "utility" members that // need to be implemented manually. // // Manual editing work shall be restricted to the "utility includes" section // and the remainder of the automatically generated header file after the // "utility members" comment. The "util_init()", "util_clone()" and "util_destruct()" // members shall not be removed however. In this way, automatic future updates // of the generated header will be possible without the need to manually merge // all non-automatically generated code (using proper merge scripts). fprintf(fp, "// %s.H: %s nodes.\n", node->typeId, node->typeId); fprintf(fp, "\n"); fprintf(fp, "// This file has been generated using nodegen %d.%d%s.\n", MAJOR_VERSION, MINOR_VERSION, RELEASE); fprintf(fp, "// Restrict manual editing to the sections delimited by\n"); fprintf(fp, "// . the comments \"utility includes\" and \"end of utility includes\"\n"); fprintf(fp, "// . the comments \"utility members\" and \"end of utility members\"\n"); fprintf(fp, "\n"); fprintf(fp, "#ifndef _%s_H_\n#define _%s_H_\n\n", node->typeId, node->typeId); // The header files do not depend on vrmlP.H: we want to hide the // internals of the node interface, event ourting, etc... to the user // of this VRML library. fprintf(fp, "#include \"xrml.H\"\n"); // include parent node header files for (int i=0; idependNodes.size; i++) { fprintf(fp, "#include \"%s.H\"\n", node->dependNodes[i]->typeId); } fprintf(fp, "\n"); // utility includes fprintf(fp, "%s\n", UtilityIncludesStartDelim(node)); if (util_includes) InsertFile(fp, util_includes); fprintf(fp, "%s\n", UtilityIncludesEndDelim(node)); fprintf(fp, "\n"); fprintf(fp, "namespace xrml {\n"); fprintf(fp, "#define %sTypeId \t\"%s\"\n", node->typeId, node->typeId); fprintf(fp, "extern bool Is%s(SFNode*);\n", node->typeId); fprintf(fp, "\n"); fprintf(fp, "class %s:", node->typeId); GenerateParentNodeDecl(fp, node); fprintf(fp, " {\n"); GeneratePrivateHeader(fp, node); GenerateProtectedHeader(fp, node); GeneratePublicHeader(fp, node); fprintf(fp, "%s\n", UtilityMembersStartDelim(node)); if (util_members) InsertFile(fp, util_members); else { fprintf(fp, " \n"); fprintf(fp, "protected:\n"); fprintf(fp, " inline void util_init(void) { }\n"); fprintf(fp, " inline void util_clone(const %s& src) { }\n", node->typeId); fprintf(fp, " inline void util_destruct(void) { }\n"); fprintf(fp, "};\n\n"); } fprintf(fp, "%s\n", UtilityMembersEndDelim(node)); fprintf(fp, "} // namespace xrml\n"); fprintf(fp, "#endif /*_%s_H_*/\n", node->typeId); } static void GeneratePublicSource(FILE *fp, SFNode *node) { // The public source file contains all the stuff that cannot be generated // automatically. By hiding the internals of the node interface and // event processing, we protect manual implementations against // future changes in the internals that require the private sources // to be regenerated. // // A good solution if you can't implement the routines here or other utility // members without access to the internals is to move the implementations // to a second, new, private source file: // . the primary private source file can be replaced automatically without // loss of manual work // . the secondary private sources will need editing but will never // be overwritten automatically. // . the public sources never need re-editing after a change of // the internals and do not need to be regenerated interfaceDeclaration *decl; int i; fprintf(fp, "/* %s.C: %s nodes (public source) */\n", node->typeId, node->typeId); fprintf(fp, "\n"); fprintf(fp, "#include \"%s.H\"\n", node->typeId); fprintf(fp, "\n"); fprintf(fp, "namespace xrml {\n"); // eventIns: avoid accessing the interface members directly! for (i=0, decl=node->interface; inrInterfaceDeclarations; i++, decl++) { if (decl->kind == keventIn) { fprintf(fp, "void %s::%s(%s%s%s)\n", node->typeId, decl->Id, decl->type==tSFNode ? "" : "const ", fieldTypeName(decl->type), decl->type==tSFNode ? "*" : "&"); fprintf(fp, "{\n"); fprintf(fp, " Warning(NULL, \"%s::%s(): not yet implemented\");\n", node->typeId, decl->Id); fprintf(fp, "}\n"); fprintf(fp, "\n"); } } // render function fprintf(fp, "void %s::render(void)\n", node->typeId); fprintf(fp, "{\n"); fprintf(fp, " Warning(NULL, \"%s::render(): not yet implemented\");\n", node->typeId); fprintf(fp, "}\n"); fprintf(fp, "\n"); fprintf(fp, "} // namespace xrml\n"); } // top-down static void CallUtilInit(FILE *fp, SFNode *node) { for (int i=0; iparentNodes.size; i++) CallUtilInit(fp, node->parentNodes[i]); fprintf(fp, " %s::util_init();\n", node->typeId); } // top-down static void CallUtilClone(FILE *fp, SFNode *node) { for (int i=0; iparentNodes.size; i++) CallUtilClone(fp, node->parentNodes[i]); fprintf(fp, " %s::util_clone(src);\n", node->typeId); } // bottom-up static void CallUtilDestruct(FILE *fp, SFNode *node) { fprintf(fp, " %s::util_destruct();\n", node->typeId); for (int i=0; iparentNodes.size; i++) CallUtilDestruct(fp, node->parentNodes[i]); } static void GenerateEventInPrivateSource(FILE *fp, SFNode* node, interfaceDeclaration *decl, int index) { // eventIn processing "frontends", needed because member functions cannot be // passed to nodeInterface constructors. // (the process_xxx() member function itself is implemented in the public source) if (node->isParent) // only for leaf node classes return; if (decl->kind == keventIn) { fprintf(fp, "static void process_%s_%s(SFNode* node, const fieldValue& value)\n", node->typeId, decl->Id); fprintf(fp, "{\n"); fprintf(fp, " %s* %s_node = dynamic_cast<%s*>(node);\n", node->typeId, node->typeId, node->typeId); fprintf(fp, " if (!%s_node)\n", node->typeId); fprintf(fp, " Fatal(-1, \"process_%s_%s\", \"called for a non-%s node\");\n", node->typeId, decl->Id, node->typeId); fprintf(fp, " %s_node->%s((%s%s%s)value);\n", node->typeId, decl->Id, decl->type == tSFNode ? "" : "const ", fieldTypeName(decl->type), decl->type == tSFNode ? "*&" : "&"); fprintf(fp, "}\n"); fprintf(fp, "\n"); } } static void GenerateUpdateStatusSource(FILE *fp, SFNode *node, interfaceDeclaration* decl) { // update status inquiry and reset: implemented inline in header for leaf node // classes, stub needed for base classes. if (!node->isParent) return; fprintf(fp, "bool %s::%s_is_updated(void)", node->typeId, decl->Id); fprintf(fp, "{\n"); fprintf(fp, " stub(\"%s::%s_is_updated\");\n", node->typeId, decl->Id); fprintf(fp, " return true;\n"); fprintf(fp, "}\n\n"); fprintf(fp, "void %s::%s_clear_update(void)", node->typeId, decl->Id); fprintf(fp, "{\n"); fprintf(fp, " stub(\"%s::%s_clear_update\");\n", node->typeId, decl->Id); fprintf(fp, "}\n\n"); } static void GenerateFieldSynchronizeSource(FILE *fp, SFNode *node, interfaceDeclaration *decl) { // synchronize() member functions for SFNode or MFNode field values. // Implemented for the base class where the field value is defined. if (!(decl->type==tSFNode || decl->type==tMFNode) || IsAncestorMember(decl->Id, node)) return; fprintf(fp, "void %s::synchronize_%s(void)\n", node->typeId, decl->Id); fprintf(fp, "{\n"); if (decl->type == tSFNode) { fprintf(fp, " %s = (_%s) ? dynamic_cast<%s*>(_%s->firstnode()) : 0;\n", decl->Id, decl->Id, decl->nodeClassId ? decl->nodeClassId : "SFNode", decl->Id); } if (decl->type == tMFNode) { fprintf(fp, " if (_%s.size > %s.size) %s.grow(_%s.size - %s.size);\n", decl->Id, decl->Id, decl->Id, decl->Id, decl->Id); fprintf(fp, " for (int i=%s.size=0; i<_%s.size; i++)\n", decl->Id, decl->Id); fprintf(fp, " %s.append(dynamic_cast<%s*>(_%s[i]->firstnode()));\n", decl->Id, decl->nodeClassId ? decl->nodeClassId : "SFNode", decl->Id); } fprintf(fp, "}\n\n"); } static void GenerateFieldAssignMemberSource(FILE *fp, SFNode *node, interfaceDeclaration *decl, int index) { // Assign member functions: stubs for base classes and real implementation // only for leaf classes. The assign member functions check the value being // passed, do proper assignement and call synchronize() for [S|M]FNode value // types. fprintf(fp, "bool %s::assign_%s(%s%s%s value)\n", node->typeId, decl->Id, decl->type==tSFNode ? "" : "const ", fieldTypeName(decl->type), decl->type==tSFNode ? "*" : "&"); fprintf(fp, "{\n"); if (node->isParent) { fprintf(fp, " stub(\"%s::assign_%s\");\n", node->typeId, decl->Id); fprintf(fp, " return false;\n"); } else { if (decl->type == tSFNode || decl->type == tMFNode) { fprintf(fp, " %s%s oldval = _%s;\n", fieldTypeName(decl->type), decl->type==tSFNode ? "*" : "", decl->Id); fprintf(fp, " _%s = value;\n", decl->Id); fprintf(fp, " if (checkValue(_%s, Is%s, \"%s.%s\", \"%s\")) {\n", decl->Id, decl->nodeClassId ? decl->nodeClassId : "SFNode", node->typeId, decl->Id, decl->nodeClassId ? decl->nodeClassId : "SFNode"); fprintf(fp, " synchronize_%s();\n", decl->Id); fprintf(fp, " status |= %s_updated;\n", decl->Id); fprintf(fp, " timestamp = interface[%d]->timestamp = world ? world->time : 0;\n", index); fprintf(fp, " return true;\n"); fprintf(fp, " } else {\n"); fprintf(fp, " _%s = oldval;\n", decl->Id); fprintf(fp, " return false;\n"); fprintf(fp, " }\n"); } else { fprintf(fp, " // TODO: value range check!\n"); fprintf(fp, " %s = value;\n", decl->Id); fprintf(fp, " status |= %s_updated;\n", decl->Id); fprintf(fp, " timestamp = interface[%d]->timestamp = world ? world->time : 0;\n", index); fprintf(fp, " return true;\n"); // assume valid value by default } } fprintf(fp, "}\n\n"); } static void GenerateFieldAssignCallerSource(FILE *fp, SFNode *node, interfaceDeclaration *decl) { if (node->isParent) return; // only for leaf node classes fprintf(fp, "static bool assign_%s_%s(SFNode* node, const fieldValue& value)\n{\n", node->typeId, decl->Id); fprintf(fp, " %s* %s_node = dynamic_cast<%s*>(node);\n", node->typeId, node->typeId, node->typeId); fprintf(fp, " if (!%s_node)\n", node->typeId); fprintf(fp, " Fatal(-1, \"assign_%s_%s\", \"called for a non-%s node\");\n", node->typeId, decl->Id, node->typeId); fprintf(fp, " return %s_node->assign_%s((%s%s%s)value);\n", node->typeId, decl->Id, decl->type ==tSFNode ? "" : "const ", fieldTypeName(decl->type), decl->type==tSFNode ? "*&" : "&"); fprintf(fp, "}\n\n"); } static void GenerateFieldPrivateSource(FILE *fp, SFNode *node, interfaceDeclaration *decl, int index) { GenerateFieldSynchronizeSource(fp, node, decl); GenerateFieldAssignMemberSource(fp, node, decl, index); GenerateFieldAssignCallerSource(fp, node, decl); GenerateUpdateStatusSource(fp, node, decl); } static void GenerateExposedFieldPrivateSource(FILE *fp, SFNode *node, interfaceDeclaration *decl, int index) { GenerateFieldPrivateSource(fp, node, decl, index); // set_ eventIn: stub for base classes, real implementation for // leaf node classes fprintf(fp, "void %s::set_%s(%s%s%s val)\n", node->typeId, decl->Id, decl->type==tSFNode ? "" : "const ", fieldTypeName(decl->type), decl->type==tSFNode ? "*" : "&"); fprintf(fp, "{\n"); if (node->isParent) { fprintf(fp, " stub(\"%s::set_%s\");\n", node->typeId, decl->Id); } else { fprintf(fp, " %s%s tmpval(val);\n", fieldTypeName(decl->type), decl->type==tSFNode ? "*" : ""); fprintf(fp, " fieldValue v(&tmpval);\n"); fprintf(fp, " interface[%d]->assign(this, v);\n", index); } fprintf(fp, "}\n\n"); } static void GenerateEventOutPrivateSource(FILE *fp, SFNode *node, interfaceDeclaration *decl, int index) { if (!node->isParent) { // proper posting of the eventOut fprintf(fp, "void %s::post_%s(void)\n", node->typeId, decl->Id); fprintf(fp, "{\n"); fprintf(fp, " interface[%d]->post(this, interface[%d]->value);\n", index, index); fprintf(fp, "}\n\n"); } // assigns a value to the eventOut and post() above. fprintf(fp, "void %s::post_%s(%s%s%s val)\n", node->typeId, decl->Id, decl->type==tSFNode ? "" : "const ", fieldTypeName(decl->type), decl->type==tSFNode ? "*" : "&"); fprintf(fp, "{\n"); if (node->isParent) { fprintf(fp, " stub(\"%s::post_%s\");\n", node->typeId, decl->Id); } else { fprintf(fp, " %s = val;\n", decl->Id); fprintf(fp, " status |= %s_updated;\n", decl->Id); fprintf(fp, " post_%s();\n", decl->Id); } fprintf(fp, "}\n\n"); GenerateUpdateStatusSource(fp, node, decl); } static void GenerateInterfaceConstructorSource(FILE *fp, SFNode *node) { interfaceDeclaration *decl; int i; if (node->nrInterfaceDeclarations <= 0) { fprintf(fp, " interfaceMember** the_interface = 0;\n"); } else { fprintf(fp, " interfaceMember* the_interface[%d] = {\n", node->nrInterfaceDeclarations); for (i=0, decl=node->interface; inrInterfaceDeclarations; i++, decl++) { switch (decl->kind) { case keventIn: fprintf(fp, " new eventIn(\"%s\", t%s, process_%s_%s),\n", decl->Id, fieldTypeName(decl->type), node->typeId, decl->Id); break; case kexposedField: if (decl->type == tSFNode || decl->type == tMFNode) fprintf(fp, " new exposedField(\"%s\", fieldValue(&_%s), assign_%s_%s),\n", decl->Id, decl->Id, node->typeId, decl->Id); else fprintf(fp, " new exposedField(\"%s\", fieldValue(&%s), assign_%s_%s),\n", decl->Id, decl->Id, node->typeId, decl->Id); break; case kfield: if (decl->type == tSFNode || decl->type == tMFNode) fprintf(fp, " new field(\"%s\", fieldValue(&_%s), assign_%s_%s),\n", decl->Id, decl->Id, node->typeId, decl->Id); else fprintf(fp, " new field(\"%s\", fieldValue(&%s), assign_%s_%s),\n", decl->Id, decl->Id, node->typeId, decl->Id); break; case keventOut: fprintf(fp, " new eventOut(\"%s\", fieldValue(&%s)),\n", decl->Id, decl->Id); break; default: fprintf(stderr, "Dummy interface member in node %s!!!\n", node->typeId); break; } } fprintf(fp, " };\n"); } // nrInterfaceMembers > 0 fprintf(fp, " SFNode::construct(%sTypeId, %d, the_interface);\n\n", node->typeId, node->nrInterfaceDeclarations); } static void GenerateDefaultConstructorSource(FILE *fp, SFNode *node) { interfaceDeclaration *decl; int i; // default constructor fprintf(fp, "%s::%s()\n", node->typeId, node->typeId); fprintf(fp, "{\n"); if (!node->isParent) { // node interface members: only defined for leaf nodes as only leaf // nodes have all the field values. GenerateInterfaceConstructorSource(fp, node); } else { fprintf(fp, " typeId = \"%s\";\n", node->typeId); } // default values for the fields: int numstatusbits = 0; for (i=0, decl=node->interface; inrInterfaceDeclarations; i++, decl++) { if (decl->kind == keventOut) { decl->value = default_fieldValue(decl->type); // default value for given type } if (decl->kind == kfield || decl->kind == kexposedField || decl->kind == keventOut) { GenerateDefaultValueCode(fp, decl); numstatusbits++; } } if (!node->isParent) { // utility data initialisation: only for leaf node classes fprintf(fp, " \n"); CallUtilInit(fp, node); } fprintf(fp, "}\n\n"); } static void GenerateDestructorSource(FILE *fp, SFNode *node) { if (node->isParent) return; // destructor for parent classes needs nothing to do // destructor: fprintf(fp, "void %s::destruct(void)\n", node->typeId); fprintf(fp, "{\n"); CallUtilDestruct(fp, node); fprintf(fp, " SFNode::destruct();\n"); fprintf(fp, "}\n\n"); fprintf(fp, "%s::~%s()\n", node->typeId, node->typeId); fprintf(fp, "{\n"); fprintf(fp, " destruct();\n"); fprintf(fp, "}\n\n"); } static void GenerateCopyConstructorSource(FILE *fp, SFNode *node) { interfaceDeclaration *decl; int i; if (node->isParent) return; // only for leaf classes // clone(): makes interface members point to the new nodes own state and // copies the source state values. All values (members of // node superclasses or not) are handled at the leaf node class level. fprintf(fp, "void %s::clone_here(const %s& src)\n", node->typeId, node->typeId); fprintf(fp, "{\n"); // duplicate source interface members fprintf(fp, " SFNode::clone(src);\n"); fprintf(fp, " \n"); // make field or exposedField interface members point to the new nodes // own state (SFNode::clone() make exact copies of the source interface // members, but can't do this work because SFNode doesn't know the // leaf node state values). for (i=0, decl=node->interface; inrInterfaceDeclarations; i++, decl++) { if (decl->kind == kfield || decl->kind == kexposedField || decl->kind == keventOut) fprintf(fp, " interface[%d]->value = fieldValue(&%s%s);\n", i, (decl->kind!=keventOut && (decl->type == tSFNode || decl->type==tMFNode)) ? "_" : "", decl->Id); } fprintf(fp, " \n"); // copy field/eventOut values from source for (i=0, decl=node->interface; inrInterfaceDeclarations; i++, decl++) { if (decl->kind == kfield || decl->kind == kexposedField) { fprintf(fp, " %s = src.%s;", decl->Id, decl->Id); if (decl->type==tSFNode || decl->type==tMFNode) fprintf(fp, "\t _%s = src._%s;", decl->Id, decl->Id); fprintf(fp, "\n"); } if (decl->kind == keventOut) { fprintf(fp, " %s = src.%s;\n", decl->Id, decl->Id); } } // call clone_util() for this and all parent nodes fprintf(fp, " \n"); CallUtilClone(fp, node); fprintf(fp, "}\n\n"); // copy constructor fprintf(fp, "%s::%s(const %s& src)\n", node->typeId, node->typeId, node->typeId); fprintf(fp, "{\n"); fprintf(fp, " clone_here(src);\n"); fprintf(fp, "}\n\n"); // assignement operator fprintf(fp, "%s& %s::operator=(const %s& src)\n", node->typeId, node->typeId, node->typeId); fprintf(fp, "{\n"); fprintf(fp, " if (this != &src) {\n"); fprintf(fp, " destruct();\n"); fprintf(fp, " clone_here(src);\n"); fprintf(fp, " }\n"); fprintf(fp, " return *this;\n"); fprintf(fp, "}\n\n"); // instantiate: create new instance of 'this'. Let interface member // links and routes etc... point to the 'master' PROTO (if non-nil). // instantiate_interface() is a member of the SFNode base class and // will recursively instantiate children nodes. fprintf(fp, "SFNode* %s::instantiate(Proto *enclosing_proto)\n", node->typeId); fprintf(fp, "{\n"); fprintf(fp, " if (nameIndex>=0)\n"); fprintf(fp, " // named node: return pointer to pre-made instance\n"); fprintf(fp, " return enclosing_proto ? enclosing_proto->namedNodes[nameIndex] : this;\n"); fprintf(fp, " \n"); fprintf(fp, " %s* instance = new %s(*this);\n", node->typeId, node->typeId); fprintf(fp, " instance->instantiate_interface(enclosing_proto);\n"); for (i=0, decl=node->interface; inrInterfaceDeclarations; i++, decl++) { if (decl->kind == kfield || decl->kind == kexposedField) { if (decl->type == tSFNode || decl->type == tMFNode) { fprintf(fp, " instance->synchronize_%s();\n", decl->Id); } } } fprintf(fp, " return instance;\n"); fprintf(fp, "}\n\n"); } // 2000-01-21: process_eventIn and validate_[exposed]field are now static functions // with node and fieldValue argument instead of private member functions due // to problems to cast the functions to member functions of the virtual base class. static void GeneratePrivateSource(FILE *fp, SFNode *node) { // private source: everything that depends on the node interface and // event processing internals (vrmlP.H). Mostly automatically // generated. Shall never be edited manually. interfaceDeclaration *decl; int i; fprintf(fp, "// %sP.C: %s nodes (private source).\n", node->typeId, node->typeId); fprintf(fp, "// Automatically generated with nodegen %d.%d%s - do not edit.\n", MAJOR_VERSION, MINOR_VERSION, RELEASE); fprintf(fp, "\n"); fprintf(fp, "#include \"%s.H\"\n", node->typeId); fprintf(fp, "#include \"xrmlP.H\"\n"); fprintf(fp, "\n"); fprintf(fp, "namespace xrml {\n"); fprintf(fp, "int %s::major_version(void) { return %d; }\n", node->typeId, MAJOR_VERSION); fprintf(fp, "int %s::minor_version(void) { return %d; }\n", node->typeId, MINOR_VERSION); fprintf(fp, "bool %s::is_leaf_class(void) { return %s; }\n", node->typeId, node->isParent ? "false" : "true"); fprintf(fp, "\n"); // fprintf(fp, "POOL* %s::pool = 0;\n", node->typeId); // fprintf(fp, "\n"); // test whether the node is of the given type. fprintf(fp, "bool Is%s(SFNode* node)\n", node->typeId); fprintf(fp, "{\n"); fprintf(fp, " return (dynamic_cast<%s*>(node) != 0);\n", node->typeId); fprintf(fp, "}\n\n"); for (i=0, decl=node->interface; inrInterfaceDeclarations; i++, decl++) { switch (decl->kind) { case keventIn: GenerateEventInPrivateSource(fp, node, decl, i); break; case kfield: GenerateFieldPrivateSource(fp, node, decl, i); break; case kexposedField: GenerateExposedFieldPrivateSource(fp, node, decl, i); break; case keventOut: GenerateEventOutPrivateSource(fp, node, decl, i); break; default: Fatal(-1, "GeneratePrivateSource", "Invalid field kind %d\n", decl->kind); } } GenerateDefaultConstructorSource(fp, node); GenerateDestructorSource(fp, node); GenerateCopyConstructorSource(fp, node); fprintf(fp, "} // namespace xrml\n"); } static bool Backup(char *filename) { FILE *fp = fopen(filename, "r"); if (fp) { char cmd[200]; sprintf(cmd, "mv %s %s.bak", filename, filename); fprintf(stderr, "%s ...\n", cmd); system(cmd); return true; } return false; } static void Extract(FILE *from, char *delim1, char *delim2, FILE *to) { #define bufsize 1000 char buf[bufsize]; bool insection = false; while (fgets(buf, bufsize, from)) { if (!insection && strncmp(buf, delim1, strlen(delim1))==0) insection = true; else if (insection && strncmp(buf, delim2, strlen(delim2))==0) return; // finished else if (insection) fputs(buf, to); } } static FILE* ExtractUtilIncludes(FILE *fp, SFNode *node) { char fname[100]; sprintf(fname, "%s.utinc", node->typeId); fprintf(stderr, "Extracting utility includes to %s ...\n", fname); FILE *utinc = fopen(fname, "w"); char *delim1 = UtilityIncludesStartDelim(node); char *delim2 = UtilityIncludesEndDelim(node); Extract(fp, delim1, delim2, utinc); fclose(utinc); return fopen(fname, "r"); } static FILE* ExtractUtilMembers(FILE *fp, SFNode *node) { char fname[100]; sprintf(fname, "%s.utmem", node->typeId); fprintf(stderr, "Extracting utility member code to %s ...\n", fname); FILE *utmem = fopen(fname, "w"); char *delim1 = UtilityMembersStartDelim(node); char *delim2 = UtilityMembersEndDelim(node); Extract(fp, delim1, delim2, utmem); fclose(utmem); return fopen(fname, "r"); } bool generate_private, generate_public, generate_header; static void GenerateNodeCode(SFNode *node) { char fname[100]; FILE *fp; if (generate_header) { FILE *util_includes=0, *util_members=0; sprintf(fname, "%s.H", node->typeId); if (Backup(fname)) { char bakfname[100]; sprintf(bakfname, "%s.H.bak", node->typeId); FILE *bak = fopen(bakfname, "r"); if (!bak) Fatal(1, "GenerateNodeCode", "Can't open the backup file I just generated!!!"); util_includes = ExtractUtilIncludes(bak, node); util_members = ExtractUtilMembers(bak, node); fclose(bak); } fprintf(stderr, "Generating %s ...\n", fname); fp = fopen(fname, "w"); GenerateHeader(fp, node, util_includes, util_members); fclose(fp); if (util_includes) fclose(util_includes); if (util_members) fclose(util_members); } if (generate_public) { sprintf(fname, "%s.C", node->typeId); Backup(fname); fprintf(stderr, "Generating %s ...\n", fname); fp = fopen(fname, "w"); GeneratePublicSource(fp, node); fclose(fp); } if (generate_private) { sprintf(fname, "%sP.C", node->typeId); Backup(fname); sprintf(fname, "%sP.C", node->typeId); fprintf(stderr, "Generating %s ...\n", fname); fp = fopen(fname, "w"); GeneratePrivateSource(fp, node); fclose(fp); } } void DumpNodeCatalog(void) { for (int i=0; itypeId) == 0) return nodeCatalog[i]; return 0; } static void AddDependency(SFNode *child, SFNode *parent) { int i; for (i=0; idependNodes.size; i++) if (child->dependNodes[i] == parent) return; child->dependNodes.append(parent); } // the node is considered an ancestor of itself. static bool IsAncestor(SFNode* child, SFNode* parent) { if (strcmp(child->typeId, parent->typeId)==0) return true; for (int i=0; iparentClassIds.size; i++) if (IsAncestor(LookupBuiltin(child->parentClassIds[i]), parent)) return true; return false; } static void AddParent(SFNode* child, SFNode* parent) { // remove ancestors of parent from child->parentNodes int i; array tmp = child->parentNodes; for (i=0; iparentNodes.size = 0; for (i=0; iparentNodes.append(tmp[i]); // check whether parent is ancestor of any already recorded parent node, for (i=0; iparentNodes.size; i++) if (IsAncestor(child->parentNodes[i], parent)) return; // if not, add the new parent node child->parentNodes.append(parent); AddDependency(child, parent); } // constructs list of parent nodes (duplicates etc... resolved) // and list of all nodes upon which the implementation of the node class // depends. static void ResolveDependencies(SFNode *node) { int i; for (i=0; iparentClassIds.size; i++) { SFNode *n = LookupBuiltin(node->parentClassIds[i]); if (!n) Fatal(1, NULL, "node %s parent %s type not found", node->typeId, node->parentClassIds[i]); else { AddParent(node, n); n->isParent = true; } } for (i=0; inrInterfaceDeclarations; i++) { interfaceDeclaration *decl = &node->interface[i]; if (!decl->nodeClassId) { if ((decl->kind==kexposedField || decl->kind==kfield) && (decl->type==tSFNode || decl->type==tMFNode)) Warning(NULL, "No node %s.%s SF|MFNode class field type given", node->typeId, decl->Id); continue; } SFNode *n = LookupBuiltin(decl->nodeClassId); if (!n) Fatal(1, NULL, "node %s.%s SF|MFNode class field %s type not found", node->typeId, decl->Id, decl->nodeClassId); else AddDependency(node, n); } } static void ResolveDependencies(void) { for (int i=0; i= argc) { usage(); return 1; } if (strcmp(argv[i], "all") == 0) DumpNodeCatalog(); else { for (; i