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
28 # include "SC_Win32Utils.h"
33 # include <sys/param.h>
34 # include <sys/stat.h>
35 # include <sys/types.h>
38 #include "SC_DirUtils.h"
40 #if defined(__APPLE__) || defined(SC_IPHONE)
41 #ifndef _SC_StandAloneInfo_
42 # include "SC_StandAloneInfo_Darwin.h"
44 # include <CoreFoundation/CFString.h>
45 # include <CoreFoundation/CFBundle.h>
47 # include <CoreServices/CoreServices.h>
51 const char * gIdeName
= "none";
53 // Add a component to a path.
55 void sc_AppendToPath(char *path
, size_t max_size
, const char *component
)
57 size_t currentLength
= strlen(path
);
58 if (currentLength
>= max_size
-1)
60 path
[currentLength
] = SC_PATH_DELIMITER
[0];
61 path
[currentLength
+1] = 0;
64 char * tail
= path
+ currentLength
;
65 size_t remain
= max_size
- currentLength
;
67 strncat(tail
, component
, remain
);
71 char *sc_StandardizePath(const char *path
, char *newpath2
)
73 char newpath1
[MAXPATHLEN
];
78 size_t pathLen
= strlen(path
);
80 if ((pathLen
>= 2) && (path
[0] == '~') && ((path
[1] == '/') || (path
[1] == '\\'))) {
82 sc_GetUserHomeDirectory(home
, PATH_MAX
);
85 if ((pathLen
- 1 + strlen(home
)) >= MAXPATHLEN
) {
88 strcpy(newpath1
, home
);
89 strcat(newpath1
, path
+ 1);
91 if (pathLen
>= MAXPATHLEN
) {
94 strcpy(newpath1
, path
);
98 if (pathLen
>= MAXPATHLEN
) {
101 strcpy(newpath1
, path
);
104 bool isAlias
= false;
105 if(sc_ResolveIfAlias(newpath1
, newpath2
, isAlias
, PATH_MAX
)!=0) {
106 strcpy(newpath2
, newpath1
);
113 // Returns TRUE iff dirname is an existing directory.
115 bool sc_DirectoryExists(const char *dirname
)
118 DWORD attr
= GetFileAttributes(dirname
);
119 return ((attr
!= INVALID_FILE_ATTRIBUTES
) &&
120 (attr
& FILE_ATTRIBUTE_DIRECTORY
));
123 return ((stat(dirname
, &buf
) == 0) &&
124 S_ISDIR(buf
.st_mode
));
128 bool sc_IsSymlink(const char* path
)
136 return ((stat(path
, &buf
) == 0) &&
137 S_ISLNK(buf
.st_mode
));
141 bool sc_IsNonHostPlatformDir(const char *name
)
143 #if defined(SC_IPHONE)
144 const char a
[] = "linux", b
[] = "windows", c
[]="osx";
145 #elif defined(__APPLE__)
146 const char a
[] = "linux", b
[] = "windows", c
[]="iphone";
147 #elif defined(__linux__)
148 const char a
[] = "osx", b
[] = "windows", c
[]="iphone";
149 #elif defined(__FreeBSD__)
150 const char a
[] = "osx", b
[] = "windows", c
[]="iphone";
151 #elif defined(_WIN32)
152 const char a
[] = "osx", b
[] = "linux", c
[]="iphone";
154 return ((strcmp(name
, a
) == 0) ||
155 (strcmp(name
, b
) == 0) ||
156 (strcmp(name
, c
) == 0));
160 // Returns TRUE iff 'name' is special directory '.' or '..'
162 inline static bool sc_IsSpecialDirectory(const char* name
)
164 return (strcmp(name
, ".") == 0) || (strcmp(name
, "..") == 0);
167 // Returns TRUE iff 'name' is to be ignored during compilation.
169 bool sc_SkipDirectory(const char *name
)
171 return ((strcasecmp(name
, "help") == 0) ||
172 (strcasecmp(name
, "ignore") == 0) ||
173 (strcmp(name
, ".svn") == 0) ||
174 (strcmp(name
, ".git") == 0) ||
175 (strcmp(name
, "_darcs") == 0) ||
176 ((strncmp(name
, "scide_", 6) == 0) && (strcmp(name
+6, gIdeName
) != 0)) ||
177 sc_IsNonHostPlatformDir(name
));
181 int sc_ResolveIfAlias(const char *path
, char *returnPath
, bool &isAlias
, int length
)
184 #if defined(__APPLE__) && !defined(SC_IPHONE)
186 OSStatus osStatusErr
= FSPathMakeRef ((const UInt8
*) path
, &dirRef
, NULL
);
187 if ( !osStatusErr
) {
190 OSErr err
= FSResolveAliasFile (&dirRef
, true, &isFolder
, &wasAliased
);
195 isAlias
= wasAliased
;
198 UInt8 resolvedPath
[PATH_MAX
];
199 osStatusErr
= FSRefMakePath (&dirRef
, resolvedPath
, length
);
204 strncpy(returnPath
, (char *) resolvedPath
, length
);
209 strcpy(returnPath
, path
);
213 // Support for Bundles
215 #if defined(__APPLE__) && !defined(SC_IPHONE) // running on OS X
217 // Support for stand-alone applications
219 bool sc_IsStandAlone()
221 return SC_StandAloneInfo::IsStandAlone();
224 void sc_GetResourceDirectory(char* pathBuf
, int length
)
226 SC_StandAloneInfo::GetResourceDir(pathBuf
, length
);
229 #elif defined(SC_IPHONE)
231 bool sc_IsStandAlone()
236 void sc_GetResourceDirectory(char* pathBuf
, int length
)
238 sc_GetUserAppSupportDirectory(pathBuf
, length
);
241 #elif defined(__unix__)
243 bool sc_IsStandAlone()
248 void sc_GetResourceDirectory(char* pathBuf
, int length
)
251 strncpy(pathBuf
, SC_DATA_DIR
, length
);
253 strncpy(pathBuf
, "/usr/share/SuperCollider", length
);
259 bool sc_IsStandAlone()
264 static void sc_GetResourceDirectoryFromAppDirectory(char* pathBuf
, int length
)
266 char * result
= getcwd(pathBuf
, length
);
267 if (result
!= pathBuf
)
268 throw std::runtime_error("cannot get current working directory");
272 void sc_GetResourceDirectory(char* pathBuf
, int length
)
274 return sc_GetResourceDirectoryFromAppDirectory(pathBuf
, length
);
281 // Support for Extensions
283 // Get the user home directory.
285 void sc_GetUserHomeDirectory(char *str
, int size
)
288 const char *home
= getenv("HOME");
290 strncpy(str
, home
, size
);
292 // cwd is not the user home directory; but this is better than leaving mem uninitialised.
296 win32_GetHomeFolder(str
,size
);
301 // Get the System level data directory.
303 void sc_GetSystemAppSupportDirectory(char *str
, int size
)
306 #if defined(SC_DATA_DIR)
308 #elif defined(SC_IPHONE)
310 #elif defined(__APPLE__)
311 "/Library/Application Support/SuperCollider",
312 #elif defined(_WIN32)
313 ( getenv("SC_SYSAPPSUP_PATH")==NULL
) ? "C:\\SuperCollider" : getenv("SC_SYSAPPSUP_PATH"),
315 "/usr/local/share/SuperCollider",
321 // Get the User level data directory.
323 void sc_GetUserAppSupportDirectory(char *str
, int size
)
325 // XDG support according to http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
326 const char * xdg_data_home
= getenv("XDG_DATA_HOME");
328 strncpy(str
, xdg_data_home
, size
);
329 sc_AppendToPath(str
, size
, "SuperCollider");
333 sc_GetUserHomeDirectory(str
, size
);
335 #if defined(SC_IPHONE)
336 sc_AppendToPath(str
, size
, "Documents");
337 #elif defined(__APPLE__)
338 sc_AppendToPath(str
, size
, "Library/Application Support/SuperCollider");
339 #elif defined(_WIN32)
340 sc_AppendToPath(str
, size
, "SuperCollider");
342 sc_AppendToPath(str
, size
, ".local/share/SuperCollider");
347 // Get the System level 'Extensions' directory.
349 void sc_GetSystemExtensionDirectory(char *str
, int size
)
351 sc_GetSystemAppSupportDirectory(str
, size
);
352 sc_AppendToPath(str
, size
, "Extensions");
356 // Get the System level 'Extensions' directory.
358 void sc_GetUserExtensionDirectory(char *str
, int size
)
360 sc_GetUserAppSupportDirectory(str
, size
);
361 sc_AppendToPath(str
, size
, "Extensions");
364 // Get the directory for the configuration files.
365 void sc_GetUserConfigDirectory(char *str
, int size
)
367 // XDG support according to http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
368 const char * xdg_config_home
= getenv("XDG_CONFIG_HOME");
369 if (xdg_config_home
) {
370 strncpy(str
, xdg_config_home
, size
);
371 sc_AppendToPath(str
, size
, "SuperCollider");
374 #if defined(__linux__) || defined(__freebsd__)
377 sc_GetUserHomeDirectory(str
, size
);
378 sc_AppendToPath(str
, size
, ".config/SuperCollider");
380 sc_GetUserAppSupportDirectory(str
, size
);
391 WIN32_FIND_DATA mEntry
;
395 struct dirent
* mEntry
;
399 SC_DirHandle
* sc_OpenDir(const char* dirname
)
401 SC_DirHandle
* dir
= new SC_DirHandle
;
402 memset(dir
, 0, sizeof(SC_DirHandle
));
405 char allInDir
[PATH_MAX
];
406 snprintf(allInDir
, PATH_MAX
, "%s\\*.*", dirname
);
408 dir
->mHandle
= ::FindFirstFile(allInDir
, &dir
->mEntry
);
409 if (dir
->mHandle
== INVALID_HANDLE_VALUE
) {
416 dir
->mHandle
= opendir(dirname
);
426 void sc_CloseDir(SC_DirHandle
* dir
)
429 ::FindClose(dir
->mHandle
);
431 closedir(dir
->mHandle
);
436 bool sc_ReadDir(SC_DirHandle
* dir
, const char* dirname
, char* path
, bool& skipEntry
)
444 const char* entry
= dir
->mEntry
.cFileName
;
446 if (sc_IsSpecialDirectory(entry
) || (skipEntry
&& sc_SkipDirectory(entry
))) {
454 char entrypathname
[PATH_MAX
];
455 strncpy(entrypathname
, dirname
, PATH_MAX
);
456 sc_AppendToPath(entrypathname
, PATH_MAX
, dir
->mEntry
.cFileName
);
458 bool isAlias
= false;
459 sc_ResolveIfAlias(entrypathname
, path
, isAlias
, PATH_MAX
);
461 if (!::FindNextFile(dir
->mHandle
, &dir
->mEntry
)) {
470 dir
->mEntry
= readdir(dir
->mHandle
);
474 const char* entry
= dir
->mEntry
->d_name
;
476 if (sc_IsSpecialDirectory(entry
) || (skipEntry
&& sc_SkipDirectory(entry
))) {
483 // construct path from dir entry
484 char entrypathname
[PATH_MAX
];
485 strncpy(entrypathname
, dirname
, PATH_MAX
);
486 sc_AppendToPath(entrypathname
, PATH_MAX
, dir
->mEntry
->d_name
);
489 bool isAlias
= false;
490 if (sc_ResolveIfAlias(entrypathname
, path
, isAlias
, strlen(entrypathname
))<0)
506 char mFolder
[PATH_MAX
];
507 WIN32_FIND_DATA mEntry
;
508 char mEntryPath
[PATH_MAX
];
516 SC_GlobHandle
* sc_Glob(const char* pattern
)
518 SC_GlobHandle
* glob
= new SC_GlobHandle
;
521 char patternWin
[1024];
523 strncpy(patternWin
, pattern
, 1024);
524 patternWin
[1023] = 0;
525 win32_ReplaceCharInString(patternWin
, 1024, '/', '\\');
527 win32_ExtractContainingFolder(glob
->mFolder
, patternWin
, PATH_MAX
);
529 glob
->mHandle
= ::FindFirstFile(patternWin
, &glob
->mEntry
);
530 if (glob
->mHandle
== INVALID_HANDLE_VALUE
) {
535 glob
->mAtEnd
= false;
537 int flags
= GLOB_MARK
| GLOB_TILDE
;
542 int err
= ::glob(pattern
, flags
, NULL
, &glob
->mHandle
);
554 void sc_GlobFree(SC_GlobHandle
* glob
)
557 ::FindClose(glob
->mHandle
);
559 globfree(&glob
->mHandle
);
564 const char* sc_GlobNext(SC_GlobHandle
* glob
)
569 strncpy(glob
->mEntryPath
, glob
->mFolder
, PATH_MAX
);
570 sc_AppendToPath(glob
->mEntryPath
, PATH_MAX
, glob
->mEntry
.cFileName
);
571 if (!::FindNextFile(glob
->mHandle
, &glob
->mEntry
))
573 return glob
->mEntryPath
;
575 if (glob
->mEntry
>= glob
->mHandle
.gl_pathc
)
577 return glob
->mHandle
.gl_pathv
[glob
->mEntry
++];