ComponentDispatchHelper.c

/*
 
    File:       ComponentDispatchHelper.c
 
    Copyright:  © 1995-2001 by Apple Computer, Inc., all rights reserved.
 
    Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
                ("Apple") in consideration of your agreement to the following terms, and your
                use, installation, modification or redistribution of this Apple software
                constitutes acceptance of these terms.  If you do not agree with these terms,
                please do not use, install, modify or redistribute this Apple software.
 
                In consideration of your agreement to abide by the following terms, and subject
                to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
                copyrights in this original Apple software (the "Apple Software"), to use,
                reproduce, modify and redistribute the Apple Software, with or without
                modifications, in source and/or binary forms; provided that if you redistribute
                the Apple Software in its entirety and without modifications, you must retain
                this notice and the following text and disclaimers in all such redistributions of
                the Apple Software.  Neither the name, trademarks, service marks or logos of
                Apple Computer, Inc. may be used to endorse or promote products derived from the
                Apple Software without specific prior written permission from Apple.  Except as
                expressly stated in this notice, no other rights or licenses, express or implied,
                are granted by Apple herein, including but not limited to any patent rights that
                may be infringed by your derivative works or by other works in which the Apple
                Software may be incorporated.
 
                The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
                WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
                WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
                COMBINATION WITH YOUR PRODUCTS.
 
                IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
                CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
                GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
                OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
                (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
                ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
*/
 
// **** BEGIN: Error Checking the Required Macros
 
// Make sure BASENAME is defined
#ifndef COMPONENT_BASENAME
    #ifdef CALLCOMPONENT_BASENAME
        #define COMPONENT_BASENAME()    CALLCOMPONENT_BASENAME()
    #else
        #error "COMPONENT_BASENAME or CALLCOMPONENT_BASENAME must be defined for ComponentDispatchHelper.c"
    #endif
#endif
 
// Make sure GLOBALS is defined
#ifndef COMPONENT_GLOBALS
    #ifdef CALLCOMPONENT_GLOBALS
        #define COMPONENT_GLOBALS()     CALLCOMPONENT_GLOBALS()
    #else
        #error "COMPONENT_GLOBALS or CALLCOMPONENT_GLOBALS must be defined for ComponentDispatchHelper.c"
    #endif
#endif
 
// Make sure DISPATCH_FILE is defined
#ifndef COMPONENT_DISPATCH_FILE
    #error "COMPONENT_DISPATCH_FILE must be defined for ComponentDispatchHelper.c"
#endif
 
 
// Make sure UPP_PREFIX and SELECT_PREFIX are defined
#if !defined(COMPONENT_UPP_SELECT_ROOT)  && !defined(COMPONENT_UPP_PREFIX) && !defined(COMPONENT_SELECT_PREFIX)
    #error "COMPONENT_UPP_SELECT_ROOT or (COMPONENT_UPP_PREFIX and COMPONENT_SELECT_PREFIX) must be defined for ComponentDispatchHelper.c"
#endif
#ifdef COMPONENT_UPP_SELECT_ROOT
    #if defined(COMPONENT_UPP_PREFIX) || defined(COMPONENT_SELECT_PREFIX)
        #error "use only COMPONENT_UPP_SELECT_ROOT or (COMPONENT_UPP_PREFIX and COMPONENT_SELECT_PREFIX) for ComponentDispatchHelper.c"
    #endif
#else
    #if !defined(COMPONENT_UPP_PREFIX) || !defined(COMPONENT_SELECT_PREFIX)
        #error "COMPONENT_UPP_SELECT_ROOT or (COMPONENT_UPP_PREFIX and COMPONENT_SELECT_PREFIX) must be defined for ComponentDispatchHelper.c"
    #endif
#endif
#ifndef COMPONENT_UPP_PREFIX
    #ifndef COMPONENT_UPP_SELECT_ROOT
        #error "COMPONENT_UPP_SELECT_ROOT or (COMPONENT_UPP_PREFIX and COMPONENT_SELECT_PREFIX) must be defined for ComponentDispatchHelper.c"
    #else 
        #define COMPONENT_UPP_PREFIX()      cdh_GLUE2(upp,COMPONENT_UPP_SELECT_ROOT())
    #endif
#endif
#ifndef COMPONENT_SELECT_PREFIX
    #ifndef COMPONENT_UPP_SELECT_ROOT
        #error "COMPONENT_UPP_SELECT_ROOT or (COMPONENT_UPP_PREFIX and COMPONENT_SELECT_PREFIX) must be defined for ComponentDispatchHelper.c"
    #else 
        #define COMPONENT_SELECT_PREFIX()   cdh_GLUE2(k,COMPONENT_UPP_SELECT_ROOT())
    #endif
