home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / AppleScript / Additions / Wild 1.0.1 / project / C sources / wild.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-09  |  14.1 KB  |  497 lines  |  [TEXT/KAHL]

  1. //    wild.c        wildcard AppleScript addition
  2. //
  3. //    93/11/15    File created
  4. //    93/12/08    *** released Wild 0.1.0 ***
  5. //    93/12/09    moved common files to the THINK C Folder
  6. //    94/01/24    removed the licensing mechanism with NO_LICENCE
  7. //    94/01/24    *** released Wild 1.0.0 ***
  8. //    94/05/09    Totally removed the licensing mechanism and added the GNU comments
  9. //
  10. //--------------------------------------------------------------------------------------------------
  11. //  Copyright © 1993, 1994 by Rainbow Hill Pty Ltd.
  12. //
  13. //    This program is free software; you can redistribute it and/or modify it under the terms of
  14. //    the GNU General Public License as published by the Free Software Foundation; either version 2
  15. //    of the License, or any later version.
  16. //
  17. //    This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  18. //    without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  19. //    See the GNU General Public License for more details.
  20. //
  21. //    You should have received a copy of the GNU General Public License along with this program;
  22. //    if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  23. //
  24.  
  25. //#define DEBUG_SHOW_PARM
  26. //#define DEBUG_SHOW_ITEMS
  27. //#define DEBUG_SHOW_ERR_MESS
  28.  
  29. //---------------------------- Apple includes
  30. #include <Aliases.h>
  31. #include <AppleEvents.h>
  32. #include <Errors.h>
  33. #include <Files.h>
  34. #include <Resources.h>
  35.  
  36. //---------------------------- C includes
  37. #include <string.h>
  38.  
  39. //---------------------------- other includes
  40. #include <AERegistry.h>
  41. #include "parm.h"
  42. #include "match.h"
  43. #include "wild.h"
  44.  
  45. static OSErr addItem(
  46.                         FSSpec *,        // --> fss of the item to be added
  47.                         AEDescList *,    // <-> output list to be returned as reply
  48.                         char *            // <--  error message
  49.                         );
  50.  
  51. //****************************************************************************************** main
  52. pascal OSErr main(
  53.                     AppleEvent    event,
  54.                     AppleEvent    reply,
  55.                     long        handlerRefCon
  56.                     ) {
  57.  
  58.     OSErr            retVal;
  59.     AEDescList        inList;
  60.     AEDescList        outList;
  61.     DescType        typeCode;
  62.     Size            actualSize;
  63.     char            buff[WILD_bufferLength];
  64.     long            nItems;
  65.     long            kItem;
  66.     FSSpec            fss;
  67.     AEKeyword        key;
  68.     char            errMessage[WILD_bufferLength];
  69.     Ptr                aPtr;
  70.     Boolean            wasChanged;
  71.     CInfoPBRec        param;
  72.      wild_parm_t        parms;
  73.      Boolean            itMatches;
  74.      Boolean            inListCreated;
  75.      Boolean            outListCreated;
  76.      char            theName[WILD_nameLength];        // [wildcarded] item name from descriptor
  77.      unsigned char    paramName[WILD_nameLength];
  78.     short            k;
  79.     Boolean            itemOK;
  80.     short            index;
  81.     match_wild_t    wilds[WILD_maxFilenameLen];
  82.     short            nWild;
  83.     match_wild_t    onlyWilds[WILD_maxFilenameLen];
  84.     short            nOnlyWild;
  85.  
  86.     // initialise some variables
  87.     errMessage[0] = '\0';
  88.     outListCreated = false;
  89.     inListCreated = false;    
  90.  
  91.     retVal = AEGetParamDesc(&event, keyDirectObject, typeAEList, &inList);
  92.     if (retVal != noErr) {
  93. #        ifdef DEBUG_SHOW_ERR_MESS
  94.             strcpy(errMessage, "AEGetParamDesc");
  95. #        endif
  96.         goto DONE_LBL;                                                                    // --->
  97.         }
  98.     inListCreated = true;
  99.  
  100.     // extract the parameters from the AE
  101.     retVal = parm_get(&event, &parms, errMessage);
  102.     if (retVal != noErr) goto DONE_LBL;                                                    // --->
  103.  
  104.     // check that the user has not switched off both files and folders
  105.     if (parms.files == false && parms.folders == false) {
  106.         retVal = errAEEventNotHandled;
  107.         GetIndString(errMessage, WILD_errMessRsrc, WILD_nothingErrStr);
  108.         p2cstr(errMessage);
  109.         goto DONE_LBL;                                                                    // --->
  110.         }
  111.  
  112. #        ifdef DEBUG_SHOW_PARM
  113.         {
  114.             #define Place(x, i, what) {                    \
  115.                 i++;                                    \
  116.                 strcpy(&x[i], (const char *)what);        \
  117.                 i += strlen(what) - 1;                    \
  118.                 }
  119.  
  120.             k = 0;
  121.             Place(buff, k, "wild cards: ");
  122.             buff[++k] = parms.longW;
  123.             buff[++k] = parms.shortW;
  124.             Place(buff, k, "\rfile:");        Place(buff, k, ((parms.files) ? "T" : "F"));
  125.             Place(buff, k, " fold:");        Place(buff, k, ((parms.folders) ? "T" : "F"));
  126.             Place(buff, k, " case:");        Place(buff, k, ((parms.caseS) ? "T" : "F"));
  127.             Place(buff, k, " long:");        Place(buff, k, ((parms.doLong) ? "T" : "F"));
  128.             Place(buff, k, " shor:");        Place(buff, k, ((parms.doShort) ? "T" : "F"));
  129.             Place(buff, k, " crea:");        Place(buff, k, ((parms.doCreator) ? "T" : "F"));
  130.             Place(buff, k, " type:");        Place(buff, k, ((parms.doType) ? "T" : "F"));
  131.             if (parms.doCreator) {
  132.                 Place(buff, k, "\rcreator: '");
  133.                 strncpy(&buff[++k], (const char *)&parms.creator, 4);
  134.                 k += 3;
  135.                 Place(buff, k, "'");
  136.                 }
  137.             if (parms.doType) {
  138.                 Place(buff, k, "\rfile type: '");
  139.                 strncpy(&buff[++k], (const char *)&parms.type, 4);
  140.                 k += 3;
  141.                 Place(buff, k, "'");
  142.                 }
  143.             buff[0] = k;
  144.             ParamText(buff, "", "", "");
  145.             Alert(WILD_genericDialogRsrc, nil);
  146.             }
  147. #            endif
  148.  
  149.     // get the number of descriptor records in the list
  150.     retVal = AECountItems(&inList, &nItems);
  151.     if (retVal != noErr) {
  152. #        ifdef DEBUG_SHOW_ERR_MESS
  153.             strcpy(errMessage, "AECountItems");
  154. #        endif
  155.         goto DONE_LBL;                                                                    // --->
  156.         }
  157.  
  158.     // create a descriptor list to return the items which pass filtering
  159.     retVal = AECreateList(nil, (Size)0, false, &outList);
  160.     if (retVal != noErr) {
  161. #        ifdef DEBUG_SHOW_ERR_MESS
  162.             strcpy(errMessage, "AECreateList");
  163. #        endif
  164.         goto DONE_LBL;                                                                    // --->
  165.         }
  166.     outListCreated = true;
  167.  
  168.     // analyse the wildcards in the selection if there is one
  169.     if (parms.only[0] == '\0')
  170.         nOnlyWild = 0;
  171.     else
  172.         nOnlyWild = match_setWild(parms.only, &parms, onlyWilds);
  173.  
  174.     // get each descriptor from the list
  175.     for (kItem = 1; kItem <= nItems && retVal == noErr; kItem++) {
  176.         retVal = AEGetNthPtr(
  177.                             &inList,
  178.                             kItem,
  179.                             typeWildCard,
  180.                             &key,
  181.                             &typeCode,
  182.                             (Ptr)buff,
  183.                             sizeof(buff),
  184.                             &actualSize
  185.                             );
  186.         if (retVal != noErr) {
  187. #            ifdef DEBUG_SHOW_ERR_MESS
  188.                 strcpy(errMessage, "AEGetNthPtr");
  189. #            endif
  190.             goto DONE_LBL;                                                                // --->
  191.             }
  192.  
  193.         // determine the type of the descriptor and act accordingly
  194.         nWild = 0;
  195.         switch (typeCode) {
  196.  
  197.             case typeChar:            // string
  198.             case typeStyledText:
  199.             case typeIntlText:
  200.                 buff[actualSize] = '\0';
  201.  
  202.                 // extract the item name from buff
  203.                 for (k = actualSize - 1; k >= 0 && buff[k] != ':'; k--)
  204.                     ;
  205.                 strcpy(theName, (const char *)&buff[k + 1]);
  206.  
  207.                 // check whether the name is wildcarded and if so, process wildcards
  208.                 nWild = match_setWild(theName, &parms, wilds);
  209.  
  210.                 // covert the parameter to an FSS
  211.                 c2pstr(buff);
  212.                 retVal = FSMakeFSSpec(-1, 2L, buff, &fss);
  213.                 p2cstr(buff);
  214.                 if (retVal == fnfErr) {
  215.  
  216.                     // if the name is wildcarded, we expect not to find it
  217.                     if (nWild != 0) {
  218.                         retVal = noErr;
  219.                         }
  220.                     else {
  221.  
  222.                         GetIndString(errMessage, WILD_miscStrRsrc, WILD_itemStr);
  223.  
  224.                         // append the item number within the input list
  225.                         k = errMessage[0] + 1;
  226.                         NumToString((long)kItem, &errMessage[k]);
  227.                         errMessage[0] += errMessage[k] + 1;
  228.                         errMessage[k] = ' ';    // mask the second p-length with a space
  229.  
  230.                         // append the error string
  231.                         k = errMessage[0] + 1;
  232.                         GetIndString(&errMessage[k], WILD_errMessRsrc, WILD_notFoundErrStr);
  233.                         errMessage[0] += errMessage[k] + 1;
  234.                         errMessage[k] = ' ';    // mask the second p-length with a space
  235.  
  236.                         p2cstr(errMessage);
  237.                         goto DONE_LBL;                                                    // --->
  238.                         }
  239.  
  240.                     } // FSMakeFSSpec could not find the item
  241.                 else if (retVal != noErr) {
  242.  
  243. #                    ifdef DEBUG_SHOW_ERR_MESS
  244.                         strcpy(errMessage, "FSMakeFSSpec");
  245. #                    endif
  246.                     goto DONE_LBL;                                                        // --->
  247.                     }
  248.  
  249.                 break;
  250.  
  251.             case typeAlias:            // alias
  252.                 aPtr = (Ptr)buff;
  253.                 retVal = ResolveAlias(nil, (AliasHandle)&aPtr, &fss, &wasChanged);
  254.                 if (retVal != noErr) {
  255. #                    ifdef DEBUG_SHOW_ERR_MESS
  256.                         strcpy(errMessage, "ResolveAlias");
  257. #                    endif
  258.                     goto DONE_LBL;                                                        // --->
  259.                     }
  260.  
  261.                 // save the name of the item (which cannot be wildcarded)
  262.                 memcpy((void *)theName, (const void *)&fss.name[1], (Size)fss.name[0]);
  263.                 theName[fss.name[0]] = '\0';
  264.  
  265.                 break;
  266.  
  267.             default:            // a type of descriptor that we do not process
  268.                 retVal = errAEWrongDataType;
  269.                 GetIndString(errMessage, WILD_errMessRsrc, WILD_dirParDataErrStr);
  270.                 p2cstr(errMessage);
  271.                 goto DONE_LBL;                                                            // --->
  272.             }
  273.  
  274.         // if the name is wildcarded, loop on all items of the parent directory and
  275.         // only retain the items which match all the criteria
  276.         if (nWild != 0) {
  277.             param.dirInfo.ioCompletion = nil;
  278.             param.dirInfo.ioNamePtr = paramName;
  279.  
  280.             // we will exit the loop when we attempt to use a Directory Index that exceeds
  281.             // the number of items in the directory
  282.             for (index = 1; retVal == noErr; index++ ) {
  283.                 param.dirInfo.ioVRefNum = fss.vRefNum;
  284.                 param.dirInfo.ioDrDirID = fss.parID;
  285.                 param.dirInfo.ioFDirIndex = index;
  286.                 paramName[0] = '\0';
  287.                 retVal = PBGetCatInfo(¶m, false);
  288.                 p2cstr(paramName);
  289.                 if (retVal != noErr) {
  290. #                    ifdef DEBUG_SHOW_ERR_MESS
  291.                         strcpy(errMessage, "PBGetCatInfo 1");
  292. #                    endif
  293.                     }
  294.                 else {
  295.  
  296.                     // check whether the item name matches the wildcarded name
  297.                     if (
  298.                             match_string((char *)paramName, theName, wilds, nWild, parms.caseS)
  299.                         ) {
  300.  
  301.                         // The name matches. Check the selection if it is there.
  302.                         if (
  303.                                 parms.only[0] == '\0'
  304.                                 ||
  305.                                 match_string(
  306.                                                 (char *)paramName,
  307.                                                 parms.only,
  308.                                                 onlyWilds,
  309.                                                 nOnlyWild,
  310.                                                 parms.caseS
  311.                                                 )
  312.                                 ) {
  313.  
  314.                             // The selection is not there or it is matched. Check the rest.
  315.                             if (match_criteria(¶m, &parms)) {
  316.  
  317.                                 // make an alias and attach it to the list for the reply AE
  318.                                 strcpy((char *)&fss.name[1], (const char *)paramName);
  319.                                 fss.name[0] = strlen((char *)paramName);
  320.                                 retVal = addItem(&fss, &outList, errMessage);
  321.  
  322.                                 } // the other filtering criteria were satisfied
  323.                             } // the selection was not there or was matched
  324.                         } // the item name matched the wildcards
  325.                     } // PBGetCatInfo was successful
  326.                 } // looping on all items
  327.             if (retVal != fnfErr) goto DONE_LBL;                                        // --->
  328.             retVal = noErr;
  329.  
  330.             } // the name was wildcarded
  331.         else {
  332.  
  333.             // obtain the catalogue info to distinguish between files and folders
  334.             c2pstr(theName);
  335.             param.dirInfo.ioCompletion = nil;
  336.             param.dirInfo.ioVRefNum = fss.vRefNum;
  337.             param.dirInfo.ioNamePtr = (unsigned char *)theName;
  338.             param.dirInfo.ioDrDirID = fss.parID;
  339.             param.dirInfo.ioFDirIndex = 0;
  340.             retVal = PBGetCatInfo(¶m, false);
  341.             p2cstr(theName);
  342.             if (retVal == noErr) {
  343.  
  344.                 // check the selection if it is there
  345.                 if (
  346.                         parms.only[0] == '\0'
  347.                         ||
  348.                         match_string(
  349.                                         theName,
  350.                                         parms.only,
  351.                                         onlyWilds,
  352.                                         nOnlyWild,
  353.                                         parms.caseS
  354.                                         )
  355.                         ) {
  356.  
  357.                     // Right. Now check the filtering criteria.
  358.                     if (match_criteria(¶m, &parms)) {
  359.  
  360.                         // make an alias and attach it to the list that will go into the reply AE
  361.                         retVal = addItem(&fss, &outList, errMessage);
  362.  
  363.                         } // the other filtering criteria were satisfied
  364.                     } // the selection was not there or was matched
  365.                 } // PBGetCatInfo was successful
  366.             else if (retVal == fnfErr) {
  367.  
  368.                 retVal = noErr;
  369.  
  370.                 } // PBGetCatInfo could not find the item
  371.             else {
  372.  
  373. #                ifdef DEBUG_SHOW_ERR_MESS
  374.                     strcpy(errMessage, "PBGetCatInfo 2");
  375. #                endif
  376.                 goto DONE_LBL;                                                            // --->
  377.  
  378.                 } // PBGetCatInfo returned an error
  379.             } // the name was not wildcarded
  380.         } // going through all descriptors in the list
  381.  
  382.     // prepare the reply
  383.     retVal = AEPutParamDesc(&reply, keyDirectObject, &outList);
  384.     if (retVal != noErr) {
  385. #        ifdef DEBUG_SHOW_ERR_MESS
  386.             strcpy(errMessage, "AEPutParamDesc");
  387. #        endif
  388.         goto DONE_LBL;                                                                    // --->
  389.         }
  390.  
  391. DONE_LBL:                                                                                // <---
  392.  
  393.     // cleanup
  394.     if (inListCreated) {
  395.         if (retVal == noErr) {
  396.             retVal = AEDisposeDesc((AEDesc *)&inList);
  397. #            ifdef DEBUG_SHOW_ERR_MESS
  398.                 if (retVal != noErr) strcpy(errMessage, "AEDisposeDesc: inList");
  399. #            endif
  400.             }
  401.         else {
  402.             (void)AEDisposeDesc((AEDesc *)&inList);
  403.             }
  404.         }
  405.  
  406.     if (outListCreated) {
  407.         if (retVal == noErr) {
  408.             retVal = AEDisposeDesc((AEDesc *)&outList);
  409. #            ifdef DEBUG_SHOW_ERR_MESS
  410.                 if (retVal != noErr) strcpy(errMessage, "AEDisposeDesc: outList");
  411. #            endif
  412.             }
  413.         else {
  414.             (void)AEDisposeDesc((AEDesc *)&outList);
  415.             }
  416.         }
  417.  
  418.     if (retVal != noErr && errMessage[0] != '\0') {
  419.         if (retVal == userCanceledErr) {
  420.  
  421.             // We use userCanceledErr to return a message to the user, but we have to
  422.             // change it, otherwise AppleScript will not display any message at all. Note
  423.             // that if the error code is userCanceledErr but there is no errMessage, we
  424.             // don't pass here. In that case, the cancelling is passed back to AppleScript
  425.             // as expected. Here we can use the error we like, because AppleScript only
  426.             // display our message.
  427.             retVal = 12345;
  428.             }
  429.         else {
  430.             strcat(errMessage, "\r(");
  431.             GetIndString(buff, WILD_miscStrRsrc, WILD_OSErrStr);
  432.             p2cstr(buff);
  433.             strcat(errMessage, (const char *)buff);
  434.             NumToString((long)retVal, buff);
  435.             p2cstr(buff);
  436.             strcat(errMessage, (const char *)buff);
  437.             strcat(errMessage, ")");
  438.             }
  439.         (void)AEPutParamPtr(
  440.                             &reply,
  441.                             keyErrorString,
  442.                             typeChar,
  443.                             errMessage,
  444.                             (Size)strlen(errMessage)
  445.                             );
  446.         }
  447.  
  448.     return (retVal);
  449.     } // main
  450.  
  451. //------------------------------------------------------------------------------------------ addItem
  452. static OSErr addItem(
  453.                         FSSpec        *fss,            // --> fss of the item to be added
  454.                         AEDescList    *outList,        // <-> output list to be returned as reply
  455.                         char        *errMessage        // <--  error message
  456.                         ) {
  457.     OSErr            retVal;
  458.     AliasHandle        theAlias;
  459.  
  460. #    ifdef DEBUG_SHOW_ITEMS
  461.     {
  462.         char    aStr[WILD_bufferLength];
  463.         short    k;
  464.  
  465.         NumToString((long)fss->vRefNum, aStr);
  466.         k = aStr[0] + 1;
  467.         NumToString(fss->parID, &aStr[k]);
  468.         aStr[0] += aStr[k] + 1;
  469.         aStr[k] = '\r';
  470.         ParamText(aStr, "\p\r", fss->name, "");
  471.         Alert(WILD_genericDialogRsrc, nil);
  472.         }
  473. #    endif
  474.  
  475.     // make an alias out of the FSS
  476.     retVal = NewAliasMinimal(fss, &theAlias);
  477.     if (retVal != noErr || theAlias == nil) {
  478. #        ifdef DEBUG_SHOW_ERR_MESS
  479.             strcpy(errMessage, "NewAliasMinimal");
  480. #        endif
  481.         }
  482.     else {
  483.  
  484.         // add the item to the output descriptor list
  485.         HLock(theAlias);
  486.         retVal = AEPutPtr(outList, 0L, typeAlias, (Ptr)*theAlias, (*theAlias)->aliasSize);
  487.         HUnlock(theAlias);
  488.         if (retVal != noErr) {
  489. #            ifdef DEBUG_SHOW_ERR_MESS
  490.                 strcpy(errMessage, "AEPutPtr");
  491. #            endif
  492.             }
  493.         }
  494.  
  495.     return (retVal);
  496.     } // addItem;
  497.