This is DynamicItemSpec.m in view mode; [Download] [Up]
/*
Copyright 1993 Jeremy Slade.
You are free to use all or any parts of the Locus project
however you wish, just give credit where credit is due.
The author (Jeremy Slade) shall not be held responsible
for any damages that result out of use or misuse of any
part of this project.
*/
/*
Project: Locus
File: DynamicItemSpec.m
Description: See DynamicItemSpec.h
Original Author: Jeremy Slade
Revision History:
Created
V.101 JGS Tue Feb 2 19:11:44 GMT-0700 1993
*/
#import "DynamicItemSpec.h"
#import "DynamicItems.h"
#import "Globals.h"
#import "Group.h"
#import "ItemCell.h"
#import <regex.h>
#import <sys/dir.h>
#import <sys/types.h>
@implementation DynamicItemSpec
// -------------------------------------------------------------------------
// Creating, initializing
// -------------------------------------------------------------------------
+ initialize
{
[self setVersion:DynamicItemSpec_VERSION];
return ( self );
}
- initExpr:(const char *)aString
{
[super init];
[self setExpression:aString];
enabled = YES;
return ( self );
}
- free
{
if ( expression ) NX_FREE ( expression );
if ( regexpr ) NX_FREE ( regexpr );
return ( [super free] );
}
// -------------------------------------------------------------------------
// Expression
// -------------------------------------------------------------------------
- setExpression:(const char *)aString
{
if ( expression ) NX_FREE ( expression );
if ( regexpr ) NX_FREE ( regexpr ); regexpr = NULL;
expression = aString ? NXCopyStringBuffer ( aString ) : NULL;
return ( self );
}
- (const char *)expression
{
return ( expression );
}
- (const char *)regexpression
/*
Translate the shell-style globbing expression into a regular expression so we can use it with recmp.
*/
{
char buf[MAXPATHLEN+1] = "";
char *in, *out;
if ( regexpr )
return ( regexpr );
// Translate the expression. Following is a brief summary of the
// translation:
// '.' is replaced with '\.'
// '?' is replaced with '.'
// '*' is replaced with '.*'
// '[a-z]' is left the same
// '[!a-z]' is replaced with '[^a-z]'
// Only include part of expression after last '/'
if ( in = rindex ( expression, '/' ) ) in++;
else in = expression;
out = buf;
*out++ = '^';
while ( *in ) {
switch ( *in ) {
case 0x2e: // Period -- '.'
*out++ = '\\'; *out++ = '.';
in++;
break;
case 0x3f: // Question Mark -- '?'
*out++ = '.';
in++;
break;
case 0x2a: // Asterisk -- '*'
*out++ = '.'; *out++ = '*';
in++;
break;
case 0x5b: // Left bracket -- '['
*out++ = '['; in++; // Output left bracket, move to next char
if ( *in == '!' ) *out++ = '^'; // Test for next char being '!'
else *out++ = *in;
in++;
while ( *in != ']' && *in != '\0' ) {
// Output until right bracket
*out++ = *in++;
}
*out++ = ']'; // Output the right bracket
in++;
break;
default: *out++ = *in++;
}
}
*out++ = '$';
*out = '\0'; // Make sure output is terminated
regexpr = NXCopyStringBuffer ( buf );
return ( regexpr );
}
- setEnabled:(BOOL)flag
{
enabled = flag;
return ( self );
}
- (BOOL)enabled
{
return ( enabled );
}
// -------------------------------------------------------------------------
// Scanning for Matching Items
// -------------------------------------------------------------------------
const char *match; // Used by matchItems(), set before each search
- addMatchingItemsToGroup:group
/*
Scan the directories for all items matching our expression and add them to the group.
*/
{
struct direct **namelist;
int i, count;
int matchItems ( struct direct *dp );
char path[MAXPATHLEN+1], *s;
id newItem;
if ( !expression || !enabled )
return ( self );
match = [self regexpression]; // assign our expression to the global
// If the expression specifies a full path, search that path
if ( expression[0] == '/' ) {
if ( s = rindex ( expression, '/' ) ) *s = '\0';
strcpy ( path, expression );
if ( s ) *s = '/';
} else
// expression has '/' in it, must be a relative path
if ( index ( expression, '/' ) ) {
if ( [group defaultPath] ) {
if ( s = rindex ( expression, '/' ) ) *s = '\0';
sprintf ( path, "%s/%s", [group defaultPath], expression );
if ( s ) *s = '/';
} else
return ( self ); // No default path specified,
// can't use relative expression
} else
// Just do search in the group's defaultPath
if ( [group defaultPath] ) {
strcpy ( path, [group defaultPath] );
} else
return ( self ); // Don't have a path to search
// Perform the search using scandir()...
count = scandir ( path, &namelist, matchItems, NULL );
// Add list of matched files to the group...
// set s to end of path string so we can just append the matching
// items to create the full path.
s = path + strlen(path) -1;
if ( *s != '/' ) {
strcat ( path, "/" );
s++;
}
s++;
for ( i=0; i<count; i++ ) {
strcpy ( s, namelist[i]->d_name );
newItem = [[ItemCell alloc] initPath:path];
[[newItem setDynamic:YES] setGroup:group];
[group addDynamicItem:newItem];
free ( namelist[i] );
}
if ( count != -1 ) free ( namelist );
return ( self );
}
int matchItems ( struct direct *dp )
/*
This is the matching function used by scandir(). Match the specified entry against the current regular expression defined by match.
*/
{
if ( !strcmp ( dp->d_name, "." ) || !strcmp ( dp->d_name, ".." ) )
return ( 0 );
else
return ( (!recmp ( (char *)match, dp->d_name )) ? 1 : 0 );
}
// -------------------------------------------------------------------------
// Archiving
// -------------------------------------------------------------------------
- awake
{
[super awake];
// Ignore archived regular expression -- generate it again
if ( regexpr ) {
NX_FREE ( regexpr );
regexpr = NULL;
}
return ( self );
}
- read:(NXTypedStream *)stream
{
int versionNumber;
[super read:stream];
versionNumber = NXTypedStreamClassVersion ( stream, [[self class] name] );
if ( versionNumber <= DynamicItemSpec_VERSION ) { // thru current version
NXReadTypes ( stream, "**s",
&expression,
®expr,
&enabled );
}
else { // Unrecongized version!
[self errMsg:"DynamicItemSpec: unrecognized version %i of archived object!\n", versionNumber];
}
return ( self );
}
- write:(NXTypedStream *)stream
{
[super write:stream];
NXWriteTypes ( stream, "**s",
&expression,
®expr,
&enabled );
return ( self );
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.