2001-12-17 14:31:42 +00:00
|
|
|
|
/** Implementation of GNUSTEP string class
|
1998-10-15 05:03:16 +00:00
|
|
|
|
Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
|
2002-04-29 12:20:08 +00:00
|
|
|
|
|
1996-04-17 20:17:45 +00:00
|
|
|
|
Written by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
|
1995-03-12 19:54:14 +00:00
|
|
|
|
Date: January 1995
|
1997-05-03 18:05:21 +00:00
|
|
|
|
|
1998-01-08 15:25:59 +00:00
|
|
|
|
Unicode implementation by Stevo Crvenkovski <stevo@btinternet.com>
|
1997-05-03 18:05:21 +00:00
|
|
|
|
Date: February 1997
|
|
|
|
|
|
1998-10-15 05:03:16 +00:00
|
|
|
|
Optimisations by Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
2000-10-29 14:52:33 +00:00
|
|
|
|
Date: October 1998 - 2000
|
1998-10-15 05:03:16 +00:00
|
|
|
|
|
1996-05-12 00:56:10 +00:00
|
|
|
|
This file is part of the GNUstep Base Library.
|
1995-03-12 19:54:14 +00:00
|
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
2002-04-29 12:20:08 +00:00
|
|
|
|
|
1995-03-12 19:54:14 +00:00
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
Library General Public License for more details.
|
1997-05-03 18:05:21 +00:00
|
|
|
|
|
1995-03-12 19:54:14 +00:00
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
|
|
|
License along with this library; if not, write to the Free
|
2006-04-09 16:16:07 +00:00
|
|
|
|
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
|
Boston, MA 02111 USA.
|
2001-12-18 16:54:15 +00:00
|
|
|
|
|
|
|
|
|
<title>NSString class reference</title>
|
|
|
|
|
$Date$ $Revision$
|
2002-04-29 12:20:08 +00:00
|
|
|
|
*/
|
1995-03-12 19:54:14 +00:00
|
|
|
|
|
2002-04-29 12:20:08 +00:00
|
|
|
|
/* Caveats:
|
1995-04-03 01:35:42 +00:00
|
|
|
|
|
1997-05-03 18:05:21 +00:00
|
|
|
|
Some implementations will need to be changed.
|
2002-04-29 12:20:08 +00:00
|
|
|
|
Does not support all justification directives for `%@' in format strings
|
1996-09-02 13:20:20 +00:00
|
|
|
|
on non-GNU-libc systems.
|
1995-04-03 01:35:42 +00:00
|
|
|
|
*/
|
|
|
|
|
|
2001-03-20 02:13:19 +00:00
|
|
|
|
/*
|
|
|
|
|
Locales somewhat supported.
|
1997-05-03 18:05:21 +00:00
|
|
|
|
Limited choice of default encodings.
|
|
|
|
|
*/
|
|
|
|
|
|
2006-05-10 03:18:08 +00:00
|
|
|
|
/* Needed for visiblity of fwprintf prototype. */
|
|
|
|
|
#ifndef _GNU_SOURCE
|
|
|
|
|
#define _GNU_SOURCE
|
|
|
|
|
#endif
|
|
|
|
|
|
2003-06-07 01:24:41 +00:00
|
|
|
|
#include "config.h"
|
2000-06-14 04:03:56 +00:00
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
2003-07-31 23:49:32 +00:00
|
|
|
|
#include "GNUstepBase/preface.h"
|
2003-08-07 18:22:03 +00:00
|
|
|
|
#include "Foundation/NSAutoreleasePool.h"
|
2003-06-07 01:24:41 +00:00
|
|
|
|
#include "Foundation/NSString.h"
|
|
|
|
|
#include "Foundation/NSCalendarDate.h"
|
|
|
|
|
#include "Foundation/NSArray.h"
|
|
|
|
|
#include "Foundation/NSCharacterSet.h"
|
|
|
|
|
#include "Foundation/NSException.h"
|
|
|
|
|
#include "Foundation/NSValue.h"
|
|
|
|
|
#include "Foundation/NSDictionary.h"
|
|
|
|
|
#include "Foundation/NSFileManager.h"
|
|
|
|
|
#include "Foundation/NSPortCoder.h"
|
|
|
|
|
#include "Foundation/NSPathUtilities.h"
|
|
|
|
|
#include "Foundation/NSRange.h"
|
|
|
|
|
#include "Foundation/NSException.h"
|
|
|
|
|
#include "Foundation/NSData.h"
|
|
|
|
|
#include "Foundation/NSBundle.h"
|
|
|
|
|
#include "Foundation/NSURL.h"
|
|
|
|
|
#include "Foundation/NSMapTable.h"
|
|
|
|
|
#include "Foundation/NSLock.h"
|
|
|
|
|
#include "Foundation/NSUserDefaults.h"
|
|
|
|
|
#include "Foundation/NSDebug.h"
|
2004-01-28 23:13:55 +00:00
|
|
|
|
// For private method _decodePropertyListForKey:
|
|
|
|
|
#include "Foundation/NSKeyedArchiver.h"
|
2003-07-31 23:49:32 +00:00
|
|
|
|
#include "GNUstepBase/GSMime.h"
|
2004-05-14 10:52:30 +00:00
|
|
|
|
#include "GSPrivate.h"
|
2003-07-31 23:49:32 +00:00
|
|
|
|
#include "GSFormat.h"
|
1995-04-03 01:35:42 +00:00
|
|
|
|
#include <limits.h>
|
1996-10-31 17:03:44 +00:00
|
|
|
|
#include <sys/stat.h>
|
2002-05-02 21:22:06 +00:00
|
|
|
|
#ifdef HAVE_UNISTD_H
|
1996-10-31 17:03:44 +00:00
|
|
|
|
#include <unistd.h>
|
2002-02-20 06:42:05 +00:00
|
|
|
|
#endif
|
1996-10-31 17:03:44 +00:00
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <stdio.h>
|
2006-02-13 03:36:19 +00:00
|
|
|
|
#include <wchar.h>
|
1996-10-31 17:03:44 +00:00
|
|
|
|
|
2003-07-31 23:49:32 +00:00
|
|
|
|
#include "GNUstepBase/Unicode.h"
|
1997-05-03 18:05:21 +00:00
|
|
|
|
|
2002-03-13 09:58:43 +00:00
|
|
|
|
#include "GSPrivate.h"
|
2001-11-10 17:31:39 +00:00
|
|
|
|
|
2003-07-08 08:39:45 +00:00
|
|
|
|
extern BOOL GSScanDouble(unichar*, unsigned, double*);
|
|
|
|
|
|
2000-10-23 06:18:03 +00:00
|
|
|
|
@class GSString;
|
2000-11-03 10:11:56 +00:00
|
|
|
|
@class GSMutableString;
|
|
|
|
|
@class GSPlaceholderString;
|
2005-07-08 11:48:37 +00:00
|
|
|
|
@interface GSPlaceholderString : NSObject // Help the compiler
|
|
|
|
|
@end
|
2001-01-08 16:45:36 +00:00
|
|
|
|
@class GSMutableArray;
|
2001-01-09 09:17:31 +00:00
|
|
|
|
@class GSMutableDictionary;
|
2005-07-08 11:48:37 +00:00
|
|
|
|
@class NSImmutableString;
|
|
|
|
|
@interface NSImmutableString : NSObject // Help the compiler
|
|
|
|
|
@end
|
|
|
|
|
@class GSImmutableString;
|
|
|
|
|
@interface GSImmutableString : NSObject // Help the compiler
|
|
|
|
|
@end
|
2000-10-23 11:44:34 +00:00
|
|
|
|
|
1998-10-09 04:24:56 +00:00
|
|
|
|
|
2000-08-07 22:00:31 +00:00
|
|
|
|
/*
|
2000-10-23 11:44:34 +00:00
|
|
|
|
* Cache classes and method implementations for speed.
|
2000-08-07 22:00:31 +00:00
|
|
|
|
*/
|
2000-10-23 11:44:34 +00:00
|
|
|
|
static Class NSDataClass;
|
2000-10-23 06:18:03 +00:00
|
|
|
|
static Class NSStringClass;
|
|
|
|
|
static Class NSMutableStringClass;
|
|
|
|
|
|
|
|
|
|
static Class GSStringClass;
|
2000-11-03 10:11:56 +00:00
|
|
|
|
static Class GSMutableStringClass;
|
|
|
|
|
static Class GSPlaceholderStringClass;
|
|
|
|
|
|
|
|
|
|
static GSPlaceholderString *defaultPlaceholderString;
|
|
|
|
|
static NSMapTable *placeholderMap;
|
|
|
|
|
static NSLock *placeholderLock;
|
1999-05-10 11:02:28 +00:00
|
|
|
|
|
2000-11-01 12:31:21 +00:00
|
|
|
|
static SEL cMemberSel = 0;
|
2000-10-23 11:44:34 +00:00
|
|
|
|
|
2004-08-26 13:43:34 +00:00
|
|
|
|
#define IMMUTABLE(S) AUTORELEASE([(S) copyWithZone: NSDefaultMallocZone()])
|
2001-04-26 23:54:01 +00:00
|
|
|
|
|
|
|
|
|
#define IS_BIT_SET(a,i) ((((a) & (1<<(i)))) > 0)
|
|
|
|
|
|
|
|
|
|
static unsigned const char *whitespaceBitmapRep = NULL;
|
|
|
|
|
#define GS_IS_WHITESPACE(X) IS_BIT_SET(whitespaceBitmapRep[(X)/8], (X) % 8)
|
|
|
|
|
|
2002-11-10 06:19:17 +00:00
|
|
|
|
static void setupWhitespace(void)
|
2000-10-23 11:44:34 +00:00
|
|
|
|
{
|
2001-04-26 23:54:01 +00:00
|
|
|
|
if (whitespaceBitmapRep == NULL)
|
2000-10-23 11:44:34 +00:00
|
|
|
|
{
|
2001-04-26 23:54:01 +00:00
|
|
|
|
NSCharacterSet *whitespace;
|
2001-04-28 13:57:23 +00:00
|
|
|
|
NSData *bitmap;
|
2001-04-26 23:54:01 +00:00
|
|
|
|
|
2001-04-28 13:57:23 +00:00
|
|
|
|
/*
|
2001-04-28 15:32:01 +00:00
|
|
|
|
We can not use whitespaceAndNewlineCharacterSet here as this would lead
|
|
|
|
|
to a recursion, as this also reads in a property list.
|
|
|
|
|
whitespace = [NSCharacterSet whitespaceAndNewlineCharacterSet];
|
|
|
|
|
*/
|
2001-04-26 23:54:01 +00:00
|
|
|
|
whitespace = [NSCharacterSet characterSetWithCharactersInString:
|
|
|
|
|
@" \t\r\n\f\b"];
|
2001-04-28 13:57:23 +00:00
|
|
|
|
|
|
|
|
|
bitmap = RETAIN([whitespace bitmapRepresentation]);
|
|
|
|
|
whitespaceBitmapRep = [bitmap bytes];
|
2000-10-23 11:44:34 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1999-05-20 09:20:46 +00:00
|
|
|
|
/*
|
|
|
|
|
* Include sequence handling code with instructions to generate search
|
|
|
|
|
* and compare functions for NSString objects.
|
|
|
|
|
*/
|
|
|
|
|
#define GSEQ_STRCOMP strCompNsNs
|
|
|
|
|
#define GSEQ_STRRANGE strRangeNsNs
|
|
|
|
|
#define GSEQ_O GSEQ_NS
|
|
|
|
|
#define GSEQ_S GSEQ_NS
|
2003-06-07 01:24:41 +00:00
|
|
|
|
#include "GSeq.h"
|
1997-05-03 18:05:21 +00:00
|
|
|
|
|
2005-03-21 12:29:02 +00:00
|
|
|
|
/*
|
|
|
|
|
* The path handling mode.
|
|
|
|
|
*/
|
|
|
|
|
static enum {
|
|
|
|
|
PH_DO_THE_RIGHT_THING,
|
|
|
|
|
PH_UNIX,
|
|
|
|
|
PH_WINDOWS
|
|
|
|
|
} pathHandling = PH_DO_THE_RIGHT_THING;
|
|
|
|
|
|
2006-04-09 16:16:07 +00:00
|
|
|
|
/**
|
|
|
|
|
* This function is intended to be called at startup (before anything else
|
|
|
|
|
* which needs to use paths, such as reading config files and user defaults)
|
|
|
|
|
* to allow a program to control the style of path handling required.<br />
|
|
|
|
|
* Almost all programs should avoid using this.<br />
|
|
|
|
|
* Changing the path handling mode is not thread-safe.<br />
|
|
|
|
|
* If mode is "windows" this sets path handling to be windows specific,<br />
|
|
|
|
|
* If mode is "unix" it sets path handling to be unix specific,<br />
|
|
|
|
|
* Any other none-null string sets do-the-right-thing mode.<br />
|
|
|
|
|
* The function returns a C String describing the old mode.
|
|
|
|
|
*/
|
|
|
|
|
const char*
|
|
|
|
|
GSPathHandling(const char *mode)
|
|
|
|
|
{
|
|
|
|
|
int old = pathHandling;
|
|
|
|
|
|
|
|
|
|
if (mode != 0)
|
|
|
|
|
{
|
|
|
|
|
if (strcasecmp(mode, "windows") == 0)
|
|
|
|
|
{
|
|
|
|
|
pathHandling = PH_WINDOWS;
|
|
|
|
|
}
|
|
|
|
|
else if (strcasecmp(mode, "unix") == 0)
|
|
|
|
|
{
|
|
|
|
|
pathHandling = PH_UNIX;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pathHandling = PH_DO_THE_RIGHT_THING;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
switch (old)
|
|
|
|
|
{
|
|
|
|
|
case PH_WINDOWS: return "windows";
|
|
|
|
|
case PH_UNIX: return "unix";
|
|
|
|
|
default: return "right";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define GSPathHandlingRight() \
|
|
|
|
|
((pathHandling == PH_DO_THE_RIGHT_THING) ? YES : NO)
|
|
|
|
|
#define GSPathHandlingUnix() \
|
|
|
|
|
((pathHandling == PH_UNIX) ? YES : NO)
|
|
|
|
|
#define GSPathHandlingWindows() \
|
|
|
|
|
((pathHandling == PH_WINDOWS) ? YES : NO)
|
2000-10-23 11:44:34 +00:00
|
|
|
|
|
1999-01-20 13:28:28 +00:00
|
|
|
|
/*
|
2002-04-29 12:20:08 +00:00
|
|
|
|
* The pathSeps character set is used for parsing paths ... it *must*
|
|
|
|
|
* contain the '/' character, which is the internal path separator,
|
|
|
|
|
* and *may* contain additiona system specific separators.
|
|
|
|
|
*
|
|
|
|
|
* We can't have a 'pathSeps' variable initialized in the +initialize
|
2005-03-21 12:29:02 +00:00
|
|
|
|
* method because that would cause recursion.
|
1999-01-20 13:28:28 +00:00
|
|
|
|
*/
|
|
|
|
|
static NSCharacterSet*
|
2002-11-10 06:19:17 +00:00
|
|
|
|
pathSeps(void)
|
1999-01-20 13:28:28 +00:00
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
static NSCharacterSet *wPathSeps = nil;
|
|
|
|
|
static NSCharacterSet *uPathSeps = nil;
|
2006-04-09 16:16:07 +00:00
|
|
|
|
static NSCharacterSet *rPathSeps = nil;
|
|
|
|
|
if (GSPathHandlingRight())
|
|
|
|
|
{
|
|
|
|
|
if (rPathSeps == nil)
|
|
|
|
|
{
|
|
|
|
|
[placeholderLock lock];
|
|
|
|
|
if (rPathSeps == nil)
|
|
|
|
|
{
|
|
|
|
|
rPathSeps
|
|
|
|
|
= [NSCharacterSet characterSetWithCharactersInString: @"/\\"];
|
|
|
|
|
IF_NO_GC(RETAIN(rPathSeps));
|
|
|
|
|
}
|
|
|
|
|
[placeholderLock unlock];
|
|
|
|
|
}
|
|
|
|
|
return rPathSeps;
|
|
|
|
|
}
|
2005-03-21 12:29:02 +00:00
|
|
|
|
if (GSPathHandlingUnix())
|
1999-01-20 13:28:28 +00:00
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
if (uPathSeps == nil)
|
|
|
|
|
{
|
2006-04-09 16:16:07 +00:00
|
|
|
|
[placeholderLock lock];
|
|
|
|
|
if (uPathSeps == nil)
|
|
|
|
|
{
|
|
|
|
|
uPathSeps
|
|
|
|
|
= [NSCharacterSet characterSetWithCharactersInString: @"/"];
|
|
|
|
|
IF_NO_GC(RETAIN(uPathSeps));
|
|
|
|
|
}
|
|
|
|
|
[placeholderLock unlock];
|
2005-03-21 12:29:02 +00:00
|
|
|
|
}
|
|
|
|
|
return uPathSeps;
|
|
|
|
|
}
|
2006-04-09 16:16:07 +00:00
|
|
|
|
if (GSPathHandlingWindows())
|
2005-03-21 12:29:02 +00:00
|
|
|
|
{
|
|
|
|
|
if (wPathSeps == nil)
|
|
|
|
|
{
|
2006-04-09 16:16:07 +00:00
|
|
|
|
[placeholderLock lock];
|
|
|
|
|
if (wPathSeps == nil)
|
|
|
|
|
{
|
|
|
|
|
wPathSeps
|
|
|
|
|
= [NSCharacterSet characterSetWithCharactersInString: @"\\"];
|
|
|
|
|
IF_NO_GC(RETAIN(wPathSeps));
|
|
|
|
|
}
|
|
|
|
|
[placeholderLock unlock];
|
2005-03-21 12:29:02 +00:00
|
|
|
|
}
|
|
|
|
|
return wPathSeps;
|
1999-01-20 13:28:28 +00:00
|
|
|
|
}
|
2006-04-09 16:16:07 +00:00
|
|
|
|
pathHandling = PH_DO_THE_RIGHT_THING;
|
|
|
|
|
return pathSeps();
|
1999-09-03 11:05:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-04-06 22:51:48 +00:00
|
|
|
|
inline static BOOL
|
1999-09-03 11:05:33 +00:00
|
|
|
|
pathSepMember(unichar c)
|
|
|
|
|
{
|
2001-04-06 22:51:48 +00:00
|
|
|
|
if (c == (unichar)'/')
|
|
|
|
|
{
|
2006-04-09 16:16:07 +00:00
|
|
|
|
if (GSPathHandlingWindows() == NO)
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
2001-04-06 22:51:48 +00:00
|
|
|
|
}
|
2006-04-09 16:16:07 +00:00
|
|
|
|
else if (c == (unichar)'\\')
|
2001-04-06 22:51:48 +00:00
|
|
|
|
{
|
2006-04-09 16:16:07 +00:00
|
|
|
|
if (GSPathHandlingUnix() == NO)
|
2005-03-21 12:29:02 +00:00
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
2001-04-06 22:51:48 +00:00
|
|
|
|
}
|
2005-03-21 12:29:02 +00:00
|
|
|
|
return NO;
|
1999-01-20 13:28:28 +00:00
|
|
|
|
}
|
1997-09-13 17:52:31 +00:00
|
|
|
|
|
2006-04-09 16:16:07 +00:00
|
|
|
|
/*
|
|
|
|
|
* For cross-platform portability we always use slash as the separator
|
|
|
|
|
* when building paths ... unless specific windows path handling is
|
|
|
|
|
* required.
|
|
|
|
|
*/
|
2006-01-26 02:49:59 +00:00
|
|
|
|
inline static unichar
|
|
|
|
|
pathSepChar()
|
|
|
|
|
{
|
2006-04-09 16:16:07 +00:00
|
|
|
|
if (GSPathHandlingWindows() == NO)
|
2006-01-26 02:49:59 +00:00
|
|
|
|
{
|
|
|
|
|
return '/';
|
|
|
|
|
}
|
|
|
|
|
return '\\';
|
|
|
|
|
}
|
|
|
|
|
|
2006-04-09 16:16:07 +00:00
|
|
|
|
/*
|
|
|
|
|
* For cross-platform portability we always use slash as the separator
|
|
|
|
|
* when building paths ... unless specific windows path handling is
|
|
|
|
|
* required.
|
|
|
|
|
*/
|
2006-01-26 02:49:59 +00:00
|
|
|
|
inline static NSString*
|
|
|
|
|
pathSepString()
|
|
|
|
|
{
|
2006-04-09 16:16:07 +00:00
|
|
|
|
if (GSPathHandlingWindows() == NO)
|
2006-01-26 02:49:59 +00:00
|
|
|
|
{
|
|
|
|
|
return @"/";
|
|
|
|
|
}
|
|
|
|
|
return @"\\";
|
|
|
|
|
}
|
|
|
|
|
|
2005-03-21 12:29:02 +00:00
|
|
|
|
/*
|
|
|
|
|
* Find end of 'root' sequence in a string. Characters before this
|
|
|
|
|
* point in the string cannot be split into path components/extensions.
|
|
|
|
|
* Possible roots are -
|
|
|
|
|
*
|
|
|
|
|
* '/' absolute root on unix
|
|
|
|
|
* '' if entire path is empty string
|
|
|
|
|
* 'C:/' absolute root for a drive on windows
|
|
|
|
|
* 'C:' if entire path is 'C:' or 'C:relativepath'
|
|
|
|
|
* '//host/share/' absolute root for a host and share on windows
|
|
|
|
|
* '//host/share' if entire path is '//host/share'
|
|
|
|
|
* '~/' home directory for user
|
|
|
|
|
* '~' if entire path is '~'
|
|
|
|
|
* '~username/' home directory for user
|
|
|
|
|
* '~username' if entire path is '~username'
|
|
|
|
|
*
|
|
|
|
|
* Most roots are terminated in '/' (or '\') unless the root is the entire
|
|
|
|
|
* path. The exception is for windows drive-relative paths, where the root
|
|
|
|
|
* may be a drive letter followed by a colon, but there may still be path
|
|
|
|
|
* components after the root with no path separator.
|
|
|
|
|
*
|
|
|
|
|
* The presence of any non-empty root indicates an absolute path except -
|
|
|
|
|
* 1. A windows drive-relative path is not absolute unless the root
|
|
|
|
|
* ends with a path separator, since the path part on the drive is relative.
|
|
|
|
|
* 2. On windows, a root consisting of a single path separator indicates
|
|
|
|
|
* a drive-relative path with no drive ... so the path is relative.
|
|
|
|
|
*/
|
2005-11-11 14:25:38 +00:00
|
|
|
|
static unsigned rootOf(NSString *s, unsigned l)
|
2005-03-21 12:29:02 +00:00
|
|
|
|
{
|
|
|
|
|
unsigned root = 0;
|
|
|
|
|
|
|
|
|
|
if (l > 0)
|
|
|
|
|
{
|
|
|
|
|
unichar c = [s characterAtIndex: 0];
|
|
|
|
|
|
|
|
|
|
if (c == '~')
|
|
|
|
|
{
|
|
|
|
|
NSRange range = NSMakeRange(1, l-1);
|
|
|
|
|
|
|
|
|
|
range = [s rangeOfCharacterFromSet: pathSeps()
|
|
|
|
|
options: NSLiteralSearch
|
|
|
|
|
range: range];
|
|
|
|
|
if (range.length == 0)
|
|
|
|
|
{
|
|
|
|
|
root = l; // ~ or ~name
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
root = NSMaxRange(range); // ~/... or ~name/...
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (pathSepMember(c))
|
|
|
|
|
{
|
|
|
|
|
root++;
|
|
|
|
|
}
|
|
|
|
|
if (GSPathHandlingUnix() == NO)
|
|
|
|
|
{
|
|
|
|
|
if (root == 0 && l > 1
|
|
|
|
|
&& ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
|
|
|
|
|
&& [s characterAtIndex: 1] == ':')
|
|
|
|
|
{
|
|
|
|
|
// Got a drive relative path ... see if it's absolute.
|
|
|
|
|
root = 2;
|
|
|
|
|
if (l > 2 && pathSepMember([s characterAtIndex: 2]))
|
|
|
|
|
{
|
|
|
|
|
root++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (root == 1
|
|
|
|
|
&& l > 4 && pathSepMember([s characterAtIndex: 1]))
|
|
|
|
|
{
|
|
|
|
|
NSRange range = NSMakeRange(2, l-2);
|
|
|
|
|
|
|
|
|
|
range = [s rangeOfCharacterFromSet: pathSeps()
|
|
|
|
|
options: NSLiteralSearch
|
|
|
|
|
range: range];
|
|
|
|
|
if (range.length > 0 && range.location > 2)
|
|
|
|
|
{
|
|
|
|
|
unsigned pos = NSMaxRange(range);
|
|
|
|
|
|
|
|
|
|
// Found end of UNC host perhaps ... look for share
|
|
|
|
|
if (pos < l)
|
|
|
|
|
{
|
|
|
|
|
range = NSMakeRange(pos, l - pos);
|
|
|
|
|
range = [s rangeOfCharacterFromSet: pathSeps()
|
|
|
|
|
options: NSLiteralSearch
|
|
|
|
|
range: range];
|
|
|
|
|
if (range.length > 0)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Found another slash ... but if it comes
|
|
|
|
|
* immediately after the last one this can't
|
|
|
|
|
* be a UNC path as it's '//host//' rather
|
|
|
|
|
* than '//host/share'
|
|
|
|
|
*/
|
|
|
|
|
if (range.location > pos)
|
|
|
|
|
{
|
|
|
|
|
root = NSMaxRange(range);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
root = l;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return root;
|
|
|
|
|
}
|
2001-04-06 22:51:48 +00:00
|
|
|
|
|
|
|
|
|
|
2001-03-27 17:30:07 +00:00
|
|
|
|
/* Convert a high-low surrogate pair into Unicode scalar code-point */
|
2006-01-26 02:49:59 +00:00
|
|
|
|
static inline uint32_t
|
2001-03-27 17:30:07 +00:00
|
|
|
|
surrogatePairValue(unichar high, unichar low)
|
|
|
|
|
{
|
2001-04-12 09:11:31 +00:00
|
|
|
|
return ((high - (unichar)0xD800) * (unichar)400)
|
|
|
|
|
+ ((low - (unichar)0xDC00) + (unichar)10000);
|
2001-03-27 17:30:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
1995-03-12 19:54:14 +00:00
|
|
|
|
|
|
|
|
|
@implementation NSString
|
2004-06-22 22:40:40 +00:00
|
|
|
|
// NSString itself is an abstract class which provides factory
|
|
|
|
|
// methods to generate objects of unspecified subclasses.
|
1995-04-03 01:35:42 +00:00
|
|
|
|
|
1998-01-08 15:25:59 +00:00
|
|
|
|
static NSStringEncoding _DefaultStringEncoding;
|
2002-03-16 09:54:50 +00:00
|
|
|
|
static BOOL _ByteEncodingOk;
|
2001-03-27 17:30:07 +00:00
|
|
|
|
static const unichar byteOrderMark = 0xFEFF;
|
|
|
|
|
static const unichar byteOrderMarkSwapped = 0xFFFE;
|
|
|
|
|
|
|
|
|
|
/* UTF-16 Surrogate Ranges */
|
|
|
|
|
static NSRange highSurrogateRange = {0xD800, 1024};
|
|
|
|
|
static NSRange lowSurrogateRange = {0xDC00, 1024};
|
|
|
|
|
|
1998-01-08 15:25:59 +00:00
|
|
|
|
|
2002-05-02 21:22:06 +00:00
|
|
|
|
#ifdef HAVE_REGISTER_PRINTF_FUNCTION
|
1996-01-23 23:41:02 +00:00
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <printf.h>
|
|
|
|
|
#include <stdarg.h>
|
1996-05-06 18:59:01 +00:00
|
|
|
|
|
2002-04-29 12:20:08 +00:00
|
|
|
|
/* <sattler@volker.cs.Uni-Magdeburg.DE>, with libc-5.3.9 thinks this
|
|
|
|
|
flag PRINTF_ATSIGN_VA_LIST should be 0, but for me, with libc-5.0.9,
|
1997-09-01 21:59:51 +00:00
|
|
|
|
it crashes. -mccallum
|
|
|
|
|
|
|
|
|
|
Apparently GNU libc 2.xx needs this to be 0 also, along with Linux
|
|
|
|
|
libc versions 5.2.xx and higher (including libc6, which is just GNU
|
|
|
|
|
libc). -chung */
|
1996-07-15 18:41:44 +00:00
|
|
|
|
#define PRINTF_ATSIGN_VA_LIST \
|
|
|
|
|
(defined(_LINUX_C_LIB_VERSION_MINOR) \
|
|
|
|
|
&& _LINUX_C_LIB_VERSION_MAJOR <= 5 \
|
|
|
|
|
&& _LINUX_C_LIB_VERSION_MINOR < 2)
|
1996-05-07 01:14:54 +00:00
|
|
|
|
|
|
|
|
|
#if ! PRINTF_ATSIGN_VA_LIST
|
1996-05-06 18:59:01 +00:00
|
|
|
|
static int
|
1997-09-01 21:59:51 +00:00
|
|
|
|
arginfo_func (const struct printf_info *info, size_t n, int *argtypes)
|
|
|
|
|
{
|
1996-05-06 18:59:01 +00:00
|
|
|
|
*argtypes = PA_POINTER;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
1996-07-15 18:41:44 +00:00
|
|
|
|
#endif /* !PRINTF_ATSIGN_VA_LIST */
|
1996-05-06 18:59:01 +00:00
|
|
|
|
|
|
|
|
|
static int
|
2002-04-29 12:20:08 +00:00
|
|
|
|
handle_printf_atsign (FILE *stream,
|
1996-01-23 23:41:02 +00:00
|
|
|
|
const struct printf_info *info,
|
1996-05-07 01:14:54 +00:00
|
|
|
|
#if PRINTF_ATSIGN_VA_LIST
|
|
|
|
|
va_list *ap_pointer)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
#elif defined(_LINUX_C_LIB_VERSION_MAJOR) \
|
|
|
|
|
&& _LINUX_C_LIB_VERSION_MAJOR < 6
|
1996-05-07 01:14:54 +00:00
|
|
|
|
const void **const args)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
#else /* GNU libc needs the following. */
|
|
|
|
|
const void *const *args)
|
1996-05-07 01:14:54 +00:00
|
|
|
|
#endif
|
1996-01-23 23:30:05 +00:00
|
|
|
|
{
|
1996-05-07 01:14:54 +00:00
|
|
|
|
#if ! PRINTF_ATSIGN_VA_LIST
|
1996-05-06 18:59:01 +00:00
|
|
|
|
const void *ptr = *args;
|
1996-05-07 01:14:54 +00:00
|
|
|
|
#endif
|
1996-01-23 23:30:05 +00:00
|
|
|
|
id string_object;
|
|
|
|
|
int len;
|
|
|
|
|
|
2002-04-29 12:20:08 +00:00
|
|
|
|
/* xxx This implementation may not pay pay attention to as much
|
1996-01-23 23:30:05 +00:00
|
|
|
|
of printf_info as it should. */
|
|
|
|
|
|
1996-05-07 01:14:54 +00:00
|
|
|
|
#if PRINTF_ATSIGN_VA_LIST
|
|
|
|
|
string_object = va_arg (*ap_pointer, id);
|
|
|
|
|
#else
|
1996-07-15 18:41:44 +00:00
|
|
|
|
string_object = *((id*) ptr);
|
1996-05-07 01:14:54 +00:00
|
|
|
|
#endif
|
2006-02-13 03:36:19 +00:00
|
|
|
|
string_object = [string_object description];
|
|
|
|
|
if (info->wide)
|
|
|
|
|
{
|
|
|
|
|
if (sizeof(wchar_t) == 4)
|
|
|
|
|
{
|
|
|
|
|
unsigned length = [string_object length];
|
|
|
|
|
wchar_t buf[length + 1];
|
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < length; i++)
|
|
|
|
|
{
|
|
|
|
|
buf[i] = [string_object characterAtIndex: i];
|
|
|
|
|
}
|
|
|
|
|
buf[i] = 0;
|
|
|
|
|
len = fwprintf(stream, L"%*ls",
|
|
|
|
|
(info->left ? - info->width : info->width), buf);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
len = fwprintf(stream, L"%*ls",
|
|
|
|
|
(info->left ? - info->width : info->width),
|
|
|
|
|
[string_object cStringUsingEncoding: NSUnicodeStringEncoding]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
len = fprintf(stream, "%*s",
|
|
|
|
|
(info->left ? - info->width : info->width),
|
|
|
|
|
[string_object lossyCString]);
|
|
|
|
|
}
|
1996-01-23 23:30:05 +00:00
|
|
|
|
return len;
|
|
|
|
|
}
|
|
|
|
|
#endif /* HAVE_REGISTER_PRINTF_FUNCTION */
|
|
|
|
|
|
1995-04-03 01:35:42 +00:00
|
|
|
|
+ (void) initialize
|
|
|
|
|
{
|
2001-04-26 16:19:12 +00:00
|
|
|
|
/*
|
|
|
|
|
* Flag required as we call this method explicitly from GSBuildStrings()
|
|
|
|
|
* to ensure that NSString is initialised properly.
|
|
|
|
|
*/
|
|
|
|
|
static BOOL beenHere = NO;
|
|
|
|
|
|
|
|
|
|
if (self == [NSString class] && beenHere == NO)
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
2001-04-26 16:19:12 +00:00
|
|
|
|
beenHere = YES;
|
2000-10-30 18:00:27 +00:00
|
|
|
|
cMemberSel = @selector(characterIsMember:);
|
2001-05-23 14:32:56 +00:00
|
|
|
|
caiSel = @selector(characterAtIndex:);
|
|
|
|
|
gcrSel = @selector(getCharacters:range:);
|
|
|
|
|
ranSel = @selector(rangeOfComposedCharacterSequenceAtIndex:);
|
|
|
|
|
|
1998-01-08 15:25:59 +00:00
|
|
|
|
_DefaultStringEncoding = GetDefEncoding();
|
2002-03-16 09:54:50 +00:00
|
|
|
|
_ByteEncodingOk = GSIsByteEncoding(_DefaultStringEncoding);
|
|
|
|
|
|
2000-10-23 06:18:03 +00:00
|
|
|
|
NSStringClass = self;
|
2000-10-30 18:00:27 +00:00
|
|
|
|
[self setVersion: 1];
|
2000-10-23 06:18:03 +00:00
|
|
|
|
NSMutableStringClass = [NSMutableString class];
|
2000-10-23 11:44:34 +00:00
|
|
|
|
NSDataClass = [NSData class];
|
2000-11-03 10:11:56 +00:00
|
|
|
|
GSPlaceholderStringClass = [GSPlaceholderString class];
|
2000-10-23 06:18:03 +00:00
|
|
|
|
GSStringClass = [GSString class];
|
2000-11-03 10:11:56 +00:00
|
|
|
|
GSMutableStringClass = [GSMutableString class];
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Set up infrastructure for placeholder strings.
|
|
|
|
|
*/
|
|
|
|
|
defaultPlaceholderString = (GSPlaceholderString*)
|
|
|
|
|
NSAllocateObject(GSPlaceholderStringClass, 0, NSDefaultMallocZone());
|
|
|
|
|
placeholderMap = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
|
|
|
|
|
NSNonRetainedObjectMapValueCallBacks, 0);
|
|
|
|
|
placeholderLock = [NSLock new];
|
1996-01-23 23:30:05 +00:00
|
|
|
|
|
2002-05-02 21:22:06 +00:00
|
|
|
|
#ifdef HAVE_REGISTER_PRINTF_FUNCTION
|
2002-04-29 12:20:08 +00:00
|
|
|
|
if (register_printf_function ('@',
|
|
|
|
|
handle_printf_atsign,
|
1996-05-07 01:14:54 +00:00
|
|
|
|
#if PRINTF_ATSIGN_VA_LIST
|
|
|
|
|
0))
|
|
|
|
|
#else
|
1997-09-01 21:59:51 +00:00
|
|
|
|
arginfo_func))
|
1996-05-07 01:14:54 +00:00
|
|
|
|
#endif
|
1996-03-26 19:35:47 +00:00
|
|
|
|
[NSException raise: NSGenericException
|
|
|
|
|
format: @"register printf handling of %%@ failed"];
|
1996-01-23 23:30:05 +00:00
|
|
|
|
#endif /* HAVE_REGISTER_PRINTF_FUNCTION */
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1999-11-26 19:43:43 +00:00
|
|
|
|
+ (id) allocWithZone: (NSZone*)z
|
1995-11-19 20:29:39 +00:00
|
|
|
|
{
|
2000-10-23 06:18:03 +00:00
|
|
|
|
if (self == NSStringClass)
|
2000-08-07 22:00:31 +00:00
|
|
|
|
{
|
2000-11-03 10:11:56 +00:00
|
|
|
|
/*
|
|
|
|
|
* For a constant string, we return a placeholder object that can
|
|
|
|
|
* be converted to a real object when its initialisation method
|
|
|
|
|
* is called.
|
|
|
|
|
*/
|
|
|
|
|
if (z == NSDefaultMallocZone() || z == 0)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* As a special case, we can return a placeholder for a string
|
|
|
|
|
* in the default malloc zone extremely efficiently.
|
|
|
|
|
*/
|
|
|
|
|
return defaultPlaceholderString;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
id obj;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* For anything other than the default zone, we need to
|
|
|
|
|
* locate the correct placeholder in the (lock protected)
|
|
|
|
|
* table of placeholders.
|
|
|
|
|
*/
|
|
|
|
|
[placeholderLock lock];
|
|
|
|
|
obj = (id)NSMapGet(placeholderMap, (void*)z);
|
|
|
|
|
if (obj == nil)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* There is no placeholder object for this zone, so we
|
|
|
|
|
* create a new one and use that.
|
|
|
|
|
*/
|
|
|
|
|
obj = (id)NSAllocateObject(GSPlaceholderStringClass, 0, z);
|
|
|
|
|
NSMapInsert(placeholderMap, (void*)z, (void*)obj);
|
|
|
|
|
}
|
|
|
|
|
[placeholderLock unlock];
|
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (GSObjCIsKindOf(self, GSStringClass) == YES)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"Called +allocWithZone: on private string class"];
|
|
|
|
|
return nil; /* NOT REACHED */
|
2000-08-07 22:00:31 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2000-11-03 10:11:56 +00:00
|
|
|
|
/*
|
|
|
|
|
* For user provided strings, we simply allocate an object of
|
|
|
|
|
* the given class.
|
|
|
|
|
*/
|
2000-08-07 22:00:31 +00:00
|
|
|
|
return NSAllocateObject (self, 0, z);
|
|
|
|
|
}
|
1995-11-19 20:29:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-10-02 13:29:54 +00:00
|
|
|
|
/**
|
2002-10-02 14:05:07 +00:00
|
|
|
|
* Return the class used to store constant strings (those ascii strings
|
|
|
|
|
* placed in the source code using the @"this is a string" syntax).<br />
|
|
|
|
|
* Use this method to obtain the constant string class rather than
|
|
|
|
|
* using the obsolete name <em>NXConstantString</em> in your code ...
|
|
|
|
|
* with more recent compiler versions the name of this class is variable
|
|
|
|
|
* (and will automatically be changed by GNUstep to avoid conflicts
|
|
|
|
|
* with the default implementation in the Objective-C runtime library).
|
2002-10-02 13:29:54 +00:00
|
|
|
|
*/
|
2001-06-06 15:18:28 +00:00
|
|
|
|
+ (Class) constantStringClass
|
|
|
|
|
{
|
2002-10-02 14:05:07 +00:00
|
|
|
|
return [NXConstantString class];
|
2001-06-06 15:18:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Create an empty string.
|
|
|
|
|
*/
|
1999-11-26 19:43:43 +00:00
|
|
|
|
+ (id) string
|
1997-05-03 17:05:57 +00:00
|
|
|
|
{
|
1999-06-03 10:59:25 +00:00
|
|
|
|
return AUTORELEASE([[self allocWithZone: NSDefaultMallocZone()] init]);
|
1997-05-03 17:05:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Create a copy of aString.
|
|
|
|
|
*/
|
1999-11-26 19:43:43 +00:00
|
|
|
|
+ (id) stringWithString: (NSString*)aString
|
1997-12-08 20:04:16 +00:00
|
|
|
|
{
|
2000-11-03 10:11:56 +00:00
|
|
|
|
NSString *obj;
|
|
|
|
|
|
|
|
|
|
obj = [self allocWithZone: NSDefaultMallocZone()];
|
|
|
|
|
obj = [obj initWithString: aString];
|
|
|
|
|
return AUTORELEASE(obj);
|
1997-12-08 20:04:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Create a string of unicode characters.
|
|
|
|
|
*/
|
1999-11-26 19:43:43 +00:00
|
|
|
|
+ (id) stringWithCharacters: (const unichar*)chars
|
2002-03-13 13:46:12 +00:00
|
|
|
|
length: (unsigned int)length
|
1997-05-03 18:05:21 +00:00
|
|
|
|
{
|
2000-10-29 14:52:33 +00:00
|
|
|
|
NSString *obj;
|
|
|
|
|
|
2000-11-03 10:11:56 +00:00
|
|
|
|
obj = [self allocWithZone: NSDefaultMallocZone()];
|
2000-10-29 14:52:33 +00:00
|
|
|
|
obj = [obj initWithCharacters: chars length: length];
|
|
|
|
|
return AUTORELEASE(obj);
|
1997-05-03 18:05:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Create a string based on the given C (char[]) string, which should be
|
|
|
|
|
* null-terminated and encoded in the default C string encoding. (Characters
|
|
|
|
|
* will be converted to unicode representation internally.)
|
|
|
|
|
*/
|
2005-05-08 07:08:28 +00:00
|
|
|
|
+ (id) stringWithCString: (const char*)byteString
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
2000-10-29 14:52:33 +00:00
|
|
|
|
NSString *obj;
|
2001-10-18 15:42:29 +00:00
|
|
|
|
unsigned length = byteString ? strlen(byteString) : 0;
|
2000-10-29 14:52:33 +00:00
|
|
|
|
|
2000-11-03 10:11:56 +00:00
|
|
|
|
obj = [self allocWithZone: NSDefaultMallocZone()];
|
2000-10-29 14:52:33 +00:00
|
|
|
|
obj = [obj initWithCString: byteString length: length];
|
|
|
|
|
return AUTORELEASE(obj);
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2005-05-08 07:08:28 +00:00
|
|
|
|
/**
|
|
|
|
|
* Create a string based on the given C (char[]) string, which should be
|
|
|
|
|
* null-terminated and encoded in the specified C string encoding.
|
|
|
|
|
* Characters may be converted to unicode representation internally.
|
|
|
|
|
*/
|
|
|
|
|
+ (id) stringWithCString: (const char*)byteString
|
|
|
|
|
encoding: (NSStringEncoding)encoding
|
|
|
|
|
{
|
|
|
|
|
NSString *obj;
|
|
|
|
|
|
|
|
|
|
obj = [self allocWithZone: NSDefaultMallocZone()];
|
|
|
|
|
obj = [obj initWithCString: byteString encoding: encoding];
|
|
|
|
|
return AUTORELEASE(obj);
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Create a string based on the given C (char[]) string, which may contain
|
|
|
|
|
* null bytes and should be encoded in the default C string encoding.
|
|
|
|
|
* (Characters will be converted to unicode representation internally.)
|
|
|
|
|
*/
|
1999-11-26 19:43:43 +00:00
|
|
|
|
+ (id) stringWithCString: (const char*)byteString
|
2002-03-13 13:46:12 +00:00
|
|
|
|
length: (unsigned int)length
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
2000-10-29 14:52:33 +00:00
|
|
|
|
NSString *obj;
|
|
|
|
|
|
2000-11-03 10:11:56 +00:00
|
|
|
|
obj = [self allocWithZone: NSDefaultMallocZone()];
|
2000-10-29 14:52:33 +00:00
|
|
|
|
obj = [obj initWithCString: byteString length: length];
|
|
|
|
|
return AUTORELEASE(obj);
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Create a string based on the given UTF-8 string, null-terminated.
|
|
|
|
|
*/
|
2000-09-30 04:54:43 +00:00
|
|
|
|
+ (id) stringWithUTF8String: (const char *)bytes
|
2000-09-12 23:09:50 +00:00
|
|
|
|
{
|
2000-11-03 10:11:56 +00:00
|
|
|
|
NSString *obj;
|
|
|
|
|
|
|
|
|
|
obj = [self allocWithZone: NSDefaultMallocZone()];
|
|
|
|
|
obj = [obj initWithUTF8String: bytes];
|
|
|
|
|
return AUTORELEASE(obj);
|
2000-09-12 23:09:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Load contents of file at path into a new string. Will interpret file as
|
|
|
|
|
* containing direct unicode if it begins with the unicode byte order mark,
|
|
|
|
|
* else converts to unicode using default C string encoding.
|
|
|
|
|
*/
|
1999-11-26 19:43:43 +00:00
|
|
|
|
+ (id) stringWithContentsOfFile: (NSString *)path
|
1997-03-03 20:07:35 +00:00
|
|
|
|
{
|
2000-11-03 10:11:56 +00:00
|
|
|
|
NSString *obj;
|
|
|
|
|
|
|
|
|
|
obj = [self allocWithZone: NSDefaultMallocZone()];
|
|
|
|
|
obj = [obj initWithContentsOfFile: path];
|
|
|
|
|
return AUTORELEASE(obj);
|
1997-03-03 20:07:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Load contents of given URL into a new string. Will interpret contents as
|
|
|
|
|
* containing direct unicode if it begins with the unicode byte order mark,
|
|
|
|
|
* else converts to unicode using default C string encoding.
|
|
|
|
|
*/
|
2000-09-12 23:09:50 +00:00
|
|
|
|
+ (id) stringWithContentsOfURL: (NSURL *)url
|
|
|
|
|
{
|
2000-11-03 10:11:56 +00:00
|
|
|
|
NSString *obj;
|
|
|
|
|
|
|
|
|
|
obj = [self allocWithZone: NSDefaultMallocZone()];
|
|
|
|
|
obj = [obj initWithContentsOfURL: url];
|
|
|
|
|
return AUTORELEASE(obj);
|
2000-09-12 23:09:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Creates a new string using C printf-style formatting. First argument should
|
|
|
|
|
* be a constant format string, like '<code>@"float val = %f"</code>', remaining
|
|
|
|
|
* arguments should be the variables to print the values of, comma-separated.
|
|
|
|
|
*/
|
1999-11-26 19:43:43 +00:00
|
|
|
|
+ (id) stringWithFormat: (NSString*)format,...
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
|
|
|
|
va_list ap;
|
|
|
|
|
id ret;
|
|
|
|
|
|
|
|
|
|
va_start(ap, format);
|
1999-05-06 14:42:26 +00:00
|
|
|
|
if (format == nil)
|
|
|
|
|
ret = nil;
|
|
|
|
|
else
|
1999-06-03 10:59:25 +00:00
|
|
|
|
ret = AUTORELEASE([[self allocWithZone: NSDefaultMallocZone()]
|
|
|
|
|
initWithFormat: format arguments: ap]);
|
1995-04-03 01:35:42 +00:00
|
|
|
|
va_end(ap);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-07 05:43:20 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* <p>In MacOS-X class clusters do not have designated initialisers,
|
|
|
|
|
* and there is a general rule that -init is treated as the designated
|
|
|
|
|
* initialiser of the class cluster, but that other intitialisers
|
2006-05-20 13:24:53 +00:00
|
|
|
|
* may not work as expected and would need to be individually overridden
|
2004-09-07 05:43:20 +00:00
|
|
|
|
* in any subclass.
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>GNUstep tries to make it easier to subclass a class cluster,
|
|
|
|
|
* by making class clusters follow the same convention as normal
|
|
|
|
|
* classes, so the designated initialiser is the <em>richest</em>
|
|
|
|
|
* initialiser. This means that all other initialisers call the
|
|
|
|
|
* documented designated initialiser (which calls -init only for
|
|
|
|
|
* MacOS-X compatibility), and anyone writing a subclass only needs
|
|
|
|
|
* to override that one initialiser in order to have all the other
|
|
|
|
|
* ones work.
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>For MacOS-X compatibility, you may also need to override various
|
|
|
|
|
* other initialisers. Exactly which ones, you will need to determine
|
|
|
|
|
* by trial on a MacOS-X system ... and may vary between releases of
|
|
|
|
|
* MacOS-X. So to be safe, on MacOS-X you probably need to re-implement
|
|
|
|
|
* <em>all</em> the class cluster initialisers you might use in conjunction
|
|
|
|
|
* with your subclass.
|
|
|
|
|
* </p>
|
2006-05-20 13:24:53 +00:00
|
|
|
|
* <p>NB. The GNUstep designated initialiser for the NSString class cluster
|
|
|
|
|
* has changed to -initWithBytesNoCopy:length:encoding:freeWhenDone:
|
|
|
|
|
* from -initWithCharactersNoCopy:length:freeWhenDone: and older code
|
|
|
|
|
* subclassing NSString will need to be updated.
|
|
|
|
|
* </p>
|
2004-09-07 05:43:20 +00:00
|
|
|
|
*/
|
|
|
|
|
- (id) init
|
|
|
|
|
{
|
|
|
|
|
self = [super init];
|
|
|
|
|
return self;
|
|
|
|
|
}
|
1995-04-03 01:35:42 +00:00
|
|
|
|
|
2004-01-30 07:17:30 +00:00
|
|
|
|
/**
|
|
|
|
|
* Initialises the receiver with a copy of the supplied length of bytes,
|
|
|
|
|
* using the specified encoding.<br />
|
|
|
|
|
* For NSUnicodeStringEncoding and NSUTF8String encoding, a Byte Order
|
|
|
|
|
* Marker (if present at the start of the data) is removed automatically.<br />
|
|
|
|
|
* If the data can not be interpreted using the encoding, the receiver
|
|
|
|
|
* is released and nil is returned.
|
|
|
|
|
*/
|
|
|
|
|
- (id) initWithBytes: (const void*)bytes
|
2004-03-28 11:13:36 +00:00
|
|
|
|
length: (unsigned int)length
|
2004-01-30 07:17:30 +00:00
|
|
|
|
encoding: (NSStringEncoding)encoding
|
|
|
|
|
{
|
|
|
|
|
if (length == 0)
|
|
|
|
|
{
|
2006-05-20 13:24:53 +00:00
|
|
|
|
return [self initWithBytesNoCopy: (void *)0
|
|
|
|
|
length: 0
|
|
|
|
|
encoding: encoding
|
|
|
|
|
freeWhenDone: NO];
|
2004-01-30 07:17:30 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2006-05-20 13:24:53 +00:00
|
|
|
|
void *buf = NSZoneMalloc(GSObjCZone(self), length);
|
2004-01-30 07:17:30 +00:00
|
|
|
|
|
2006-05-20 13:24:53 +00:00
|
|
|
|
memcpy(buf, bytes, length);
|
|
|
|
|
return [self initWithBytesNoCopy: buf
|
|
|
|
|
length: length
|
|
|
|
|
encoding: encoding
|
|
|
|
|
freeWhenDone: YES];
|
2004-01-30 07:17:30 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2006-05-20 13:24:53 +00:00
|
|
|
|
/** <init /> <override-subclass />
|
2004-01-30 07:17:30 +00:00
|
|
|
|
* Initialises the receiver with the supplied length of bytes, using the
|
|
|
|
|
* specified encoding.<br />
|
|
|
|
|
* For NSUnicodeStringEncoding and NSUTF8String encoding, a Byte Order
|
|
|
|
|
* Marker (if present at the start of the data) is removed automatically.<br />
|
|
|
|
|
* If the data is not in a format which can be used internally unmodified,
|
|
|
|
|
* it is copied, otherwise it is used as is. If the data is not copied
|
|
|
|
|
* the flag determines whether the string will free it when it is no longer
|
|
|
|
|
* needed.<br />
|
|
|
|
|
* If the data can not be interpreted using the encoding, the receiver
|
|
|
|
|
* is released and nil is returned.
|
2006-05-20 13:24:53 +00:00
|
|
|
|
* <p>Note, this is the most basic initialiser for strings.
|
|
|
|
|
* In the GNUstep implementation, your subclasses may override
|
|
|
|
|
* this initialiser in order to have all others function.</p>
|
2004-01-30 07:17:30 +00:00
|
|
|
|
*/
|
2006-05-20 13:24:53 +00:00
|
|
|
|
- (id) initWithBytesNoCopy: (void*)bytes
|
2004-03-28 11:13:36 +00:00
|
|
|
|
length: (unsigned int)length
|
2004-01-30 07:17:30 +00:00
|
|
|
|
encoding: (NSStringEncoding)encoding
|
|
|
|
|
freeWhenDone: (BOOL)flag
|
|
|
|
|
{
|
2006-05-20 13:24:53 +00:00
|
|
|
|
self = [self init];
|
2004-01-30 07:17:30 +00:00
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2006-05-20 13:24:53 +00:00
|
|
|
|
/**
|
2004-06-22 22:40:40 +00:00
|
|
|
|
* <p>Initialize with given unicode chars up to length, regardless of presence
|
|
|
|
|
* of null bytes. Does not copy the string. If flag, frees its storage when
|
|
|
|
|
* this instance is deallocated.</p>
|
2002-08-20 10:22:05 +00:00
|
|
|
|
*/
|
1997-05-03 18:05:21 +00:00
|
|
|
|
- (id) initWithCharactersNoCopy: (unichar*)chars
|
2002-03-13 13:46:12 +00:00
|
|
|
|
length: (unsigned int)length
|
1999-11-26 19:43:43 +00:00
|
|
|
|
freeWhenDone: (BOOL)flag
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
2006-05-20 13:24:53 +00:00
|
|
|
|
return [self initWithBytesNoCopy: chars
|
|
|
|
|
length: length * sizeof(unichar)
|
|
|
|
|
encoding: NSUnicodeStringEncoding
|
|
|
|
|
freeWhenDone: flag];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* <p>Initialize with given unicode chars up to length, regardless of presence
|
|
|
|
|
* of null bytes. Copies the string and frees copy when deallocated.</p>
|
|
|
|
|
*/
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (id) initWithCharacters: (const unichar*)chars
|
2002-03-13 13:46:12 +00:00
|
|
|
|
length: (unsigned int)length
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
2006-05-20 13:24:53 +00:00
|
|
|
|
return [self initWithBytes: chars
|
|
|
|
|
length: length * sizeof(unichar)
|
|
|
|
|
encoding: NSUnicodeStringEncoding];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* <p>Initialize with given C string byteString up to length, regardless of
|
|
|
|
|
* presence of null bytes. Characters converted to unicode based on the
|
|
|
|
|
* default C encoding. Does not copy the string. If flag, frees its storage
|
|
|
|
|
* when this instance is deallocated.</p>
|
|
|
|
|
*/
|
1997-05-03 18:05:21 +00:00
|
|
|
|
- (id) initWithCStringNoCopy: (char*)byteString
|
2002-03-13 13:46:12 +00:00
|
|
|
|
length: (unsigned int)length
|
2000-09-27 15:26:16 +00:00
|
|
|
|
freeWhenDone: (BOOL)flag
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
2006-05-20 13:24:53 +00:00
|
|
|
|
return [self initWithBytesNoCopy: byteString
|
|
|
|
|
length: length
|
|
|
|
|
encoding: _DefaultStringEncoding
|
|
|
|
|
freeWhenDone: flag];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2005-05-08 07:08:28 +00:00
|
|
|
|
/**
|
|
|
|
|
* <p>Initialize with given C string byteString up to first nul byte.
|
|
|
|
|
* Characters converted to unicode based on the specified C encoding.
|
|
|
|
|
* Copies the string.</p>
|
|
|
|
|
*/
|
|
|
|
|
- (id) initWithCString: (const char*)byteString
|
|
|
|
|
encoding: (NSStringEncoding)encoding
|
|
|
|
|
{
|
|
|
|
|
return [self initWithBytes: byteString
|
|
|
|
|
length: strlen(byteString)
|
|
|
|
|
encoding: encoding];
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* <p>Initialize with given C string byteString up to length, regardless of
|
|
|
|
|
* presence of null bytes. Characters converted to unicode based on the
|
|
|
|
|
* default C encoding. Copies the string.</p>
|
|
|
|
|
*/
|
2002-03-13 13:46:12 +00:00
|
|
|
|
- (id) initWithCString: (const char*)byteString length: (unsigned int)length
|
1997-05-03 18:05:21 +00:00
|
|
|
|
{
|
2006-05-20 13:24:53 +00:00
|
|
|
|
return [self initWithBytes: byteString
|
|
|
|
|
length: length
|
|
|
|
|
encoding: _DefaultStringEncoding];
|
1997-05-03 18:05:21 +00:00
|
|
|
|
}
|
1997-01-09 16:24:07 +00:00
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* <p>Initialize with given C string byteString, which should be
|
|
|
|
|
* null-terminated. Characters are converted to unicode based on the default
|
|
|
|
|
* C encoding. Copies the string.</p>
|
|
|
|
|
*/
|
1997-05-03 18:05:21 +00:00
|
|
|
|
- (id) initWithCString: (const char*)byteString
|
|
|
|
|
{
|
2006-05-20 13:24:53 +00:00
|
|
|
|
return [self initWithBytes: byteString
|
|
|
|
|
length: (byteString ? strlen(byteString) : 0)
|
|
|
|
|
encoding: _DefaultStringEncoding];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Initialize to be a copy of the given string.
|
|
|
|
|
*/
|
1997-05-03 18:05:21 +00:00
|
|
|
|
- (id) initWithString: (NSString*)string
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
1999-07-02 13:26:37 +00:00
|
|
|
|
unsigned length = [string length];
|
1998-10-15 05:03:16 +00:00
|
|
|
|
|
1999-07-02 13:26:37 +00:00
|
|
|
|
if (length > 0)
|
|
|
|
|
{
|
2000-10-31 16:17:33 +00:00
|
|
|
|
unichar *s = NSZoneMalloc(GSObjCZone(self), sizeof(unichar)*length);
|
2000-09-27 15:26:16 +00:00
|
|
|
|
|
2004-08-22 10:18:52 +00:00
|
|
|
|
[string getCharacters: s range: ((NSRange){0, length})];
|
2000-09-27 15:26:16 +00:00
|
|
|
|
self = [self initWithCharactersNoCopy: s
|
|
|
|
|
length: length
|
|
|
|
|
freeWhenDone: YES];
|
1999-07-02 13:26:37 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2003-03-10 12:57:43 +00:00
|
|
|
|
self = [self initWithCharactersNoCopy: (unichar*)0
|
2000-09-27 15:26:16 +00:00
|
|
|
|
length: 0
|
|
|
|
|
freeWhenDone: NO];
|
1999-07-02 13:26:37 +00:00
|
|
|
|
}
|
2000-09-27 15:26:16 +00:00
|
|
|
|
return self;
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Initialize based on given null-terminated UTF-8 string bytes.
|
|
|
|
|
*/
|
2000-09-30 04:54:43 +00:00
|
|
|
|
- (id) initWithUTF8String: (const char *)bytes
|
2000-09-12 23:09:50 +00:00
|
|
|
|
{
|
2006-05-20 13:24:53 +00:00
|
|
|
|
return [self initWithBytes: bytes
|
|
|
|
|
length: (bytes ? strlen(bytes) : 0)
|
|
|
|
|
encoding: NSUTF8StringEncoding];
|
2000-09-12 23:09:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
|
/**
|
|
|
|
|
* Invokes -initWithFormat:locale:arguments: with a nil locale.
|
|
|
|
|
*/
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (id) initWithFormat: (NSString*)format,...
|
|
|
|
|
{
|
|
|
|
|
va_list ap;
|
|
|
|
|
va_start(ap, format);
|
2000-07-07 19:19:26 +00:00
|
|
|
|
self = [self initWithFormat: format locale: nil arguments: ap];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
va_end(ap);
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
|
/**
|
|
|
|
|
* Invokes -initWithFormat:locale:arguments:
|
|
|
|
|
*/
|
2000-07-07 19:19:26 +00:00
|
|
|
|
- (id) initWithFormat: (NSString*)format
|
2001-11-12 13:01:09 +00:00
|
|
|
|
locale: (NSDictionary*)locale, ...
|
2000-07-07 19:19:26 +00:00
|
|
|
|
{
|
2001-11-12 13:01:09 +00:00
|
|
|
|
va_list ap;
|
|
|
|
|
va_start(ap, locale);
|
2001-07-07 04:45:38 +00:00
|
|
|
|
return [self initWithFormat: format locale: locale arguments: ap];
|
2001-11-12 13:01:09 +00:00
|
|
|
|
va_end(ap);
|
|
|
|
|
return self;
|
2000-07-07 19:19:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
|
/**
|
|
|
|
|
* Invokes -initWithFormat:locale:arguments: with a nil locale.
|
|
|
|
|
*/
|
2000-07-07 19:19:26 +00:00
|
|
|
|
- (id) initWithFormat: (NSString*)format
|
2002-06-09 07:31:58 +00:00
|
|
|
|
arguments: (va_list)argList
|
2000-07-07 19:19:26 +00:00
|
|
|
|
{
|
2002-06-09 07:31:58 +00:00
|
|
|
|
return [self initWithFormat: format locale: nil arguments: argList];
|
2000-07-07 19:19:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
|
/**
|
|
|
|
|
* Initialises the string using the specified format and locale
|
|
|
|
|
* to format the following arguments.
|
|
|
|
|
*/
|
2001-02-02 06:14:42 +00:00
|
|
|
|
- (id) initWithFormat: (NSString*)format
|
|
|
|
|
locale: (NSDictionary*)locale
|
2002-06-09 07:31:58 +00:00
|
|
|
|
arguments: (va_list)argList
|
2001-02-02 06:14:42 +00:00
|
|
|
|
{
|
2004-06-05 09:34:41 +00:00
|
|
|
|
extern void GSStrExternalize();
|
2004-05-14 10:52:30 +00:00
|
|
|
|
unsigned char buf[2048];
|
|
|
|
|
GSStr_t f;
|
|
|
|
|
unichar fbuf[1024];
|
|
|
|
|
unichar *fmt = fbuf;
|
2001-02-02 06:14:42 +00:00
|
|
|
|
size_t len;
|
|
|
|
|
|
2004-05-14 10:52:30 +00:00
|
|
|
|
/*
|
|
|
|
|
* First we provide an array of unichar characters containing the
|
|
|
|
|
* format string. For performance reasons we try to use an on-stack
|
|
|
|
|
* buffer if the format string is small enough ... it almost always
|
|
|
|
|
* will be.
|
|
|
|
|
*/
|
2001-02-02 06:14:42 +00:00
|
|
|
|
len = [format length];
|
2004-05-14 10:52:30 +00:00
|
|
|
|
if (len >= 1024)
|
|
|
|
|
{
|
|
|
|
|
fmt = objc_malloc((len+1)*sizeof(unichar));
|
|
|
|
|
}
|
2004-08-22 10:18:52 +00:00
|
|
|
|
[format getCharacters: fmt range: ((NSRange){0, len})];
|
2001-02-02 06:14:42 +00:00
|
|
|
|
fmt[len] = '\0';
|
2004-05-14 10:52:30 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Now set up 'f' as a GSMutableString object whose initial buffer is
|
|
|
|
|
* allocated on the stack. The GSFormat function can write into it.
|
|
|
|
|
*/
|
|
|
|
|
f.isa = GSMutableStringClass;
|
|
|
|
|
f._zone = NSDefaultMallocZone();
|
|
|
|
|
f._contents.c = buf;
|
|
|
|
|
f._capacity = sizeof(buf);
|
|
|
|
|
f._count = 0;
|
|
|
|
|
f._flags.wide = 0;
|
|
|
|
|
f._flags.free = 0;
|
2002-06-09 07:31:58 +00:00
|
|
|
|
GSFormat(&f, fmt, argList, locale);
|
2004-06-05 09:34:41 +00:00
|
|
|
|
GSStrExternalize(&f);
|
2004-05-14 10:52:30 +00:00
|
|
|
|
if (fmt != fbuf)
|
|
|
|
|
{
|
|
|
|
|
objc_free(fmt);
|
|
|
|
|
}
|
2001-02-02 06:14:42 +00:00
|
|
|
|
|
2004-05-14 10:52:30 +00:00
|
|
|
|
/*
|
|
|
|
|
* Don't use noCopy because f._contents.u may be memory on the stack,
|
|
|
|
|
* and even if it wasn't f._capacity may be greater than f._count so
|
|
|
|
|
* we could be wasting quite a bit of space. Better to accept a
|
|
|
|
|
* performance hit due to copying data (and allocating/deallocating
|
|
|
|
|
* the temporary buffer) for large strings. For most strings, the
|
|
|
|
|
* on-stack memory will have been used, so we will get better performance.
|
|
|
|
|
*/
|
|
|
|
|
if (f._flags.wide == 1)
|
|
|
|
|
{
|
|
|
|
|
self = [self initWithCharacters: f._contents.u length: f._count];
|
|
|
|
|
}
|
|
|
|
|
else
|
2000-03-24 00:25:42 +00:00
|
|
|
|
{
|
2005-07-08 11:48:37 +00:00
|
|
|
|
self = [self initWithCString: (char*)f._contents.c length: f._count];
|
2000-03-24 00:25:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-05-14 10:52:30 +00:00
|
|
|
|
/*
|
|
|
|
|
* If the string had to grow beyond the initial buffer size, we must
|
|
|
|
|
* release any allocated memory.
|
|
|
|
|
*/
|
|
|
|
|
if (f._flags.free == 1)
|
|
|
|
|
{
|
|
|
|
|
NSZoneFree(f._zone, f._contents.c);
|
|
|
|
|
}
|
1995-04-03 01:35:42 +00:00
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2002-10-04 09:32:48 +00:00
|
|
|
|
/**
|
|
|
|
|
* Initialises the receiver with the supplied data, using the
|
|
|
|
|
* specified encoding.<br />
|
|
|
|
|
* For NSUnicodeStringEncoding and NSUTF8String encoding, a Byte Order
|
|
|
|
|
* Marker (if present at the start of the data) is removed automatically.<br />
|
|
|
|
|
* If the data can not be interpreted using the encoding, the receiver
|
|
|
|
|
* is released and nil is returned.
|
|
|
|
|
*/
|
1997-05-03 18:05:21 +00:00
|
|
|
|
- (id) initWithData: (NSData*)data
|
1999-07-02 13:26:37 +00:00
|
|
|
|
encoding: (NSStringEncoding)encoding
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
2006-05-20 13:24:53 +00:00
|
|
|
|
return [self initWithBytes: [data bytes]
|
|
|
|
|
length: [data length]
|
|
|
|
|
encoding: encoding];
|
1997-05-03 18:05:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-10-04 09:08:09 +00:00
|
|
|
|
/**
|
2002-10-04 09:32:48 +00:00
|
|
|
|
* <p>Initialises the receiver with the contents of the file at path.
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>Invokes [NSData-initWithContentsOfFile:] to read the file, then
|
2002-10-04 09:08:09 +00:00
|
|
|
|
* examines the data to infer its encoding type, and converts the
|
2002-10-04 09:32:48 +00:00
|
|
|
|
* data to a string using -initWithData:encoding:
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>The encoding to use is determined as follows ... if the data begins
|
|
|
|
|
* with the 16-bit unicode Byte Order Marker, then it is assumed to be
|
|
|
|
|
* unicode data in the appropriate ordering and converted as such.<br />
|
|
|
|
|
* If it begins with a UTF8 representation of the BOM, the UTF8 encoding
|
|
|
|
|
* is used.<br />
|
|
|
|
|
* Otherwise, the default C String encoding is used.
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>Releases the receiver and returns nil if the file could not be read
|
2002-10-04 09:08:09 +00:00
|
|
|
|
* and converted to a string.
|
2002-10-04 09:32:48 +00:00
|
|
|
|
* </p>
|
2002-10-04 09:08:09 +00:00
|
|
|
|
*/
|
1997-05-03 18:05:21 +00:00
|
|
|
|
- (id) initWithContentsOfFile: (NSString*)path
|
1998-01-08 15:25:59 +00:00
|
|
|
|
{
|
2002-10-04 09:08:09 +00:00
|
|
|
|
NSStringEncoding enc = _DefaultStringEncoding;
|
|
|
|
|
NSData *d;
|
|
|
|
|
unsigned int len;
|
2003-10-18 06:10:41 +00:00
|
|
|
|
const unsigned char *data_bytes;
|
1997-05-03 18:05:21 +00:00
|
|
|
|
|
2002-10-04 09:08:09 +00:00
|
|
|
|
d = [[NSDataClass alloc] initWithContentsOfFile: path];
|
1999-07-02 13:26:37 +00:00
|
|
|
|
if (d == nil)
|
2002-10-04 09:08:09 +00:00
|
|
|
|
{
|
|
|
|
|
RELEASE(self);
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
len = [d length];
|
2001-03-20 03:42:41 +00:00
|
|
|
|
if (len == 0)
|
2002-10-04 09:08:09 +00:00
|
|
|
|
{
|
2002-10-04 09:32:48 +00:00
|
|
|
|
RELEASE(d);
|
|
|
|
|
RELEASE(self);
|
2002-10-04 09:08:09 +00:00
|
|
|
|
return @"";
|
|
|
|
|
}
|
2003-10-18 06:10:41 +00:00
|
|
|
|
data_bytes = [d bytes];
|
|
|
|
|
if ((data_bytes != NULL) && (len >= 2))
|
2001-03-20 03:42:41 +00:00
|
|
|
|
{
|
2003-10-18 06:10:41 +00:00
|
|
|
|
const unichar *data_ucs2chars = (const unichar *) data_bytes;
|
|
|
|
|
if ((data_ucs2chars[0] == byteOrderMark)
|
|
|
|
|
|| (data_ucs2chars[0] == byteOrderMarkSwapped))
|
2002-10-04 09:08:09 +00:00
|
|
|
|
{
|
|
|
|
|
/* somebody set up us the BOM! */
|
|
|
|
|
enc = NSUnicodeStringEncoding;
|
|
|
|
|
}
|
2003-10-18 06:10:41 +00:00
|
|
|
|
else if (len >= 3
|
|
|
|
|
&& data_bytes[0] == 0xEF
|
|
|
|
|
&& data_bytes[1] == 0xBB
|
|
|
|
|
&& data_bytes[2] == 0xBF)
|
2002-10-04 09:32:48 +00:00
|
|
|
|
{
|
|
|
|
|
enc = NSUTF8StringEncoding;
|
|
|
|
|
}
|
2001-03-20 03:42:41 +00:00
|
|
|
|
}
|
2002-10-04 09:08:09 +00:00
|
|
|
|
self = [self initWithData: d encoding: enc];
|
|
|
|
|
RELEASE(d);
|
|
|
|
|
if (self == nil)
|
2001-03-20 03:42:41 +00:00
|
|
|
|
{
|
2002-10-04 09:08:09 +00:00
|
|
|
|
NSWarnMLog(@"Contents of file '%@' are not string data", path);
|
2001-03-20 03:42:41 +00:00
|
|
|
|
}
|
2002-10-04 09:08:09 +00:00
|
|
|
|
return self;
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* <p>Initialises the receiver with the contents of the given URL.
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>Invokes [NSData+dataWithContentsOfURL:] to read the contents, then
|
|
|
|
|
* examines the data to infer its encoding type, and converts the
|
|
|
|
|
* data to a string using -initWithData:encoding:
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>The encoding to use is determined as follows ... if the data begins
|
|
|
|
|
* with the 16-bit unicode Byte Order Marker, then it is assumed to be
|
|
|
|
|
* unicode data in the appropriate ordering and converted as such.<br />
|
|
|
|
|
* If it begins with a UTF8 representation of the BOM, the UTF8 encoding
|
|
|
|
|
* is used.<br />
|
|
|
|
|
* Otherwise, the default C String encoding is used.
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>Releases the receiver and returns nil if the URL contents could not be
|
|
|
|
|
* read and converted to a string.
|
|
|
|
|
* </p>
|
|
|
|
|
*/
|
2000-09-12 23:09:50 +00:00
|
|
|
|
- (id) initWithContentsOfURL: (NSURL*)url
|
|
|
|
|
{
|
2002-10-04 09:08:09 +00:00
|
|
|
|
NSStringEncoding enc = _DefaultStringEncoding;
|
2000-10-23 11:44:34 +00:00
|
|
|
|
NSData *d = [NSDataClass dataWithContentsOfURL: url];
|
2001-03-20 03:42:41 +00:00
|
|
|
|
unsigned int len = [d length];
|
2003-10-18 06:10:41 +00:00
|
|
|
|
const unsigned char *data_bytes;
|
2000-09-12 23:09:50 +00:00
|
|
|
|
|
|
|
|
|
if (d == nil)
|
2002-10-04 09:08:09 +00:00
|
|
|
|
{
|
|
|
|
|
NSWarnMLog(@"Contents of URL '%@' are not readable", url);
|
|
|
|
|
RELEASE(self);
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
2001-03-20 03:42:41 +00:00
|
|
|
|
if (len == 0)
|
2002-10-04 09:08:09 +00:00
|
|
|
|
{
|
|
|
|
|
RELEASE(self);
|
|
|
|
|
return @"";
|
|
|
|
|
}
|
2003-10-18 06:10:41 +00:00
|
|
|
|
data_bytes = [d bytes];
|
|
|
|
|
if ((data_bytes != NULL) && (len >= 2))
|
2001-03-20 03:42:41 +00:00
|
|
|
|
{
|
2003-10-18 06:10:41 +00:00
|
|
|
|
const unichar *data_ucs2chars = (const unichar *) data_bytes;
|
|
|
|
|
if ((data_ucs2chars[0] == byteOrderMark)
|
|
|
|
|
|| (data_ucs2chars[0] == byteOrderMarkSwapped))
|
2002-10-04 09:08:09 +00:00
|
|
|
|
{
|
|
|
|
|
enc = NSUnicodeStringEncoding;
|
|
|
|
|
}
|
2003-10-18 06:10:41 +00:00
|
|
|
|
else if (len >= 3
|
|
|
|
|
&& data_bytes[0] == 0xEF
|
|
|
|
|
&& data_bytes[1] == 0xBB
|
|
|
|
|
&& data_bytes[2] == 0xBF)
|
2002-10-04 09:32:48 +00:00
|
|
|
|
{
|
|
|
|
|
enc = NSUTF8StringEncoding;
|
|
|
|
|
}
|
2001-03-20 03:42:41 +00:00
|
|
|
|
}
|
2002-10-04 09:08:09 +00:00
|
|
|
|
self = [self initWithData: d encoding: enc];
|
|
|
|
|
if (self == nil)
|
2001-03-20 03:42:41 +00:00
|
|
|
|
{
|
2002-10-04 09:08:09 +00:00
|
|
|
|
NSWarnMLog(@"Contents of URL '%@' are not string data", url);
|
2001-03-20 03:42:41 +00:00
|
|
|
|
}
|
2002-10-04 09:08:09 +00:00
|
|
|
|
return self;
|
2000-09-12 23:09:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns the number of Unicode characters in this string, including the
|
|
|
|
|
* individual characters of composed character sequences,
|
|
|
|
|
*/
|
2002-03-13 13:46:12 +00:00
|
|
|
|
- (unsigned int) length
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
1999-05-06 14:42:26 +00:00
|
|
|
|
[self subclassResponsibility: _cmd];
|
1997-05-03 18:05:21 +00:00
|
|
|
|
return 0;
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Accessing Characters
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns unicode character at index. <code>unichar</code> is an unsigned
|
|
|
|
|
* short. Thus, a 16-bit character is returned.
|
|
|
|
|
*/
|
2002-03-13 13:46:12 +00:00
|
|
|
|
- (unichar) characterAtIndex: (unsigned int)index
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
1999-05-06 14:42:26 +00:00
|
|
|
|
[self subclassResponsibility: _cmd];
|
1997-05-03 18:05:21 +00:00
|
|
|
|
return (unichar)0;
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns this string as an array of 16-bit <code>unichar</code> (unsigned
|
|
|
|
|
* short) values. buffer must be preallocated and should be capable of
|
|
|
|
|
* holding -length shorts.
|
|
|
|
|
*/
|
|
|
|
|
// Inefficient. Should be overridden
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (void) getCharacters: (unichar*)buffer
|
|
|
|
|
{
|
2000-10-05 15:17:18 +00:00
|
|
|
|
[self getCharacters: buffer range: ((NSRange){0, [self length]})];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns aRange of string as an array of 16-bit <code>unichar</code>
|
|
|
|
|
* (unsigned short) values. buffer must be preallocated and should be capable
|
|
|
|
|
* of holding a sufficient number of shorts.
|
|
|
|
|
*/
|
|
|
|
|
// Inefficient. Should be overridden
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (void) getCharacters: (unichar*)buffer
|
1999-05-20 09:20:46 +00:00
|
|
|
|
range: (NSRange)aRange
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
1999-06-04 15:15:59 +00:00
|
|
|
|
unsigned l = [self length];
|
|
|
|
|
unsigned i;
|
2002-03-13 13:46:12 +00:00
|
|
|
|
unichar (*caiImp)(NSString*, SEL, unsigned int);
|
1999-06-04 15:15:59 +00:00
|
|
|
|
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GS_RANGE_CHECK(aRange, l);
|
1999-06-04 15:15:59 +00:00
|
|
|
|
|
2002-11-10 06:19:17 +00:00
|
|
|
|
caiImp = (unichar (*)(NSString*,SEL,unsigned))
|
|
|
|
|
[self methodForSelector: caiSel];
|
2000-10-05 15:17:18 +00:00
|
|
|
|
|
1996-09-02 13:38:19 +00:00
|
|
|
|
for (i = 0; i < aRange.length; i++)
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
2000-08-07 22:00:31 +00:00
|
|
|
|
buffer[i] = (*caiImp)(self, caiSel, aRange.location + i);
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-07-04 09:25:50 +00:00
|
|
|
|
/**
|
|
|
|
|
* Constructs a new ASCII string which is a representation of the receiver
|
2005-11-06 13:53:40 +00:00
|
|
|
|
* in which characters are escaped where necessary in order to produce a
|
2004-07-04 09:25:50 +00:00
|
|
|
|
* legal URL.<br />
|
|
|
|
|
* Returns nil if the receiver cannot be represented using the specified
|
|
|
|
|
* encoding.
|
|
|
|
|
*/
|
|
|
|
|
- (NSString*) stringByAddingPercentEscapesUsingEncoding: (NSStringEncoding)e
|
|
|
|
|
{
|
|
|
|
|
NSData *data = [self dataUsingEncoding: e];
|
|
|
|
|
NSString *s = nil;
|
|
|
|
|
|
|
|
|
|
if (data != nil)
|
|
|
|
|
{
|
|
|
|
|
unsigned char *src = (unsigned char*)[data bytes];
|
|
|
|
|
unsigned int slen = [data length];
|
|
|
|
|
NSMutableData *d = [[NSMutableData alloc] initWithLength: slen * 3];
|
|
|
|
|
unsigned char *dst = (unsigned char*)[d mutableBytes];
|
|
|
|
|
unsigned int spos = 0;
|
|
|
|
|
unsigned int dpos = 0;
|
|
|
|
|
|
|
|
|
|
while (spos < slen)
|
|
|
|
|
{
|
|
|
|
|
unsigned char c = src[spos++];
|
|
|
|
|
unsigned int hi;
|
|
|
|
|
unsigned int lo;
|
|
|
|
|
|
|
|
|
|
switch (c)
|
|
|
|
|
{
|
|
|
|
|
case ',':
|
|
|
|
|
case ';':
|
|
|
|
|
case '"':
|
|
|
|
|
case '\'':
|
|
|
|
|
case '&':
|
|
|
|
|
case '=':
|
|
|
|
|
case '(':
|
|
|
|
|
case ')':
|
|
|
|
|
case '<':
|
|
|
|
|
case '>':
|
|
|
|
|
case '?':
|
|
|
|
|
case '#':
|
|
|
|
|
case '{':
|
|
|
|
|
case '}':
|
|
|
|
|
case '%':
|
|
|
|
|
case ' ':
|
|
|
|
|
case '+':
|
|
|
|
|
dst[dpos++] = '%';
|
|
|
|
|
hi = (c & 0xf0) >> 4;
|
|
|
|
|
dst[dpos++] = (hi > 9) ? 'A' + hi - 10 : '0' + hi;
|
|
|
|
|
lo = (c & 0x0f);
|
|
|
|
|
dst[dpos++] = (lo > 9) ? 'A' + lo - 10 : '0' + lo;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
if (c < ' ' || c > 127)
|
|
|
|
|
{
|
|
|
|
|
dst[dpos++] = '%';
|
|
|
|
|
hi = (c & 0xf0) >> 4;
|
|
|
|
|
dst[dpos++] = (hi > 9) ? 'A' + hi - 10 : '0' + hi;
|
|
|
|
|
lo = (c & 0x0f);
|
|
|
|
|
dst[dpos++] = (lo > 9) ? 'A' + lo - 10 : '0' + lo;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
dst[dpos++] = c;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
[d setLength: dpos];
|
|
|
|
|
s = [[NSString alloc] initWithData: d encoding: NSASCIIStringEncoding];
|
|
|
|
|
RELEASE(d);
|
|
|
|
|
AUTORELEASE(s);
|
|
|
|
|
}
|
|
|
|
|
return s;
|
|
|
|
|
}
|
1995-04-03 01:35:42 +00:00
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Constructs a new string consisting of this instance followed by the string
|
|
|
|
|
* specified by format.
|
|
|
|
|
*/
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (NSString*) stringByAppendingFormat: (NSString*)format,...
|
|
|
|
|
{
|
2001-04-12 09:11:31 +00:00
|
|
|
|
va_list ap;
|
|
|
|
|
id ret;
|
|
|
|
|
|
1995-04-03 01:35:42 +00:00
|
|
|
|
va_start(ap, format);
|
2002-04-29 12:20:08 +00:00
|
|
|
|
ret = [self stringByAppendingString:
|
2001-04-12 09:11:31 +00:00
|
|
|
|
[NSString stringWithFormat: format arguments: ap]];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
va_end(ap);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Constructs a new string consisting of this instance followed by the aString.
|
|
|
|
|
*/
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (NSString*) stringByAppendingString: (NSString*)aString
|
|
|
|
|
{
|
2000-09-27 15:26:16 +00:00
|
|
|
|
unsigned len = [self length];
|
|
|
|
|
unsigned otherLength = [aString length];
|
2000-10-31 16:17:33 +00:00
|
|
|
|
NSZone *z = GSObjCZone(self);
|
2000-09-27 15:26:16 +00:00
|
|
|
|
unichar *s = NSZoneMalloc(z, (len+otherLength)*sizeof(unichar));
|
|
|
|
|
NSString *tmp;
|
1998-10-15 05:03:16 +00:00
|
|
|
|
|
2004-08-22 10:18:52 +00:00
|
|
|
|
[self getCharacters: s range: ((NSRange){0, len})];
|
|
|
|
|
[aString getCharacters: s + len range: ((NSRange){0, otherLength})];
|
2000-11-03 10:11:56 +00:00
|
|
|
|
tmp = [[NSStringClass allocWithZone: z] initWithCharactersNoCopy: s
|
2000-10-23 06:18:03 +00:00
|
|
|
|
length: len + otherLength freeWhenDone: YES];
|
1999-06-03 10:59:25 +00:00
|
|
|
|
return AUTORELEASE(tmp);
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Dividing Strings into Substrings
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* <p>Returns an array of [NSString]s representing substrings of this string
|
|
|
|
|
* that are separated by separator (which itself is never returned in the
|
|
|
|
|
* array). If there are no occurrences of separator, the whole string is
|
|
|
|
|
* returned. If string begins or ends with separator, empty strings will
|
|
|
|
|
* be returned for those positions.</p>
|
|
|
|
|
* <p>Note, use an [NSScanner] if you need more sophisticated parsing.</p>
|
|
|
|
|
*/
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (NSArray*) componentsSeparatedByString: (NSString*)separator
|
|
|
|
|
{
|
2001-04-12 09:11:31 +00:00
|
|
|
|
NSRange search;
|
|
|
|
|
NSRange complete;
|
|
|
|
|
NSRange found;
|
1996-03-19 01:44:01 +00:00
|
|
|
|
NSMutableArray *array = [NSMutableArray array];
|
(componentsSeparatedByString:, substringFromRange:,
rangeOfCharacterFromSet:, rangeOfCharacterFromSet:options:,
rangeOfCharacterFromSet:options:range:, rangeOfString:,
rangeOfString:options:, caseInsensitiveCompare:, hasPrefix:,
hasSuffix:, lastPathComponent, pathExtension,
stringByAppendingPathComponent:, stringByAppendingPathExtension:,
stringByDeletingLastPathComponent, stringByDeletingPathExtension):
Implemented methods.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@505 72102866-910b-0410-8b05-ffd578937521
1995-08-02 15:10:41 +00:00
|
|
|
|
|
1997-03-03 20:07:35 +00:00
|
|
|
|
search = NSMakeRange (0, [self length]);
|
1997-09-13 17:52:31 +00:00
|
|
|
|
complete = search;
|
1996-03-19 01:44:01 +00:00
|
|
|
|
found = [self rangeOfString: separator];
|
2001-04-12 09:11:31 +00:00
|
|
|
|
while (found.length != 0)
|
(componentsSeparatedByString:, substringFromRange:,
rangeOfCharacterFromSet:, rangeOfCharacterFromSet:options:,
rangeOfCharacterFromSet:options:range:, rangeOfString:,
rangeOfString:options:, caseInsensitiveCompare:, hasPrefix:,
hasSuffix:, lastPathComponent, pathExtension,
stringByAppendingPathComponent:, stringByAppendingPathExtension:,
stringByDeletingLastPathComponent, stringByDeletingPathExtension):
Implemented methods.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@505 72102866-910b-0410-8b05-ffd578937521
1995-08-02 15:10:41 +00:00
|
|
|
|
{
|
|
|
|
|
NSRange current;
|
1997-09-13 17:52:31 +00:00
|
|
|
|
|
1996-03-19 01:44:01 +00:00
|
|
|
|
current = NSMakeRange (search.location,
|
2001-04-12 09:11:31 +00:00
|
|
|
|
found.location - search.location);
|
1999-06-21 08:30:26 +00:00
|
|
|
|
[array addObject: [self substringWithRange: current]];
|
1997-09-13 17:52:31 +00:00
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
search = NSMakeRange (found.location + found.length,
|
2001-04-12 09:11:31 +00:00
|
|
|
|
complete.length - found.location - found.length);
|
2002-04-29 12:20:08 +00:00
|
|
|
|
found = [self rangeOfString: separator
|
2001-04-12 09:11:31 +00:00
|
|
|
|
options: 0
|
|
|
|
|
range: search];
|
(componentsSeparatedByString:, substringFromRange:,
rangeOfCharacterFromSet:, rangeOfCharacterFromSet:options:,
rangeOfCharacterFromSet:options:range:, rangeOfString:,
rangeOfString:options:, caseInsensitiveCompare:, hasPrefix:,
hasSuffix:, lastPathComponent, pathExtension,
stringByAppendingPathComponent:, stringByAppendingPathExtension:,
stringByDeletingLastPathComponent, stringByDeletingPathExtension):
Implemented methods.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@505 72102866-910b-0410-8b05-ffd578937521
1995-08-02 15:10:41 +00:00
|
|
|
|
}
|
1997-03-03 20:07:35 +00:00
|
|
|
|
// Add the last search string range
|
1999-06-21 08:30:26 +00:00
|
|
|
|
[array addObject: [self substringWithRange: search]];
|
(componentsSeparatedByString:, substringFromRange:,
rangeOfCharacterFromSet:, rangeOfCharacterFromSet:options:,
rangeOfCharacterFromSet:options:range:, rangeOfString:,
rangeOfString:options:, caseInsensitiveCompare:, hasPrefix:,
hasSuffix:, lastPathComponent, pathExtension,
stringByAppendingPathComponent:, stringByAppendingPathExtension:,
stringByDeletingLastPathComponent, stringByDeletingPathExtension):
Implemented methods.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@505 72102866-910b-0410-8b05-ffd578937521
1995-08-02 15:10:41 +00:00
|
|
|
|
|
|
|
|
|
// FIXME: Need to make mutable array into non-mutable array?
|
|
|
|
|
return array;
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2003-01-24 12:06:33 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns a substring of the receiver from character at the specified
|
|
|
|
|
* index to the end of the string.<br />
|
|
|
|
|
* So, supplying an index of 3 would return a substring consisting of
|
|
|
|
|
* the entire string apart from the first three character (those would
|
|
|
|
|
* be at index 0, 1, and 2).<br />
|
|
|
|
|
* If the supplied index is greater than or equal to the length of the
|
|
|
|
|
* receiver an exception is raised.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
*/
|
2002-03-13 13:46:12 +00:00
|
|
|
|
- (NSString*) substringFromIndex: (unsigned int)index
|
1999-06-21 08:30:26 +00:00
|
|
|
|
{
|
|
|
|
|
return [self substringWithRange: ((NSRange){index, [self length]-index})];
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-24 12:06:33 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns a substring of the receiver from the start of the
|
|
|
|
|
* string to (but not including) the specified index position.<br />
|
|
|
|
|
* So, supplying an index of 3 would return a substring consisting of
|
|
|
|
|
* the first three characters of the receiver.<br />
|
|
|
|
|
* If the supplied index is greater than the length of the receiver
|
|
|
|
|
* an exception is raised.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
*/
|
2002-03-13 13:46:12 +00:00
|
|
|
|
- (NSString*) substringToIndex: (unsigned int)index
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
return [self substringWithRange: ((NSRange){0,index})];;
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2003-01-24 12:06:33 +00:00
|
|
|
|
/**
|
|
|
|
|
* An obsolete name for -substringWithRange: ... deprecated.
|
|
|
|
|
*/
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (NSString*) substringFromRange: (NSRange)aRange
|
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
return [self substringWithRange: aRange];
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-24 12:06:33 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns a substring of the receiver containing the characters
|
|
|
|
|
* in aRange.<br />
|
|
|
|
|
* If aRange specifies any character position not
|
|
|
|
|
* present in the receiver, an exception is raised.<br />
|
|
|
|
|
* If aRange has a length of zero, an empty string is returned.
|
|
|
|
|
*/
|
1999-06-21 08:30:26 +00:00
|
|
|
|
- (NSString*) substringWithRange: (NSRange)aRange
|
|
|
|
|
{
|
|
|
|
|
unichar *buf;
|
|
|
|
|
id ret;
|
|
|
|
|
unsigned len = [self length];
|
|
|
|
|
|
|
|
|
|
GS_RANGE_CHECK(aRange, len);
|
1997-12-08 20:04:16 +00:00
|
|
|
|
|
|
|
|
|
if (aRange.length == 0)
|
|
|
|
|
return @"";
|
2000-10-31 16:17:33 +00:00
|
|
|
|
buf = NSZoneMalloc(GSObjCZone(self), sizeof(unichar)*aRange.length);
|
1999-05-06 14:42:26 +00:00
|
|
|
|
[self getCharacters: buf range: aRange];
|
2000-11-03 10:11:56 +00:00
|
|
|
|
ret = [[NSStringClass allocWithZone: NSDefaultMallocZone()]
|
2000-09-27 15:26:16 +00:00
|
|
|
|
initWithCharactersNoCopy: buf length: aRange.length freeWhenDone: YES];
|
1999-06-03 10:59:25 +00:00
|
|
|
|
return AUTORELEASE(ret);
|
1997-12-08 20:04:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
1995-04-03 01:35:42 +00:00
|
|
|
|
// Finding Ranges of Characters and Substrings
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns position of first character in this string that is in aSet.
|
|
|
|
|
* Positions start at 0. If the character is a composed character sequence,
|
|
|
|
|
* the range returned will contain the whole sequence, else just the character
|
|
|
|
|
* itself.
|
|
|
|
|
*/
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (NSRange) rangeOfCharacterFromSet: (NSCharacterSet*)aSet
|
|
|
|
|
{
|
(componentsSeparatedByString:, substringFromRange:,
rangeOfCharacterFromSet:, rangeOfCharacterFromSet:options:,
rangeOfCharacterFromSet:options:range:, rangeOfString:,
rangeOfString:options:, caseInsensitiveCompare:, hasPrefix:,
hasSuffix:, lastPathComponent, pathExtension,
stringByAppendingPathComponent:, stringByAppendingPathExtension:,
stringByDeletingLastPathComponent, stringByDeletingPathExtension):
Implemented methods.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@505 72102866-910b-0410-8b05-ffd578937521
1995-08-02 15:10:41 +00:00
|
|
|
|
NSRange all = NSMakeRange(0, [self length]);
|
2001-04-12 09:11:31 +00:00
|
|
|
|
|
1999-05-06 14:42:26 +00:00
|
|
|
|
return [self rangeOfCharacterFromSet: aSet
|
2001-04-12 09:11:31 +00:00
|
|
|
|
options: 0
|
|
|
|
|
range: all];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns position of first character in this string that is in aSet.
|
|
|
|
|
* Positions start at 0. If the character is a composed character sequence,
|
|
|
|
|
* the range returned will contain the whole sequence, else just the character
|
|
|
|
|
* itself. mask may contain <code>NSCaseInsensitiveSearch</code>,
|
|
|
|
|
* <code>NSLiteralSearch</code> (don't consider alternate forms of composed
|
|
|
|
|
* characters equal), or <code>NSBackwardsSearch</code> (search from end of
|
|
|
|
|
* string).
|
|
|
|
|
*/
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (NSRange) rangeOfCharacterFromSet: (NSCharacterSet*)aSet
|
2002-03-13 13:46:12 +00:00
|
|
|
|
options: (unsigned int)mask
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
(componentsSeparatedByString:, substringFromRange:,
rangeOfCharacterFromSet:, rangeOfCharacterFromSet:options:,
rangeOfCharacterFromSet:options:range:, rangeOfString:,
rangeOfString:options:, caseInsensitiveCompare:, hasPrefix:,
hasSuffix:, lastPathComponent, pathExtension,
stringByAppendingPathComponent:, stringByAppendingPathExtension:,
stringByDeletingLastPathComponent, stringByDeletingPathExtension):
Implemented methods.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@505 72102866-910b-0410-8b05-ffd578937521
1995-08-02 15:10:41 +00:00
|
|
|
|
NSRange all = NSMakeRange(0, [self length]);
|
2001-04-12 09:11:31 +00:00
|
|
|
|
|
1999-05-06 14:42:26 +00:00
|
|
|
|
return [self rangeOfCharacterFromSet: aSet
|
2001-04-12 09:11:31 +00:00
|
|
|
|
options: mask
|
|
|
|
|
range: all];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns position of first character in this string that is in aSet.
|
|
|
|
|
* Positions start at 0. If the character is a composed character sequence,
|
|
|
|
|
* the range returned will contain the whole sequence, else just the character
|
|
|
|
|
* itself. mask may contain <code>NSCaseInsensitiveSearch</code>,
|
|
|
|
|
* <code>NSLiteralSearch</code> (don't consider alternate forms of composed
|
|
|
|
|
* characters equal), or <code>NSBackwardsSearch</code> (search from end of
|
|
|
|
|
* string). Search only carried out within aRange.
|
|
|
|
|
*/
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (NSRange) rangeOfCharacterFromSet: (NSCharacterSet*)aSet
|
2002-03-13 13:46:12 +00:00
|
|
|
|
options: (unsigned int)mask
|
1998-11-19 20:42:06 +00:00
|
|
|
|
range: (NSRange)aRange
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
2003-01-03 20:14:47 +00:00
|
|
|
|
unsigned int i;
|
|
|
|
|
unsigned int start;
|
|
|
|
|
unsigned int stop;
|
2001-04-12 09:11:31 +00:00
|
|
|
|
int step;
|
|
|
|
|
NSRange range;
|
2002-03-13 13:46:12 +00:00
|
|
|
|
unichar (*cImp)(id, SEL, unsigned int);
|
1999-02-04 13:49:27 +00:00
|
|
|
|
BOOL (*mImp)(id, SEL, unichar);
|
(componentsSeparatedByString:, substringFromRange:,
rangeOfCharacterFromSet:, rangeOfCharacterFromSet:options:,
rangeOfCharacterFromSet:options:range:, rangeOfString:,
rangeOfString:options:, caseInsensitiveCompare:, hasPrefix:,
hasSuffix:, lastPathComponent, pathExtension,
stringByAppendingPathComponent:, stringByAppendingPathExtension:,
stringByDeletingLastPathComponent, stringByDeletingPathExtension):
Implemented methods.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@505 72102866-910b-0410-8b05-ffd578937521
1995-08-02 15:10:41 +00:00
|
|
|
|
|
1998-11-19 20:42:06 +00:00
|
|
|
|
i = [self length];
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GS_RANGE_CHECK(aRange, i);
|
(componentsSeparatedByString:, substringFromRange:,
rangeOfCharacterFromSet:, rangeOfCharacterFromSet:options:,
rangeOfCharacterFromSet:options:range:, rangeOfString:,
rangeOfString:options:, caseInsensitiveCompare:, hasPrefix:,
hasSuffix:, lastPathComponent, pathExtension,
stringByAppendingPathComponent:, stringByAppendingPathExtension:,
stringByDeletingLastPathComponent, stringByDeletingPathExtension):
Implemented methods.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@505 72102866-910b-0410-8b05-ffd578937521
1995-08-02 15:10:41 +00:00
|
|
|
|
|
|
|
|
|
if ((mask & NSBackwardsSearch) == NSBackwardsSearch)
|
|
|
|
|
{
|
1998-07-15 12:48:57 +00:00
|
|
|
|
start = NSMaxRange(aRange)-1; stop = aRange.location-1; step = -1;
|
(componentsSeparatedByString:, substringFromRange:,
rangeOfCharacterFromSet:, rangeOfCharacterFromSet:options:,
rangeOfCharacterFromSet:options:range:, rangeOfString:,
rangeOfString:options:, caseInsensitiveCompare:, hasPrefix:,
hasSuffix:, lastPathComponent, pathExtension,
stringByAppendingPathComponent:, stringByAppendingPathExtension:,
stringByDeletingLastPathComponent, stringByDeletingPathExtension):
Implemented methods.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@505 72102866-910b-0410-8b05-ffd578937521
1995-08-02 15:10:41 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
start = aRange.location; stop = NSMaxRange(aRange); step = 1;
|
|
|
|
|
}
|
2002-02-05 18:20:47 +00:00
|
|
|
|
range.location = NSNotFound;
|
(componentsSeparatedByString:, substringFromRange:,
rangeOfCharacterFromSet:, rangeOfCharacterFromSet:options:,
rangeOfCharacterFromSet:options:range:, rangeOfString:,
rangeOfString:options:, caseInsensitiveCompare:, hasPrefix:,
hasSuffix:, lastPathComponent, pathExtension,
stringByAppendingPathComponent:, stringByAppendingPathExtension:,
stringByDeletingLastPathComponent, stringByDeletingPathExtension):
Implemented methods.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@505 72102866-910b-0410-8b05-ffd578937521
1995-08-02 15:10:41 +00:00
|
|
|
|
range.length = 0;
|
1999-02-04 13:49:27 +00:00
|
|
|
|
|
2002-11-10 06:19:17 +00:00
|
|
|
|
cImp = (unichar(*)(id,SEL,unsigned int))
|
|
|
|
|
[self methodForSelector: caiSel];
|
1999-02-04 13:49:27 +00:00
|
|
|
|
mImp = (BOOL(*)(id,SEL,unichar))
|
|
|
|
|
[aSet methodForSelector: cMemberSel];
|
|
|
|
|
|
|
|
|
|
for (i = start; i != stop; i += step)
|
(componentsSeparatedByString:, substringFromRange:,
rangeOfCharacterFromSet:, rangeOfCharacterFromSet:options:,
rangeOfCharacterFromSet:options:range:, rangeOfString:,
rangeOfString:options:, caseInsensitiveCompare:, hasPrefix:,
hasSuffix:, lastPathComponent, pathExtension,
stringByAppendingPathComponent:, stringByAppendingPathExtension:,
stringByDeletingLastPathComponent, stringByDeletingPathExtension):
Implemented methods.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@505 72102866-910b-0410-8b05-ffd578937521
1995-08-02 15:10:41 +00:00
|
|
|
|
{
|
1999-05-19 20:05:49 +00:00
|
|
|
|
unichar letter = (unichar)(*cImp)(self, caiSel, i);
|
2001-04-12 09:11:31 +00:00
|
|
|
|
|
1999-02-04 13:49:27 +00:00
|
|
|
|
if ((*mImp)(aSet, cMemberSel, letter))
|
(componentsSeparatedByString:, substringFromRange:,
rangeOfCharacterFromSet:, rangeOfCharacterFromSet:options:,
rangeOfCharacterFromSet:options:range:, rangeOfString:,
rangeOfString:options:, caseInsensitiveCompare:, hasPrefix:,
hasSuffix:, lastPathComponent, pathExtension,
stringByAppendingPathComponent:, stringByAppendingPathExtension:,
stringByDeletingLastPathComponent, stringByDeletingPathExtension):
Implemented methods.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@505 72102866-910b-0410-8b05-ffd578937521
1995-08-02 15:10:41 +00:00
|
|
|
|
{
|
|
|
|
|
range = NSMakeRange(i, 1);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return range;
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
|
/**
|
2004-06-22 22:40:40 +00:00
|
|
|
|
* Invokes -rangeOfString:options: with no options.
|
2002-08-20 10:22:05 +00:00
|
|
|
|
*/
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (NSRange) rangeOfString: (NSString*)string
|
|
|
|
|
{
|
2001-04-12 09:11:31 +00:00
|
|
|
|
NSRange all = NSMakeRange(0, [self length]);
|
|
|
|
|
|
1999-05-06 14:42:26 +00:00
|
|
|
|
return [self rangeOfString: string
|
2001-04-12 09:11:31 +00:00
|
|
|
|
options: 0
|
|
|
|
|
range: all];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
|
/**
|
|
|
|
|
* Invokes -rangeOfString:options:range: with the range set
|
2005-11-06 13:53:40 +00:00
|
|
|
|
* set to the range of the whole of the receiver.
|
2002-08-20 10:22:05 +00:00
|
|
|
|
*/
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (NSRange) rangeOfString: (NSString*)string
|
2002-03-13 13:46:12 +00:00
|
|
|
|
options: (unsigned int)mask
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
2001-04-12 09:11:31 +00:00
|
|
|
|
NSRange all = NSMakeRange(0, [self length]);
|
|
|
|
|
|
1999-05-06 14:42:26 +00:00
|
|
|
|
return [self rangeOfString: string
|
2001-04-12 09:11:31 +00:00
|
|
|
|
options: mask
|
|
|
|
|
range: all];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns the range giving the location and length of the first
|
|
|
|
|
* occurrence of aString within aRange.
|
|
|
|
|
* <br/>
|
|
|
|
|
* If aString does not exist in the receiver (an empty
|
|
|
|
|
* string is never considered to exist in the receiver),
|
|
|
|
|
* the length of the returned range is zero.
|
|
|
|
|
* <br/>
|
|
|
|
|
* If aString is nil, an exception is raised.
|
|
|
|
|
* <br/>
|
|
|
|
|
* If any part of aRange lies outside the range of the
|
|
|
|
|
* receiver, an exception is raised.
|
|
|
|
|
* <br/>
|
|
|
|
|
* The options mask may contain the following options -
|
|
|
|
|
* <list>
|
2004-06-22 22:40:40 +00:00
|
|
|
|
* <item><code>NSCaseInsensitiveSearch</code></item>
|
|
|
|
|
* <item><code>NSLiteralSearch</code></item>
|
|
|
|
|
* <item><code>NSBackwardsSearch</code></item>
|
|
|
|
|
* <item><code>NSAnchoredSearch</code></item>
|
2002-08-20 10:22:05 +00:00
|
|
|
|
* </list>
|
2004-06-22 22:40:40 +00:00
|
|
|
|
* The <code>NSAnchoredSearch</code> option means aString must occur at the
|
|
|
|
|
* beginning (or end, if <code>NSBackwardsSearch</code> is also given) of the
|
|
|
|
|
* string. Options should be OR'd together using <code>'|'</code>.
|
2002-08-20 10:22:05 +00:00
|
|
|
|
*/
|
|
|
|
|
- (NSRange) rangeOfString: (NSString *)aString
|
|
|
|
|
options: (unsigned int)mask
|
|
|
|
|
range: (NSRange)aRange
|
1999-05-20 09:20:46 +00:00
|
|
|
|
{
|
1999-05-25 14:27:42 +00:00
|
|
|
|
if (aString == nil)
|
|
|
|
|
[NSException raise: NSInvalidArgumentException format: @"range of nil"];
|
1999-05-20 09:20:46 +00:00
|
|
|
|
return strRangeNsNs(self, aString, mask, aRange);
|
1996-09-02 13:38:19 +00:00
|
|
|
|
}
|
1995-04-03 01:35:42 +00:00
|
|
|
|
|
2000-06-06 16:50:52 +00:00
|
|
|
|
- (unsigned int) indexOfString: (NSString *)substring
|
|
|
|
|
{
|
2001-04-12 09:11:31 +00:00
|
|
|
|
NSRange range = {0, [self length]};
|
2000-06-06 16:50:52 +00:00
|
|
|
|
|
2001-04-12 09:11:31 +00:00
|
|
|
|
range = [self rangeOfString: substring options: 0 range: range];
|
|
|
|
|
return range.length ? range.location : NSNotFound;
|
2000-06-06 16:50:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-13 13:46:12 +00:00
|
|
|
|
- (unsigned int) indexOfString: (NSString*)substring
|
|
|
|
|
fromIndex: (unsigned int)index
|
2000-06-06 16:50:52 +00:00
|
|
|
|
{
|
2001-04-12 09:11:31 +00:00
|
|
|
|
NSRange range = {index, [self length] - index};
|
2000-06-06 16:50:52 +00:00
|
|
|
|
|
2001-04-12 09:11:31 +00:00
|
|
|
|
range = [self rangeOfString: substring options: 0 range: range];
|
|
|
|
|
return range.length ? range.location : NSNotFound;
|
2000-06-06 16:50:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
1995-04-03 01:35:42 +00:00
|
|
|
|
// Determining Composed Character Sequences
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Unicode utility method. If character at anIndex is part of a composed
|
|
|
|
|
* character sequence anIndex (note indices start from 0), returns the full
|
|
|
|
|
* range of this sequence.
|
|
|
|
|
*/
|
2002-03-13 13:46:12 +00:00
|
|
|
|
- (NSRange) rangeOfComposedCharacterSequenceAtIndex: (unsigned int)anIndex
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
1999-05-10 06:35:41 +00:00
|
|
|
|
unsigned start;
|
|
|
|
|
unsigned end;
|
|
|
|
|
unsigned length = [self length];
|
2001-03-19 10:48:26 +00:00
|
|
|
|
unichar ch;
|
2002-03-13 13:46:12 +00:00
|
|
|
|
unichar (*caiImp)(NSString*, SEL, unsigned int);
|
2001-03-19 10:48:26 +00:00
|
|
|
|
NSCharacterSet *nbSet = [NSCharacterSet nonBaseCharacterSet];
|
1997-05-03 18:05:21 +00:00
|
|
|
|
|
1999-05-10 06:35:41 +00:00
|
|
|
|
if (anIndex >= length)
|
|
|
|
|
[NSException raise: NSRangeException format:@"Invalid location."];
|
2002-11-10 06:19:17 +00:00
|
|
|
|
caiImp = (unichar (*)(NSString*,SEL,unsigned))
|
|
|
|
|
[self methodForSelector: caiSel];
|
2001-03-19 10:48:26 +00:00
|
|
|
|
|
|
|
|
|
for (start = anIndex; start > 0; start--)
|
|
|
|
|
{
|
|
|
|
|
ch = (*caiImp)(self, caiSel, start);
|
|
|
|
|
if ([nbSet characterIsMember: ch] == NO)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
for (end = start+1; end < length; end++)
|
|
|
|
|
{
|
|
|
|
|
ch = (*caiImp)(self, caiSel, end);
|
|
|
|
|
if ([nbSet characterIsMember: ch] == NO)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
1997-05-03 18:05:21 +00:00
|
|
|
|
return NSMakeRange(start, end-start);
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
1997-05-03 18:05:21 +00:00
|
|
|
|
// Identifying and Comparing Strings
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* <p>Compares this instance with aString. Returns
|
|
|
|
|
* <code>NSOrderedAscending</code>, <code>NSOrderedDescending</code>, or
|
|
|
|
|
* <code>NSOrderedSame</code>, depending on whether this instance occurs
|
|
|
|
|
* before or after string in lexical order, or is equal to it.</p>
|
|
|
|
|
*/
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (NSComparisonResult) compare: (NSString*)aString
|
|
|
|
|
{
|
1999-05-06 14:42:26 +00:00
|
|
|
|
return [self compare: aString options: 0];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* <p>Compares this instance with aString. mask may be either
|
|
|
|
|
* <code>NSCaseInsensitiveSearch</code> or <code>NSLiteralSearch</code>. The
|
|
|
|
|
* latter requests a literal byte-by-byte comparison, which is fastest but may
|
|
|
|
|
* return inaccurate results in cases where two different composed character
|
|
|
|
|
* sequences may be used to express the same character.</p>
|
|
|
|
|
*/
|
2002-04-29 12:20:08 +00:00
|
|
|
|
- (NSComparisonResult) compare: (NSString*)aString
|
2002-03-13 13:46:12 +00:00
|
|
|
|
options: (unsigned int)mask
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
2002-04-29 12:20:08 +00:00
|
|
|
|
return [self compare: aString options: mask
|
1999-05-19 20:05:49 +00:00
|
|
|
|
range: ((NSRange){0, [self length]})];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* <p>Compares this instance with string. mask may be either
|
|
|
|
|
* <code>NSCaseInsensitiveSearch</code> or <code>NSLiteralSearch</code>. The
|
|
|
|
|
* latter requests a literal byte-by-byte comparison, which is fastest but may
|
|
|
|
|
* return inaccurate results in cases where two different composed character
|
|
|
|
|
* sequences may be used to express the same character. aRange refers
|
|
|
|
|
* to this instance, and should be set to 0..length to compare the whole
|
|
|
|
|
* string.</p>
|
|
|
|
|
*/
|
1997-05-03 18:05:21 +00:00
|
|
|
|
// xxx Should implement full POSIX.2 collate
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (NSComparisonResult) compare: (NSString*)aString
|
2002-03-13 13:46:12 +00:00
|
|
|
|
options: (unsigned int)mask
|
1999-05-19 20:05:49 +00:00
|
|
|
|
range: (NSRange)aRange
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
1999-05-25 14:27:42 +00:00
|
|
|
|
if (aString == nil)
|
|
|
|
|
[NSException raise: NSInvalidArgumentException format: @"compare with nil"];
|
1999-05-20 09:20:46 +00:00
|
|
|
|
return strCompNsNs(self, aString, mask, aRange);
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns whether this string starts with aString.
|
|
|
|
|
*/
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (BOOL) hasPrefix: (NSString*)aString
|
|
|
|
|
{
|
2001-04-12 09:11:31 +00:00
|
|
|
|
NSRange range;
|
|
|
|
|
|
2001-03-27 17:30:07 +00:00
|
|
|
|
range = [self rangeOfString: aString options: NSAnchoredSearch];
|
|
|
|
|
return (range.length > 0) ? YES : NO;
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns whether this string ends with aString.
|
|
|
|
|
*/
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (BOOL) hasSuffix: (NSString*)aString
|
|
|
|
|
{
|
2001-04-12 09:11:31 +00:00
|
|
|
|
NSRange range;
|
|
|
|
|
|
2001-03-27 17:30:07 +00:00
|
|
|
|
range = [self rangeOfString: aString
|
|
|
|
|
options: NSAnchoredSearch | NSBackwardsSearch];
|
|
|
|
|
return (range.length > 0) ? YES : NO;
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
2004-09-27 21:32:45 +00:00
|
|
|
|
* Returns whether the receiver and an anObject are equals as strings.
|
|
|
|
|
* If anObject isn't an NSString, returns NO.
|
2004-06-22 22:40:40 +00:00
|
|
|
|
*/
|
1997-05-03 18:05:21 +00:00
|
|
|
|
- (BOOL) isEqual: (id)anObject
|
|
|
|
|
{
|
1999-07-02 13:26:37 +00:00
|
|
|
|
if (anObject == self)
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
1998-10-09 04:24:56 +00:00
|
|
|
|
}
|
2000-10-31 16:17:33 +00:00
|
|
|
|
if (anObject != nil && GSObjCIsInstance(anObject) == YES)
|
1999-07-02 13:26:37 +00:00
|
|
|
|
{
|
2000-10-31 16:17:33 +00:00
|
|
|
|
Class c = GSObjCClass(anObject);
|
1998-10-09 04:24:56 +00:00
|
|
|
|
|
1999-07-02 13:26:37 +00:00
|
|
|
|
if (c != nil)
|
|
|
|
|
{
|
2000-10-31 16:17:33 +00:00
|
|
|
|
if (GSObjCIsKindOf(c, NSStringClass))
|
1999-07-02 13:26:37 +00:00
|
|
|
|
{
|
|
|
|
|
return [self isEqualToString: anObject];
|
1998-10-09 04:24:56 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
1999-07-02 13:26:37 +00:00
|
|
|
|
return NO;
|
1997-05-03 18:05:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns whether this instance is equal as a string to aString. See also
|
|
|
|
|
* -compare: and related methods.
|
|
|
|
|
*/
|
1997-05-03 18:05:21 +00:00
|
|
|
|
- (BOOL) isEqualToString: (NSString*)aString
|
|
|
|
|
{
|
1998-08-03 15:31:33 +00:00
|
|
|
|
if ([self hash] != [aString hash])
|
|
|
|
|
return NO;
|
1999-05-20 09:20:46 +00:00
|
|
|
|
if (strCompNsNs(self, aString, 0, (NSRange){0, [self length]})
|
|
|
|
|
== NSOrderedSame)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
return YES;
|
1999-05-20 09:20:46 +00:00
|
|
|
|
return NO;
|
1997-05-03 18:05:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-08-30 09:32:46 +00:00
|
|
|
|
/**
|
2000-10-05 15:17:18 +00:00
|
|
|
|
* Return 28-bit hash value (in 32-bit integer). The top few bits are used
|
|
|
|
|
* for other purposes in a bitfield in the concrete string subclasses, so we
|
|
|
|
|
* must not use the full unsigned integer.
|
|
|
|
|
*/
|
2002-03-13 13:46:12 +00:00
|
|
|
|
- (unsigned int) hash
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
2004-03-31 21:41:28 +00:00
|
|
|
|
unsigned ret = 0;
|
|
|
|
|
unsigned len = [self length];
|
1998-01-08 15:25:59 +00:00
|
|
|
|
|
2001-04-12 09:11:31 +00:00
|
|
|
|
if (len > 0)
|
1998-01-08 15:25:59 +00:00
|
|
|
|
{
|
2004-03-31 21:41:28 +00:00
|
|
|
|
unichar buf[64];
|
|
|
|
|
unichar *ptr = (len <= 64) ? buf :
|
|
|
|
|
NSZoneMalloc(NSDefaultMallocZone(), len * sizeof(unichar));
|
1999-05-19 20:05:49 +00:00
|
|
|
|
unichar *p;
|
|
|
|
|
unsigned char_count = 0;
|
1998-01-08 15:25:59 +00:00
|
|
|
|
|
2004-03-31 21:41:28 +00:00
|
|
|
|
[self getCharacters: ptr range: NSMakeRange(0,len)];
|
|
|
|
|
|
|
|
|
|
p = ptr;
|
|
|
|
|
|
|
|
|
|
while (char_count++ < len)
|
|
|
|
|
{
|
|
|
|
|
unichar c = *p++;
|
1998-10-06 15:11:27 +00:00
|
|
|
|
|
2004-03-31 21:41:28 +00:00
|
|
|
|
// FIXME ... should normalize composed character sequences.
|
|
|
|
|
ret = (ret << 5) + ret + c;
|
|
|
|
|
}
|
1998-10-06 15:11:27 +00:00
|
|
|
|
|
2004-03-31 21:41:28 +00:00
|
|
|
|
if (ptr != buf)
|
1999-05-19 20:05:49 +00:00
|
|
|
|
{
|
2004-03-31 21:41:28 +00:00
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), ptr);
|
1999-05-19 20:05:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The hash caching in our concrete string classes uses zero to denote
|
|
|
|
|
* an empty cache value, so we MUST NOT return a hash of zero.
|
|
|
|
|
*/
|
2004-05-03 20:16:37 +00:00
|
|
|
|
ret &= 0x0fffffff;
|
1999-05-19 20:05:49 +00:00
|
|
|
|
if (ret == 0)
|
2004-03-31 21:41:28 +00:00
|
|
|
|
{
|
|
|
|
|
ret = 0x0fffffff;
|
|
|
|
|
}
|
1999-05-19 20:05:49 +00:00
|
|
|
|
return ret;
|
|
|
|
|
}
|
1998-01-08 15:25:59 +00:00
|
|
|
|
else
|
2004-03-31 21:41:28 +00:00
|
|
|
|
{
|
|
|
|
|
return 0x0ffffffe; /* Hash for an empty string. */
|
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1995-04-03 01:35:42 +00:00
|
|
|
|
|
1997-05-03 18:05:21 +00:00
|
|
|
|
// Getting a Shared Prefix
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns the largest initial portion of this instance shared with aString.
|
|
|
|
|
* mask may be either <code>NSCaseInsensitiveSearch</code> or
|
|
|
|
|
* <code>NSLiteralSearch</code>. The latter requests a literal byte-by-byte
|
|
|
|
|
* comparison, which is fastest but may return inaccurate results in cases
|
|
|
|
|
* where two different composed character sequences may be used to express
|
|
|
|
|
* the same character.
|
|
|
|
|
*/
|
1997-05-03 18:05:21 +00:00
|
|
|
|
- (NSString*) commonPrefixWithString: (NSString*)aString
|
2002-03-13 13:46:12 +00:00
|
|
|
|
options: (unsigned int)mask
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
1999-05-19 20:05:49 +00:00
|
|
|
|
if (mask & NSLiteralSearch)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-05-19 20:05:49 +00:00
|
|
|
|
int prefix_len = 0;
|
2004-08-22 10:18:52 +00:00
|
|
|
|
unsigned length = [self length];
|
|
|
|
|
unsigned aLength = [aString length];
|
1999-05-19 20:05:49 +00:00
|
|
|
|
unichar *u,*w;
|
2004-08-22 10:18:52 +00:00
|
|
|
|
unichar a1[length+1];
|
1999-05-19 20:05:49 +00:00
|
|
|
|
unichar *s1 = a1;
|
2004-08-22 10:18:52 +00:00
|
|
|
|
unichar a2[aLength+1];
|
1999-05-19 20:05:49 +00:00
|
|
|
|
unichar *s2 = a2;
|
|
|
|
|
|
|
|
|
|
u = s1;
|
2004-08-22 10:18:52 +00:00
|
|
|
|
[self getCharacters: s1 range: ((NSRange){0, length})];
|
|
|
|
|
s1[length] = (unichar)0;
|
|
|
|
|
[aString getCharacters: s2 range: ((NSRange){0, aLength})];
|
|
|
|
|
s2[aLength] = (unichar)0;
|
1999-05-19 20:05:49 +00:00
|
|
|
|
u = s1;
|
|
|
|
|
w = s2;
|
|
|
|
|
|
|
|
|
|
if (mask & NSCaseInsensitiveSearch)
|
|
|
|
|
{
|
|
|
|
|
while (*s1 && *s2 && (uni_tolower(*s1) == uni_tolower(*s2)))
|
|
|
|
|
{
|
|
|
|
|
s1++;
|
|
|
|
|
s2++;
|
|
|
|
|
prefix_len++;
|
|
|
|
|
}
|
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
else
|
1999-05-19 20:05:49 +00:00
|
|
|
|
{
|
2002-04-29 12:20:08 +00:00
|
|
|
|
while (*s1 && *s2 && (*s1 == *s2))
|
1999-05-19 20:05:49 +00:00
|
|
|
|
{
|
|
|
|
|
s1++;
|
|
|
|
|
s2++;
|
|
|
|
|
prefix_len++;
|
|
|
|
|
}
|
|
|
|
|
}
|
2000-10-29 14:52:33 +00:00
|
|
|
|
return [NSStringClass stringWithCharacters: u length: prefix_len];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1999-05-19 20:05:49 +00:00
|
|
|
|
else
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
2002-03-13 13:46:12 +00:00
|
|
|
|
unichar (*scImp)(NSString*, SEL, unsigned int);
|
|
|
|
|
unichar (*ocImp)(NSString*, SEL, unsigned int);
|
1999-07-12 04:27:18 +00:00
|
|
|
|
void (*sgImp)(NSString*, SEL, unichar*, NSRange) = 0;
|
|
|
|
|
void (*ogImp)(NSString*, SEL, unichar*, NSRange) = 0;
|
2002-03-13 13:46:12 +00:00
|
|
|
|
NSRange (*srImp)(NSString*, SEL, unsigned int) = 0;
|
|
|
|
|
NSRange (*orImp)(NSString*, SEL, unsigned int) = 0;
|
1999-05-19 20:05:49 +00:00
|
|
|
|
BOOL gotRangeImps = NO;
|
|
|
|
|
BOOL gotFetchImps = NO;
|
|
|
|
|
NSRange sRange;
|
|
|
|
|
NSRange oRange;
|
|
|
|
|
unsigned sLength = [self length];
|
|
|
|
|
unsigned oLength = [aString length];
|
|
|
|
|
unsigned sIndex = 0;
|
|
|
|
|
unsigned oIndex = 0;
|
|
|
|
|
|
|
|
|
|
if (!sLength)
|
2004-08-26 13:43:34 +00:00
|
|
|
|
return IMMUTABLE(self);
|
1999-05-19 20:05:49 +00:00
|
|
|
|
if (!oLength)
|
2004-08-26 13:43:34 +00:00
|
|
|
|
return IMMUTABLE(aString);
|
1999-05-19 20:05:49 +00:00
|
|
|
|
|
2002-11-10 06:19:17 +00:00
|
|
|
|
scImp = (unichar (*)(NSString*,SEL,unsigned))
|
|
|
|
|
[self methodForSelector: caiSel];
|
|
|
|
|
ocImp = (unichar (*)(NSString*,SEL,unsigned))
|
|
|
|
|
[aString methodForSelector: caiSel];
|
1999-05-19 20:05:49 +00:00
|
|
|
|
|
|
|
|
|
while ((sIndex < sLength) && (oIndex < oLength))
|
|
|
|
|
{
|
|
|
|
|
unichar sc = (*scImp)(self, caiSel, sIndex);
|
|
|
|
|
unichar oc = (*ocImp)(aString, caiSel, oIndex);
|
|
|
|
|
|
|
|
|
|
if (sc == oc)
|
|
|
|
|
{
|
|
|
|
|
sIndex++;
|
|
|
|
|
oIndex++;
|
|
|
|
|
}
|
|
|
|
|
else if ((mask & NSCaseInsensitiveSearch)
|
|
|
|
|
&& (uni_tolower(sc) == uni_tolower(oc)))
|
|
|
|
|
{
|
|
|
|
|
sIndex++;
|
|
|
|
|
oIndex++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (gotRangeImps == NO)
|
|
|
|
|
{
|
|
|
|
|
gotRangeImps = YES;
|
|
|
|
|
srImp=(NSRange (*)())[self methodForSelector: ranSel];
|
|
|
|
|
orImp=(NSRange (*)())[aString methodForSelector: ranSel];
|
|
|
|
|
}
|
|
|
|
|
sRange = (*srImp)(self, ranSel, sIndex);
|
|
|
|
|
oRange = (*orImp)(aString, ranSel, oIndex);
|
|
|
|
|
|
|
|
|
|
if ((sRange.length < 2) || (oRange.length < 2))
|
1999-06-21 08:30:26 +00:00
|
|
|
|
return [self substringWithRange: NSMakeRange(0, sIndex)];
|
1999-05-19 20:05:49 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
GSEQ_MAKE(sBuf, sSeq, sRange.length);
|
|
|
|
|
GSEQ_MAKE(oBuf, oSeq, oRange.length);
|
|
|
|
|
|
|
|
|
|
if (gotFetchImps == NO)
|
|
|
|
|
{
|
|
|
|
|
gotFetchImps = YES;
|
|
|
|
|
sgImp=(void (*)())[self methodForSelector: gcrSel];
|
|
|
|
|
ogImp=(void (*)())[aString methodForSelector: gcrSel];
|
|
|
|
|
}
|
|
|
|
|
(*sgImp)(self, gcrSel, sBuf, sRange);
|
|
|
|
|
(*ogImp)(aString, gcrSel, oBuf, oRange);
|
|
|
|
|
|
|
|
|
|
if (GSeq_compare(&sSeq, &oSeq) == NSOrderedSame)
|
|
|
|
|
{
|
|
|
|
|
sIndex += sRange.length;
|
|
|
|
|
oIndex += oRange.length;
|
|
|
|
|
}
|
|
|
|
|
else if (mask & NSCaseInsensitiveSearch)
|
|
|
|
|
{
|
|
|
|
|
GSeq_lowercase(&sSeq);
|
|
|
|
|
GSeq_lowercase(&oSeq);
|
|
|
|
|
if (GSeq_compare(&sSeq, &oSeq) == NSOrderedSame)
|
|
|
|
|
{
|
|
|
|
|
sIndex += sRange.length;
|
|
|
|
|
oIndex += oRange.length;
|
|
|
|
|
}
|
|
|
|
|
else
|
1999-06-21 08:30:26 +00:00
|
|
|
|
return [self substringWithRange: NSMakeRange(0,sIndex)];
|
1999-05-19 20:05:49 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
1999-06-21 08:30:26 +00:00
|
|
|
|
return [self substringWithRange: NSMakeRange(0,sIndex)];
|
1999-05-19 20:05:49 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
1999-06-21 08:30:26 +00:00
|
|
|
|
return [self substringWithRange: NSMakeRange(0, sIndex)];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-08-30 09:32:46 +00:00
|
|
|
|
/**
|
|
|
|
|
* Determines the smallest range of lines containing aRange and returns
|
|
|
|
|
* the information as a range.<br />
|
|
|
|
|
* Calls -getLineStart:end:contentsEnd:forRange: to do the work.
|
|
|
|
|
*/
|
1999-05-19 20:05:49 +00:00
|
|
|
|
- (NSRange) lineRangeForRange: (NSRange)aRange
|
1998-01-08 15:25:59 +00:00
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
unsigned startIndex;
|
|
|
|
|
unsigned lineEndIndex;
|
1998-01-08 15:25:59 +00:00
|
|
|
|
|
|
|
|
|
[self getLineStart: &startIndex
|
|
|
|
|
end: &lineEndIndex
|
|
|
|
|
contentsEnd: NULL
|
1999-05-06 14:42:26 +00:00
|
|
|
|
forRange: aRange];
|
1998-01-08 15:25:59 +00:00
|
|
|
|
return NSMakeRange(startIndex, lineEndIndex - startIndex);
|
|
|
|
|
}
|
|
|
|
|
|
2002-08-30 09:32:46 +00:00
|
|
|
|
/**
|
|
|
|
|
* Determines the smallest range of lines containing aRange and returns
|
|
|
|
|
* the locations in that range.<br />
|
|
|
|
|
* Lines are delimited by any of these character sequences, the longest
|
|
|
|
|
* (CRLF) sequence preferred.
|
|
|
|
|
* <list>
|
|
|
|
|
* <item>U+000A (linefeed)</item>
|
|
|
|
|
* <item>U+000D (carriage return)</item>
|
|
|
|
|
* <item>U+2028 (Unicode line separator)</item>
|
|
|
|
|
* <item>U+2029 (Unicode paragraph separator)</item>
|
2002-08-30 14:54:07 +00:00
|
|
|
|
* <item>U+000D U+000A (CRLF)</item>
|
2002-08-30 09:32:46 +00:00
|
|
|
|
* </list>
|
|
|
|
|
* The index of the first character of the line at or before aRange is
|
|
|
|
|
* returned in startIndex.<br />
|
|
|
|
|
* The index of the first character of the next line after the line terminator
|
|
|
|
|
* is returned in endIndex.<br />
|
2002-08-30 14:54:07 +00:00
|
|
|
|
* The index of the last character before the line terminator is returned
|
2002-08-30 09:32:46 +00:00
|
|
|
|
* contentsEndIndex.<br />
|
|
|
|
|
* Raises an NSRangeException if the range is invalid, but permits the index
|
|
|
|
|
* arguments to be null pointers (in which case no value is returned in that
|
|
|
|
|
* argument).
|
|
|
|
|
*/
|
2002-03-13 13:46:12 +00:00
|
|
|
|
- (void) getLineStart: (unsigned int *)startIndex
|
|
|
|
|
end: (unsigned int *)lineEndIndex
|
|
|
|
|
contentsEnd: (unsigned int *)contentsEndIndex
|
1999-11-26 19:43:43 +00:00
|
|
|
|
forRange: (NSRange)aRange
|
1998-01-08 15:25:59 +00:00
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
unichar thischar;
|
2002-07-29 19:37:40 +00:00
|
|
|
|
unsigned start, end, len, termlen;
|
2002-03-13 13:46:12 +00:00
|
|
|
|
unichar (*caiImp)(NSString*, SEL, unsigned int);
|
1998-01-08 15:25:59 +00:00
|
|
|
|
|
|
|
|
|
len = [self length];
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GS_RANGE_CHECK(aRange, len);
|
|
|
|
|
|
2000-08-07 22:00:31 +00:00
|
|
|
|
caiImp = (unichar (*)())[self methodForSelector: caiSel];
|
1999-06-21 08:30:26 +00:00
|
|
|
|
start = aRange.location;
|
1998-01-08 15:25:59 +00:00
|
|
|
|
|
1999-02-04 13:49:27 +00:00
|
|
|
|
if (startIndex)
|
1999-06-24 19:30:29 +00:00
|
|
|
|
{
|
2000-08-07 22:00:31 +00:00
|
|
|
|
if (start == 0)
|
1999-06-24 19:30:29 +00:00
|
|
|
|
{
|
2000-08-07 22:00:31 +00:00
|
|
|
|
*startIndex = 0;
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
start--;
|
|
|
|
|
while (start > 0)
|
|
|
|
|
{
|
|
|
|
|
BOOL done = NO;
|
1999-06-21 08:30:26 +00:00
|
|
|
|
|
2000-08-07 22:00:31 +00:00
|
|
|
|
thischar = (*caiImp)(self, caiSel, start);
|
|
|
|
|
switch (thischar)
|
1999-06-24 19:30:29 +00:00
|
|
|
|
{
|
2002-04-29 12:20:08 +00:00
|
|
|
|
case (unichar)0x000A:
|
|
|
|
|
case (unichar)0x000D:
|
|
|
|
|
case (unichar)0x2028:
|
|
|
|
|
case (unichar)0x2029:
|
1999-06-24 19:30:29 +00:00
|
|
|
|
done = YES;
|
|
|
|
|
break;
|
2002-04-29 12:20:08 +00:00
|
|
|
|
default:
|
1999-06-24 19:30:29 +00:00
|
|
|
|
start--;
|
|
|
|
|
break;
|
2001-04-12 09:11:31 +00:00
|
|
|
|
}
|
1999-06-24 19:30:29 +00:00
|
|
|
|
if (done)
|
|
|
|
|
break;
|
2001-04-12 09:11:31 +00:00
|
|
|
|
}
|
1999-06-24 19:30:29 +00:00
|
|
|
|
if (start == 0)
|
|
|
|
|
{
|
2001-06-01 16:27:06 +00:00
|
|
|
|
thischar = (*caiImp)(self, caiSel, start);
|
|
|
|
|
switch (thischar)
|
|
|
|
|
{
|
2002-04-29 12:20:08 +00:00
|
|
|
|
case (unichar)0x000A:
|
|
|
|
|
case (unichar)0x000D:
|
|
|
|
|
case (unichar)0x2028:
|
|
|
|
|
case (unichar)0x2029:
|
2001-06-01 16:27:06 +00:00
|
|
|
|
start++;
|
|
|
|
|
break;
|
2002-04-29 12:20:08 +00:00
|
|
|
|
default:
|
2001-06-01 16:27:06 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
2001-06-01 16:27:06 +00:00
|
|
|
|
{
|
|
|
|
|
start++;
|
|
|
|
|
}
|
1999-06-24 19:30:29 +00:00
|
|
|
|
*startIndex = start;
|
|
|
|
|
}
|
|
|
|
|
}
|
1998-01-08 15:25:59 +00:00
|
|
|
|
|
1999-02-04 13:49:27 +00:00
|
|
|
|
if (lineEndIndex || contentsEndIndex)
|
1998-01-08 15:25:59 +00:00
|
|
|
|
{
|
2002-07-29 19:37:40 +00:00
|
|
|
|
BOOL found = NO;
|
2002-08-28 21:40:31 +00:00
|
|
|
|
end = aRange.location;
|
2005-02-22 11:22:44 +00:00
|
|
|
|
if (aRange.length)
|
2002-08-28 21:40:31 +00:00
|
|
|
|
{
|
|
|
|
|
end += (aRange.length - 1);
|
|
|
|
|
}
|
2000-08-07 22:00:31 +00:00
|
|
|
|
while (end < len)
|
1999-06-21 08:30:26 +00:00
|
|
|
|
{
|
2000-08-07 22:00:31 +00:00
|
|
|
|
thischar = (*caiImp)(self, caiSel, end);
|
|
|
|
|
switch (thischar)
|
1999-06-21 08:30:26 +00:00
|
|
|
|
{
|
2002-04-29 12:20:08 +00:00
|
|
|
|
case (unichar)0x000A:
|
|
|
|
|
case (unichar)0x000D:
|
|
|
|
|
case (unichar)0x2028:
|
|
|
|
|
case (unichar)0x2029:
|
2002-07-29 19:37:40 +00:00
|
|
|
|
found = YES;
|
1999-06-21 08:30:26 +00:00
|
|
|
|
break;
|
2002-04-29 12:20:08 +00:00
|
|
|
|
default:
|
1999-06-21 08:30:26 +00:00
|
|
|
|
break;
|
2001-04-12 09:11:31 +00:00
|
|
|
|
}
|
1999-06-21 08:30:26 +00:00
|
|
|
|
end++;
|
2002-07-29 19:37:40 +00:00
|
|
|
|
if (found)
|
1999-06-21 08:30:26 +00:00
|
|
|
|
break;
|
2001-04-12 09:11:31 +00:00
|
|
|
|
}
|
2002-07-29 19:37:40 +00:00
|
|
|
|
termlen = 1;
|
2001-06-01 16:27:06 +00:00
|
|
|
|
if (lineEndIndex)
|
1999-06-21 08:30:26 +00:00
|
|
|
|
{
|
2001-06-01 16:27:06 +00:00
|
|
|
|
if (end < len
|
2002-07-29 19:37:40 +00:00
|
|
|
|
&& ((*caiImp)(self, caiSel, end-1) == (unichar)0x000D)
|
|
|
|
|
&& ((*caiImp)(self, caiSel, end) == (unichar)0x000A))
|
1999-06-21 08:30:26 +00:00
|
|
|
|
{
|
2001-06-01 16:27:06 +00:00
|
|
|
|
*lineEndIndex = end+1;
|
2002-07-29 19:37:40 +00:00
|
|
|
|
termlen = 2;
|
1999-06-21 08:30:26 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
2001-06-01 16:27:06 +00:00
|
|
|
|
{
|
|
|
|
|
*lineEndIndex = end;
|
|
|
|
|
}
|
1999-06-21 08:30:26 +00:00
|
|
|
|
}
|
2001-06-01 16:27:06 +00:00
|
|
|
|
if (contentsEndIndex)
|
1999-06-21 08:30:26 +00:00
|
|
|
|
{
|
2002-07-29 19:37:40 +00:00
|
|
|
|
if (found)
|
2001-06-01 16:27:06 +00:00
|
|
|
|
{
|
2002-07-29 19:37:40 +00:00
|
|
|
|
*contentsEndIndex = end-termlen;
|
2001-06-01 16:27:06 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* xxx OPENSTEP documentation does not say what to do if last
|
|
|
|
|
line is not terminated. Assume this */
|
|
|
|
|
*contentsEndIndex = end;
|
|
|
|
|
}
|
1999-06-21 08:30:26 +00:00
|
|
|
|
}
|
1998-01-08 15:25:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1997-05-03 18:05:21 +00:00
|
|
|
|
// Changing Case
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns version of string in which each whitespace-delimited <em>word</em>
|
|
|
|
|
* is capitalized (not every letter). Conversion to capitals is done in a
|
|
|
|
|
* unicode-compliant manner but there may be exceptional cases where behavior
|
|
|
|
|
* is not what is desired.
|
|
|
|
|
*/
|
1997-05-03 18:05:21 +00:00
|
|
|
|
// xxx There is more than this in word capitalization in Unicode,
|
|
|
|
|
// but this will work in most cases
|
|
|
|
|
- (NSString*) capitalizedString
|
|
|
|
|
{
|
1999-07-02 13:26:37 +00:00
|
|
|
|
unichar *s;
|
|
|
|
|
unsigned count = 0;
|
|
|
|
|
BOOL found = YES;
|
|
|
|
|
unsigned len = [self length];
|
1999-02-04 13:49:27 +00:00
|
|
|
|
|
1999-07-02 13:26:37 +00:00
|
|
|
|
if (len == 0)
|
2004-08-26 13:43:34 +00:00
|
|
|
|
return IMMUTABLE(self);
|
2001-04-26 23:54:01 +00:00
|
|
|
|
if (whitespaceBitmapRep == NULL)
|
|
|
|
|
setupWhitespace();
|
1998-01-08 15:25:59 +00:00
|
|
|
|
|
2000-10-31 16:17:33 +00:00
|
|
|
|
s = NSZoneMalloc(GSObjCZone(self), sizeof(unichar)*len);
|
2004-08-22 10:18:52 +00:00
|
|
|
|
[self getCharacters: s range: ((NSRange){0, len})];
|
1999-07-17 14:41:31 +00:00
|
|
|
|
while (count < len)
|
1998-01-08 15:25:59 +00:00
|
|
|
|
{
|
2001-04-26 23:54:01 +00:00
|
|
|
|
if (GS_IS_WHITESPACE(s[count]))
|
1999-07-02 13:26:37 +00:00
|
|
|
|
{
|
|
|
|
|
count++;
|
1999-07-17 14:41:31 +00:00
|
|
|
|
found = YES;
|
|
|
|
|
while (count < len
|
2001-04-26 23:54:01 +00:00
|
|
|
|
&& GS_IS_WHITESPACE(s[count]))
|
1999-07-02 13:26:37 +00:00
|
|
|
|
{
|
|
|
|
|
count++;
|
|
|
|
|
}
|
|
|
|
|
}
|
1999-07-17 14:41:31 +00:00
|
|
|
|
if (count < len)
|
1999-07-02 13:26:37 +00:00
|
|
|
|
{
|
1999-07-17 14:41:31 +00:00
|
|
|
|
if (found)
|
1999-07-02 13:26:37 +00:00
|
|
|
|
{
|
1999-07-17 14:41:31 +00:00
|
|
|
|
s[count] = uni_toupper(s[count]);
|
1999-07-02 13:26:37 +00:00
|
|
|
|
count++;
|
|
|
|
|
}
|
1999-07-17 14:41:31 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
while (count < len
|
2001-04-26 23:54:01 +00:00
|
|
|
|
&& !GS_IS_WHITESPACE(s[count]))
|
1999-07-17 14:41:31 +00:00
|
|
|
|
{
|
|
|
|
|
s[count] = uni_tolower(s[count]);
|
|
|
|
|
count++;
|
|
|
|
|
}
|
|
|
|
|
}
|
1999-07-02 13:26:37 +00:00
|
|
|
|
}
|
1999-07-17 14:41:31 +00:00
|
|
|
|
found = NO;
|
1998-01-08 15:25:59 +00:00
|
|
|
|
}
|
1999-06-03 10:59:25 +00:00
|
|
|
|
return AUTORELEASE([[NSString allocWithZone: NSDefaultMallocZone()]
|
2000-09-27 15:26:16 +00:00
|
|
|
|
initWithCharactersNoCopy: s length: len freeWhenDone: YES]);
|
1997-05-03 18:05:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns a copy of the receiver with all characters converted
|
|
|
|
|
* to lowercase.
|
|
|
|
|
*/
|
1997-05-03 18:05:21 +00:00
|
|
|
|
- (NSString*) lowercaseString
|
|
|
|
|
{
|
2004-08-22 10:18:52 +00:00
|
|
|
|
static NSCharacterSet *uc = nil;
|
1999-06-03 10:59:25 +00:00
|
|
|
|
unichar *s;
|
|
|
|
|
unsigned count;
|
2004-08-22 10:18:52 +00:00
|
|
|
|
NSRange start;
|
1999-06-03 10:59:25 +00:00
|
|
|
|
unsigned len = [self length];
|
|
|
|
|
|
1999-07-02 13:26:37 +00:00
|
|
|
|
if (len == 0)
|
2000-08-07 22:00:31 +00:00
|
|
|
|
{
|
2004-08-26 13:43:34 +00:00
|
|
|
|
return IMMUTABLE(self);
|
2000-08-07 22:00:31 +00:00
|
|
|
|
}
|
2004-08-22 10:18:52 +00:00
|
|
|
|
if (uc == nil)
|
|
|
|
|
{
|
|
|
|
|
uc = RETAIN([NSCharacterSet uppercaseLetterCharacterSet]);
|
|
|
|
|
}
|
|
|
|
|
start = [self rangeOfCharacterFromSet: uc
|
|
|
|
|
options: NSLiteralSearch
|
|
|
|
|
range: ((NSRange){0, len})];
|
|
|
|
|
if (start.length == 0)
|
|
|
|
|
{
|
2004-08-26 13:43:34 +00:00
|
|
|
|
return IMMUTABLE(self);
|
2004-08-22 10:18:52 +00:00
|
|
|
|
}
|
2000-10-31 16:17:33 +00:00
|
|
|
|
s = NSZoneMalloc(GSObjCZone(self), sizeof(unichar)*len);
|
2004-08-22 10:18:52 +00:00
|
|
|
|
[self getCharacters: s range: ((NSRange){0, len})];
|
|
|
|
|
for (count = start.location; count < len; count++)
|
2000-08-07 22:00:31 +00:00
|
|
|
|
{
|
2004-08-22 10:18:52 +00:00
|
|
|
|
s[count] = uni_tolower(s[count]);
|
2000-08-07 22:00:31 +00:00
|
|
|
|
}
|
2000-11-03 10:11:56 +00:00
|
|
|
|
return AUTORELEASE([[NSStringClass allocWithZone: NSDefaultMallocZone()]
|
2000-09-27 15:26:16 +00:00
|
|
|
|
initWithCharactersNoCopy: s length: len freeWhenDone: YES]);
|
1997-05-03 18:05:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns a copy of the receiver with all characters converted
|
|
|
|
|
* to uppercase.
|
|
|
|
|
*/
|
2001-12-17 14:31:42 +00:00
|
|
|
|
- (NSString*) uppercaseString
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
2004-08-22 10:18:52 +00:00
|
|
|
|
static NSCharacterSet *lc = nil;
|
1999-06-03 10:59:25 +00:00
|
|
|
|
unichar *s;
|
|
|
|
|
unsigned count;
|
2004-08-22 10:18:52 +00:00
|
|
|
|
NSRange start;
|
1999-06-03 10:59:25 +00:00
|
|
|
|
unsigned len = [self length];
|
|
|
|
|
|
1999-07-02 13:26:37 +00:00
|
|
|
|
if (len == 0)
|
2000-08-07 22:00:31 +00:00
|
|
|
|
{
|
2004-08-26 13:43:34 +00:00
|
|
|
|
return IMMUTABLE(self);
|
2000-08-07 22:00:31 +00:00
|
|
|
|
}
|
2004-08-22 10:18:52 +00:00
|
|
|
|
if (lc == nil)
|
|
|
|
|
{
|
|
|
|
|
lc = RETAIN([NSCharacterSet lowercaseLetterCharacterSet]);
|
|
|
|
|
}
|
|
|
|
|
start = [self rangeOfCharacterFromSet: lc
|
|
|
|
|
options: NSLiteralSearch
|
|
|
|
|
range: ((NSRange){0, len})];
|
|
|
|
|
if (start.length == 0)
|
|
|
|
|
{
|
2004-08-26 13:43:34 +00:00
|
|
|
|
return IMMUTABLE(self);
|
2004-08-22 10:18:52 +00:00
|
|
|
|
}
|
2000-10-31 16:17:33 +00:00
|
|
|
|
s = NSZoneMalloc(GSObjCZone(self), sizeof(unichar)*len);
|
2004-08-22 10:18:52 +00:00
|
|
|
|
[self getCharacters: s range: ((NSRange){0, len})];
|
|
|
|
|
for (count = start.location; count < len; count++)
|
2000-08-07 22:00:31 +00:00
|
|
|
|
{
|
2004-08-22 10:18:52 +00:00
|
|
|
|
s[count] = uni_toupper(s[count]);
|
2000-08-07 22:00:31 +00:00
|
|
|
|
}
|
2000-11-03 10:11:56 +00:00
|
|
|
|
return AUTORELEASE([[NSStringClass allocWithZone: NSDefaultMallocZone()]
|
2000-09-27 15:26:16 +00:00
|
|
|
|
initWithCharactersNoCopy: s length: len freeWhenDone: YES]);
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Storing the String
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/** Returns <code>self</code>. */
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (NSString*) description
|
|
|
|
|
{
|
1997-03-03 20:07:35 +00:00
|
|
|
|
return self;
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Getting C Strings
|
|
|
|
|
|
* Add support for systems that support unichar file paths (e.g.
Windows).
* Headers/Foundation/NSFileManager.h (-localFromOpenStepPath:,
_openStepPathFromLocal:): New methods.
(NSDirectoryEnumerator): Updated ivars.
* Source/NSFileManager.m: Idem.
(-changeCurrentDirectoryPath, changeFileAttributes:,
currentDirectoryPath, etc): Update for Windows unichar paths.
* Headers/Foundation/NSString.h: (-unicharString,
-localFromOpenStepPath:, _openStepPathFromLocal:): New methods.
* Source/NSString.m: Idem.
* Source/GSFileHandle.m (-initForReadingAtPath:,
-initForWritingAtPath, -initForUpdatingAtPath:): Update for Windows
unichar paths.
* Source/NSData.m (readContentsOfFile, -writeToFile:,
initWithContentsOfMappedFile:): Idem.
* Source/NSTask.m (NSConcreteWindowsTask): Update for Windows
unichar paths.
(Patch from Roland Schwingle <roland.schwingel@onevision.de>)
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@20502 72102866-910b-0410-8b05-ffd578937521
2004-12-29 04:21:37 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns a pointer to a null terminated string of 16-bit unichar
|
|
|
|
|
* The memory pointed to is not owned by the caller, so the
|
2005-02-08 11:20:42 +00:00
|
|
|
|
* caller must copy its contents to keep it.
|
* Add support for systems that support unichar file paths (e.g.
Windows).
* Headers/Foundation/NSFileManager.h (-localFromOpenStepPath:,
_openStepPathFromLocal:): New methods.
(NSDirectoryEnumerator): Updated ivars.
* Source/NSFileManager.m: Idem.
(-changeCurrentDirectoryPath, changeFileAttributes:,
currentDirectoryPath, etc): Update for Windows unichar paths.
* Headers/Foundation/NSString.h: (-unicharString,
-localFromOpenStepPath:, _openStepPathFromLocal:): New methods.
* Source/NSString.m: Idem.
* Source/GSFileHandle.m (-initForReadingAtPath:,
-initForWritingAtPath, -initForUpdatingAtPath:): Update for Windows
unichar paths.
* Source/NSData.m (readContentsOfFile, -writeToFile:,
initWithContentsOfMappedFile:): Idem.
* Source/NSTask.m (NSConcreteWindowsTask): Update for Windows
unichar paths.
(Patch from Roland Schwingle <roland.schwingel@onevision.de>)
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@20502 72102866-910b-0410-8b05-ffd578937521
2004-12-29 04:21:37 +00:00
|
|
|
|
*/
|
|
|
|
|
- (const unichar*) unicharString
|
|
|
|
|
{
|
2005-02-08 11:20:42 +00:00
|
|
|
|
NSMutableData *data;
|
|
|
|
|
unichar *uniStr;
|
* Add support for systems that support unichar file paths (e.g.
Windows).
* Headers/Foundation/NSFileManager.h (-localFromOpenStepPath:,
_openStepPathFromLocal:): New methods.
(NSDirectoryEnumerator): Updated ivars.
* Source/NSFileManager.m: Idem.
(-changeCurrentDirectoryPath, changeFileAttributes:,
currentDirectoryPath, etc): Update for Windows unichar paths.
* Headers/Foundation/NSString.h: (-unicharString,
-localFromOpenStepPath:, _openStepPathFromLocal:): New methods.
* Source/NSString.m: Idem.
* Source/GSFileHandle.m (-initForReadingAtPath:,
-initForWritingAtPath, -initForUpdatingAtPath:): Update for Windows
unichar paths.
* Source/NSData.m (readContentsOfFile, -writeToFile:,
initWithContentsOfMappedFile:): Idem.
* Source/NSTask.m (NSConcreteWindowsTask): Update for Windows
unichar paths.
(Patch from Roland Schwingle <roland.schwingel@onevision.de>)
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@20502 72102866-910b-0410-8b05-ffd578937521
2004-12-29 04:21:37 +00:00
|
|
|
|
|
2005-06-04 07:22:51 +00:00
|
|
|
|
GSOnceMLog(@"deprecated ... use cStringUsingEncoding:");
|
|
|
|
|
|
2005-02-08 11:20:42 +00:00
|
|
|
|
data = [NSMutableData dataWithLength: ([self length] + 1) * sizeof(unichar)];
|
|
|
|
|
uniStr = (unichar*)[data mutableBytes];
|
|
|
|
|
if (uniStr != 0)
|
|
|
|
|
{
|
|
|
|
|
[self getCharacters: uniStr];
|
|
|
|
|
}
|
|
|
|
|
return uniStr;
|
* Add support for systems that support unichar file paths (e.g.
Windows).
* Headers/Foundation/NSFileManager.h (-localFromOpenStepPath:,
_openStepPathFromLocal:): New methods.
(NSDirectoryEnumerator): Updated ivars.
* Source/NSFileManager.m: Idem.
(-changeCurrentDirectoryPath, changeFileAttributes:,
currentDirectoryPath, etc): Update for Windows unichar paths.
* Headers/Foundation/NSString.h: (-unicharString,
-localFromOpenStepPath:, _openStepPathFromLocal:): New methods.
* Source/NSString.m: Idem.
* Source/GSFileHandle.m (-initForReadingAtPath:,
-initForWritingAtPath, -initForUpdatingAtPath:): Update for Windows
unichar paths.
* Source/NSData.m (readContentsOfFile, -writeToFile:,
initWithContentsOfMappedFile:): Idem.
* Source/NSTask.m (NSConcreteWindowsTask): Update for Windows
unichar paths.
(Patch from Roland Schwingle <roland.schwingel@onevision.de>)
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@20502 72102866-910b-0410-8b05-ffd578937521
2004-12-29 04:21:37 +00:00
|
|
|
|
}
|
2005-02-08 11:20:42 +00:00
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
|
/**
|
2004-06-22 22:40:40 +00:00
|
|
|
|
* Returns a pointer to a null terminated string of 8-bit characters in the
|
|
|
|
|
* default encoding. The memory pointed to is not owned by the caller, so the
|
|
|
|
|
* caller must copy its contents to keep it. Raises an
|
|
|
|
|
* <code>NSCharacterConversionException</code> if loss of information would
|
|
|
|
|
* occur during conversion. (See -canBeConvertedToEncoding: .)
|
2002-08-20 10:22:05 +00:00
|
|
|
|
*/
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (const char*) cString
|
|
|
|
|
{
|
2000-08-07 22:00:31 +00:00
|
|
|
|
NSData *d;
|
2000-10-23 11:44:34 +00:00
|
|
|
|
NSMutableData *m;
|
2000-08-07 22:00:31 +00:00
|
|
|
|
|
|
|
|
|
d = [self dataUsingEncoding: _DefaultStringEncoding
|
2001-04-12 09:11:31 +00:00
|
|
|
|
allowLossyConversion: NO];
|
1999-08-25 14:47:19 +00:00
|
|
|
|
if (d == nil)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSCharacterConversionException
|
|
|
|
|
format: @"unable to convert to cString"];
|
|
|
|
|
}
|
2000-10-23 11:44:34 +00:00
|
|
|
|
m = [d mutableCopy];
|
|
|
|
|
[m appendBytes: "" length: 1];
|
|
|
|
|
AUTORELEASE(m);
|
|
|
|
|
return (const char*)[m bytes];
|
1999-08-25 14:47:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2005-05-08 07:08:28 +00:00
|
|
|
|
/**
|
2005-06-04 07:22:51 +00:00
|
|
|
|
* Returns a pointer to a null terminated string of characters in the
|
2005-05-08 07:08:28 +00:00
|
|
|
|
* specified encoding.<br />
|
2005-06-04 07:22:51 +00:00
|
|
|
|
* NB. under GNUstep you can used this to obtain a nul terminated utf-16
|
|
|
|
|
* string (sixteen bit characters) as well as eight bit strings.<br />
|
2005-05-08 07:08:28 +00:00
|
|
|
|
* The memory pointed to is not owned by the caller, so the
|
|
|
|
|
* caller must copy its contents to keep it.<br />
|
2005-06-04 07:22:51 +00:00
|
|
|
|
* Raises an <code>NSCharacterConversionException</code> if loss of
|
2005-05-08 07:08:28 +00:00
|
|
|
|
* information would occur during conversion.
|
|
|
|
|
*/
|
|
|
|
|
- (const char*) cStringUsingEncoding: (NSStringEncoding)encoding
|
|
|
|
|
{
|
|
|
|
|
NSData *d;
|
|
|
|
|
NSMutableData *m;
|
|
|
|
|
|
|
|
|
|
d = [self dataUsingEncoding: encoding allowLossyConversion: NO];
|
|
|
|
|
if (d == nil)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSCharacterConversionException
|
|
|
|
|
format: @"unable to convert to cString"];
|
|
|
|
|
}
|
|
|
|
|
m = [d mutableCopy];
|
2005-05-08 15:07:59 +00:00
|
|
|
|
if (encoding == NSUnicodeStringEncoding)
|
|
|
|
|
{
|
|
|
|
|
unichar c = 0;
|
|
|
|
|
|
|
|
|
|
[m appendBytes: &c length: 2];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
[m appendBytes: "" length: 1];
|
|
|
|
|
}
|
2005-05-08 07:08:28 +00:00
|
|
|
|
AUTORELEASE(m);
|
|
|
|
|
return (const char*)[m bytes];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the number of bytes needed to encode the receiver in the
|
|
|
|
|
* specified encoding (without adding a nul character terminator).<br />
|
|
|
|
|
* Returns 0 if the conversion is not possible.
|
|
|
|
|
*/
|
|
|
|
|
- (unsigned) lengthOfBytesUsingEncoding: (NSStringEncoding)encoding
|
|
|
|
|
{
|
|
|
|
|
NSData *d;
|
|
|
|
|
|
|
|
|
|
d = [self dataUsingEncoding: encoding allowLossyConversion: NO];
|
|
|
|
|
return [d length];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns a size guaranteed to be large enough to encode the receiver in the
|
|
|
|
|
* specified encoding (without adding a nul character terminator). This may
|
|
|
|
|
* be larger than the actual number of bytes needed.
|
|
|
|
|
*/
|
|
|
|
|
- (unsigned) maximumLengthOfBytesUsingEncoding: (NSStringEncoding)encoding
|
|
|
|
|
{
|
|
|
|
|
if (encoding == NSUnicodeStringEncoding)
|
|
|
|
|
return [self length] * 2;
|
|
|
|
|
if (encoding == NSUTF8StringEncoding)
|
|
|
|
|
return [self length] * 6;
|
|
|
|
|
if (encoding == NSUTF7StringEncoding)
|
|
|
|
|
return [self length] * 8;
|
|
|
|
|
return [self length]; // Assume single byte/char
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns a C string converted using the default C string encoding, which may
|
|
|
|
|
* result in information loss. The memory pointed to is not owned by the
|
|
|
|
|
* caller, so the caller must copy its contents to keep it.
|
|
|
|
|
*/
|
1999-08-25 14:47:19 +00:00
|
|
|
|
- (const char*) lossyCString
|
|
|
|
|
{
|
2000-08-07 22:00:31 +00:00
|
|
|
|
NSData *d;
|
2000-10-23 11:44:34 +00:00
|
|
|
|
NSMutableData *m;
|
2000-08-07 22:00:31 +00:00
|
|
|
|
|
|
|
|
|
d = [self dataUsingEncoding: _DefaultStringEncoding
|
2001-03-19 10:48:26 +00:00
|
|
|
|
allowLossyConversion: YES];
|
2000-10-23 11:44:34 +00:00
|
|
|
|
m = [d mutableCopy];
|
|
|
|
|
[m appendBytes: "" length: 1];
|
|
|
|
|
AUTORELEASE(m);
|
|
|
|
|
return (const char*)[m bytes];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns null-terminated UTF-8 version of this unicode string. The char[]
|
|
|
|
|
* memory comes from an autoreleased object, so it will eventually go out of
|
|
|
|
|
* scope.
|
|
|
|
|
*/
|
2000-09-30 04:54:43 +00:00
|
|
|
|
- (const char *) UTF8String
|
2000-09-12 23:09:50 +00:00
|
|
|
|
{
|
|
|
|
|
NSData *d;
|
2000-10-23 11:44:34 +00:00
|
|
|
|
NSMutableData *m;
|
2000-09-12 23:09:50 +00:00
|
|
|
|
|
|
|
|
|
d = [self dataUsingEncoding: NSUTF8StringEncoding
|
2001-03-19 10:48:26 +00:00
|
|
|
|
allowLossyConversion: NO];
|
2000-10-23 11:44:34 +00:00
|
|
|
|
m = [d mutableCopy];
|
|
|
|
|
[m appendBytes: "" length: 1];
|
|
|
|
|
AUTORELEASE(m);
|
|
|
|
|
return (const char*)[m bytes];
|
2000-09-12 23:09:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns length of a version of this unicode string converted to bytes
|
|
|
|
|
* using the default C string encoding. If the conversion would result in
|
|
|
|
|
* information loss, the results are unpredictable. Check
|
|
|
|
|
* -canBeConvertedToEncoding: first.
|
|
|
|
|
*/
|
2002-03-13 13:46:12 +00:00
|
|
|
|
- (unsigned int) cStringLength
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
2000-08-07 22:00:31 +00:00
|
|
|
|
NSData *d;
|
|
|
|
|
|
|
|
|
|
d = [self dataUsingEncoding: _DefaultStringEncoding
|
2001-03-19 10:48:26 +00:00
|
|
|
|
allowLossyConversion: NO];
|
2000-08-07 22:00:31 +00:00
|
|
|
|
return [d length];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-10-21 13:59:16 +00:00
|
|
|
|
/**
|
2006-04-09 16:16:07 +00:00
|
|
|
|
* Deprecated ... do not use.<br />.
|
|
|
|
|
* Use -getCString:maxLength:encoding: instead.
|
2002-10-21 13:59:16 +00:00
|
|
|
|
*/
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (void) getCString: (char*)buffer
|
|
|
|
|
{
|
1999-05-06 14:42:26 +00:00
|
|
|
|
[self getCString: buffer maxLength: NSMaximumStringLength
|
2000-08-07 22:00:31 +00:00
|
|
|
|
range: ((NSRange){0, [self length]})
|
|
|
|
|
remainingRange: NULL];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-10-21 13:59:16 +00:00
|
|
|
|
/**
|
2006-04-09 16:16:07 +00:00
|
|
|
|
* Deprecated ... do not use.<br />.
|
|
|
|
|
* Use -getCString:maxLength:encoding: instead.
|
2002-10-21 13:59:16 +00:00
|
|
|
|
*/
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (void) getCString: (char*)buffer
|
2002-03-13 13:46:12 +00:00
|
|
|
|
maxLength: (unsigned int)maxLength
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
2002-04-29 12:20:08 +00:00
|
|
|
|
[self getCString: buffer maxLength: maxLength
|
2000-08-07 22:00:31 +00:00
|
|
|
|
range: ((NSRange){0, [self length]})
|
|
|
|
|
remainingRange: NULL];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2005-05-08 07:08:28 +00:00
|
|
|
|
/**
|
|
|
|
|
* Retrieve up to maxLength bytes from the receiver into the buffer.<br />
|
2006-04-09 16:16:07 +00:00
|
|
|
|
* In GNUstep, this method implements the actual behavior of the MacOS-X
|
|
|
|
|
* method rather than it's documented behavior ...<br />
|
|
|
|
|
* The maxLength argument must be the size (in bytes) of the area of
|
|
|
|
|
* memory pointed to by the buffer argument.<br />
|
|
|
|
|
* Returns YES on success.<br />
|
|
|
|
|
* Returns NO if maxLength is too small to hold the entire string
|
|
|
|
|
* including a terminating nul character.<br />
|
|
|
|
|
* If it returns NO, the terminating nul will <em>not</em> have been
|
|
|
|
|
* written to the buffer.<br />
|
|
|
|
|
* Raises an exception if the string can not be converted to the
|
|
|
|
|
* specified encoding without loss of information.<br />
|
|
|
|
|
* eg. If the receiver is @"hello" then the provided buffer must be
|
|
|
|
|
* at least six bytes long and the value of maxLength must be at least
|
|
|
|
|
* six if NSASCIIStringEncoding is requested, but they must be at least
|
|
|
|
|
* twelve if NSUnicodeStringEncoding is requested.
|
2005-05-08 07:08:28 +00:00
|
|
|
|
*/
|
2006-04-09 16:16:07 +00:00
|
|
|
|
- (BOOL) getCString: (char*)buffer
|
2005-05-08 07:08:28 +00:00
|
|
|
|
maxLength: (unsigned int)maxLength
|
|
|
|
|
encoding: (NSStringEncoding)encoding
|
|
|
|
|
{
|
2005-05-08 15:07:59 +00:00
|
|
|
|
if (encoding == NSUnicodeStringEncoding)
|
|
|
|
|
{
|
2006-04-09 16:16:07 +00:00
|
|
|
|
unsigned length = [self length];
|
|
|
|
|
|
|
|
|
|
if (maxLength > length * sizeof(unichar))
|
|
|
|
|
{
|
|
|
|
|
unichar *ptr = (unichar*)buffer;
|
|
|
|
|
|
|
|
|
|
maxLength = (maxLength - 1) / sizeof(unichar);
|
|
|
|
|
[self getCharacters: ptr
|
|
|
|
|
range: NSMakeRange(0, maxLength)];
|
|
|
|
|
ptr[maxLength] = 0;
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSData *d = [self dataUsingEncoding: encoding];
|
|
|
|
|
unsigned length = [d length];
|
|
|
|
|
BOOL result = (length <= maxLength) ? YES : NO;
|
|
|
|
|
|
|
|
|
|
if (length > maxLength) length = maxLength;
|
|
|
|
|
memcpy(buffer, [d bytes], length);
|
|
|
|
|
buffer[length] = '\0';
|
|
|
|
|
return result;
|
2005-05-08 15:07:59 +00:00
|
|
|
|
}
|
2005-05-08 07:08:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-04-15 12:43:28 +00:00
|
|
|
|
/**
|
2006-04-09 16:16:07 +00:00
|
|
|
|
* Deprecated ... do not use.<br />.
|
|
|
|
|
* Use -getCString:maxLength:encoding: instead.
|
2004-04-15 12:43:28 +00:00
|
|
|
|
*/
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (void) getCString: (char*)buffer
|
2002-03-13 13:46:12 +00:00
|
|
|
|
maxLength: (unsigned int)maxLength
|
1999-07-02 13:26:37 +00:00
|
|
|
|
range: (NSRange)aRange
|
|
|
|
|
remainingRange: (NSRange*)leftoverRange
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
1999-07-02 13:26:37 +00:00
|
|
|
|
unsigned len;
|
|
|
|
|
unsigned count;
|
2002-03-13 13:46:12 +00:00
|
|
|
|
unichar (*caiImp)(NSString*, SEL, unsigned int);
|
1995-04-03 01:35:42 +00:00
|
|
|
|
|
1998-11-19 20:42:06 +00:00
|
|
|
|
len = [self cStringLength];
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GS_RANGE_CHECK(aRange, len);
|
1998-11-19 20:42:06 +00:00
|
|
|
|
|
2000-10-05 15:17:18 +00:00
|
|
|
|
caiImp = (unichar (*)())[self methodForSelector: caiSel];
|
|
|
|
|
|
1995-04-03 01:35:42 +00:00
|
|
|
|
if (maxLength < aRange.length)
|
|
|
|
|
{
|
|
|
|
|
len = maxLength;
|
|
|
|
|
if (leftoverRange)
|
|
|
|
|
{
|
|
|
|
|
leftoverRange->location = 0;
|
|
|
|
|
leftoverRange->length = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
len = aRange.length;
|
|
|
|
|
if (leftoverRange)
|
|
|
|
|
{
|
|
|
|
|
leftoverRange->location = aRange.location + maxLength;
|
|
|
|
|
leftoverRange->length = aRange.length - maxLength;
|
|
|
|
|
}
|
|
|
|
|
}
|
1999-07-02 13:26:37 +00:00
|
|
|
|
count = 0;
|
|
|
|
|
while (count < len)
|
|
|
|
|
{
|
2000-12-14 09:47:02 +00:00
|
|
|
|
buffer[count] = encode_unitochar(
|
|
|
|
|
(*caiImp)(self, caiSel, aRange.location + count),
|
|
|
|
|
_DefaultStringEncoding);
|
|
|
|
|
if (buffer[count] == 0)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSCharacterConversionException
|
|
|
|
|
format: @"unable to convert to cString"];
|
|
|
|
|
}
|
1999-07-02 13:26:37 +00:00
|
|
|
|
count++;
|
|
|
|
|
}
|
1997-05-03 18:05:21 +00:00
|
|
|
|
buffer[len] = '\0';
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Getting Numeric Values
|
|
|
|
|
|
2005-05-08 07:08:28 +00:00
|
|
|
|
// xxx Should we use NSScanner here ?
|
1997-05-03 18:05:21 +00:00
|
|
|
|
|
2002-08-07 11:06:49 +00:00
|
|
|
|
/**
|
|
|
|
|
* If the string consists of the words 'true' or 'yes' (case insensitive)
|
|
|
|
|
* or begins with a non-zero numeric value, return YES, otherwise return
|
|
|
|
|
* NO.
|
|
|
|
|
*/
|
1998-10-21 11:56:58 +00:00
|
|
|
|
- (BOOL) boolValue
|
|
|
|
|
{
|
2002-04-29 12:20:08 +00:00
|
|
|
|
if ([self caseInsensitiveCompare: @"YES"] == NSOrderedSame)
|
2002-08-07 11:06:49 +00:00
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
if ([self caseInsensitiveCompare: @"true"] == NSOrderedSame)
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
1999-07-02 13:26:37 +00:00
|
|
|
|
return [self intValue] != 0 ? YES : NO;
|
1998-10-21 11:56:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
2003-07-07 09:05:53 +00:00
|
|
|
|
/**
|
2004-06-22 22:40:40 +00:00
|
|
|
|
* Returns the string's content as a double. Skips leading whitespace.<br />
|
|
|
|
|
* Conversion is not localised (i.e. uses '.' as the decimal separator).<br />
|
2003-07-07 09:05:53 +00:00
|
|
|
|
* Returns 0.0 on underflow or if the string does not contain a number.
|
|
|
|
|
*/
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (double) doubleValue
|
|
|
|
|
{
|
2003-07-07 09:05:53 +00:00
|
|
|
|
unichar buf[32];
|
|
|
|
|
unsigned len = [self length];
|
|
|
|
|
double d = 0.0;
|
|
|
|
|
|
|
|
|
|
if (len > 32) len = 32;
|
|
|
|
|
[self getCharacters: buf range: NSMakeRange(0, len)];
|
|
|
|
|
GSScanDouble(buf, len, &d);
|
|
|
|
|
return d;
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2003-07-07 09:05:53 +00:00
|
|
|
|
/**
|
2004-06-22 22:40:40 +00:00
|
|
|
|
* Returns the string's content as a float. Skips leading whitespace.<br />
|
|
|
|
|
* Conversion is not localised (i.e. uses '.' as the decimal separator).<br />
|
2003-07-07 09:05:53 +00:00
|
|
|
|
* Returns 0.0 on underflow or if the string does not contain a number.
|
|
|
|
|
*/
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (float) floatValue
|
|
|
|
|
{
|
2003-07-07 09:05:53 +00:00
|
|
|
|
unichar buf[32];
|
|
|
|
|
unsigned len = [self length];
|
|
|
|
|
double d = 0.0;
|
|
|
|
|
|
|
|
|
|
if (len > 32) len = 32;
|
|
|
|
|
[self getCharacters: buf range: NSMakeRange(0, len)];
|
|
|
|
|
GSScanDouble(buf, len, &d);
|
|
|
|
|
return (float)d;
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* <p>Returns the string's content as an int.<br/>
|
|
|
|
|
* Current implementation uses C library <code>atoi()</code>, which does not
|
|
|
|
|
* detect conversion errors -- use with care!</p>
|
|
|
|
|
*/
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (int) intValue
|
|
|
|
|
{
|
2000-12-14 09:47:02 +00:00
|
|
|
|
return atoi([self lossyCString]);
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Working With Encodings
|
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
|
/**
|
|
|
|
|
* <p>
|
|
|
|
|
* Returns the encoding used for any method accepting a C string.
|
2004-06-22 22:40:40 +00:00
|
|
|
|
* This value is determined automatically from the program's
|
2002-08-20 10:22:05 +00:00
|
|
|
|
* environment and cannot be changed programmatically.
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>
|
|
|
|
|
* You should <em>NOT</em> override this method in an attempt to
|
|
|
|
|
* change the encoding being used... it won't work.
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>
|
|
|
|
|
* In GNUstep, this encoding is determined by the initial value
|
|
|
|
|
* of the <code>GNUSTEP_STRING_ENCODING</code> environment
|
|
|
|
|
* variable. If this is not defined,
|
|
|
|
|
* <code>NSISOLatin1StringEncoding</code> is assumed.
|
|
|
|
|
* </p>
|
|
|
|
|
*/
|
1995-04-03 01:35:42 +00:00
|
|
|
|
+ (NSStringEncoding) defaultCStringEncoding
|
|
|
|
|
{
|
1998-01-08 15:25:59 +00:00
|
|
|
|
return _DefaultStringEncoding;
|
|
|
|
|
}
|
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns an array of all available string encodings,
|
|
|
|
|
* terminated by a null value.
|
|
|
|
|
*/
|
1999-11-26 19:43:43 +00:00
|
|
|
|
+ (NSStringEncoding*) availableStringEncodings
|
1998-01-08 15:25:59 +00:00
|
|
|
|
{
|
2000-09-30 18:55:15 +00:00
|
|
|
|
return GetAvailableEncodings();
|
1998-01-08 15:25:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns the localized name of the encoding specified.
|
|
|
|
|
*/
|
1999-11-26 19:43:43 +00:00
|
|
|
|
+ (NSString*) localizedNameOfStringEncoding: (NSStringEncoding)encoding
|
1998-01-08 15:25:59 +00:00
|
|
|
|
{
|
|
|
|
|
id ourbundle;
|
|
|
|
|
id ourname;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Should be path to localizable.strings file.
|
2001-03-19 10:48:26 +00:00
|
|
|
|
Until we have it, just make sure that bundle
|
1998-01-08 15:25:59 +00:00
|
|
|
|
is initialized.
|
|
|
|
|
*/
|
2004-02-02 14:46:48 +00:00
|
|
|
|
ourbundle = [NSBundle bundleForLibrary: @"gnustep-base"];
|
1998-01-08 15:25:59 +00:00
|
|
|
|
|
|
|
|
|
ourname = GetEncodingName(encoding);
|
2000-08-07 22:00:31 +00:00
|
|
|
|
return [ourbundle localizedStringForKey: ourname
|
|
|
|
|
value: ourname
|
|
|
|
|
table: nil];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns whether this string can be converted to the given string encoding
|
|
|
|
|
* without information loss.
|
|
|
|
|
*/
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (BOOL) canBeConvertedToEncoding: (NSStringEncoding)encoding
|
|
|
|
|
{
|
2000-09-30 04:54:43 +00:00
|
|
|
|
id d = [self dataUsingEncoding: encoding allowLossyConversion: NO];
|
2001-04-12 09:11:31 +00:00
|
|
|
|
|
|
|
|
|
return d != nil ? YES : NO;
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Converts string to a byte array in the given encoding, returning nil if
|
|
|
|
|
* this would result in information loss.
|
|
|
|
|
*/
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (NSData*) dataUsingEncoding: (NSStringEncoding)encoding
|
|
|
|
|
{
|
1997-09-01 21:59:51 +00:00
|
|
|
|
return [self dataUsingEncoding: encoding allowLossyConversion: NO];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Converts string to a byte array in the given encoding. If flag is NO,
|
|
|
|
|
* nil would be returned if this would result in information loss.
|
|
|
|
|
*/
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (NSData*) dataUsingEncoding: (NSStringEncoding)encoding
|
1999-02-04 22:06:59 +00:00
|
|
|
|
allowLossyConversion: (BOOL)flag
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
2000-08-07 22:00:31 +00:00
|
|
|
|
unsigned int count = 0;
|
|
|
|
|
unsigned int len = [self length];
|
2002-03-13 13:46:12 +00:00
|
|
|
|
unichar (*caiImp)(NSString*, SEL, unsigned int);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-07-02 13:26:37 +00:00
|
|
|
|
if (len == 0)
|
2000-08-07 22:00:31 +00:00
|
|
|
|
{
|
2000-10-23 11:44:34 +00:00
|
|
|
|
return [NSDataClass data];
|
2000-08-07 22:00:31 +00:00
|
|
|
|
}
|
1999-07-02 13:26:37 +00:00
|
|
|
|
|
2000-08-07 22:00:31 +00:00
|
|
|
|
caiImp = (unichar (*)())[self methodForSelector: caiSel];
|
|
|
|
|
if ((encoding == NSASCIIStringEncoding)
|
|
|
|
|
|| (encoding == NSISOLatin1StringEncoding)
|
|
|
|
|
|| (encoding == NSISOLatin2StringEncoding)
|
|
|
|
|
|| (encoding == NSNEXTSTEPStringEncoding)
|
|
|
|
|
|| (encoding == NSNonLossyASCIIStringEncoding)
|
|
|
|
|
|| (encoding == NSSymbolStringEncoding)
|
2002-10-22 14:29:34 +00:00
|
|
|
|
|| (encoding == NSISOCyrillicStringEncoding)
|
|
|
|
|
|| (encoding == NSISOThaiStringEncoding))
|
1999-02-04 22:06:59 +00:00
|
|
|
|
{
|
2000-08-07 22:00:31 +00:00
|
|
|
|
char t;
|
|
|
|
|
unsigned char *buff;
|
1999-02-04 22:06:59 +00:00
|
|
|
|
|
1999-08-25 14:47:19 +00:00
|
|
|
|
buff = (unsigned char*)NSZoneMalloc(NSDefaultMallocZone(), len+1);
|
1999-02-04 22:06:59 +00:00
|
|
|
|
if (!flag)
|
|
|
|
|
{
|
|
|
|
|
for (count = 0; count < len; count++)
|
|
|
|
|
{
|
2000-08-07 22:00:31 +00:00
|
|
|
|
t = encode_unitochar((*caiImp)(self, caiSel, count), encoding);
|
1999-02-04 22:06:59 +00:00
|
|
|
|
if (t)
|
|
|
|
|
{
|
|
|
|
|
buff[count] = t;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), buff);
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else /* lossy */
|
|
|
|
|
{
|
|
|
|
|
for (count = 0; count < len; count++)
|
|
|
|
|
{
|
2000-08-07 22:00:31 +00:00
|
|
|
|
t = encode_unitochar((*caiImp)(self, caiSel, count), encoding);
|
1999-02-04 22:06:59 +00:00
|
|
|
|
if (t)
|
|
|
|
|
{
|
|
|
|
|
buff[count] = t;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* xxx should handle decomposed characters */
|
|
|
|
|
/* OpenStep documentation is unclear on what to do
|
|
|
|
|
* if there is no simple replacement for character
|
|
|
|
|
*/
|
|
|
|
|
buff[count] = '*';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
1999-08-25 14:47:19 +00:00
|
|
|
|
buff[count] = '\0';
|
2000-10-23 11:44:34 +00:00
|
|
|
|
return [NSDataClass dataWithBytesNoCopy: buff length: count];
|
1999-02-04 22:06:59 +00:00
|
|
|
|
}
|
2001-03-27 17:30:07 +00:00
|
|
|
|
else if (encoding == NSUTF8StringEncoding)
|
|
|
|
|
{
|
|
|
|
|
unsigned char *buff;
|
|
|
|
|
unsigned i, j;
|
|
|
|
|
unichar ch, ch2;
|
2006-01-26 02:49:59 +00:00
|
|
|
|
uint32_t cp;
|
2001-03-27 17:30:07 +00:00
|
|
|
|
|
|
|
|
|
buff = (unsigned char *)NSZoneMalloc(NSDefaultMallocZone(), len*3);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Each UTF-16 character maps to at most 3 bytes of UTF-8, so we simply
|
|
|
|
|
* allocate three times as many bytes as UTF-16 characters, then use
|
|
|
|
|
* NSZoneRealloc() later to trim the excess. Most Unix virtual memory
|
|
|
|
|
* implementations allocate address space, and actual memory pages are
|
|
|
|
|
* not actually allocated until used, so this method shouldn't cause
|
|
|
|
|
* memory problems on most Unix systems. On other systems, it may prove
|
|
|
|
|
* advantageous to scan the UTF-16 string to determine the UTF-8 string
|
|
|
|
|
* length before allocating memory.
|
|
|
|
|
*/
|
|
|
|
|
for (i = j = 0; i < len; i++)
|
|
|
|
|
{
|
|
|
|
|
ch = (*caiImp)(self, caiSel, i);
|
|
|
|
|
if (NSLocationInRange(ch, highSurrogateRange) && ((i+1) < len))
|
|
|
|
|
{
|
|
|
|
|
ch2 = (*caiImp)(self, caiSel, i+1);
|
|
|
|
|
if (NSLocationInRange(ch2, lowSurrogateRange))
|
|
|
|
|
{
|
|
|
|
|
cp = surrogatePairValue(ch, ch2);
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
else
|
2006-01-26 02:49:59 +00:00
|
|
|
|
cp = (uint32_t)ch;
|
2001-03-27 17:30:07 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
2006-01-26 02:49:59 +00:00
|
|
|
|
cp = (uint32_t)ch;
|
2001-03-27 17:30:07 +00:00
|
|
|
|
|
|
|
|
|
if (cp < 0x80)
|
|
|
|
|
{
|
|
|
|
|
buff[j++] = cp;
|
|
|
|
|
}
|
|
|
|
|
else if (cp < 0x800)
|
|
|
|
|
{
|
|
|
|
|
buff[j++] = 0xC0 | ch>>6;
|
|
|
|
|
buff[j++] = 0x80 | (ch & 0x3F);
|
|
|
|
|
}
|
|
|
|
|
else if (cp < 0x10000)
|
|
|
|
|
{
|
|
|
|
|
buff[j++] = 0xE0 | ch>>12;
|
|
|
|
|
buff[j++] = 0x80 | (ch>>6 & 0x3F);
|
|
|
|
|
buff[j++] = 0x80 | (ch & 0x3F);
|
|
|
|
|
}
|
|
|
|
|
else if (cp < 0x200000)
|
|
|
|
|
{
|
|
|
|
|
buff[j++] = 0xF0 | ch>>18;
|
|
|
|
|
buff[j++] = 0x80 | (ch>>12 & 0x3F);
|
|
|
|
|
buff[j++] = 0x80 | (ch>>6 & 0x3F);
|
|
|
|
|
buff[j++] = 0x80 | (ch & 0x3F);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-10-01 07:48:36 +00:00
|
|
|
|
buff = NSZoneRealloc(NSDefaultMallocZone(), buff, j);
|
2001-03-27 17:30:07 +00:00
|
|
|
|
|
|
|
|
|
return [NSDataClass dataWithBytesNoCopy: buff
|
2002-02-12 17:53:04 +00:00
|
|
|
|
length: j];
|
2001-03-27 17:30:07 +00:00
|
|
|
|
}
|
1999-02-04 22:06:59 +00:00
|
|
|
|
else if (encoding == NSUnicodeStringEncoding)
|
|
|
|
|
{
|
2000-08-07 22:00:31 +00:00
|
|
|
|
unichar *buff;
|
1999-02-04 22:06:59 +00:00
|
|
|
|
|
2000-10-23 11:44:34 +00:00
|
|
|
|
buff = (unichar*)NSZoneMalloc(NSDefaultMallocZone(),
|
|
|
|
|
sizeof(unichar)*(len+1));
|
2002-04-06 06:33:34 +00:00
|
|
|
|
buff[0] = byteOrderMark;
|
2004-08-22 10:18:52 +00:00
|
|
|
|
[self getCharacters: &buff[1] range: ((NSRange){0, len})];
|
2000-10-23 11:44:34 +00:00
|
|
|
|
return [NSDataClass dataWithBytesNoCopy: buff
|
|
|
|
|
length: sizeof(unichar)*(len+1)];
|
1999-02-04 22:06:59 +00:00
|
|
|
|
}
|
2000-10-23 11:44:34 +00:00
|
|
|
|
else
|
1999-02-04 22:06:59 +00:00
|
|
|
|
{
|
2002-03-16 09:54:50 +00:00
|
|
|
|
unsigned char *b = 0;
|
2005-07-08 11:48:37 +00:00
|
|
|
|
unsigned l = 0;
|
2000-10-23 11:44:34 +00:00
|
|
|
|
unichar *u;
|
|
|
|
|
|
|
|
|
|
u = (unichar*)NSZoneMalloc(NSDefaultMallocZone(), len*sizeof(unichar));
|
2004-08-22 10:18:52 +00:00
|
|
|
|
[self getCharacters: u range: ((NSRange){0, len})];
|
2002-03-16 09:54:50 +00:00
|
|
|
|
if (GSFromUnicode(&b, &l, u, len, encoding, NSDefaultMallocZone(),
|
|
|
|
|
(flag == NO) ? GSUniStrict : 0)
|
|
|
|
|
== NO)
|
2001-08-03 12:24:25 +00:00
|
|
|
|
{
|
2002-03-16 09:54:50 +00:00
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), u);
|
2000-10-23 11:44:34 +00:00
|
|
|
|
return nil;
|
|
|
|
|
}
|
2002-03-16 09:54:50 +00:00
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), u);
|
|
|
|
|
return [NSDataClass dataWithBytesNoCopy: b length: l];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1998-01-08 15:25:59 +00:00
|
|
|
|
return nil;
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the encoding with which this string can be converted without
|
|
|
|
|
* information loss that would result in most efficient character access.
|
|
|
|
|
*/
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (NSStringEncoding) fastestEncoding
|
|
|
|
|
{
|
2000-10-23 06:18:03 +00:00
|
|
|
|
return NSUnicodeStringEncoding;
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns the smallest encoding with which this string can be converted
|
|
|
|
|
* without information loss.
|
|
|
|
|
*/
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (NSStringEncoding) smallestEncoding
|
|
|
|
|
{
|
2000-10-23 06:18:03 +00:00
|
|
|
|
return NSUnicodeStringEncoding;
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-03-13 13:46:12 +00:00
|
|
|
|
- (unsigned int) completePathIntoString: (NSString**)outputName
|
2002-04-29 12:20:08 +00:00
|
|
|
|
caseSensitive: (BOOL)flag
|
|
|
|
|
matchesIntoArray: (NSArray**)outputArray
|
|
|
|
|
filterTypes: (NSArray*)filterTypes
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
NSString *basePath = [self stringByDeletingLastPathComponent];
|
|
|
|
|
NSString *lastComp = [self lastPathComponent];
|
|
|
|
|
NSString *tmpPath;
|
1999-07-12 04:27:18 +00:00
|
|
|
|
NSDirectoryEnumerator *e;
|
|
|
|
|
NSMutableArray *op = nil;
|
2005-03-21 12:29:02 +00:00
|
|
|
|
unsigned matchCount = 0;
|
1998-10-15 18:46:27 +00:00
|
|
|
|
|
1998-11-19 20:42:06 +00:00
|
|
|
|
if (outputArray != 0)
|
2003-08-01 10:15:11 +00:00
|
|
|
|
{
|
|
|
|
|
op = (NSMutableArray*)[NSMutableArray array];
|
|
|
|
|
}
|
1998-11-19 20:42:06 +00:00
|
|
|
|
|
1999-07-12 04:27:18 +00:00
|
|
|
|
if (outputName != NULL)
|
2003-08-01 10:15:11 +00:00
|
|
|
|
{
|
|
|
|
|
*outputName = nil;
|
|
|
|
|
}
|
1998-10-15 18:46:27 +00:00
|
|
|
|
|
2005-03-21 12:29:02 +00:00
|
|
|
|
if ([basePath length] == 0)
|
2003-08-01 10:15:11 +00:00
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
basePath = @".";
|
2003-08-01 10:15:11 +00:00
|
|
|
|
}
|
1998-10-15 18:46:27 +00:00
|
|
|
|
|
2005-03-21 12:29:02 +00:00
|
|
|
|
e = [[NSFileManager defaultManager] enumeratorAtPath: basePath];
|
|
|
|
|
while (tmpPath = [e nextObject], tmpPath)
|
1998-10-15 18:46:27 +00:00
|
|
|
|
{
|
|
|
|
|
/* Prefix matching */
|
2003-08-01 10:15:11 +00:00
|
|
|
|
if (flag == YES)
|
1998-10-15 18:46:27 +00:00
|
|
|
|
{ /* Case sensitive */
|
2005-03-21 12:29:02 +00:00
|
|
|
|
if ([tmpPath hasPrefix: lastComp] == NO)
|
2003-08-01 10:15:11 +00:00
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
1998-10-15 18:46:27 +00:00
|
|
|
|
}
|
2005-03-21 12:29:02 +00:00
|
|
|
|
else if ([[tmpPath uppercaseString]
|
|
|
|
|
hasPrefix: [lastComp uppercaseString]] == NO)
|
1998-10-15 18:46:27 +00:00
|
|
|
|
{
|
2003-08-01 10:15:11 +00:00
|
|
|
|
continue;
|
1998-10-15 18:46:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Extensions filtering */
|
2003-08-01 10:15:11 +00:00
|
|
|
|
if (filterTypes
|
2005-03-21 12:29:02 +00:00
|
|
|
|
&& ([filterTypes containsObject: [tmpPath pathExtension]] == NO))
|
2003-08-01 10:15:11 +00:00
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
1998-10-15 18:46:27 +00:00
|
|
|
|
|
|
|
|
|
/* Found a completion */
|
2005-03-21 12:29:02 +00:00
|
|
|
|
matchCount++;
|
1998-10-15 18:46:27 +00:00
|
|
|
|
if (outputArray != NULL)
|
2003-08-01 10:15:11 +00:00
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
[op addObject: tmpPath];
|
2003-08-01 10:15:11 +00:00
|
|
|
|
}
|
2002-04-29 12:20:08 +00:00
|
|
|
|
|
|
|
|
|
if ((outputName != NULL) &&
|
2005-03-21 12:29:02 +00:00
|
|
|
|
((*outputName == nil) || (([*outputName length] < [tmpPath length]))))
|
2003-08-01 10:15:11 +00:00
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
*outputName = tmpPath;
|
2003-08-01 10:15:11 +00:00
|
|
|
|
}
|
1998-10-15 18:46:27 +00:00
|
|
|
|
}
|
1998-11-19 20:42:06 +00:00
|
|
|
|
if (outputArray != NULL)
|
2003-08-01 10:15:11 +00:00
|
|
|
|
{
|
|
|
|
|
*outputArray = AUTORELEASE([op copy]);
|
|
|
|
|
}
|
2005-03-21 12:29:02 +00:00
|
|
|
|
return matchCount;
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2005-02-18 06:13:20 +00:00
|
|
|
|
static NSFileManager *fm = nil;
|
|
|
|
|
|
2005-11-05 07:12:00 +00:00
|
|
|
|
#if defined(__MINGW32__)
|
2005-11-28 15:41:35 +00:00
|
|
|
|
- (const GSNativeChar*) fileSystemRepresentation
|
1997-11-03 01:40:03 +00:00
|
|
|
|
{
|
2001-04-21 18:12:06 +00:00
|
|
|
|
if (fm == nil)
|
|
|
|
|
{
|
2002-04-18 07:51:46 +00:00
|
|
|
|
fm = RETAIN([NSFileManager defaultManager]);
|
2001-04-21 18:12:06 +00:00
|
|
|
|
}
|
2005-11-05 07:12:00 +00:00
|
|
|
|
return [fm fileSystemRepresentationWithPath: self];
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-28 15:41:35 +00:00
|
|
|
|
- (BOOL) getFileSystemRepresentation: (GSNativeChar*)buffer
|
2005-11-05 07:12:00 +00:00
|
|
|
|
maxLength: (unsigned int)size
|
|
|
|
|
{
|
2005-11-05 16:20:19 +00:00
|
|
|
|
const unichar *ptr;
|
2005-11-05 07:12:00 +00:00
|
|
|
|
unsigned i;
|
2002-04-29 12:20:08 +00:00
|
|
|
|
|
2005-11-05 16:20:19 +00:00
|
|
|
|
if (size == 0)
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
if (buffer == 0)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"%@ given null pointer",
|
|
|
|
|
NSStringFromSelector(_cmd)];
|
|
|
|
|
}
|
|
|
|
|
ptr = [self fileSystemRepresentation];
|
2005-11-05 07:12:00 +00:00
|
|
|
|
for (i = 0; i < size; i++)
|
|
|
|
|
{
|
|
|
|
|
buffer[i] = ptr[i];
|
|
|
|
|
if (ptr[i] == 0)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (i == size && ptr[i] != 0)
|
|
|
|
|
{
|
2005-11-05 16:20:19 +00:00
|
|
|
|
return NO; // Not at end.
|
2005-11-05 07:12:00 +00:00
|
|
|
|
}
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
#else
|
2005-11-28 15:41:35 +00:00
|
|
|
|
- (const GSNativeChar*) fileSystemRepresentation
|
2005-11-05 07:12:00 +00:00
|
|
|
|
{
|
|
|
|
|
if (fm == nil)
|
|
|
|
|
{
|
|
|
|
|
fm = RETAIN([NSFileManager defaultManager]);
|
|
|
|
|
}
|
2001-04-21 18:12:06 +00:00
|
|
|
|
return [fm fileSystemRepresentationWithPath: self];
|
1997-11-03 01:40:03 +00:00
|
|
|
|
}
|
2005-02-18 06:13:20 +00:00
|
|
|
|
|
2005-11-28 15:41:35 +00:00
|
|
|
|
- (BOOL) getFileSystemRepresentation: (GSNativeChar*)buffer
|
2002-03-13 13:46:12 +00:00
|
|
|
|
maxLength: (unsigned int)size
|
1997-11-03 01:40:03 +00:00
|
|
|
|
{
|
2005-11-05 16:20:19 +00:00
|
|
|
|
const char* ptr;
|
|
|
|
|
|
|
|
|
|
if (size == 0)
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
if (buffer == 0)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"%@ given null pointer",
|
|
|
|
|
NSStringFromSelector(_cmd)];
|
|
|
|
|
}
|
|
|
|
|
ptr = [self fileSystemRepresentation];
|
1997-11-03 01:40:03 +00:00
|
|
|
|
if (strlen(ptr) > size)
|
2005-11-05 16:20:19 +00:00
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
1997-11-03 01:40:03 +00:00
|
|
|
|
strcpy(buffer, ptr);
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
2005-11-05 07:12:00 +00:00
|
|
|
|
#endif
|
1997-11-03 01:40:03 +00:00
|
|
|
|
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (NSString*) lastPathComponent
|
|
|
|
|
{
|
2002-04-29 12:20:08 +00:00
|
|
|
|
unsigned int l = [self length];
|
2005-03-21 12:29:02 +00:00
|
|
|
|
NSRange range;
|
|
|
|
|
unsigned int i;
|
(componentsSeparatedByString:, substringFromRange:,
rangeOfCharacterFromSet:, rangeOfCharacterFromSet:options:,
rangeOfCharacterFromSet:options:range:, rangeOfString:,
rangeOfString:options:, caseInsensitiveCompare:, hasPrefix:,
hasSuffix:, lastPathComponent, pathExtension,
stringByAppendingPathComponent:, stringByAppendingPathExtension:,
stringByDeletingLastPathComponent, stringByDeletingPathExtension):
Implemented methods.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@505 72102866-910b-0410-8b05-ffd578937521
1995-08-02 15:10:41 +00:00
|
|
|
|
|
2002-04-29 12:20:08 +00:00
|
|
|
|
if (l == 0)
|
2002-04-18 07:51:46 +00:00
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
return @""; // self is empty
|
2002-04-18 07:51:46 +00:00
|
|
|
|
}
|
2005-03-21 12:29:02 +00:00
|
|
|
|
|
|
|
|
|
// Skip back over any trailing path separators, but not in to root.
|
|
|
|
|
i = rootOf(self, l);
|
|
|
|
|
while (l > i && pathSepMember([self characterAtIndex: l-1]) == YES)
|
(componentsSeparatedByString:, substringFromRange:,
rangeOfCharacterFromSet:, rangeOfCharacterFromSet:options:,
rangeOfCharacterFromSet:options:range:, rangeOfString:,
rangeOfString:options:, caseInsensitiveCompare:, hasPrefix:,
hasSuffix:, lastPathComponent, pathExtension,
stringByAppendingPathComponent:, stringByAppendingPathExtension:,
stringByDeletingLastPathComponent, stringByDeletingPathExtension):
Implemented methods.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@505 72102866-910b-0410-8b05-ffd578937521
1995-08-02 15:10:41 +00:00
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
l--;
|
|
|
|
|
}
|
2002-04-29 12:20:08 +00:00
|
|
|
|
|
2005-03-21 12:29:02 +00:00
|
|
|
|
// If only the root is left, return it.
|
|
|
|
|
if (i == l)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* NB. tilde escapes should not have trailing separator in the
|
|
|
|
|
* path component as they are not trreated as true roots.
|
|
|
|
|
*/
|
|
|
|
|
if ([self characterAtIndex: 0] == '~'
|
|
|
|
|
&& pathSepMember([self characterAtIndex: i-1]) == YES)
|
2002-04-18 07:51:46 +00:00
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
return [self substringToIndex: i-1];
|
2002-04-18 07:51:46 +00:00
|
|
|
|
}
|
2005-03-21 12:29:02 +00:00
|
|
|
|
return [self substringToIndex: i];
|
(componentsSeparatedByString:, substringFromRange:,
rangeOfCharacterFromSet:, rangeOfCharacterFromSet:options:,
rangeOfCharacterFromSet:options:range:, rangeOfString:,
rangeOfString:options:, caseInsensitiveCompare:, hasPrefix:,
hasSuffix:, lastPathComponent, pathExtension,
stringByAppendingPathComponent:, stringByAppendingPathExtension:,
stringByDeletingLastPathComponent, stringByDeletingPathExtension):
Implemented methods.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@505 72102866-910b-0410-8b05-ffd578937521
1995-08-02 15:10:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2005-03-21 12:29:02 +00:00
|
|
|
|
// Got more than root ... find last component.
|
|
|
|
|
range = [self rangeOfCharacterFromSet: pathSeps()
|
|
|
|
|
options: NSBackwardsSearch
|
|
|
|
|
range: ((NSRange){i, l-i})];
|
|
|
|
|
if (range.length > 0)
|
|
|
|
|
{
|
|
|
|
|
// Found separator ... adjust to point to component.
|
|
|
|
|
i = NSMaxRange(range);
|
|
|
|
|
}
|
|
|
|
|
return [self substringWithRange: ((NSRange){i, l-i})];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
1997-09-13 17:52:31 +00:00
|
|
|
|
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (NSString*) pathExtension
|
|
|
|
|
{
|
2002-04-29 12:20:08 +00:00
|
|
|
|
NSRange range;
|
2005-03-21 12:29:02 +00:00
|
|
|
|
unsigned int l = [self length];
|
|
|
|
|
unsigned int root;
|
|
|
|
|
|
|
|
|
|
if (l == 0)
|
|
|
|
|
{
|
|
|
|
|
return @"";
|
|
|
|
|
}
|
|
|
|
|
root = rootOf(self, l);
|
(componentsSeparatedByString:, substringFromRange:,
rangeOfCharacterFromSet:, rangeOfCharacterFromSet:options:,
rangeOfCharacterFromSet:options:range:, rangeOfString:,
rangeOfString:options:, caseInsensitiveCompare:, hasPrefix:,
hasSuffix:, lastPathComponent, pathExtension,
stringByAppendingPathComponent:, stringByAppendingPathExtension:,
stringByDeletingLastPathComponent, stringByDeletingPathExtension):
Implemented methods.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@505 72102866-910b-0410-8b05-ffd578937521
1995-08-02 15:10:41 +00:00
|
|
|
|
|
2002-04-29 12:20:08 +00:00
|
|
|
|
/*
|
|
|
|
|
* Step past trailing path separators.
|
|
|
|
|
*/
|
2005-03-21 12:29:02 +00:00
|
|
|
|
while (l > root && pathSepMember([self characterAtIndex: l-1]) == YES)
|
2002-04-18 07:51:46 +00:00
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
l--;
|
2002-04-18 07:51:46 +00:00
|
|
|
|
}
|
2005-03-21 12:29:02 +00:00
|
|
|
|
range = NSMakeRange(root, l-root);
|
2003-09-26 15:39:14 +00:00
|
|
|
|
|
|
|
|
|
/*
|
2005-03-21 12:29:02 +00:00
|
|
|
|
* Look for a dot in the path ... if there isn't one, or if it is
|
|
|
|
|
* immediately after the root or a path separator, there is no extension.
|
2003-09-26 15:39:14 +00:00
|
|
|
|
*/
|
2002-04-29 12:20:08 +00:00
|
|
|
|
range = [self rangeOfString: @"." options: NSBackwardsSearch range: range];
|
2005-03-21 12:29:02 +00:00
|
|
|
|
if (range.length > 0 && range.location > root
|
|
|
|
|
&& pathSepMember([self characterAtIndex: range.location-1]) == NO)
|
2002-04-18 07:51:46 +00:00
|
|
|
|
{
|
2003-09-26 15:39:14 +00:00
|
|
|
|
NSRange sepRange;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Found a dot, so we determine the range of the (possible)
|
2005-03-21 12:29:02 +00:00
|
|
|
|
* path extension, then check to see if we have a path
|
2003-09-26 15:39:14 +00:00
|
|
|
|
* separator within it ... if we have a path separator then
|
|
|
|
|
* the dot is inside the last path component and there is
|
2005-03-21 12:29:02 +00:00
|
|
|
|
* therefore no extension.
|
2003-09-26 15:39:14 +00:00
|
|
|
|
*/
|
2002-04-29 12:20:08 +00:00
|
|
|
|
range.location++;
|
2005-03-21 12:29:02 +00:00
|
|
|
|
range.length = l - range.location;
|
2003-09-26 15:39:14 +00:00
|
|
|
|
sepRange = [self rangeOfCharacterFromSet: pathSeps()
|
|
|
|
|
options: NSBackwardsSearch
|
|
|
|
|
range: range];
|
|
|
|
|
if (sepRange.length == 0)
|
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
return [self substringFromRange: range];
|
2003-09-26 15:39:14 +00:00
|
|
|
|
}
|
2002-04-18 07:51:46 +00:00
|
|
|
|
}
|
2002-04-29 12:20:08 +00:00
|
|
|
|
|
2005-03-21 12:29:02 +00:00
|
|
|
|
return @"";
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString*) stringByAppendingPathComponent: (NSString*)aString
|
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
unsigned originalLength = [self length];
|
|
|
|
|
unsigned length = originalLength;
|
2000-03-23 18:57:43 +00:00
|
|
|
|
unsigned aLength = [aString length];
|
2005-03-21 12:29:02 +00:00
|
|
|
|
unsigned root = rootOf(aString, aLength);
|
2000-03-23 18:57:43 +00:00
|
|
|
|
unichar buf[length+aLength+1];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
2005-03-21 12:29:02 +00:00
|
|
|
|
if (length == 0)
|
2002-04-29 12:20:08 +00:00
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
[aString getCharacters: buf range: ((NSRange){0, aLength})];
|
|
|
|
|
length = aLength;
|
2002-04-29 12:20:08 +00:00
|
|
|
|
}
|
2005-03-21 12:29:02 +00:00
|
|
|
|
else
|
2000-03-23 18:57:43 +00:00
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
[self getCharacters: buf range: ((NSRange){0, length})];
|
|
|
|
|
|
|
|
|
|
/* We strip back trailing path separators, and replace them with
|
|
|
|
|
* a single one ... except in the case where we have a windows
|
|
|
|
|
* drive specification, and the string being appended does not
|
|
|
|
|
* have a path separator as a root. In that case we just want to
|
|
|
|
|
* append to the drive specification directly, leaving a relative
|
|
|
|
|
* path like c:foo
|
|
|
|
|
*/
|
|
|
|
|
if (length != 2 || buf[1] != ':' || GSPathHandlingUnix() == YES
|
|
|
|
|
|| buf[0] < 'A' || buf[0] > 'z' || (buf[0] > 'Z' && buf[0] < 'a')
|
|
|
|
|
|| (root > 0 && pathSepMember([aString characterAtIndex: root-1])))
|
2000-03-24 11:50:18 +00:00
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
while (length > 0 && pathSepMember(buf[length-1]) == YES)
|
|
|
|
|
{
|
|
|
|
|
length--;
|
|
|
|
|
}
|
2006-01-26 02:49:59 +00:00
|
|
|
|
buf[length++] = pathSepChar();
|
2000-03-24 11:50:18 +00:00
|
|
|
|
}
|
2005-03-21 12:29:02 +00:00
|
|
|
|
|
|
|
|
|
if ((aLength - root) > 0)
|
|
|
|
|
{
|
|
|
|
|
// appending .. discard root from aString
|
|
|
|
|
[aString getCharacters: &buf[length]
|
|
|
|
|
range: ((NSRange){root, aLength-root})];
|
|
|
|
|
length += aLength-root;
|
|
|
|
|
}
|
|
|
|
|
// Find length of root part of new path.
|
|
|
|
|
root = rootOf(self, originalLength);
|
2000-03-23 18:57:43 +00:00
|
|
|
|
}
|
2005-03-21 12:29:02 +00:00
|
|
|
|
|
|
|
|
|
// Trim trailing path separators
|
2000-03-23 18:57:43 +00:00
|
|
|
|
while (length > 1 && pathSepMember(buf[length-1]) == YES)
|
|
|
|
|
{
|
|
|
|
|
length--;
|
|
|
|
|
}
|
2005-03-21 12:29:02 +00:00
|
|
|
|
|
|
|
|
|
/* Trim multi separator sequences outside root (root may contain an
|
|
|
|
|
* initial // pair if it is a windows UNC path).
|
|
|
|
|
*/
|
2000-04-04 18:36:46 +00:00
|
|
|
|
if (length > 0)
|
2000-03-23 18:57:43 +00:00
|
|
|
|
{
|
2000-04-04 18:36:46 +00:00
|
|
|
|
aLength = length - 1;
|
2005-03-21 12:29:02 +00:00
|
|
|
|
while (aLength > root)
|
2000-03-23 18:57:43 +00:00
|
|
|
|
{
|
2000-04-04 18:36:46 +00:00
|
|
|
|
if (pathSepMember(buf[aLength]) == YES)
|
2000-03-23 18:57:43 +00:00
|
|
|
|
{
|
2006-01-26 02:49:59 +00:00
|
|
|
|
buf[aLength] = pathSepChar();
|
2000-04-04 18:36:46 +00:00
|
|
|
|
if (pathSepMember(buf[aLength-1]) == YES)
|
2000-03-23 18:57:43 +00:00
|
|
|
|
{
|
2000-04-04 18:36:46 +00:00
|
|
|
|
unsigned pos;
|
|
|
|
|
|
2006-01-26 02:49:59 +00:00
|
|
|
|
buf[aLength-1] = pathSepChar();
|
2000-04-04 18:36:46 +00:00
|
|
|
|
for (pos = aLength+1; pos < length; pos++)
|
|
|
|
|
{
|
|
|
|
|
buf[pos-1] = buf[pos];
|
|
|
|
|
}
|
|
|
|
|
length--;
|
2000-03-23 18:57:43 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2000-04-04 18:36:46 +00:00
|
|
|
|
aLength--;
|
2000-03-23 18:57:43 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2000-10-23 06:18:03 +00:00
|
|
|
|
return [NSStringClass stringWithCharacters: buf length: length];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString*) stringByAppendingPathExtension: (NSString*)aString
|
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
unsigned l = [self length];
|
|
|
|
|
unsigned originalLength = l;
|
|
|
|
|
unsigned root;
|
|
|
|
|
|
|
|
|
|
if (l == 0)
|
2002-04-29 12:20:08 +00:00
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
NSLog(@"[%@-%@] cannot append extension '%@' to empty string",
|
|
|
|
|
NSStringFromClass([self class]), NSStringFromSelector(_cmd), aString);
|
|
|
|
|
return @""; // Must have a file name to append extension.
|
2002-04-29 12:20:08 +00:00
|
|
|
|
}
|
2005-03-21 12:29:02 +00:00
|
|
|
|
root = rootOf(self, l);
|
|
|
|
|
/*
|
|
|
|
|
* Step past trailing path separators.
|
|
|
|
|
*/
|
|
|
|
|
while (l > root && pathSepMember([self characterAtIndex: l-1]) == YES)
|
2002-04-29 12:20:08 +00:00
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
l--;
|
|
|
|
|
}
|
|
|
|
|
if (root == l)
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"[%@-%@] cannot append extension '%@' to path '%@'",
|
|
|
|
|
NSStringFromClass([self class]), NSStringFromSelector(_cmd),
|
|
|
|
|
aString, self);
|
|
|
|
|
return IMMUTABLE(self); // Must have a file name to append extension.
|
|
|
|
|
}
|
2002-04-29 12:20:08 +00:00
|
|
|
|
|
2005-03-21 12:29:02 +00:00
|
|
|
|
/* MacOS-X prohibits an extension beginning with a path separator,
|
|
|
|
|
* but this code extends that a little to prohibit any root from
|
|
|
|
|
* being used as an extension. Perhaps we should be more permissive?
|
|
|
|
|
*/
|
|
|
|
|
root = rootOf(aString, [aString length]);
|
|
|
|
|
if (root > 0)
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"[%@-%@] cannot append extension '%@' to path '%@'",
|
|
|
|
|
NSStringFromClass([self class]), NSStringFromSelector(_cmd),
|
|
|
|
|
aString, self);
|
|
|
|
|
return IMMUTABLE(self); // Must have a file name to append extension.
|
|
|
|
|
}
|
2002-04-29 12:20:08 +00:00
|
|
|
|
|
2005-03-21 12:29:02 +00:00
|
|
|
|
if (originalLength != l)
|
|
|
|
|
{
|
|
|
|
|
NSRange range = NSMakeRange(0, l);
|
|
|
|
|
|
|
|
|
|
return [[self substringFromRange: range]
|
|
|
|
|
stringByAppendingFormat: @".%@", aString];
|
2002-04-29 12:20:08 +00:00
|
|
|
|
}
|
2005-03-21 12:29:02 +00:00
|
|
|
|
return [self stringByAppendingFormat: @".%@", aString];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString*) stringByDeletingLastPathComponent
|
|
|
|
|
{
|
2002-04-29 12:20:08 +00:00
|
|
|
|
NSRange range;
|
2005-03-21 12:29:02 +00:00
|
|
|
|
unsigned int l = [self length];
|
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
|
|
if (l == 0)
|
|
|
|
|
{
|
|
|
|
|
return @"";
|
|
|
|
|
}
|
|
|
|
|
i = rootOf(self, l);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Any root without a trailing path separator can be deleted
|
|
|
|
|
* as it's either a relative path or a tilde expression.
|
|
|
|
|
*/
|
|
|
|
|
if (i == l && pathSepMember([self characterAtIndex: i-1]) == NO)
|
|
|
|
|
{
|
|
|
|
|
return @""; // Delete relative root
|
|
|
|
|
}
|
(componentsSeparatedByString:, substringFromRange:,
rangeOfCharacterFromSet:, rangeOfCharacterFromSet:options:,
rangeOfCharacterFromSet:options:range:, rangeOfString:,
rangeOfString:options:, caseInsensitiveCompare:, hasPrefix:,
hasSuffix:, lastPathComponent, pathExtension,
stringByAppendingPathComponent:, stringByAppendingPathExtension:,
stringByDeletingLastPathComponent, stringByDeletingPathExtension):
Implemented methods.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@505 72102866-910b-0410-8b05-ffd578937521
1995-08-02 15:10:41 +00:00
|
|
|
|
|
2002-04-29 12:20:08 +00:00
|
|
|
|
/*
|
|
|
|
|
* Step past trailing path separators.
|
|
|
|
|
*/
|
2005-03-21 12:29:02 +00:00
|
|
|
|
while (l > i && pathSepMember([self characterAtIndex: l-1]) == YES)
|
2002-04-29 12:20:08 +00:00
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
l--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If all we have left is the root, return that root, except for the
|
|
|
|
|
* special case of a tilde expression ... which may be deleted even
|
|
|
|
|
* when it is followed by a separator.
|
|
|
|
|
*/
|
|
|
|
|
if (l == i)
|
|
|
|
|
{
|
|
|
|
|
if ([self characterAtIndex: 0] == '~')
|
|
|
|
|
{
|
|
|
|
|
return @""; // Tilde roots may be deleted.
|
|
|
|
|
}
|
|
|
|
|
return [self substringToIndex: i]; // Return root component.
|
2002-04-29 12:20:08 +00:00
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
2002-04-29 12:20:08 +00:00
|
|
|
|
/*
|
2005-11-06 13:53:40 +00:00
|
|
|
|
* Locate path separator preceding last path component.
|
2002-04-29 12:20:08 +00:00
|
|
|
|
*/
|
|
|
|
|
range = [self rangeOfCharacterFromSet: pathSeps()
|
|
|
|
|
options: NSBackwardsSearch
|
2005-03-21 12:29:02 +00:00
|
|
|
|
range: ((NSRange){i, l-i})];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
if (range.length == 0)
|
2002-04-29 12:20:08 +00:00
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
return [self substringToIndex: i];
|
2002-04-29 12:20:08 +00:00
|
|
|
|
}
|
2005-03-21 12:29:02 +00:00
|
|
|
|
return [self substringToIndex: range.location];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString*) stringByDeletingPathExtension
|
|
|
|
|
{
|
2001-05-15 13:35:28 +00:00
|
|
|
|
NSRange range;
|
|
|
|
|
NSRange r0;
|
|
|
|
|
NSRange r1;
|
|
|
|
|
NSString *substring;
|
2005-03-21 12:29:02 +00:00
|
|
|
|
unsigned l = [self length];
|
|
|
|
|
unsigned root;
|
|
|
|
|
|
|
|
|
|
if ((root = rootOf(self, l)) == l)
|
|
|
|
|
{
|
|
|
|
|
return IMMUTABLE(self);
|
|
|
|
|
}
|
(componentsSeparatedByString:, substringFromRange:,
rangeOfCharacterFromSet:, rangeOfCharacterFromSet:options:,
rangeOfCharacterFromSet:options:range:, rangeOfString:,
rangeOfString:options:, caseInsensitiveCompare:, hasPrefix:,
hasSuffix:, lastPathComponent, pathExtension,
stringByAppendingPathComponent:, stringByAppendingPathExtension:,
stringByDeletingLastPathComponent, stringByDeletingPathExtension):
Implemented methods.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@505 72102866-910b-0410-8b05-ffd578937521
1995-08-02 15:10:41 +00:00
|
|
|
|
|
2001-05-15 13:35:28 +00:00
|
|
|
|
/*
|
2005-03-21 12:29:02 +00:00
|
|
|
|
* Skip past any trailing path separators... but not into root.
|
2001-05-15 13:35:28 +00:00
|
|
|
|
*/
|
2005-03-21 12:29:02 +00:00
|
|
|
|
while (l > root && pathSepMember([self characterAtIndex: l-1]) == YES)
|
2001-05-15 13:35:28 +00:00
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
l--;
|
2001-05-15 13:35:28 +00:00
|
|
|
|
}
|
2005-03-21 12:29:02 +00:00
|
|
|
|
range = NSMakeRange(root, l-root);
|
2001-05-15 13:35:28 +00:00
|
|
|
|
/*
|
|
|
|
|
* Locate path extension.
|
|
|
|
|
*/
|
|
|
|
|
r0 = [self rangeOfString: @"."
|
|
|
|
|
options: NSBackwardsSearch
|
|
|
|
|
range: range];
|
|
|
|
|
/*
|
|
|
|
|
* Locate a path separator.
|
|
|
|
|
*/
|
|
|
|
|
r1 = [self rangeOfCharacterFromSet: pathSeps()
|
|
|
|
|
options: NSBackwardsSearch
|
|
|
|
|
range: range];
|
|
|
|
|
/*
|
|
|
|
|
* Assuming the extension separator was found in the last path
|
|
|
|
|
* component, set the length of the substring we want.
|
|
|
|
|
*/
|
2005-03-21 12:29:02 +00:00
|
|
|
|
if (r0.length > 0 && r0.location > root
|
|
|
|
|
&& (r1.length == 0 || r1.location < r0.location))
|
2001-05-15 13:35:28 +00:00
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
l = r0.location;
|
2001-05-15 13:35:28 +00:00
|
|
|
|
}
|
2005-03-21 12:29:02 +00:00
|
|
|
|
substring = [self substringToIndex: l];
|
(componentsSeparatedByString:, substringFromRange:,
rangeOfCharacterFromSet:, rangeOfCharacterFromSet:options:,
rangeOfCharacterFromSet:options:range:, rangeOfString:,
rangeOfString:options:, caseInsensitiveCompare:, hasPrefix:,
hasSuffix:, lastPathComponent, pathExtension,
stringByAppendingPathComponent:, stringByAppendingPathExtension:,
stringByDeletingLastPathComponent, stringByDeletingPathExtension):
Implemented methods.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@505 72102866-910b-0410-8b05-ffd578937521
1995-08-02 15:10:41 +00:00
|
|
|
|
return substring;
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString*) stringByExpandingTildeInPath
|
|
|
|
|
{
|
2000-08-07 22:00:31 +00:00
|
|
|
|
NSString *homedir;
|
2005-03-21 12:29:02 +00:00
|
|
|
|
NSRange firstSlashRange;
|
2003-10-08 14:27:11 +00:00
|
|
|
|
unsigned length;
|
2002-04-29 12:20:08 +00:00
|
|
|
|
|
2003-10-08 14:27:11 +00:00
|
|
|
|
if ((length = [self length]) == 0)
|
2002-04-29 12:20:08 +00:00
|
|
|
|
{
|
2004-08-26 13:43:34 +00:00
|
|
|
|
return IMMUTABLE(self);
|
2002-04-29 12:20:08 +00:00
|
|
|
|
}
|
1998-02-03 14:20:00 +00:00
|
|
|
|
if ([self characterAtIndex: 0] != 0x007E)
|
2002-04-29 12:20:08 +00:00
|
|
|
|
{
|
2004-08-26 13:43:34 +00:00
|
|
|
|
return IMMUTABLE(self);
|
2002-04-29 12:20:08 +00:00
|
|
|
|
}
|
1996-11-24 21:04:24 +00:00
|
|
|
|
|
2005-03-21 12:29:02 +00:00
|
|
|
|
/* FIXME ... should remove in future
|
2003-10-08 14:27:11 +00:00
|
|
|
|
* Anything beginning '~@' is assumed to be a windows path specification
|
|
|
|
|
* which can't be expanded.
|
|
|
|
|
*/
|
|
|
|
|
if (length > 1 && [self characterAtIndex: 1] == 0x0040)
|
|
|
|
|
{
|
2004-08-26 13:43:34 +00:00
|
|
|
|
return IMMUTABLE(self);
|
2003-10-08 14:27:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2005-03-21 12:29:02 +00:00
|
|
|
|
firstSlashRange = [self rangeOfCharacterFromSet: pathSeps()
|
2004-08-22 10:18:52 +00:00
|
|
|
|
options: NSLiteralSearch
|
|
|
|
|
range: ((NSRange){0, length})];
|
2005-03-21 12:29:02 +00:00
|
|
|
|
if (firstSlashRange.length == 0)
|
2005-03-15 09:30:56 +00:00
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
firstSlashRange.location = length;
|
2005-03-15 09:30:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2005-03-21 12:29:02 +00:00
|
|
|
|
/* FIXME ... should remove in future
|
2005-03-15 09:30:56 +00:00
|
|
|
|
* Anything beginning '~' followed by a single letter is assumed
|
|
|
|
|
* to be a windows drive specification.
|
|
|
|
|
*/
|
2005-03-21 12:29:02 +00:00
|
|
|
|
if (firstSlashRange.location == 2 && isalpha([self characterAtIndex: 1]))
|
2005-03-15 09:30:56 +00:00
|
|
|
|
{
|
|
|
|
|
return IMMUTABLE(self);
|
|
|
|
|
}
|
1996-11-24 21:04:24 +00:00
|
|
|
|
|
2005-03-21 12:29:02 +00:00
|
|
|
|
if (firstSlashRange.location != 1)
|
1996-11-24 21:04:24 +00:00
|
|
|
|
{
|
2005-03-15 09:30:56 +00:00
|
|
|
|
/* It is of the form `~username/blah/...' or '~username' */
|
2005-03-21 12:29:02 +00:00
|
|
|
|
int userNameLen;
|
2001-04-23 09:56:33 +00:00
|
|
|
|
NSString *uname;
|
1996-11-24 21:04:24 +00:00
|
|
|
|
|
2005-03-21 12:29:02 +00:00
|
|
|
|
if (firstSlashRange.length != 0)
|
2001-04-23 09:56:33 +00:00
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
userNameLen = firstSlashRange.location - 1;
|
2001-04-23 09:56:33 +00:00
|
|
|
|
}
|
1996-11-24 21:04:24 +00:00
|
|
|
|
else
|
2001-04-23 09:56:33 +00:00
|
|
|
|
{
|
|
|
|
|
/* It is actually of the form `~username' */
|
2005-03-21 12:29:02 +00:00
|
|
|
|
userNameLen = [self length] - 1;
|
|
|
|
|
firstSlashRange.location = [self length];
|
2001-04-23 09:56:33 +00:00
|
|
|
|
}
|
2005-03-21 12:29:02 +00:00
|
|
|
|
uname = [self substringWithRange: ((NSRange){1, userNameLen})];
|
1996-11-24 21:04:24 +00:00
|
|
|
|
homedir = NSHomeDirectoryForUser (uname);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2005-03-15 09:30:56 +00:00
|
|
|
|
/* It is of the form `~/blah/...' or is '~' */
|
1996-11-24 21:04:24 +00:00
|
|
|
|
homedir = NSHomeDirectory ();
|
|
|
|
|
}
|
2005-03-15 09:30:56 +00:00
|
|
|
|
|
2002-04-29 12:20:08 +00:00
|
|
|
|
if (homedir != nil)
|
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
if (firstSlashRange.location < length)
|
2005-03-15 09:30:56 +00:00
|
|
|
|
{
|
|
|
|
|
return [homedir stringByAppendingPathComponent:
|
2005-03-21 12:29:02 +00:00
|
|
|
|
[self substringFromIndex: firstSlashRange.location]];
|
2005-03-15 09:30:56 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return IMMUTABLE(homedir);
|
|
|
|
|
}
|
2002-04-29 12:20:08 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2004-08-26 13:43:34 +00:00
|
|
|
|
return IMMUTABLE(self);
|
2002-04-29 12:20:08 +00:00
|
|
|
|
}
|
1996-11-24 21:04:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString*) stringByAbbreviatingWithTildeInPath
|
|
|
|
|
{
|
2002-04-29 12:20:08 +00:00
|
|
|
|
NSString *homedir = NSHomeDirectory ();
|
1996-11-24 21:04:24 +00:00
|
|
|
|
|
|
|
|
|
if (![self hasPrefix: homedir])
|
2002-04-29 12:20:08 +00:00
|
|
|
|
{
|
2004-08-26 13:43:34 +00:00
|
|
|
|
return IMMUTABLE(self);
|
2002-04-29 12:20:08 +00:00
|
|
|
|
}
|
|
|
|
|
if ([self length] == [homedir length])
|
|
|
|
|
{
|
|
|
|
|
return @"~";
|
|
|
|
|
}
|
2003-10-08 14:27:11 +00:00
|
|
|
|
return [@"~" stringByAppendingPathComponent:
|
2004-02-02 14:46:48 +00:00
|
|
|
|
[self substringFromIndex: [homedir length]]];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-08-30 08:36:20 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns a string formed by extending or truncating the receiver to
|
|
|
|
|
* newLength characters. If the new string is larger, it is padded
|
|
|
|
|
* by appending characters from padString (appending it as many times
|
|
|
|
|
* as required). The first character from padString to be appended
|
|
|
|
|
* is specified by padIndex.<br />
|
|
|
|
|
*/
|
|
|
|
|
- (NSString*) stringByPaddingToLength: (unsigned int)newLength
|
|
|
|
|
withString: (NSString*)padString
|
|
|
|
|
startingAtIndex: (unsigned int)padIndex
|
|
|
|
|
{
|
|
|
|
|
unsigned length = [self length];
|
|
|
|
|
unsigned padLength;
|
|
|
|
|
|
|
|
|
|
if (padString == nil || [padString isKindOfClass: [NSString class]] == NO)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"%@ - Illegal pad string", NSStringFromSelector(_cmd)];
|
|
|
|
|
}
|
|
|
|
|
padLength = [padString length];
|
|
|
|
|
if (padIndex >= padLength)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSRangeException
|
|
|
|
|
format: @"%@ - pad index larger too big", NSStringFromSelector(_cmd)];
|
|
|
|
|
}
|
|
|
|
|
if (newLength == length)
|
|
|
|
|
{
|
2004-08-26 13:43:34 +00:00
|
|
|
|
return IMMUTABLE(self);
|
2002-08-30 08:36:20 +00:00
|
|
|
|
}
|
|
|
|
|
else if (newLength < length)
|
|
|
|
|
{
|
|
|
|
|
return [self substringToIndex: newLength];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
length = newLength - length; // What we want to add.
|
|
|
|
|
if (length <= (padLength - padIndex))
|
|
|
|
|
{
|
2002-08-30 09:03:33 +00:00
|
|
|
|
NSRange r;
|
|
|
|
|
|
|
|
|
|
r = NSMakeRange(padIndex, length);
|
2002-08-30 08:36:20 +00:00
|
|
|
|
return [self stringByAppendingString:
|
2002-08-30 09:03:33 +00:00
|
|
|
|
[padString substringWithRange: r]];
|
2002-08-30 08:36:20 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSMutableString *m = [self mutableCopy];
|
|
|
|
|
|
|
|
|
|
if (padIndex > 0)
|
|
|
|
|
{
|
2002-08-30 09:03:33 +00:00
|
|
|
|
NSRange r;
|
|
|
|
|
|
|
|
|
|
r = NSMakeRange(padIndex, padLength - padIndex);
|
|
|
|
|
[m appendString: [padString substringWithRange: r]];
|
|
|
|
|
length -= r.length;
|
2002-08-30 08:36:20 +00:00
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* In case we have to append a small string lots of times,
|
|
|
|
|
* we cache the method impllementation to do it.
|
|
|
|
|
*/
|
|
|
|
|
if (length >= padLength)
|
|
|
|
|
{
|
|
|
|
|
void (*appImp)(NSMutableString*, SEL, NSString*);
|
|
|
|
|
SEL appSel;
|
|
|
|
|
|
|
|
|
|
appSel = @selector(appendString:);
|
|
|
|
|
appImp = (void (*)(NSMutableString*, SEL, NSString*))
|
|
|
|
|
[m methodForSelector: appSel];
|
|
|
|
|
while (length >= padLength)
|
|
|
|
|
{
|
|
|
|
|
(*appImp)(m, appSel, padString);
|
|
|
|
|
length -= padLength;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (length > 0)
|
|
|
|
|
{
|
|
|
|
|
[m appendString:
|
|
|
|
|
[padString substringWithRange: NSMakeRange(0, length)]];
|
|
|
|
|
}
|
|
|
|
|
return AUTORELEASE(m);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-07-04 09:25:50 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns a string created by replacing percent escape sequences in the
|
2005-11-06 13:53:40 +00:00
|
|
|
|
* receiver assuming that the resulting data represents characters in
|
2004-07-04 09:25:50 +00:00
|
|
|
|
* the specified encoding.<br />
|
2005-11-06 13:53:40 +00:00
|
|
|
|
* Returns nil if the result is not a string in the specified encoding.
|
2004-07-04 09:25:50 +00:00
|
|
|
|
*/
|
|
|
|
|
- (NSString*) stringByReplacingPercentEscapesUsingEncoding: (NSStringEncoding)e
|
|
|
|
|
{
|
2005-02-22 11:22:44 +00:00
|
|
|
|
NSMutableData *d;
|
2004-07-04 09:25:50 +00:00
|
|
|
|
NSString *s = nil;
|
|
|
|
|
|
|
|
|
|
d = [[self dataUsingEncoding: NSASCIIStringEncoding] mutableCopy];
|
|
|
|
|
if (d != nil)
|
|
|
|
|
{
|
|
|
|
|
unsigned char *p = (unsigned char*)[d mutableBytes];
|
|
|
|
|
unsigned l = [d length];
|
|
|
|
|
unsigned i = 0;
|
|
|
|
|
unsigned j = 0;
|
|
|
|
|
|
|
|
|
|
while (i < l)
|
|
|
|
|
{
|
|
|
|
|
unsigned char t;
|
|
|
|
|
|
|
|
|
|
if ((t = p[i++]) == '%')
|
|
|
|
|
{
|
|
|
|
|
unsigned char c;
|
|
|
|
|
|
|
|
|
|
if (i >= l)
|
|
|
|
|
{
|
|
|
|
|
DESTROY(d);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
t = p[i++];
|
|
|
|
|
|
|
|
|
|
if (isxdigit(t))
|
|
|
|
|
{
|
|
|
|
|
if (t <= '9')
|
|
|
|
|
{
|
|
|
|
|
c = t - '0';
|
|
|
|
|
}
|
|
|
|
|
else if (t <= 'A')
|
|
|
|
|
{
|
|
|
|
|
c = t - 'A' + 10;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
c = t - 'a' + 10;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
DESTROY(d);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
c <<= 4;
|
|
|
|
|
|
|
|
|
|
if (i >= l)
|
|
|
|
|
{
|
|
|
|
|
DESTROY(d);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
t = p[i++];
|
|
|
|
|
if (isxdigit(t))
|
|
|
|
|
{
|
|
|
|
|
if (t <= '9')
|
|
|
|
|
{
|
|
|
|
|
c |= t - '0';
|
|
|
|
|
}
|
|
|
|
|
else if (t <= 'A')
|
|
|
|
|
{
|
|
|
|
|
c |= t - 'A' + 10;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
c |= t - 'a' + 10;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
DESTROY(d);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
p[j++] = c;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
p[j++] = t;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
[d setLength: j];
|
|
|
|
|
s = AUTORELEASE([[NSString alloc] initWithData: d encoding: e]);
|
|
|
|
|
RELEASE(d);
|
|
|
|
|
}
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (NSString*) stringByResolvingSymlinksInPath
|
|
|
|
|
{
|
2005-10-11 19:09:26 +00:00
|
|
|
|
#if defined(__MINGW32__)
|
2004-08-26 13:43:34 +00:00
|
|
|
|
return IMMUTABLE(self);
|
2002-04-29 12:20:08 +00:00
|
|
|
|
#else
|
2000-06-13 14:50:40 +00:00
|
|
|
|
#ifndef MAX_PATH
|
|
|
|
|
#define MAX_PATH 1024
|
|
|
|
|
#endif
|
2005-03-21 12:29:02 +00:00
|
|
|
|
char newBuf[MAX_PATH];
|
2002-05-02 21:22:06 +00:00
|
|
|
|
#ifdef HAVE_REALPATH
|
1998-10-15 13:46:35 +00:00
|
|
|
|
|
2005-03-21 12:29:02 +00:00
|
|
|
|
if (realpath([self fileSystemRepresentation], newBuf) == 0)
|
2004-08-26 13:43:34 +00:00
|
|
|
|
return IMMUTABLE(self);
|
1999-07-12 04:21:05 +00:00
|
|
|
|
#else
|
1999-07-20 09:03:50 +00:00
|
|
|
|
char extra[MAX_PATH];
|
|
|
|
|
char *dest;
|
2004-04-15 12:43:28 +00:00
|
|
|
|
const char *name = [self fileSystemRepresentation];
|
1999-07-20 09:03:50 +00:00
|
|
|
|
const char *start;
|
|
|
|
|
const char *end;
|
|
|
|
|
unsigned num_links = 0;
|
|
|
|
|
|
|
|
|
|
if (name[0] != '/')
|
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
if (!getcwd(newBuf, MAX_PATH))
|
|
|
|
|
{
|
|
|
|
|
return IMMUTABLE(self); /* Couldn't get directory. */
|
|
|
|
|
}
|
|
|
|
|
dest = strchr(newBuf, '\0');
|
1999-07-20 09:03:50 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
1998-10-15 13:46:35 +00:00
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
newBuf[0] = '/';
|
|
|
|
|
dest = &newBuf[1];
|
1999-07-20 09:03:50 +00:00
|
|
|
|
}
|
1998-10-15 13:46:35 +00:00
|
|
|
|
|
1999-07-20 09:03:50 +00:00
|
|
|
|
for (start = end = name; *start; start = end)
|
|
|
|
|
{
|
|
|
|
|
struct stat st;
|
|
|
|
|
int n;
|
|
|
|
|
int len;
|
|
|
|
|
|
|
|
|
|
/* Elide repeated path separators */
|
|
|
|
|
while (*start == '/')
|
2005-03-21 12:29:02 +00:00
|
|
|
|
{
|
|
|
|
|
start++;
|
|
|
|
|
}
|
1999-07-20 09:03:50 +00:00
|
|
|
|
/* Locate end of path component */
|
|
|
|
|
end = start;
|
|
|
|
|
while (*end && *end != '/')
|
2005-03-21 12:29:02 +00:00
|
|
|
|
{
|
|
|
|
|
end++;
|
|
|
|
|
}
|
1999-07-20 09:03:50 +00:00
|
|
|
|
len = end - start;
|
|
|
|
|
if (len == 0)
|
1998-10-15 13:46:35 +00:00
|
|
|
|
{
|
1999-07-20 09:03:50 +00:00
|
|
|
|
break; /* End of path. */
|
1998-10-15 13:46:35 +00:00
|
|
|
|
}
|
1999-07-20 09:03:50 +00:00
|
|
|
|
else if (len == 1 && *start == '.')
|
1998-10-15 13:46:35 +00:00
|
|
|
|
{
|
1999-07-20 09:03:50 +00:00
|
|
|
|
/* Elide '/./' sequence by ignoring it. */
|
1998-10-15 13:46:35 +00:00
|
|
|
|
}
|
1999-07-20 09:03:50 +00:00
|
|
|
|
else if (len == 2 && strncmp(start, "..", len) == 0)
|
1998-10-15 13:46:35 +00:00
|
|
|
|
{
|
1999-07-20 09:03:50 +00:00
|
|
|
|
/*
|
|
|
|
|
* Backup - if we are not at the root, remove the last component.
|
|
|
|
|
*/
|
2005-03-21 12:29:02 +00:00
|
|
|
|
if (dest > &newBuf[1])
|
1999-07-20 09:03:50 +00:00
|
|
|
|
{
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
dest--;
|
|
|
|
|
}
|
|
|
|
|
while (dest[-1] != '/');
|
|
|
|
|
}
|
1998-10-15 13:46:35 +00:00
|
|
|
|
}
|
1999-07-20 09:03:50 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (dest[-1] != '/')
|
2005-03-21 12:29:02 +00:00
|
|
|
|
{
|
|
|
|
|
*dest++ = '/';
|
|
|
|
|
}
|
|
|
|
|
if (&dest[len] >= &newBuf[MAX_PATH])
|
|
|
|
|
{
|
|
|
|
|
return IMMUTABLE(self); /* Resolved name too long. */
|
|
|
|
|
}
|
1999-07-20 09:03:50 +00:00
|
|
|
|
memcpy(dest, start, len);
|
|
|
|
|
dest += len;
|
|
|
|
|
*dest = '\0';
|
|
|
|
|
|
2005-03-21 12:29:02 +00:00
|
|
|
|
if (lstat(newBuf, &st) < 0)
|
|
|
|
|
{
|
|
|
|
|
return IMMUTABLE(self); /* Unable to stat file. */
|
|
|
|
|
}
|
1999-07-20 09:03:50 +00:00
|
|
|
|
if (S_ISLNK(st.st_mode))
|
|
|
|
|
{
|
|
|
|
|
char buf[MAX_PATH];
|
|
|
|
|
|
|
|
|
|
if (++num_links > MAXSYMLINKS)
|
2005-03-21 12:29:02 +00:00
|
|
|
|
{
|
|
|
|
|
return IMMUTABLE(self); /* Too many links. */
|
|
|
|
|
}
|
|
|
|
|
n = readlink(newBuf, buf, MAX_PATH);
|
1999-07-20 09:03:50 +00:00
|
|
|
|
if (n < 0)
|
2005-03-21 12:29:02 +00:00
|
|
|
|
{
|
|
|
|
|
return IMMUTABLE(self); /* Couldn't resolve. */
|
|
|
|
|
}
|
1999-07-20 09:03:50 +00:00
|
|
|
|
buf[n] = '\0';
|
|
|
|
|
|
|
|
|
|
if ((n + strlen(end)) >= MAX_PATH)
|
2005-03-21 12:29:02 +00:00
|
|
|
|
{
|
|
|
|
|
return IMMUTABLE(self); /* Path too long. */
|
|
|
|
|
}
|
1999-07-20 09:03:50 +00:00
|
|
|
|
/*
|
|
|
|
|
* Concatenate the resolved name with the string still to
|
|
|
|
|
* be processed, and start using the result as input.
|
|
|
|
|
*/
|
|
|
|
|
strcat(buf, end);
|
|
|
|
|
strcpy(extra, buf);
|
|
|
|
|
name = end = extra;
|
|
|
|
|
|
|
|
|
|
if (buf[0] == '/')
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* For an absolute link, we start at root again.
|
|
|
|
|
*/
|
2005-03-21 12:29:02 +00:00
|
|
|
|
dest = newBuf + 1;
|
1999-07-20 09:03:50 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Backup - remove the last component.
|
|
|
|
|
*/
|
2005-03-21 12:29:02 +00:00
|
|
|
|
if (dest > newBuf + 1)
|
1999-07-20 09:03:50 +00:00
|
|
|
|
{
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
dest--;
|
|
|
|
|
}
|
|
|
|
|
while (dest[-1] != '/');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
num_links = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
1998-10-15 13:46:35 +00:00
|
|
|
|
}
|
2005-03-21 12:29:02 +00:00
|
|
|
|
if (dest > newBuf + 1 && dest[-1] == '/')
|
|
|
|
|
{
|
|
|
|
|
--dest;
|
|
|
|
|
}
|
1999-07-20 09:03:50 +00:00
|
|
|
|
*dest = '\0';
|
1999-07-12 04:21:05 +00:00
|
|
|
|
#endif
|
2005-03-21 12:29:02 +00:00
|
|
|
|
if (strncmp(newBuf, "/private/", 9) == 0)
|
1999-07-20 09:03:50 +00:00
|
|
|
|
{
|
|
|
|
|
struct stat st;
|
|
|
|
|
|
2005-03-21 12:29:02 +00:00
|
|
|
|
if (lstat(&newBuf[8], &st) == 0)
|
|
|
|
|
{
|
|
|
|
|
strcpy(newBuf, &newBuf[8]);
|
|
|
|
|
}
|
1999-07-20 09:03:50 +00:00
|
|
|
|
}
|
2004-04-15 12:43:28 +00:00
|
|
|
|
return [[NSFileManager defaultManager]
|
2005-03-21 12:29:02 +00:00
|
|
|
|
stringWithFileSystemRepresentation: newBuf length: strlen(newBuf)];
|
2005-10-11 19:09:26 +00:00
|
|
|
|
#endif /* (__MINGW32__) */
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString*) stringByStandardizingPath
|
|
|
|
|
{
|
1999-07-12 04:21:05 +00:00
|
|
|
|
NSMutableString *s;
|
|
|
|
|
NSRange r;
|
2002-03-13 13:46:12 +00:00
|
|
|
|
unichar (*caiImp)(NSString*, SEL, unsigned int);
|
2005-03-21 12:29:02 +00:00
|
|
|
|
unsigned int l = [self length];
|
|
|
|
|
unichar c;
|
|
|
|
|
unsigned root;
|
|
|
|
|
|
|
|
|
|
if (l == 0)
|
|
|
|
|
{
|
|
|
|
|
return @"";
|
|
|
|
|
}
|
|
|
|
|
c = [self characterAtIndex: 0];
|
|
|
|
|
if (c == '~')
|
|
|
|
|
{
|
|
|
|
|
s = AUTORELEASE([[self stringByExpandingTildeInPath] mutableCopy]);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
s = AUTORELEASE([self mutableCopy]);
|
|
|
|
|
}
|
2006-04-09 16:16:07 +00:00
|
|
|
|
|
2006-01-26 02:49:59 +00:00
|
|
|
|
if (GSPathHandlingUnix() == YES)
|
|
|
|
|
{
|
|
|
|
|
[s replaceString: @"\\" withString: @"/"];
|
|
|
|
|
}
|
2006-04-09 16:16:07 +00:00
|
|
|
|
else if (GSPathHandlingWindows() == YES)
|
2006-01-26 02:49:59 +00:00
|
|
|
|
{
|
|
|
|
|
[s replaceString: @"/" withString: @"\\"];
|
|
|
|
|
}
|
|
|
|
|
|
2005-03-21 12:29:02 +00:00
|
|
|
|
l = [s length];
|
|
|
|
|
root = rootOf(s, l);
|
1996-11-24 21:04:24 +00:00
|
|
|
|
|
2000-08-07 22:00:31 +00:00
|
|
|
|
caiImp = (unichar (*)())[s methodForSelector: caiSel];
|
1996-11-24 21:04:24 +00:00
|
|
|
|
|
2005-03-21 12:29:02 +00:00
|
|
|
|
// Condense multiple separator ('/') sequences.
|
|
|
|
|
r = (NSRange){root, l-root};
|
1999-07-12 04:21:05 +00:00
|
|
|
|
while ((r = [s rangeOfCharacterFromSet: pathSeps()
|
|
|
|
|
options: 0
|
2005-03-21 12:29:02 +00:00
|
|
|
|
range: r]).length == 1)
|
1999-07-12 04:21:05 +00:00
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
while (NSMaxRange(r) < l
|
|
|
|
|
&& pathSepMember((*caiImp)(s, caiSel, NSMaxRange(r))) == YES)
|
1999-07-12 04:21:05 +00:00
|
|
|
|
{
|
|
|
|
|
r.length++;
|
|
|
|
|
}
|
2005-03-21 12:29:02 +00:00
|
|
|
|
r.location++;
|
|
|
|
|
r.length--;
|
|
|
|
|
if (r.length > 0)
|
1999-07-20 09:03:50 +00:00
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
[s deleteCharactersInRange: r];
|
|
|
|
|
l -= r.length;
|
1999-07-20 09:03:50 +00:00
|
|
|
|
}
|
2005-03-21 12:29:02 +00:00
|
|
|
|
r.length = l - r.location;
|
|
|
|
|
}
|
|
|
|
|
// Condense ('/./') sequences.
|
|
|
|
|
r = (NSRange){root, l-root};
|
2006-01-26 02:49:59 +00:00
|
|
|
|
while ((r = [s rangeOfString: @"." options: 0 range: r]).length == 1)
|
2005-03-21 12:29:02 +00:00
|
|
|
|
{
|
2006-01-26 02:49:59 +00:00
|
|
|
|
if (r.location > 0
|
|
|
|
|
&& pathSepMember((*caiImp)(s, caiSel, r.location-1)) == YES
|
|
|
|
|
&& (NSMaxRange(r) == l
|
|
|
|
|
|| pathSepMember((*caiImp)(s, caiSel, NSMaxRange(r))) == YES))
|
2002-04-18 07:51:46 +00:00
|
|
|
|
{
|
2006-01-26 02:49:59 +00:00
|
|
|
|
r.length++;
|
2005-03-21 12:29:02 +00:00
|
|
|
|
[s deleteCharactersInRange: r];
|
|
|
|
|
l -= r.length;
|
2002-04-18 07:51:46 +00:00
|
|
|
|
}
|
1999-07-12 04:21:05 +00:00
|
|
|
|
else
|
2002-04-18 07:51:46 +00:00
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
r.location++;
|
2002-04-18 07:51:46 +00:00
|
|
|
|
}
|
2005-03-21 12:29:02 +00:00
|
|
|
|
r.length = l - r.location;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Strip trailing '/' if present.
|
2006-01-26 02:49:59 +00:00
|
|
|
|
if (l > root && pathSepMember([s characterAtIndex: l - 1]) == YES)
|
2005-03-21 12:29:02 +00:00
|
|
|
|
{
|
|
|
|
|
r.length = 1;
|
|
|
|
|
r.location = l - r.length;
|
|
|
|
|
[s deleteCharactersInRange: r];
|
|
|
|
|
l -= r.length;
|
1996-11-24 21:04:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-07-12 04:21:05 +00:00
|
|
|
|
if ([s isAbsolutePath] == NO)
|
2002-04-18 07:51:46 +00:00
|
|
|
|
{
|
|
|
|
|
return s;
|
|
|
|
|
}
|
1999-07-12 04:21:05 +00:00
|
|
|
|
|
2005-03-21 12:29:02 +00:00
|
|
|
|
// Remove leading `/private' if present.
|
2002-02-20 09:28:51 +00:00
|
|
|
|
if ([s hasPrefix: @"/private"])
|
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
[s deleteCharactersInRange: ((NSRange){0,8})];
|
|
|
|
|
l -= 8;
|
2002-02-20 09:28:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-07-20 09:03:50 +00:00
|
|
|
|
/*
|
2000-06-12 05:17:41 +00:00
|
|
|
|
* For absolute paths, we must resolve symbolic links or (on MINGW)
|
1999-07-20 09:03:50 +00:00
|
|
|
|
* remove '/../' sequences and their matching parent directories.
|
|
|
|
|
*/
|
2005-10-11 19:09:26 +00:00
|
|
|
|
#if defined(__MINGW32__)
|
1996-11-24 21:04:24 +00:00
|
|
|
|
/* Condense `/../' */
|
2005-03-21 12:29:02 +00:00
|
|
|
|
r = (NSRange){root, l-root};
|
2006-01-26 02:49:59 +00:00
|
|
|
|
while ((r = [s rangeOfString: @".." options: 0 range: r]).length == 2)
|
1996-11-24 21:04:24 +00:00
|
|
|
|
{
|
2006-01-26 02:49:59 +00:00
|
|
|
|
if (r.location > 0
|
|
|
|
|
&& pathSepMember((*caiImp)(s, caiSel, r.location-1)) == YES
|
|
|
|
|
&& (NSMaxRange(r) == l
|
|
|
|
|
|| pathSepMember((*caiImp)(s, caiSel, NSMaxRange(r))) == YES))
|
1999-01-20 13:28:28 +00:00
|
|
|
|
{
|
2006-01-26 02:49:59 +00:00
|
|
|
|
r.location--;
|
|
|
|
|
r.length++;
|
2005-03-21 12:29:02 +00:00
|
|
|
|
if (r.location > root)
|
1999-07-12 04:21:05 +00:00
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
NSRange r2 = {root, r.location-root};
|
|
|
|
|
|
1999-07-12 04:21:05 +00:00
|
|
|
|
r = [s rangeOfCharacterFromSet: pathSeps()
|
|
|
|
|
options: NSBackwardsSearch
|
|
|
|
|
range: r2];
|
|
|
|
|
if (r.length == 0)
|
2002-02-20 09:28:51 +00:00
|
|
|
|
{
|
|
|
|
|
r = r2;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
r.length = NSMaxRange(r2) - r.location;
|
2002-02-20 09:28:51 +00:00
|
|
|
|
}
|
2005-03-21 12:29:02 +00:00
|
|
|
|
r.length += 3; /* Add the `/..' */
|
1999-07-12 04:21:05 +00:00
|
|
|
|
}
|
|
|
|
|
[s deleteCharactersInRange: r];
|
2005-03-21 12:29:02 +00:00
|
|
|
|
l -= r.length;
|
1999-01-20 13:28:28 +00:00
|
|
|
|
}
|
1999-07-12 04:21:05 +00:00
|
|
|
|
else
|
2002-04-18 07:51:46 +00:00
|
|
|
|
{
|
|
|
|
|
r.location++;
|
|
|
|
|
}
|
2005-03-21 12:29:02 +00:00
|
|
|
|
r.length = l - r.location;
|
1996-11-24 21:04:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
2005-03-21 12:29:02 +00:00
|
|
|
|
return IMMUTABLE(s);
|
1999-07-20 09:03:50 +00:00
|
|
|
|
#else
|
|
|
|
|
return [s stringByResolvingSymlinksInPath];
|
|
|
|
|
#endif
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-08-30 08:36:20 +00:00
|
|
|
|
/**
|
|
|
|
|
* Return a string formed by removing characters from the ends of the
|
|
|
|
|
* receiver. Characters are removed only if they are in aSet.<br />
|
|
|
|
|
* If the string consists entirely of characters in aSet, an empty
|
|
|
|
|
* string is returned.<br />
|
2005-11-06 13:53:40 +00:00
|
|
|
|
* The aSet argument must not be nil.<br />
|
2002-08-30 08:36:20 +00:00
|
|
|
|
*/
|
|
|
|
|
- (NSString*) stringByTrimmingCharactersInSet: (NSCharacterSet*)aSet
|
|
|
|
|
{
|
|
|
|
|
unsigned length = [self length];
|
|
|
|
|
unsigned end = length;
|
|
|
|
|
unsigned start = 0;
|
|
|
|
|
|
|
|
|
|
if (aSet == nil)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"%@ - nil character set argument", NSStringFromSelector(_cmd)];
|
|
|
|
|
}
|
|
|
|
|
if (length > 0)
|
|
|
|
|
{
|
|
|
|
|
unichar (*caiImp)(NSString*, SEL, unsigned int);
|
|
|
|
|
BOOL (*mImp)(id, SEL, unichar);
|
|
|
|
|
unichar letter;
|
|
|
|
|
|
|
|
|
|
caiImp = (unichar (*)())[self methodForSelector: caiSel];
|
|
|
|
|
mImp = (BOOL(*)(id,SEL,unichar)) [aSet methodForSelector: cMemberSel];
|
|
|
|
|
|
|
|
|
|
while (end > 0)
|
|
|
|
|
{
|
|
|
|
|
letter = (*caiImp)(self, caiSel, end-1);
|
|
|
|
|
if ((*mImp)(aSet, cMemberSel, letter) == NO)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
end--;
|
|
|
|
|
}
|
|
|
|
|
while (start < end)
|
|
|
|
|
{
|
|
|
|
|
letter = (*caiImp)(self, caiSel, start);
|
|
|
|
|
if ((*mImp)(aSet, cMemberSel, letter) == NO)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
start++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (start == 0 && end == length)
|
|
|
|
|
{
|
2004-08-26 13:43:34 +00:00
|
|
|
|
return IMMUTABLE(self);
|
2002-08-30 08:36:20 +00:00
|
|
|
|
}
|
|
|
|
|
if (start == end)
|
|
|
|
|
{
|
|
|
|
|
return @"";
|
|
|
|
|
}
|
|
|
|
|
return [self substringFromRange: NSMakeRange(start, end - start)];
|
|
|
|
|
}
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
// private methods for Unicode level 3 implementation
|
1997-05-03 18:05:21 +00:00
|
|
|
|
- (int) _baseLength
|
|
|
|
|
{
|
1999-04-09 17:07:21 +00:00
|
|
|
|
int blen = 0;
|
|
|
|
|
unsigned len = [self length];
|
|
|
|
|
|
|
|
|
|
if (len > 0)
|
|
|
|
|
{
|
2003-01-03 20:14:47 +00:00
|
|
|
|
unsigned int count = 0;
|
2002-03-13 13:46:12 +00:00
|
|
|
|
unichar (*caiImp)(NSString*, SEL, unsigned int);
|
1999-04-09 17:07:21 +00:00
|
|
|
|
|
2000-08-07 22:00:31 +00:00
|
|
|
|
caiImp = (unichar (*)())[self methodForSelector: caiSel];
|
1999-04-09 17:07:21 +00:00
|
|
|
|
while (count < len)
|
2000-08-07 22:00:31 +00:00
|
|
|
|
{
|
|
|
|
|
if (!uni_isnonsp((*caiImp)(self, caiSel, count++)))
|
|
|
|
|
{
|
|
|
|
|
blen++;
|
|
|
|
|
}
|
|
|
|
|
}
|
1999-04-09 17:07:21 +00:00
|
|
|
|
}
|
1997-05-03 18:05:21 +00:00
|
|
|
|
return blen;
|
2002-04-29 12:20:08 +00:00
|
|
|
|
}
|
1997-05-03 18:05:21 +00:00
|
|
|
|
|
1998-01-21 15:09:22 +00:00
|
|
|
|
+ (NSString*) pathWithComponents: (NSArray*)components
|
|
|
|
|
{
|
1999-06-03 10:59:25 +00:00
|
|
|
|
NSString *s;
|
|
|
|
|
unsigned c;
|
|
|
|
|
unsigned i;
|
1998-01-21 15:09:22 +00:00
|
|
|
|
|
1999-06-03 10:59:25 +00:00
|
|
|
|
c = [components count];
|
|
|
|
|
if (c == 0)
|
2002-04-18 07:51:46 +00:00
|
|
|
|
{
|
|
|
|
|
return @"";
|
|
|
|
|
}
|
1999-06-03 10:59:25 +00:00
|
|
|
|
s = [components objectAtIndex: 0];
|
2002-04-29 12:20:08 +00:00
|
|
|
|
if ([s length] == 0)
|
2002-04-18 07:51:46 +00:00
|
|
|
|
{
|
2006-01-26 02:49:59 +00:00
|
|
|
|
s = pathSepString();
|
2002-04-18 07:51:46 +00:00
|
|
|
|
}
|
1999-06-03 10:59:25 +00:00
|
|
|
|
for (i = 1; i < c; i++)
|
|
|
|
|
{
|
|
|
|
|
s = [s stringByAppendingPathComponent: [components objectAtIndex: i]];
|
1998-01-21 15:09:22 +00:00
|
|
|
|
}
|
1999-06-03 10:59:25 +00:00
|
|
|
|
return s;
|
1998-01-21 15:09:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) isAbsolutePath
|
|
|
|
|
{
|
2002-04-29 12:20:08 +00:00
|
|
|
|
unichar c;
|
2005-03-21 12:29:02 +00:00
|
|
|
|
unsigned l = [self length];
|
|
|
|
|
unsigned root;
|
2002-04-29 12:20:08 +00:00
|
|
|
|
|
2005-03-21 12:29:02 +00:00
|
|
|
|
if (l == 0)
|
2001-03-17 11:45:37 +00:00
|
|
|
|
{
|
2005-03-31 19:47:41 +00:00
|
|
|
|
return NO; // Empty string ... relative
|
2001-03-17 11:45:37 +00:00
|
|
|
|
}
|
2002-04-29 12:20:08 +00:00
|
|
|
|
c = [self characterAtIndex: 0];
|
2005-03-21 12:29:02 +00:00
|
|
|
|
if (c == (unichar)'~')
|
2000-09-22 04:20:52 +00:00
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
return YES; // Begins with tilde ... absolute
|
2000-09-22 04:20:52 +00:00
|
|
|
|
}
|
2005-03-31 19:47:41 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Any string beginning with '/' is absolute ... except in windows mode
|
|
|
|
|
* or on windows and not in unix mode.
|
|
|
|
|
*/
|
2006-01-26 02:49:59 +00:00
|
|
|
|
if (c == pathSepChar())
|
2001-03-17 11:45:37 +00:00
|
|
|
|
{
|
2005-10-11 19:09:26 +00:00
|
|
|
|
#if defined(__MINGW32__)
|
2005-03-31 19:47:41 +00:00
|
|
|
|
if (GSPathHandlingUnix() == YES)
|
2005-03-21 12:29:02 +00:00
|
|
|
|
{
|
2005-03-31 19:47:41 +00:00
|
|
|
|
return YES;
|
2005-03-21 12:29:02 +00:00
|
|
|
|
}
|
2005-03-31 19:47:41 +00:00
|
|
|
|
#else
|
|
|
|
|
if (GSPathHandlingWindows() == NO)
|
2005-03-21 12:29:02 +00:00
|
|
|
|
{
|
2005-03-31 19:47:41 +00:00
|
|
|
|
return YES;
|
2005-03-21 12:29:02 +00:00
|
|
|
|
}
|
2005-03-31 19:47:41 +00:00
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Any root over two characters long must be a drive specification with a
|
|
|
|
|
* slash (absolute) or a UNC path (always absolute).
|
|
|
|
|
*/
|
|
|
|
|
root = rootOf(self, l);
|
|
|
|
|
if (root > 2)
|
|
|
|
|
{
|
|
|
|
|
return YES; // UNC or C:/ ... absolute
|
2001-03-17 11:45:37 +00:00
|
|
|
|
}
|
2005-03-31 19:47:41 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* What we have left are roots of the form 'C:' or '\' or a path
|
|
|
|
|
* with no root, or a '/' (in windows mode only sence we already
|
|
|
|
|
* handled a single slash in unix mode) ...
|
|
|
|
|
* all these cases are relative paths.
|
|
|
|
|
*/
|
1999-05-06 05:53:51 +00:00
|
|
|
|
return NO;
|
1998-01-21 15:09:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSArray*) pathComponents
|
|
|
|
|
{
|
2000-03-23 18:57:43 +00:00
|
|
|
|
NSMutableArray *a;
|
|
|
|
|
NSArray *r;
|
2005-03-21 12:29:02 +00:00
|
|
|
|
NSString *s = self;
|
|
|
|
|
unsigned int l = [s length];
|
|
|
|
|
unsigned int root;
|
|
|
|
|
unsigned int i;
|
|
|
|
|
NSRange range;
|
1998-01-21 15:09:22 +00:00
|
|
|
|
|
2005-03-21 12:29:02 +00:00
|
|
|
|
if (l == 0)
|
2001-01-21 16:03:22 +00:00
|
|
|
|
{
|
|
|
|
|
return [NSArray array];
|
|
|
|
|
}
|
2005-03-21 12:29:02 +00:00
|
|
|
|
root = rootOf(s, l);
|
|
|
|
|
a = [[NSMutableArray alloc] initWithCapacity: 8];
|
|
|
|
|
if (root > 0)
|
2000-03-23 18:57:43 +00:00
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
[a addObject: [s substringToIndex: root]];
|
|
|
|
|
}
|
|
|
|
|
i = root;
|
1998-01-21 15:09:22 +00:00
|
|
|
|
|
2005-03-21 12:29:02 +00:00
|
|
|
|
while (i < l)
|
|
|
|
|
{
|
|
|
|
|
range = [s rangeOfCharacterFromSet: pathSeps()
|
|
|
|
|
options: NSLiteralSearch
|
|
|
|
|
range: ((NSRange){i, l - i})];
|
|
|
|
|
if (range.length > 0)
|
2001-05-15 13:35:28 +00:00
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
if (range.location > i)
|
2001-05-15 13:35:28 +00:00
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
[a addObject: [s substringWithRange:
|
|
|
|
|
NSMakeRange(i, range.location - i)]];
|
2001-05-15 13:35:28 +00:00
|
|
|
|
}
|
2005-03-21 12:29:02 +00:00
|
|
|
|
i = NSMaxRange(range);
|
2001-05-15 13:35:28 +00:00
|
|
|
|
}
|
2005-03-21 12:29:02 +00:00
|
|
|
|
else
|
2000-03-23 18:57:43 +00:00
|
|
|
|
{
|
2005-03-21 12:29:02 +00:00
|
|
|
|
[a addObject: [s substringFromIndex: i]];
|
|
|
|
|
i = l;
|
1998-01-21 15:09:22 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2005-03-21 12:29:02 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If the path ended with a path separator which was not already
|
|
|
|
|
* added as part of the root, add it as final component.
|
|
|
|
|
*/
|
|
|
|
|
if (l > root && pathSepMember([s characterAtIndex: l-1]))
|
|
|
|
|
{
|
2006-01-26 02:49:59 +00:00
|
|
|
|
[a addObject: pathSepString()];
|
2005-03-21 12:29:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-03-23 18:57:43 +00:00
|
|
|
|
r = [a copy];
|
|
|
|
|
RELEASE(a);
|
|
|
|
|
return AUTORELEASE(r);
|
1998-01-21 15:09:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSArray*) stringsByAppendingPaths: (NSArray*)paths
|
|
|
|
|
{
|
1999-05-06 14:42:26 +00:00
|
|
|
|
NSMutableArray *a;
|
|
|
|
|
NSArray *r;
|
2001-04-06 22:51:48 +00:00
|
|
|
|
unsigned i, count = [paths count];
|
1998-01-21 15:09:22 +00:00
|
|
|
|
|
1999-05-06 14:42:26 +00:00
|
|
|
|
a = [[NSMutableArray allocWithZone: NSDefaultMallocZone()]
|
2001-04-06 22:51:48 +00:00
|
|
|
|
initWithCapacity: count];
|
|
|
|
|
for (i = 0; i < count; i++)
|
1999-05-06 14:42:26 +00:00
|
|
|
|
{
|
|
|
|
|
NSString *s = [paths objectAtIndex: i];
|
1998-01-21 15:09:22 +00:00
|
|
|
|
|
1999-05-06 14:42:26 +00:00
|
|
|
|
s = [self stringByAppendingPathComponent: s];
|
|
|
|
|
[a addObject: s];
|
1998-01-21 15:09:22 +00:00
|
|
|
|
}
|
1999-05-06 14:42:26 +00:00
|
|
|
|
r = [a copy];
|
1999-06-03 10:59:25 +00:00
|
|
|
|
RELEASE(a);
|
|
|
|
|
return AUTORELEASE(r);
|
1998-01-21 15:09:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns an autoreleased string with given format using the default locale.
|
|
|
|
|
*/
|
1997-05-03 18:05:21 +00:00
|
|
|
|
+ (NSString*) localizedStringWithFormat: (NSString*) format, ...
|
|
|
|
|
{
|
2001-03-20 02:13:19 +00:00
|
|
|
|
va_list ap;
|
|
|
|
|
id ret;
|
|
|
|
|
NSDictionary *dict;
|
|
|
|
|
|
|
|
|
|
va_start(ap, format);
|
|
|
|
|
if (format == nil)
|
|
|
|
|
{
|
|
|
|
|
ret = nil;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2001-11-10 17:31:39 +00:00
|
|
|
|
dict = GSUserDefaultsDictionaryRepresentation();
|
2001-03-20 02:13:19 +00:00
|
|
|
|
ret = AUTORELEASE([[self allocWithZone: NSDefaultMallocZone()]
|
|
|
|
|
initWithFormat: format locale: dict arguments: ap]);
|
|
|
|
|
}
|
|
|
|
|
va_end(ap);
|
|
|
|
|
return ret;
|
1997-05-03 18:05:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Compares this string with aString ignoring case. Convenience for
|
|
|
|
|
* -compare:options:range: with the <code>NSCaseInsensitiveSearch</code>
|
|
|
|
|
* option, in the default locale.
|
|
|
|
|
*/
|
1997-05-03 18:05:21 +00:00
|
|
|
|
- (NSComparisonResult) caseInsensitiveCompare: (NSString*)aString
|
|
|
|
|
{
|
1999-11-26 19:43:43 +00:00
|
|
|
|
return [self compare: aString
|
2002-04-29 12:20:08 +00:00
|
|
|
|
options: NSCaseInsensitiveSearch
|
1999-11-26 19:43:43 +00:00
|
|
|
|
range: ((NSRange){0, [self length]})];
|
1997-05-03 18:05:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* <p>Compares this instance with string, using rules in locale given by dict.
|
|
|
|
|
* mask may be either <code>NSCaseInsensitiveSearch</code> or
|
|
|
|
|
* <code>NSLiteralSearch</code>. The latter requests a literal byte-by-byte
|
|
|
|
|
* comparison, which is fastest but may return inaccurate results in cases
|
|
|
|
|
* where two different composed character sequences may be used to express
|
|
|
|
|
* the same character. compareRange refers to this instance, and should be
|
|
|
|
|
* set to 0..length to compare the whole string.</p>
|
|
|
|
|
*
|
|
|
|
|
* <p>Returns <code>NSOrderedAscending</code>, <code>NSOrderedDescending</code>,
|
|
|
|
|
* or <code>NSOrderedSame</code>, depending on whether this instance occurs
|
|
|
|
|
* before or after string in lexical order, or is equal to it.</p>
|
|
|
|
|
*
|
|
|
|
|
* <p><em><strong>Warning:</strong> this implementation and others in NSString
|
|
|
|
|
* IGNORE the locale.</em></p>
|
|
|
|
|
*/
|
2002-04-29 12:20:08 +00:00
|
|
|
|
- (NSComparisonResult) compare: (NSString *)string
|
|
|
|
|
options: (unsigned int)mask
|
|
|
|
|
range: (NSRange)compareRange
|
2000-09-30 04:54:43 +00:00
|
|
|
|
locale: (NSDictionary *)dict
|
2000-09-12 23:09:50 +00:00
|
|
|
|
{
|
2004-06-22 22:40:40 +00:00
|
|
|
|
// FIXME: This does only a normal compare, ignoring locale
|
2000-09-12 23:09:50 +00:00
|
|
|
|
return [self compare: string
|
|
|
|
|
options: mask
|
|
|
|
|
range: compareRange];
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Compares this instance with string, using rules in the default locale.
|
|
|
|
|
*/
|
2000-09-30 04:54:43 +00:00
|
|
|
|
- (NSComparisonResult) localizedCompare: (NSString *)string
|
2000-09-12 23:09:50 +00:00
|
|
|
|
{
|
2001-11-10 17:31:39 +00:00
|
|
|
|
NSDictionary *dict = GSUserDefaultsDictionaryRepresentation();
|
2001-03-20 02:13:19 +00:00
|
|
|
|
|
2000-09-12 23:09:50 +00:00
|
|
|
|
return [self compare: string
|
2001-03-20 02:13:19 +00:00
|
|
|
|
options: 0
|
|
|
|
|
range: ((NSRange){0, [self length]})
|
|
|
|
|
locale: dict];
|
2000-09-12 23:09:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Compares this instance with string, using rules in the default locale,
|
|
|
|
|
* ignoring case.
|
|
|
|
|
*/
|
2000-09-30 04:54:43 +00:00
|
|
|
|
- (NSComparisonResult) localizedCaseInsensitiveCompare: (NSString *)string
|
2000-09-12 23:09:50 +00:00
|
|
|
|
{
|
2001-11-10 17:31:39 +00:00
|
|
|
|
NSDictionary *dict = GSUserDefaultsDictionaryRepresentation();
|
2001-03-20 02:13:19 +00:00
|
|
|
|
|
2000-09-12 23:09:50 +00:00
|
|
|
|
return [self compare: string
|
2002-04-29 12:20:08 +00:00
|
|
|
|
options: NSCaseInsensitiveSearch
|
2001-03-20 02:13:19 +00:00
|
|
|
|
range: ((NSRange){0, [self length]})
|
|
|
|
|
locale: dict];
|
2000-09-12 23:09:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Writes contents out to file at filename, using the default C string encoding
|
|
|
|
|
* unless this would result in information loss, otherwise straight unicode.
|
|
|
|
|
* The '<code>atomically</code>' option if set will cause the contents to be
|
|
|
|
|
* written to a temp file, which is then closed and renamed to filename. Thus,
|
|
|
|
|
* an incomplete file at filename should never result.
|
|
|
|
|
*/
|
1997-05-03 18:05:21 +00:00
|
|
|
|
- (BOOL) writeToFile: (NSString*)filename
|
1999-11-26 19:43:43 +00:00
|
|
|
|
atomically: (BOOL)useAuxiliaryFile
|
1997-05-03 18:05:21 +00:00
|
|
|
|
{
|
2001-04-12 09:11:31 +00:00
|
|
|
|
id d = [self dataUsingEncoding: _DefaultStringEncoding];
|
|
|
|
|
|
|
|
|
|
if (d == nil)
|
|
|
|
|
{
|
|
|
|
|
d = [self dataUsingEncoding: NSUnicodeStringEncoding];
|
|
|
|
|
}
|
1998-01-08 15:25:59 +00:00
|
|
|
|
return [d writeToFile: filename atomically: useAuxiliaryFile];
|
1997-05-03 18:05:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Writes contents out to anURL, using the default C string encoding
|
|
|
|
|
* unless this would result in information loss, otherwise straight unicode.
|
|
|
|
|
* See [NSURLHandle-writeData:] on which URL types are supported.
|
|
|
|
|
* The '<code>atomically</code>' option is only heeded if the URL is a
|
|
|
|
|
* <code>file://</code> URL; see -writeToFile:atomically: .
|
|
|
|
|
*/
|
2000-09-30 04:54:43 +00:00
|
|
|
|
- (BOOL) writeToURL: (NSURL*)anURL atomically: (BOOL)atomically
|
2000-09-12 23:09:50 +00:00
|
|
|
|
{
|
2001-04-12 09:11:31 +00:00
|
|
|
|
id d = [self dataUsingEncoding: _DefaultStringEncoding];
|
|
|
|
|
|
|
|
|
|
if (d == nil)
|
|
|
|
|
{
|
|
|
|
|
d = [self dataUsingEncoding: NSUnicodeStringEncoding];
|
|
|
|
|
}
|
2000-09-12 23:09:50 +00:00
|
|
|
|
return [d writeToURL: anURL atomically: atomically];
|
|
|
|
|
}
|
|
|
|
|
|
1995-04-03 01:35:42 +00:00
|
|
|
|
/* NSCopying Protocol */
|
|
|
|
|
|
1999-11-26 19:43:43 +00:00
|
|
|
|
- (id) copyWithZone: (NSZone*)zone
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
2003-11-01 11:11:13 +00:00
|
|
|
|
/*
|
|
|
|
|
* Default implementation should not simply retain ... the string may
|
|
|
|
|
* have been initialised with freeWhenDone==NO and not own its
|
|
|
|
|
* characters ... so the code which created it may destroy the memory
|
|
|
|
|
* when it has finished with the original string ... leaving the
|
|
|
|
|
* copy with pointers to invalid data. So, we always copy in full.
|
|
|
|
|
*/
|
|
|
|
|
return [[NSStringClass allocWithZone: zone] initWithString: self];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-07-02 13:26:37 +00:00
|
|
|
|
- (id) mutableCopyWithZone: (NSZone*)zone
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
2000-11-03 10:11:56 +00:00
|
|
|
|
return [[GSMutableStringClass allocWithZone: zone] initWithString: self];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
1995-04-09 01:53:53 +00:00
|
|
|
|
/* NSCoding Protocol */
|
|
|
|
|
|
2000-10-09 04:41:18 +00:00
|
|
|
|
- (void) encodeWithCoder: (NSCoder*)aCoder
|
1995-04-09 01:53:53 +00:00
|
|
|
|
{
|
2004-01-28 07:33:20 +00:00
|
|
|
|
if ([aCoder allowsKeyedCoding])
|
|
|
|
|
{
|
2004-01-28 23:13:55 +00:00
|
|
|
|
[(NSKeyedArchiver*)aCoder _encodePropertyList: self forKey: @"NS.string"];
|
2004-01-28 07:33:20 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
2000-10-09 04:41:18 +00:00
|
|
|
|
{
|
2004-01-28 07:33:20 +00:00
|
|
|
|
unsigned count = [self length];
|
2000-10-09 04:41:18 +00:00
|
|
|
|
|
2004-01-28 07:33:20 +00:00
|
|
|
|
[aCoder encodeValueOfObjCType: @encode(unsigned int) at: &count];
|
|
|
|
|
if (count > 0)
|
|
|
|
|
{
|
|
|
|
|
NSStringEncoding enc = NSUnicodeStringEncoding;
|
|
|
|
|
unichar *chars;
|
2000-10-09 04:41:18 +00:00
|
|
|
|
|
2004-01-28 07:33:20 +00:00
|
|
|
|
[aCoder encodeValueOfObjCType: @encode(NSStringEncoding) at: &enc];
|
|
|
|
|
|
|
|
|
|
chars = NSZoneMalloc(NSDefaultMallocZone(), count*sizeof(unichar));
|
2004-08-22 10:18:52 +00:00
|
|
|
|
[self getCharacters: chars range: ((NSRange){0, count})];
|
2004-01-28 07:33:20 +00:00
|
|
|
|
[aCoder encodeArrayOfObjCType: @encode(unichar)
|
|
|
|
|
count: count
|
|
|
|
|
at: chars];
|
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), chars);
|
|
|
|
|
}
|
2000-10-09 04:41:18 +00:00
|
|
|
|
}
|
1995-04-09 01:53:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-10-09 04:41:18 +00:00
|
|
|
|
- (id) initWithCoder: (NSCoder*)aCoder
|
1995-04-09 01:53:53 +00:00
|
|
|
|
{
|
2004-01-27 21:51:33 +00:00
|
|
|
|
if ([aCoder allowsKeyedCoding])
|
|
|
|
|
{
|
2005-02-22 11:22:44 +00:00
|
|
|
|
NSString *string = (NSString*)[(NSKeyedUnarchiver*)aCoder
|
2004-01-28 23:13:55 +00:00
|
|
|
|
_decodePropertyListForKey: @"NS.string"];
|
2001-04-11 16:51:17 +00:00
|
|
|
|
|
2004-01-27 21:51:33 +00:00
|
|
|
|
self = [self initWithString: string];
|
|
|
|
|
}
|
|
|
|
|
else
|
2000-10-09 04:41:18 +00:00
|
|
|
|
{
|
2004-01-27 21:51:33 +00:00
|
|
|
|
unsigned count;
|
|
|
|
|
|
|
|
|
|
[aCoder decodeValueOfObjCType: @encode(unsigned int) at: &count];
|
2002-04-29 12:20:08 +00:00
|
|
|
|
|
2004-01-27 21:51:33 +00:00
|
|
|
|
if (count > 0)
|
|
|
|
|
{
|
|
|
|
|
NSStringEncoding enc;
|
|
|
|
|
NSZone *zone;
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2004-01-27 21:51:33 +00:00
|
|
|
|
[aCoder decodeValueOfObjCType: @encode(NSStringEncoding) at: &enc];
|
2000-10-09 04:41:18 +00:00
|
|
|
|
#if GS_WITH_GC
|
2004-01-27 21:51:33 +00:00
|
|
|
|
zone = GSAtomicMallocZone();
|
2000-10-09 04:41:18 +00:00
|
|
|
|
#else
|
2004-01-27 21:51:33 +00:00
|
|
|
|
zone = GSObjCZone(self);
|
2000-10-09 04:41:18 +00:00
|
|
|
|
#endif
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2004-01-27 21:51:33 +00:00
|
|
|
|
if (enc == NSUnicodeStringEncoding)
|
|
|
|
|
{
|
|
|
|
|
unichar *chars;
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2004-01-27 21:51:33 +00:00
|
|
|
|
chars = NSZoneMalloc(zone, count*sizeof(unichar));
|
|
|
|
|
[aCoder decodeArrayOfObjCType: @encode(unichar)
|
|
|
|
|
count: count
|
|
|
|
|
at: chars];
|
|
|
|
|
self = [self initWithCharactersNoCopy: chars
|
|
|
|
|
length: count
|
|
|
|
|
freeWhenDone: YES];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unsigned char *chars;
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2006-05-20 13:24:53 +00:00
|
|
|
|
chars = NSZoneMalloc(zone, count+1);
|
2004-01-27 21:51:33 +00:00
|
|
|
|
[aCoder decodeArrayOfObjCType: @encode(unsigned char)
|
2006-05-20 13:24:53 +00:00
|
|
|
|
count: count
|
2004-01-27 21:51:33 +00:00
|
|
|
|
at: chars];
|
2006-05-20 13:24:53 +00:00
|
|
|
|
self = [self initWithBytesNoCopy: chars
|
|
|
|
|
length: count
|
|
|
|
|
encoding: enc
|
|
|
|
|
freeWhenDone: YES];
|
2004-01-27 21:51:33 +00:00
|
|
|
|
}
|
2000-10-09 04:41:18 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
2004-01-27 21:51:33 +00:00
|
|
|
|
{
|
2006-05-20 13:24:53 +00:00
|
|
|
|
self = [self initWithBytesNoCopy: ""
|
|
|
|
|
length: 0
|
|
|
|
|
encoding: NSASCIIStringEncoding
|
|
|
|
|
freeWhenDone: NO];
|
2000-10-09 04:41:18 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1999-07-02 13:26:37 +00:00
|
|
|
|
return self;
|
1995-04-09 01:53:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-12-18 17:05:44 +00:00
|
|
|
|
- (Class) classForCoder
|
|
|
|
|
{
|
2000-10-23 06:18:03 +00:00
|
|
|
|
return NSStringClass;
|
1998-12-18 17:05:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) replacementObjectForPortCoder: (NSPortCoder*)aCoder
|
|
|
|
|
{
|
|
|
|
|
if ([aCoder isByref] == NO)
|
|
|
|
|
return self;
|
|
|
|
|
return [super replacementObjectForPortCoder: aCoder];
|
|
|
|
|
}
|
|
|
|
|
|
2002-11-11 10:18:49 +00:00
|
|
|
|
/**
|
|
|
|
|
* <p>Attempts to interpret the receiver as a <em>property list</em>
|
|
|
|
|
* and returns the result. If the receiver does not contain a
|
|
|
|
|
* string representation of a <em>property list</em> then the method
|
|
|
|
|
* returns nil.
|
|
|
|
|
* </p>
|
2004-07-03 09:08:24 +00:00
|
|
|
|
* <p>Containers (arrays and dictionaries) are decoded as <em>mutable</em>
|
|
|
|
|
* objects.
|
|
|
|
|
* </p>
|
2002-11-11 10:18:49 +00:00
|
|
|
|
* <p>There are three readable <em>property list</em> storage formats -
|
|
|
|
|
* The binary format used by [NSSerializer] does not concern us here,
|
|
|
|
|
* but there are two 'human readable' formats, the <em>traditional</em>
|
|
|
|
|
* OpenStep format (which is extended in GNUstep) and the <em>XML</em> format.
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>The [NSArray-descriptionWithLocale:indent:] and
|
|
|
|
|
* [NSDictionary-descriptionWithLocale:indent:] methods
|
|
|
|
|
* both generate strings containing traditional style <em>property lists</em>,
|
|
|
|
|
* but [NSArray-writeToFile:atomically:] and
|
|
|
|
|
* [NSDictionary-writeToFile:atomically:] generate either traditional or
|
|
|
|
|
* XML style <em>property lists</em> depending on the value of the
|
|
|
|
|
* GSMacOSXCompatible and NSWriteOldStylePropertyLists user defaults.<br />
|
|
|
|
|
* If GSMacOSXCompatible is YES then XML <em>property lists</em> are
|
|
|
|
|
* written unless NSWriteOldStylePropertyLists is also YES.<br />
|
|
|
|
|
* By default GNUstep writes old style data and always supports reading of
|
|
|
|
|
* either style.
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>The traditional format is more compact and more easily readable by
|
|
|
|
|
* people, but (without the GNUstep extensions) cannot represent date and
|
|
|
|
|
* number objects (except as strings). The XML format is more verbose and
|
|
|
|
|
* less readable, but can be fed into modern XML tools and thus used to
|
|
|
|
|
* pass data to non-OpenStep applications more readily.
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>The traditional format is strictly ascii encoded, with any unicode
|
|
|
|
|
* characters represented by escape sequences. The XML format is encoded
|
|
|
|
|
* as UTF8 data.
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>Both the traditional format and the XML format permit comments to be
|
|
|
|
|
* placed in <em>property list</em> documents. In traditional format the
|
2004-06-22 22:40:40 +00:00
|
|
|
|
* comment notations used in Objective-C programming are supported, while
|
2002-11-11 10:18:49 +00:00
|
|
|
|
* in XML format, the standard SGML comment sequences are used.
|
|
|
|
|
* </p>
|
2004-06-22 22:40:40 +00:00
|
|
|
|
* <p>See the documentation for [NSPropertyListSerialization] for more
|
|
|
|
|
* information on what a property list is.</p>
|
2002-11-11 10:18:49 +00:00
|
|
|
|
*/
|
1999-02-04 13:49:27 +00:00
|
|
|
|
- (id) propertyList
|
|
|
|
|
{
|
2004-07-02 10:37:54 +00:00
|
|
|
|
NSData *data;
|
|
|
|
|
id result = nil;
|
|
|
|
|
NSPropertyListFormat format;
|
|
|
|
|
NSString *error = nil;
|
|
|
|
|
|
|
|
|
|
if ([self length] == 0)
|
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
2004-07-30 21:36:36 +00:00
|
|
|
|
data = [self dataUsingEncoding: NSUTF8StringEncoding];
|
|
|
|
|
NSAssert(data, @"Couldn't get utf8 data from string.");
|
2004-07-02 10:37:54 +00:00
|
|
|
|
|
|
|
|
|
result = [NSPropertyListSerialization
|
|
|
|
|
propertyListFromData: data
|
2004-07-03 09:02:49 +00:00
|
|
|
|
mutabilityOption: NSPropertyListMutableContainers
|
2004-07-02 10:37:54 +00:00
|
|
|
|
format: &format
|
|
|
|
|
errorDescription: &error];
|
|
|
|
|
|
|
|
|
|
if (result == nil)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSGenericException
|
|
|
|
|
format: @"Parse failed - %@", error];
|
|
|
|
|
}
|
|
|
|
|
return result;
|
1999-02-04 13:49:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-11-11 10:18:49 +00:00
|
|
|
|
/**
|
|
|
|
|
* <p>Reads a <em>property list</em> (see -propertyList) from a simplified
|
|
|
|
|
* file format. This format is a traditional style property list file
|
|
|
|
|
* containing a single dictionary, but with the leading '{' and trailing
|
|
|
|
|
* '}' characters omitted.
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>That is to say, the file contains only semicolon separated key/value
|
|
|
|
|
* pairs (and optionally comments). As a convenience, it is possible to
|
|
|
|
|
* omit the equals sign and the value, so an entry consists of a key string
|
|
|
|
|
* followed by a semicolon. In this case, the value for that key is
|
|
|
|
|
* assumed to be an empty string.
|
|
|
|
|
* </p>
|
2005-02-22 11:22:44 +00:00
|
|
|
|
* <example>
|
2002-11-11 10:18:49 +00:00
|
|
|
|
* // Strings file entries follow -
|
|
|
|
|
* key1 = " a string value";
|
|
|
|
|
* key2; // This key has an empty string as a value.
|
|
|
|
|
* "Another key" = "a longer string value for th third key";
|
2005-02-22 11:22:44 +00:00
|
|
|
|
* </example>
|
2002-11-11 10:18:49 +00:00
|
|
|
|
*/
|
1999-02-04 13:49:27 +00:00
|
|
|
|
- (NSDictionary*) propertyListFromStringsFileFormat
|
|
|
|
|
{
|
2004-07-02 10:37:54 +00:00
|
|
|
|
extern id GSPropertyListFromStringsFormat(NSString *string);
|
|
|
|
|
|
2000-10-23 11:44:34 +00:00
|
|
|
|
return GSPropertyListFromStringsFormat(self);
|
1999-02-04 13:49:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
1995-04-03 01:35:42 +00:00
|
|
|
|
@end
|
|
|
|
|
|
2002-08-30 12:30:50 +00:00
|
|
|
|
/**
|
2004-06-22 22:40:40 +00:00
|
|
|
|
* This is the mutable form of the [NSString] class.
|
2002-08-30 12:30:50 +00:00
|
|
|
|
*/
|
1995-04-03 01:35:42 +00:00
|
|
|
|
@implementation NSMutableString
|
|
|
|
|
|
1999-07-02 13:26:37 +00:00
|
|
|
|
+ (id) allocWithZone: (NSZone*)z
|
1995-11-19 20:29:39 +00:00
|
|
|
|
{
|
2000-10-23 06:18:03 +00:00
|
|
|
|
if (self == NSMutableStringClass)
|
2000-08-07 22:00:31 +00:00
|
|
|
|
{
|
2000-11-03 10:11:56 +00:00
|
|
|
|
return NSAllocateObject(GSMutableStringClass, 0, z);
|
2000-08-07 22:00:31 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return NSAllocateObject(self, 0, z);
|
|
|
|
|
}
|
1995-11-19 20:29:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
1995-04-03 01:35:42 +00:00
|
|
|
|
// Creating Temporary Strings
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Constructs an empty string.
|
|
|
|
|
*/
|
2005-07-08 11:48:37 +00:00
|
|
|
|
+ (id) string
|
1999-12-01 19:36:20 +00:00
|
|
|
|
{
|
2000-11-03 10:11:56 +00:00
|
|
|
|
return AUTORELEASE([[GSMutableStringClass allocWithZone:
|
1999-12-01 19:36:20 +00:00
|
|
|
|
NSDefaultMallocZone()] initWithCapacity: 0]);
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Constructs an empty string with initial buffer size of capacity.
|
|
|
|
|
*/
|
2002-03-13 13:46:12 +00:00
|
|
|
|
+ (NSMutableString*) stringWithCapacity: (unsigned int)capacity
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
2000-11-03 10:11:56 +00:00
|
|
|
|
return AUTORELEASE([[GSMutableStringClass allocWithZone:
|
1999-12-01 19:36:20 +00:00
|
|
|
|
NSDefaultMallocZone()] initWithCapacity: capacity]);
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Create a string of unicode characters.
|
|
|
|
|
*/
|
|
|
|
|
// Inefficient implementation.
|
2005-07-08 11:48:37 +00:00
|
|
|
|
+ (id) stringWithCharacters: (const unichar*)characters
|
|
|
|
|
length: (unsigned int)length
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
2000-11-03 10:11:56 +00:00
|
|
|
|
return AUTORELEASE([[GSMutableStringClass allocWithZone:
|
1999-12-01 19:36:20 +00:00
|
|
|
|
NSDefaultMallocZone()] initWithCharacters: characters length: length]);
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Load contents of file at path into a new string. Will interpret file as
|
|
|
|
|
* containing direct unicode if it begins with the unicode byte order mark,
|
|
|
|
|
* else converts to unicode using default C string encoding.
|
|
|
|
|
*/
|
1999-12-01 19:36:20 +00:00
|
|
|
|
+ (id) stringWithContentsOfFile: (NSString *)path
|
|
|
|
|
{
|
2000-11-03 10:11:56 +00:00
|
|
|
|
return AUTORELEASE([[GSMutableStringClass allocWithZone:
|
1999-12-01 19:36:20 +00:00
|
|
|
|
NSDefaultMallocZone()] initWithContentsOfFile: path]);
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Create a string based on the given C (char[]) string, which should be
|
|
|
|
|
* null-terminated and encoded in the default C string encoding. (Characters
|
|
|
|
|
* will be converted to unicode representation internally.)
|
|
|
|
|
*/
|
2005-07-08 11:48:37 +00:00
|
|
|
|
+ (id) stringWithCString: (const char*)byteString
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
2000-11-03 10:11:56 +00:00
|
|
|
|
return AUTORELEASE([[GSMutableStringClass allocWithZone:
|
1999-06-03 10:59:25 +00:00
|
|
|
|
NSDefaultMallocZone()] initWithCString: byteString]);
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Create a string based on the given C (char[]) string, which may contain
|
|
|
|
|
* null bytes and should be encoded in the default C string encoding.
|
|
|
|
|
* (Characters will be converted to unicode representation internally.)
|
|
|
|
|
*/
|
2005-07-08 11:48:37 +00:00
|
|
|
|
+ (id) stringWithCString: (const char*)byteString
|
|
|
|
|
length: (unsigned int)length
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
2000-11-03 10:11:56 +00:00
|
|
|
|
return AUTORELEASE([[GSMutableStringClass allocWithZone:
|
1999-06-03 10:59:25 +00:00
|
|
|
|
NSDefaultMallocZone()] initWithCString: byteString length: length]);
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Creates a new string using C printf-style formatting. First argument should
|
|
|
|
|
* be a constant format string, like '<code>@"float val = %f"</code>', remaining
|
|
|
|
|
* arguments should be the variables to print the values of, comma-separated.
|
|
|
|
|
*/
|
2005-07-08 11:48:37 +00:00
|
|
|
|
+ (id) stringWithFormat: (NSString*)format, ...
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
|
|
|
|
va_list ap;
|
|
|
|
|
va_start(ap, format);
|
1999-05-06 14:42:26 +00:00
|
|
|
|
self = [super stringWithFormat: format arguments: ap];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
va_end(ap);
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-07 05:43:20 +00:00
|
|
|
|
/** <init/> <override-subclass />
|
|
|
|
|
* Constructs an empty string with initial buffer size of capacity.<br />
|
|
|
|
|
* Calls -init (which does nothing but maintain MacOS-X compatibility),
|
|
|
|
|
* and needs to be re-implemented in subclasses in order to have all
|
|
|
|
|
* other initialisers work.
|
2004-06-22 22:40:40 +00:00
|
|
|
|
*/
|
2002-03-13 13:46:12 +00:00
|
|
|
|
- (id) initWithCapacity: (unsigned int)capacity
|
1997-05-03 18:05:21 +00:00
|
|
|
|
{
|
2004-09-07 05:43:20 +00:00
|
|
|
|
self = [self init];
|
1997-05-03 18:05:21 +00:00
|
|
|
|
return self;
|
|
|
|
|
}
|
1995-04-03 01:35:42 +00:00
|
|
|
|
|
2000-10-31 18:11:30 +00:00
|
|
|
|
- (id) initWithCharactersNoCopy: (unichar*)chars
|
2002-03-13 13:46:12 +00:00
|
|
|
|
length: (unsigned int)length
|
2000-10-31 18:11:30 +00:00
|
|
|
|
freeWhenDone: (BOOL)flag
|
|
|
|
|
{
|
|
|
|
|
if ((self = [self initWithCapacity: length]) != nil && length > 0)
|
|
|
|
|
{
|
|
|
|
|
NSString *tmp;
|
|
|
|
|
|
|
|
|
|
tmp = [NSString allocWithZone: NSDefaultMallocZone()];
|
|
|
|
|
tmp = [tmp initWithCharactersNoCopy: chars
|
|
|
|
|
length: length
|
|
|
|
|
freeWhenDone: flag];
|
|
|
|
|
[self replaceCharactersInRange: NSMakeRange(0,0) withString: tmp];
|
|
|
|
|
RELEASE(tmp);
|
|
|
|
|
}
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) initWithCStringNoCopy: (char*)chars
|
2002-03-13 13:46:12 +00:00
|
|
|
|
length: (unsigned int)length
|
2000-10-31 18:11:30 +00:00
|
|
|
|
freeWhenDone: (BOOL)flag
|
|
|
|
|
{
|
|
|
|
|
if ((self = [self initWithCapacity: length]) != nil && length > 0)
|
|
|
|
|
{
|
|
|
|
|
NSString *tmp;
|
|
|
|
|
|
|
|
|
|
tmp = [NSString allocWithZone: NSDefaultMallocZone()];
|
|
|
|
|
tmp = [tmp initWithCStringNoCopy: chars
|
|
|
|
|
length: length
|
|
|
|
|
freeWhenDone: flag];
|
|
|
|
|
[self replaceCharactersInRange: NSMakeRange(0,0) withString: tmp];
|
|
|
|
|
RELEASE(tmp);
|
|
|
|
|
}
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
1995-04-03 01:35:42 +00:00
|
|
|
|
// Modify A String
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Modifies this string by appending aString.
|
|
|
|
|
*/
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (void) appendString: (NSString*)aString
|
|
|
|
|
{
|
1998-01-26 14:18:18 +00:00
|
|
|
|
NSRange aRange;
|
|
|
|
|
|
|
|
|
|
aRange.location = [self length];
|
|
|
|
|
aRange.length = 0;
|
|
|
|
|
[self replaceCharactersInRange: aRange withString: aString];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Modifies this string by appending string described by given format.
|
|
|
|
|
*/
|
|
|
|
|
// Inefficient implementation.
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (void) appendFormat: (NSString*)format, ...
|
|
|
|
|
{
|
2001-02-02 06:14:42 +00:00
|
|
|
|
va_list ap;
|
|
|
|
|
id tmp;
|
|
|
|
|
|
1995-04-03 01:35:42 +00:00
|
|
|
|
va_start(ap, format);
|
2001-02-02 06:14:42 +00:00
|
|
|
|
tmp = [[NSStringClass allocWithZone: NSDefaultMallocZone()]
|
1999-05-06 14:42:26 +00:00
|
|
|
|
initWithFormat: format arguments: ap];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
va_end(ap);
|
1999-05-06 14:42:26 +00:00
|
|
|
|
[self appendString: tmp];
|
1999-06-03 10:59:25 +00:00
|
|
|
|
RELEASE(tmp);
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2000-10-09 04:41:18 +00:00
|
|
|
|
- (Class) classForCoder
|
|
|
|
|
{
|
2000-10-23 06:18:03 +00:00
|
|
|
|
return NSMutableStringClass;
|
2000-10-09 04:41:18 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Modifies this instance by deleting specified range of characters.
|
|
|
|
|
*/
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (void) deleteCharactersInRange: (NSRange)range
|
|
|
|
|
{
|
1999-05-06 14:42:26 +00:00
|
|
|
|
[self replaceCharactersInRange: range withString: nil];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Modifies this instance by inserting aString at loc.
|
|
|
|
|
*/
|
2002-03-13 13:46:12 +00:00
|
|
|
|
- (void) insertString: (NSString*)aString atIndex: (unsigned int)loc
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
1997-12-08 20:04:16 +00:00
|
|
|
|
NSRange range = {loc, 0};
|
1999-05-06 14:42:26 +00:00
|
|
|
|
[self replaceCharactersInRange: range withString: aString];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Modifies this instance by deleting characters in range and then inserting
|
|
|
|
|
* aString at its beginning.
|
|
|
|
|
*/
|
2002-04-29 12:20:08 +00:00
|
|
|
|
- (void) replaceCharactersInRange: (NSRange)range
|
1999-11-26 19:43:43 +00:00
|
|
|
|
withString: (NSString*)aString
|
1995-04-03 01:35:42 +00:00
|
|
|
|
{
|
1999-05-06 14:42:26 +00:00
|
|
|
|
[self subclassResponsibility: _cmd];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2003-01-26 19:50:42 +00:00
|
|
|
|
/**
|
|
|
|
|
* Replaces all occurrences of the replace string with the by string,
|
|
|
|
|
* for those cases where the entire replace string lies within the
|
|
|
|
|
* specified searchRange value.<br />
|
|
|
|
|
* The value of opts determines the direction of the search is and
|
2005-11-06 13:53:40 +00:00
|
|
|
|
* whether only leading/trailing occurrences (anchored search) of
|
2003-01-26 19:50:42 +00:00
|
|
|
|
* replace are substituted.<br />
|
|
|
|
|
* Raises NSInvalidArgumentException if either string argument is nil.<br />
|
|
|
|
|
* Raises NSRangeException if part of searchRange is beyond the end
|
|
|
|
|
* of the receiver.
|
|
|
|
|
*/
|
|
|
|
|
- (unsigned int) replaceOccurrencesOfString: (NSString*)replace
|
|
|
|
|
withString: (NSString*)by
|
|
|
|
|
options: (unsigned int)opts
|
|
|
|
|
range: (NSRange)searchRange
|
|
|
|
|
{
|
|
|
|
|
NSRange range;
|
|
|
|
|
unsigned int count = 0;
|
|
|
|
|
|
|
|
|
|
if (replace == nil)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"%@ nil search string", NSStringFromSelector(_cmd)];
|
|
|
|
|
}
|
|
|
|
|
if (by == nil)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"%@ nil replace string", NSStringFromSelector(_cmd)];
|
|
|
|
|
}
|
|
|
|
|
range = [self rangeOfString: replace options: opts range: searchRange];
|
|
|
|
|
|
|
|
|
|
if (range.length > 0)
|
|
|
|
|
{
|
|
|
|
|
unsigned byLen = [by length];
|
|
|
|
|
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
count++;
|
|
|
|
|
[self replaceCharactersInRange: range
|
|
|
|
|
withString: by];
|
|
|
|
|
if ((opts & NSBackwardsSearch) == NSBackwardsSearch)
|
|
|
|
|
{
|
|
|
|
|
searchRange.length = range.location - searchRange.location;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unsigned int newEnd;
|
|
|
|
|
|
|
|
|
|
newEnd = NSMaxRange(searchRange) + byLen - range.length;
|
|
|
|
|
searchRange.location = range.location + byLen;
|
|
|
|
|
searchRange.length = newEnd - searchRange.location;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
range = [self rangeOfString: replace
|
|
|
|
|
options: opts
|
|
|
|
|
range: searchRange];
|
|
|
|
|
}
|
|
|
|
|
while (range.length > 0);
|
|
|
|
|
}
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Modifies this instance by replacing contents with those of aString.
|
|
|
|
|
*/
|
1995-04-03 01:35:42 +00:00
|
|
|
|
- (void) setString: (NSString*)aString
|
|
|
|
|
{
|
1997-12-08 20:04:16 +00:00
|
|
|
|
NSRange range = {0, [self length]};
|
1999-05-06 14:42:26 +00:00
|
|
|
|
[self replaceCharactersInRange: range withString: aString];
|
1995-04-03 01:35:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
2002-08-30 12:30:50 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* GNUstep specific (non-standard) additions to the NSMutableString class.
|
|
|
|
|
* The methods in this category are not available in MacOS-X
|
|
|
|
|
*/
|
2000-10-23 06:18:03 +00:00
|
|
|
|
@implementation NSMutableString (GNUstep)
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-09-15 18:26:56 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns a proxy to the receiver which will allow access to the
|
|
|
|
|
* receiver as an NSString, but which will not allow any of the
|
|
|
|
|
* extra NSMutableString methods to be used. You can use this method
|
|
|
|
|
* to provide other code with read-only access to a mutable string
|
|
|
|
|
* you own.
|
|
|
|
|
*/
|
|
|
|
|
- (NSString*) immutableProxy
|
|
|
|
|
{
|
|
|
|
|
if ([self isKindOfClass: GSMutableStringClass])
|
|
|
|
|
{
|
|
|
|
|
return AUTORELEASE([[GSImmutableString alloc] initWithString: self]);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return AUTORELEASE([[NSImmutableString alloc] initWithString: self]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1999-02-13 00:50:41 +00:00
|
|
|
|
@end
|
|
|
|
|
|