#endif
    
// Make sure SUBTYPE UPP_PREFIX and SELECT_PREFIX are defined correctly if they are used at all
#if defined(COMPONENT_SUBTYPE_UPP_SELECT_ROOT) || defined(COMPONENT_SUBTYPE_UPP_PREFIX) || defined(COMPONENT_SUBTYPE_SELECT_PREFIX)
    #ifdef COMPONENT_SUBTYPE_UPP_SELECT_ROOT
        #if defined(COMPONENT_SUBTYPE_UPP_PREFIX) || defined(COMPONENT_SUBTYPE_SELECT_PREFIX)
            #error "use only COMPONENT_SUBTYPE_UPP_PREFIX and COMPONENT_SUBTYPE_SELECT_PREFIX OR COMPONENT_SUBTYPE_UPP_SELECT_ROOT for ComponentDispatchHelper.c"
        #endif
    #else
        #if !defined(COMPONENT_SUBTYPE_UPP_PREFIX) || !defined(COMPONENT_SUBTYPE_SELECT_PREFIX)
            #error "COMPONENT_SUBTYPE_UPP_PREFIX and COMPONENT_SUBTYPE_SELECT_PREFIX OR COMPONENT_SUBTYPE_UPP_SELECT_ROOT must be defined for ComponentDispatchHelper.c"
        #endif
    #endif
    #ifndef COMPONENT_SUBTYPE_UPP_PREFIX
        #ifndef COMPONENT_SUBTYPE_UPP_SELECT_ROOT
            #error "COMPONENT_SUBTYPE_UPP_PREFIX or COMPONENT_SUBTYPE_UPP_SELECT_ROOT must be defined for ComponentDispatchHelper.c"
        #else 
            #define COMPONENT_SUBTYPE_UPP_PREFIX()      cdh_GLUE2(upp,COMPONENT_SUBTYPE_UPP_SELECT_ROOT())
        #endif
    #endif
    #ifndef COMPONENT_SUBTYPE_SELECT_PREFIX
        #ifndef COMPONENT_SUBTYPE_UPP_SELECT_ROOT
            #error "COMPONENT_SUBTYPE_SELECT_PREFIX or COMPONENT_SUBTYPE_UPP_SELECT_ROOT must be defined for ComponentDispatchHelper.c"
        #else 
            #define COMPONENT_SUBTYPE_SELECT_PREFIX()   cdh_GLUE2(k,COMPONENT_SUBTYPE_UPP_SELECT_ROOT())
        #endif
    #endif
#endif
 
// **** END: Error Checking the Required Macros
 
#if TARGET_API_MAC_OSX
#define CDHCONST    const
#else
#define CDHCONST
#endif
 
#if TARGET_OS_MAC
    #define PASCAL_RTN  pascal
#else
    #define PASCAL_RTN
#endif
#if !TARGET_OS_MAC || TARGET_CPU_PPC
    #define C_DISPATCH_WITH_GLOBALS 1
    #define C_DISPATCH_WITH_SWITCH  0
#elif TARGET_CPU_68K
    #ifdef COMPONENT_C_DISPATCHER
        #define C_DISPATCH_WITH_GLOBALS 0
        #define C_DISPATCH_WITH_SWITCH  1
    #else
        #define C_DISPATCH_WITH_GLOBALS 0
        #define C_DISPATCH_WITH_SWITCH  0
    #endif
#else
    #error "I have no idea what kind of machine you are using"
#endif
 
/*
    C_DISPATCH_WITH_GLOBALS implies global storage for dispatch information 
                            and procinfos returned by COMPONENTSELECTORLOOKUP
    C_DISPATCH_WITH_SWITCH  implies no global storage, dispatch by switch
                            and no procinfos returned by COMPONENTSELECTORLOOKUP
*/
 
    #define COMPONENTSELECTORLOOKUP ADD_BASENAME(FindRoutineUPP)
 
#ifdef COMPONENT_DISPATCH_MAIN
    #define COMPONENT_DISPATCH_ENTRY main
#else
    #define COMPONENT_DISPATCH_ENTRY ADD_BASENAME(ComponentDispatch)
#endif
 
#ifndef __COMPONENTS_K__
    #include "Components.k.h"
#endif
 
#define kCOMPONENT_NOERROR  ((ComponentFunctionUPP)-2)
#define kCOMPONENT_ERROR    ((ComponentFunctionUPP)-1)
#define kCOMPONENT_DELEGATE ((ComponentFunctionUPP)0)
 
