home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / opendc12.zip / od124os2.exe / od12osr1.exe / src / CMHndOps.c < prev    next >
C/C++ Source or Header  |  1997-03-21  |  21KB  |  497 lines

  1. /* @(#)Z 1.4 com/src/cm/CMHndOps.c, odstorage, od96os2, odos29712d 97/03/21 17:19:32 (96/10/29 09:16:43) */
  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:        CMHndOps.c
  31.  
  32.     Contains:    Container Manager Handler Operations
  33.  
  34.     Written by:    Ira L. Ruben
  35.  
  36.     Owned by:    Ed Lai
  37.  
  38.     Copyright:    ⌐ 1991-1994 by Apple Computer, Inc., all rights reserved.
  39.  
  40.     Change History (most recent first):
  41.  
  42.          <2>     8/26/94    EL        #1181622 Ownership update.
  43.          <1>      2/3/94    EL        first checked in
  44.  
  45.     To Do:
  46. */
  47.  
  48. /*---------------------------------------------------------------------------*
  49.  |                                                                           |
  50.  |                           <<<   CMHndOps.c   >>>                          |
  51.  |                                                                           |
  52.  |                    Container Manager Handler Operations                   |
  53.  |                                                                           |
  54.  |                               Ira L. Ruben                                |
  55.  |                                 12/05/91                                  |
  56.  |                                                                           |
  57.  |                  Copyright Apple Computer, Inc. 1991-1994                 |
  58.  |                           All rights reserved.                            |
  59.  |                                                                           |
  60.  *---------------------------------------------------------------------------*
  61.  
  62.  Containers are always access through handlers, to provide platform independence.  Handlers
  63.  are responsible for doing all the I/O operations, including opening and closing, to
  64.  containers.  They are also responsible for reading and writing the container label.
  65.  
  66.  The routines in this file are the API interfaces to allow the Container Manager to
  67.  determine what handlers it should use for a particular container.  The Container Manager
  68.  handler routines defined here maintain container type name/metahandler associations.
  69.  
  70.  A metahandler is a special required routine the API user defines which is called by the
  71.  API to return the address of the handler I/O routines that the Container Manager needs.
  72.  There following handlers are needed by the API.  They should have these prototypes:    
  73.  
  74.  void open_Handler(CMRefCon refCon, CMOpenMode mode);
  75.  void close_Handler(CMRefCon refCon);
  76.  CMSize flush_Handler(CMRefCon refCon);
  77.  CMSize seek_Handler(CMRefCon refCon, CM_LONG posOff, CMSeekMode mode);
  78.  CMSize tell_Handler(CMRefCon refCon);
  79.  CMSize read_Handler(CMRefCon refCon, CMPtr buffer, CMSize elementSize, CMCount theCount);
  80.  CMSize write_Handler(CMRefCon refCon, CMPtr buffer, CMSize elementSize, CMCount theCount);
  81.  CMEofStatus eof_Handler(CMRefCon refCon);
  82.  CMBoolean trunc_Handler(CMRefCon refCon, CMSize containerSize);
  83.  CMSize containerSize_Handler(CMRefCon refCon);
  84.  void readLabel_Handler(CMRefCon refCon, CMMagicBytes magicByteSequence,
  85.                                                 CMContainerFlags *flags, CM_USHORT *bufSize,
  86.                                                 CM_USHORT *majorVersion, USHORT *minorVersion,
  87.                                                 CMSize *tocOffset, CMSize *tocSize);
  88.  void writeLabel_Handler(CMRefCon refCon, CMMagicBytes magicByteSequence,
  89.                                                  CMContainerFlags flags, CM_USHORT bufSize,
  90.                                                  CM_USHORT majorVersion, USHORT minorVersion,
  91.                                                  CMSize tocOffset, CMSize tocSize);    
  92.  CMValue returnParentValue_Handler(CMRefCon refCon);
  93.  CM_UCHAR *returnContainerName_Handler(CMRefCon refCon);
  94.  CMType returnTargetType_Handler(CMRefCon refCon, CMContainer container);
  95.  void extractData_Handler(CMRefCon refCon, CMDataBuffer buffer, 
  96.                                                      CMSize size, CMPrivateData data);
  97.  void formatData_Handler(CMRefCon refCon, CMDataBuffer buffer, 
  98.                                                   CMSize size, CMPrivateData data);
  99.  
  100.  The names chosen can be, of course, anything.  They were chosen here to document what
  101.  each routine does since the semantics for each routine follow exactly those of standard
  102.  ANSI C.  The last two routines are for reading and writing labels.  See documentation of
  103.  those routines for further details.  Note, we will talk about the "refCon" a little later.
  104.  
  105.  Not all of the above handlers are required at all times.  Some are obviously used only
  106.  for input and others for output.  Here is a chart as to which  routines are required for
  107.  reading, writing, and updating:
  108.  
  109.                                         Mode
  110.                                                      Reading  |  Writing  | Updating
  111.                                                      ---------+-----------+---------
  112.                                 open             X     |     X     |    X
  113.                                 close            X     |     X     |    X
  114.                                 flush                  |           |
  115.                                 seek              X     |     X     |    X
  116.                                 tell              X     |     X     |    X
  117.                                 read               X     |           |    X
  118.                                 write                  |     X     |    X
  119.                                 eof                      |           |
  120.                                 trunc                          |           |
  121.                                 size          X     |     X     |    X
  122.                                 readLabel     X     |           |    X
  123.                                 writeLabel          |     X     |    X
  124.                                 parent              1     |     1     |    
  125.                                 name                |           |     
  126.                                 targetType          |           |    X
  127.                                 extract       X     |     X     |    X
  128.                                 format        X     |     X     |    X
  129.                                                      ---------+-----------+---------
  130.  
  131.  Notes: 1. The parent value handler is required ONLY for embedded container handlers.
  132.                 
  133.  The X's indicate required for the mode.  Blanks mean optional or are not used for the
  134.  mode.  Note, that updating generally is an or'ing of the reading and writing cases.
  135.     
  136.  In each handler routine a "refCon" is passed.  This is short for "reference constant". It
  137.  is an arbitrary (void *) value that is passed to the Container Manager when a container
  138.  is to be opened.  The Container Manager doesn't look at it. It simply passes it on each
  139.  handler call.  The intent is that it will be used as a communication device to allow the
  140.  handler routines to coordinate among themselves.
  141. */
  142.  
  143.  
  144. #include <stddef.h>
  145. #include <string.h>
  146. #include <stdarg.h>
  147. #include <stdio.h>
  148.  
  149. #ifndef __CMVERSION__
  150. #include "CMVers.h"   
  151. #endif
  152. #ifndef __CMTYPES__
  153. #include "CMTypes.h"
  154. #endif
  155. #ifndef __CM_API__
  156. #include "CMAPI.h"
  157. #endif
  158. #ifndef __LISTMGR__
  159. #include "ListMgr.h"
  160. #endif
  161. #ifndef __TOCENTRIES__
  162. #include "TOCEnts.h"   
  163. #endif
  164. #ifndef __TOCOBJECTS__
  165. #include "TOCObjs.h"   
  166. #endif
  167. #ifndef __GLOBALNAMES__
  168. #include "GlbNames.h"   
  169. #endif
  170. #ifndef __CONTAINEROPS__
  171. #include "Containr.h"  
  172. #endif
  173. #ifndef __HANDLERS__
  174. #include "Handlers.h"
  175. #endif
  176. #ifndef __SESSIONDATA__
  177. #include "Session.h"          
  178. #endif
  179. #ifndef __ERRORRPT__
  180. #include "ErrorRpt.h"      
  181. #endif
  182. #ifndef __UTILITYROUTINES__
  183. #include "Utility.h"        
  184. #endif
  185.  
  186.                                                                     CM_CFUNCTIONS
  187.  
  188. /* The following generates a segment directive for Mac only due to 32K Jump Table             */
  189. /* Limitations.  If you don't know what I'm talking about don't worry about it.  The        */
  190. /* default is not to generate the pragma.  Theoritically unknown pragmas in ANSI won't    */
  191. /* choke compilers that don't recognize them.  Besides why would they be looked at if        */
  192. /* it's being conditionally skipped over anyway?  I know, famous last words!                        */
  193.  
  194. #if CM_MPW
  195. #pragma segment CMHandlerOps
  196. #endif
  197.  
  198.  
  199. struct GetOpComArea {                            /* CMGetOperation() object walking comm area layout:    */
  200.     TOCValuePtr      theValue;                /*        the first (should be only) global name value        */
  201.     CM_USHORT             nbrOfGlobalNames;/*        count of nbr of global names found in object        */
  202. };
  203. typedef struct GetOpComArea GetOpComArea, *GetOpComAreaPtr;
  204.  
  205.  
  206. /*-----------------------------------------------------------------------*
  207.  | CMSetMetaHandler - associate a container type name with a metahandler |
  208.  *-----------------------------------------------------------------------*
  209.  
  210.  This routine records the association of type names with their metahandlers. A type name
  211.  is passed to CMOpen[New]Container() so that the Container Manager can use it to call the
  212.  appropriate metahandler to get the actual handler addresses.  Further, a value that has
  213.  a global type name which has an associated metahandler will produce a "dynamic" value.
  214.  
  215.  The function returns the address of the previous metahandler for the specified type if
  216.  one exists.  Otherwise NULL is returned.
  217.  
  218.  Note, that type name/metahandler associations are global to all containers.  Therefore,
  219.  the Container Manager neest to store its information as a function of the current session
  220.  global data defined by CMStartSession().  Hence the sessionData pointer should always be
  221.  the value returned by CMStartSession().
  222. */
  223.  
  224. CMHandlerAddr CM_FIXEDARGS CMSetMetaHandler(CMconst_CMSession sessionData,
  225.                                                                                         CMconst_CMGlobalName typeName,
  226.                                                                                           CMMetaHandler metaHandler)
  227. {
  228.     Boolean                dup;
  229.     CMMetaHandler  prevMetaHandler;
  230.     MetaHandlerPtr h;
  231.     
  232.     if (sessionData == NULL) return (NULL);            /* NOP if not initialized!                                */
  233.     
  234.     /* Enter the new metahandler and its type name into the metaHandler symbol table. The    */
  235.     /* address of the new entry is returned.  If there is one already there, the address     */
  236.     /* of that is returned, dup is set true, and nothing else done.                                                */
  237.     
  238.     h = cmDefineMetaHandler(metaHandler, (CM_UCHAR *)typeName, &dup,
  239.                                                     (SessionGlobalDataPtr)sessionData);
  240.     
  241.     if (!h)    {                                                                        /* if allocation failed...                                */
  242.         SessionERROR1(CM_err_NoHandler, typeName);/* yell and do nothing else                                    */
  243.         return (NULL);                                                        /* ...that's what I said!                                    */
  244.     }
  245.     
  246.     /* If there was a previous entry, update it with the new metahandler address and             */
  247.     /* return the "old" address.                                                                                                                    */
  248.     
  249.     if (dup)    {                                                                    /* if dup entry...                                                */
  250.         prevMetaHandler = h->metaHandler;                    /* ...we will return "old" metahandler        */
  251.         h->metaHandler = metaHandler;                            /* ...just replace with new metahandler        */
  252.     } else
  253.         prevMetaHandler = NULL;                                        /* if not dup, there is no prev. handler    */
  254.     
  255.     return ((CMHandlerAddr)prevMetaHandler);
  256. }
  257.  
  258.  
  259. /*-------------------------------------------------------------------------------*
  260.  | CMGetMetaHandler - return the metahandler address associated with a type name |
  261.  *-------------------------------------------------------------------------------*
  262.  
  263.  This function searches the metaHandler symbol table for the specified typeName and returns
  264.  the associated metahandler address.  NULL is returned if the type name does not exist.
  265.  
  266.  As with CMSetMetaHandler() above, CMGetMetaHandler() requires the session global data
  267.  pointer returned by CMStartSession().
  268. */
  269.  
  270. CMHandlerAddr CM_FIXEDARGS CMGetMetaHandler(CMconst_CMSession sessionData,
  271.                                                                                         CMconst_CMGlobalName typeName)
  272. {
  273.     MetaHandlerPtr h;
  274.     
  275.     if (sessionData == NULL) return (NULL);                            /* NOP if not initialized!                */
  276.  
  277.     h = cmLookupMetaHandler((CM_UCHAR *)typeName, (SessionGlobalDataPtr)sessionData);
  278.     
  279.     if (!((SessionGlobalDataPtr)sessionData)->success) {/* if we had allocation error...    */
  280.         SessionERROR1(CM_err_HandlerError, typeName);            /* ...yell                                                */
  281.         h = NULL;
  282.     }
  283.  
  284.     return (h ? (CMHandlerAddr)h->metaHandler : NULL);    /* NULL or found metahandler            */
  285. }
  286.  
  287.  
  288. /*---------------------------------------------------------*
  289.  | checkValue - check a value to see if it's a global name |
  290.  *---------------------------------------------------------*
  291.  
  292.  This is a cmWalkObject() action routine initiated by CMGetOperation() below to find the
  293.  global name value in an object. The "refCon" is a pointer to a GetOpComArea communication
  294.  area where we will save the value pointer.  We also count the number of global names
  295.  seen in the object.  It shoould be 1.  But we walk the entire object just to be sure.
  296.  
  297.  Note, this "static" is intentionally left to default memory model under DOS since it is
  298.  passed as a function pointer to cmWalkObject().
  299. */
  300.  
  301. static TOCWalkReturns checkValue(ContainerPtr container, TOCValuePtr theValue, CMRefCon refCon)
  302. {
  303.     GetOpComAreaPtr g = (GetOpComAreaPtr)refCon;
  304.     ContainerPtr        unused = container;
  305.     
  306.     if (theValue->flags & kCMGlobalName) {
  307.         g->theValue = theValue;                                                    /* save global name ptr                            */
  308.         ++g->nbrOfGlobalNames;                                                    /* count it too                                            */
  309.     }
  310.     
  311.     return (WalkNextTOCValue);                                                /* continue value walk                            */
  312. }
  313.  
  314.  
  315. /*--------------------------------------------------------------------------*
  316.  | CMGetOperation - get handler for a specific operation on a specific type |
  317.  *--------------------------------------------------------------------------*
  318.  
  319.  This routine takes a targetType which is defined as a globally unique name and uses that
  320.  name find a metahandler. The matahandler, in turn, is used to get the handler routine
  321.  address for the specified operationType.  The function returns the resulting address.
  322.  
  323.  Metahandler proc addresses are given to the Container Manager by calls to
  324.  CMSetMetaHandler().  The global name value for the input targetType is treated as the
  325.  typeName to find the metahandler.  As just mentioned above, the  metahandler is called
  326.  with the operationType to get the operation address returned.
  327. */
  328.  
  329. CMHandlerAddr CM_FIXEDARGS CMGetOperation(CMType targetType,
  330.                                                                                     CMconst_CMGlobalName operationType)
  331. {    
  332.     TOCObjectPtr      theObject;
  333.     TOCValuePtr         theValue;
  334.     ContainerPtr      container;
  335.     CM_CHAR                  *typeName;
  336.     MetaHandlerPtr metaHandler;
  337.     GetOpComArea      getOpComArea;
  338.     
  339.     ExitIfBadType(targetType, NULL);                                    /* validate targetType                            */
  340.  
  341.     theObject = (TOCObjectPtr)targetType;
  342.     container = theObject->container;
  343.         
  344.     /* Walk the entire object and look at all the values to find the value for a global        */
  345.     /* name.  The object can have other properties and values, but there better be only     */
  346.     /* one global name.  The object is walked with cmWalkObject().  The "refCon" we pass    */
  347.     /* is a pointer to a communication area which will hold the count of the global name    */
  348.     /* values and the pointer to it.  As just mentioned, if the count comes back other         */
  349.     /* than 1, we have an error.                                                                                                                    */
  350.     
  351.     getOpComArea.theValue = NULL;                                            /* init value ptr to no value yet        */
  352.     getOpComArea.nbrOfGlobalNames = 0;                                /* there are no global names yet too*/
  353.     
  354.     cmWalkObject(container, theObject, &getOpComArea, NULL, NULL, NULL, checkValue);
  355.     
  356.     /* Get the global name for this type. The type must have only one property, one value,*/
  357.     /* and that value must be for a global name.                                                                                    */
  358.         
  359.     if (getOpComArea.nbrOfGlobalNames > 1) {                    /* must have exactly 1 global name    */
  360.         ERROR2(CM_err_AmbiguousType, "CMGetOperation", CONTAINERNAME);
  361.         return (NULL);
  362.     }
  363.  
  364.     if (getOpComArea.nbrOfGlobalNames == 0) {
  365.         ERROR2(CM_err_TypeNotGlobal, "CMGetOperation", CONTAINERNAME);
  366.         return (NULL);
  367.     }
  368.     
  369.     /* Set the typeName to point at the global name now that we're happy there is one...    */
  370.     
  371.     theValue = getOpComArea.theValue;
  372.     if (theValue == NULL) return (NULL);                            /* safety                                                        */
  373.     typeName = GetGlobalName(theValue->value.globalName.globalNameSymbol);
  374.     
  375.     /* Use the global name to look up the metahandler in the meta handler symbol table.        */
  376.     /* A few things can go wrong here, but if we successfully found a metahandler symbol    */
  377.     /* table entry we use the resulting metahandler proc pointer to get the routine                */
  378.     /* address for the input operationType.  That's what we return.                                                */
  379.     
  380.     if ((metaHandler = cmLookupMetaHandler((CM_UCHAR *)typeName, SESSION)) == NULL) { 
  381.         ERROR1(CM_err_UndefMetaHandler, typeName);
  382.         return (NULL);
  383.     }
  384.     
  385.     if (!SessionSuccess) {                                                        /* if allocation error...                        */
  386.         ERROR1(CM_err_HandlerError, typeName);                    /* ...yell                                                    */
  387.         return (NULL);
  388.     }
  389.     
  390.     return ((CMHandlerAddr)(*metaHandler->metaHandler)(NULL, operationType));
  391. }
  392.  
  393.  
  394. /*---------------------------------------------------------------------------*
  395.  | CMMalloc - handler/user interface to Container Manager's memory allocator |
  396.  *---------------------------------------------------------------------------*
  397.  
  398.  This routine provides a access path for the user (usually a handler writer) to use the
  399.  same memory management allocator defined for the current Container Manager session.  size
  400.  bytes are allocated as defined by that handler.  
  401.  
  402.  The session memory allocator handler is defined by the metahandler passed to
  403.  CMStartSession().  The sessionData is the current session refNum returned from
  404.  CMStartSession().
  405. */
  406.  
  407. void CM_PTR * CM_FIXEDARGS CMMalloc(CMSize size, CMSession sessionData)
  408. {
  409.     return ((sessionData == NULL) ? NULL : SessionMalloc(size));
  410. }
  411.  
  412.  
  413. /*---------------------------------------------------------------------------*
  414.  | CMFree - handler/user interface to Container Manager's memory deallocator |
  415.  *---------------------------------------------------------------------------*
  416.  
  417.  This routine provides a access path for the user (usually a handler writer) to use the
  418.  same memory management deallocator defined for the current Container Manager session.  A
  419.  pointer (ptr) assumed to be allocated by CMMalloc() is passed to release the memory in the
  420.  manner defined by the handler.  
  421.  
  422.  The session memory deallocator handler is defined by the metahandler passed to
  423.  CMStartSession().  The sessionData is the current session refNum returned from
  424.  CMStartSession().
  425. */
  426.  
  427. void CM_FIXEDARGS CMFree(CMPtr ptr, CMSession sessionData)
  428. {
  429.     if (sessionData != NULL) SessionFree(ptr);
  430. }
  431.  
  432.  
  433. /*--------------------------------------------------------------------------------*
  434.  | CMError - handler/user interface to Container Manager's session error reporter |
  435.  *--------------------------------------------------------------------------------*
  436.  
  437.  This routines provides an access path for the user (usually an handler writer) to use the
  438.  same error reporter defined for the current Container Manager session.  The session error 
  439.  reporting handler is defined by the metahandler passed to CMStartSession().  The
  440.  sessionData is the current session refNum returned from CMStartSession().  The string is
  441.  the message to be processed by the handler.  Optional string inserts can be passed to put
  442.  into the string.  The string indicates the position of the inserts by "^0", "^1", etc.
  443.  "^0" gets the first insert, "^1" the second, and so on.  Inserts may be repeated.
  444.  
  445.  Note, the maximum length of the passed message plus its inserts is limited to 256 
  446.  characters.  Also, if the error reporting handler returns, so with this routine.
  447. */
  448.  
  449. void CM_VARARGS CMError(CMSession sessionData, CMErrorString message, ...)
  450. {
  451.     va_list inserts;
  452.     
  453.     va_start(inserts, message);
  454.     CMVError(sessionData, message, inserts);
  455.     va_end(inserts);
  456. }
  457.  
  458.  
  459. /*---------------------------------------------------------------------------------*
  460.  | CMVError - handler/user interface to Container Manager's session error reporter |
  461.  *---------------------------------------------------------------------------------*
  462.  
  463.  This routine is the same as CMError() above, except that the extra message inserts are
  464.  given as a variable argument list as defined by the "stdarg" facility.
  465.  
  466.  This routine assumes the caller sets up and terminates the variable arg list using the
  467.  "stdarg.h" calls as follows:
  468.  
  469.              #include <stdarg.h>
  470.             
  471.              callersRoutine(args, ...)
  472.             {
  473.                 va_list inserts;
  474.                 
  475.                 - - -
  476.                 
  477.                 va_start(inserts, args);
  478.                 CMVError(sessionData, message, inserts);
  479.                 va_end(inserts);
  480.                 
  481.                 - - -
  482.             }
  483.             
  484.  See CMError() for further details.
  485. */
  486.  
  487. void CM_FIXEDARGS CMVError(CMSession sessionData, CMErrorString message, va_list inserts)
  488. {
  489.     if (sessionData != NULL) {                                                                        /* if session defined...*/
  490.         strcpy((CM_CHAR *)SessionScratchBufr, message);                                /* ...use private bufr    */
  491.         CMVAddMsgInserts((CM_CHAR *)SessionScratchBufr, 256, inserts);    /* ...add in inserts        */
  492.         SessionERROR1(CM_err_GenericMessage, SessionScratchBufr);        /* ...report error            */
  493.     }
  494. }
  495.                                                           
  496.                                                             CM_END_CFUNCTIONS
  497.