OWconfig.c revision 919
536N/A * Copyright 1996 Sun Microsystems, Inc. All rights reserved. 536N/A * Use is subject to license terms. 919N/A * Permission is hereby granted, free of charge, to any person obtaining a 919N/A * copy of this software and associated documentation files (the "Software"), 919N/A * to deal in the Software without restriction, including without limitation 919N/A * the rights to use, copy, modify, merge, publish, distribute, sublicense, 919N/A * and/or sell copies of the Software, and to permit persons to whom the 919N/A * Software is furnished to do so, subject to the following conditions: 919N/A * The above copyright notice and this permission notice (including the next 919N/A * paragraph) shall be included in all copies or substantial portions of the 919N/A * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 919N/A * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 919N/A * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 919N/A * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 919N/A * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 536N/A * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 536N/A * DEALINGS IN THE SOFTWARE. /*************************************************************************** Implementation Note: This implementation was done with some generality in mind. If at some point it becomes necessary to add more elaborate per class or per instance data, this should be readily accommodated by this implementation. It is assumed that the configuration database is relatively small, say, fewer than 1000 entries. There's no hard limit, but there's no optimization either. The "package" mechanism is hokey. It was done to address the concern that nobody wanted package names specified on a per instance basis, but there needed to be some mechanism that identified an instance as belonging to a package. The previous implementation mentioned that it was not MTsafe or MThot. The same applies to this implementation. Error handling is very primitive. If a more sophisticated means of reporting and acting upon error conditions can be It would be nice if we could use alloca, but since this is also an Xsun server library, we can't. ***************************************************************************/ /*************************************************************************** OWconfig implementation private data structures... ***************************************************************************/ * A class list is a child of the database. * An instance list is a child of a class. * An attribute list is a child of an instance. * Store comments as a singly linked list... /*** Max pathname length... ***/ /*** Unit of allocation for input line buffer... ***/ /*** Max length of statically allocated strings... ***/ /*************************************************************************** ***************************************************************************/ /*** If ever there are multiple databases, this could be moved into /*************************************************************************** **************************************************************************** Implementation private functions... **************************************************************************** ***************************************************************************/ /*************************************************************************** freeNodeList: The generic node list destructor... ***************************************************************************/ /*************************************************************************** freeClass: The class node destructor... ***************************************************************************/ /*************************************************************************** freeInstance: The instance node destructor... ***************************************************************************/ /*************************************************************************** freeAttr: The attribute node destructor... ***************************************************************************/ /*************************************************************************** hashValue: Generates the arithmetic sum of the bytes of the string ***************************************************************************/ /*************************************************************************** dupString: Given a non-null pointer to a string, allocates memory sufficient to contain a copy of the string pointed to by "str", copies the string to the newly allocated memory, and returns a pointer to the new string. ***************************************************************************/ /*************************************************************************** searchNodeList: Searches next-wise along a list, starting at the node pointed to by "node", until either the end of the list is found, or a node whose name matches the string pointed to by ***************************************************************************/ /*************************************************************************** searchClass: Searches for the class node whose name matches the string ***************************************************************************/ /*************************************************************************** searchInstance: Searches for the instance node identified by "name", parented by the class node identified by "class". ***************************************************************************/ /*************************************************************************** searchAttr: Searches for the attribute node identified by "attr", parented by the instance node identified by "name", which in turn is parented by the class node identified by "class". ***************************************************************************/ /*************************************************************************** createClass: Creates a new class node within the OWconfig database. ***************************************************************************/ /*************************************************************************** createInstance: Creates a new instance node parented by the class node identified by "class". The instance node will be identified by "name". If the class node does not already exist, it will ***************************************************************************/ /*************************************************************************** unlockOWconfig: Remove the read or write lock from an OWconfig file. ***************************************************************************/ lockStruct.l_type = F_UNLCK; (void)fcntl(f, F_SETLK, &lockStruct); /*************************************************************************** readLockOWconfig: Place a read lock on an OWconfig file. Should only fail if the file is write locked. ***************************************************************************/ Do not do any read locking. lockStruct.l_type = F_RDLCK; result = fcntl(f, F_SETLK, &lockStruct); /*************************************************************************** writeLockOWconfig: Place a write lock on an OWconfig file. Will fail if any other locks, read or write, are already on the file. ***************************************************************************/ Do not do any write locking. lockStruct.l_type = F_WRLCK; result = fcntl(f, F_SETLK, &lockStruct); /*************************************************************************** ***************************************************************************/ /*************************************************************************** ***************************************************************************/ /*************************************************************************** initDatabase: If a database already exists, free it, and set the OWconfigDatabase structure to a known state. ***************************************************************************/ /*************************************************************************** reAllocMem: Because we don't really want to add another parameter to OWconfigInit..., we implement a realloc routine that uses the allocMem and freeMem routines specified by OWconfigInit. ***************************************************************************/ /*************************************************************************** readLine: Read the file, line by line, until an "interesting" line is encountered. Maintain a line number counter along the way. When a line is found, fill "lineBuf" with the data. It is the responsibility of the caller to free the dynamically Note: Need to find proper way to use ctype functions... ***************************************************************************/ /*************************************************************************** readPair: Starting at character position "charPos" in "lineBuf", search for an expression of appx. the following syntax: <alnum>{<whitespace>}<equal>{<whitespace>}\ (<quote><anything goes, even \ stuff><quote>) | \ If such an expression is found, "nameBuf" is filled with the value to the left of the = and "valBuf" is filled with the value to the right of the =. "charPos" will be updated to point at the next candidate expression. ***************************************************************************/ /*** Skip whitespace preceding name... ***/ if (*
ptr == (
char)0 || *
ptr ==
';')
/*** Skip "=" and whitespace preceding open quote or string...***/ /*** Fetch quote delimited string... ***/ /*** Fetch white space terminated string... ***/ /*** Skip past terminating character, if any. ***/ /*************************************************************************** readOWconfig: Read the OWconfig database file named by "fileName". The internal database is built and the file's last modified time is returned in "timeStamp". If anything goes wrong, it is the caller's responsibility to clean up the database. ***************************************************************************/ /*** class=<value> ??? ***/ /*** name=<value> ??? ***/ /*** package=<value> ??? ***/ /*** <attr>=<value> ??? ***/ }
/* while readPair... */ }
/* while readLine... *//*************************************************************************** writeString: Writes to "fp" a quoted string specified by "str". Does ***************************************************************************/ if (*
str ==
'\\' || *
str ==
'"')
/*************************************************************************** ***************************************************************************/ /*** Need to do something about Copyright notices... ***/ /*** Write database in something resembling /*** Start new package? ***/ /*** Write database, class by class... ***/ /*** Start new package? ***/ /*************************************************************************** writeOWconfig: Writes the internal database, in OWconfig syntax, to the file specified by fileName. As a precaution, the original file is preserved, renamed as <filename>.BAK. Note: I'm concerned that a more sophisticated locking mechanism might be more trouble prone than this one. ***************************************************************************/ /*** Try write locking current OWconfig file... ***/ /*************************************************************************** **************************************************************************** **************************************************************************** ***************************************************************************/ /*************************************************************************** This function establishes the name of the package to associate with database resources created by subsequent calls to OWconfigSetAttribute or ***************************************************************************/ /*************************************************************************** This function removes any resources from the database that were associated with the named package. Return: OWCFG_OK or !OWCFG_OK. Note: The data structure is not really optimal for searching by package, but performance isn't really critical here. ***************************************************************************/ /*************************************************************************** "OWconfigSetInstance" is a convenient front end to "OWconfigSetAttribute". It takes a list of attributes and adds them to an instance of a class. If that class and/or instance does not already exist, they are or it is created.If that instance does exist, replacements, when necessary, occur on a per attribute/value pair basis, otherwise they are merely added to the instance. Return: OWCFG_OK or !OWCFG_OK(could occur during an out of memory condition). ***************************************************************************/ /*************************************************************************** "OWconfigRemoveInstance" removes an instance of a class, identified by Return: OWCFG_OK or !OWCFG_OK ***************************************************************************/ /*************************************************************************** "OWconfigSetAttribute" takes an attribute/value pair and adds it to an instance of a class. If that class and/or instance does not already exist, they are or it is created. If the named attribute already exists within the instance, it is replaced. Return: OWCFG_OK or !OWCFG_OK(could occur during with out of memory condition). ***************************************************************************/ /*************************************************************************** "OWconfigGetClassNames" returns a list of the names of all the instances of the named class. The end of the list is indicated by a NULL pointer. All users of this function may call "OWconfigFreeClassNames" to free the list and the strings it points to. Return: (char **) to list of class instance names or NULL if class did ***************************************************************************/ /*** Count the number of instances in the class... ***/ /*** If dupString fails, free previously allocated strings and return NULL... /*************************************************************************** "OWconfigFreeClassNames" frees the list of class names returned by ***************************************************************************/ /*************************************************************************** "OWconfigGetInstance" returns a list of attribute definitions belonging to the instance identified by "class" and "name". Use "OWconfigFreeInstance" to free the memory allocated to the information returned by OWconfigAttributePtr or NULL (if instance doesn't exist). ***************************************************************************/ /*** Count the number of attributes in the instance... ***/ /*************************************************************************** "OWconfigFreeInstance" frees the data returned by OWconfigGetInstance. ***************************************************************************/ /*************************************************************************** "OWconfigGetAttribute" returns the string value of the requested attribute. Return: (char *) to value of attribute or NULL if attribute could not ***************************************************************************/ /*************************************************************************** "OWconfigFreeAttribute" frees the string returned by OWconfigGetAttribute. ***************************************************************************/ /*************************************************************************** If writefile was specified, the existing target file, if any, is write locked using fcntl. If the lock succeeds, the new OWconfig file is written to the same directory, with a temporary name. The old file is removed and the new file is renamed to match the old file. The internal database is freed. Return: OWCFG_OK or !OWCFG_OK(could occur if write or write lock failed). Note: When a file is written, all comments are lost from the original file(s). When written, the OWconfig entries will be grouped by class. ***************************************************************************/ /*************************************************************************** OWconfigValidate: Verifies that the internal database is up to date with respect to the database file indicated by the global "readFlags". If it isn't, the files are re-read and a new internal database is OWCFG_OK or !OWCFG_OK (if re-read fails). ***************************************************************************/ /*** Setting databaseValid to zero causes initDatabase() to NOT free existing database... /*************************************************************************** "OWconfigInit" will read the OWconfig files named by readfile1 and Class instances and attribute/value pairs read from readfile2 will override those read from readfile1. The replacement will occur on a per read locked using the fcntl facility. Immediately after the file Return: OWCFG_OK or !OWCFG_OK. Bogus filepaths can return !OWCFG_OK. If readfile1 and readfile2 are both non-NULL, and the read of readfile1 succeeds but the read of readfile2 fails, OWCFG_OK will be returned. Lock test failures will return !OWCFG_OK. ***************************************************************************/ /*** Check for specific corner cases... ***/ /*** Read file 1, if specified... ***/ /*** Read file 2, if specified... ***/