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 >
C/C++ Source or Header  |  1997-03-21  |  36KB  |  864 lines

  1. /* @(#)Z 1.7 com/src/cm/CMObjOps.c, odstorage, od96os2, odos29712d 97/03/21 17:19:32 (96/10/29 09:16:50) */
  2. /*====START_GENERATED_PROLOG======================================
  3.  */
  4. /*
  5.  *   COMPONENT_NAME: odstorage
  6.  *
  7.  *   CLASSES: none
  8.  *
  9.  *   ORIGINS: 82,27
  10.  *
  11.  *
  12.  *   (C) COPYRIGHT International Business Machines Corp. 1995,1996
  13.  *   All Rights Reserved
  14.  *   Licensed Materials - Property of IBM
  15.  *   US Government Users Restricted Rights - Use, duplication or
  16.  *   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  17.  *       
  18.  *   IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  19.  *   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  20.  *   PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  21.  *   CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
  22.  *   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  23.  *   OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
  24.  *   OR PERFORMANCE OF THIS SOFTWARE.
  25.  */
  26. /*====END_GENERATED_PROLOG========================================
  27.  */
  28.  
  29. /*
  30.     File:         CMObjOps.c  
  31.  
  32.     Contains:    Container Manager Object Operations
  33.  
  34.     Written by:    Ira L. Ruben
  35.  
  36.     Owned by:    Ed Lai
  37.  
  38.     Copyright:    ⌐ 1991-1995 by Apple Computer, Inc., all rights reserved.
  39.  
  40.     Change History (most recent first):
  41.  
  42.          <4>     2/15/95    EL        1182275: Move CMKeepObject to CMRefOps
  43.                                     because CMKeepObject depends on references.
  44.          <3>     12/9/94    EL        #1182275 Now we garbage collect property
  45.                                                     and type object, so need to track their
  46.                                                     usage.
  47.          <2>     8/26/94    EL        #1181622 Ownership update.
  48.          <2>     3/17/94    EL        Add CMKeepObject call. #1149983
  49.          <1>      2/3/94    EL        first checked in
  50.          <8>     1/25/94    EL        Undo the last change.
  51.          <7>     1/21/94    EL        Disable checking of useCount in
  52.                                                     CMDeleteObject until after alpha.
  53.          <6>    11/10/93    EL        Add CMCountProperties call.
  54.          <5>     10/6/93    EL        Rename CMGetAdjacentXXXX to getAdjacentXXXX
  55.                                                     and static near.
  56.          <4>     10/4/93    EL        Add CMGetPrevObject and CMGetPrevObjectWithProperty, 
  57.                                                      replace CMGetPrevObjectProperty
  58.          <3>     9/27/93    VL        Added CMGetPrevObjectProperty.
  59.          <2>      9/8/93    VL        Added GetObject and GetObjectID.
  60.  
  61.     To Do:
  62. */
  63.  
  64. /*---------------------------------------------------------------------------*
  65.  |                                                                           |
  66.  |                           <<<  CMObjOps.c   >>>                           |
  67.  |                                                                           |
  68.  |                    Container Manager Object Operations                    |
  69.  |                                                                           |
  70.  |                               Ira L. Ruben                                |
  71.  |                                 12/15/91                                  |
  72.  |                                                                           |
  73.  |                  Copyright Apple Computer, Inc. 1991-1994                 |
  74.  |                           All rights reserved.                            |
  75.  |                                                                           |
  76.  *---------------------------------------------------------------------------*
  77.  
  78.  All Container Manager API routines dealing with objects (not their properties, types, 
  79.  or values) are handled in this file.  Properties and types are also objects, but they 
  80.  are treated separately.
  81.  
  82.  An object is defined in terms of its properties.  The properties are defined in terms of
  83.  the typed values.  Here we mainly create and access just the objects.  Internally they
  84.  are kept distince by object ID's.  From the API user's point of view objects are 
  85.  manipulated through refNums.
  86. */
  87.  
  88.  
  89. #include <stddef.h>
  90. #include <string.h>
  91. #include <stdio.h>
  92.  
  93. #ifndef __CMTYPES__
  94. #include "CMTypes.h"
  95. #endif
  96. #ifndef __CM_API__
  97. #include "CMAPI.h"
  98. #endif
  99. #ifndef __LISTMGR__
  100. #include "ListMgr.h"
  101. #endif
  102. #ifndef __TOCENTRIES__
  103. #include "TOCEnts.h"   
  104. #endif
  105. #ifndef __TOCOBJECTS__
  106. #include "TOCObjs.h"   
  107. #endif
  108. #ifndef __GLOBALNAMES__
  109. #include "GlbNames.h"   
  110. #endif
  111. #ifndef __CONTAINEROPS__
  112. #include "Containr.h"  
  113. #endif
  114. #ifndef __HANDLERS__
  115. #include "Handlers.h"
  116. #endif
  117. #ifndef __UPDATING__
  118. #include "Update.h"  
  119. #endif
  120. #ifndef __SESSIONDATA__
  121. #include "Session.h"          
  122. #endif
  123. #ifndef __ERRORRPT__
  124. #include "ErrorRpt.h"      
  125. #endif
  126. #ifndef __UTILITYROUTINES__
  127. #include "Utility.h"        
  128. #endif
  129.                                                                 
  130.                                                                     CM_CFUNCTIONS
  131.  
  132. /* The following generates a segment directive for Mac only due to 32K Jump Table             */
  133. /* Limitations.  If you don't know what I'm talking about don't worry about it.  The        */
  134. /* default is not to generate the pragma.  Theoritically unknown pragmas in ANSI won't    */
  135. /* choke compilers that don't recognize them.  Besides why would they be looked at if        */
  136. /* it's being conditionally skipped over anyway?  I know, famous last words!                        */
  137.  
  138. #if CM_MPW
  139. #pragma segment CMObjectOps
  140. #endif
  141.                                                                     
  142.  
  143. struct GetGNameComArea {                    /* CMGetGlobalName() object walking comm area layout:    */
  144.     TOCValuePtr      theValue;                /*        the first (should be only) global name value        */
  145.     CM_USHORT             nbrOfGlobalNames;/*        count of nbr of global names found in object        */
  146. };
  147. typedef struct GetGNameComArea GetGNameComArea, *GetGNameComAreaPtr;
  148.  
  149.  
  150. /*-----------------------------------*
  151.  | CMNewObject - create a new object |
  152.  *-----------------------------------*
  153.  
  154.  A new object is created in the specified container and its refNum returned.  At this
  155.  point the object is considered as "undefined".  It has no properties and thus no values.
  156. */
  157.  
  158. CMObject CM_FIXEDARGS CMNewObject(CMContainer targetContainer)
  159. {
  160.     TOCObjectPtr theObject;
  161.     ContainerPtr container = (ContainerPtr)targetContainer;
  162.     
  163.     NOPifNotInitialized(NULL);                                                /* NOP if not initialized!                    */
  164.     
  165.     /* The object is created as "undefined".  CMNewValue() will mark it defined because     */
  166.     /* at that time it will get a property and a value.                                                                        */
  167.     
  168.     theObject = cmDefineObject(container, container->nextUserObjectID, 0, 0, NULL, 0, 0, 
  169.                                                           UndefinedObject | ObjectObject, NULL);
  170.  
  171.     if (theObject) {
  172.         theObject->useCount = 1;                                                /* initial use of this object                */
  173.         IncrementObjectID(container->nextUserObjectID);    /* set to use next available user ID*/
  174.     }
  175.     
  176.     return ((CMObject)theObject);
  177. }
  178.  
  179.  
  180. /*----------------------------------------------------------------------------------*
  181.  | getAdjacentObject - get adjacent object in the container by increasing object ID |
  182.  *----------------------------------------------------------------------------------*
  183.  
  184.  This routine returns the refNum for the next/previous object in the container 
  185.  following/preceding currObject. If currObject is NULL, the refNum for the first/last
  186.  object is returned.  If currObject is not NULL, the object with the next highest ID 
  187.  next lowerest is returned.  NULL is returned if there are no more objects following/preceding
  188.  currObject.
  189.  
  190.  currObject is generally a refNum previously returned from this routine.  Successive calls
  191.  to this routine will thus yield all the objects in the container.
  192. */
  193.  
  194. static CMObject CM_NEAR getAdjacentObject(CMContainer targetContainer, 
  195.                                                                                     CMObject currObject,
  196.                                                                                     Boolean forward)
  197. {
  198.     TOCObjectPtr theObject;
  199.     ContainerPtr container = (ContainerPtr)targetContainer;
  200.     
  201.     NOPifNotInitialized(NULL);                                                /* NOP if not initialized!                    */
  202.     
  203.     if (currObject == NULL) {                                                    /* NULL ==> use head/tail of list                */
  204.         if (forward)
  205.             theObject = (TOCObjectPtr)cmGetMasterListHead(container->toc, ObjectObject);
  206.         else
  207.             theObject = (TOCObjectPtr)cmGetMasterListTail(container->toc, ObjectObject);
  208.         if (theObject) ++theObject->useCount;                        /* bump use count for next object        */
  209.         return ((CMObject)theObject);
  210.     }
  211.     
  212.     ExitIfBadObject(currObject, NULL);                                /* validate currObject                            */
  213.     
  214.     if (container->targetContainer != ((TOCObjectPtr)currObject)->container->targetContainer) {
  215.         ERROR3(CM_err_BadContainer, "object", CONTAINERNAMEx(((TOCObjectPtr)currObject)->container), CONTAINERNAMEx(container));
  216.         return (NULL);
  217.     }
  218.     
  219.     /* In our implementation the objects are already chained in sorted order.  So all we     */
  220.     /* have to do is follow the chain (or is it a yellow brick road?).                                        */
  221.     
  222.     if (forward)
  223.         theObject = ((TOCObjectPtr)currObject)->nextObject;
  224.     else
  225.         theObject = ((TOCObjectPtr)currObject)->prevObject;
  226.     if (theObject) ++theObject->useCount;                            /* bump use count for adjacent object    */
  227.     
  228.     return ((CMObject)theObject);                                            /* return NULL or next object refNum*/
  229. }
  230.  
  231. /*----------------------------------------------------------------------------*
  232.  | CMGetNextObject - get next object in the container by increasing object ID |
  233.  *----------------------------------------------------------------------------*
  234.  
  235.  Just call getAdjacentObject with forward = true.
  236. */
  237.  
  238. CMObject CM_FIXEDARGS CMGetNextObject(CMContainer targetContainer, CMObject currObject)
  239.  
  240. {
  241.     return getAdjacentObject(targetContainer, currObject, true);
  242. }
  243.  
  244. /*--------------------------------------------------------------------------------*
  245.  | CMGetPrevObject - get previous object in the container by increasing object ID |
  246.  *--------------------------------------------------------------------------------*
  247.  
  248.  Just call getAdjacentObject with forward = false.
  249. */
  250.  
  251. CMObject CM_FIXEDARGS CMGetPrevObject(CMContainer targetContainer, CMObject currObject)
  252.  
  253. {
  254.     return getAdjacentObject(targetContainer, currObject, false);
  255. }
  256.  
  257. /*--------------------------------------------------------------------------------*
  258.  | getAdjacentObjectProperty - get the adjacent property for the specified object |
  259.  *--------------------------------------------------------------------------------*
  260.  
  261.  This routine returns the refNum for the next/prev property defined for the given object.  If
  262.  currProperty is NULL, the refNum for the first/last property for the object is returned.  If 
  263.  it is not NULL, the next/prev property refNum following currProperty is returned.
  264.  
  265.  currProperty is generally a refNum previously returned from this routine. Successive
  266.  calls to this routine will thus yield all the properties for the given object.
  267. */
  268.  
  269. static CMProperty CM_NEAR getAdjacentObjectProperty(CMObject theObject, CMProperty currProperty, 
  270.                                                                                                         Boolean forward)
  271. {
  272.     TOCObjectPtr      theAdjacentObject;
  273.     TOCPropertyPtr theProperty;
  274.     ContainerPtr      container;
  275.     
  276.     ExitIfBadObject(theObject, NULL);                                    /* validate theObject                                */
  277.  
  278.     container = ((TOCObjectPtr)theObject)->container;
  279.     
  280.     /* If currProperty is NULL we return the object with the property ID taken from the        */
  281.     /* first/last property on theObject.                                                                                                    */
  282.     
  283.     if (currProperty == NULL)    {                                                /* NULL ==> use head of list                */
  284.         if (forward)
  285.             theProperty = (TOCPropertyPtr)cmGetListHead(&((TOCObjectPtr)theObject)->propertyList);
  286.         else
  287.             theProperty = (TOCPropertyPtr)cmGetListTail(&((TOCObjectPtr)theObject)->propertyList);
  288.  
  289.         if (theProperty == NULL)
  290.             return (NULL);
  291.         else
  292.  
  293.             return ((CMProperty)cmFindObject(container->toc, theProperty->propertyID));
  294.     }
  295.     
  296.     ExitIfBadProperty(currProperty, NULL);                        /* validate currProperty                        */
  297.     
  298.     if (container->targetContainer != ((TOCObjectPtr)currProperty)->container->targetContainer) {
  299.         ERROR2(CM_err_2Containers, CONTAINERNAMEx(container),
  300.                                                              CONTAINERNAMEx(((TOCObjectPtr)currProperty)->container));
  301.         return (NULL);
  302.     }
  303.     
  304.     /* Here we ant to find the next/prev property for the object.  Since currProperty is     */
  305.     /* not NULL, it points to an object because it's a refNum.  Remember it is not a             */
  306.     /* TOCPropertyPtr.  What we have to do is use the property ID to find the property        */
  307.     /* (a real TOCPropertyPtr) we found the last time this routine was called.  Then we        */
  308.     /* simply get the next/prev on the list to get the next/prev property ID.                            */
  309.     
  310.     theProperty = cmGetObjectProperty((TOCObjectPtr)theObject, /* find prop ID for object    */
  311.                                                                         ((TOCObjectPtr)currProperty)->objectID);
  312.     if (theProperty) {                                                                /* if we found ID on the list...        */
  313.         if (forward)
  314.             theProperty = (TOCPropertyPtr)cmGetNextListCell(theProperty); /* ...get next            */
  315.         else
  316.             theProperty = (TOCPropertyPtr)cmGetPrevListCell(theProperty); /* ...get previous    */
  317.         if (theProperty) {                                                            /* if there's a next property...        */
  318.             theAdjacentObject = cmFindObject(container->toc, theProperty->propertyID); /* get obj    */
  319.             if (theAdjacentObject) ++theAdjacentObject->useCount;    /* bump its use count                */
  320.             return ((CMProperty)theAdjacentObject);                /* give caller the property object    */
  321.         }
  322.     }
  323.     
  324.     return (NULL);
  325. }
  326.  
  327. /*--------------------------------------------------------------------------*
  328.  | CMGetNextObjectProperty - get the next property for the specified object |
  329.  *--------------------------------------------------------------------------*
  330.  
  331.  Just call getAdjacentObjectProperty with forward = true.
  332. */
  333.  
  334. CMProperty CM_FIXEDARGS CMGetNextObjectProperty(CMObject theObject, CMProperty currProperty)
  335. {
  336.     return getAdjacentObjectProperty(theObject, currProperty, true);
  337. }
  338.  
  339. /*------------------------------------------------------------------------------*
  340.  | CMGetPrevObjectProperty - get the previous property for the specified object |
  341.  *------------------------------------------------------------------------------*
  342.  
  343.  Just call getAdjacentObjectProperty with forward = false.
  344. */
  345.  
  346. CMProperty CM_FIXEDARGS CMGetPrevObjectProperty(CMObject theObject, CMProperty currProperty)
  347. {
  348.     return getAdjacentObjectProperty(theObject, currProperty, false);
  349. }
  350.  
  351. /*-----------------------------------------------------------------------------------------*
  352.  | getAdjacentObjectWithProperty - get the adjacent object that has the specified property |
  353.  *-----------------------------------------------------------------------------------------*
  354.  
  355.  This routine returns the refNum for the next/previous object in the container that has the 
  356.  given property.  If currObject is NULL, the search starts with the first/last object in the 
  357.  container.  If it is not NULL the search starts with the object immediately following/preceding
  358.  currObject.  If there is no next/previous object with the given property, NULL is returned. 
  359.  
  360.  currObject is generally a refNum previously returned from this routine. Successive calls
  361.  to this routine will thus yield all the objects with the given property.
  362.  */
  363.  
  364. static CMObject CM_NEAR getAdjacentObjectWithProperty(CMContainer targetContainer,
  365.                                                                                                     CMObject currObject, CMProperty property,
  366.                                                                                                     Boolean forward)
  367. {
  368.     ContainerPtr container = (ContainerPtr)targetContainer;
  369.     TOCObjectPtr theObject = (TOCObjectPtr)currObject;
  370.     
  371.     NOPifNotInitialized(NULL);                                                    /* NOP if not initialized!                */
  372.     
  373.     /* If we are given a non-NULL currObject, then start up the search with the next             */
  374.     /* object following that.  If currObject is NULL we start our search with the first        */
  375.     /* object.                                                                                                                                                        */
  376.     
  377.     if (forward) {
  378.         if (theObject != NULL) {                                                        /* if we have a starting object...*/
  379.             ExitIfBadObject(theObject, NULL);                                    /* ...validate theObject                    */
  380.             theObject = theObject->nextObject;                                /* ...get next object                            */
  381.             if (theObject == NULL) return (NULL);                            /* return NULL if no more objects    */
  382.         } 
  383.         else
  384.             theObject = cmGetMasterListHead(container->toc, ObjectObject);/* get first object        */
  385.     } 
  386.     else {
  387.         if (theObject != NULL) {                                                        /* if we have a starting object...*/
  388.             ExitIfBadObject(theObject, NULL);                                    /* ...validate theObject                    */
  389.             theObject = theObject->prevObject;                                /* ...get prev object                            */
  390.             if (theObject == NULL) return (NULL);                            /* return NULL if no more objects    */
  391.         } 
  392.         else
  393.             theObject = cmGetMasterListTail(container->toc, ObjectObject);/* get first object        */
  394.     }
  395.  
  396.     ExitIfBadProperty(property, NULL);                                    /* ...validate property                        */
  397.     
  398.     if (container->targetContainer != ((TOCObjectPtr)property)->container->targetContainer) {
  399.         ERROR2(CM_err_2Containers, CONTAINERNAMEx(container),
  400.                                                              CONTAINERNAMEx(((TOCObjectPtr)property)->container));
  401.         return (NULL);
  402.     }
  403.     
  404.     /* Starting with the first object or the next one after currObject we check each             */
  405.     /* object on the object chain to see if it has a property with the property ID of the */
  406.     /* given property object (descriptor). If it is found, the object pointer is returned.*/
  407.     /* If not, NULL is returned. This is easy to do since we already got a routine named    */
  408.     /* that scans an object for a property ID.                                                                                        */
  409.     
  410.     while (theObject) {
  411.         if (cmGetObjectProperty(theObject, ((TOCObjectPtr)property)->objectID) != NULL) {
  412.             ++theObject->useCount;                                                    /* if found, bump obj's use count    */
  413.             return ((CMObject)theObject);                                        /* give refNum back to user                */
  414.         }
  415.         if (forward)
  416.             theObject = theObject->nextObject;                                /* not found, keep looking                */
  417.         else
  418.             theObject = theObject->prevObject;                                /* not found, keep looking                */
  419.     }
  420.  
  421.     return (NULL);                                                                            /* not found                                             */
  422. }
  423.  
  424. /*-----------------------------------------------------------------------------------*
  425.  | CMGetNextObjectWithProperty - get the next object that has the specified property |
  426.  *-----------------------------------------------------------------------------------*
  427.  
  428.  Just call getAdjacentObjectWithProperty with forward = true.
  429.  */
  430.  
  431. CMObject CM_FIXEDARGS CMGetNextObjectWithProperty(CMContainer targetContainer,
  432.                                                                                                     CMObject currObject, CMProperty property)
  433. {
  434.     return getAdjacentObjectWithProperty(targetContainer, currObject, property, true);
  435. }
  436.  
  437. /*-------------------------------------------------------------------------------------------*
  438.  | CMGetPrevObjectWithProperty - get the previous object that has the specified property |
  439.  *-------------------------------------------------------------------------------------------*
  440.  
  441.  Just call getAdjacentObjectWithProperty with forward = false.
  442.  */
  443.  
  444. CMObject CM_FIXEDARGS CMGetPrevObjectWithProperty(CMContainer targetContainer,
  445.                                                                                                     CMObject currObject, CMProperty property)
  446. {
  447.     return getAdjacentObjectWithProperty(targetContainer, currObject, property, false);
  448. }
  449.  
  450. #if 0
  451. /*--------------------------------------------------------*
  452.  | CMGetReferenceData - create a "reference" to an object |
  453.  *--------------------------------------------------------*
  454.  
  455.  Creates a "reference" to an object (refNum), referencedObject, as data, theReferenceData,
  456.  to be written as (part of) the value data for the specified value.  The function returns
  457.  the input pointer to theReferenceData.  The caller should write the data to the value
  458.  possibly along with other data.  The size of this data is determined by the size of the
  459.  CMReference type, i.e., sizeof(CMReference).
  460.  
  461.  The returned data is in a form suitable for retrival by CMGetReferencedObject() to 
  462.  convert the data back to the object refNum.
  463. */
  464.  
  465. CMReference CM_PTR * CM_FIXEDARGS CMGetReferenceData(CMValue value,
  466.                                                                                                          CMObject referencedObject,
  467.                                                                                                           CMReference CM_PTR theReferenceData)
  468. {
  469.     ContainerPtr container;
  470.     
  471.     ExitIfBadValue(value, NULL);                                        /* validate value                                            */
  472.     ExitIfBadObject(referencedObject, NULL);                /* validate referencedObject                    */
  473.  
  474.     container = ((TOCValueHdrPtr)value)->container;
  475.     
  476.     if (container->targetContainer != ((TOCObjectPtr)referencedObject)->container->targetContainer) {
  477.         ERROR2(CM_err_CantReference, CONTAINERNAMEx(container),
  478.                                                                  CONTAINERNAMEx(((TOCObjectPtr)referencedObject)->container));
  479.         return (NULL);
  480.     }
  481.     
  482.     /*                         -- "DANGER WILL ROBINSON" --                                                             */
  483.     
  484.     /* A CMObjectID for some hardware implementations may NOT be exactly 4 bytes (but it    */
  485.     /* better be at least 4 bytes).  A user's "reference" data is always 4 bytes because    */
  486.     /* we define such data here as an object ID.  We must take care to convert the                 */
  487.     /* internal, i.e., hardware, representation to that of a container representation. By    */
  488.     /* share "luck" (yea right, want to buy a bridge?) we just happen to have a handler     */
  489.     /* that does this conversion.                                                                                                                    */
  490.     
  491.     CMformatData(container, theReferenceData, 4, &((TOCObjectPtr)referencedObject)->objectID);
  492.     
  493.     return ((CMReference *)theReferenceData);                /* return the ptr to the "reference"    */
  494. }
  495.  
  496.  
  497. /*-----------------------------------------------------------------------*
  498.  | CMGetReferencedObject - retrieve a object (refNum) from a "reference" |
  499.  *-----------------------------------------------------------------------*
  500.  
  501.  Converts an object "reference", created by CMGetReferenceData(), back to an object refNum,
  502.  from the data supplied by the specified value.
  503. */
  504.  
  505. CMObject CM_FIXEDARGS CMGetReferencedObject(CMValue value, CMReference CM_PTR theReferenceData)
  506. {
  507.     ContainerPtr container;
  508.     CMObjectID     objectID;
  509.     TOCObjectPtr theObject;
  510.     CM_CHAR          idStr[15];
  511.  
  512.     ExitIfBadValue(value, NULL);                                                            /* validate value                        */
  513.     
  514.     container = ((TOCValueHdrPtr)value)->container;
  515.     
  516.     /* Use handler to convert external representation back to internal representation.         */
  517.     /* See comments in CMGetReferenceData() why we do this.                                                                */
  518.     
  519.     CMextractData(container, theReferenceData, 4, &objectID);    /* get "reference" object ID*/
  520.     
  521.     theObject = cmFindObject(container->toc, objectID);                /* get the "refNum"                    */
  522.     if (theObject == NULL)                                                                        /* huh?                                            */
  523.         ERROR2(CM_err_UndefReference, cmltostr(objectID, 1, false, idStr), CONTAINERNAME);
  524.     
  525.     ++theObject->useCount;                                                                        /* count this use of the obj*/
  526.     
  527.     return ((CMObject)theObject);                                                            /* give back the refNum            */
  528. }
  529. #endif
  530.  
  531.  
  532. /*------------------------------------------------------------------------*
  533.  | CMGetObjectContainer - get the container refNum for one of its objects |
  534.  *------------------------------------------------------------------------*
  535.  
  536.  The refNum for the container which contains the specified object is returned.
  537. */
  538.  
  539. CMContainer CM_FIXEDARGS CMGetObjectContainer(CMObject theObject)
  540. {
  541.     ExitIfBadObject(theObject, NULL);                                /* validate theObject                                    */
  542.  
  543.     return ((CMContainer)(((TOCObjectPtr)theObject)->container));
  544. }
  545.  
  546.  
  547. /*---------------------------------------------------------*
  548.  | checkValue - check a value to see if it's a global name |
  549.  *---------------------------------------------------------*
  550.  
  551.  This is a cmWalkObject() action routine initiated by CMGetGlobalName() below to find the
  552.  global name value in an object.  The "refCon" is a pointer to a GetGNameComArea
  553.  communication area where we will save the value pointer.  We also count the number of
  554.  global names seen in the object.  It shoould be 1.  But we walk the entire object just to
  555.  be sure.
  556.  
  557.  Note, this "static" is intentionally left to default memory model under DOS since it is
  558.  passed as a function pointer to cmWalkObject().
  559. */
  560.  
  561. static TOCWalkReturns checkValue(ContainerPtr container, TOCValuePtr theValue, CMRefCon refCon)
  562. {
  563.     GetGNameComAreaPtr g = (GetGNameComAreaPtr)refCon;
  564.     ContainerPtr             unused = container;
  565.     
  566.     if (theValue->flags & kCMGlobalName) {
  567.         g->theValue = theValue;                                                    /* save global name ptr                            */
  568.         ++g->nbrOfGlobalNames;                                                    /* count it too                                            */
  569.     }
  570.     
  571.     return (WalkNextTOCValue);                                                /* continue value walk                            */
  572. }
  573.  
  574.  
  575. /*--------------------------------------------------------------------*
  576.  | CMGetGlobalName - get the global name (string) value for an object |
  577.  *--------------------------------------------------------------------*
  578.  
  579.  This routine takes an object refNum and searches its values to see if it has a global
  580.  name (defined by CMRegisterType() or CMRegisterProperty()).  If it does, a pointer to
  581.  the global name string is returned.  If none is found, NULL is returned.
  582.  
  583.  Caution: the user must treat the returned pointer as a value pointing to a read-only
  584.           entity!  The pointer we return here is a pointer directly to the name string
  585.                     in the global name symbol table.  There is no enforcement of this (how?).
  586. */
  587.  
  588. CMGlobalName CM_FIXEDARGS CMGetGlobalName(CMObject theObject)
  589. {
  590.     TOCValuePtr             theValue;
  591.     GetGNameComArea gNameComArea;
  592.     ContainerPtr        container;
  593.  
  594.     ExitIfBadObject(theObject, NULL);                                /* validate theObject                                    */
  595.     
  596.     container = ((TOCObjectPtr)theObject)->container;
  597.  
  598.     /* Walk the entire object and look at all the values to find the value for a global        */
  599.     /* name.  The object can have other properties and values, but there better be only     */
  600.     /* one global name.  The object is walked with cmWalkObject().  The "refCon" we pass    */
  601.     /* is a pointer to a communication area which will hold the count of the global name    */
  602.     /* values and the pointer to it.  As just mentioned, if the count comes back other         */
  603.     /* than 1, we have an error.                                                                                                                    */
  604.     
  605.     gNameComArea.theValue = NULL;                                        /* init value ptr to no value yet            */
  606.     gNameComArea.nbrOfGlobalNames = 0;                            /* there are no global names yet too    */
  607.     
  608.     cmWalkObject(container, (TOCObjectPtr)theObject, &gNameComArea, NULL, NULL, NULL, checkValue);
  609.     
  610.     /* After the walk we should have found 1 or 0 global names. If there is more than 1     */
  611.     /* we have an ambiguity.  0 means return NULL.                                                                                */
  612.         
  613.     if (gNameComArea.nbrOfGlobalNames > 1) {                /* must have exactly 1 global name        */
  614.         ERROR2(CM_err_AmbiguousType, "CMGetGlobalName", CONTAINERNAME);
  615.         return (NULL);
  616.     }
  617.  
  618.     if (gNameComArea.nbrOfGlobalNames == 0)                    /* no name ==> NULL return                        */
  619.         return (NULL);
  620.     
  621.     theValue = gNameComArea.theValue;
  622.     if (theValue == NULL) return (NULL);                        /* safety                                                            */
  623.     
  624.     return ((CMGlobalName)GetGlobalName(theValue->value.globalName.globalNameSymbol));
  625. }
  626.  
  627. /*-----------------------------------------------------------------*
  628.  | CMCountProperties - count the number of properties in an object |
  629.  *-----------------------------------------------------------------*
  630.  
  631.  An object can be defined to have any number of properties.  The properties for a given 
  632.  object are unique.  This routine is used to determine the total number of properties 
  633.  for an object or whether a property is present in that object.
  634.  
  635.  If the property is specified as NULL, the total number of properties in the object
  636.  is returned.  If the property is not NULL, 1 is returned if that property is present
  637.  (because there can be a maximum of one value of that type), and 0 otherwise.
  638. */
  639.  
  640. CMCount CM_FIXEDARGS CMCountProperties(CMObject object, CMProperty property)
  641. {
  642.     ContainerPtr      container;
  643.     
  644.     ExitIfBadObject(object, 0);                                                /* validate object                                    */
  645.     
  646.     container = ((TOCObjectPtr)object)->container;
  647.     
  648.     /* Process explicitly specified type separately...                                                                        */
  649.     
  650.     if (property != NULL) {
  651.         ExitIfBadProperty(property, 0);                            /* validate property                                        */
  652.  
  653.         if (container->targetContainer != ((TOCObjectPtr)property)->container->targetContainer) {
  654.             ERROR2(CM_err_2Containers, CONTAINERNAMEx(container),
  655.                                                                  CONTAINERNAMEx(((TOCObjectPtr)property)->container));
  656.             return (0);
  657.         }
  658.         
  659.         /* Find the TOCProperty belonging to the object with the property ID of the                    */
  660.         /* specified property object...                                                                                                            */
  661.     
  662.         return ((CMCount)(cmGetObjectProperty((TOCObjectPtr)object,
  663.                                                                           ((TOCObjectPtr)property)->objectID) != NULL));
  664.     }
  665.     
  666.     /* From here on we're interested in just the total number of properties...                        */
  667.     
  668.     return ((CMCount)cmCountListCells(&((TOCObjectPtr)object)->propertyList));
  669. }
  670.  
  671. /*---------------------------------------------------*
  672.  | CMGetObjectRefCon - return user's object "refCon" |
  673.  *---------------------------------------------------*
  674.  
  675.  This routine returns the user's "refCon" (reference constant) that s/he may associate
  676.  with any object refNum (i.e., a CMObject).  The refCon is a CM_ULONG that the user may use
  677.  in any way.  It is not touched by the API except to init it to 0 when the object is
  678.  initially created.
  679.  
  680.  Note, the refCon is NOT perserved across closed containers, i.e., it is not saved in the
  681.  TOC.
  682. */
  683.  
  684. CMRefCon CM_FIXEDARGS CMGetObjectRefCon(CMObject theObject)
  685. {
  686.     ExitIfBadObject(theObject, (CMRefCon)NULL);                            /* validate theObject                    */
  687.     
  688.     return (((TOCObjectPtr)theObject)->objectRefCon);                /* return user's refCon                */
  689. }
  690.  
  691.  
  692. /*----------------------------------------------------*
  693.  | CMSetObjectRefCon - set the user's object "refCon" |
  694.  *----------------------------------------------------*
  695.  
  696.  This routine is used to set the user's "refCon" (reference constant) to be assoicated with
  697.  an object.  The refCon is a CM_ULONG that the user may use in any way.  It is not touched
  698.  by the API.
  699.  
  700.  Note, the refCon is NOT perserved across closed containers, i.e., it is not saved in the
  701.  TOC.
  702. */
  703.  
  704. void CM_FIXEDARGS CMSetObjectRefCon(CMObject theObject, CMRefCon refCon)
  705. {
  706.     ExitIfBadObject(theObject, CM_NOVALUE);                                    /* validate theObject                    */
  707.     
  708.     ((TOCObjectPtr)theObject)->objectRefCon = refCon;                /* set the user's refCon            */
  709. }
  710.  
  711.  
  712. /*-----------------------------------*
  713.  | CMDeleteObject - delete an object |
  714.  *-----------------------------------*
  715.  
  716.  The specified object and all its properties and values are deleted.  It is an error to
  717.  use this object (refNum) from this point on.  Deleted objects no longer exist.  The
  718.  CMGetNext... routines will also never return them.
  719.  
  720.  Note, some objects are protected from deletion.  This includes the predefined TOC
  721.  objects (seed and offset values) and objects representing currently opened embedded
  722.  containers. 
  723. */
  724.  
  725. void CM_FIXEDARGS CMDeleteObject(CMObject theObject)
  726. {
  727.     ContainerPtr container;
  728.     
  729.     ExitIfBadObject(theObject, CM_NOVALUE);                            /* validate theObject                            */
  730.     
  731.     container = ((TOCObjectPtr)theObject)->container->updatingContainer;
  732.     
  733.     if ((container->useFlags & kCMWriting) == 0) {            /* make sure opened for writing        */
  734.         ERROR2(CM_err_DeleteIllegal, "object", CONTAINERNAME);
  735.         return;
  736.     }
  737.  
  738.     if (((TOCObjectPtr)theObject)->useCount > 1) {            /* there are other users!                    */
  739.         ERROR1(CM_err_CantDelete6, CONTAINERNAME);
  740.         return;
  741.     }
  742.     
  743.     ((TOCObjectPtr)theObject)->useCount = 0;                        /* no longer in use (obviously)        */
  744.     
  745.     /* It is an error to delete a protected object (e.g., object ID 1) or an object             */
  746.     /* containing dynamic values.  But if it's not one of these, delete the object. If        */
  747.     /* we're recording updates, then define touched list entry for the delete...                    */
  748.     
  749.     if (((TOCObjectPtr)theObject)->objectFlags & ProtectedObject)
  750.         ERROR1(CM_err_CantDelete1, CONTAINERNAME)
  751.     else if (((TOCObjectPtr)theObject)->objectFlags & DynamicValuesObject)
  752.         ERROR1(CM_err_CantDelete5, CONTAINERNAME)
  753.     else {
  754.         cmMarkObjectDeleted(container, (TOCObjectPtr)theObject);
  755.         cmTouchDeletedObject((TOCObjectPtr)theObject);         /* must call AFTER marking                */
  756.     }
  757. }
  758.  
  759.  
  760. /*------------------------------------------------------------*
  761.  | CMDeleteObjectProperty - delete a property of an an object |
  762.  *------------------------------------------------------------*
  763.  
  764.  The property corresponding to the object ID of theProperty is deleted along with all of 
  765.  its values.
  766.  
  767.  Note, some property values are protected from deletion.  This includes the predefined
  768.  TOC object values (seed and offset) and the currently open embedded container values.
  769. */
  770.  
  771. void CM_FIXEDARGS CMDeleteObjectProperty(CMObject theObject, CMProperty theProperty)
  772. {
  773.     ContainerPtr      container;
  774.     TOCValueHdrPtr theValueHdr;
  775.  
  776.     ExitIfBadObject(theObject, CM_NOVALUE);                    /* validate theObject                                    */
  777.     ExitIfBadProperty(theProperty,CM_NOVALUE);            /* validate theProperty                                */
  778.     
  779.     container = ((TOCObjectPtr)theObject)->container;
  780.     
  781.     if (container->targetContainer != ((TOCObjectPtr)theProperty)->container->targetContainer) {
  782.         ERROR2(CM_err_2Containers, CONTAINERNAMEx(container),
  783.                                                              CONTAINERNAMEx(((TOCObjectPtr)theProperty)->container));
  784.         return;
  785.     }
  786.  
  787.     container = container->updatingContainer;                /* use updating container from here on*/
  788.     
  789.     if ((container->useFlags & kCMWriting) == 0) {
  790.         ERROR2(CM_err_DeleteIllegal, "object's property", CONTAINERNAME);
  791.         return;
  792.     }
  793.     
  794.     /* Search through the properties for this object looking for the one that has the            */
  795.     /* ID as the passed property descriptor object. Note we store back into theProperty        */
  796.     /* (the variable) thus changing its meaning and type.    I just thought I would point         */
  797.     /* that out explicitly!                                                                                                                                */
  798.     
  799.     theProperty = (CMProperty)cmGetObjectProperty((TOCObjectPtr)theObject,
  800.                                                                                                 ((TOCObjectPtr)theProperty)->objectID);
  801.     if (theProperty == NULL) return;                                /* exit if property not in object            */
  802.     
  803.     /* Scan the values (headers) for this property to make sure there are no protected        */
  804.     /* values.  These are values which we never want deleted.  If there are any then it     */
  805.     /* is an error to delete this property from the object.  Sorry about that!                        */
  806.     
  807.     theValueHdr = (TOCValueHdrPtr)cmGetListHead(&((TOCPropertyPtr)theProperty)->valueHdrList);
  808.     while (theValueHdr) {
  809.         if ((theValueHdr->valueFlags & ValueProtected) != 0){    /* can't delete if protected!    */
  810.             ERROR1(CM_err_CantDelete2, CONTAINERNAME);
  811.             return;
  812.         }
  813.         theValueHdr = (TOCValueHdrPtr)cmGetNextListCell(theValueHdr);
  814.     } /* while */
  815.  
  816.     /* If we're recording updates, then define touched list entry for the delete...                */
  817.     
  818.     cmTouchDeletedProperty((TOCPropertyPtr)theProperty, ((TOCPropertyPtr)theProperty)->theObject);
  819.         
  820.     cmDeleteProperty(container, (TOCPropertyPtr)theProperty);
  821. }
  822.  
  823.  
  824. /*------------------------------------------------------------------------*
  825.  | CMReleaseObject - destroy association between an object and its refNum |
  826.  *------------------------------------------------------------------------*
  827.  
  828.  The association between the refNum and the object is destroyed. There should be no further
  829.  operations with the object (refNum) once this routine is called.
  830. */
  831.  
  832. void CM_FIXEDARGS CMReleaseObject(CMObject theObject)
  833. {
  834.     ContainerPtr container;
  835.     
  836.     ExitIfBadObject(theObject, CM_NOVALUE);                    /* validate theObject                                    */
  837.     
  838.     if (((TOCObjectPtr)theObject)->useCount == 0) {    /* error if already fully released        */
  839.         container = ((TOCObjectPtr)theObject)->container;
  840.         ERROR1(CM_err_AlreadyReleased2, CONTAINERNAME);
  841.     } else
  842.         --((TOCObjectPtr)theObject)->useCount;                /* decrement the object's use count        */
  843. }
  844.  
  845. CMObject CM_FIXEDARGS CMGetObject(CMContainer targetContainer, CMObjectID objectID)
  846. {
  847.     ContainerPtr container = (ContainerPtr)targetContainer;
  848.     TOCObjectPtr    object;
  849.     
  850.     object = cmFindObject(container->toc, objectID);
  851.     if (object != NULL)
  852.         ++object->useCount;
  853.     
  854.     return (CMObject) object;
  855. }
  856.     
  857. CMObjectID CM_FIXEDARGS CMGetObjectID(CMObject object)
  858. {
  859.     return ((TOCObjectPtr) object)->objectID;
  860. }
  861.     
  862.                                                           
  863.                                                             CM_END_CFUNCTIONS
  864.