OWconfig.c revision 824
418N/A * Copyright 1996 Sun Microsystems, Inc. All rights reserved. 605N/A * Use is subject to license terms. 1063N/A * Permission is hereby granted, free of charge, to any person obtaining a 418N/A * copy of this software and associated documentation files (the 418N/A * "Software"), to deal in the Software without restriction, including 919N/A * without limitation the rights to use, copy, modify, merge, publish, 919N/A * distribute, and/or sell copies of the Software, and to permit persons 919N/A * to whom the Software is furnished to do so, provided that the above 919N/A * copyright notice(s) and this permission notice appear in all copies of 919N/A * the Software and that both the above copyright notice(s) and this 919N/A * permission notice appear in supporting documentation. 919N/A * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 919N/A * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 919N/A * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 919N/A * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 919N/A * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL 919N/A * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING 919N/A * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 919N/A * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 919N/A * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 418N/A * Except as contained in this notice, the name of a copyright holder 418N/A * shall not be used in advertising or otherwise to promote the sale, use 418N/A * or other dealings in this Software without prior written authorization 418N/A * of the copyright holder. 970N/A/*************************************************************************** 970N/AImplementation Note: This implementation was done with some generality 970N/A in mind. If at some point it becomes necessary to add more 970N/A elaborate per class or per instance data, this should be 418N/A readily accommodated by this implementation. 418N/A It is assumed that the configuration database is relatively 911N/A small, say, fewer than 1000 entries. There's no hard limit, but 1063N/A there's no optimization either. 911N/A The "package" mechanism is hokey. It was done to 418N/A address the concern that nobody wanted package names specified 553N/A on a per instance basis, but there needed to be some mechanism 418N/A that identified an instance as belonging to a package. 553N/A The previous implementation mentioned that it was not 553N/A MTsafe or MThot. The same applies to this implementation. 418N/A Error handling is very primitive. If a more sophisticated 418N/A means of reporting and acting upon error conditions can be 418N/A It would be nice if we could use alloca, but since this 418N/A is also an Xsun server library, we can't. 1143N/A***************************************************************************/ 418N/A/*************************************************************************** 1143N/A OWconfig implementation private data structures... 1143N/A***************************************************************************/ 851N/A * A class list is a child of the database. 672N/A * An instance list is a child of a class. 418N/A * An attribute list is a child of an instance. 857N/A * Store comments as a singly linked list... 1143N/A/*** Max pathname length... ***/ 1143N/A/*** Unit of allocation for input line buffer... ***/ 1143N/A/*** 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... ***/