This is MOPathString.m in view mode; [Download] [Up]
// MOPathString.m
//
// by Mike Ferris
// Part of MOKit
// Copyright 1993, all rights reserved.
// ABOUT MOKit
// by Mike Ferris (mike@lorax.com)
//
// MOKit is a collection of useful and general objects. Permission is
// granted by the author to use MOKit in your own programs in any way
// you see fit. All other rights pertaining to the kit are reserved by the
// author including the right to sell these objects as objects, as part
// of a LIBRARY, or as SOURCE CODE. In plain English, I wish to retain
// rights to these objects as objects, but allow the use of the objects
// as pieces in a fully functional program. Permission is also granted to
// redistribute the source code of MOKit for FREE as long as this copyright
// notice is left intact and unchanged. NO WARRANTY is expressed or implied.
// The author will under no circumstances be held responsible for ANY
// consequences from the use of these objects. Since you don't have to pay
// for them, and full source is provided, I think this is perfectly fair.
#import "MOPathString.h"
#import <objc/objc-runtime.h>
#define CLASS_VERSION 0
#define CLASS_NAME "MOPathString"
#define DEFAULT_PATH_SEPARATOR '/'
#define DEFAULT_EXT_SEPARATOR '.'
@implementation MOPathString
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// =-=-=-=-=-=-=-=-=-=-=-=- Initializing the class -=-=-=-=-=-=-=-=-=-=-=-=
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+ initialize
// Set our version.
{
if (self == objc_lookUpClass(CLASS_NAME)) {
[self setVersion:CLASS_VERSION];
}
return self;
}
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// =-=-=-=-=-=-=-=-=-=-=-=-=- Initializing paths -=-=-=-=-=-=-=-=-=-=-=-=-=
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
- initPath:(const char *)path
// Identical to -initStringValue:path.
{
return [self initStringValue:path];
}
- initDirectory:(const char *)dir file:(const char *)file
// Identical to -initFromFormat:"%s/%s, dir, file. Use the
// DEFAULT_PATH_SEPARATOR because the instance variable won't be set
// up yet, and when it is it will be set to the default value anyway.
{
return [self initFromFormat:"%s%c%s", dir, DEFAULT_PATH_SEPARATOR, file];
}
- initStringValueNoCopy:(char *)s shouldFree:(BOOL)flag
// This is the designated initializer for this class.
{
[super initStringValueNoCopy:s shouldFree:flag];
pathSeparator = DEFAULT_PATH_SEPARATOR;
extSeparator = DEFAULT_EXT_SEPARATOR;
return self;
}
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-= Setting paths =-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
- setPath:(const char *)path
// Identical to -setStringValue:path
{
return [self setStringValue:path];
}
- setDirectory:(const char *)dir file:(const char *)file
// Identical to -setFromFormat:"%s/%s, dir, file.
{
return [self setFromFormat:"%s%c%s", dir, pathSeparator, file];
}
- setPathSeparator:(char)c
// Set the character used as the path component separator.
{
pathSeparator = c;
return self;
}
- (char)pathSeparator
// Return the character used as the path component separator.
{
return pathSeparator;
}
- setExtensionSeparator:(char)c
// Set the character used as the file extension separator.
{
extSeparator = c;
return self;
}
- (char)extensionSeparator
// Return the character used as the file extension separator.
{
return extSeparator;
}
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// =-=-=-=-=-=-=-=-=- Accessing important parts of a path -=-=-=-=-=-=-=-=-=
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
- (const char *)path
// Identical to -stringValue.
{
return [self stringValue];
}
- directory
// If there is an occurrence of pathSeparator in the string, this
// returns the substring to the left of the last occurrence of
// pathSeparator (not including the final pathSeparator).
// Otherwise it returns an empty string. Returned substring objects are
// the receiving object's class and must be freed by the caller.
{
int index = [self positionOf:pathSeparator nthOccurrence:-1];
if (index == -1) {
return [[[self class] allocFromZone:[self zone]] initStringValue:""];
}
if (index == 0) {
// it's a single pathSeparator, so we return an empty string.
return [[[self class] allocFromZone:[self zone]] initStringValue:""];
}
return [self substringFrom:0 to:index-1];
}
- file
// If there is an occurrence of pathSeparator in the string, this
// returns the substring to the right of the last occurrence of
// pathSeparator (not including the pathSeparator).
// Otherwise it returns a copy of the whole string. If the pathSeparator
// is the last character in the string, this returns an empty string.
// Returned substring objects are the receiving object's class and must be
// freed by the caller.
{
int index = [self positionOf:pathSeparator nthOccurrence:-1];
if (index == -1) {
return [[[self class] allocFromZone:[self zone]]
initStringValue:[self stringValue]];
}
if (index == [self length] - 1) {
// string ends in pathSeparator
return [[[self class] allocFromZone:[self zone]] initStringValue:""];
}
return [self substringFrom:index+1 to:[self length]-1];
}
- fileExtension
// If the file (as returned by -file) has an occurrence of extSeparator,
// this returns the substring to the right of the last occurrence of
// extSeparator (not including the separator). Otherwise it returns an
// empty string.
// Returned substring objects are the receiving object's class and must be
// freed by the caller.
{
id file = [self file];
id ret = nil;
int index = [file positionOf:extSeparator nthOccurrence:-1];
if (index == -1) {
ret = [[[self class] allocFromZone:[self zone]] initStringValue:""];
} else if (index == [self length]-1) {
// file ends in extSeparator.
ret = [[[self class] allocFromZone:[self zone]] initStringValue:""];
} else {
ret = [file substringFrom:index+1 to:[file length]-1];
}
[file free];
return ret;
}
- fileBasename
// If the file (as returned by -file) has an occurrence of extSeparator,
// this returns the substring to the left of the last occurrence of
// extSeparator (not including the separator). Otherwise it returns a
// copy of the file.
// Returned substring objects are the receiving object's class and must be
// freed by the caller.
{
id file = [self file];
id ret = nil;
int index = [file positionOf:extSeparator nthOccurrence:-1];
if (index == -1) {
ret = [[[self class] allocFromZone:[self zone]] initStringValue:""];
} else if (index == 0) {
// file begins with extSeparator.
ret = [[[self class] allocFromZone:[self zone]] initStringValue:""];
} else {
ret = [file substringFrom:0 to:index-1];
}
[file free];
return ret;
}
- (int)numberOfComponents
// Returns the number of components (that is the number of substrings
// defined by breaking the string at pathSeparators).
{
return [self countOccurrencesOf:pathSeparator] + 1;
}
- componentAt:(int)index
// Components are numbered from 0 to [self numberOfComponents]-1.
// Returned objects are the receiving object's class and must be freed
// by the caller.
{
int start, end;
id ret;
if ((index < 0) || (index > [self numberOfComponents]-1)) {
return nil;
}
start = [self positionOf:pathSeparator nthOccurrence:index];
if (start == -1) {
start = 0;
} else {
start++;
}
end = [self positionOf:pathSeparator nthOccurrence:index+1];
if (end == -1) {
end = [self length]-1;
} else {
end--;
}
ret = [self substringFrom:start to:end];
if (ret == nil) {
ret = [[[self class] allocFromZone:[self zone]] initStringValue:""];
}
return ret;
}
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// =-=-=-=-=-=-=-=-=-=-=-=-=-= Testing the file =-=-=-=-=-=-=-=-=-=-=-=-=-=
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
- (BOOL)isRelative
// Returns YES if the path is non-empty and does NOT begin with pathSeparator.
{
const char *strVal = [self stringValue];
if ((!strVal) || (!*strVal)) {
return NO;
}
return (*strVal != pathSeparator);
}
- (BOOL)isAbsolute
// Returns YES if the path is non-empty and DOES begin with pathSeparator.
{
const char *strVal = [self stringValue];
if ((!strVal) || (!*strVal)) {
return NO;
}
return (*strVal == pathSeparator);
}
- (BOOL)doesExistInFileSystem
// Returns YES if the a file exists at our path, and is visible to the user
// id of the process. A NO can mean any number of things, but a YES
// definitely indicates that the file is there and visible.
{
struct stat statBuff;
if (stat([self stringValue], &statBuff) == -1) {
return NO;
}
return YES;
}
- (BOOL)isDirectory
// Returns YES if the named file exists, and is visible to the user id of
// the process and it is a directory. A NO can mean any number of things,
// but a YES definitely indicates that the file is there and visible and
// a directory.
{
struct stat statBuff;
if (stat([self stringValue], &statBuff) == -1) {
return NO;
}
return ((statBuff.st_mode & S_IFDIR) == S_IFDIR);
}
- (BOOL)isPlainFile
// Returns YES if the named file exists, and is visible to the user id of
// the process and it is a plain file. A NO can mean any number of things,
// but a YES definitely indicates that the file is there and visible and
// a plain file.
{
struct stat statBuff;
if (stat([self stringValue], &statBuff) == -1) {
return NO;
}
return ((statBuff.st_mode & S_IFREG) == S_IFREG);
}
- (BOOL)isSymbolicLink
// Returns YES if the named file exists, and is visible to the user id of
// the process and it is a symlink. A NO can mean any number of things,
// but a YES definitely indicates that the file is there and visible and
// a symlink.
{
struct stat statBuff;
if (stat([self stringValue], &statBuff) == -1) {
return NO;
}
return ((statBuff.st_mode & S_IFLNK) == S_IFLNK);
}
- (BOOL)isCharacterSpecial
// Returns YES if the named file exists, and is visible to the user id of
// the process and it is a character special file. A NO can mean any
// number of things, but a YES definitely indicates that the file is
// there and visible and a character special file.
{
struct stat statBuff;
if (stat([self stringValue], &statBuff) == -1) {
return NO;
}
return ((statBuff.st_mode & S_IFCHR) == S_IFCHR);
}
- (BOOL)isBlockSpecial
// Returns YES if the named file exists, and is visible to the user id of
// the process and it is a block special file. A NO can mean any
// number of things, but a YES definitely indicates that the file is
// there and visible and a block special file.
{
struct stat statBuff;
if (stat([self stringValue], &statBuff) == -1) {
return NO;
}
return ((statBuff.st_mode & S_IFBLK) == S_IFBLK);
}
- (BOOL)isSocket
// Returns YES if the named file exists, and is visible to the user id of
// the process and it is a socket file. A NO can mean any
// number of things, but a YES definitely indicates that the file is
// there and visible and a socketspecial file.
{
struct stat statBuff;
if (stat([self stringValue], &statBuff) == -1) {
return NO;
}
return ((statBuff.st_mode & S_IFSOCK) == S_IFSOCK);
}
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// =-=-=-=-=-=-=-=-=-=-=-=-=-= Archiving methods =-=-=-=-=-=-=-=-=-=-=-=-=-=
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
- write:(NXTypedStream *)typedStream
// Archive the path to a typed stream.
{
[super write:typedStream];
NXWriteTypes(typedStream, "cc", &pathSeparator, &extSeparator);
return self;
}
- read:(NXTypedStream *)typedStream
// int NXTypedStreamClassVersion(NXTypedStream *typedStream,
// const char *className)
// can be used to handle multi version reading and writing.
{
int classVersion;
[super read:typedStream];
classVersion = NXTypedStreamClassVersion(typedStream, CLASS_NAME);
switch (classVersion) {
case 0: // First version.
NXReadTypes(typedStream, "cc", &pathSeparator, &extSeparator);
break;
default:
NXLogError("[%s read:] class version %d cannot read "
"instances archived with version %d",
CLASS_NAME, CLASS_VERSION, classVersion);
pathSeparator = DEFAULT_PATH_SEPARATOR;
extSeparator = DEFAULT_EXT_SEPARATOR;
break;
}
return self;
}
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// =-=-=-=-=-=-=-=-=-=-=-=-= NXTransport protocol =-=-=-=-=-=-=-=-=-=-=-=-=
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
- encodeUsing:(id <NXEncoding>)portal
// Encode the string for transmission across a distributed object connection.
{
if ([super respondsTo:@selector(encodeUsing:)]) {
[super encodeUsing:portal];
}
[portal encodeData:&pathSeparator ofType:"c"];
[portal encodeData:&extSeparator ofType:"c"];
return self;
}
- decodeUsing:(id <NXDecoding>)portal
// Decode the data sent over the distributed object connection into
// the receiving MOString.
{
if ([super respondsTo:@selector(decodeUsing:)]) {
[super decodeUsing:portal];
} else {
[self init];
}
[portal decodeData:&pathSeparator ofType:"c"];
[portal decodeData:&extSeparator ofType:"c"];
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.