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 "MOKit/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.