/* * Copyright (C) 2006 Bill Cox * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA */ /*-------------------------------------------------------------------------------------------------- Random support functions. --------------------------------------------------------------------------------------------------*/ #include #include "dv.h" /*-------------------------------------------------------------------------------------------------- Find the module from the prefix. --------------------------------------------------------------------------------------------------*/ dvModule dvFindModuleFromPrefix( utSym prefix) { dvModule module; dvForeachRootModule(dvTheRoot, module) { if(dvModuleGetPrefixSym(module) == prefix) { return module; } } dvEndRootModule; return dvModuleNull; } /*-------------------------------------------------------------------------------------------------- Find out how many args are used in a template. --------------------------------------------------------------------------------------------------*/ static uint32 countArgs( char *temp) { char c; uint32 maxArg = 0, xArg; while (*temp) { c = *temp++; if (c == '%') { c = *temp; if (c == 'l' || c == 'u' || c == 'c') { temp++; c = *temp; } if(isdigit(c)) { temp++; xArg = c - '0'; if (xArg >= maxArg) { maxArg = xArg + 1; } } else if (c == '%') { temp++; } } } return maxArg; } /*-------------------------------------------------------------------------------------------------- This code manages a simple string buffer. --------------------------------------------------------------------------------------------------*/ static char *prStringBuffer; static uint32 prStringBufferSize; static uint32 prStringBufferPosition; /*-------------------------------------------------------------------------------------------------- Append a string to the string buffer. --------------------------------------------------------------------------------------------------*/ static void appendString( char *string) { uint32 length = strlen(string); if(prStringBufferPosition + length + 1 >= prStringBufferSize) { prStringBufferSize = ((prStringBufferPosition + length + 1)*3) >> 1; utResizeArray(prStringBuffer, prStringBufferSize); } strcpy(prStringBuffer + prStringBufferPosition, string); prStringBufferPosition += length; } /*-------------------------------------------------------------------------------------------------- Append a character to the string buffer. --------------------------------------------------------------------------------------------------*/ static void appendChar( char c) { char string[2]; string[0] = c; string[1] = '\0'; appendString(string); } /*-------------------------------------------------------------------------------------------------- Initialize the utility module, allocating buffers. --------------------------------------------------------------------------------------------------*/ void prUtilStart(void) { prStringBufferSize = 42; prStringBuffer = utNewA(char, prStringBufferSize); prStringBufferPosition = 0; } /*-------------------------------------------------------------------------------------------------- Free memory used by the utility module. --------------------------------------------------------------------------------------------------*/ void prUtilStop(void) { utFree(prStringBuffer); } /*-------------------------------------------------------------------------------------------------- Write a template to a string. --------------------------------------------------------------------------------------------------*/ static void wrtemp( char *temp, va_list ap) { uint32 sArg = countArgs(temp), xArg; char *(args[10]); char *string, *arg; char c; bool lowerCase = false, upperCase = false, caps = false; prStringBufferPosition = 0; prStringBuffer[0] = '\0'; for (xArg = 0; xArg < sArg; xArg++) { args[xArg] = va_arg(ap, char *); } string = temp; while (*string) { c = *string++; if (c == '%') { c = *string; if(c == 'l') { lowerCase = true; c = *++string; } else if(c == 'u') { upperCase = true; c = *++string; } else if(c == 'c') { caps = true; c = *++string; } if(isdigit(c)) { string++; xArg = c - '0'; if(xArg >= sArg) { utExit("exWrtemp: not enough args"); } if (*args[xArg]) { if(lowerCase) { appendChar((char)tolower(*(args[xArg]))); appendString((args[xArg]) + 1); lowerCase = false; } else if(upperCase) { appendChar((char)toupper(*(args[xArg]))); appendString((args[xArg]) + 1); upperCase = false; } else if(caps) { arg = args[xArg]; while(*arg) { appendChar((char)toupper(*arg)); arg++; } caps = false; } else { appendString(args[xArg]); } } } else if (c == '%') { string++; appendChar('%'); } } else { appendChar(c); } } } /*-------------------------------------------------------------------------------------------------- Write a template to a string. --------------------------------------------------------------------------------------------------*/ char *dvSwrtemp( char *temp, ...) { va_list ap; va_start(ap, temp); wrtemp(temp, ap); va_end(ap); return utCopyString(prStringBuffer); } /*-------------------------------------------------------------------------------------------------- Write a template to a string. --------------------------------------------------------------------------------------------------*/ void dvWrtemp( FILE *file, char *temp, ...) { va_list ap; va_start(ap, temp); wrtemp(temp, ap); va_end(ap); fputs(prStringBuffer, file); } /*-------------------------------------------------------------------------------------------------- Get the property type name. --------------------------------------------------------------------------------------------------*/ char *dvPropertyGetTypeName( dvProperty property) { dvClass theClass; dvEnum theEnum; dvTypedef theTypedef; switch(dvPropertyGetType(property)) { case PROP_INT: return utSprintf("int%u", dvPropertyGetWidth(property)); case PROP_UINT: return utSprintf("uint%u", dvPropertyGetWidth(property)); case PROP_FLOAT: return "float"; case PROP_DOUBLE: return "double"; case PROP_BIT: case PROP_BOOL: return "uint8"; case PROP_CHAR: return "char"; case PROP_SYM: return "utSym"; case PROP_ENUM: theEnum = dvPropertyGetEnumProp(property); return utSprintf("%s%s", dvModuleGetPrefix(dvEnumGetModule(theEnum)), dvEnumGetName(theEnum)); case PROP_TYPEDEF: return dvTypedefGetName(dvPropertyGetTypedefProp(property)); theTypedef = dvPropertyGetTypedefProp(property); return utSprintf("%s%s", dvModuleGetPrefix(dvTypedefGetModule(theTypedef)), dvTypedefGetName(theTypedef)); case PROP_POINTER: theClass = dvPropertyGetClassProp(property); return utSprintf("%s%s", dvClassGetPrefix(theClass), dvClassGetName(theClass)); default: utExit("Unknown property type"); } return NULL; /* Dummy return */ } /*-------------------------------------------------------------------------------------------------- Get the property type name as a utility library field type. --------------------------------------------------------------------------------------------------*/ char *dvPropertyGetFieldTypeName( dvProperty property) { switch(dvPropertyGetType(property)) { case PROP_INT: return "UT_INT"; case PROP_UINT: return "UT_UINT"; case PROP_FLOAT: return "UT_FLOAT"; case PROP_DOUBLE: return "UT_DOUBLE"; case PROP_BIT: return "UT_BIT"; case PROP_BOOL: return "UT_BOOL"; case PROP_CHAR: return "UT_CHAR"; case PROP_SYM: return "UT_SYM"; case PROP_ENUM: return "UT_ENUM"; case PROP_TYPEDEF: return "UT_TYPEDEF"; case PROP_POINTER: return "UT_POINTER"; default: utExit("Unknown property type"); } return NULL; /* Dummy return */ } /*-------------------------------------------------------------------------------------------------- Find a hash summary of the enumerated type. --------------------------------------------------------------------------------------------------*/ static uint32 findEnumHash( dvEnum theEnum) { dvEntry entry; uint32 hash = utSymGetHashValue(dvEnumGetSym(theEnum)); hash = utHashValues(hash, utSymGetHashValue(dvEnumGetPrefixSym(theEnum))); dvForeachEnumEntry(theEnum, entry) { hash ^= utSymGetHashValue(dvEntryGetSym(entry)); } dvEndEnumEntry; return hash; } /*-------------------------------------------------------------------------------------------------- Find a hash signature for the class. --------------------------------------------------------------------------------------------------*/ static uint32 findPropertyHash( dvProperty property) { uint32 hash = utSymGetHashValue(dvPropertyGetSym(property)); hash = utHashValues(hash, dvPropertyGetType(property)); hash = utHashValues(hash, dvPropertyArray(property)); switch(dvPropertyGetType(property)) { case PROP_INT: case PROP_UINT: hash = utHashValues(hash, dvPropertyGetWidth(property)); break; case PROP_FLOAT: case PROP_DOUBLE: case PROP_BIT: case PROP_BOOL: case PROP_CHAR: case PROP_SYM: break; case PROP_ENUM: hash = utHashValues(hash, utSymGetHashValue(dvEnumGetSym(dvPropertyGetEnumProp(property)))); break; case PROP_TYPEDEF: hash = utHashValues(hash, utSymGetHashValue(dvTypedefGetSym(dvPropertyGetTypedefProp(property)))); break; case PROP_POINTER: hash = utHashValues(hash, utSymGetHashValue(dvClassGetSym(dvPropertyGetClassProp(property)))); break; default: utExit("Unknown property type"); } return hash; } /*-------------------------------------------------------------------------------------------------- Find a hash signature for the union. --------------------------------------------------------------------------------------------------*/ static uint32 findUnionHash( dvUnion theUnion) { dvProperty property; uint32 hash = 0; dvForeachUnionProperty(theUnion, property) { hash ^= utSymGetHashValue(dvPropertyGetSym(property)); } dvEndUnionProperty; return hash; } /*-------------------------------------------------------------------------------------------------- Find a hash signature for the relationship. --------------------------------------------------------------------------------------------------*/ static uint32 findRelationshipHash( dvRelationship relationship) { uint32 hash = utSymGetHashValue(dvClassGetSym(dvRelationshipGetParentClass(relationship))); hash = utHashValues(hash, utSymGetHashValue(dvClassGetSym(dvRelationshipGetChildClass(relationship)))); hash = utHashValues(hash, dvRelationshipGetType(relationship)); hash = utHashValues(hash, utSymGetHashValue(dvRelationshipGetParentLabelSym(relationship))); hash = utHashValues(hash, utSymGetHashValue(dvRelationshipGetChildLabelSym(relationship))); hash = utHashValues(hash, dvRelationshipMandatory(relationship)); hash = utHashValues(hash, dvRelationshipCascade(relationship)); hash = utHashValues(hash, dvRelationshipAccessChild(relationship)); hash = utHashValues(hash, dvRelationshipAccessParent(relationship)); return hash; } /*-------------------------------------------------------------------------------------------------- Find a hash signature for the class. --------------------------------------------------------------------------------------------------*/ static uint32 findClassHash( dvClass theClass) { dvProperty property; dvUnion theUnion; dvRelationship relationship; uint32 hash = utSymGetHashValue(dvClassGetSym(theClass)); if(dvClassGetBaseClass(theClass) != dvClassNull) { hash = utHashValues(hash, utSymGetHashValue(dvClassGetSym(dvClassGetBaseClass(theClass)))); } hash = utHashValues(hash, dvClassGetMemoryStyle(theClass)); hash = utHashValues(hash, dvClassGetReferenceSize(theClass)); dvForeachClassProperty(theClass, property) { hash ^= findPropertyHash(property); } dvEndClassProperty; dvForeachClassUnion(theClass, theUnion) { hash ^= findUnionHash(theUnion); } dvEndClassUnion; dvForeachClassChildRelationship(theClass, relationship) { hash ^= findRelationshipHash(relationship); } dvEndClassChildRelationship; return hash; } /*-------------------------------------------------------------------------------------------------- Find a hash summary of the entire module. --------------------------------------------------------------------------------------------------*/ static uint32 findModuleHash( dvModule module) { dvEnum theEnum; dvClass theClass; dvTypedef theTypedef; uint32 hash = utSymGetHashValue(dvModuleGetSym(module)); hash = utHashValues(hash, dvModulePersistent(module)); hash = utHashValues(hash, utSymGetHashValue(dvModuleGetPrefixSym(module))); dvForeachModuleEnum(module, theEnum) { hash ^= findEnumHash(theEnum); } dvEndModuleEnum; dvForeachModuleTypedef(module, theTypedef) { hash ^= utSymGetHashValue(dvTypedefGetSym(theTypedef)); } dvEndModuleTypedef; dvForeachModuleClass(module, theClass) { hash ^= findClassHash(theClass); } dvEndModuleClass; return hash; } /*-------------------------------------------------------------------------------------------------- Compute a hash value that depends on every aspect of the database. Two databases with the same hash value should be 100% compatible. --------------------------------------------------------------------------------------------------*/ uint32 dvComputeDatabaseHash(void) { dvModule module; uint32 hash = 0; dvForeachRootModule(dvTheRoot, module) { hash ^= findModuleHash(module); } dvEndRootModule; return hash; } /*-------------------------------------------------------------------------------------------------- Find the module prefix to use for the class. It is the prefix of the base class, if defined, otherwise the prefix of the owning module. --------------------------------------------------------------------------------------------------*/ char *dvClassGetPrefix( dvClass theClass) { dvClass baseClass; utDo { baseClass = dvClassGetBaseClass(theClass); } utWhile(baseClass != dvClassNull) { theClass = baseClass; } utRepeat; return dvModuleGetPrefix(dvClassGetModule(theClass)); } /*-------------------------------------------------------------------------------------------------- Return a symbol with the same name, but the first letter capitalized. --------------------------------------------------------------------------------------------------*/ utSym dvUpperSym( utSym sym) { char *name = utCopyString(utSymGetName(sym)); *name = toupper(*name); return utSymCreate(name); } /*-------------------------------------------------------------------------------------------------- Return the format string for printing a property value. --------------------------------------------------------------------------------------------------*/ char *dvFindPropertyFormatString( dvProperty property) { switch(dvPropertyGetType(property)) { case PROP_INT: return "%d"; case PROP_UINT: return "%u"; case PROP_FLOAT: return "%g"; case PROP_DOUBLE: return "%g"; case PROP_BIT: return "%u"; case PROP_BOOL: return "%u"; case PROP_CHAR: if(dvPropertyArray(property)) { return "\\\"%s\\\""; } return "%c"; case PROP_SYM: return "0x%x \\\"%s\\\""; case PROP_ENUM: return "%u"; case PROP_TYPEDEF: return "???"; case PROP_POINTER: return "0x%x"; default: utExit("Unknown property type"); } return NULL; /* Dummy return */ } /*-------------------------------------------------------------------------------------------------- Just return a string representing the object reference type. --------------------------------------------------------------------------------------------------*/ char *dvClassGetReferenceTypeName( dvClass theClass) { return utSprintf("uint%u", dvClassGetReferenceSize(theClass)); } /*-------------------------------------------------------------------------------------------------- Just determine if any class in the module was declared with the "attributes" class option. --------------------------------------------------------------------------------------------------*/ bool dvModuleHasClassAttributes( dvModule module) { dvClass theClass; dvForeachModuleClass(module, theClass) { if(dvClassGenerateAttributes(theClass)) { return true; } } dvEndModuleClass; return false; } /*-------------------------------------------------------------------------------------------------- Determine if this is a name-based hash relationship. --------------------------------------------------------------------------------------------------*/ bool dvRelationshipHashedByName( dvRelationship relationship) { dvProperty property; dvKey key = dvRelationshipGetFirstKey(relationship); if(dvKeyGetNextRelationshipKey(key) != dvKeyNull) { return false; } property = dvKeyGetProperty(key); return dvPropertyGetType(property) == PROP_SYM; } /*-------------------------------------------------------------------------------------------------- Find the initial value for a property. --------------------------------------------------------------------------------------------------*/ char *dvPropertyFindInitializer( dvProperty property) { if(dvPropertyGetNumInitializer(property) != 0) { return dvPropertyGetInitializer(property); } if(dvPropertyGetType(property) == PROP_POINTER) { return utSprintf("%s%sNull", dvClassGetPrefix(dvPropertyGetClassProp(property)), dvClassGetName(dvPropertyGetClassProp(property))); } else if(dvPropertyGetType(property) == PROP_SYM) { return "utSymNull"; } return "0"; }