#ifndef cdh_GLUE
    #define cdh_GLUE(a,b)       a##b
#endif
#ifndef cdh_GLUE2
    #define cdh_GLUE2(a,b)      cdh_GLUE(a,b)
#endif
#ifndef cdh_GLUE3
    #define cdh_GLUE3(a,b,c)    cdh_GLUE2(cdh_GLUE2(a,b),c)
#endif
 
#if TARGET_RT_LITTLE_ENDIAN
    #define ComponentCallLittleEndian       ComponentCall
#else
    #define ComponentCallLittleEndian       ComponentDelegate
#endif
 
#ifdef forPublicQTiRelease
    #define ComponentQTiCall(procName)              ComponentCall(procName)
    #define QTIComponentCall(procName)              ComponentCall(procName)
#endif
 
#define ADD_BASENAME(name) cdh_GLUE2(COMPONENT_BASENAME(),name)
 
#if C_DISPATCH_WITH_GLOBALS
    PASCAL_RTN ComponentResult COMPONENT_DISPATCH_ENTRY(ComponentParameters *params, COMPONENT_GLOBALS());
    static ComponentFunctionUPP COMPONENTSELECTORLOOKUP(short selector_num, ProcInfoType *procInfo);
 
    #if TARGET_OS_MAC && TARGET_CPU_PPC && !TARGET_API_MAC_CARBON
        // entry point for PowerPC native components
        struct RoutineDescriptor ADD_BASENAME(ComponentDispatchRD) =
          BUILD_ROUTINE_DESCRIPTOR((kPascalStackBased | RESULT_SIZE (kFourByteCode) |
                                    STACK_ROUTINE_PARAMETER (1, kFourByteCode) |
                                    STACK_ROUTINE_PARAMETER (2, kFourByteCode)),COMPONENT_DISPATCH_ENTRY);
    #endif
    
    PASCAL_RTN ComponentResult COMPONENT_DISPATCH_ENTRY(ComponentParameters *params,COMPONENT_GLOBALS())
    {
        ComponentFunctionUPP theProc;
        ComponentResult result = badComponentSelector;
        ProcInfoType theProcInfo;
        
        theProc = COMPONENTSELECTORLOOKUP(params->what, &theProcInfo);
 
        if (theProc) {
            if ( (theProc != kCOMPONENT_ERROR) && (theProc != kCOMPONENT_NOERROR) ) {
                if (theProcInfo != 0) {
                    result = CallComponentFunctionWithStorageProcInfo((Handle) storage, params, (ProcPtr)theProc, theProcInfo);
                }
            }
            else if ( theProc == kCOMPONENT_NOERROR ) {
                result = noErr;
            }
        }
    #ifdef GET_DELEGATE_COMPONENT
        else
            return DelegateComponentCall(params, GET_DELEGATE_COMPONENT());
    #endif
        return result;
    }
#elif C_DISPATCH_WITH_SWITCH
    PASCAL_RTN ComponentResult COMPONENT_DISPATCH_ENTRY(ComponentParameters *params, COMPONENT_GLOBALS());
    static ComponentFunctionUPP COMPONENTSELECTORLOOKUP(short selector_num);
 
    PASCAL_RTN ComponentResult COMPONENT_DISPATCH_ENTRY( ComponentParameters *params, COMPONENT_GLOBALS() )
        {
        ComponentFunctionUPP theProc;
        
        ComponentResult result = badComponentSelector;
        theProc = COMPONENTSELECTORLOOKUP(params->what);
 
        if (theProc) {
            if ( (theProc != kCOMPONENT_ERROR) && (theProc != kCOMPONENT_NOERROR) ) {
                result = CallComponentFunctionWithStorage((Handle) storage, params, theProc);
            }
            else if ( theProc == kCOMPONENT_NOERROR ) {
                result = noErr;
            }
        }
    #ifdef GET_DELEGATE_COMPONENT
        else
            result = DelegateComponentCall(params, GET_DELEGATE_COMPONENT());
    #endif
        return result;
        }
#endif
 
