home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1995 August / NEBULA.mdf / Apps / Utilities / Desktop / Locus / Source / DynamicItemSpec.m < prev    next >
Encoding:
Text File  |  1993-05-25  |  6.4 KB  |  326 lines

  1.  
  2. /*
  3.     Copyright 1993  Jeremy Slade.
  4.  
  5.     You are free to use all or any parts of the Locus project
  6.     however you wish, just give credit where credit is due.
  7.     The author (Jeremy Slade) shall not be held responsible
  8.     for any damages that result out of use or misuse of any
  9.     part of this project.
  10.  
  11. */
  12.  
  13. /*
  14.     Project: Locus
  15.  
  16.     File: DynamicItemSpec.m
  17.  
  18.     Description: See DynamicItemSpec.h
  19.  
  20.     Original Author: Jeremy Slade
  21.  
  22.     Revision History:
  23.         Created
  24.             V.101    JGS Tue Feb  2 19:11:44 GMT-0700 1993
  25.  
  26. */
  27.  
  28.  
  29. #import "DynamicItemSpec.h"
  30.  
  31. #import "DynamicItems.h"
  32. #import "Globals.h"
  33. #import "Group.h"
  34. #import "ItemCell.h"
  35.  
  36. #import <regex.h>
  37. #import <sys/dir.h>
  38. #import <sys/types.h>
  39.  
  40.  
  41. @implementation DynamicItemSpec
  42.  
  43.  
  44. // -------------------------------------------------------------------------
  45. //   Creating, initializing
  46. // -------------------------------------------------------------------------
  47.  
  48.  
  49. + initialize
  50. {
  51.     [self setVersion:DynamicItemSpec_VERSION];
  52.     return ( self );
  53. }
  54.  
  55.  
  56.  
  57. - initExpr:(const char *)aString
  58. {
  59.     [super init];
  60.     
  61.     [self setExpression:aString];
  62.     enabled = YES;
  63.     
  64.     return ( self );
  65. }
  66.  
  67.  
  68.  
  69. - free
  70. {
  71.     if ( expression ) NX_FREE ( expression );
  72.     if ( regexpr ) NX_FREE ( regexpr );
  73.     return ( [super free] );
  74. }
  75.  
  76.  
  77.  
  78. // -------------------------------------------------------------------------
  79. //   Expression
  80. // -------------------------------------------------------------------------
  81.  
  82.  
  83. - setExpression:(const char *)aString
  84. {
  85.     if ( expression ) NX_FREE ( expression );
  86.     if ( regexpr ) NX_FREE ( regexpr ); regexpr = NULL;
  87.     
  88.     expression = aString ? NXCopyStringBuffer ( aString ) : NULL;
  89.     
  90.     return ( self );
  91. }
  92.  
  93.  
  94.  
  95. - (const char *)expression
  96. {
  97.     return ( expression );
  98. }
  99.  
  100.  
  101.  
  102. - (const char *)regexpression
  103. /*
  104.     Translate the shell-style globbing expression into a regular expression so we can use it with recmp.
  105. */
  106. {
  107.     char buf[MAXPATHLEN+1] = "";
  108.     char *in, *out;
  109.     
  110.     if ( regexpr )
  111.         return ( regexpr );
  112.         
  113.     // Translate the expression.  Following is a brief summary of the
  114.     // translation:
  115.     //     '.' is replaced with '\.'
  116.     //    '?' is replaced with '.'
  117.     //    '*' is replaced with '.*'
  118.     //    '[a-z]' is left the same
  119.     //    '[!a-z]' is replaced with '[^a-z]'
  120.     
  121.     // Only include part of expression after last '/'
  122.     if ( in = rindex ( expression, '/' ) ) in++;
  123.         else in = expression;
  124.         
  125.     out = buf;
  126.     *out++ = '^';
  127.     while ( *in ) {
  128.         switch ( *in ) {
  129.             case 0x2e:    // Period -- '.'
  130.                 *out++ = '\\'; *out++ = '.';
  131.                 in++;
  132.                 break;
  133.             case 0x3f:    // Question Mark -- '?'
  134.                 *out++ = '.';
  135.                 in++;
  136.                 break;
  137.             case 0x2a:    // Asterisk -- '*'
  138.                 *out++ = '.'; *out++ = '*';
  139.                 in++;
  140.                 break;
  141.             case 0x5b:    // Left bracket -- '['
  142.                 *out++ = '['; in++; // Output left bracket, move to next char
  143.                 if ( *in == '!' ) *out++ = '^'; // Test for next char being '!'
  144.                     else *out++ = *in;
  145.                 in++;
  146.                 while ( *in != ']' && *in != '\0' ) {
  147.                     // Output until right bracket
  148.                     *out++ = *in++;
  149.                 }
  150.                 *out++ = ']';    // Output the right bracket
  151.                 in++;
  152.                 break;
  153.             default:    *out++ = *in++;
  154.         }
  155.     }
  156.     *out++ = '$';
  157.     *out = '\0'; // Make sure output is terminated
  158.  
  159.     regexpr = NXCopyStringBuffer ( buf );
  160.     return ( regexpr );
  161. }
  162.  
  163.  
  164.  
  165. - setEnabled:(BOOL)flag
  166. {
  167.     enabled = flag;
  168.     return ( self );
  169. }
  170.  
  171.  
  172.  
  173. - (BOOL)enabled
  174. {
  175.     return ( enabled );
  176. }
  177.  
  178.  
  179.  
  180. // -------------------------------------------------------------------------
  181. //   Scanning for Matching Items
  182. // -------------------------------------------------------------------------
  183.  
  184.  
  185. const char *match;  // Used by matchItems(), set before each search
  186.  
  187. - addMatchingItemsToGroup:group
  188. /*
  189.     Scan the directories for all items matching our expression and add them to the group.
  190. */
  191. {
  192.     struct direct **namelist;
  193.     int i, count;
  194.     int matchItems ( struct direct *dp );
  195.     char path[MAXPATHLEN+1], *s;
  196.     id newItem;
  197.  
  198.     if ( !expression || !enabled )
  199.         return ( self );
  200.  
  201.     match = [self regexpression]; // assign our expression to the global
  202.     
  203.     // If the expression specifies a full path, search that path
  204.     if ( expression[0] == '/' ) {
  205.         if ( s = rindex ( expression, '/' ) ) *s = '\0';
  206.         strcpy ( path, expression );
  207.         if ( s ) *s = '/';
  208.     } else
  209.  
  210.     // expression has '/' in it, must be a relative path
  211.     if ( index ( expression, '/' ) ) {
  212.         if ( [group defaultPath] ) {
  213.             if ( s = rindex ( expression, '/' ) ) *s = '\0';
  214.             sprintf ( path, "%s/%s", [group defaultPath], expression );
  215.             if ( s ) *s = '/';
  216.         } else
  217.             return ( self ); // No default path specified,
  218.                              // can't use relative expression
  219.     } else
  220.  
  221.     // Just do search in the group's defaultPath
  222.     if ( [group defaultPath] ) {
  223.         strcpy ( path, [group defaultPath] );
  224.     } else
  225.         return ( self ); // Don't have a path to search
  226.  
  227.     // Perform the search using scandir()...
  228.     count = scandir ( path, &namelist, matchItems, NULL );
  229.     
  230.     // Add list of matched files to the group...
  231.     // set s to end of path string so we can just append the matching
  232.     // items to create the full path.
  233.     s = path + strlen(path) -1;
  234.     if ( *s != '/' ) {
  235.         strcat ( path, "/" );
  236.         s++;
  237.     }
  238.     s++;
  239.     for ( i=0; i<count; i++ ) {
  240.         strcpy ( s, namelist[i]->d_name );
  241.         newItem = [[ItemCell alloc] initPath:path];
  242.         [[newItem setDynamic:YES] setGroup:group];
  243.         [group addDynamicItem:newItem];
  244.         free ( namelist[i] );
  245.     }
  246.     if ( count != -1 ) free ( namelist );
  247.     
  248.     return ( self );
  249. }
  250.  
  251.  
  252.  
  253. int matchItems ( struct direct *dp )
  254. /*
  255.     This is the matching function used by scandir().  Match the specified entry against the current regular expression defined by match.
  256. */
  257. {
  258.     if ( !strcmp ( dp->d_name, "." ) || !strcmp ( dp->d_name, ".." ) )
  259.         return ( 0 );
  260.     else
  261.         return ( (!recmp ( (char *)match, dp->d_name )) ? 1 : 0 );
  262. }
  263.  
  264.  
  265.  
  266. // -------------------------------------------------------------------------
  267. //    Archiving
  268. // -------------------------------------------------------------------------
  269.  
  270.  
  271. - awake
  272. {
  273.     [super awake];
  274.     
  275.     // Ignore archived regular expression -- generate it again
  276.     if ( regexpr ) {
  277.         NX_FREE ( regexpr );
  278.         regexpr = NULL;
  279.     }
  280.     
  281.     return ( self );
  282. }
  283.  
  284.  
  285.  
  286. - read:(NXTypedStream *)stream
  287. {
  288.     int versionNumber;
  289.     
  290.     [super read:stream];
  291.     
  292.     versionNumber = NXTypedStreamClassVersion ( stream, [[self class] name] );
  293.     
  294.     if ( versionNumber <= DynamicItemSpec_VERSION ) { // thru current version
  295.         NXReadTypes ( stream, "**s",
  296.             &expression,
  297.             ®expr,
  298.             &enabled );
  299.     }
  300.     
  301.     else { // Unrecongized version!
  302.         [self errMsg:"DynamicItemSpec: unrecognized version %i of archived object!\n", versionNumber];
  303.     }
  304.     
  305.     return ( self );
  306. }
  307.  
  308.  
  309.  
  310. - write:(NXTypedStream *)stream
  311. {
  312.     [super write:stream];
  313.     
  314.     NXWriteTypes ( stream, "**s",
  315.         &expression,
  316.         ®expr,
  317.         &enabled );
  318.         
  319.     return ( self );
  320. }
  321.  
  322.  
  323.  
  324. @end
  325.  
  326.