Path handling updates ... basically tolerate windows paths.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@20935 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-Macdonald 2005-03-21 12:29:02 +00:00
parent 64a9d2b5eb
commit a339be4200
7 changed files with 969 additions and 400 deletions

View file

@ -1,3 +1,15 @@
2005-03-21 Richard Frith-Macdonald <rfm@gnu.org>
* Headers/Foundation/NSFileManager.h: Add path handling documentation.
* Headers/Foundation/NSString.h: Add path handling methods
documentation and new method to set global path handling mode.
* Source/NSUserDefaults.m: Update path handling mode when defaults
are read in.
* Source/NSString.m: Implement selectable path handling mode ...
gnustep/unix/windows. In the default gnustep mode we try to
handle paths in any format and just do the right thing.
Also updated handling of path extensions to match MacOSX behavior.
2005-03-18 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSPathUtilities.m: Use fprintf rather than NSLog to try to

View file

@ -1,7 +1,7 @@
/* -*-objc-*-
/**
NSFileManager.h
Copyright (C) 1997,1999 Free Software Foundation, Inc.
Copyright (C) 1997,1999-2005 Free Software Foundation, Inc.
Author: Mircea Oancea <mircea@jupiter.elcom.pub.ro>
Author: Ovidiu Predescu <ovidiu@net-community.com>
@ -22,6 +22,147 @@
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
<chapter>
<heading>File management</heading>
<section>
<heading>Path handling</heading>
<p>The rules for path handling depend on the value in the
<code>GSPathHandling</code> user default and, to some extent,
on the platform on which the program mis running.<br />
The understood values of GSPathHandling are <em>unix</em>
and <em>windows</em>. If GSPathHandling is any other value
(or has not been set), GNUstep interprets this as meaning
it should try to <em>do-the-right-thing</em><br />
In the default mode of operation the system is very tolerant
of paths and allows you to work with both unix and windows
style paths. The consequences of this are apparent in the
path handling methods of [NSString] rather than in [NSFileManager].
</p>
<subsect>
<heading>unix</heading>
<p>On all Unix platforms, Path components are separated by slashes
and file names may contain any character other than slash.<br />
The file names . and .. are special cases meaning current directory
and the parent of the current directory respectively.<br />
Multiple adjacent slash characters are treated as a single separator.
</p>
Here are various examples:
<deflist>
<term>/</term>
<desc>An absolute path to the root directory.
</desc>
<term>/etc/motd</term>
<desc>An absolute path to the file named <em>motd</em>
in the subdirectory <em>etc</em> of the root directory.
</desc>
<term>..</term>
<desc>A relative path to the parent of the current directory.
</desc>
<term>program.m</term>
<desc>A relative path to the file <em>program.m</em>
in the current directory.
</desc>
<term>Source/program.m</term>
<desc>A relative path to the file <em>program.m</em> in the
subdirectory <em>Source</em> of the current directory.
</desc>
<term>../GNUmakefile</term>
<desc>A relative path to the file <em>GNUmakefile</em>
in the directory above the current directory.
</desc>
</deflist>
</subsect>
<subsect>
<heading>windows</heading>
<p>On Microsoft Windows the native paths may be either UNC
or drive-relative, so GNUstep supports both.<br />
Either or both slash (/) and backslash (\) may be used as
separators for path components in either type of name.<br />
UNC paths follow the general form //host/share/path/file,
but must at least contain the host and share parts,
i.e. //host/share is a UNC path, but //host is <em>not</em><br />
Drive-relative names consist of an optional drive specifier
(consisting of a single letter followed by a single colon)
followed by an absolute or relative path.<br />
In both forms, the names . and .. are refer to the curtrent
directory and the parent directory as in unix paths.
</p>
Here are various examples:
<deflist>
<term>//host/share/file</term>
<desc>An absolute UNC path to a file called <em>file</em>
in the top directory of the export point share on host.
</desc>
<term>C:</term>
<desc>A relative path to the current directory on drive C.
</desc>
<term>C:program.m</term>
<desc>A relative path to the file <em>program.m</em> on drive C.
</desc>
<term>C:\program.m</term>
<desc>An absolute path to the file <em>program.m</em>
in the top level directory on drive C.
</desc>
<term>/Source\program.m</term>
<desc>A drive-relative path to <em>program.m</em> in the directory
<em>Source</em> on the current drive.
</desc>
<term>\\name</term>
<desc>A drive-relative path to <em>name</em> in the top level directory
on the current drive. The '\\' is treated as a single backslash as
this is not a UNC name (there must be both a host and a share part in
a UNC name).
</desc>
</deflist>
</subsect>
<subsect>
<heading>gnustep</heading>
<p>In the default mode, GNUstep handles both unix and windows paths so
it treats both slash (/) and backslash (\) as separators and understands
the windows UNC and drive relative path roots.<br />
However, it treats any path beginning with a slash (/) as an absolute
path <em>if running on a unix system</em>.
</p>
</subsect>
<subsect>
<heading>Portability</heading>
<p>Attempting to pass absolute paths between applications working on
different systems is fraught with difficulty ... just don't do it.<br />
Where paths need to be passed around (eg. in property lists or archives)
you should pass relative paths and use a standard mechanism to construct
an absolute path in the receiving application, for instance, appending
the relative path to the home directory of a user.
</p>
Even using relative paths you should take care ...
<list>
<item>Use only the slash (/) as a path separator, not backslash (\).
</item>
<item>Never use a backslash (\) in a file name.
</item>
<item>Avoid colons in file names.
</item>
<item>Use no more than three letters in a path extension.
</item>
</list>
Remember that, while GNUstep will manipulate both windows and unix
paths, any path actually used to reference a file or directory
must be valid on the local system.
</subsect>
<subsect>
<heading>Tilde substitution</heading>
<p>GNUstep handles substitution of tilde (~) as foillows:<br />
If a path is just ~ or begins ~/ then the value returned by
NSHomeDirectory() is substituted for the tilde.<br />
If a path is of the form ~name or begins wityh a string like ~name/
then name is used as the argument to NSHomeDirectoryForUser() and
the return value from that method (if non-nil) is used to replace
the tilde.
</p>
</subsect>
</section>
</chapter>
*/
#ifndef __NSFileManager_h_GNUSTEP_BASE_INCLUDE