#if C_DISPATCH_WITH_GLOBALS
    typedef struct {
        ComponentFunctionUPP    theProc;
        ProcInfoType            theProcInfo;
    } cdhDispatchInfoRecord;
    
    typedef struct {
        short                   rangeMax;
        CDHCONST cdhDispatchInfoRecord  *cdhDispatchInfoP;
    } cdhRangeDispatchInfoRecord;
    
    #define ComponentSelectorOffset(theOffset)  enum {SelOffset = theOffset};
    
    #define ComponentRangeCount(theCount)       enum {RangeCount = theCount};
    #define ComponentRangeShift(theShift)       enum {RangeShift = theShift};
    #define ComponentRangeMask(theMask)         enum {RangeMask = cdh_GLUE2(0x0,theMask)};
    
    #define ComponentStorageType(theType)
    #define ComponentDelegateByteOffset(theOffset)
 
 
    #define StdComponentCall(procName)  \
        { (ComponentFunctionUPP) ADD_BASENAME(procName), cdh_GLUE3(uppCallComponent,procName,ProcInfo) },
    
    #define ComponentCall(procName) \
        { (ComponentFunctionUPP) ADD_BASENAME(procName), cdh_GLUE3(COMPONENT_UPP_PREFIX(),procName,ProcInfo) },
 
    #define ComponentSubTypeCall(procName)  \
        { (ComponentFunctionUPP) ADD_BASENAME(procName), cdh_GLUE3(COMPONENT_SUBTYPE_UPP_PREFIX(),procName,ProcInfo) },
 
    #define ComponentError(procName)            { kCOMPONENT_ERROR, 0 },
    
    #define StdComponentNoError(procName)       { kCOMPONENT_NOERROR, 0 },
    #define ComponentNoError(procName)          { kCOMPONENT_NOERROR, 0 },
    #define ComponentSubTypeNoError(procName)   { kCOMPONENT_NOERROR, 0 },
    
    #define ComponentDelegate(procName)         { kCOMPONENT_DELEGATE, 0 },
    
    
    #define ComponentRangeUnused(rangeNum) \
        static CDHCONST cdhDispatchInfoRecord cdh_GLUE2(cdhDispatchInfo,rangeNum)[1] = { { 0, 0 } };    \
        enum {cdh_GLUE2(cdhDispatchMax,rangeNum) = 0};
        
    #define ComponentRangeBegin(rangeNum)   \
        static CDHCONST cdhDispatchInfoRecord cdh_GLUE2(cdhDispatchInfo,rangeNum)[] = {
        
    #define ComponentRangeEnd(rangeNum)             \
        };      \
        enum {cdh_GLUE2(cdhDispatchMax,rangeNum) = sizeof(cdh_GLUE2(cdhDispatchInfo,rangeNum)) / sizeof(cdhDispatchInfoRecord)};
    
    #define ComponentComment(theComment)
 
    // define the static dispatch tables
    #include COMPONENT_DISPATCH_FILE
    
    #undef ComponentSelectorOffset
    #undef ComponentRangeCount
    #undef ComponentRangeShift
    #undef ComponentRangeMask
    #undef StdComponentCall
    #undef ComponentCall
    #undef ComponentSubTypeCall
    #undef ComponentError
    #undef StdComponentNoError
    #undef ComponentNoError
    #undef ComponentSubTypeNoError
    #undef ComponentDelegate
    #undef ComponentRangeUnused
    #undef ComponentRangeBegin
    #undef ComponentRangeEnd    
    
    #define ComponentSelectorOffset(theOffset)
    #define ComponentRangeCount(theCount)
    #define ComponentRangeShift(theShift)
    #define ComponentRangeMask(theMask)
    #define StdComponentCall(procName)
    #define ComponentCall(procName)
    #define ComponentSubTypeCall(procName)
    #define ComponentError(procName)
    #define StdComponentNoError(procName)
    #define ComponentNoError(procName)
    #define ComponentSubTypeNoError(procName)
    #define ComponentDelegate(procName)
    
    #define ComponentRangeUnused(rangeNum) \
        { 0, nil },
    #define ComponentRangeBegin(rangeNum)       \
        { cdh_GLUE2(cdhDispatchMax,rangeNum), cdh_GLUE2(cdhDispatchInfo,rangeNum) },
    #define ComponentRangeEnd(rangeNum)
    
    // define the static range tables (max per range and point to dispatch tables)
    static CDHCONST cdhRangeDispatchInfoRecord cdhRangeDispatch[RangeCount+1] = {
        #include COMPONENT_DISPATCH_FILE
    };
    
    ComponentFunctionUPP COMPONENTSELECTORLOOKUP(short selector_num, ProcInfoType *procInfo)
    {
        //ProcInfoType pinfo = 0;
        ComponentFunctionUPP result = kCOMPONENT_DELEGATE;
        CDHCONST cdhDispatchInfoRecord *infoP = nil;
        short theRange;
        
        theRange = selector_num >> RangeShift;
        if (theRange < 0) {
            selector_num += SelOffset;
            if (selector_num >= 0) {
                infoP = &(cdhRangeDispatch[0].cdhDispatchInfoP)[selector_num];
            }
        } else {
            if (theRange < RangeCount) {
                selector_num &= RangeMask;
                if (selector_num < cdhRangeDispatch[theRange+1].rangeMax)
                    infoP = &(cdhRangeDispatch[theRange+1].cdhDispatchInfoP)[selector_num];
            }
        }
        
        if (infoP) {
            *procInfo = infoP->theProcInfo;
            result = infoP->theProc;
        } 
        return result;
    }
 
