home *** CD-ROM | disk | FTP | other *** search
/ SuperHack / SuperHack CD.bin / CODING / CPP / METAKIT.ZIP / EXAMPLES / DISCAT / CATALOG.CPP next >
Encoding:
C/C++ Source or Header  |  1996-12-09  |  7.6 KB  |  224 lines

  1. //  catalog.cpp  -  recursive directory scanner sample code
  2. //
  3. //  This is a part of the MetaKit library.
  4. //  Copyright (c) 1996 Meta Four Software.
  5. //  All rights reserved.
  6. /////////////////////////////////////////////////////////////////////////////
  7. //
  8. //  The following two globally accesible routines are defined below:
  9. //                  
  10. //      c4_View fScanDirectories(const char* path_);
  11. //      c4_String fFullPath(c4_View& dirs_, int dirNum_);
  12. //      
  13. //  The fScanDirectories routine does all the work, and completely hides all
  14. //  Windows 16/32 specifics by returning a generalized catalog tree object.
  15. //  In contrast with normal C++ conventions, nearly all MetaKit objects are
  16. //  reference counted. This takes care of fully automatic cleanup after use.
  17. //  
  18. //  The structure of the object returned by fScanDirectories is as follows:
  19. //  
  20. //      Property        Type        Description
  21. //      ========        ====        ===========
  22. //          
  23. //      dirs            nested      Contains 1 record per directory
  24. //          parent      integer     Index of parent entry
  25. //          name        string      Name of this directory
  26. //          files       nested      Contains 1 record per file entry
  27. //              name    string      Name of this file
  28. //              size    string      File size
  29. //              date    integer     Modification date (DOS format 7+4+5 bits)
  30. //  
  31. //  The first directory entry (entry 0) is special: the parent is set to zero
  32. //  (points to itself), and the name is the base path name (see path_ arg).
  33. //              
  34. //  In C++ notation, a declaration for this object would be something like:
  35. //  
  36. //      struct
  37. //      {
  38. //          int parent;
  39. //          char* name;
  40. //  
  41. //          struct
  42. //          {
  43. //              char* name;
  44. //              long size;
  45. //              int date;
  46. //  
  47. //          } files [];                 // variable size, not allowed in C++
  48. //  
  49. //      } dirs [];
  50. //
  51. /////////////////////////////////////////////////////////////////////////////
  52.  
  53. #include "stdafx.h"
  54. #include "catalog.h"
  55.  
  56.     // forward declaration
  57. static void ScanSubDir(c4_View&, int, const c4_String&);
  58.  
  59. /////////////////////////////////////////////////////////////////////////////
  60. // Property definitions
  61.  
  62.     c4_ViewProp     pFiles ("files");
  63.     c4_IntProp      pParent ("parent"),
  64.                     pSize ("size"),
  65.                     pDate ("date");
  66.     c4_StringProp   pName ("name");
  67.  
  68. /////////////////////////////////////////////////////////////////////////////
  69. // Scan a directory tree and return a corresponding structure for it
  70.  
  71. c4_View fScanDirectories(const char* path_)
  72. {
  73.         // Start with a view containing the root directory entry
  74.     c4_View dirs;
  75.     dirs.Add(pName [path_]);
  76.     
  77.         // This loop "automagically" handles the recursive traversal of all
  78.         // subdirectories. The trick is that each scan may add new entries
  79.         // at the end, causing this loop to continue (GetSize() changes!).
  80.         
  81.     for (int i = 0; i < dirs.GetSize(); ++i)
  82.     {
  83.         c4_String path = fFullPath(dirs, i);
  84.  
  85.         TRACE("Scanning '%s' ...\n", (const char*) path);
  86.         ScanSubDir(dirs, i, path);
  87.     }
  88.     
  89.         // The returned object contains the entire directory tree.
  90.         // Everything is automatically destroyed when no longer referenced. 
  91.     return dirs;
  92. }
  93.  
  94. /////////////////////////////////////////////////////////////////////////////
  95. // Reconstruct the full path name from a subdirectory index in the tree
  96.  
  97. c4_String fFullPath(c4_View& dirs_, int dirNum_)
  98. {
  99.         // Prefix all parent dir names until the root level is reached
  100.     c4_String path;
  101.     for (;;)
  102.     {
  103.         path = pName (dirs_[dirNum_]) + "\\" + path;
  104.  
  105.         if (dirNum_ == 0)
  106.             return path; // this result always has a trailing backslash
  107.             
  108.         dirNum_ = (int) pParent (dirs_[dirNum_]);
  109.     }
  110. }
  111.  
  112. /////////////////////////////////////////////////////////////////////////////
  113. // There are two versions of ScanSubDir, one for Win32 and one for Win16
  114.  
  115. #ifdef _WIN32
  116.  
  117.         // Convert a Win32 filedate back to the good old DOS format
  118.     static WORD DosDate(FILETIME& ft)
  119.     {
  120.         SYSTEMTIME st;
  121.         
  122.         if (!FileTimeToSystemTime(&ft, &st))
  123.             return 0;
  124.             
  125.         return (WORD) (((st.wYear-1980) << 9) | (st.wMonth << 5) | st.wDay);
  126.     }
  127.     
  128.         // Scan subdirectory and update the directory structure
  129.     static void ScanSubDir(c4_View& dirs_, int dirNum_, const c4_String& path_)
  130.     {
  131.         WIN32_FIND_DATA fd;
  132.         
  133.         HANDLE h = FindFirstFile(path_ + "*", &fd);
  134.         if (h)
  135.         {
  136.                 //  Some notes on efficiency:
  137.                 //
  138.                 //  1)  It is probably faster to fill a view with data, and
  139.                 //      then store it in a persistent field, than to modify
  140.                 //      persistent structures in place. In this example, this
  141.                 //      is needed anyway, since we also sort all filenames.
  142.                 //
  143.                 //  2)  If possible, avoid constructing rows inside a loop.
  144.                 //      For that reason, both 'prop [const]' and 'row + row'
  145.                 //      are relatively inefficient.
  146.  
  147.         //  c4_View files = pFiles (dirs_[dirNum_]);
  148.             c4_View files;
  149.             c4_Row dir, file;
  150.  
  151.             do
  152.             {
  153.                 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  154.                 {
  155.                     if (fd.cFileName[0] == '.')
  156.                         continue;
  157.  
  158.                 //  dirs_.Add(pParent [dirNum_] + pName [fd.cFileName]);
  159.                     pParent (dir) = dirNum_;
  160.                     pName (dir) = fd.cFileName;
  161.                     dirs_.Add(dir);
  162.                 }            
  163.                 else
  164.                 {
  165.                 //  files.Add(pName [fd.cFileName] + pSize [fd.nFileSizeLow]
  166.                 //              + pDate [DosDate(fd.ftLastWriteTime)]);
  167.                     pName (file) = fd.cFileName;
  168.                     pSize (file) = fd.nFileSizeLow;
  169.                     pDate (file) = DosDate(fd.ftLastWriteTime);
  170.                     files.Add(file);
  171.                 }
  172.                 
  173.             } while (FindNextFile(h, &fd));
  174.             
  175.             pFiles (dirs_[dirNum_]) = files.SortOn(pName);
  176.             
  177.             FindClose(h);
  178.         }
  179.     }
  180.  
  181. #else
  182.  
  183.     #include <dos.h>
  184.     
  185.         // Scan subdirectory and update the directory structure
  186.     static void ScanSubDir(c4_View& dirs_, int dirNum_, const c4_String& path_)
  187.     {
  188.         _find_t fd;
  189.         
  190.         if (_dos_findfirst(path_ + "*.*", _A_SUBDIR, &fd) == 0)
  191.         {
  192.             c4_View files;
  193.             c4_Row dir, file;
  194.  
  195.             do
  196.             {
  197.                 if (fd.attrib & _A_SUBDIR)
  198.                 {
  199.                     if (fd.name[0] == '.')
  200.                         continue;
  201.  
  202.                     pParent (dir) = dirNum_;
  203.                     pName (dir) = fd.name;
  204.                     dirs_.Add(dir);
  205.                 }            
  206.                 else
  207.                 {
  208.                     pName (file) = fd.name;
  209.                     pSize (file) = fd.size;
  210.                     pDate (file) = fd.wr_date;
  211.                     files.Add(file);
  212.                 }
  213.                 
  214.             } while (_dos_findnext(&fd) == 0);
  215.             
  216.             pFiles (dirs_[dirNum_]) = files.SortOn(pName);
  217.         }
  218.     }
  219.  
  220. #endif
  221.     
  222. /////////////////////////////////////////////////////////////////////////////
  223. // $Id: catalog.cpp,v 1.2 1996/12/04 14:50:06 jcw Exp $
  224.