2 * Copyright (c) 2005 Tim Walters. All rights reserved.
3 * Created by Tim Walters on 10/19/05.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
29 # include "SC_Win32Utils.h"
34 # include <sys/param.h>
35 # include <sys/stat.h>
36 # include <sys/types.h>
39 #include "SC_DirUtils.h"
41 #if defined(__APPLE__) || defined(SC_IPHONE)
42 #ifndef _SC_StandAloneInfo_
43 # include "SC_StandAloneInfo_Darwin.h"
45 # include <CoreFoundation/CFString.h>
46 # include <CoreFoundation/CFBundle.h>
48 # include <CoreServices/CoreServices.h>
52 const char * gIdeName
= "none";
54 // Add a component to a path.
56 void sc_AppendToPath(char *path
, size_t max_size
, const char *component
)
58 size_t currentLength
= strlen(path
);
59 if (currentLength
>= max_size
-1)
61 path
[currentLength
] = SC_PATH_DELIMITER
[0];
62 path
[currentLength
+1] = 0;
65 char * tail
= path
+ currentLength
;
66 size_t remain
= max_size
- currentLength
;
68 strncat(tail
, component
, remain
);
72 char *sc_StandardizePath(const char *path
, char *newpath2
)
74 char newpath1
[MAXPATHLEN
];
79 size_t pathLen
= strlen(path
);
81 if ((pathLen
>= 2) && (path
[0] == '~') && ((path
[1] == '/') || (path
[1] == '\\'))) {
83 sc_GetUserHomeDirectory(home
, PATH_MAX
);
86 if ((pathLen
- 1 + strlen(home
)) >= MAXPATHLEN
) {
89 strcpy(newpath1
, home
);
90 strcat(newpath1
, path
+ 1);
92 if (pathLen
>= MAXPATHLEN
) {
95 strcpy(newpath1
, path
);
99 if (pathLen
>= MAXPATHLEN
) {
102 strcpy(newpath1
, path
);
105 bool isAlias
= false;
106 if(sc_ResolveIfAlias(newpath1
, newpath2
, isAlias
, PATH_MAX
)!=0) {
107 strcpy(newpath2
, newpath1
);
114 // Returns TRUE iff dirname is an existing directory.
116 bool sc_DirectoryExists(const char *dirname
)
119 DWORD attr
= GetFileAttributes(dirname
);
120 return ((attr
!= INVALID_FILE_ATTRIBUTES
) &&
121 (attr
& FILE_ATTRIBUTE_DIRECTORY
));
124 return ((stat(dirname
, &buf
) == 0) &&
125 S_ISDIR(buf
.st_mode
));
129 bool sc_IsSymlink(const char* path
)
137 return ((stat(path
, &buf
) == 0) &&
138 S_ISLNK(buf
.st_mode
));
142 bool sc_IsNonHostPlatformDir(const char *name
)
144 #if defined(SC_IPHONE)
145 const char a
[] = "linux", b
[] = "windows", c
[]="osx";
146 #elif defined(__APPLE__)
147 const char a
[] = "linux", b
[] = "windows", c
[]="iphone";
148 #elif defined(__linux__)
149 const char a
[] = "osx", b
[] = "windows", c
[]="iphone";
150 #elif defined(__FreeBSD__)
151 const char a
[] = "osx", b
[] = "windows", c
[]="iphone";
152 #elif defined(_WIN32)
153 const char a
[] = "osx", b
[] = "linux", c
[]="iphone";
155 return ((strcmp(name
, a
) == 0) ||
156 (strcmp(name
, b
) == 0) ||
157 (strcmp(name
, c
) == 0));
161 // Returns TRUE iff 'name' is special directory '.' or '..'
163 inline static bool sc_IsSpecialDirectory(const char* name
)
165 return (strcmp(name
, ".") == 0) || (strcmp(name
, "..") == 0);
168 // Returns TRUE iff 'name' is to be ignored during compilation.
170 bool sc_SkipDirectory(const char *name
)
172 return ((strcasecmp(name
, "help") == 0) ||
173 (strcasecmp(name
, "ignore") == 0) ||
174 (strcmp(name
, ".svn") == 0) ||
175 (strcmp(name
, ".git") == 0) ||
176 (strcmp(name
, "_darcs") == 0) ||
177 ((strncmp(name
, "scide_", 6) == 0) && (strcmp(name
+6, gIdeName
) != 0)) ||
178 sc_IsNonHostPlatformDir(name
));
182 int sc_ResolveIfAlias(const char *path
, char *returnPath
, bool &isAlias
, int length
)
185 #if defined(__APPLE__) && !defined(SC_IPHONE)
187 OSStatus osStatusErr
= FSPathMakeRef ((const UInt8
*) path
, &dirRef
, NULL
);
188 if ( !osStatusErr
) {
191 OSErr err
= FSResolveAliasFile (&dirRef
, true, &isFolder
, &wasAliased
);
196 isAlias
= wasAliased
;
199 UInt8 resolvedPath
[PATH_MAX
];
200 osStatusErr
= FSRefMakePath (&dirRef
, resolvedPath
, length
);
205 strncpy(returnPath
, (char *) resolvedPath
, length
);
210 strcpy(returnPath
, path
);
214 // Support for Bundles
216 #if defined(__APPLE__) && !defined(SC_IPHONE) // running on OS X
218 // Support for stand-alone applications
220 bool sc_IsStandAlone()
222 return SC_StandAloneInfo::IsStandAlone();
225 void sc_GetResourceDirectory(char* pathBuf
, int length
)
227 SC_StandAloneInfo::GetResourceDir(pathBuf
, length
);
231 void sc_AppendBundleName(char *str
, int size
)
233 CFBundleRef mainBundle
;
234 mainBundle
= CFBundleGetMainBundle();
236 CFDictionaryRef dictRef
= CFBundleGetInfoDictionary(mainBundle
);
238 strRef
= (CFStringRef
)CFDictionaryGetValue(dictRef
, CFSTR("CFBundleName"));
240 const char *bundleName
= CFStringGetCStringPtr(strRef
, CFStringGetSystemEncoding());
242 sc_AppendToPath(str
, size
, bundleName
);
247 sc_AppendToPath(str
, size
, "SuperCollider");
250 #elif defined(SC_IPHONE)
252 bool sc_IsStandAlone()
257 void sc_GetResourceDirectory(char* pathBuf
, int length
)
259 sc_GetUserAppSupportDirectory(pathBuf
, length
);
262 #elif defined(__unix__)
264 bool sc_IsStandAlone()
269 void sc_GetResourceDirectory(char* pathBuf
, int length
)
272 strncpy(pathBuf
, SC_DATA_DIR
, length
);
274 strncpy(pathBuf
, "/usr/share/SuperCollider", length
);
280 bool sc_IsStandAlone()
285 static void sc_GetResourceDirectoryFromAppDirectory(char* pathBuf
, int length
)
287 char * result
= getcwd(pathBuf
, length
);
288 if (result
!= pathBuf
)
289 throw std::runtime_error("cannot get current working directory");
293 void sc_GetResourceDirectory(char* pathBuf
, int length
)
295 return sc_GetResourceDirectoryFromAppDirectory(pathBuf
, length
);
300 // Support for Extensions
302 // Get the user home directory.
304 void sc_GetUserHomeDirectory(char *str
, int size
)
307 const char *home
= getenv("HOME");
309 strncpy(str
, home
, size
);
311 // cwd is not the user home directory; but this is better than leaving mem uninitialised.
315 win32_GetHomeFolder(str
,size
);
320 // Get the System level data directory.
322 void sc_GetSystemAppSupportDirectory(char *str
, int size
)
325 #if defined(SC_DATA_DIR)
327 #elif defined(SC_IPHONE)
329 #elif defined(__APPLE__)
330 "/Library/Application Support",
331 #elif defined(_WIN32)
332 ( getenv("SC_SYSAPPSUP_PATH")==NULL
) ? "C:\\SuperCollider" : getenv("SC_SYSAPPSUP_PATH"),
334 "/usr/local/share/SuperCollider",
338 #if defined(__APPLE__)
339 // Get the main bundle name for the app from the enclosed Info.plist
340 sc_AppendBundleName(str
, size
);
345 // Get the User level data directory.
347 void sc_GetUserAppSupportDirectory(char *str
, int size
)
349 // XDG support according to http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
350 const char * xdg_data_home
= getenv("XDG_DATA_HOME");
352 strncpy(str
, xdg_data_home
, size
);
353 sc_AppendToPath(str
, size
, "SuperCollider");
357 sc_GetUserHomeDirectory(str
, size
);
359 #if defined(SC_IPHONE)
360 sc_AppendToPath(str
, size
, "Documents");
361 #elif defined(__APPLE__)
362 // Get the main bundle name for the app
363 sc_AppendToPath(str
, size
, "Library/Application Support");
364 sc_AppendBundleName(str
, size
);
365 #elif defined(_WIN32)
366 sc_AppendToPath(str
, size
, "SuperCollider");
368 sc_AppendToPath(str
, size
, ".local/share/SuperCollider");
373 // Get the System level 'Extensions' directory.
375 void sc_GetSystemExtensionDirectory(char *str
, int size
)
377 sc_GetSystemAppSupportDirectory(str
, size
);
378 sc_AppendToPath(str
, size
, "Extensions");
382 // Get the System level 'Extensions' directory.
384 void sc_GetUserExtensionDirectory(char *str
, int size
)
386 sc_GetUserAppSupportDirectory(str
, size
);
387 sc_AppendToPath(str
, size
, "Extensions");
390 // Get the directory for the configuration files.
391 void sc_GetUserConfigDirectory(char *str
, int size
)
393 // XDG support according to http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
394 const char * xdg_config_home
= getenv("XDG_CONFIG_HOME");
395 if (xdg_config_home
) {
396 strncpy(str
, xdg_config_home
, size
);
397 sc_AppendToPath(str
, size
, "SuperCollider");
401 #if defined(__linux__) || defined(__freebsd__)
404 sc_GetUserHomeDirectory(str
, size
);
405 sc_AppendToPath(str
, size
, ".config/SuperCollider");
407 sc_GetUserAppSupportDirectory(str
, size
);
418 WIN32_FIND_DATA mEntry
;
422 struct dirent
* mEntry
;
426 SC_DirHandle
* sc_OpenDir(const char* dirname
)
428 SC_DirHandle
* dir
= new SC_DirHandle
;
429 memset(dir
, 0, sizeof(SC_DirHandle
));
432 char allInDir
[PATH_MAX
];
433 snprintf(allInDir
, PATH_MAX
, "%s\\*.*", dirname
);
435 dir
->mHandle
= ::FindFirstFile(allInDir
, &dir
->mEntry
);
436 if (dir
->mHandle
== INVALID_HANDLE_VALUE
) {
443 dir
->mHandle
= opendir(dirname
);
453 void sc_CloseDir(SC_DirHandle
* dir
)
456 ::FindClose(dir
->mHandle
);
458 closedir(dir
->mHandle
);
463 bool sc_ReadDir(SC_DirHandle
* dir
, const char* dirname
, char* path
, bool& skipEntry
)
471 const char* entry
= dir
->mEntry
.cFileName
;
473 if (sc_IsSpecialDirectory(entry
) || (skipEntry
&& sc_SkipDirectory(entry
))) {
481 char entrypathname
[PATH_MAX
];
482 strncpy(entrypathname
, dirname
, PATH_MAX
);
483 sc_AppendToPath(entrypathname
, PATH_MAX
, dir
->mEntry
.cFileName
);
485 bool isAlias
= false;
486 sc_ResolveIfAlias(entrypathname
, path
, isAlias
, PATH_MAX
);
488 if (!::FindNextFile(dir
->mHandle
, &dir
->mEntry
)) {
497 dir
->mEntry
= readdir(dir
->mHandle
);
501 const char* entry
= dir
->mEntry
->d_name
;
503 if (sc_IsSpecialDirectory(entry
) || (skipEntry
&& sc_SkipDirectory(entry
))) {
510 // construct path from dir entry
511 char entrypathname
[PATH_MAX
];
512 strncpy(entrypathname
, dirname
, PATH_MAX
);
513 sc_AppendToPath(entrypathname
, PATH_MAX
, dir
->mEntry
->d_name
);
516 bool isAlias
= false;
517 if (sc_ResolveIfAlias(entrypathname
, path
, isAlias
, strlen(entrypathname
))<0)
533 char mFolder
[PATH_MAX
];
534 WIN32_FIND_DATA mEntry
;
535 char mEntryPath
[PATH_MAX
];
543 SC_GlobHandle
* sc_Glob(const char* pattern
)
545 SC_GlobHandle
* glob
= new SC_GlobHandle
;
548 char patternWin
[1024];
550 strncpy(patternWin
, pattern
, 1024);
551 patternWin
[1023] = 0;
552 win32_ReplaceCharInString(patternWin
, 1024, '/', '\\');
554 win32_ExtractContainingFolder(glob
->mFolder
, patternWin
, PATH_MAX
);
556 glob
->mHandle
= ::FindFirstFile(patternWin
, &glob
->mEntry
);
557 if (glob
->mHandle
== INVALID_HANDLE_VALUE
) {
562 glob
->mAtEnd
= false;
564 int flags
= GLOB_MARK
| GLOB_TILDE
;
569 int err
= ::glob(pattern
, flags
, NULL
, &glob
->mHandle
);
581 void sc_GlobFree(SC_GlobHandle
* glob
)
584 ::FindClose(glob
->mHandle
);
586 globfree(&glob
->mHandle
);
591 const char* sc_GlobNext(SC_GlobHandle
* glob
)
596 strncpy(glob
->mEntryPath
, glob
->mFolder
, PATH_MAX
);
597 sc_AppendToPath(glob
->mEntryPath
, PATH_MAX
, glob
->mEntry
.cFileName
);
598 if (!::FindNextFile(glob
->mHandle
, &glob
->mEntry
))
600 return glob
->mEntryPath
;
602 if (glob
->mEntry
>= glob
->mHandle
.gl_pathc
)
604 return glob
->mHandle
.gl_pathv
[glob
->mEntry
++];