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
30 # include "SC_Win32Utils.h"
35 # include <sys/param.h>
36 # include <sys/stat.h>
37 # include <sys/types.h>
41 #include "SC_DirUtils.h"
43 #if defined(__APPLE__) || defined(SC_IPHONE)
44 #ifndef _SC_StandAloneInfo_
45 # include "SC_StandAloneInfo_Darwin.h"
47 # include <CoreFoundation/CFString.h>
48 # include <CoreFoundation/CFBundle.h>
50 # include <CoreServices/CoreServices.h>
56 const char * gIdeName
= "none";
58 // Add a component to a path.
60 void sc_AppendToPath(char *path
, const char *component
)
63 strncat(path
, "\\", PATH_MAX
);
65 strncat(path
, "/", PATH_MAX
);
67 strncat(path
, component
, PATH_MAX
);
70 char *sc_StandardizePath(const char *path
, char *newpath2
)
72 char newpath1
[MAXPATHLEN
];
77 size_t pathLen
= strlen(path
);
79 if ((pathLen
>= 2) && (path
[0] == '~') && ((path
[1] == '/') || (path
[1] == '\\'))) {
81 sc_GetUserHomeDirectory(home
, PATH_MAX
);
84 if ((pathLen
- 1 + strlen(home
)) >= MAXPATHLEN
) {
87 strcpy(newpath1
, home
);
88 strcat(newpath1
, path
+ 1);
90 if (pathLen
>= MAXPATHLEN
) {
93 strcpy(newpath1
, path
);
97 if (pathLen
>= MAXPATHLEN
) {
100 strcpy(newpath1
, path
);
103 bool isAlias
= false;
104 if(sc_ResolveIfAlias(newpath1
, newpath2
, isAlias
, PATH_MAX
)!=0) {
105 strcpy(newpath2
, newpath1
);
112 // Returns TRUE iff dirname is an existing directory.
114 bool sc_DirectoryExists(const char *dirname
)
117 DWORD attr
= GetFileAttributes(dirname
);
118 return ((attr
!= INVALID_FILE_ATTRIBUTES
) &&
119 (attr
& FILE_ATTRIBUTE_DIRECTORY
));
122 return ((stat(dirname
, &buf
) == 0) &&
123 S_ISDIR(buf
.st_mode
));
127 bool sc_IsSymlink(const char* path
)
135 return ((stat(path
, &buf
) == 0) &&
136 S_ISLNK(buf
.st_mode
));
140 bool sc_IsNonHostPlatformDir(const char *name
)
142 #if defined(SC_IPHONE)
143 const char a
[] = "linux", b
[] = "windows", c
[]="osx";
144 #elif defined(__APPLE__)
145 const char a
[] = "linux", b
[] = "windows", c
[]="iphone";
146 #elif defined(__linux__)
147 const char a
[] = "osx", b
[] = "windows", c
[]="iphone";
148 #elif defined(__FreeBSD__)
149 const char a
[] = "osx", b
[] = "windows", c
[]="iphone";
150 #elif defined(_WIN32)
151 const char a
[] = "osx", b
[] = "linux", c
[]="iphone";
153 return ((strcmp(name
, a
) == 0) ||
154 (strcmp(name
, b
) == 0) ||
155 (strcmp(name
, c
) == 0));
159 // Returns TRUE iff 'name' is special directory '.' or '..'
161 inline static bool sc_IsSpecialDirectory(const char* name
)
163 return (strcmp(name
, ".") == 0) || (strcmp(name
, "..") == 0);
166 // Returns TRUE iff 'name' is to be ignored during compilation.
168 bool sc_SkipDirectory(const char *name
)
170 return ((strcasecmp(name
, "help") == 0) ||
171 (strcasecmp(name
, "ignore") == 0) ||
172 (strcmp(name
, ".svn") == 0) ||
173 (strcmp(name
, ".git") == 0) ||
174 (strcmp(name
, "_darcs") == 0) ||
175 ((strncmp(name
, "scide_", 6) == 0) && (strcmp(name
+6, gIdeName
) != 0)) ||
176 sc_IsNonHostPlatformDir(name
));
180 int sc_ResolveIfAlias(const char *path
, char *returnPath
, bool &isAlias
, int length
)
183 #if defined(__APPLE__) && !defined(SC_IPHONE)
185 OSStatus osStatusErr
= FSPathMakeRef ((const UInt8
*) path
, &dirRef
, NULL
);
186 if ( !osStatusErr
) {
189 OSErr err
= FSResolveAliasFile (&dirRef
, true, &isFolder
, &wasAliased
);
194 isAlias
= wasAliased
;
197 UInt8 resolvedPath
[PATH_MAX
];
198 osStatusErr
= FSRefMakePath (&dirRef
, resolvedPath
, length
);
203 strncpy(returnPath
, (char *) resolvedPath
, length
);
208 strcpy(returnPath
, path
);
212 // Support for Bundles
214 #if defined(__APPLE__) && !defined(SC_IPHONE) // running on OS X
216 // Support for stand-alone applications
218 bool sc_IsStandAlone()
220 return SC_StandAloneInfo::IsStandAlone();
223 void sc_GetResourceDirectory(char* pathBuf
, int length
)
225 SC_StandAloneInfo::GetResourceDir(pathBuf
, length
);
228 #elif defined(SC_IPHONE)
230 bool sc_IsStandAlone()
235 void sc_GetResourceDirectory(char* pathBuf
, int length
)
237 sc_GetUserAppSupportDirectory(pathBuf
, length
);
240 #elif defined(__unix__)
242 bool sc_IsStandAlone()
247 void sc_GetResourceDirectory(char* pathBuf
, int length
)
250 strncpy(pathBuf
, SC_DATA_DIR
, length
);
252 strncpy(pathBuf
, "/usr/share/SuperCollider", length
);
258 bool sc_IsStandAlone()
263 static void sc_GetResourceDirectoryFromAppDirectory(char* pathBuf
, int length
)
265 char * result
= getcwd(pathBuf
, length
);
266 if (result
!= pathBuf
)
267 throw std::runtime_error("cannot get current working directory");
271 void sc_GetResourceDirectory(char* pathBuf
, int length
)
273 return sc_GetResourceDirectoryFromAppDirectory(pathBuf
, length
);
280 // Support for Extensions
282 // Get the user home directory.
284 void sc_GetUserHomeDirectory(char *str
, int size
)
287 char *home
= getenv("HOME");
289 strncpy(str
, home
, size
);
291 // cwd is not the user home directory; but this is better than leaving mem uninitialised.
295 win32_GetHomeFolder(str
,size
);
300 // Get the System level data directory.
302 void sc_GetSystemAppSupportDirectory(char *str
, int size
)
305 #if defined(SC_DATA_DIR)
307 #elif defined(SC_IPHONE)
309 #elif defined(__APPLE__)
310 "/Library/Application Support/SuperCollider",
311 #elif defined(_WIN32)
312 ( getenv("SC_SYSAPPSUP_PATH")==NULL
) ? "C:\\SuperCollider" : getenv("SC_SYSAPPSUP_PATH"),
314 "/usr/local/share/SuperCollider",
320 // Get the User level data directory.
322 void sc_GetUserAppSupportDirectory(char *str
, int size
)
324 // XDG support according to http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
325 char * xdg_data_home
= getenv("XDG_DATA_HOME");
327 string config_folder
= string(xdg_data_home
) + SC_PATH_DELIMITER
+ "SuperCollider";
328 strncpy(str
, config_folder
.c_str(), size
);
333 sc_GetUserHomeDirectory(home
, PATH_MAX
);
337 #if defined(SC_IPHONE)
339 #elif defined(__APPLE__)
340 "%s/Library/Application Support/SuperCollider",
341 #elif defined(_WIN32)
344 "%s/.local/share/SuperCollider",
350 // Get the System level 'Extensions' directory.
352 void sc_GetSystemExtensionDirectory(char *str
, int size
)
355 sc_GetSystemAppSupportDirectory(path
, sizeof(path
));
356 sc_AppendToPath(path
, "Extensions");
357 strncpy(str
, path
, size
);
361 // Get the System level 'Extensions' directory.
363 void sc_GetUserExtensionDirectory(char *str
, int size
)
366 sc_GetUserAppSupportDirectory(path
, sizeof(path
));
367 sc_AppendToPath(path
, "Extensions");
368 strncpy(str
, path
, size
);
371 // Get the directory for the configuration files.
372 void sc_GetUserConfigDirectory(char *str
, int size
)
374 // XDG support according to http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
375 char * xdg_config_home
= getenv("XDG_CONFIG_HOME");
376 if (xdg_config_home
) {
377 string config_folder
= string(xdg_config_home
) + SC_PATH_DELIMITER
+ "SuperCollider";
378 strncpy(str
, config_folder
.c_str(), size
);
382 #if defined(__linux__) || defined(__freebsd__)
385 sc_GetUserHomeDirectory(home
, PATH_MAX
);
386 sc_AppendToPath(home
, ".config/SuperCollider");
387 strncpy(str
, home
, size
);
389 sc_GetUserAppSupportDirectory(str
, size
);
400 WIN32_FIND_DATA mEntry
;
404 struct dirent
* mEntry
;
408 SC_DirHandle
* sc_OpenDir(const char* dirname
)
410 SC_DirHandle
* dir
= new SC_DirHandle
;
411 memset(dir
, 0, sizeof(SC_DirHandle
));
414 char allInDir
[PATH_MAX
];
415 snprintf(allInDir
, PATH_MAX
, "%s\\*.*", dirname
);
417 dir
->mHandle
= ::FindFirstFile(allInDir
, &dir
->mEntry
);
418 if (dir
->mHandle
== INVALID_HANDLE_VALUE
) {
425 dir
->mHandle
= opendir(dirname
);
435 void sc_CloseDir(SC_DirHandle
* dir
)
438 ::FindClose(dir
->mHandle
);
440 closedir(dir
->mHandle
);
445 bool sc_ReadDir(SC_DirHandle
* dir
, const char* dirname
, char* path
, bool& skipEntry
)
453 const char* entry
= dir
->mEntry
.cFileName
;
455 if (sc_IsSpecialDirectory(entry
) || (skipEntry
&& sc_SkipDirectory(entry
))) {
463 char entrypathname
[PATH_MAX
];
464 strncpy(entrypathname
, dirname
, PATH_MAX
);
465 sc_AppendToPath(entrypathname
, dir
->mEntry
.cFileName
);
467 bool isAlias
= false;
468 sc_ResolveIfAlias(entrypathname
, path
, isAlias
, PATH_MAX
);
470 if (!::FindNextFile(dir
->mHandle
, &dir
->mEntry
)) {
479 dir
->mEntry
= readdir(dir
->mHandle
);
483 const char* entry
= dir
->mEntry
->d_name
;
485 if (sc_IsSpecialDirectory(entry
) || (skipEntry
&& sc_SkipDirectory(entry
))) {
492 // construct path from dir entry
493 char entrypathname
[PATH_MAX
];
494 strncpy(entrypathname
, dirname
, PATH_MAX
);
495 sc_AppendToPath(entrypathname
, dir
->mEntry
->d_name
);
498 bool isAlias
= false;
499 if (sc_ResolveIfAlias(entrypathname
, path
, isAlias
, strlen(entrypathname
))<0)
515 char mFolder
[PATH_MAX
];
516 WIN32_FIND_DATA mEntry
;
517 char mEntryPath
[PATH_MAX
];
525 SC_GlobHandle
* sc_Glob(const char* pattern
)
527 SC_GlobHandle
* glob
= new SC_GlobHandle
;
530 char patternWin
[1024];
532 strncpy(patternWin
, pattern
, 1024);
533 patternWin
[1023] = 0;
534 win32_ReplaceCharInString(patternWin
, 1024, '/', '\\');
536 win32_ExtractContainingFolder(glob
->mFolder
, patternWin
, PATH_MAX
);
538 glob
->mHandle
= ::FindFirstFile(patternWin
, &glob
->mEntry
);
539 if (glob
->mHandle
== INVALID_HANDLE_VALUE
) {
544 glob
->mAtEnd
= false;
546 int flags
= GLOB_MARK
| GLOB_TILDE
;
551 int err
= ::glob(pattern
, flags
, NULL
, &glob
->mHandle
);
563 void sc_GlobFree(SC_GlobHandle
* glob
)
566 ::FindClose(glob
->mHandle
);
568 globfree(&glob
->mHandle
);
573 const char* sc_GlobNext(SC_GlobHandle
* glob
)
578 strncpy(glob
->mEntryPath
, glob
->mFolder
, PATH_MAX
);
579 sc_AppendToPath(glob
->mEntryPath
, glob
->mEntry
.cFileName
);
580 if (!::FindNextFile(glob
->mHandle
, &glob
->mEntry
))
582 return glob
->mEntryPath
;
584 if (glob
->mEntry
>= glob
->mHandle
.gl_pathc
)
586 return glob
->mHandle
.gl_pathv
[glob
->mEntry
++];