/* DataDraw Copyright(C) 1992-2006 Bill Cox This program can be distributed under the terms of the GNU Library GPL. See the file COPYING.LIB. */ #include "dv.h" static char *dvPrefix; /*-------------------------------------------------------------------------------------------------- Write out constructor/destructor variable declarations. --------------------------------------------------------------------------------------------------*/ static void writeClassConstructorDestructorVariables( dvClass theClass) { char *name = dvClassGetName(theClass); dvWrtemp(dvFile, "extern void(*%0%1ConstructorCallback)(%2%1);\n", dvPrefix, name, dvClassGetPrefix(theClass)); if(dvClassGetMemoryStyle(theClass) != MEM_CREATE_ONLY) { dvWrtemp(dvFile, "extern void(*%0%1DestructorCallback)(%2%1);\n", dvPrefix, name, dvClassGetPrefix(theClass)); } } /*-------------------------------------------------------------------------------------------------- Write out all the constructor/destructor variable declarations. --------------------------------------------------------------------------------------------------*/ static void writeConstructorDestructorVariables( dvModule module) { dvClass theClass; dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Constructor/Destructor hooks.\n" "----------------------------------------------------------------------------------------*/\n" ); dvForeachModuleClass(module, theClass) { writeClassConstructorDestructorVariables(theClass); } dvEndModuleClass; fputs("\n", dvFile); } /*-------------------------------------------------------------------------------------------------- Write out the general/internal fields in root struct for theClass. --------------------------------------------------------------------------------------------------*/ static void writeClassRootMemoryManagementFields( dvClass theClass) { char *name = dvClassGetName(theClass); if(dvClassGetBaseClass(theClass) == dvClassNull) { if(dvClassGetMemoryStyle(theClass) == MEM_FREE_LIST) { dvWrtemp(dvFile, " %0%1 firstFree%1;\n", dvPrefix, name); } dvWrtemp(dvFile, " %1 used%0, allocated%0;\n", name, dvClassGetReferenceTypeName(theClass)); } else { dvWrtemp(dvFile, " %1 allocated%0;\n", name, dvClassGetReferenceTypeName(theClass)); } } /*-------------------------------------------------------------------------------------------------- Write out the property fields in root struct for theClass. --------------------------------------------------------------------------------------------------*/ static void writeClassRootPropertyFields( dvClass theClass) { char *name = dvClassGetName(theClass); dvProperty prop; dvForeachClassProperty(theClass, prop) { if(dvPropertyArray(prop)) { dvWrtemp(dvFile, " uint32 used%0%1, allocated%0%1, free%0%1;\n", name, dvPropertyGetName(prop)); } } dvEndClassProperty; } /*-------------------------------------------------------------------------------------------------- Write root structure fields for theClass. --------------------------------------------------------------------------------------------------*/ static void writeClassRootFields( dvClass theClass) { writeClassRootMemoryManagementFields(theClass); writeClassRootPropertyFields(theClass); } /*-------------------------------------------------------------------------------------------------- Write out the general/internal macros in root struct for theClass. --------------------------------------------------------------------------------------------------*/ static void writeClassRootMemoryManagementMacros( dvClass theClass) { char *name = dvClassGetName(theClass); char *preString, *postString; if(dvClassGetBaseClass(theClass) == dvClassNull) { if(dvClassGetMemoryStyle(theClass) == MEM_FREE_LIST) { dvWrtemp(dvFile, "#define %0FirstFree%1() %0RootData.firstFree%1\n", dvPrefix, name); preString = dvSwrtemp(!dvClassUndo(theClass)? "" : " \\\n (void)utRecordGlobal(%0ModuleID, %2, &%0RootData.firstFree%1, true)," " \\\n ", dvPrefix, name, utSprintf("%u", dvClassGetReferenceSize(theClass) >> 3)); postString = dvSwrtemp(!dvClassRedo(theClass)? "" : ", \\\n (void)utRecordGlobal(%0ModuleID, %2, &%0RootData.firstFree%1, false)", dvPrefix, name, utSprintf("%u", dvClassGetReferenceSize(theClass) >> 3)); dvWrtemp(dvFile, "#define %0SetFirstFree%1(value) (%2%0RootData.firstFree%1 = (value)%3)\n", dvPrefix, name, preString, postString); } dvWrtemp(dvFile, "#define %0Used%1() %0RootData.used%1\n" "#define %0Allocated%1() %0RootData.allocated%1\n", dvPrefix, name); preString = dvSwrtemp(!dvClassUndo(theClass)? "" : " \\\n (void)utRecordGlobal(%0ModuleID, %2, &%0RootData.used%1, true), \\\n ", dvPrefix, name, utSprintf("%u", dvClassGetReferenceSize(theClass) >> 3)); postString = dvSwrtemp(!dvClassRedo(theClass)? "" : ", \\\n (void)utRecordGlobal(%0ModuleID, %2, &%0RootData.used%1, false)", dvPrefix, name, utSprintf("%u", dvClassGetReferenceSize(theClass) >> 3)); dvWrtemp(dvFile, "#define %0SetUsed%1(value) (%2%0RootData.used%1 = (value)%3)\n", dvPrefix, name, preString, postString); preString = dvSwrtemp(!dvClassUndo(theClass)? "" : " \\\n (void)utRecordGlobal(%0ModuleID, %2, &%0RootData.allocated%1, true)," " \\\n ", dvPrefix, name, utSprintf("%u", dvClassGetReferenceSize(theClass) >> 3)); postString = dvSwrtemp(!dvClassRedo(theClass)? "" : ", \\\n (void)utRecordGlobal(%0ModuleID, %2, &%0RootData.allocated%1, false)", dvPrefix, name, utSprintf("%u", dvClassGetReferenceSize(theClass) >> 3)); dvWrtemp(dvFile, "#define %0SetAllocated%1(value) (%2%0RootData.allocated%1 = (value)%3)\n", dvPrefix, name, preString, postString); } else { dvWrtemp(dvFile, "#define %0Allocated%1() %0RootData.allocated%1\n", dvPrefix, name); preString = dvSwrtemp(!dvClassUndo(theClass)? "" : " \\\n (void)utRecordGlobal(%0ModuleID, %2, &%0RootData.allocated%1, true)," " \\\n", dvPrefix, name, utSprintf("%u", dvClassGetReferenceSize(theClass) >> 3)); postString = dvSwrtemp(!dvClassRedo(theClass)? "" : ", \\\n (void)utRecordGlobal(%0ModuleID, %2, &%0RootData.allocated%1, false)", dvPrefix, name, utSprintf("%u", dvClassGetReferenceSize(theClass) >> 3)); dvWrtemp(dvFile, "#define %0SetAllocated%1(value) (%2%0RootData.allocated%1 = (value)%3)\n", dvPrefix, name, preString, postString); } } /*-------------------------------------------------------------------------------------------------- Write out the property macros in root struct for theClass. --------------------------------------------------------------------------------------------------*/ static void writeClassRootPropertyMacros( dvClass theClass) { char *name = dvClassGetName(theClass); dvProperty prop; char *preString, *postString; dvForeachClassProperty(theClass, prop) { if(dvPropertyArray(prop)) { dvWrtemp(dvFile, "#define %0Used%1%2() %0RootData.used%1%2\n" "#define %0Allocated%1%2() %0RootData.allocated%1%2\n" "#define %0Free%1%2() %0RootData.free%1%2\n", dvPrefix, name, dvPropertyGetName(prop)); preString = dvSwrtemp(!dvClassUndo(theClass)? "" : " \\\n (void)utRecordGlobal(%0ModuleID, sizeof(uint32), &%0RootData.used%1%2," " true), \\\n ", dvPrefix, name, dvPropertyGetName(prop)); postString = dvSwrtemp(!dvClassRedo(theClass)? "" : ", \\\n (void)utRecordGlobal(%0ModuleID, sizeof(uint32), &%0RootData.used%1%2," " false)", dvPrefix, name, dvPropertyGetName(prop)); dvWrtemp(dvFile, "#define %0SetUsed%1%2(value) (%3%0RootData.used%1%2 = (value)%4)\n", dvPrefix, name, dvPropertyGetName(prop), preString, postString); preString = dvSwrtemp(!dvClassUndo(theClass)? "" : " \\\n (void)utRecordGlobal(%0ModuleID, sizeof(uint32), " "&%0RootData.allocated%1%2, true), \\\n ", dvPrefix, name, dvPropertyGetName(prop)); postString = dvSwrtemp(!dvClassRedo(theClass)? "" : ", \\\n (void)utRecordGlobal(%0ModuleID, sizeof(uint32), " "&%0RootData.allocated%1%2, false)", dvPrefix, name, dvPropertyGetName(prop)); dvWrtemp(dvFile, "#define %0SetAllocated%1%2(value) (%3%0RootData.allocated%1%2 = (value)%4)\n", dvPrefix, name, dvPropertyGetName(prop), preString, postString); preString = dvSwrtemp(!dvClassUndo(theClass)? "" : " \\\n (void)utRecordGlobal(%0ModuleID, sizeof(uint32), " "&%0RootData.free%1%2, true), \\\n ", dvPrefix, name, dvPropertyGetName(prop)); postString = dvSwrtemp(!dvClassRedo(theClass)? "" : ", \\\n (void)utRecordGlobal(%0ModuleID, sizeof(uint32), " "&%0RootData.free%1%2, false)", dvPrefix, name, dvPropertyGetName(prop)); dvWrtemp(dvFile, "#define %0SetFree%1%2(value) (%3%0RootData.free%1%2 = (value)%4)\n", dvPrefix, name, dvPropertyGetName(prop), preString, postString); } } dvEndClassProperty; } /*-------------------------------------------------------------------------------------------------- Write out the macros for the gen/internal fields in root struct for theClass. --------------------------------------------------------------------------------------------------*/ static void writeClassRootMacros( dvClass theClass) { writeClassRootMemoryManagementMacros(theClass); writeClassRootPropertyMacros(theClass); } /*-------------------------------------------------------------------------------------------------- Write the root structure and associated macros. --------------------------------------------------------------------------------------------------*/ static void writeRoot( dvModule module) { dvClass theClass; dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Root structure\n" "----------------------------------------------------------------------------------------*/\n" "struct %0RootType_ {\n" " uint32 hash; /* This depends only on the structure of the database */\n", dvPrefix); dvForeachModuleClass(module, theClass) { writeClassRootFields(theClass); } dvEndModuleClass; dvWrtemp(dvFile, "};\nextern struct %0RootType_ %0RootData;\n\n", dvPrefix); dvWrtemp(dvFile, "#define %0Hash() (%0RootData.hash)\n", dvPrefix); dvForeachModuleClass(module, theClass) { writeClassRootMacros(theClass); } dvEndModuleClass; fputs("\n", dvFile); } /*-------------------------------------------------------------------------------------------------- Write the temporary variable union. --------------------------------------------------------------------------------------------------*/ static void writeTempUnion( dvModule module) { dvClass theClass; dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Temp Union structure - Macro temp variables, use only one\n" "----------------------------------------------------------------------------------------*/\n" "union %0TempType_ {\n" , dvPrefix); dvForeachModuleClass(module, theClass) { dvWrtemp(dvFile, " %0%1 %1;\n", dvClassGetPrefix(theClass), dvClassGetName(theClass)); } dvEndModuleClass; fputs("};\n\n", dvFile); dvWrtemp(dvFile, "extern union %0TempType_ %0Temp_;\n\n", dvPrefix); } /*-------------------------------------------------------------------------------------------------- Write out union types for the class. --------------------------------------------------------------------------------------------------*/ static void writeUnionTypes( dvClass theClass) { dvUnion theUnion; dvProperty property; if(dvClassGetFirstUnion(theClass) == dvUnionNull) { return; } dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Unions for class %0.\n" "----------------------------------------------------------------------------------------*/\n" , dvClassGetName(theClass)); dvForeachClassUnion(theClass, theUnion) { dvWrtemp(dvFile, "typedef union {\n"); dvForeachUnionProperty(theUnion, property) { dvWrtemp(dvFile, " %0 %1;\n", dvPropertyGetTypeName(property), dvPropertyGetName(property)); }dvEndUnionProperty; dvWrtemp(dvFile, "} %0;\n\n", dvUnionGetTypeName(theUnion)); } dvEndClassUnion; } /*-------------------------------------------------------------------------------------------------- Write out the property fields for theClass. --------------------------------------------------------------------------------------------------*/ static void writeClassFields( dvClass theClass) { dvUnion theUnion; dvProperty prop; dvForeachClassProperty(theClass, prop) { if(!dvPropertySparse(prop)) { if(dvPropertyGetUnion(prop) == dvUnionNull) { dvWrtemp(dvFile, " %0 *%1;\n", dvPropertyGetTypeName(prop), dvPropertyGetName(prop)); } } } dvEndClassProperty; dvForeachClassUnion(theClass, theUnion) { dvWrtemp(dvFile, " %0 *%1;\n", dvUnionGetTypeName(theUnion), dvUnionGetFieldName(theUnion)); } dvEndClassUnion; } /*-------------------------------------------------------------------------------------------------- Write out the structure for a class. --------------------------------------------------------------------------------------------------*/ static void writeClassStruct( dvClass theClass) { char *name = dvClassGetName(theClass); dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Fields for class %1.\n" "----------------------------------------------------------------------------------------*/\n" "struct %0%1Fields {\n", dvPrefix, name); writeClassFields(theClass); dvWrtemp(dvFile, "};\n" "extern struct %0%1Fields %0%1s;\n" "\n", dvPrefix, name); } /*-------------------------------------------------------------------------------------------------- Write the header's bottom portion. --------------------------------------------------------------------------------------------------*/ static void writeHeaderBot( dvModule module) { dvWrtemp(dvFile, "extern uint8 %0ModuleID;\n", dvPrefix); dvWrtemp(dvFile, "void %0DatabaseStart(void);\n" "void %0DatabaseStop(void);\n" "#if defined __cplusplus\n" "}\n" "#endif\n\n" "#endif\n", dvPrefix); } /*-------------------------------------------------------------------------------------------------- class has bit fields --------------------------------------------------------------------------------------------------*/ static bool classHasBitfields( dvClass theClass) { dvProperty prop; dvForeachClassProperty(theClass, prop) { if(dvPropertyGetType(prop) == PROP_BIT) { return true; } } dvEndClassProperty; return false; } /*-------------------------------------------------------------------------------------------------- Write object's create function declaration. --------------------------------------------------------------------------------------------------*/ static void writeClassCreateExternFunc( dvClass theClass) { dvProperty prop; char *name = dvClassGetName(theClass); if(dvClassGetBaseClass(theClass) == dvClassNull) { if(dvClassGetMemoryStyle(theClass) == MEM_FREE_LIST) { dvWrtemp(dvFile, "#define %0%1Free(%1) (", dvPrefix, name); dvForeachClassProperty(theClass, prop) { if(dvPropertyArray(prop)) { dvWrtemp(dvFile, "%0%1Free%2s(%1), \\\n ", dvPrefix, name, dvPropertyGetName(prop)); } } dvEndClassProperty; dvWrtemp(dvFile, "%0%1SetNextFree(%1, %0RootData.firstFree%1), \\\n" " %0SetFirstFree%1(%1))\n" "void %0%1Destroy(%0%1 %1);\n", dvPrefix, name); } dvWrtemp(dvFile, "void %0%1AllocMore(void);\n", dvPrefix, name); dvWrtemp(dvFile, "void %0%1CopyProps(%0%1 %0Old%1, %0%1 %0New%1);\n", dvPrefix, name); if(classHasBitfields(theClass)) { dvWrtemp(dvFile, "void %0%1SetBitfield(%0%1 _%1, uint32 bitfield);\n", dvPrefix, name); dvWrtemp(dvFile, "uint32 %0%1GetBitfield(%0%1 _%1);\n", dvPrefix, name); } } } /*-------------------------------------------------------------------------------------------------- Write the object's function declarations for property allocs. --------------------------------------------------------------------------------------------------*/ static void writeClassPropExternFuncs( dvClass theClass) { char *name = dvClassGetName(theClass); dvProperty prop; dvForeachClassProperty(theClass, prop) { if(dvPropertyArray(prop)) { dvWrtemp(dvFile, "void %0%1Alloc%2s(%3%1 %1, uint32 num%2s);\n" "void %0%1Resize%2s(%3%1 %1, uint32 num%2s);\n" "void %0%1Free%2s(%3%1 %1);\n" "void %0Compact%1%2s(void);\n", dvPrefix, name, dvPropertyGetName(prop), dvClassGetPrefix(theClass)); } } dvEndClassProperty; } /*-------------------------------------------------------------------------------------------------- Write the object's extern function declarations for relationships. --------------------------------------------------------------------------------------------------*/ static void writeClassRelExternFuncs( dvClass theClass) { dvRelationship relationship; dvClass childClass; dvRelationshipType type; char *name = dvClassGetName(theClass); char *childLabel, *childName; dvForeachClassChildRelationship(theClass, relationship) { type = dvRelationshipGetType(relationship); childClass = dvRelationshipGetChildClass(relationship); childLabel = dvRelationshipGetChildLabel(relationship); childName = dvClassGetName(childClass); if(dvRelationshipAccessChild(relationship)) { if(type == REL_LINKED_LIST || type == REL_DOUBLY_LINKED || type == REL_TAIL_LINKED || type == REL_HASHED) { dvWrtemp(dvFile, "void %0%1Insert%2%3(%4%1 %1, %5%3 _%3);\n" "void %0%1Remove%2%3(%4%1 %1, %5%3 _%3);\n" "void %0%1InsertAfter%2%3(%4%1 %1, %5%3 prev%3, %5%3 _%3);\n", dvPrefix, name, childLabel, childName, dvClassGetPrefix(theClass), dvClassGetPrefix(childClass)); if(type != REL_LINKED_LIST) { dvWrtemp(dvFile, "void %0%1Append%2%3(%4%1 %1, %5%3 _%3);\n", dvPrefix, name, childLabel, childName, dvClassGetPrefix(theClass), dvClassGetPrefix(childClass)); } } else if(type == REL_ARRAY || type == REL_HEAP) { dvWrtemp(dvFile, "void %0%1Insert%2%3(%4%1 %1, uint32 x, %5%3 _%3);\n" "void %0%1Append%2%3(%4%1 %1, %5%3 _%3);\n", dvPrefix, name, childLabel, dvClassGetName(childClass), dvClassGetPrefix(theClass), dvClassGetPrefix(childClass)); if(dvRelationshipAccessParent(relationship)) { dvWrtemp(dvFile, "void %0%1Remove%2%3(%4%1 %1, %5%3 _%3);\n", dvPrefix, name, childLabel, dvClassGetName(childClass), dvClassGetPrefix(theClass), dvClassGetPrefix(childClass)); } if(type == REL_HEAP) { dvWrtemp(dvFile, "static void %0%1Swap%2%3(%4%1 %1, uint32 x, uint32 y);\n" "static void %0%1HeapDown%2%3(%4%1 %1, uint32 arg_x);\n" "static void %0%1HeapUp%2%3(%4%1 %1, uint32 arg_x);\n" "void %0%1Improve%2%3(%5%3 %3);\n" "void %0%1Push%2%3(%4%1 %1, %5%3 %3);\n" "%5%3 %0%1Peek%2%3(%4%1 %1);\n" "%5%3 %0%1Pop%2%3(%4%1 %1);\n" "int %0%1Compare%2%3(%5%3 a, %5%3 b);\n", dvPrefix, name, childLabel, dvClassGetName(childClass), dvClassGetPrefix(theClass), dvClassGetPrefix(childClass)); } } } } dvEndClassChildRelationship; } /*-------------------------------------------------------------------------------------------------- Write the external function declarations for an object. --------------------------------------------------------------------------------------------------*/ static void writeClassExternFuncs( dvClass theClass) { fputs("\n", dvFile); writeClassCreateExternFunc(theClass); writeClassPropExternFuncs(theClass); writeClassRelExternFuncs(theClass); fputs("\n", dvFile); } /*-------------------------------------------------------------------------------------------------- Write the class's property access macros. --------------------------------------------------------------------------------------------------*/ static void writeClassPropMacros( dvClass theClass) { dvUnion theUnion; dvProperty prop; char *name; char *propName, *preString, *postString; dvForeachClassProperty(theClass, prop) { name = dvClassGetName(theClass); propName = dvPropertyGetName(prop); if(dvPropertyArray(prop)) { dvWrtemp(dvFile, "#if defined(DD_DEBUG)\n" "#define %0%1Check%2Index(%1, x) ((%4)(x) < %0%1GetNum%2(%1)? (x) : \\\n" " (utAssert(false),(x)))\n" "#else\n" "#define %0%1Check%2Index(%1, x) (x)\n" "#endif\n" "#define %0%1Geti%2(_%1, x) ((%0%1s.%2)[ \\\n" " %0%1Get%2Index(_%1) + %0%1Check%2Index(_%1, (x))])\n" "#define %0%1Get%2(%1) (%0%1s.%2 + %0%1Get%2Index(%1))\n" "#define %0%1Get%2s %0%1Get%2\n", dvPrefix, name, propName, dvClassGetPrefix(theClass), dvClassGetReferenceTypeName(theClass)); preString = dvSwrtemp(!dvClassUndo(theClass)? "" : " \\\n (void)utRecordArray(%0ModuleID, %3, %0%1Get%2Index(%1), " "%0%1GetNum%2(%1), true), \\\n ", dvPrefix, name, propName, utSprintf("%u", dvPropertyGetFieldNumber(prop))); postString = dvSwrtemp(!dvClassRedo(theClass)? "" : ", \\\n (void)utRecordArray(%0ModuleID, %3, %0%1Get%2Index(%1), " "%0%1GetNum%2(%1), false)", dvPrefix, name, propName, utSprintf("%u", dvPropertyGetFieldNumber(prop))); dvWrtemp(dvFile, "#define %0%1Set%2(%1, valuePtr, num%2) (%0%1Resize%2s(%1, num%2), %4memcpy(%0%1Get%2s(%1), valuePtr, \\\n" " num%2*sizeof(%3))%5)\n", dvPrefix, name, propName, dvPropertyGetTypeName(prop), preString, postString); preString = dvSwrtemp(!dvClassUndo(theClass)? "" : " \\\n (void)utRecordField(%0ModuleID, %3, %0%1Get%2Index(%1) + (x), true)," " \\\n ", dvPrefix, name, propName, utSprintf("%u", dvPropertyGetFieldNumber(prop))); postString = dvSwrtemp(!dvClassRedo(theClass)? "" : ", \\\n (void)utRecordField(%0ModuleID, %3, %0%1Get%2Index(%1) + (x), false)", dvPrefix, name, propName, utSprintf("%u", dvPropertyGetFieldNumber(prop))); dvWrtemp(dvFile, "#define %0%1Seti%2(%1, x, value) (%3(%0%1s.%2)[ \\\n" " %0%1Get%2Index(%1) + %0%1Check%2Index(%1, (x))] = (value)%4)\n", dvPrefix, name, propName, preString, postString); } else if(dvPropertySparse(prop)) { /* Access the data through the hash table */ dvWrtemp(dvFile, "extern %5 %0%1%3%2(%4%1 %1);\n" "extern void %0%1Set%2(%4%1 %1, %5 value);\n", dvPrefix, name, propName, dvPropertyGetType(prop) == PROP_BOOL? "" : "Get", dvClassGetPrefix(theClass), dvPropertyGetTypeName(prop)); } else { theUnion = dvPropertyGetUnion(prop); if(theUnion == dvUnionNull) { preString = dvSwrtemp(!dvClassUndo(theClass)? "" : " \\\n (void)utRecordField(%0ModuleID, %3, %2%12ValidIndex(_%1)%4, true), \\\n ", dvPrefix, name, dvClassGetPrefix(theClass), utSprintf("%u", dvPropertyGetFieldNumber(prop)), dvPropertyGetType(prop) == PROP_BIT? " >> 3" : ""); postString = dvSwrtemp(!dvClassRedo(theClass)? "" : ", \\\n (void)utRecordField(%0ModuleID, %3, %2%12ValidIndex(_%1)%4, false)", dvPrefix, name, dvClassGetPrefix(theClass), utSprintf("%u", dvPropertyGetFieldNumber(prop)), dvPropertyGetType(prop) == PROP_BIT? " >> 3" : ""); } else { preString = dvSwrtemp(!dvClassUndo(theClass)? "" : " \\\n (void)utRecordField(%0ModuleID, %3, %2%12ValidIndex(_%1), true), \\\n ", dvPrefix, name, dvClassGetPrefix(theClass), utSprintf("%u", dvUnionGetFieldNumber(theUnion))); postString = dvSwrtemp(!dvClassRedo(theClass)? "" : ", \\\n (void)utRecordField(%0ModuleID, %3, %2%12ValidIndex(_%1), false)", dvPrefix, name, dvClassGetPrefix(theClass), utSprintf("%u", dvUnionGetFieldNumber(theUnion))); } if(dvPropertyGetType(prop) == PROP_BIT) { dvWrtemp(dvFile, "#define %0%1%2(_%1) (((%0%1s.%2)[%3%12ValidIndex(_%1) >> 3] >> \\\n" " (%3%12ValidIndex(_%1) & 7)) & 1)\n" "#define %0%1Set%2(_%1, value) (%4(%0%1s.%2)[%3%12ValidIndex(_%1) >> 3] = \\\n" " (uint8)((%4(%0%1s.%2)[%3%12ValidIndex(_%1) >> 3] & ~(1 << (%3%12ValidIndex(_%1) & 7))) | \\\n" " (((value) != 0) << (%3%12ValidIndex(_%1) & 7)))%5)\n", dvPrefix, name, propName, dvClassGetPrefix(theClass), preString, postString); } else { if(theUnion == dvUnionNull) { dvWrtemp(dvFile, "#define %0%1%3%2(_%1) (%0%1s.%2[%4%12ValidIndex(_%1)])\n" "#define %0%1Set%2(_%1, value) (%5(%0%1s.%2)[%4%12ValidIndex(_%1)] = (value)%6)\n", dvPrefix, name, propName, dvPropertyGetType(prop) == PROP_BOOL? "" : "Get", dvClassGetPrefix(theClass), preString, postString); } else { dvWrtemp(dvFile, "#define %0%1%3%2(_%1) (%0%1s.%7[%4%12ValidIndex(_%1)].%2)\n" "#define %0%1Set%2(_%1, value) \\\n" " (%5%0%1s.%7[%4%12ValidIndex(_%1)].%2 = (value)%6)\n", dvPrefix, name, propName, dvPropertyGetType(prop) == PROP_BOOL? "" : "Get", dvClassGetPrefix(theClass), preString, postString, dvUnionGetFieldName(theUnion)); } } } } dvEndClassProperty; } /*-------------------------------------------------------------------------------------------------- Return a string representing the parameters to the find function for the relationship. --------------------------------------------------------------------------------------------------*/ static char *getHashedRelationshipKeyParameters( dvRelationship relationship) { dvProperty property; dvKey key; char *parameters = ""; dvForeachRelationshipKey(relationship, key) { property = dvKeyGetProperty(key); parameters = utSprintf("%s, %s %s", parameters, dvPropertyGetTypeName(property), dvPropertyGetName(property)); } dvEndRelationshipKey; return parameters; } /*-------------------------------------------------------------------------------------------------- Write theClass's child rel macros. --------------------------------------------------------------------------------------------------*/ static void writeClassChildRelMacros( dvClass theClass) { dvRelationship relationship; dvClass childClass; dvRelationshipType type; char *name = dvClassGetName(theClass); char *keyParams; dvForeachClassChildRelationship(theClass, relationship) { type = dvRelationshipGetType(relationship); if(dvRelationshipAccessChild(relationship)) { childClass = dvRelationshipGetChildClass(relationship); if(type == REL_HASHED) { keyParams = getHashedRelationshipKeyParameters(relationship); dvWrtemp(dvFile, "%5%3 %0%1Find%2%3(%4%1 %1%6);\n" "void %0%1Rename%2%3(%4%1 %1, %5%3 _%3, utSym sym);\n", dvPrefix, name, dvRelationshipGetChildLabel(relationship), dvClassGetName(childClass), dvClassGetPrefix(theClass), dvClassGetPrefix(childClass), keyParams); if(dvRelationshipHashedByName(relationship)) { dvWrtemp(dvFile, "#define %0%2Get%1Name(%2) utSymGetName(%0%2Get%1Sym(%2))\n", dvPrefix, dvRelationshipGetChildLabel(relationship), dvClassGetName(childClass)); } } if(type == REL_LINKED_LIST || type == REL_DOUBLY_LINKED || type == REL_TAIL_LINKED || type == REL_HASHED) { dvWrtemp(dvFile, "#define %0Foreach%1%2%3(pVar, cVar) \\\n" " for(cVar = %0%1GetFirst%2%3(pVar); cVar != %5%3Null; \\\n" " cVar = %0%3GetNext%1%2%3(cVar))\n" "#define %0End%1%2%3\n", dvPrefix, name, dvRelationshipGetChildLabel(relationship), dvClassGetName(childClass), dvClassGetPrefix(theClass), dvClassGetPrefix(childClass)); dvWrtemp(dvFile, "#define %0SafeForeach%1%2%3(pVar, cVar) { \\\n" " %5%3 _next%3; \\\n" " for(cVar = %0%1GetFirst%2%3(pVar); cVar != %5%3Null; cVar = _next%3) { \\\n" " _next%3 = %0%3GetNext%1%2%3(cVar);\n" "#define %0EndSafe%1%2%3 }}\n", dvPrefix, name, dvRelationshipGetChildLabel(relationship), dvClassGetName(childClass), dvClassGetPrefix(theClass), dvClassGetPrefix(childClass)); } if(type == REL_ARRAY || type == REL_HEAP) { dvWrtemp(dvFile, "#define %0Foreach%1%2%3(pVar, cVar) { \\\n" " uint32 _x%3; \\\n" " for(_x%3 = 0; _x%3 < %0%1GetUsed%2%3(pVar); _x%3++) { \\\n" " cVar = %0%1Geti%2%3(pVar, _x%3); \\\n" " if(cVar != %4%3Null) {\n" "#define %0End%1%2%3 }}}\n", dvPrefix, name, dvRelationshipGetChildLabel(relationship), dvClassGetName(childClass), dvClassGetPrefix(childClass)); } } } dvEndClassChildRelationship; } /*-------------------------------------------------------------------------------------------------- Write the constructor callback in the creation macro. --------------------------------------------------------------------------------------------------*/ static void writeClassConstructorCallback( dvClass theClass) { dvWrtemp(dvFile, " %0%1ConstructorCallback != NULL && (%0%1ConstructorCallback(%0Temp_.%1), true), \\\n", dvPrefix, dvClassGetName(theClass)); } /*-------------------------------------------------------------------------------------------------- Write code to initialize properties of an object. --------------------------------------------------------------------------------------------------*/ void writePropertyInits( dvClass theClass) { dvUnion theUnion; dvProperty prop; char *nullObj; dvForeachClassProperty(theClass, prop) { if(dvPropertyArray(prop)) { dvWrtemp(dvFile, " %0%1SetNum%2(%0Temp_.%1, 0), \\\n", dvPrefix, dvClassGetName(theClass), dvPropertyGetName(prop)); } else { theUnion = dvPropertyGetUnion(prop); if(theUnion == dvUnionNull || dvUnionGetFirstProperty(theUnion) == prop) { nullObj = dvPropertyFindInitializer(prop); if(dvPropertyGetType(prop) != PROP_TYPEDEF) { dvWrtemp(dvFile, " %0%1Set%2(%0Temp_.%1, %3), \\\n", dvPrefix, dvClassGetName(theClass), dvPropertyGetName(prop), nullObj); } } } } dvEndClassProperty; } /*-------------------------------------------------------------------------------------------------- Write a create macro for a free-list class. --------------------------------------------------------------------------------------------------*/ static void writeCreateMacroForFreeListClass( dvClass theClass, bool initFields) { char *name = dvClassGetName(theClass); dvWrtemp(dvFile, "#define %0%2%1() ( \\\n", dvPrefix, initFields ? "Alloc" : "AllocRaw", name); dvWrtemp(dvFile, " %0RootData.firstFree%1 != %0%1Null? \\\n" " (%0Temp_.%1 = %0RootData.firstFree%1, \\\n" " %0SetFirstFree%1(%0%1NextFree(%0Temp_.%1)), true) \\\n" " : (%0RootData.used%1 == %0RootData.allocated%1 && (%0%1AllocMore(), true), \\\n" " %0Temp_.%1 = %0Index2%1(%0RootData.used%1), \\\n" " %0SetUsed%1(%0Used%1() + 1)), \\\n", dvPrefix, name); if(initFields) { writePropertyInits(theClass); writeClassConstructorCallback(theClass); } dvWrtemp(dvFile, " %0Temp_.%1)\n", dvPrefix, name); } /*-------------------------------------------------------------------------------------------------- Write a create macro for a create-only class. --------------------------------------------------------------------------------------------------*/ static void writeCreateMacroForCreateOnlyClass( dvClass theClass, bool initFields) { char *name = dvClassGetName(theClass); dvWrtemp(dvFile, "#define %0%2%1() ( \\\n", dvPrefix, initFields ? "Alloc" : "AllocRaw", name); dvWrtemp(dvFile, " %0RootData.used%1 == %0RootData.allocated%1 && (%0%1AllocMore(), true), \\\n" " %0Temp_.%1 = %0Index2%1(%0RootData.used%1), \\\n" " %0SetUsed%1(%0Used%1() + 1), \\\n", dvPrefix, name); if(initFields) { writePropertyInits(theClass); writeClassConstructorCallback(theClass); } dvWrtemp(dvFile, " %0Temp_.%1)\n", dvPrefix, name); } /*-------------------------------------------------------------------------------------------------- Write the create macro for theClass. --------------------------------------------------------------------------------------------------*/ static void writeClassCreateMacro( dvClass theClass) { if(dvClassGetMemoryStyle(theClass) == MEM_FREE_LIST) { writeCreateMacroForFreeListClass(theClass, false); writeCreateMacroForFreeListClass(theClass, true); } else if(dvClassGetMemoryStyle(theClass) == MEM_CREATE_ONLY) { writeCreateMacroForCreateOnlyClass(theClass, false); writeCreateMacroForCreateOnlyClass(theClass, true); } else { utExit("Unknown type of memory option for %s", dvClassGetName(theClass)); } } /*-------------------------------------------------------------------------------------------------- Write an init macro for a free-list class. --------------------------------------------------------------------------------------------------*/ static void writeClassInitMacro( dvClass theClass) { char *name = dvClassGetName(theClass); dvWrtemp(dvFile, "#define %0%1Init(%1) (" " %0Temp_.%1 = (%1), \\\n", dvPrefix, name); writePropertyInits(theClass); writeClassConstructorCallback(theClass); dvWrtemp(dvFile, " true)\n", dvPrefix, name); } /*-------------------------------------------------------------------------------------------------- Write all misc. macros for traversal of theClass. --------------------------------------------------------------------------------------------------*/ static void writeClassMiscMacros( dvClass theClass) { char *name = dvClassGetName(theClass); dvProperty prop; char *preString, *postString; dvWrtemp(dvFile, "#define %0%1SetConstructorCallback(func) (%0%1ConstructorCallback = (func))\n" "#define %0%1GetConstructorCallback() (%0%1ConstructorCallback)\n", dvPrefix, name); if(dvClassGetMemoryStyle(theClass) == MEM_CREATE_ONLY) { dvWrtemp(dvFile, "#define %0First%1() (%0RootData.used%1 == 0? %0%1Null : %0Index2%1(0))\n" "#define %0Last%1() (%0RootData.used%1 == 0? %0%1Null : \\\n" " %0Index2%1(%0RootData.used%1 - 1))\n" "#define %0Next%1(%1) (%0%12ValidIndex(%1) + 1 == %0RootData.used%1? %0%1Null : \\\n" " (%1) + 1)\n" "#define %0Prev%1(%1) (%0%12ValidIndex(%1) == 0? %0%1Null : (%1) - 1)\n" "#define %0Foreach%1(var) \\\n" " for(var = %0Index2%1(0); %0%12Index(var) != %0RootData.used%1; var++)\n" "#define %0End%1\n", dvPrefix, name, dvClassGetReferenceTypeName(theClass)); dvWrtemp(dvFile, "#define %0%1FreeAll() (%0SetUsed%1(0)", dvPrefix, name); dvForeachClassProperty(theClass, prop) { if(dvPropertyArray(prop)) { dvWrtemp(dvFile, ", %0SetUsed%1%2(0)" , dvPrefix, name, dvPropertyGetName(prop)); } } dvEndClassProperty; dvWrtemp(dvFile, ")\n"); } else if(dvClassGetMemoryStyle(theClass) == MEM_FREE_LIST) { prop = dvClassGetFreeListProperty(theClass); dvWrtemp(dvFile, "#define %0%1SetDestructorCallback(func) (%0%1DestructorCallback = (func))\n" "#define %0%1GetDestructorCallback() (%0%1DestructorCallback)\n", dvPrefix, name); dvWrtemp(dvFile, "#define %0%1NextFree(_%1) (((%0%1 *)(void *)(%0%1s.%3))[%2%12ValidIndex(_%1)])\n", dvPrefix, name, dvClassGetPrefix(theClass), dvPropertyGetName(prop)); preString = dvSwrtemp(!dvClassUndo(theClass)? "" : " \\\n (void)utRecordField(%0ModuleID, %3, %2%12ValidIndex(%1), true), \\\n ", dvPrefix, name, dvClassGetPrefix(theClass), utSprintf("%u", dvPropertyGetFieldNumber(prop))); postString = dvSwrtemp(!dvClassRedo(theClass)? "" : ", \\\n (void)utRecordField(%0ModuleID, %3, %2%12ValidIndex(%1), false)", dvPrefix, name, dvClassGetPrefix(theClass), utSprintf("%u", dvPropertyGetFieldNumber(prop))); dvWrtemp(dvFile, "#define %0%1SetNextFree(_%1, value) (%4((%0%1 *)(void *)(%0%1s.%3)) \\\n" " [%2%12ValidIndex(_%1)] = (value)%5)\n", dvPrefix, name, dvClassGetPrefix(theClass), dvPropertyGetName(prop), preString, postString); } } /*-------------------------------------------------------------------------------------------------- Write attribute shortcut macros. --------------------------------------------------------------------------------------------------*/ static void writeAttributeShortcuts( dvClass theClass) { dvWrtemp(dvFile, "#define %0%1FindAttribute(_%1, sym) (%0%1GetAttrlist(_%1) == %0AttrlistNull? \\\n" " %0AttributeNull : %0AttrlistFindAttribute(%0%1GetAttrlist(_%1), (sym)))\n" "void %0%1DeleteAttribute(%2%1 _%1, utSym sym);\n" "int64 %0%1GetInt64Attribute(%2%1 _%1, utSym sym);\n" "double %0%1GetDoubleAttribute(%2%1 _%1, utSym sym);\n" "bool %0%1GetBoolAttribute(%2%1 _%1, utSym sym);\n" "utSym %0%1GetSymAttribute(%2%1 _%1, utSym sym);\n" "char *%0%1GetStringAttribute(%2%1 _%1, utSym sym);\n" "uint8 *%0%1GetBlobAttribute(%2%1 _%1, utSym sym, uint32 *length);\n" "void %0%1SetInt64Attribute(%2%1 _%1, utSym sym, int64 value);\n" "void %0%1SetDoubleAttribute(%2%1 _%1, utSym sym, double value);\n" "void %0%1SetBoolAttribute(%2%1 _%1, utSym sym, bool value);\n" "void %0%1SetSymAttribute(%2%1 _%1, utSym sym, utSym value);\n" "void %0%1SetStringAttribute(%2%1 _%1, utSym sym, char *string);\n" "void %0%1SetBlobAttribute(%2%1 _%1, utSym sym, uint8 *data, uint32 length);\n" "#define %0%1GetFirstAttribute(_%1) (%0Temp_.Attrlist = %0%1GetAttrlist(_%1), \\\n" " %0Temp_.Attrlist == %0AttrlistNull? %0AttributeNull : %0AttrlistGetFirstAttribute(%0Temp_.Attrlist))\n" "#define %0Foreach%1Attribute(_%1, attribute) \\\n" " for(attribute = %0%1GetFirstAttribute(_%1), attribute != %0AttributeNull; \\\n" " attribute = %0AttributeGetNextAttrlistAttribute(attribute))\n" "#define %0End%1Attribute\n" "void %0%1CopyAttributes(%2%1 old%1, %2%1 new%1);\n", dvPrefix, dvClassGetName(theClass), dvClassGetPrefix(theClass)); } /*-------------------------------------------------------------------------------------------------- Write all the access/modify macros for theClass. --------------------------------------------------------------------------------------------------*/ static void writeClassMacros( dvClass theClass) { writeClassPropMacros(theClass); writeClassChildRelMacros(theClass); if(dvClassGetBaseClass(theClass) == dvClassNull) { writeClassMiscMacros(theClass); writeClassCreateMacro(theClass); } else { writeClassInitMacro(theClass); } if(dvClassGenerateAttributes(theClass)) { writeAttributeShortcuts(theClass); } } /*-------------------------------------------------------------------------------------------------- Check to see if Typedef section is needed for this tool. --------------------------------------------------------------------------------------------------*/ static bool needTypedefSection( dvModule module) { dvClass theClass; dvForeachModuleClass(module, theClass) { if(dvClassGetBaseClass(theClass) == dvClassNull) { return true; } } dvEndModuleClass; return false; } /*-------------------------------------------------------------------------------------------------- Write the type definitions for handles to objects. --------------------------------------------------------------------------------------------------*/ static void writeTypedefs( dvModule module) { dvClass theClass; dvWrtemp(dvFile, "/* Class reference definitions */\n\n" "#if defined(DD_DEBUG) && !defined(DD_NOSTRICT)\n", dvFile); dvForeachModuleClass(module, theClass) { if(dvClassGetBaseClass(theClass) == dvClassNull) { dvWrtemp(dvFile, "typedef struct _struct_%0%1{char val;} *%0%1;\n" "#define %0%1Null ((%0%1)(%c3_MAX))\n" "#define %0%12Index(%1) ((uint32)((%1) - (%0%1)(0)))\n" "#define %0%12ValidIndex(%1) ((uint32)(%0Valid%1(%1) - (%0%1)(0)))\n" "#define %0Index2%1(x%1) ((%0%1)((x%1) + (%0%1)(0)))\n", dvPrefix, dvClassGetName(theClass), dvClassGetReferenceTypeName(theClass), dvClassGetReferenceTypeName(theClass)); } } dvEndModuleClass; fputs("#else\n", dvFile); dvForeachModuleClass(module, theClass) { if(dvClassGetBaseClass(theClass) == dvClassNull) { dvWrtemp(dvFile, "typedef %2 %0%1;\n" "#define %0%1Null %c3_MAX\n" "#define %0%12Index(%1) (%1)\n" "#define %0%12ValidIndex(%1) (%0Valid%1(%1))\n" "#define %0Index2%1(x%1) ((x%1))\n", dvClassGetPrefix(theClass), dvClassGetName(theClass), dvClassGetReferenceTypeName(theClass), dvClassGetReferenceTypeName(theClass)); } } dvEndModuleClass; fputs("#endif\n\n", dvFile); } /*-------------------------------------------------------------------------------------------------- Write macros for validating object references. --------------------------------------------------------------------------------------------------*/ static void writeValidateMacros( dvModule module) { dvClass theClass; dvWrtemp(dvFile, "/* Validate macros */\n"); fputs("#if defined(DD_DEBUG)\n", dvFile); dvForeachModuleClass(module, theClass) { if(dvClassGetBaseClass(theClass) == dvClassNull) { dvWrtemp(dvFile, "#define %0Valid%1(%1) (utLikely((uint32)((%1) - (%0%1)0) < \\\n" " %0RootData.used%1)? (%1) : (utExit(\"Invalid %1\"), (%0%1)0))\n", dvPrefix, dvClassGetName(theClass)); } } dvEndModuleClass; fputs("#else\n", dvFile); dvForeachModuleClass(module, theClass) { if(dvClassGetBaseClass(theClass) == dvClassNull) { dvWrtemp(dvFile, "#define %0Valid%1(%1) (%1)\n", dvClassGetPrefix(theClass), dvClassGetName(theClass), dvClassGetReferenceTypeName(theClass)); } } dvEndModuleClass; fputs("#endif\n\n", dvFile); } /*-------------------------------------------------------------------------------------------------- Write the enumerated types. --------------------------------------------------------------------------------------------------*/ static void writeEnms( dvModule module) { dvEnum theEnum; dvEntry entry; dvForeachModuleEnum(module, theEnum) { dvWrtemp(dvFile, "/* %0 enumerated type */\n", dvEnumGetName(theEnum)); fputs("typedef enum {\n", dvFile); dvForeachEnumEntry(theEnum, entry) { dvWrtemp(dvFile, " %0%1", utSymGetName(dvEnumGetPrefixSym(theEnum)), dvEntryGetName(entry)); if(dvEntryGetNextEnumEntry(entry) != dvEntryNull) { fprintf(dvFile, " = %u,\n", dvEntryGetValue(entry)); } else { fprintf(dvFile, " = %u\n", dvEntryGetValue(entry)); } } dvEndEnumEntry; dvWrtemp(dvFile, "} %0%1;\n\n", dvPrefix, dvEnumGetName(theEnum)); } dvEndModuleEnum; } /*-------------------------------------------------------------------------------------------------- Write the header's top portion. --------------------------------------------------------------------------------------------------*/ static void writeHeaderTop( dvModule module) { dvLink link; bool hasHeader = false; dvWrtemp(dvFile, "/*----------------------------------------------------------------------------------------\n" " Module header file for: %0 module\n" "----------------------------------------------------------------------------------------*/\n" "#ifndef %c0DATABASE_H\n\n" "#define %c0DATABASE_H\n\n" "#if defined __cplusplus\n" "extern \"C\" {\n" "#endif\n\n" "#ifndef DD_UTIL_H\n" "#include \"ddutil.h\"\n" "#endif\n\n", dvPrefix); if(dvModuleGetFirstTypedef(module) != dvTypedefNull) { dvWrtemp(dvFile, "#include \"%0typedef.h\"\n", dvPrefix); hasHeader = true; } dvForeachModuleImportLink(module, link) { dvWrtemp(dvFile, "#include \"%0database.h\"\n", dvModuleGetPrefix(dvLinkGetExportModule(link))); hasHeader = true; } dvEndModuleImportLink; if(hasHeader) { dvWrtemp(dvFile, "\n"); } } /*-------------------------------------------------------------------------------------------------- Write the overall types in tool including enums. --------------------------------------------------------------------------------------------------*/ static void writeTypes( dvModule module) { if(needTypedefSection(module)) { writeTypedefs(module); } writeEnms(module); } /*-------------------------------------------------------------------------------------------------- Write the header file. --------------------------------------------------------------------------------------------------*/ void dvWriteHeaderFile( dvModule module, char *includeFile) { dvClass theClass; char *fileName = includeFile; if(utDirectoryExists(includeFile)) { fileName = utSprintf("%s%c%sdatabase.h", includeFile, UTDIRSEP, dvModuleGetPrefix(module)); } dvFile = fopen(fileName, "wt"); if(dvFile == NULL) { utError("Could not open file %s", fileName); return; } utLogMessage("Generating header file %s", fileName); dvPrefix = dvModuleGetPrefix(module); writeHeaderTop(module); writeTypes(module); writeValidateMacros(module); dvForeachModuleClass(module, theClass) { writeUnionTypes(theClass); writeClassStruct(theClass); writeClassMacros(theClass); writeClassExternFuncs(theClass); } dvEndModuleClass; writeTempUnion(module); writeConstructorDestructorVariables(module); writeRoot(module); writeHeaderBot(module); fclose(dvFile); }