View file

@ -173,7 +173,22 @@ enum {
*/
@interface NSString :NSObject <NSCoding, NSCopying, NSMutableCopying>
// Creating Temporary Strings
#ifndef NO_GNUSTEP
/**
* Sets the path handling mode for the NSString path manipulation methods.<br />
* <em>unix</em> mode treats paths as Unix/POSIX paths in which a slash (/)
* is the only path separator, and a single leading slash indicates an
* absolute path.<br />
* <em>windows</em> mode treats paths as windows drive-relative or UNC paths
* in which either slash (/) or backslash (\) may be used as path separators
* and the 'root' of a path may be of the form 'C:/' or '//host/share/'.<br />
* The mode selected if you provide any other argument to this
* method is the default <em>gnustep</em> mode, in which the system tries
* to <em>do-the-right-thing</em> and support both windows and unix style
* paths at the same time.
*/
+ (void) setPathHandling: (NSString*)mode;
#endif
+ (id) string;
+ (id) stringWithCharacters: (const unichar*)chars
length: (unsigned int)length;
@ -304,7 +319,16 @@ enum {
- (NSStringEncoding) fastestEncoding;
- (NSStringEncoding) smallestEncoding;
// Manipulating File System Paths
/**
* Attempts to complete this string as a path in the filesystem by finding
* a unique completion if one exists and returning it by reference in
* outputName (which must be a non-nil pointer), or if it finds a set of
* completions they are returned by reference in outputArray, if it is non-nil.
* filterTypes can be an array of strings specifying extensions to consider;
* files without these extensions will be ignored and will not constitute
* completions. Returns 0 if no match found, else a positive number that is
* only accurate if outputArray was non-nil.
*/
- (unsigned int) completePathIntoString: (NSString**)outputName
caseSensitive: (BOOL)flag
matchesIntoArray: (NSArray**)outputArray
@ -313,18 +337,188 @@ enum {
- (NSString*) localFromOpenStepPath;
- (NSString*) openStepPathFromLocal;
#endif
/**
* Converts the receiver to a C string path expressed in the character
* encoding appropriate for the local host file system. This string will be
* automatically freed soon after it is returned, so copy it if you need it
* for long.
*/
- (const char*) fileSystemRepresentation;
/**
* Converts the receiver to a C string path using the character encoding
* appropriate to the local file system. This string will be
* stored into buffer if it is shorter than size, otherwise NO is returned.
*/
- (BOOL) getFileSystemRepresentation: (char*)buffer
maxLength: (unsigned int)size;
/**
* Returns a string containing the last path component of the receiver.<br />
* The path component is the last non-empty substring delimited by the ends
* of the string, or by path separator characters.<br />
* If the receiver only contains a root part, this method returns it.<br />
* If there are no non-empty substrings, this returns an empty string.<br />
* NB. In a windows UNC path, the host and share specification is treated as
* a single path component, even though it contains separators.
* So a string of the form '//host/share' may be returned.<br />
* Other special cases are apply when the string is the root.
* <example>
* @"foo/bar" produces @"bar"
* @"foo/bar/" produces @"bar"
* @"/foo/bar" produces @"bar"
* @"/foo" produces @"foo"
* @"/" produces @"/" (root is a special case)
* @"" produces @""
* @"C:/" produces @"C:/" (root is a special case)
* @"C:" produces @"C:"
* @"//host/share/" produces @"//host/share/" (root is a special case)
* @"//host/share" produces @"//host/share"
* </example>
*/
- (NSString*) lastPathComponent;
/**
* Returns a new string containing the path extension of the receiver.<br />
* The path extension is a suffix on the last path component which starts
* with the extension separator (a '.') (for example .tiff is the
* pathExtension for /foo/bar.tiff).<br />
* Returns an empty string if no such extension exists.
* <example>
* @"a.b" produces @"b"
* @"a.b/" produces @"b"
* @"/path/a.ext" produces @"ext"
* @"/path/a." produces @""
* @"/path/.a" produces @"" (.a is not an extension to a file)
* @".a" produces @"" (.a is not an extension to a file)
* </example>
*/
- (NSString*) pathExtension;
/**
* Returns a string where a prefix of the current user's home directory is
* abbreviated by '~', or returns the receiver (or an immutable copy) if
* it was not found to have the home directory as a prefix.
*/
- (NSString*) stringByAbbreviatingWithTildeInPath;
/**
* Returns a new string with the path component given in aString
* appended to the receiver.<br />
* This removes trailing path separators from the receiver and the root
* part from aString and replaces them with a single slash as a path
* separator.<br />
* Also condenses any multiple separator sequences in the result into
* single path separators.
* <example>
* @"" with @"file" produces @"file"
* @"path" with @"file" produces @"path/file"
* @"/" with @"file" produces @"/file"
* @"/" with @"file" produces @"/file"
* @"/" with @"/file" produces @"/file"
* @"path with @"C:/file" produces @"path/file"
* </example>
*/
- (NSString*) stringByAppendingPathComponent: (NSString*)aString;
/**
* Returns a new string with the path extension given in aString
* appended to the receiver after an extensionSeparator ('.').<br />
* If the receiver has trailing path separator characters, they are
* stripped before the extension separator is added.<br />
* If the receiver contains no components after the root, the extension
* cannot be apppended (an extension can only be appended to a file name),
* so a copy of the unmodified receiver is returned.<br />
* An empty string may be used as an extension ... in which case the extension
* separator is appended.<br />
* This behavior mirrors that of the -stringByDeletingPathExtension method.
* <example>
* @"Mail" with @"app" produces @"Mail.app"
* @"Mail.app" with @"old" produces @"Mail.app.old"
* @"file" with @"" produces @"file."
* @"/" with @"app" produces @"/" (no file name to append to)
* @"" with @"app" produces @"" (no file name to append to)
* </example>
*/
- (NSString*) stringByAppendingPathExtension: (NSString*)aString;
/**
* Returns a new string with the last path component (including any final
* path separators) removed from the receiver.<br />
* A string without a path component other than the root is returned
* without alteration.<br />
* See -lastPathComponent for a definition of a path component.
* <example>
* @"hello/there" produces @"hello"
* @"hello" produces @""
* @"/hello" produces @"/"
* @"/" produces @"/"
* @"C:file" produces @"C:"
* @"C:" produces @"C:"
* @"C:/file" produces @"C:/"
* @"C:/" produces @"C:/"
* @"//host/share/file" produces @"//host/share/"
* @"//host/share/" produces @"/host/share/"
* @"//host/share" produces @"/host/share"
* <example>
*/
- (NSString*) stringByDeletingLastPathComponent;
/**
* Returns a new string with the path extension removed from the receiver.<br />
* Strips any trailing path separators before checking for the extension
* separator.<br />
* NB. This method does not consider a string which contains nothing
* between the root part and the extension separator ('.') to be a path
* extension. This mirrors the behavior of the -stringByAppendingPathExtension:
* method.
* <example>
* @"file.ext" produces @"file"
* @"/file.ext" produces @"/file"
* @"/file.ext/" produces @"/file" (trailing path separators are ignored)
* @"/file..ext" produces @"/file."
* @"/file." produces @"/file"
* @"/.ext" produces @"/.ext" (there is no file to strip from)
* @".ext" produces @".ext" (there is no file to strip from)
* </example>
*/
- (NSString*) stringByDeletingPathExtension;
/**
* Returns a string created by expanding the initial tilde ('~') and any
* following username to be the home directory of the current user or the
* named user.<br />
* Returns the receiver or an immutable copy if it was not possible to
* expand it.
*/
- (NSString*) stringByExpandingTildeInPath;
/**
* Replaces path string by one in which path components representing symbolic
* links have been replaced by their referents.<br />
* If links cannot be resolved, returns an unmodified coopy of the receiver.
*/
- (NSString*) stringByResolvingSymlinksInPath;
/**
* Returns a standardised form of the receiver, with unnecessary parts
* removed, tilde characters expanded, and symbolic links resolved
* where possible.<br />
* NB. Refers to the local filesystem to resolve symbolic links in
* absolute paths, and to expand tildes ... so this can't be used for
* general path manipulation.<br />
* If the string is an invalid path, the unmodified receiver is returned.<br />
* <p>
* Uses -stringByExpandingTildeInPath to expand tilde expressions.<br />
* Simplifies '//' and '/./' sequences and removes trailing '/' or '.'.<br />
* </p>
* <p>
* For absolute paths, uses -stringByResolvingSymlinksInPath to resolve
* any links, then gets rid of '/../' sequences and removes any '/private'
* prefix.
* </p>
*/
- (NSString*) stringByStandardizingPath;
@ -332,10 +526,45 @@ enum {
- (int) _baseLength;
#ifndef STRICT_OPENSTEP
/**
* Concatenates the path components in the array and returns the result.<br />
* This method does not remove empty path components, but does recognize an
* empty initial component as a special case meaning that the string
* returned will begin with a slash.
*/
+ (NSString*) pathWithComponents: (NSArray*)components;
/**
* Returns YES if the receiver represents an absolute path ...<br />
* Returns NO otherwise.<br />
* An absolute path in unix mode is one which begins
* with a slash or tilde.<br />
* In windows mode a drive specification (eg C:) or a UNC server and share
* (eg //host/share) followed by a slash or backslash, is an absolute path,
* as is any path beginning with a tilde.<br />
* In gnustep path handling mode, the rules are the same as for windows,
* except that a path whose root is a slash denotes an absolute path
* when running on unix and a relative path when running under windows.
*/
- (BOOL) isAbsolutePath;
/**
* Returns the path components of the receiver separated into an array.<br />
* If the receiver begins with a root sequence such as the path separator
* character (or a drive specification in windows) then that is used as the
* first element in the array.<br />
* Empty components are removed.<br />
* A trailing path separator (which was not part of the root) is added as the
* last element in the array.
*/
- (NSArray*) pathComponents;
/**
* Returns an array of strings made by appending the values in paths
* to the receiver.
*/
- (NSArray*) stringsByAppendingPaths: (NSArray*)paths;
+ (NSString*) localizedStringWithFormat: (NSString*) format, ...;
+ (id) stringWithString: (NSString*) aString;

View file

@ -254,7 +254,11 @@ static void debugWrite(GSHTTPURLHandle *handle, NSData *data)
- (void) dealloc
{
RELEASE(sock);
if (sock != nil)
{
[sock closeFile];
DESTROY(sock);
}
RELEASE(u);
RELEASE(url);
RELEASE(dat);

File diff suppressed because it is too large Load diff

View file

@ -95,6 +95,7 @@ static void updateCache(NSUserDefaults *self)
if (self == sharedDefaults)
{
NSArray *debug;
NSString *string;
/**
* If there is an array NSUserDefault called GNU-Debug,
@ -125,6 +126,20 @@ static void updateCache(NSUserDefaults *self)
= [self boolForKey: @"GSLogThread"];
flags[NSWriteOldStylePropertyLists]
= [self boolForKey: @"NSWriteOldStylePropertyLists"];
string = [self stringForKey: @"GSPathHandling"];
if (string != nil)
{
/*
* NB. path handling defaults to the 'gnustep' tolerant mode
* so that files can be handled to read in the defaults database.
* only once the database has been read in will the defaults
* system update the mode. This avoids a horrible recursion
* if we were to try to initialise the path handling mode from
* the defaults system.
*/
[NSString setPathHandling: string];
}
}
}

View file

@ -88,6 +88,8 @@ int main ()
struct objc_struct_layout layout;
unsigned i;
NSLog(@"%@", [@"//home//nicola" pathComponents]);
NSLog(@"Orig: %@", [NSUserDefaults userLanguages]);
[NSUserDefaults setUserLanguages: [NSArray arrayWithObject: @"Bletch"]];
NSLog(@"Set: %@", [NSUserDefaults userLanguages]);