Sources/MSAECountElements.c

// MSAECountElements.c
//
// Original version by Jon Lansdell and Nigel Humphreys.
// 4.0 and 3.1 updates by Greg Sutton.
// ©Apple Computer Inc 1996, all rights reserved.
 
/*
    Changes for 3.1
 
    14-Nov-95 : GS : Disposed of all interim descriptors in DoCountElements()
                        and GetDescForNumberOfElements().
 
    Changes for 4.0
 
    29-Feb-96 : GS : Added ability to count menus and menu items in MyCountProc()
*/
 
#include "MSAECountElements.h"
 
#include "MSToken.h"
#include "MSAEUtils.h"
#include "MSAETextUtils.h"
#include "MSAEWindowUtils.h"
#include "MSAEMenuUtils.h"
 
 
#pragma segment AppleEvent
 
 
// -----------------------------------------------------------------------
//  Name:       DoCountElements
//  Purpose:    Handles the Number Of Elements AppleEvent.
// -----------------------------------------------------------------------
 
pascal OSErr    DoCountElements(const AppleEvent    *theAppleEvent,
                                      AppleEvent    *reply,
                                      long          handlerRefCon)
{
#ifdef __MWERKS__
    #pragma unused (handlerRefCon)
#endif
 
    AEDesc      container = {typeNull, NULL},
                countDesc = {typeNull, NULL};
    DescType    desiredType;
    DescType    returnedType;
    Size        actualSize;
    OSErr       err;
    
        // pick up direct object, which is the container
        // in which things are to be counted.
    err = AEGetParamDesc(theAppleEvent, keyDirectObject, typeWildCard, &container);
    if (noErr != err) goto done;
        
        // now the class of objects to be counted
    err = AEGetParamPtr(theAppleEvent, keyAEObjectClass, typeType,
                                &returnedType, (Ptr)&desiredType, sizeof(desiredType), &actualSize);
    if (noErr != err) goto done;
        
        // missing any parameters?
    err = GotRequiredParams(theAppleEvent);
    if (noErr != err) goto done;
    
        // now get descriptor for count - put through function that
        // can handle lists.
    err = GetDescForNumberOfElements(desiredType, &container, &countDesc);
    
    err = AddResultToReply(&countDesc, reply, err);
 
done:
    if (container.dataHandle)
        AEDisposeDesc(&container);
    if (countDesc.dataHandle)
        AEDisposeDesc(&countDesc);
    
    return(err);
} // DoCountElements
 
 
OSErr   GetDescForNumberOfElements(DescType desiredType, AEDesc* container, AEDesc* result)
{
    long        itemCount,
                index,
                elementCount;
    AEDesc      tempDesc = {typeNull, NULL},
                aDesc = {typeNull, NULL},
                resultDesc = {typeNull, NULL};
    DescType    returnedType;
    OSErr       err;
    
            // If it's an object specifier, resolve into a token
    if (typeObjectSpecifier == container->descriptorType)
        err = AEResolve(container, kAEIDoMinimum, &tempDesc);
    else    // Otherwise, just copy it
        err = AEDuplicateDesc(container, &tempDesc);
 
    if (noErr != err) goto done;
 
    if (typeAEList == tempDesc.descriptorType)
    {
        err = AECreateList(NULL, 0 , false, result);    // Result will also be a list of items
        if (noErr != err) goto done;
        err = AECountItems(&tempDesc, &itemCount);
        if (noErr != err) goto done;
 
        for (index = 1; index <= itemCount; index++)    // Do in forward order
        {
            err = AEGetNthDesc(&tempDesc, index, typeWildCard, &returnedType, &aDesc);
 
            if (noErr == err)       // Call this function recursively if necessary
                err = GetDescForNumberOfElements(desiredType, &aDesc, &resultDesc);
            
            if (noErr == err)       // Add item to the end of our list
                err = AEPutDesc(result, 0, &resultDesc);
            
            if (aDesc.dataHandle)
                AEDisposeDesc(&aDesc);
            if (resultDesc.dataHandle)
                AEDisposeDesc(&resultDesc);
        }
    }
    else
    {
        err = MyCountProc(desiredType, tempDesc.descriptorType, &tempDesc, &elementCount);
        if (noErr != err) goto done;
        err = AECreateDesc(typeLongInteger, (Ptr)&elementCount, sizeof(elementCount), result);
    }
 
done:
    if (tempDesc.dataHandle)
        AEDisposeDesc(&tempDesc);
    if (aDesc.dataHandle)
        AEDisposeDesc(&aDesc);
    if (resultDesc.dataHandle)
        AEDisposeDesc(&resultDesc);
 
    return(err);
}
 
 
// This count procedure is installed along with MyCompareProc() to support
// formTest and formWhose.
 
pascal OSErr MyCountProc(DescType desiredType, DescType containerClass,
                                        const AEDesc *container, long* result)
{   
    AEDesc      aDesc = {typeNull, NULL},
                tempDesc = {typeNull, NULL};
    TextToken   aTextToken;
    MenuToken   aMenuToken;
    Size        actualSize;
    short       shortResult;
    OSErr       err;
        
            // If it's an object specifier, resolve into a token
    if (typeObjectSpecifier == container->descriptorType)
        err = AEResolve(container, kAEIDoMinimum, &tempDesc);
    else    // Otherwise, just copy it
        err = AEDuplicateDesc(container, &tempDesc);
        
    if (noErr != err) goto done;
    
    *result = -1;           // easily recognized illegal value
    
    switch (desiredType)
    {
        case cWindow:
            if ((containerClass == typeNull) || (containerClass == cApplication))
                *result = CountWindows();
            else
                err = errAEWrongDataType;
            break;
 
        case cDocument:
            if ((containerClass == typeNull) || (containerClass == cApplication))
                *result = CountDocuments();
            else
                err = errAEWrongDataType;
            break;
            
        case cChar:
        case cWord:
        case cParagraph:
            err = AECoerceDesc(&tempDesc, typeMyText, &aDesc);
            if (typeNull == aDesc.descriptorType)
                err = errAENoSuchObject;
            if (noErr != err) break;
            GetRawDataFromDescriptor(&aDesc, (Ptr)&aTextToken, sizeof(aTextToken), &actualSize);
 
            err = CountTextElements(TEHandleFromTextToken(&aTextToken),
                                        aTextToken.tokenOffset, aTextToken.tokenLength,
                                                                    desiredType, &shortResult);
            if (noErr != err) break;
            *result = shortResult;
            break;
            
        case cMenu:
            if ((containerClass == typeNull) || (containerClass == cApplication))
                *result = CountMenus( );
            else
                err = errAEWrongDataType;
            break;
            
        case cMenuItem:
            if ( typeMyMenu == tempDesc.descriptorType )
            {
                GetRawDataFromDescriptor( &tempDesc,
                        (Ptr)&aMenuToken, sizeof( aMenuToken ), &actualSize );
 
                *result = CountMenuTokenItems( &aMenuToken );
            }
            else
                err = errAEWrongDataType;
            break;
            
        default:
            err = errAECantHandleClass;
    }
    
done:
    if (tempDesc.dataHandle)
        AEDisposeDesc(&tempDesc);
    if (aDesc.dataHandle)
        AEDisposeDesc(&aDesc);
        
    return(err);
}   // MyCountProc