2 * Copyright (c) 1999, 2008 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 #include <NSSystemDirectories.h>
26 #include <sys/param.h>
30 #define NSUserDomainIndex 0
31 #define NSLocalDomainIndex 1
32 #define NSNetworkDomainIndex 2
33 #define NSSystemDomainIndex 3
35 #define numDomains (NSSystemDomainIndex + 1)
36 #define DomainMask ((1 << numDomains) - 1)
38 #define addNextRoot(x) (*(x) == '/' || *(x) == 0)
40 #define Network "/Network"
41 #define System "/System"
44 #define NSApplicationDirectoryBase "/Applications"
45 #define NSDemoApplicationDirectoryBase "/Applications/Demos"
46 #define NSDeveloperApplicationDirectoryBase "/Developer/Applications"
47 #define NSAdminApplicationDirectoryBase "/Applications/Utilities"
48 #define NSLibraryDirectoryBase "/Library"
49 #define NSDeveloperDirectoryBase "/Developer"
50 #define NSUserDirectoryBase "/Users"
51 #define NSDocumentationDirectoryBase "/Library/Documentation"
52 #define NSDocumentDirectoryBase "/Documents"
53 #define NSCoreServiceDirectoryBase "/Library/CoreServices"
54 #define NSAutosavedDocumentsDirectoryBase "/Library/Autosave Information"
55 #define NSDesktopDirectoryBase "/Desktop"
56 #define NSCachesDirectoryBase "/Library/Caches"
57 #define NSInputMethodsDirectoryBase "/Library/Input Methods"
58 #define NSMoviesDirectoryBase "/Movies"
59 #define NSMusicDirectoryBase "/Music"
60 #define NSPicturesDirectoryBase "/Pictures"
61 #define NSPrinterDescriptionDirectoryBase "/Library/Printers/PPDs"
62 #define NSSharedPublicDirectoryBase "/Public"
63 #define NSPreferencePanesDirectoryBase "/Library/PreferencePanes"
64 #define NSApplicationSupportDirectoryBase "/Library/Application Support"
65 #define NSDownloadsDirectoryBase "/Downloads"
67 static const char * const prefixAll
[] = {
73 static const char * const prefixAllSystem
[] = {
79 static const char * const prefixNoUserSystem
[] = {
85 static const char * const prefixNoNetwork
[] = {
91 static const char * const prefixSystemOnly
[] = {
97 static const char * const prefixUserOnly
[] = {
104 static const char * const _prefixNetwork4
[] = {
110 static const char * const _prefixNone4
[] = {
116 static const char * const _prefixTilde4
[] = {
122 static const char * const * const prefixAllApplicationsDirectory
[] = {
128 static const char * const baseAllApplicationsDirectory
[] = {
129 NSApplicationDirectoryBase
,
130 NSAdminApplicationDirectoryBase
,
131 NSDeveloperApplicationDirectoryBase
,
132 NSDemoApplicationDirectoryBase
135 static const char * const _prefixNetwork2
[] = {
139 static const char * const _prefixNone2
[] = {
143 static const char * const _prefixSystemNone2
[] = {
147 static const char * const _prefixTilde2
[] = {
151 static const char * const * const prefixAllLibrariesDirectory
[] = {
157 static const char * const baseAllLibrariesDirectory
[] = {
158 NSLibraryDirectoryBase
,
159 NSDeveloperDirectoryBase
162 // The dirInfo table drives path creation
165 const void * const * const prefix
;
166 const void * const base
;
168 { // NSApplicationDirectory
170 (const void * const * const)prefixAll
,
171 (const void * const)NSApplicationDirectoryBase
173 { // NSDemoApplicationDirectory
175 (const void * const * const)prefixAll
,
176 (const void * const)NSDemoApplicationDirectoryBase
178 { // NSDeveloperApplicationDirectory
180 (const void * const * const)prefixAll
,
181 (const void * const)NSDeveloperApplicationDirectoryBase
183 { // NSAdminApplicationDirectory
185 (const void * const * const)prefixAll
,
186 (const void * const)NSAdminApplicationDirectoryBase
188 { // NSLibraryDirectory
190 (const void * const * const)prefixAllSystem
,
191 (const void * const)NSLibraryDirectoryBase
193 { // NSDeveloperDirectory
195 (const void * const * const)prefixAll
,
196 (const void * const)NSDeveloperDirectoryBase
200 (const void * const * const)prefixNoUserSystem
,
201 (const void * const)NSUserDirectoryBase
203 { // NSDocumentationDirectory
205 (const void * const * const)prefixAllSystem
,
206 (const void * const)NSDocumentationDirectoryBase
208 { // NSDocumentDirectory
210 (const void * const * const)prefixUserOnly
,
211 (const void * const)NSDocumentDirectoryBase
213 { // NSCoreServiceDirectory
215 (const void * const * const)prefixSystemOnly
,
216 (const void * const)NSCoreServiceDirectoryBase
218 { // NSAutosavedInformationDirectory
220 (const void * const * const)prefixUserOnly
,
221 (const void * const)NSAutosavedDocumentsDirectoryBase
223 { // NSDesktopDirectory
225 (const void * const * const)prefixUserOnly
,
226 (const void * const)NSDesktopDirectoryBase
228 { // NSCachesDirectory
230 (const void * const * const)prefixNoNetwork
,
231 (const void * const)NSCachesDirectoryBase
233 { // NSApplicationSupportDirectory
235 (const void * const * const)prefixAll
,
236 (const void * const)NSApplicationSupportDirectoryBase
238 { // NSDownloadsDirectory
240 (const void * const * const)prefixUserOnly
,
241 (const void * const)NSDownloadsDirectoryBase
243 { // NSInputMethodsDirectory
245 (const void * const * const)prefixAllSystem
,
246 (const void * const)NSInputMethodsDirectoryBase
248 { // NSMoviesDirectory
250 (const void * const * const)prefixUserOnly
,
251 (const void * const)NSMoviesDirectoryBase
253 { // NSMusicDirectory
255 (const void * const * const)prefixUserOnly
,
256 (const void * const)NSMusicDirectoryBase
258 { // NSPicturesDirectory
260 (const void * const * const)prefixUserOnly
,
261 (const void * const)NSPicturesDirectoryBase
263 { // NSPrinterDescriptionDirectory
265 (const void * const * const)prefixSystemOnly
,
266 (const void * const)NSPrinterDescriptionDirectoryBase
268 { // NSSharedPublicDirectory
270 (const void * const * const)prefixUserOnly
,
271 (const void * const)NSSharedPublicDirectoryBase
273 { // NSPreferencePanesDirectory
275 (const void * const * const)prefixNoNetwork
,
276 (const void * const)NSPreferencePanesDirectoryBase
278 { // NSAllApplicationsDirectory
280 (const void * const * const)prefixAllApplicationsDirectory
,
281 (const void * const)baseAllApplicationsDirectory
283 { // NSAllLibrariesDirectory
285 (const void * const * const)prefixAllLibrariesDirectory
,
286 (const void * const)baseAllLibrariesDirectory
290 #define Index(dir) (((dir) >= NSApplicationDirectory && (dir) <= NSPreferencePanesDirectory) ? ((dir) - 1) : (((dir) >= NSAllApplicationsDirectory && (dir) <= NSAllLibrariesDirectory) ? ((dir) - NSAllApplicationsDirectory + NSPreferencePanesDirectory) : -1))
292 #define invalidDomains 0x00 // some domains may be invalid on non-Mach systems
293 #define ByteMask 0xff
295 #define IndexShift 16
297 NSSearchPathEnumerationState
NSStartSearchPathEnumeration(NSSearchPathDirectory dir
, NSSearchPathDomainMask domainMask
) {
298 // The state is AABBCCCC, where
299 // AA is the dir(s) requested
300 // BB is the current state of dirs (if AA < 100, then this is always 0; otherwise it goes up to number of dirs)
301 // CCCC is the domains requested
302 // the state always contains the next item; if CCCC is 0, then we're done
305 if((i
= Index(dir
)) < 0) {
308 domainMask
= domainMask
& DomainMask
& ~invalidDomains
; // Just leave useful bits in there
310 // Trim Duplicates - This assumes the compiler generates a single address
311 // for multiple occurrences of the same literal strings.
312 if ((domainMask
& (NSLocalDomainMask
| NSSystemDomainMask
)) == (NSLocalDomainMask
| NSSystemDomainMask
) && dirInfo
[i
].prefix
[NSLocalDomainIndex
] == dirInfo
[i
].prefix
[NSSystemDomainIndex
]) {
313 domainMask
&= ~NSSystemDomainMask
;
316 return (dir
<< DirShift
) + domainMask
;
319 static const char *nextRoot
= NULL
;
320 static pthread_once_t nextRoot_init_once
= PTHREAD_ONCE_INIT
;
325 if (!issetugid() && (nextRoot
= getenv("NEXT_ROOT")) != NULL
) {
326 nextRoot
= strdup(nextRoot
);
328 if (nextRoot
== NULL
) {
333 NSSearchPathEnumerationState
NSGetNextSearchPathEnumeration(NSSearchPathEnumerationState state
, char *path
) {
334 int dir
= (state
>> DirShift
) & ByteMask
;
335 int domainMask
= state
& DomainMask
;
337 const char *prefix
, *base
;
339 if ((i
= Index(dir
)) < 0 || (domain
= ffs(domainMask
)) == 0)
341 domain
--; // adjust to zero-based index
343 if ((n
= dirInfo
[i
].pathsPerDomain
) == 1) {
344 const char * const *p
= (const char * const *)dirInfo
[i
].prefix
;
345 for (;;) { // loop, skipping over invalid domains (prefix is NULL)
346 domainMask
&= ~(1 << domain
);
347 if ((prefix
= p
[domain
]) != NULL
) {
350 if ((domain
= ffs(domainMask
)) == 0) {
353 domain
--; // adjust to zero-based index
355 base
= (const char *)dirInfo
[i
].base
;
356 state
= (dir
<< DirShift
) + domainMask
;
357 } else { // multiple paths per domain
358 const char * const **p
= (const char * const **)dirInfo
[i
].prefix
;
359 const char * const *b
= (const char * const *)dirInfo
[i
].base
;
360 int dirIndex
= (state
>> IndexShift
) & ByteMask
;
362 if (dirIndex
>= n
) { // done with the current domain, go to the next
363 domainMask
&= ~(1 << domain
);
364 if ((domain
= ffs(domainMask
)) == 0) {
367 domain
--; // adjust to zero-based index
370 prefix
= p
[domain
][dirIndex
];
372 state
= (dir
<< DirShift
) + (++dirIndex
<< IndexShift
) + domainMask
;
375 if (addNextRoot(prefix
)) {
376 if (pthread_once(&nextRoot_init_once
, nextRoot_init
) != 0 || nextRoot
== NULL
)// Error
378 strlcpy(path
, nextRoot
, PATH_MAX
);
382 strlcat(path
, prefix
, PATH_MAX
);
383 strlcat(path
, base
, PATH_MAX
);