home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
opendc12.zip
/
od124os2.exe
/
od12osr1.exe
/
src
/
CMObjOps.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-03-21
|
36KB
|
864 lines
/* @(#)Z 1.7 com/src/cm/CMObjOps.c, odstorage, od96os2, odos29712d 97/03/21 17:19:32 (96/10/29 09:16:50) */
/*====START_GENERATED_PROLOG======================================
*/
/*
* COMPONENT_NAME: odstorage
*
* CLASSES: none
*
* ORIGINS: 82,27
*
*
* (C) COPYRIGHT International Business Machines Corp. 1995,1996
* All Rights Reserved
* Licensed Materials - Property of IBM
* US Government Users Restricted Rights - Use, duplication or
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
*
* IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
* OR PERFORMANCE OF THIS SOFTWARE.
*/
/*====END_GENERATED_PROLOG========================================
*/
/*
File: CMObjOps.c
Contains: Container Manager Object Operations
Written by: Ira L. Ruben
Owned by: Ed Lai
Copyright: ⌐ 1991-1995 by Apple Computer, Inc., all rights reserved.
Change History (most recent first):
<4> 2/15/95 EL 1182275: Move CMKeepObject to CMRefOps
because CMKeepObject depends on references.
<3> 12/9/94 EL #1182275 Now we garbage collect property
and type object, so need to track their
usage.
<2> 8/26/94 EL #1181622 Ownership update.
<2> 3/17/94 EL Add CMKeepObject call. #1149983
<1> 2/3/94 EL first checked in
<8> 1/25/94 EL Undo the last change.
<7> 1/21/94 EL Disable checking of useCount in
CMDeleteObject until after alpha.
<6> 11/10/93 EL Add CMCountProperties call.
<5> 10/6/93 EL Rename CMGetAdjacentXXXX to getAdjacentXXXX
and static near.
<4> 10/4/93 EL Add CMGetPrevObject and CMGetPrevObjectWithProperty,
replace CMGetPrevObjectProperty
<3> 9/27/93 VL Added CMGetPrevObjectProperty.
<2> 9/8/93 VL Added GetObject and GetObjectID.
To Do:
*/
/*---------------------------------------------------------------------------*
| |
| <<< CMObjOps.c >>> |
| |
| Container Manager Object Operations |
| |
| Ira L. Ruben |
| 12/15/91 |
| |
| Copyright Apple Computer, Inc. 1991-1994 |
| All rights reserved. |
| |
*---------------------------------------------------------------------------*
All Container Manager API routines dealing with objects (not their properties, types,
or values) are handled in this file. Properties and types are also objects, but they
are treated separately.
An object is defined in terms of its properties. The properties are defined in terms of
the typed values. Here we mainly create and access just the objects. Internally they
are kept distince by object ID's. From the API user's point of view objects are
manipulated through refNums.
*/
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#ifndef __CMTYPES__
#include "CMTypes.h"
#endif
#ifndef __CM_API__
#include "CMAPI.h"
#endif
#ifndef __LISTMGR__
#include "ListMgr.h"
#endif
#ifndef __TOCENTRIES__
#include "TOCEnts.h"
#endif
#ifndef __TOCOBJECTS__
#include "TOCObjs.h"
#endif
#ifndef __GLOBALNAMES__
#include "GlbNames.h"
#endif
#ifndef __CONTAINEROPS__
#include "Containr.h"
#endif
#ifndef __HANDLERS__
#include "Handlers.h"
#endif
#ifndef __UPDATING__
#include "Update.h"
#endif
#ifndef __SESSIONDATA__
#include "Session.h"
#endif
#ifndef __ERRORRPT__
#include "ErrorRpt.h"
#endif
#ifndef __UTILITYROUTINES__
#include "Utility.h"
#endif
CM_CFUNCTIONS
/* The following generates a segment directive for Mac only due to 32K Jump Table */
/* Limitations. If you don't know what I'm talking about don't worry about it. The */
/* default is not to generate the pragma. Theoritically unknown pragmas in ANSI won't */
/* choke compilers that don't recognize them. Besides why would they be looked at if */
/* it's being conditionally skipped over anyway? I know, famous last words! */
#if CM_MPW
#pragma segment CMObjectOps
#endif
struct GetGNameComArea { /* CMGetGlobalName() object walking comm area layout: */
TOCValuePtr theValue; /* the first (should be only) global name value */
CM_USHORT nbrOfGlobalNames;/* count of nbr of global names found in object */
};
typedef struct GetGNameComArea GetGNameComArea, *GetGNameComAreaPtr;
/*-----------------------------------*
| CMNewObject - create a new object |
*-----------------------------------*
A new object is created in the specified container and its refNum returned. At this
point the object is considered as "undefined". It has no properties and thus no values.
*/
CMObject CM_FIXEDARGS CMNewObject(CMContainer targetContainer)
{
TOCObjectPtr theObject;
ContainerPtr container = (ContainerPtr)targetContainer;
NOPifNotInitialized(NULL); /* NOP if not initialized! */
/* The object is created as "undefined". CMNewValue() will mark it defined because */
/* at that time it will get a property and a value. */
theObject = cmDefineObject(container, container->nextUserObjectID, 0, 0, NULL, 0, 0,
UndefinedObject | ObjectObject, NULL);
if (theObject) {
theObject->useCount = 1; /* initial use of this object */
IncrementObjectID(container->nextUserObjectID); /* set to use next available user ID*/
}
return ((CMObject)theObject);
}
/*----------------------------------------------------------------------------------*
| getAdjacentObject - get adjacent object in the container by increasing object ID |
*----------------------------------------------------------------------------------*
This routine returns the refNum for the next/previous object in the container
following/preceding currObject. If currObject is NULL, the refNum for the first/last
object is returned. If currObject is not NULL, the object with the next highest ID
next lowerest is returned. NULL is returned if there are no more objects following/preceding
currObject.
currObject is generally a refNum previously returned from this routine. Successive calls
to this routine will thus yield all the objects in the container.
*/
static CMObject CM_NEAR getAdjacentObject(CMContainer targetContainer,
CMObject currObject,
Boolean forward)
{
TOCObjectPtr theObject;
ContainerPtr container = (ContainerPtr)targetContainer;
NOPifNotInitialized(NULL); /* NOP if not initialized! */
if (currObject == NULL) { /* NULL ==> use head/tail of list */
if (forward)
theObject = (TOCObjectPtr)cmGetMasterListHead(container->toc, ObjectObject);
else
theObject = (TOCObjectPtr)cmGetMasterListTail(container->toc, ObjectObject);
if (theObject) ++theObject->useCount; /* bump use count for next object */
return ((CMObject)theObject);
}
ExitIfBadObject(currObject, NULL); /* validate currObject */
if (container->targetContainer != ((TOCObjectPtr)currObject)->container->targetContainer) {
ERROR3(CM_err_BadContainer, "object", CONTAINERNAMEx(((TOCObjectPtr)currObject)->container), CONTAINERNAMEx(container));
return (NULL);
}
/* In our implementation the objects are already chained in sorted order. So all we */
/* have to do is follow the chain (or is it a yellow brick road?). */
if (forward)
theObject = ((TOCObjectPtr)currObject)->nextObject;
else
theObject = ((TOCObjectPtr)currObject)->prevObject;
if (theObject) ++theObject->useCount; /* bump use count for adjacent object */
return ((CMObject)theObject); /* return NULL or next object refNum*/
}
/*----------------------------------------------------------------------------*
| CMGetNextObject - get next object in the container by increasing object ID |
*----------------------------------------------------------------------------*
Just call getAdjacentObject with forward = true.
*/
CMObject CM_FIXEDARGS CMGetNextObject(CMContainer targetContainer, CMObject currObject)
{
return getAdjacentObject(targetContainer, currObject, true);
}
/*--------------------------------------------------------------------------------*
| CMGetPrevObject - get previous object in the container by increasing object ID |
*--------------------------------------------------------------------------------*
Just call getAdjacentObject with forward = false.
*/
CMObject CM_FIXEDARGS CMGetPrevObject(CMContainer targetContainer, CMObject currObject)
{
return getAdjacentObject(targetContainer, currObject, false);
}
/*--------------------------------------------------------------------------------*
| getAdjacentObjectProperty - get the adjacent property for the specified object |
*--------------------------------------------------------------------------------*
This routine returns the refNum for the next/prev property defined for the given object. If
currProperty is NULL, the refNum for the first/last property for the object is returned. If
it is not NULL, the next/prev property refNum following currProperty is returned.
currProperty is generally a refNum previously returned from this routine. Successive
calls to this routine will thus yield all the properties for the given object.
*/
static CMProperty CM_NEAR getAdjacentObjectProperty(CMObject theObject, CMProperty currProperty,
Boolean forward)
{
TOCObjectPtr theAdjacentObject;
TOCPropertyPtr theProperty;
ContainerPtr container;
ExitIfBadObject(theObject, NULL); /* validate theObject */
container = ((TOCObjectPtr)theObject)->container;
/* If currProperty is NULL we return the object with the property ID taken from the */
/* first/last property on theObject. */
if (currProperty == NULL) { /* NULL ==> use head of list */
if (forward)
theProperty = (TOCPropertyPtr)cmGetListHead(&((TOCObjectPtr)theObject)->propertyList);
else
theProperty = (TOCPropertyPtr)cmGetListTail(&((TOCObjectPtr)theObject)->propertyList);
if (theProperty == NULL)
return (NULL);
else
return ((CMProperty)cmFindObject(container->toc, theProperty->propertyID));
}
ExitIfBadProperty(currProperty, NULL); /* validate currProperty */
if (container->targetContainer != ((TOCObjectPtr)currProperty)->container->targetContainer) {
ERROR2(CM_err_2Containers, CONTAINERNAMEx(container),
CONTAINERNAMEx(((TOCObjectPtr)currProperty)->container));
return (NULL);
}
/* Here we ant to find the next/prev property for the object. Since currProperty is */
/* not NULL, it points to an object because it's a refNum. Remember it is not a */
/* TOCPropertyPtr. What we have to do is use the property ID to find the property */
/* (a real TOCPropertyPtr) we found the last time this routine was called. Then we */
/* simply get the next/prev on the list to get the next/prev property ID. */
theProperty = cmGetObjectProperty((TOCObjectPtr)theObject, /* find prop ID for object */
((TOCObjectPtr)currProperty)->objectID);
if (theProperty) { /* if we found ID on the list... */
if (forward)
theProperty = (TOCPropertyPtr)cmGetNextListCell(theProperty); /* ...get next */
else
theProperty = (TOCPropertyPtr)cmGetPrevListCell(theProperty); /* ...get previous */
if (theProperty) { /* if there's a next property... */
theAdjacentObject = cmFindObject(container->toc, theProperty->propertyID); /* get obj */
if (theAdjacentObject) ++theAdjacentObject->useCount; /* bump its use count */
return ((CMProperty)theAdjacentObject); /* give caller the property object */
}
}
return (NULL);
}
/*--------------------------------------------------------------------------*
| CMGetNextObjectProperty - get the next property for the specified object |
*--------------------------------------------------------------------------*
Just call getAdjacentObjectProperty with forward = true.
*/
CMProperty CM_FIXEDARGS CMGetNextObjectProperty(CMObject theObject, CMProperty currProperty)
{
return getAdjacentObjectProperty(theObject, currProperty, true);
}
/*------------------------------------------------------------------------------*
| CMGetPrevObjectProperty - get the previous property for the specified object |
*------------------------------------------------------------------------------*
Just call getAdjacentObjectProperty with forward = false.
*/
CMProperty CM_FIXEDARGS CMGetPrevObjectProperty(CMObject theObject, CMProperty currProperty)
{
return getAdjacentObjectProperty(theObject, currProperty, false);
}
/*-----------------------------------------------------------------------------------------*
| getAdjacentObjectWithProperty - get the adjacent object that has the specified property |
*-----------------------------------------------------------------------------------------*
This routine returns the refNum for the next/previous object in the container that has the
given property. If currObject is NULL, the search starts with the first/last object in the
container. If it is not NULL the search starts with the object immediately following/preceding
currObject. If there is no next/previous object with the given property, NULL is returned.
currObject is generally a refNum previously returned from this routine. Successive calls
to this routine will thus yield all the objects with the given property.
*/
static CMObject CM_NEAR getAdjacentObjectWithProperty(CMContainer targetContainer,
CMObject currObject, CMProperty property,
Boolean forward)
{
ContainerPtr container = (ContainerPtr)targetContainer;
TOCObjectPtr theObject = (TOCObjectPtr)currObject;
NOPifNotInitialized(NULL); /* NOP if not initialized! */
/* If we are given a non-NULL currObject, then start up the search with the next */
/* object following that. If currObject is NULL we start our search with the first */
/* object. */
if (forward) {
if (theObject != NULL) { /* if we have a starting object...*/
ExitIfBadObject(theObject, NULL); /* ...validate theObject */
theObject = theObject->nextObject; /* ...get next object */
if (theObject == NULL) return (NULL); /* return NULL if no more objects */
}
else
theObject = cmGetMasterListHead(container->toc, ObjectObject);/* get first object */
}
else {
if (theObject != NULL) { /* if we have a starting object...*/
ExitIfBadObject(theObject, NULL); /* ...validate theObject */
theObject = theObject->prevObject; /* ...get prev object */
if (theObject == NULL) return (NULL); /* return NULL if no more objects */
}
else
theObject = cmGetMasterListTail(container->toc, ObjectObject);/* get first object */
}
ExitIfBadProperty(property, NULL); /* ...validate property */
if (container->targetContainer != ((TOCObjectPtr)property)->container->targetContainer) {
ERROR2(CM_err_2Containers, CONTAINERNAMEx(container),
CONTAINERNAMEx(((TOCObjectPtr)property)->container));
return (NULL);
}
/* Starting with the first object or the next one after currObject we check each */
/* object on the object chain to see if it has a property with the property ID of the */
/* given property object (descriptor). If it is found, the object pointer is returned.*/
/* If not, NULL is returned. This is easy to do since we already got a routine named */
/* that scans an object for a property ID. */
while (theObject) {
if (cmGetObjectProperty(theObject, ((TOCObjectPtr)property)->objectID) != NULL) {
++theObject->useCount; /* if found, bump obj's use count */
return ((CMObject)theObject); /* give refNum back to user */
}
if (forward)
theObject = theObject->nextObject; /* not found, keep looking */
else
theObject = theObject->prevObject; /* not found, keep looking */
}
return (NULL); /* not found */
}
/*-----------------------------------------------------------------------------------*
| CMGetNextObjectWithProperty - get the next object that has the specified property |
*-----------------------------------------------------------------------------------*
Just call getAdjacentObjectWithProperty with forward = true.
*/
CMObject CM_FIXEDARGS CMGetNextObjectWithProperty(CMContainer targetContainer,
CMObject currObject, CMProperty property)
{
return getAdjacentObjectWithProperty(targetContainer, currObject, property, true);
}
/*-------------------------------------------------------------------------------------------*
| CMGetPrevObjectWithProperty - get the previous object that has the specified property |
*-------------------------------------------------------------------------------------------*
Just call getAdjacentObjectWithProperty with forward = false.
*/
CMObject CM_FIXEDARGS CMGetPrevObjectWithProperty(CMContainer targetContainer,
CMObject currObject, CMProperty property)
{
return getAdjacentObjectWithProperty(targetContainer, currObject, property, false);
}
#if 0
/*--------------------------------------------------------*
| CMGetReferenceData - create a "reference" to an object |
*--------------------------------------------------------*
Creates a "reference" to an object (refNum), referencedObject, as data, theReferenceData,
to be written as (part of) the value data for the specified value. The function returns
the input pointer to theReferenceData. The caller should write the data to the value
possibly along with other data. The size of this data is determined by the size of the
CMReference type, i.e., sizeof(CMReference).
The returned data is in a form suitable for retrival by CMGetReferencedObject() to
convert the data back to the object refNum.
*/
CMReference CM_PTR * CM_FIXEDARGS CMGetReferenceData(CMValue value,
CMObject referencedObject,
CMReference CM_PTR theReferenceData)
{
ContainerPtr container;
ExitIfBadValue(value, NULL); /* validate value */
ExitIfBadObject(referencedObject, NULL); /* validate referencedObject */
container = ((TOCValueHdrPtr)value)->container;
if (container->targetContainer != ((TOCObjectPtr)referencedObject)->container->targetContainer) {
ERROR2(CM_err_CantReference, CONTAINERNAMEx(container),
CONTAINERNAMEx(((TOCObjectPtr)referencedObject)->container));
return (NULL);
}
/* -- "DANGER WILL ROBINSON" -- */
/* A CMObjectID for some hardware implementations may NOT be exactly 4 bytes (but it */
/* better be at least 4 bytes). A user's "reference" data is always 4 bytes because */
/* we define such data here as an object ID. We must take care to convert the */
/* internal, i.e., hardware, representation to that of a container representation. By */
/* share "luck" (yea right, want to buy a bridge?) we just happen to have a handler */
/* that does this conversion. */
CMformatData(container, theReferenceData, 4, &((TOCObjectPtr)referencedObject)->objectID);
return ((CMReference *)theReferenceData); /* return the ptr to the "reference" */
}
/*-----------------------------------------------------------------------*
| CMGetReferencedObject - retrieve a object (refNum) from a "reference" |
*-----------------------------------------------------------------------*
Converts an object "reference", created by CMGetReferenceData(), back to an object refNum,
from the data supplied by the specified value.
*/
CMObject CM_FIXEDARGS CMGetReferencedObject(CMValue value, CMReference CM_PTR theReferenceData)
{
ContainerPtr container;
CMObjectID objectID;
TOCObjectPtr theObject;
CM_CHAR idStr[15];
ExitIfBadValue(value, NULL); /* validate value */
container = ((TOCValueHdrPtr)value)->container;
/* Use handler to convert external representation back to internal representation. */
/* See comments in CMGetReferenceData() why we do this. */
CMextractData(container, theReferenceData, 4, &objectID); /* get "reference" object ID*/
theObject = cmFindObject(container->toc, objectID); /* get the "refNum" */
if (theObject == NULL) /* huh? */
ERROR2(CM_err_UndefReference, cmltostr(objectID, 1, false, idStr), CONTAINERNAME);
++theObject->useCount; /* count this use of the obj*/
return ((CMObject)theObject); /* give back the refNum */
}
#endif
/*------------------------------------------------------------------------*
| CMGetObjectContainer - get the container refNum for one of its objects |
*------------------------------------------------------------------------*
The refNum for the container which contains the specified object is returned.
*/
CMContainer CM_FIXEDARGS CMGetObjectContainer(CMObject theObject)
{
ExitIfBadObject(theObject, NULL); /* validate theObject */
return ((CMContainer)(((TOCObjectPtr)theObject)->container));
}
/*---------------------------------------------------------*
| checkValue - check a value to see if it's a global name |
*---------------------------------------------------------*
This is a cmWalkObject() action routine initiated by CMGetGlobalName() below to find the
global name value in an object. The "refCon" is a pointer to a GetGNameComArea
communication area where we will save the value pointer. We also count the number of
global names seen in the object. It shoould be 1. But we walk the entire object just to
be sure.
Note, this "static" is intentionally left to default memory model under DOS since it is
passed as a function pointer to cmWalkObject().
*/
static TOCWalkReturns checkValue(ContainerPtr container, TOCValuePtr theValue, CMRefCon refCon)
{
GetGNameComAreaPtr g = (GetGNameComAreaPtr)refCon;
ContainerPtr unused = container;
if (theValue->flags & kCMGlobalName) {
g->theValue = theValue; /* save global name ptr */
++g->nbrOfGlobalNames; /* count it too */
}
return (WalkNextTOCValue); /* continue value walk */
}
/*--------------------------------------------------------------------*
| CMGetGlobalName - get the global name (string) value for an object |
*--------------------------------------------------------------------*
This routine takes an object refNum and searches its values to see if it has a global
name (defined by CMRegisterType() or CMRegisterProperty()). If it does, a pointer to
the global name string is returned. If none is found, NULL is returned.
Caution: the user must treat the returned pointer as a value pointing to a read-only
entity! The pointer we return here is a pointer directly to the name string
in the global name symbol table. There is no enforcement of this (how?).
*/
CMGlobalName CM_FIXEDARGS CMGetGlobalName(CMObject theObject)
{
TOCValuePtr theValue;
GetGNameComArea gNameComArea;
ContainerPtr container;
ExitIfBadObject(theObject, NULL); /* validate theObject */
container = ((TOCObjectPtr)theObject)->container;
/* Walk the entire object and look at all the values to find the value for a global */
/* name. The object can have other properties and values, but there better be only */
/* one global name. The object is walked with cmWalkObject(). The "refCon" we pass */
/* is a pointer to a communication area which will hold the count of the global name */
/* values and the pointer to it. As just mentioned, if the count comes back other */
/* than 1, we have an error. */
gNameComArea.theValue = NULL; /* init value ptr to no value yet */
gNameComArea.nbrOfGlobalNames = 0; /* there are no global names yet too */
cmWalkObject(container, (TOCObjectPtr)theObject, &gNameComArea, NULL, NULL, NULL, checkValue);
/* After the walk we should have found 1 or 0 global names. If there is more than 1 */
/* we have an ambiguity. 0 means return NULL. */
if (gNameComArea.nbrOfGlobalNames > 1) { /* must have exactly 1 global name */
ERROR2(CM_err_AmbiguousType, "CMGetGlobalName", CONTAINERNAME);
return (NULL);
}
if (gNameComArea.nbrOfGlobalNames == 0) /* no name ==> NULL return */
return (NULL);
theValue = gNameComArea.theValue;
if (theValue == NULL) return (NULL); /* safety */
return ((CMGlobalName)GetGlobalName(theValue->value.globalName.globalNameSymbol));
}
/*-----------------------------------------------------------------*
| CMCountProperties - count the number of properties in an object |
*-----------------------------------------------------------------*
An object can be defined to have any number of properties. The properties for a given
object are unique. This routine is used to determine the total number of properties
for an object or whether a property is present in that object.
If the property is specified as NULL, the total number of properties in the object
is returned. If the property is not NULL, 1 is returned if that property is present
(because there can be a maximum of one value of that type), and 0 otherwise.
*/
CMCount CM_FIXEDARGS CMCountProperties(CMObject object, CMProperty property)
{
ContainerPtr container;
ExitIfBadObject(object, 0); /* validate object */
container = ((TOCObjectPtr)object)->container;
/* Process explicitly specified type separately... */
if (property != NULL) {
ExitIfBadProperty(property, 0); /* validate property */
if (container->targetContainer != ((TOCObjectPtr)property)->container->targetContainer) {
ERROR2(CM_err_2Containers, CONTAINERNAMEx(container),
CONTAINERNAMEx(((TOCObjectPtr)property)->container));
return (0);
}
/* Find the TOCProperty belonging to the object with the property ID of the */
/* specified property object... */
return ((CMCount)(cmGetObjectProperty((TOCObjectPtr)object,
((TOCObjectPtr)property)->objectID) != NULL));
}
/* From here on we're interested in just the total number of properties... */
return ((CMCount)cmCountListCells(&((TOCObjectPtr)object)->propertyList));
}
/*---------------------------------------------------*
| CMGetObjectRefCon - return user's object "refCon" |
*---------------------------------------------------*
This routine returns the user's "refCon" (reference constant) that s/he may associate
with any object refNum (i.e., a CMObject). The refCon is a CM_ULONG that the user may use
in any way. It is not touched by the API except to init it to 0 when the object is
initially created.
Note, the refCon is NOT perserved across closed containers, i.e., it is not saved in the
TOC.
*/
CMRefCon CM_FIXEDARGS CMGetObjectRefCon(CMObject theObject)
{
ExitIfBadObject(theObject, (CMRefCon)NULL); /* validate theObject */
return (((TOCObjectPtr)theObject)->objectRefCon); /* return user's refCon */
}
/*----------------------------------------------------*
| CMSetObjectRefCon - set the user's object "refCon" |
*----------------------------------------------------*
This routine is used to set the user's "refCon" (reference constant) to be assoicated with
an object. The refCon is a CM_ULONG that the user may use in any way. It is not touched
by the API.
Note, the refCon is NOT perserved across closed containers, i.e., it is not saved in the
TOC.
*/
void CM_FIXEDARGS CMSetObjectRefCon(CMObject theObject, CMRefCon refCon)
{
ExitIfBadObject(theObject, CM_NOVALUE); /* validate theObject */
((TOCObjectPtr)theObject)->objectRefCon = refCon; /* set the user's refCon */
}
/*-----------------------------------*
| CMDeleteObject - delete an object |
*-----------------------------------*
The specified object and all its properties and values are deleted. It is an error to
use this object (refNum) from this point on. Deleted objects no longer exist. The
CMGetNext... routines will also never return them.
Note, some objects are protected from deletion. This includes the predefined TOC
objects (seed and offset values) and objects representing currently opened embedded
containers.
*/
void CM_FIXEDARGS CMDeleteObject(CMObject theObject)
{
ContainerPtr container;
ExitIfBadObject(theObject, CM_NOVALUE); /* validate theObject */
container = ((TOCObjectPtr)theObject)->container->updatingContainer;
if ((container->useFlags & kCMWriting) == 0) { /* make sure opened for writing */
ERROR2(CM_err_DeleteIllegal, "object", CONTAINERNAME);
return;
}
if (((TOCObjectPtr)theObject)->useCount > 1) { /* there are other users! */
ERROR1(CM_err_CantDelete6, CONTAINERNAME);
return;
}
((TOCObjectPtr)theObject)->useCount = 0; /* no longer in use (obviously) */
/* It is an error to delete a protected object (e.g., object ID 1) or an object */
/* containing dynamic values. But if it's not one of these, delete the object. If */
/* we're recording updates, then define touched list entry for the delete... */
if (((TOCObjectPtr)theObject)->objectFlags & ProtectedObject)
ERROR1(CM_err_CantDelete1, CONTAINERNAME)
else if (((TOCObjectPtr)theObject)->objectFlags & DynamicValuesObject)
ERROR1(CM_err_CantDelete5, CONTAINERNAME)
else {
cmMarkObjectDeleted(container, (TOCObjectPtr)theObject);
cmTouchDeletedObject((TOCObjectPtr)theObject); /* must call AFTER marking */
}
}
/*------------------------------------------------------------*
| CMDeleteObjectProperty - delete a property of an an object |
*------------------------------------------------------------*
The property corresponding to the object ID of theProperty is deleted along with all of
its values.
Note, some property values are protected from deletion. This includes the predefined
TOC object values (seed and offset) and the currently open embedded container values.
*/
void CM_FIXEDARGS CMDeleteObjectProperty(CMObject theObject, CMProperty theProperty)
{
ContainerPtr container;
TOCValueHdrPtr theValueHdr;
ExitIfBadObject(theObject, CM_NOVALUE); /* validate theObject */
ExitIfBadProperty(theProperty,CM_NOVALUE); /* validate theProperty */
container = ((TOCObjectPtr)theObject)->container;
if (container->targetContainer != ((TOCObjectPtr)theProperty)->container->targetContainer) {
ERROR2(CM_err_2Containers, CONTAINERNAMEx(container),
CONTAINERNAMEx(((TOCObjectPtr)theProperty)->container));
return;
}
container = container->updatingContainer; /* use updating container from here on*/
if ((container->useFlags & kCMWriting) == 0) {
ERROR2(CM_err_DeleteIllegal, "object's property", CONTAINERNAME);
return;
}
/* Search through the properties for this object looking for the one that has the */
/* ID as the passed property descriptor object. Note we store back into theProperty */
/* (the variable) thus changing its meaning and type. I just thought I would point */
/* that out explicitly! */
theProperty = (CMProperty)cmGetObjectProperty((TOCObjectPtr)theObject,
((TOCObjectPtr)theProperty)->objectID);
if (theProperty == NULL) return; /* exit if property not in object */
/* Scan the values (headers) for this property to make sure there are no protected */
/* values. These are values which we never want deleted. If there are any then it */
/* is an error to delete this property from the object. Sorry about that! */
theValueHdr = (TOCValueHdrPtr)cmGetListHead(&((TOCPropertyPtr)theProperty)->valueHdrList);
while (theValueHdr) {
if ((theValueHdr->valueFlags & ValueProtected) != 0){ /* can't delete if protected! */
ERROR1(CM_err_CantDelete2, CONTAINERNAME);
return;
}
theValueHdr = (TOCValueHdrPtr)cmGetNextListCell(theValueHdr);
} /* while */
/* If we're recording updates, then define touched list entry for the delete... */
cmTouchDeletedProperty((TOCPropertyPtr)theProperty, ((TOCPropertyPtr)theProperty)->theObject);
cmDeleteProperty(container, (TOCPropertyPtr)theProperty);
}
/*------------------------------------------------------------------------*
| CMReleaseObject - destroy association between an object and its refNum |
*------------------------------------------------------------------------*
The association between the refNum and the object is destroyed. There should be no further
operations with the object (refNum) once this routine is called.
*/
void CM_FIXEDARGS CMReleaseObject(CMObject theObject)
{
ContainerPtr container;
ExitIfBadObject(theObject, CM_NOVALUE); /* validate theObject */
if (((TOCObjectPtr)theObject)->useCount == 0) { /* error if already fully released */
container = ((TOCObjectPtr)theObject)->container;
ERROR1(CM_err_AlreadyReleased2, CONTAINERNAME);
} else
--((TOCObjectPtr)theObject)->useCount; /* decrement the object's use count */
}
CMObject CM_FIXEDARGS CMGetObject(CMContainer targetContainer, CMObjectID objectID)
{
ContainerPtr container = (ContainerPtr)targetContainer;
TOCObjectPtr object;
object = cmFindObject(container->toc, objectID);
if (object != NULL)
++object->useCount;
return (CMObject) object;
}
CMObjectID CM_FIXEDARGS CMGetObjectID(CMObject object)
{
return ((TOCObjectPtr) object)->objectID;
}
CM_END_CFUNCTIONS