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
) {
71 char newpath1
[MAXPATHLEN
];
76 size_t pathLen
= strlen(path
);
78 if ((pathLen
>= 2) && (path
[0] == '~') && ((path
[1] == '/') || (path
[1] == '\\'))) {
80 sc_GetUserHomeDirectory(home
, PATH_MAX
);
83 if ((pathLen
- 1 + strlen(home
)) >= MAXPATHLEN
) {
86 strcpy(newpath1
, home
);
87 strcat(newpath1
, path
+ 1);
89 if (pathLen
>= MAXPATHLEN
) {
92 strcpy(newpath1
, path
);
96 if (pathLen
>= MAXPATHLEN
) {
99 strcpy(newpath1
, path
);
102 bool isAlias
= false;
103 sc_ResolveIfAlias(newpath1
, newpath2
, isAlias
, PATH_MAX
);
109 // Returns TRUE iff dirname is an existing directory.
111 bool sc_DirectoryExists(const char *dirname
)
114 DWORD attr
= GetFileAttributes(dirname
);
115 return ((attr
!= INVALID_FILE_ATTRIBUTES
) &&
116 (attr
& FILE_ATTRIBUTE_DIRECTORY
));
119 return ((stat(dirname
, &buf
) == 0) &&
120 S_ISDIR(buf
.st_mode
));
124 bool sc_IsSymlink(const char* path
)
132 return ((stat(path
, &buf
) == 0) &&
133 S_ISLNK(buf
.st_mode
));
137 bool sc_IsNonHostPlatformDir(const char *name
)
139 #if defined(SC_IPHONE)
140 const char a
[] = "linux", b
[] = "windows", c
[]="osx";
141 #elif defined(__APPLE__)
142 const char a
[] = "linux", b
[] = "windows", c
[]="iphone";
143 #elif defined(__linux__)
144 const char a
[] = "osx", b
[] = "windows", c
[]="iphone";
145 #elif defined(__FreeBSD__)
146 const char a
[] = "osx", b
[] = "windows", c
[]="iphone";
147 #elif defined(_WIN32)
148 const char a
[] = "osx", b
[] = "linux", c
[]="iphone";
150 return ((strcmp(name
, a
) == 0) ||
151 (strcmp(name
, b
) == 0) ||
152 (strcmp(name
, c
) == 0));
156 // Returns TRUE iff 'name' is special directory '.' or '..'
158 inline static bool sc_IsSpecialDirectory(const char* name
)
160 return (strcmp(name
, ".") == 0) || (strcmp(name
, "..") == 0);
163 // Returns TRUE iff 'name' is to be ignored during compilation.
165 bool sc_SkipDirectory(const char *name
)
167 return ((strcasecmp(name
, "help") == 0) ||
168 (strcasecmp(name
, "ignore") == 0) ||
169 (strcmp(name
, ".svn") == 0) ||
170 (strcmp(name
, ".git") == 0) ||
171 (strcmp(name
, "_darcs") == 0) ||
172 ((strncmp(name
, "scide_", 6) == 0) && (strcmp(name
+6, gIdeName
) != 0)) ||
173 sc_IsNonHostPlatformDir(name
));
177 int sc_ResolveIfAlias(const char *path
, char *returnPath
, bool &isAlias
, int length
)
180 #if defined(__APPLE__) && !defined(SC_IPHONE)
182 OSStatus osStatusErr
= FSPathMakeRef ((const UInt8
*) path
, &dirRef
, NULL
);
183 if ( !osStatusErr
) {
186 OSErr err
= FSResolveAliasFile (&dirRef
, true, &isFolder
, &wasAliased
);
191 isAlias
= wasAliased
;
194 UInt8 resolvedPath
[PATH_MAX
];
195 osStatusErr
= FSRefMakePath (&dirRef
, resolvedPath
, length
);
200 strncpy(returnPath
, (char *) resolvedPath
, length
);
204 #elif defined(__linux__) || defined(__FreeBSD__)
205 isAlias
= sc_IsSymlink(path
);
206 if (realpath(path
, returnPath
))
213 strcpy(returnPath
, path
);
217 // Support for Bundles
219 #if defined(__APPLE__) && !defined(SC_IPHONE) // running on OS X
221 // Support for stand-alone applications
223 bool sc_IsStandAlone()
225 return SC_StandAloneInfo::IsStandAlone();
228 void sc_GetResourceDirectory(char* pathBuf
, int length
)
230 SC_StandAloneInfo::GetResourceDir(pathBuf
, length
);
233 #elif defined(SC_IPHONE)
235 bool sc_IsStandAlone()
240 void sc_GetResourceDirectory(char* pathBuf
, int length
)
242 sc_GetUserAppSupportDirectory(pathBuf
, length
);
245 #elif defined(__unix__)
247 bool sc_IsStandAlone()
252 void sc_GetResourceDirectory(char* pathBuf
, int length
)
255 strncpy(pathBuf
, SC_DATA_DIR
, length
);
257 strncpy(pathBuf
, "/usr/share/SuperCollider", length
);
263 bool sc_IsStandAlone()
268 static void sc_GetResourceDirectoryFromAppDirectory(char* pathBuf
, int length
)
270 char * result
= getcwd(pathBuf
, length
);
271 if (result
!= pathBuf
)
272 throw std::runtime_error("cannot get current working directory");
276 void sc_GetResourceDirectory(char* pathBuf
, int length
)
278 return sc_GetResourceDirectoryFromAppDirectory(pathBuf
, length
);
285 // Support for Extensions
287 // Get the user home directory.
289 void sc_GetUserHomeDirectory(char *str
, int size
)
292 char *home
= getenv("HOME");
294 strncpy(str
, home
, size
);
296 // cwd is not the user home directory; but this is better than leaving mem uninitialised.
300 win32_GetHomeFolder(str
,size
);
305 // Get the System level data directory.
307 void sc_GetSystemAppSupportDirectory(char *str
, int size
)
310 #if defined(SC_DATA_DIR)
312 #elif defined(SC_IPHONE)
314 #elif defined(__APPLE__)
315 "/Library/Application Support/SuperCollider",
316 #elif defined(_WIN32)
317 ( getenv("SC_SYSAPPSUP_PATH")==NULL
) ? "C:\\SuperCollider" : getenv("SC_SYSAPPSUP_PATH"),
319 "/usr/local/share/SuperCollider",
325 // Get the User level data directory.
327 void sc_GetUserAppSupportDirectory(char *str
, int size
)
329 // XDG support according to http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
330 char * xdg_data_home
= getenv("XDG_DATA_HOME");
332 string config_folder
= string(xdg_data_home
) + SC_PATH_DELIMITER
+ "SuperCollider";
333 strncpy(str
, config_folder
.c_str(), size
);
338 sc_GetUserHomeDirectory(home
, PATH_MAX
);
342 #if defined(SC_IPHONE)
344 #elif defined(__APPLE__)
345 "%s/Library/Application Support/SuperCollider",
346 #elif defined(_WIN32)
349 "%s/.local/share/SuperCollider",
355 // Get the System level 'Extensions' directory.
357 void sc_GetSystemExtensionDirectory(char *str
, int size
)
360 sc_GetSystemAppSupportDirectory(path
, sizeof(path
));
361 sc_AppendToPath(path
, "Extensions");
362 strncpy(str
, path
, size
);
366 // Get the System level 'Extensions' directory.
368 void sc_GetUserExtensionDirectory(char *str
, int size
)
371 sc_GetUserAppSupportDirectory(path
, sizeof(path
));
372 sc_AppendToPath(path
, "Extensions");
373 strncpy(str
, path
, size
);
376 // Get the directory for the configuration files.
377 void sc_GetUserConfigDirectory(char *str
, int size
)
379 // XDG support according to http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
380 char * xdg_config_home
= getenv("XDG_CONFIG_HOME");
381 if (xdg_config_home
) {
382 string config_folder
= string(xdg_config_home
) + SC_PATH_DELIMITER
+ "SuperCollider";
383 strncpy(str
, config_folder
.c_str(), size
);
387 #if defined(__linux__) || defined(__freebsd__)
390 sc_GetUserHomeDirectory(home
, PATH_MAX
);
391 sc_AppendToPath(home
, ".config/SuperCollider");
392 strncpy(str
, home
, size
);
394 sc_GetUserAppSupportDirectory(str
, size
);
405 WIN32_FIND_DATA mEntry
;
409 struct dirent
* mEntry
;
413 SC_DirHandle
* sc_OpenDir(const char* dirname
)
415 SC_DirHandle
* dir
= new SC_DirHandle
;
416 memset(dir
, 0, sizeof(SC_DirHandle
));
419 char allInDir
[PATH_MAX
];
420 snprintf(allInDir
, PATH_MAX
, "%s\\*.*", dirname
);
422 dir
->mHandle
= ::FindFirstFile(allInDir
, &dir
->mEntry
);
423 if (dir
->mHandle
== INVALID_HANDLE_VALUE
) {
430 dir
->mHandle
= opendir(dirname
);
440 void sc_CloseDir(SC_DirHandle
* dir
)
443 ::FindClose(dir
->mHandle
);
445 closedir(dir
->mHandle
);
450 bool sc_ReadDir(SC_DirHandle
* dir
, const char* dirname
, char* path
, bool& skipEntry
)
458 const char* entry
= dir
->mEntry
.cFileName
;
460 if (sc_IsSpecialDirectory(entry
) || (skipEntry
&& sc_SkipDirectory(entry
))) {
468 char entrypathname
[PATH_MAX
];
469 strncpy(entrypathname
, dirname
, PATH_MAX
);
470 sc_AppendToPath(entrypathname
, dir
->mEntry
.cFileName
);
472 bool isAlias
= false;
473 sc_ResolveIfAlias(entrypathname
, path
, isAlias
, PATH_MAX
);
475 if (!::FindNextFile(dir
->mHandle
, &dir
->mEntry
)) {
484 dir
->mEntry
= readdir(dir
->mHandle
);
488 const char* entry
= dir
->mEntry
->d_name
;
490 if (sc_IsSpecialDirectory(entry
) || (skipEntry
&& sc_SkipDirectory(entry
))) {
497 // construct path from dir entry
498 char entrypathname
[PATH_MAX
];
499 strncpy(entrypathname
, dirname
, PATH_MAX
);
500 sc_AppendToPath(entrypathname
, dir
->mEntry
->d_name
);
503 bool isAlias
= false;
504 if (sc_ResolveIfAlias(entrypathname
, path
, isAlias
, strlen(entrypathname
))<0)
520 char mFolder
[PATH_MAX
];
521 WIN32_FIND_DATA mEntry
;
522 char mEntryPath
[PATH_MAX
];
530 SC_GlobHandle
* sc_Glob(const char* pattern
)
532 SC_GlobHandle
* glob
= new SC_GlobHandle
;
535 char patternWin
[1024];
537 strncpy(patternWin
, pattern
, 1024);
538 patternWin
[1023] = 0;
539 win32_ReplaceCharInString(patternWin
, 1024, '/', '\\');
541 win32_ExtractContainingFolder(glob
->mFolder
, patternWin
, PATH_MAX
);
543 glob
->mHandle
= ::FindFirstFile(patternWin
, &glob
->mEntry
);
544 if (glob
->mHandle
== INVALID_HANDLE_VALUE
) {
549 glob
->mAtEnd
= false;
551 int flags
= GLOB_MARK
| GLOB_TILDE
;
556 int err
= ::glob(pattern
, flags
, NULL
, &glob
->mHandle
);
568 void sc_GlobFree(SC_GlobHandle
* glob
)
571 ::FindClose(glob
->mHandle
);
573 globfree(&glob
->mHandle
);
578 const char* sc_GlobNext(SC_GlobHandle
* glob
)
583 strncpy(glob
->mEntryPath
, glob
->mFolder
, PATH_MAX
);
584 sc_AppendToPath(glob
->mEntryPath
, glob
->mEntry
.cFileName
);
585 if (!::FindNextFile(glob
->mHandle
, &glob
->mEntry
))
587 return glob
->mEntryPath
;
589 if (glob
->mEntry
>= glob
->mHandle
.gl_pathc
)
591 return glob
->mHandle
.gl_pathv
[glob
->mEntry
++];