ComponentIncludes/ComponentDispatchHelper.c

/*
 
    File:       ComponentDispatchHelper.c
 
    Copyright:  © 1995-2001 by Apple Computer, Inc., all rights reserved.
 
*/
 
// **** 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(0x,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 };   \
        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;
}