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
, size_t max_size
, const char *component
)
62 size_t currentLength
= strlen(path
);
63 if (currentLength
>= max_size
-1)
65 path
[currentLength
] = SC_PATH_DELIMITER
[0];
66 path
[currentLength
+1] = 0;
69 char * tail
= path
+ currentLength
;
70 size_t remain
= max_size
- currentLength
;
72 strncat(tail
, component
, remain
);
76 char *sc_StandardizePath(const char *path
, char *newpath2
)
78 char newpath1
[MAXPATHLEN
];
83 size_t pathLen
= strlen(path
);
85 if ((pathLen
>= 2) && (path
[0] == '~') && ((path
[1] == '/') || (path
[1] == '\\'))) {
87 sc_GetUserHomeDirectory(home
, PATH_MAX
);
90 if ((pathLen
- 1 + strlen(home
)) >= MAXPATHLEN
) {
93 strcpy(newpath1
, home
);
94 strcat(newpath1
, path
+ 1);
96 if (pathLen
>= MAXPATHLEN
) {
99 strcpy(newpath1
, path
);
103 if (pathLen
>= MAXPATHLEN
) {
106 strcpy(newpath1
, path
);
109 bool isAlias
= false;
110 if(sc_ResolveIfAlias(newpath1
, newpath2
, isAlias
, PATH_MAX
)!=0) {
111 strcpy(newpath2
, newpath1
);
118 // Returns TRUE iff dirname is an existing directory.
120 bool sc_DirectoryExists(const char *dirname
)
123 DWORD attr
= GetFileAttributes(dirname
);
124 return ((attr
!= INVALID_FILE_ATTRIBUTES
) &&
125 (attr
& FILE_ATTRIBUTE_DIRECTORY
));
128 return ((stat(dirname
, &buf
) == 0) &&
129 S_ISDIR(buf
.st_mode
));
133 bool sc_IsSymlink(const char* path
)
141 return ((stat(path
, &buf
) == 0) &&
142 S_ISLNK(buf
.st_mode
));
146 bool sc_IsNonHostPlatformDir(const char *name
)
148 #if defined(SC_IPHONE)
149 const char a
[] = "linux", b
[] = "windows", c
[]="osx";
150 #elif defined(__APPLE__)
151 const char a
[] = "linux", b
[] = "windows", c
[]="iphone";
152 #elif defined(__linux__)
153 const char a
[] = "osx", b
[] = "windows", c
[]="iphone";
154 #elif defined(__FreeBSD__)
155 const char a
[] = "osx", b
[] = "windows", c
[]="iphone";
156 #elif defined(_WIN32)
157 const char a
[] = "osx", b
[] = "linux", c
[]="iphone";
159 return ((strcmp(name
, a
) == 0) ||
160 (strcmp(name
, b
) == 0) ||
161 (strcmp(name
, c
) == 0));
165 // Returns TRUE iff 'name' is special directory '.' or '..'
167 inline static bool sc_IsSpecialDirectory(const char* name
)
169 return (strcmp(name
, ".") == 0) || (strcmp(name
, "..") == 0);
172 // Returns TRUE iff 'name' is to be ignored during compilation.
174 bool sc_SkipDirectory(const char *name
)
176 return ((strcasecmp(name
, "help") == 0) ||
177 (strcasecmp(name
, "ignore") == 0) ||
178 (strcmp(name
, ".svn") == 0) ||
179 (strcmp(name
, ".git") == 0) ||
180 (strcmp(name
, "_darcs") == 0) ||
181 ((strncmp(name
, "scide_", 6) == 0) && (strcmp(name
+6, gIdeName
) != 0)) ||
182 sc_IsNonHostPlatformDir(name
));
186 int sc_ResolveIfAlias(const char *path
, char *returnPath
, bool &isAlias
, int length
)
189 #if defined(__APPLE__) && !defined(SC_IPHONE)
191 OSStatus osStatusErr
= FSPathMakeRef ((const UInt8
*) path
, &dirRef
, NULL
);
192 if ( !osStatusErr
) {
195 OSErr err
= FSResolveAliasFile (&dirRef
, true, &isFolder
, &wasAliased
);
200 isAlias
= wasAliased
;
203 UInt8 resolvedPath
[PATH_MAX
];
204 osStatusErr
= FSRefMakePath (&dirRef
, resolvedPath
, length
);
209 strncpy(returnPath
, (char *) resolvedPath
, length
);
214 strcpy(returnPath
, path
);
218 // Support for Bundles
220 #if defined(__APPLE__) && !defined(SC_IPHONE) // running on OS X
222 // Support for stand-alone applications
224 bool sc_IsStandAlone()
226 return SC_StandAloneInfo::IsStandAlone();
229 void sc_GetResourceDirectory(char* pathBuf
, int length
)
231 SC_StandAloneInfo::GetResourceDir(pathBuf
, length
);
234 #elif defined(SC_IPHONE)
236 bool sc_IsStandAlone()
241 void sc_GetResourceDirectory(char* pathBuf
, int length
)
243 sc_GetUserAppSupportDirectory(pathBuf
, length
);
246 #elif defined(__unix__)
248 bool sc_IsStandAlone()
253 void sc_GetResourceDirectory(char* pathBuf
, int length
)
256 strncpy(pathBuf
, SC_DATA_DIR
, length
);
258 strncpy(pathBuf
, "/usr/share/SuperCollider", length
);
264 bool sc_IsStandAlone()
269 static void sc_GetResourceDirectoryFromAppDirectory(char* pathBuf
, int length
)
271 char * result
= getcwd(pathBuf
, length
);
272 if (result
!= pathBuf
)
273 throw std::runtime_error("cannot get current working directory");
277 void sc_GetResourceDirectory(char* pathBuf
, int length
)
279 return sc_GetResourceDirectoryFromAppDirectory(pathBuf
, length
);
286 // Support for Extensions
288 // Get the user home directory.
290 void sc_GetUserHomeDirectory(char *str
, int size
)
293 char *home
= getenv("HOME");
295 strncpy(str
, home
, size
);
297 // cwd is not the user home directory; but this is better than leaving mem uninitialised.
301 win32_GetHomeFolder(str
,size
);
306 // Get the System level data directory.
308 void sc_GetSystemAppSupportDirectory(char *str
, int size
)
311 #if defined(SC_DATA_DIR)
313 #elif defined(SC_IPHONE)
315 #elif defined(__APPLE__)
316 "/Library/Application Support/SuperCollider",
317 #elif defined(_WIN32)
318 ( getenv("SC_SYSAPPSUP_PATH")==NULL
) ? "C:\\SuperCollider" : getenv("SC_SYSAPPSUP_PATH"),
320 "/usr/local/share/SuperCollider",
326 // Get the User level data directory.
328 void sc_GetUserAppSupportDirectory(char *str
, int size
)
330 // XDG support according to http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
331 char * xdg_data_home
= getenv("XDG_DATA_HOME");
333 string config_folder
= string(xdg_data_home
) + SC_PATH_DELIMITER
+ "SuperCollider";
334 strncpy(str
, config_folder
.c_str(), size
);
339 sc_GetUserHomeDirectory(home
, PATH_MAX
);
343 #if defined(SC_IPHONE)
345 #elif defined(__APPLE__)
346 "%s/Library/Application Support/SuperCollider",
347 #elif defined(_WIN32)
350 "%s/.local/share/SuperCollider",
356 // Get the System level 'Extensions' directory.
358 void sc_GetSystemExtensionDirectory(char *str
, int size
)
361 sc_GetSystemAppSupportDirectory(path
, sizeof(path
));
362 sc_AppendToPath(path
, PATH_MAX
, "Extensions");
363 strncpy(str
, path
, size
);
367 // Get the System level 'Extensions' directory.
369 void sc_GetUserExtensionDirectory(char *str
, int size
)
372 sc_GetUserAppSupportDirectory(path
, sizeof(path
));
373 sc_AppendToPath(path
, PATH_MAX
, "Extensions");
374 strncpy(str
, path
, size
);
377 // Get the directory for the configuration files.
378 void sc_GetUserConfigDirectory(char *str
, int size
)
380 // XDG support according to http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
381 char * xdg_config_home
= getenv("XDG_CONFIG_HOME");
382 if (xdg_config_home
) {
383 string config_folder
= string(xdg_config_home
) + SC_PATH_DELIMITER
+ "SuperCollider";
384 strncpy(str
, config_folder
.c_str(), size
);
388 #if defined(__linux__) || defined(__freebsd__)
391 sc_GetUserHomeDirectory(home
, PATH_MAX
);
392 sc_AppendToPath(home
, PATH_MAX
, ".config/SuperCollider");
393 strncpy(str
, home
, size
);
395 sc_GetUserAppSupportDirectory(str
, size
);
406 WIN32_FIND_DATA mEntry
;
410 struct dirent
* mEntry
;
414 SC_DirHandle
* sc_OpenDir(const char* dirname
)
416 SC_DirHandle
* dir
= new SC_DirHandle
;
417 memset(dir
, 0, sizeof(SC_DirHandle
));
420 char allInDir
[PATH_MAX
];
421 snprintf(allInDir
, PATH_MAX
, "%s\\*.*", dirname
);
423 dir
->mHandle
= ::FindFirstFile(allInDir
, &dir
->mEntry
);
424 if (dir
->mHandle
== INVALID_HANDLE_VALUE
) {
431 dir
->mHandle
= opendir(dirname
);
441 void sc_CloseDir(SC_DirHandle
* dir
)
444 ::FindClose(dir
->mHandle
);
446 closedir(dir
->mHandle
);
451 bool sc_ReadDir(SC_DirHandle
* dir
, const char* dirname
, char* path
, bool& skipEntry
)
459 const char* entry
= dir
->mEntry
.cFileName
;
461 if (sc_IsSpecialDirectory(entry
) || (skipEntry
&& sc_SkipDirectory(entry
))) {
469 char entrypathname
[PATH_MAX
];
470 strncpy(entrypathname
, dirname
, PATH_MAX
);
471 sc_AppendToPath(entrypathname
, dir
->mEntry
.cFileName
);
473 bool isAlias
= false;
474 sc_ResolveIfAlias(entrypathname
, path
, isAlias
, PATH_MAX
);
476 if (!::FindNextFile(dir
->mHandle
, &dir
->mEntry
)) {
485 dir
->mEntry
= readdir(dir
->mHandle
);
489 const char* entry
= dir
->mEntry
->d_name
;
491 if (sc_IsSpecialDirectory(entry
) || (skipEntry
&& sc_SkipDirectory(entry
))) {
498 // construct path from dir entry
499 char entrypathname
[PATH_MAX
];
500 strncpy(entrypathname
, dirname
, PATH_MAX
);
501 sc_AppendToPath(entrypathname
, PATH_MAX
, dir
->mEntry
->d_name
);
504 bool isAlias
= false;
505 if (sc_ResolveIfAlias(entrypathname
, path
, isAlias
, strlen(entrypathname
))<0)
521 char mFolder
[PATH_MAX
];
522 WIN32_FIND_DATA mEntry
;
523 char mEntryPath
[PATH_MAX
];
531 SC_GlobHandle
* sc_Glob(const char* pattern
)
533 SC_GlobHandle
* glob
= new SC_GlobHandle
;
536 char patternWin
[1024];
538 strncpy(patternWin
, pattern
, 1024);
539 patternWin
[1023] = 0;
540 win32_ReplaceCharInString(patternWin
, 1024, '/', '\\');
542 win32_ExtractContainingFolder(glob
->mFolder
, patternWin
, PATH_MAX
);
544 glob
->mHandle
= ::FindFirstFile(patternWin
, &glob
->mEntry
);
545 if (glob
->mHandle
== INVALID_HANDLE_VALUE
) {
550 glob
->mAtEnd
= false;
552 int flags
= GLOB_MARK
| GLOB_TILDE
;
557 int err
= ::glob(pattern
, flags
, NULL
, &glob
->mHandle
);
569 void sc_GlobFree(SC_GlobHandle
* glob
)
572 ::FindClose(glob
->mHandle
);
574 globfree(&glob
->mHandle
);
579 const char* sc_GlobNext(SC_GlobHandle
* glob
)
584 strncpy(glob
->mEntryPath
, glob
->mFolder
, PATH_MAX
);
585 sc_AppendToPath(glob
->mEntryPath
, glob
->mEntry
.cFileName
);
586 if (!::FindNextFile(glob
->mHandle
, &glob
->mEntry
))
588 return glob
->mEntryPath
;
590 if (glob
->mEntry
>= glob
->mHandle
.gl_pathc
)
592 return glob
->mHandle
.gl_pathv
[glob
->mEntry
++];