#elif C_DISPATCH_WITH_SWITCH
    ComponentFunctionUPP COMPONENTSELECTORLOOKUP( short selector_num )
    {
        ComponentFunctionUPP aProc = (ComponentFunctionUPP) kCOMPONENT_DELEGATE;
    
        #define ComponentSelectorOffset(theOffset)
 
        #define case_ComponentCall(kPrefix,procName)    case cdh_GLUE3(kPrefix,procName,Select): aProc = (ComponentFunctionUPP)ADD_BASENAME(procName); break;
        #define StdComponentCall(procName)              case_ComponentCall(kComponent,procName)
        #define ComponentCall(procName)                 case_ComponentCall(COMPONENT_SELECT_PREFIX(),procName)
        #define ComponentSubTypeCall(procName)          case_ComponentCall(COMPONENT_SUBTYPE_SELECT_PREFIX(),procName)
 
        #define case_ComponentNoError(kPrefix,procName) case cdh_GLUE3(kPrefix,procName,Select): aProc = (ComponentFunctionUPP)kCOMPONENT_NOERROR; break;
        #define StdComponentNoError(procName)           case_ComponentNoError(kComponent,procName)
        #define ComponentNoError(procName)              case_ComponentNoError(COMPONENT_SELECT_PREFIX(),procName)
        #define ComponentSubTypeNoError(procName)       case_ComponentNoError(COMPONENT_SUBTYPE_SELECT_PREFIX(),procName)
 
        #define ComponentError(procName)                //ComponentError for C_DISPATCH_WITH_SWITCH uses default case (delegate if we can)
 
        #define ComponentDelegate(procName)             //The default case for C_DISPATCH_WITH_SWITCH is to delegate if we can, error if we can't
        
        #define ComponentRangeCount(theCount)
        #define ComponentRangeShift(theShift)
        #define ComponentRangeMask(theMask)
        #define ComponentRangeBegin(rangeNum)
        #define ComponentRangeEnd(rangeNum)
        #define ComponentRangeUnused(rangeNum)
        #define ComponentStorageType(theType)
        #define ComponentDelegateByteOffset(theOffset)
        #define ComponentComment(theComment)
 
        switch (selector_num) {
            #include COMPONENT_DISPATCH_FILE
            }
    
        return aProc;
    }
#endif
 
#ifdef OVERRIDE_CANDO
    ComponentResult OVERRIDE_CANDO( COMPONENT_GLOBALS(), short ftnNumber, ComponentResult result);
#endif
 
#ifndef TOUCH_UNUSED_ARG
    // a macro to avoid "unused variable" warnings
    #define TOUCH_UNUSED_ARG(arg)   ((void)arg)
#endif
 
PASCAL_RTN ComponentResult ADD_BASENAME(CanDo)( COMPONENT_GLOBALS(), short ftnNumber );
PASCAL_RTN ComponentResult ADD_BASENAME(CanDo)( COMPONENT_GLOBALS(), short ftnNumber )
{
    ComponentResult result;
#if C_DISPATCH_WITH_GLOBALS
    ProcInfoType ignore;
    result = (ComponentResult) COMPONENTSELECTORLOOKUP(ftnNumber, &ignore);
#else
    result = (ComponentResult) COMPONENTSELECTORLOOKUP(ftnNumber);
#endif
    
    /* check for a ComponentError */
    if ( result == (ComponentResult) kCOMPONENT_ERROR )
        result = false;
    else if ( result == (ComponentResult) kCOMPONENT_DELEGATE )
        result = false;
    else
        result = true;
 
#ifdef GET_DELEGATE_COMPONENT
    /* if we're delegated, then keep looking */
    if (!result)
        {
        if (GET_DELEGATE_COMPONENT())
            result = CallComponentCanDo( GET_DELEGATE_COMPONENT(), ftnNumber );
        }
#endif
 
#ifdef OVERRIDE_CANDO
    result = OVERRIDE_CANDO( storage, ftnNumber, result);
#else
    TOUCH_UNUSED_ARG(storage);
#endif
 
    return result;
}