improve handling of user domain paths

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@30998 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
rfm 2010-07-19 08:34:29 +00:00
parent 3b00aacbfe
commit 8b1d3e61ba
3 changed files with 240 additions and 83 deletions

View file

@ -1,3 +1,15 @@
2010-07-19 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSPathUtilities.m: User domain handling improvements.
Match gnustep-make in allowing absolute paths to be specified for the
user domain directories rather than always treating user domain paths
as being within the user's home directory.
Also, add support for simple field substitution into the path:
'%u' --> user name
'%i' --> user id
'%%' --> '%'
* Documentation/Base.gsdoc: Document the new behavior.
2010-07-19 Niels Grewe <niels.grewe@halbordnung.de>
* Headers/Additions/GNUstepBase/GSConfig.h: Define GS_USE_ICU when

View file

@ -517,39 +517,90 @@ notice and this notice are preserved.
of no name.<br />
System paths are defined by the following:
</p>
<deflist>
<term>GNUSTEP_SYSTEM_ROOT</term>
<desc>
Obsolete.
Used to specify the GNUstep system root directory ... all
system libraries, tools, applications, headers, resources
in general are located relative to this.
</desc>
<term>GNUSTEP_NETWORK_ROOT</term>
<desc>
Obsolete. Used to specify the GNUstep root directory for local
(non-system) resources that are intended to be shared
across a local network. Typically this is an NFS exported
directory shared by many machines. It provides an
alternative to GNUSTEP_LOCAL_ROOT but is usually defined
to the same value.
</desc>
<term>GNUSTEP_LOCAL_ROOT</term>
<desc>
Obsolete. Used to specify the GNUstep root directory for local
(non-system) resources. Typically all locally produced
or contributed software is installed relative to this.
</desc>
</deflist>
<deflist>
<term>GNUSTEP_SYSTEM_APPS</term>
<desc>This is where System GUI Applications get installed.<br />
Traditionally it is /usr/GNUstep/System/Applications.
</desc>
<term>GNUSTEP_SYSTEM_ADMIN_APPS</term>
<desc>This is where System GUI Applications that only the
Administrator can use get installed.<br />
Traditionally it is /usr/GNUstep/System/Applications/Admin.
</desc>
<term>GNUSTEP_SYSTEM_WEB_APPS</term>
<desc>This is where System Web Applications (GSWeb, SOPE) get
installed.<br />
Traditionally it is /usr/GNUstep/System/Library/WebApplications.
</desc>
<term>GNUSTEP_SYSTEM_TOOLS</term>
<desc>This is where System Command-Line Tools get installed.<br />
Traditionally it is /usr/GNUstep/System/Tools.
</desc>
<term>GNUSTEP_SYSTEM_ADMIN_TOOLS</term>
<desc>This is where System Command-Line Tools that only the
Administrator can use get installed. Important: this
should not be in the PATH of normal users.<br />
Traditionally it is /usr/GNUstep/System/Tools/Admin.
</desc>
<term>GNUSTEP_SYSTEM_LIBRARY</term>
<desc>This is where System resources get installed.
This directory will contain a lot of executable code
since *step traditionally likes to
bundle executables and resources together.<br />
Traditionally it is /usr/GNUstep/System/Library.
</desc>
<term>GNUSTEP_SYSTEM_HEADERS</term>
<desc>This is where System headers get installed. They are the
library .h headers.<br />
Traditionally it is /usr/GNUstep/System/Library/Headers.
</desc>
<term>GNUSTEP_SYSTEM_LIBRARIES</term>
<desc>This is where System libraries get installed.
By libraries we mean the shared/static object files that
you can link into programs.<br />
Traditionally it is /usr/GNUstep/System/Library/Libraries.
</desc>
<term>GNUSTEP_SYSTEM_DOC</term>
<desc>This is where System documentation get installed.
This is known not to contain any executable, so we keep
it separate.<br />
Traditionally it is /usr/GNUstep/System/Library/Documentation.
</desc>
<term>GNUSTEP_SYSTEM_DOC_MAN</term>
<desc>This is where System man pages get installed.<br />
Traditionally it is
/usr/GNUstep/System/Library/Documentation/man.
</desc>
<term>GNUSTEP_SYSTEM_DOC_INFO</term>
<desc>This is where System info pages get installed.<br />
Traditionally it is
/usr/GNUstep/System/Library/Documentation/info.
</desc>
</deflist>
<p>
Paths for each user are defined by the following:
In addition to the above SYSTEM domain paths, there are
corresponding LOCAL, NETWORK, and USER domain paths (with the
same names except for replacing 'SYSTEM' with 'LOCAL', 'NETWORK',
or 'USER'.<br />
All these paths must be absolute, except for the USER domain
paths which, if not absolute, are considered to be with the
user's home directory.<br />
NB. as a special case a path may begin with './' or '../' when
it is to be resolved to an absolute path relative to the
location of the GNUstep configuration file.
So while such paths appear to be relative, they actually produce
absolute locations at runtime since the location of the
configuration file is known.<br />
Finally, for paths in the USER domain only, a limited substitution
into the path is performed at runtime as follows:<br />
'%u' is replaced by the user name<br />
'%i' is replaced by the user ID<br />
'%%' is replaced by a single '%'<br />
</p>
<p>
Other paths for each user are defined by the following:
</p>
<deflist>
<term>GNUSTEP_USER_DIR</term>
<desc>Obsolete.
Path for user specific GNUstep resources (eg. 'GNUstep').
Relative to the user's home directory.
</desc>
<term>GNUSTEP_USER_CONFIG_FILE</term>
<desc>Name of user configuration file (eg. '.GNUstep.conf')
relative to the user's home directory.<br />
@ -558,7 +609,7 @@ notice and this notice are preserved.
</desc>
<term>GNUSTEP_USER_DEFAULTS_DIR</term>
<desc>Name of directory for user defaults files.
Relative to the user's home directory.<br />
Always relative to the user's home directory except:<br />
On mswindows this may be set to be ':REGISTRY:' to have defaults
stored in the windows registry rather than in the standard file
format.<br />

View file

@ -138,6 +138,8 @@ static NSString *gnustep_is_flattened =
static NSString *gnustepConfigPath = nil;
static NSString *gnustepUserHome = nil;
static NSString *gnustepUserID = nil;
static NSString *gnustepUserName = nil;
static NSString *gnustepUserDefaultsDir = nil;
static NSString *theUserName = nil; /* The user's login name */
@ -236,6 +238,10 @@ static void ShutdownPathUtilities(void);
}\
})
/* Grab a path from the config file, making it relative to the config
* file location if it begins with './' or '../', and checking that the
* result is an absolute path.
*/
#define ASSIGN_PATH(var, dictionary, key) ({\
id val = getPathConfig(dictionary, key);\
if (val != nil)\
@ -246,6 +252,23 @@ static void ShutdownPathUtilities(void);
}\
})
/* Like ASSIGN_PATH(), but permits the result to be a relative path as that
* is what we normally use (the path is within the user's home directory).
*/
#define ASSIGN_USER(var, dictionary, key) ({\
id val = [dictionary objectForKey: key];\
if (val != nil)\
{\
val = getPath(val);\
}\
if (val != nil)\
{\
RELEASE(var);\
var = RETAIN(val);\
[dictionary removeObjectForKey: key];\
}\
})
/* Conditionally assign lval to var only if var is nil */
#define TEST_ASSIGN(var, lval) ({\
if ((var == nil)&&(lval != nil))\
@ -262,6 +285,77 @@ static void ShutdownPathUtilities(void);
}\
})
/* The user domain paths are normally located within the user's home directory,
* but if they are specified as absolute paths they can be anywhere you like.
*
*/
#define ASSIGN_USER_PATH(var, val) ({\
if (nil == var) \
{\
ASSIGN(var, ([val isAbsolutePath] ? substUser(val) : \
[gnustepUserHome stringByAppendingPathComponent: substUser(val)]));\
}\
})
/* For user domain paths, we allow '%u' as the username, '%i' as the userid,
* and '%%' as a '%' in cases where it would otherwise be treated as a
* username or userid.
*/
static NSString*
substUser(NSString *str)
{
if (str != nil && [str rangeOfString: @"%"].length > 0)
{
NSMutableString *m = [[str mutableCopy] autorelease];
int l = [m length];
int i = 0;
BOOL percent = NO;
while (i < l)
{
unichar c = [m characterAtIndex: i];
if (YES == percent)
{
NSString *s;
if (c == '%')
{
s = @"%"; // Escaped percent
}
else if (c == 'i')
{
s = gnustepUserID; // User ID
}
else if (c == 'u')
{
s = gnustepUserName; // User name
}
else
{
s = nil; // No substitution
}
if (s != nil)
{
int diff = [s length] - 2;
[m replaceCharactersInRange: NSMakeRange(i-1, 2)
withString: s];
l += diff;
i += diff;
}
percent = NO;
}
else if (c == '%')
{
percent = YES;
}
i++;
}
str = m;
}
return str;
}
/* Get a full path string */
static inline NSString *
@ -302,8 +396,8 @@ getPathConfig(NSDictionary *dict, NSString *key)
unichar buf[3];
[path getCharacters: buf range: NSMakeRange(0, 3)];
if ((buf[0] == '/' || bug[0] == '\\') && isalpha(buf[1])
&& (buf[2] == '/' || bug[2] == '\\'))
if ((buf[0] == '/' || buf[0] == '\\') && isalpha(buf[1])
&& (buf[2] == '/' || buf[2] == '\\'))
{
path = [NSString stringWithFormat: @"%c:%@", (char)buf[1],
[path substringFromindex: 2]];
@ -370,27 +464,27 @@ static void ExtractValuesFromConfig(NSDictionary *config)
ASSIGN_PATH(gnustepLocalDocumentationMan, c, @"GNUSTEP_LOCAL_DOC_MAN");
ASSIGN_PATH(gnustepLocalDocumentationInfo, c, @"GNUSTEP_LOCAL_DOC_INFO");
ASSIGN_IF_SET(gnustepUserDirApps, c, @"GNUSTEP_USER_DIR_APPS");
ASSIGN_USER(gnustepUserDirApps, c, @"GNUSTEP_USER_DIR_APPS");
TEST_ASSIGN(gnustepUserDirApps, @GNUSTEP_TARGET_USER_DIR_APPS);
ASSIGN_IF_SET(gnustepUserDirAdminApps, c, @"GNUSTEP_USER_DIR_ADMIN_APPS");
ASSIGN_USER(gnustepUserDirAdminApps, c, @"GNUSTEP_USER_DIR_ADMIN_APPS");
TEST_ASSIGN(gnustepUserDirAdminApps, @GNUSTEP_TARGET_USER_DIR_ADMIN_APPS);
ASSIGN_IF_SET(gnustepUserDirWebApps, c, @"GNUSTEP_USER_DIR_WEB_APPS");
ASSIGN_USER(gnustepUserDirWebApps, c, @"GNUSTEP_USER_DIR_WEB_APPS");
TEST_ASSIGN(gnustepUserDirWebApps, @GNUSTEP_TARGET_USER_DIR_WEB_APPS);
ASSIGN_IF_SET(gnustepUserDirTools, c, @"GNUSTEP_USER_DIR_TOOLS");
ASSIGN_USER(gnustepUserDirTools, c, @"GNUSTEP_USER_DIR_TOOLS");
TEST_ASSIGN(gnustepUserDirTools, @GNUSTEP_TARGET_USER_DIR_TOOLS);
ASSIGN_IF_SET(gnustepUserDirAdminTools, c, @"GNUSTEP_USER_DIR_ADMIN_TOOLS");
ASSIGN_USER(gnustepUserDirAdminTools, c, @"GNUSTEP_USER_DIR_ADMIN_TOOLS");
TEST_ASSIGN(gnustepUserDirAdminTools, @GNUSTEP_TARGET_USER_DIR_ADMIN_TOOLS);
ASSIGN_IF_SET(gnustepUserDirLibrary, c, @"GNUSTEP_USER_DIR_LIBRARY");
ASSIGN_USER(gnustepUserDirLibrary, c, @"GNUSTEP_USER_DIR_LIBRARY");
TEST_ASSIGN(gnustepUserDirLibrary, @GNUSTEP_TARGET_USER_DIR_LIBRARY);
ASSIGN_IF_SET(gnustepUserDirLibraries, c, @"GNUSTEP_USER_DIR_LIBRARIES");
ASSIGN_USER(gnustepUserDirLibraries, c, @"GNUSTEP_USER_DIR_LIBRARIES");
TEST_ASSIGN(gnustepUserDirLibraries, @GNUSTEP_TARGET_USER_DIR_LIBRARIES);
ASSIGN_IF_SET(gnustepUserDirHeaders, c, @"GNUSTEP_USER_DIR_HEADERS");
ASSIGN_USER(gnustepUserDirHeaders, c, @"GNUSTEP_USER_DIR_HEADERS");
TEST_ASSIGN(gnustepUserDirHeaders, @GNUSTEP_TARGET_USER_DIR_HEADERS);
ASSIGN_IF_SET(gnustepUserDirDocumentation, c, @"GNUSTEP_USER_DIR_DOC");
ASSIGN_USER(gnustepUserDirDocumentation, c, @"GNUSTEP_USER_DIR_DOC");
TEST_ASSIGN(gnustepUserDirDocumentation, @GNUSTEP_TARGET_USER_DIR_DOC);
ASSIGN_IF_SET(gnustepUserDirDocumentationMan, c, @"GNUSTEP_USER_DIR_DOC_MAN");
ASSIGN_USER(gnustepUserDirDocumentationMan, c, @"GNUSTEP_USER_DIR_DOC_MAN");
TEST_ASSIGN(gnustepUserDirDocumentationMan, @GNUSTEP_TARGET_USER_DIR_DOC_MAN);
ASSIGN_IF_SET(gnustepUserDirDocumentationInfo, c, @"GNUSTEP_USER_DIR_DOC_INFO");
ASSIGN_USER(gnustepUserDirDocumentationInfo, c, @"GNUSTEP_USER_DIR_DOC_INFO");
TEST_ASSIGN(gnustepUserDirDocumentationInfo, @GNUSTEP_TARGET_USER_DIR_DOC_INFO);
/*
@ -486,41 +580,17 @@ static void ExtractValuesFromConfig(NSDictionary *config)
* Set the GNUSTEP_USER_xxx variables from the user home and the
* GNUSTEP_USER_DIR_xxx variables.
*/
ASSIGN(gnustepUserApps,
[gnustepUserHome stringByAppendingPathComponent: gnustepUserDirApps]);
ASSIGN(gnustepUserAdminApps,
[gnustepUserHome stringByAppendingPathComponent: gnustepUserDirAdminApps]);
ASSIGN(gnustepUserWebApps,
[gnustepUserHome stringByAppendingPathComponent: gnustepUserDirWebApps]);
ASSIGN(gnustepUserTools,
[gnustepUserHome stringByAppendingPathComponent: gnustepUserDirTools]);
ASSIGN(gnustepUserAdminTools,
[gnustepUserHome stringByAppendingPathComponent: gnustepUserDirAdminTools]);
ASSIGN(gnustepUserLibrary,
[gnustepUserHome stringByAppendingPathComponent: gnustepUserDirLibrary]);
ASSIGN(gnustepUserLibraries,
[gnustepUserHome stringByAppendingPathComponent: gnustepUserDirLibraries]);
ASSIGN(gnustepUserHeaders,
[gnustepUserHome stringByAppendingPathComponent: gnustepUserDirHeaders]);
ASSIGN(gnustepUserDocumentation,
[gnustepUserHome stringByAppendingPathComponent:
gnustepUserDocumentation]);
ASSIGN(gnustepUserDocumentationMan,
[gnustepUserHome stringByAppendingPathComponent:
gnustepUserDocumentationMan]);
ASSIGN(gnustepUserDocumentationInfo,
[gnustepUserHome stringByAppendingPathComponent:
gnustepUserDocumentationInfo]);
ASSIGN_USER_PATH(gnustepUserApps, gnustepUserDirApps);
ASSIGN_USER_PATH(gnustepUserAdminApps, gnustepUserDirAdminApps);
ASSIGN_USER_PATH(gnustepUserWebApps, gnustepUserDirWebApps);
ASSIGN_USER_PATH(gnustepUserTools, gnustepUserDirTools);
ASSIGN_USER_PATH(gnustepUserAdminTools, gnustepUserDirAdminTools);
ASSIGN_USER_PATH(gnustepUserLibrary, gnustepUserDirLibrary);
ASSIGN_USER_PATH(gnustepUserLibraries, gnustepUserDirLibraries);
ASSIGN_USER_PATH(gnustepUserHeaders, gnustepUserDirHeaders);
ASSIGN_USER_PATH(gnustepUserDocumentation, gnustepUserDocumentation);
ASSIGN_USER_PATH(gnustepUserDocumentationMan, gnustepUserDocumentationMan);
ASSIGN_USER_PATH(gnustepUserDocumentationInfo, gnustepUserDocumentationInfo);
/*
* Try to ensure that essential user directories exist.
@ -867,14 +937,36 @@ static void InitialisePathUtilities(void)
/* Set up our root paths */
NS_DURING
{
NSString *userName;
NSMutableDictionary *config;
[gnustep_global_lock lock];
userName = NSUserName();
gnustepUserName = [NSUserName() copy];
#if defined(__MINGW__)
{
unichar buf[1024];
SID_NAME_USE use;
SID sid;
DWORD n = 1024;
if (GetUserNameW(buf, &n) == 0 || buf[0] == '\0')
{
[NSException raise: NSInternalInconsistencyException
format: @"Unable to determine current user name"];
}
n = sizeof(SID);
if (LookupAccountName(0, buf, &sid, &n, NULL, 0, &use) == 0)
{
[NSException raise: NSInternalInconsistencyException
format: @"Unable to determine current account"];
}
gnustepUserID = [[NSString alloc] initWithFormat: @"%ld", (long)sid];
}
#else
gnustepUserID = [[NSString alloc] initWithFormat: @"%ld", (long)getuid()];
#endif
config = GNUstepConfig(nil);
GNUstepUserConfig(config, userName);
ASSIGNCOPY(gnustepUserHome, NSHomeDirectoryForUser(userName));
GNUstepUserConfig(config, gnustepUserName);
gnustepUserHome = [NSHomeDirectoryForUser(gnustepUserName) copy];
ExtractValuesFromConfig(config);
[gnustep_global_lock unlock];
@ -894,6 +986,8 @@ static void InitialisePathUtilities(void)
static void ShutdownPathUtilities(void)
{
DESTROY(gnustepUserHome);
DESTROY(gnustepUserID);
DESTROY(gnustepUserName);
DESTROY(gnustepUserDefaultsDir);
DESTROY(gnustepMakefiles);