home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / System / Sample 2.4 Think C distribution / scn.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-07-11  |  21.7 KB  |  714 lines  |  [TEXT/KAHL]

  1. /*______________________________________________________________________
  2.  
  3.     scn.c - Volume Scanning Module.
  4.     
  5.     Copyright © 1988, 1989, 1990 Northwestern University.  Permission is granted
  6.     to use this code in your own projects, provided you give credit to both
  7.     John Norstad and Northwestern University in your about box or document.
  8.     
  9.     This reusable module implements volume scanning.
  10.     
  11.     The caller supplies a pointer to a function to be called for each file
  12.     and folder on the volume.  In addition, the caller may supply three 
  13.     optional rectangles which are updated as the scan progresses, for the 
  14.     folder name currently being scanned, the file name currently being scanned, 
  15.     and a thermometer.
  16.     
  17.     The module handles both HFS and MFS volumes.
  18.     
  19.     The caller may also specify that only a single folder or file be 
  20.     scanned.
  21.     
  22.     See TN 68 for details on the scan algorithm.  The algorithm has been
  23.     modified to improve its behaviour when other users or tasks are creating
  24.     or deleting files or folders while the scan is in progress.  This is
  25.     especially important on server volume scans.
  26.     
  27.     All of the code is placed in its own segment named "scn".
  28. _____________________________________________________________________*/
  29.  
  30. #include    <string.h>
  31.  
  32. #include "scn.h"
  33. #include "utl.h"
  34. #include    "vol.h"
  35.  
  36. #define nil 0
  37.  
  38. /*______________________________________________________________________
  39.  
  40.     Global Variables.
  41. _____________________________________________________________________*/
  42.  
  43.  
  44. /* Global variables are used instead of local variables to minimize the size
  45.     of the stack frames for recursive calls to the ScanCat routine.
  46.     See TN 68. */
  47.  
  48.  
  49. static scn_DoFilePtr    DoFile;            /* ptr to func to be called to process
  50.                                                         each file */
  51. static scn_CheckCancelPtr        CheckCancel;
  52.                                                     /* ptr to func to be called to check 
  53.                                                         for cancel of scan */
  54. static long                RefCon;                /* value passed through to DoFile */
  55. static Rect                *FoldNameRect;        /* folder name rectangle, or nil */
  56. static Rect                *FileNameRect;        /* file name rectangle, or nil */
  57. static Rect                *ThermRect;            /* thermometer rectangle, or nil */
  58. static Boolean            MFS;                    /* true if mfs volume */
  59. static CInfoPBRec        PBlock;                /* PBGetCatInfo param block for hfs
  60.                                                         scanning. */
  61. static ParamBlockRec    MFSPBlock;            /* PBGetFInfo param block for mfs
  62.                                                         scanning */
  63. static Str255            FName;                /* current folder or file name */
  64. static Str255            OldFName;            /* old folder or file name */
  65. static long                TotFiles;            /* total num files on vol */
  66. static long                NumFiles;            /* num files scanned so far */
  67. static Rect                GrayRect;            /* therm subrect to be filled */
  68. static Boolean            Canceled;            /* true if scan canceled */
  69. static short            NameFont;            /* font num for fold and file names */
  70. static short            NameSize;            /* font size for fold and file names */
  71. static short            FontNum;                /* window's font number */
  72. static short            FontSize;            /* window's font size */
  73. static scn_FListElHandle    FolderList;    /* handle to head of folder list */
  74. static scn_FListElHandle    NextFolder;    /* handle to next el of folder list */
  75. static Boolean            DoingScan = false;    /* true while scan in progress */
  76. static Str255            FFName;                /* file name if file scan */
  77. static short            OldIndex;            /* index in directory of file */
  78.  
  79. /*______________________________________________________________________
  80.  
  81.     DrawName - Draw File or Folder Name.
  82.     
  83.     Entry:    drawRect = pointer to rectangle in which the name should
  84.                     be drawn, or nil if none.
  85.                 fName = pointer to file or folder name.
  86. _____________________________________________________________________*/
  87.  
  88.  
  89. static void DrawName (Rect *drawRect, Str255 *fName)
  90.  
  91. {
  92.     Rect            rect;            /* rectangle to be erased */
  93.     short            nameWidth;    /* width of name */
  94.     
  95.     if (drawRect) {
  96.         TextFont(NameFont); TextSize(NameSize);
  97.         rect = *drawRect;
  98.         nameWidth = StringWidth((StringPtr)fName);
  99.         TextBox((Ptr)fName+1, (long)((*fName)[0]), drawRect, teJustLeft);
  100.         if (nameWidth < (rect.right-rect.left)) {
  101.             rect.left += nameWidth;
  102.             EraseRect(&rect);
  103.         };
  104.         TextFont(FontNum); TextSize(FontSize);
  105.     };
  106. }
  107.  
  108. /*______________________________________________________________________
  109.  
  110.     DrawTherm - Update Thermometer.
  111. _____________________________________________________________________*/
  112.  
  113.  
  114. static void DrawTherm (void)
  115.  
  116. {
  117.     short            newRight;            /* new right coord of therm rect */
  118.     
  119.     if (ThermRect) {
  120.         NumFiles++;
  121.         newRight = ThermRect->left + NumFiles * 
  122.             (ThermRect->right - ThermRect->left - 1) / TotFiles;
  123.         if (newRight > ThermRect->right) newRight = ThermRect->right;
  124.         if (newRight > GrayRect.right) {
  125.             GrayRect.left = GrayRect.right-1;
  126.             GrayRect.right = newRight;
  127.             FillRect(&GrayRect, &gray);
  128.         };
  129.     };
  130. }
  131.  
  132. /*______________________________________________________________________
  133.  
  134.     ScanMFSVol - Scan MFS Volume.
  135. _____________________________________________________________________*/
  136.  
  137.  
  138. static void ScanMFSVol (void)
  139.  
  140. {
  141.     short            index;                /* cur index in volume */
  142.     
  143.     index = 1;
  144.     
  145.     while (true) {
  146.     
  147.         MFSPBlock.fileParam.ioFDirIndex = index;
  148.         if (PBGetFInfo(&MFSPBlock, false)) break;
  149.             
  150.         /*  Update the file name rectangle. */
  151.     
  152.         DrawName(FileNameRect, &FName);
  153.         
  154.         /* Update the thermometer. */
  155.         
  156.         DrawTherm();
  157.         
  158.         /* Copy fields from MFSPBlock to PBlock. */
  159.         
  160.         PBlock.hFileInfo.ioFRefNum = MFSPBlock.fileParam.ioFRefNum;
  161.         PBlock.hFileInfo.ioFlAttrib = MFSPBlock.fileParam.ioFlAttrib;
  162.         PBlock.hFileInfo.ioFlFndrInfo = MFSPBlock.fileParam.ioFlFndrInfo;
  163.         PBlock.hFileInfo.ioFlCrDat = MFSPBlock.fileParam.ioFlCrDat;
  164.         PBlock.hFileInfo.ioFlMdDat = MFSPBlock.fileParam.ioFlMdDat;
  165.         /* PBlock.hFileInfo.ioACUser = 0; */
  166.         *(&PBlock.hFileInfo.ioFlAttrib+1) = 0;
  167.                     
  168.         /* Call the user-specified function. */
  169.         
  170.         if (DoFile) {
  171.             if (Canceled = 
  172.                 (*DoFile)(&PBlock, FolderList, RefCon, true)) return;
  173.         };
  174.         
  175.         /* Check for user cancel. */
  176.         
  177.         if (CheckCancel)
  178.             if (Canceled = (*CheckCancel)()) return;
  179.         
  180.         /* The following code deals with the problem of other users or
  181.             tasks creating or deleting files while we are scanning, and also
  182.             the case where the DoFile routine deleted the file. */
  183.             
  184.         utl_CopyPString(&OldFName, &FName);
  185.         MFSPBlock.fileParam.ioFDirIndex = index;
  186.         if (!PBGetFInfo(&MFSPBlock, false)) {
  187.             if (OldFName[0] == FName[0] && !strncmp((char *)&OldFName[1], (char *)&FName[1],
  188.                 FName[0])) {
  189.                 index++;
  190.                 continue;
  191.             };
  192.         };
  193.         OldIndex = index;
  194.         index = 1;
  195.         while (true) {
  196.             MFSPBlock.fileParam.ioFDirIndex = index;
  197.             if (PBGetFInfo(&MFSPBlock, false)) {
  198.                 index = OldIndex;
  199.                 break;
  200.             };
  201.             if (OldFName[0] == FName[0] && !strncmp((char *)&OldFName[1], (char *)&FName[1],
  202.                 FName[0])) {
  203.                     index++;
  204.                     break;
  205.             };
  206.             index++;
  207.         };
  208.                 
  209.     };
  210.             
  211. }
  212.  
  213. /*______________________________________________________________________
  214.  
  215.     ScanCat - Scan Catalog.
  216.     
  217.     Entry:    dirID = directory id of catalog to scan.
  218. _____________________________________________________________________*/
  219.  
  220.  
  221. static void ScanCat (long dirID)
  222.  
  223. {
  224.     short            index;            /* cur index in directory */
  225.  
  226.     index = 1;
  227.     
  228.     while (true) {
  229.     
  230.         PBlock.hFileInfo.ioFDirIndex = index;
  231.         PBlock.hFileInfo.ioDirID = dirID;
  232.         /* PBlock.hFileInfo.ioACUser = 0; */
  233.         *(&PBlock.hFileInfo.ioFlAttrib+1) = 0;
  234.         if (PBGetCatInfo(&PBlock, false)) break;
  235.         if (((PBlock.hFileInfo.ioFlAttrib >> 4) & 1) == 1) {
  236.         
  237.             /* Folder.  Update the file and folder name rectangles. */
  238.         
  239.             if (FileNameRect) EraseRect(FileNameRect);
  240.             DrawName(FoldNameRect, &FName);
  241.             
  242.             /* Call the user-specified function. */
  243.             
  244.             if (DoFile) {
  245.                 if (Canceled = 
  246.                     (*DoFile)(&PBlock, FolderList, RefCon, false)) return;
  247.             };
  248.     
  249.             /* Check for user cancel. */
  250.             
  251.             if (CheckCancel)
  252.                 if (Canceled = (*CheckCancel)()) return;
  253.                 
  254.             /* Push the folder name onto the folder list. */
  255.             
  256.             NextFolder =  (scn_FListElHandle) NewHandle(sizeof(scn_FListEl));
  257.             (**NextFolder).next = FolderList;
  258.             utl_CopyPString((Str255 *)(**NextFolder).name, &FName);
  259.             /* (**NextFolder).accessRights = PBlock.hFileInfo.ioACUser; */
  260.             (**NextFolder).accessRights = *(&PBlock.hFileInfo.ioFlAttrib+1);
  261.             FolderList = NextFolder;
  262.             
  263.             /* Call ourselves recursively to scan the new folder. */
  264.             
  265.             ScanCat(PBlock.hFileInfo.ioDirID);
  266.             if (Canceled) return;
  267.             
  268.             /* Pop the folder name from the folder list. */
  269.             
  270.             utl_CopyPString(&FName, (Str255 *)(**FolderList).name);
  271.             NextFolder = (**FolderList).next;
  272.             DisposHandle((Handle)FolderList);
  273.             FolderList = NextFolder;
  274.             
  275.             /* Update the file and folder name rectangles. */
  276.             
  277.             if (FileNameRect) EraseRect(FileNameRect);
  278.             HLock((Handle)FolderList);
  279.             DrawName(FoldNameRect, (Str255 *)(**FolderList).name);
  280.             HUnlock((Handle)FolderList);
  281.             
  282.         } else {
  283.         
  284.             /* File. Update the file name rectangle. */
  285.         
  286.             DrawName(FileNameRect, &FName);
  287.             
  288.             /* Update the thermometer. */
  289.             
  290.             DrawTherm();
  291.             
  292.             /* Call the user-specified function. */
  293.             
  294.             if (DoFile) {
  295.                 if (Canceled = 
  296.                     (*DoFile)(&PBlock, FolderList, RefCon, false)) return;
  297.             };
  298.     
  299.             /* Check for user cancel. */
  300.             
  301.             if (CheckCancel)
  302.                 if (Canceled = (*CheckCancel)()) return;
  303.                 
  304.         };
  305.         
  306.         /* The following code deals with the problem of other users or
  307.             tasks creating or deleting files or folders while we are scanning.
  308.             This activity can invalidate our index in the current directory.
  309.             This problem is especially serious when scanning servers. The code
  310.             also covers the case where the DoFile routine deleted the file or
  311.             folder.
  312.             
  313.             The basic idea is to recall PBGetCatInfo to see if our position
  314.             in the directory has changed.  If it has changed we search the
  315.             directory to attempt to locate the new location. */
  316.         
  317.         utl_CopyPString(&OldFName, &FName);        /* save name of file or folder */
  318.         PBlock.hFileInfo.ioDirID = dirID;
  319.         PBlock.hFileInfo.ioFDirIndex = index;
  320.         if (!PBGetCatInfo(&PBlock, false)) {
  321.             if (OldFName[0] == FName[0] && !strncmp((char *)&OldFName[1], (char *)&FName[1], 
  322.                 FName[0])) {
  323.                 index++;
  324.                 continue;
  325.             };
  326.         };
  327.         OldIndex = index;
  328.         index = 1;
  329.         while (true) {
  330.             PBlock.hFileInfo.ioDirID = dirID;
  331.             PBlock.hFileInfo.ioFDirIndex = index;
  332.             if (PBGetCatInfo(&PBlock, false)) {
  333.                 index = OldIndex;
  334.                 break;
  335.             };
  336.             if (OldFName[0] == FName[0] && !strncmp((char *)&OldFName[1], (char *)&FName[1], FName[0])) {
  337.                 index++;
  338.                 break;
  339.             };
  340.             index++;
  341.         };
  342.     };
  343. }
  344.  
  345. /*______________________________________________________________________
  346.  
  347.     scn_Vol - Scan Volume.
  348.     
  349.     Entry:    volRefNum = vol ref number of vol to be scanned.
  350.                 dirID = directory id of directory to scan, or 0 if not a 
  351.                     directory scan.
  352.                 fName = name of file to scan.  Pass empty string if not a file 
  353.                     scan.
  354.                 fVRefNum = volume or working directory ref num of directory
  355.                     containing file, if file scan.
  356.                 doFile = pointer to function to be called for each file and
  357.                     folder, or nil if none.
  358.                 refCon = a longword passed through to doFile on each call.
  359.                 checkCancel = pointer to function to be called to check for
  360.                     a cancel of the scan in progress, or nil if none.
  361.                 foldNameRect = pointer to folder name rectangle, or nil if none.
  362.                 fileNameRect = pointer to file name rectangle, or nil if none.
  363.                 thermRect = pointer to thermometer rectangle, or nil if none.
  364.                 nameFont = font number for folder and file names.
  365.                 nameSize = font size for folder and file names.
  366.                 
  367.     Exit:        function result = true if scan was canceled.
  368.     
  369.     Don't forget to do a SetPort to the window before calling this routine.
  370.     
  371.     The folder and file names are drawn in font fontNum and size fontSize.
  372. _____________________________________________________________________*/
  373.  
  374.                 
  375. /*______________________________________________________________________
  376.  
  377.     The caller should supply a CheckCancel routine declared as follows:
  378.     
  379.     Boolean CheckCancel(void)
  380.     
  381.     The function should return true if the scan should be canceled, 
  382.     or false to continue the scan.  It's called once for every directory and 
  383.     file encountered in the scan.  
  384.     
  385.     The function should at least call SystemTask, then call GetNextEvent
  386.     to see if the user has typed command/period.  It can also check for a
  387.     click on a Cancel button or whatever else you desire.  It should also
  388.     check for update events, and call your window updating routine if one
  389.     occurs.  Do this even in a modal environment, since screen savers like
  390.     Moire generate update events when they deactivate, and you want your 
  391.     window to be redrawn.
  392.     
  393.     If your DoFile routine does alot of processing you should
  394.     also call CheckCancel periodically in DoFile.  If CheckCancel returns
  395.     true, DoFile should stop doing whatever its doing and also return true
  396.     as its function result.  This tells scn_Vol to terminate the scan.
  397.     
  398.     For example, in a modal environment (e.g., a modal dialog), the following
  399.     code would suffice.  It checks for command/period, and handles update
  400.     events:
  401.     
  402.     Boolean CheckCancel()
  403.     
  404.     {
  405.         EventRecord        myEvent;
  406.         
  407.         SystemTask();
  408.         
  409.         if (GetNextEvent(everyEvent ^ diskMask, &myEvent) {
  410.             if (myEvent.what == keyDown) 
  411.                 return (myEvent.modifiers & cmdKey) &&
  412.                     (myEvent.message & charCodeMask) == '.');
  413.             else if (myEvent.what == updateEvt) 
  414.                 DoUpdate();
  415.         };
  416.         return false;
  417.     }
  418.     
  419.     The CheckCancel routine in a non-modal environment must be more
  420.     complicated, since it must handle a larger range of possible events.
  421. _____________________________________________________________________*/
  422.  
  423.                 
  424. /*______________________________________________________________________
  425.  
  426.     The caller should supply a DoFile routine declared as follows:
  427.     
  428.     Boolean DoFile (CInfoPBRec *pBlock, scn_FListElHandle folderList, 
  429.         long refCon, Boolean mfs)
  430.     
  431.     This function, like CheckCancel, is called once for every directory 
  432.     and file encountered in the scan.    
  433.     
  434.     pBlock points to a PBGetCatInfo parameter block containing all sorts
  435.     of useful information about the file or folder.  See IM IV-125 and 155
  436.     for details.
  437.     
  438.     folderList is a handle to a linked list of all the folder names in 
  439.     the current path, in reverse order (lowest-level folder name to highest-level 
  440.     folder name).  The list is maintained as a push-down stack:  When a new folder 
  441.     is encountered it is added to the head of the list, and it is removed when the 
  442.     scan of that folder is complete.
  443.     
  444.     The first (lowest-level) folder name in the list is the name of the folder
  445.     that contains the current file or folder.
  446.     
  447.     The last (highest-level) folder name in the list depends on the type of scan:
  448.     a) Volume scans:  The root folder (volume name).
  449.     b) Folder scans:  The folder being scanned.
  450.     c) File scans: The folder containing the file being scanned.
  451.     
  452.     The folder list is terminated by a dummy element containing an empty name.
  453.     
  454.     Example: Suppose you are doing a volume scan of a volume named "MyVol",
  455.     and the current file being scanned is named "MyFile".  "MyFile" is located
  456.     inside folder "Folder1", which in turn is located inside folder "Folder2",
  457.     which is not located inside any other folders.  When your DoFile routine
  458.     is called for file "MyFile" the folder list contains four elements in the 
  459.     following order:  "Folder1", "Folder2", "MyVol", "".
  460.         
  461.     refCon is the longword parameter passed by the caller to the ScanVol
  462.     function.
  463.     
  464.     mfs is true if the volume is in mfs format.  In this case only the
  465.     following fields in the parameter block are filled in:
  466.     
  467.         ioNamePtr        pointer to file name.
  468.         ioVRefNum        volume reference number.
  469.         ioFRefNum        path reference number.
  470.         ioFlAttrib        file attributes.
  471.         ioFlFndrInfo    finder info.
  472.         ioACUser            access rights = 0 (all rights).
  473.         ioFlCrDat        creation date/time.
  474.         ioFlMdDat        last mod date/time.
  475.         
  476.     For HFS volumes the parameter block fields are left as set by the call
  477.     to PBGetCatInfo.
  478.     
  479.     The function should return true if the scan should be canceled, 
  480.     or false to continue the scan.
  481.     
  482.     The function may delete the file or folder.
  483. _____________________________________________________________________*/
  484.  
  485.  
  486. Boolean scn_Vol (short volRefNum, long dirID, 
  487.     Str255 *fName, short fVRefNum, scn_DoFilePtr doFile, 
  488.     long refCon, scn_CheckCancelPtr checkCancel, 
  489.     Rect *fldNameRect, Rect *fleNameRect, Rect *thrmRect, 
  490.     short nameFont, short nameSize)
  491.  
  492. {
  493.     CInfoPBRec        dBlock;                /* dir info param block */
  494.     HParamBlockRec    vBlock;                /* vol info param block */
  495.     WDPBRec            wdBlock;                /* wd info param block */
  496.     scn_FListElHandle    newEl;            /* handle to new folder list el */
  497.     Str255            dirName;                /* directory name */
  498.     char                accessRights;        /* directory access rights */
  499.     
  500.     /* Copy params to global variables. */
  501.     
  502.     DoFile = doFile;
  503.     RefCon = refCon;
  504.     CheckCancel = checkCancel;
  505.     FoldNameRect = fldNameRect;
  506.     FileNameRect = fleNameRect;
  507.     ThermRect = thrmRect;
  508.     NameFont = nameFont;
  509.     NameSize = nameSize;
  510.     *dirName = 0;
  511.     utl_CopyPString(&FFName, fName);
  512.     
  513.     /* Save the current window's font number and size in global variables. */
  514.     
  515.     FontNum = thePort->txFont;
  516.     FontSize = thePort->txSize;
  517.     
  518.     /* Initialize thermometer.  Disable the thermometer if the number
  519.         of files on the volume is 0, to prevent divide by 0 errors.  Also
  520.         disable it on folder and file scans. */
  521.     
  522.     if (ThermRect) {
  523.         if (dirID || (*fName)[0]) {
  524.             EraseRect(ThermRect);
  525.             ThermRect = nil;
  526.         } else {
  527.             if (TotFiles = utl_GetVolFilCnt(volRefNum)) {
  528.                 NumFiles = 0;
  529.                 GrayRect = *ThermRect;
  530.                 InsetRect(&GrayRect, 1, 1);
  531.                 GrayRect.right = GrayRect.left + 1;
  532.             } else {
  533.                 EraseRect(ThermRect);
  534.                 ThermRect = nil;
  535.             };
  536.         };
  537.     };
  538.     
  539.     /* Determine whether the volume is HFS or MFS. */
  540.     
  541.     MFS = utl_VolIsMFS(volRefNum);
  542.     
  543.     /* Initialize folder list */
  544.     
  545.     FolderList = (scn_FListElHandle) NewHandle(sizeof(scn_FListEl));
  546.     (**FolderList).next = nil;
  547.     *(**FolderList).name = 0;
  548.     newEl = (scn_FListElHandle)NewHandle(sizeof(scn_FListEl));
  549.     (**newEl).next = FolderList;
  550.     FolderList = newEl;
  551.     if (MFS) {
  552.         vBlock.volumeParam.ioNamePtr = dirName;
  553.         vBlock.volumeParam.ioVolIndex = 0;
  554.         vBlock.volumeParam.ioVRefNum = volRefNum;
  555.         (void) PBHGetVInfo(&vBlock, false);
  556.         accessRights = 0;
  557.     } else {
  558.         dBlock.dirInfo.ioNamePtr = dirName;
  559.         dBlock.dirInfo.ioVRefNum = volRefNum;
  560.         dBlock.dirInfo.ioFDirIndex = -1;
  561.         /* dBlock.dirInfo.ioACUser = 0; */
  562.         *(&dBlock.dirInfo.ioFlAttrib+1) = 0;
  563.         if (dirID) {
  564.             dBlock.dirInfo.ioDrDirID = dirID;
  565.         } else if ((*fName)[0]) {
  566.             wdBlock.ioNamePtr = dirName;
  567.             wdBlock.ioVRefNum = fVRefNum;
  568.             wdBlock.ioWDIndex = 0;
  569.             wdBlock.ioWDProcID = 0;
  570.             wdBlock.ioWDVRefNum = 0;
  571.             (void) PBGetWDInfo(&wdBlock, false);
  572.             dBlock.dirInfo.ioDrDirID = wdBlock.ioWDDirID;
  573.         } else {
  574.             dBlock.dirInfo.ioDrDirID = fsRtDirID;
  575.         };
  576.         (void) PBGetCatInfo(&dBlock, false);
  577.         /* accessRights = dBlock.dirInfo.ioACUser; */
  578.         accessRights = *(&dBlock.dirInfo.ioFlAttrib+1);
  579.     };
  580.     utl_CopyPString((Str255 *)(**FolderList).name, &dirName);
  581.     (**FolderList).accessRights = accessRights;
  582.     
  583.     /* Draw the folder name. */
  584.     
  585.     if (FoldNameRect) {
  586.         DrawName(FoldNameRect, &dirName);
  587.     };
  588.     
  589.     /* Draw the file name. */
  590.     
  591.     if (FileNameRect) EraseRect(FileNameRect);
  592.     if ((*fName)[0]) DrawName(FileNameRect, fName);
  593.     
  594.     /* Do the scan. */
  595.     
  596.     Canceled = false;
  597.     DoingScan = true;
  598.     
  599.     if ((*fName)[0]) {
  600.         
  601.         /* File scan. */
  602.         
  603.         if (MFS) {
  604.             MFSPBlock.fileParam.ioNamePtr = (StringPtr)fName;
  605.             MFSPBlock.fileParam.ioVRefNum = volRefNum;
  606.             MFSPBlock.fileParam.ioFVersNum = 0;
  607.             MFSPBlock.fileParam.ioFDirIndex = 0;
  608.             PBlock.hFileInfo.ioNamePtr = (StringPtr)fName;
  609.             PBlock.hFileInfo.ioVRefNum = volRefNum;
  610.             (void) PBGetFInfo(&MFSPBlock, false);
  611.             PBlock.hFileInfo.ioFRefNum = MFSPBlock.fileParam.ioFRefNum;
  612.             PBlock.hFileInfo.ioFlAttrib = MFSPBlock.fileParam.ioFlAttrib;
  613.             PBlock.hFileInfo.ioFlFndrInfo = MFSPBlock.fileParam.ioFlFndrInfo;
  614.             PBlock.hFileInfo.ioFlCrDat = MFSPBlock.fileParam.ioFlCrDat;
  615.             PBlock.hFileInfo.ioFlMdDat = MFSPBlock.fileParam.ioFlMdDat;
  616.             if (DoFile) Canceled = 
  617.                 (*DoFile)(&PBlock, FolderList, RefCon, true);
  618.         } else {
  619.             PBlock.hFileInfo.ioNamePtr = (StringPtr)fName;
  620.             PBlock.hFileInfo.ioVRefNum = volRefNum;
  621.             PBlock.hFileInfo.ioFDirIndex = 0;
  622.             PBlock.hFileInfo.ioDirID = wdBlock.ioWDDirID;
  623.             (void) PBGetCatInfo(&PBlock, false);
  624.             if (DoFile) Canceled =
  625.                 (*DoFile)(&PBlock, FolderList, RefCon, false);
  626.         };
  627.         
  628.     } else {
  629.     
  630.         /* Folder or volume scan. 
  631.             Initialize param block. */
  632.     
  633.         if (MFS) {
  634.             MFSPBlock.fileParam.ioNamePtr = FName;
  635.             MFSPBlock.fileParam.ioVRefNum = volRefNum;
  636.             MFSPBlock.fileParam.ioFVersNum = 0;
  637.         };
  638.         PBlock.hFileInfo.ioNamePtr = FName;
  639.         PBlock.hFileInfo.ioVRefNum = volRefNum;
  640.         
  641.         /*    Scan the directory. */
  642.         
  643.         if (MFS) {
  644.             ScanMFSVol();
  645.         } else {
  646.             ScanCat(dirID ? dirID : fsRtDirID);
  647.         };
  648.     };
  649.     
  650.     DoingScan = false;
  651.     
  652.     /* Clear the thermometer and folder and file names. */
  653.     
  654.     if (ThermRect) {
  655.         GrayRect = *ThermRect;
  656.         InsetRect(&GrayRect, 1, 1);
  657.         EraseRect(&GrayRect);
  658.     };
  659.     if (FoldNameRect) EraseRect(FoldNameRect);
  660.     if (FileNameRect) EraseRect(FileNameRect);
  661.     
  662.     /* Dispose of the folder list. */
  663.     
  664.     while (FolderList) {
  665.         NextFolder = (**FolderList).next;
  666.         DisposHandle((Handle)FolderList);
  667.         FolderList = NextFolder;
  668.     };
  669.     
  670.     return Canceled;
  671. }
  672.  
  673. /*______________________________________________________________________
  674.  
  675.     scn_Update - Process an Update Event.
  676.     
  677.     Entry:        thermRect = pointer to thermometer rectangle, or nil if none.
  678.     
  679.     This routine should be called whenever an update event occurs.
  680.     It redraws the volume, folder and file names and the thermometer if a 
  681.     scan is in progress.
  682. _____________________________________________________________________*/
  683.  
  684.  
  685. void scn_Update (Rect *thrmRect)
  686.  
  687. {
  688.     Rect            grayRect;        /* part of therm rect to be filled with
  689.                                             gray */
  690.  
  691.     if (!DoingScan) {
  692.         if (thrmRect) FrameRect(thrmRect);
  693.     } else {
  694.         if (ThermRect) {
  695.             FrameRect(ThermRect);
  696.             grayRect = GrayRect;
  697.             grayRect.left = ThermRect->left + 1;
  698.             FillRect(&grayRect, &gray);
  699.         };
  700.         if (FoldNameRect) {
  701.             EraseRect(FoldNameRect);
  702.             if (((PBlock.hFileInfo.ioFlAttrib >> 4) & 1) == 1) {
  703.                 DrawName(FoldNameRect, &FName);
  704.             } else {
  705.                 MoveHHi((Handle)FolderList);
  706.                 HLock((Handle)FolderList);
  707.                 DrawName(FoldNameRect, (Str255 *)(**FolderList).name);
  708.                 HUnlock((Handle)FolderList);
  709.             };
  710.         };
  711.         if (FileNameRect) EraseRect(FileNameRect);
  712.         DrawName(FileNameRect, (*FFName) ? &FFName : &FName);
  713.     };
  714. }