1 /* $Id: unix.cpp 25506 2013-06-28 21:11:35Z rubidium $ */
4 * This file is part of OpenTTD.
5 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
6 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
10 /** @file unix.cpp Implementation of Unix specific file handling. */
12 #include "../../stdafx.h"
13 #include "../../textbuf_gui.h"
14 #include "../../openttd.h"
15 #include "../../crashlog.h"
16 #include "../../core/random_func.hpp"
17 #include "../../debug.h"
18 #include "../../string_func.h"
19 #include "../../fios.h"
29 #include <sys/mount.h>
30 #elif (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L) || defined(__GLIBC__)
34 #if defined(OPENBSD) || defined(__NetBSD__) || defined(__FreeBSD__)
39 #include <sys/statvfs.h>
43 #include <sys/sysctl.h>
48 #include <exec/types.h>
49 ULONG __stack
= (1024*1024)*2; // maybe not that much is needed actually ;)
51 /* The system supplied definition of SIG_IGN does not match */
53 #define SIG_IGN (void (*)(int))1
54 #endif /* __MORPHOS__ */
57 #warning add stack symbol to avoid that user needs to set stack manually (tokai)
61 #if defined(__APPLE__)
63 /* the mac implementation needs this file included in the same file as main() */
68 #include "../../safeguards.h"
70 bool FiosIsRoot(const char *path
)
72 #if !defined(__MORPHOS__) && !defined(__AMIGAOS__)
73 return path
[1] == '\0';
75 /* On MorphOS or AmigaOS paths look like: "Volume:directory/subdirectory" */
76 const char *s
= strchr(path
, ':');
77 return s
!= NULL
&& s
[1] == '\0';
81 void FiosGetDrives(FileList
&file_list
)
86 bool FiosGetDiskFreeSpace(const char *path
, uint64
*tot
)
93 if (statfs(path
, &s
) != 0) return false;
94 free
= (uint64
)s
.f_bsize
* s
.f_bavail
;
95 #elif defined(HAS_STATVFS)
98 if (statvfs(path
, &s
) != 0) return false;
99 free
= (uint64
)s
.f_frsize
* s
.f_bavail
;
101 if (tot
!= NULL
) *tot
= free
;
105 bool FiosIsValidFile(const char *path
, const struct dirent
*ent
, struct stat
*sb
)
107 char filename
[MAX_PATH
];
109 #if defined(__MORPHOS__) || defined(__AMIGAOS__)
110 /* On MorphOS or AmigaOS paths look like: "Volume:directory/subdirectory" */
111 if (FiosIsRoot(path
)) {
112 res
= seprintf(filename
, lastof(filename
), "%s:%s", path
, ent
->d_name
);
113 } else // XXX - only next line!
115 assert(path
[strlen(path
) - 1] == PATHSEPCHAR
);
116 if (strlen(path
) > 2) assert(path
[strlen(path
) - 2] != PATHSEPCHAR
);
118 res
= seprintf(filename
, lastof(filename
), "%s%s", path
, ent
->d_name
);
120 /* Could we fully concatenate the path and filename? */
121 if (res
>= (int)lengthof(filename
) || res
< 0) return false;
123 return stat(filename
, sb
) == 0;
126 bool FiosIsHiddenFile(const struct dirent
*ent
)
128 return ent
->d_name
[0] == '.';
135 #include "../../debug.h"
136 #include "../../string_func.h"
138 const char *GetCurrentLocale(const char *param
);
140 #define INTERNALCODE "UTF-8"
143 * Try and try to decipher the current locale from environmental
144 * variables. MacOSX is hardcoded, other OS's are dynamic. If no suitable
145 * locale can be found, don't do any conversion ""
147 static const char *GetLocalCode()
149 #if defined(__APPLE__)
152 /* Strip locale (eg en_US.UTF-8) to only have UTF-8 */
153 const char *locale
= GetCurrentLocale("LC_CTYPE");
154 if (locale
!= NULL
) locale
= strchr(locale
, '.');
156 return (locale
== NULL
) ? "" : locale
+ 1;
161 * Convert between locales, which from and which to is set in the calling
162 * functions OTTD2FS() and FS2OTTD().
164 static const char *convert_tofrom_fs(iconv_t convd
, const char *name
)
166 static char buf
[1024];
167 /* There are different implementations of iconv. The older ones,
168 * e.g. SUSv2, pass a const pointer, whereas the newer ones, e.g.
169 * IEEE 1003.1 (2004), pass a non-const pointer. */
170 #ifdef HAVE_NON_CONST_ICONV
171 char *inbuf
= const_cast<char*>(name
);
173 const char *inbuf
= name
;
177 size_t outlen
= sizeof(buf
) - 1;
178 size_t inlen
= strlen(name
);
180 strecpy(outbuf
, name
, outbuf
+ outlen
);
182 iconv(convd
, NULL
, NULL
, NULL
, NULL
);
183 if (iconv(convd
, &inbuf
, &inlen
, &outbuf
, &outlen
) == (size_t)(-1)) {
184 DEBUG(misc
, 0, "[iconv] error converting '%s'. Errno %d", name
, errno
);
188 /* FIX: invalid characters will abort conversion, but they shouldn't occur? */
193 * Convert from OpenTTD's encoding to that of the local environment
194 * @param name pointer to a valid string that will be converted
195 * @return pointer to a new stringbuffer that contains the converted string
197 const char *OTTD2FS(const char *name
)
199 static iconv_t convd
= (iconv_t
)(-1);
201 if (convd
== (iconv_t
)(-1)) {
202 const char *env
= GetLocalCode();
203 convd
= iconv_open(env
, INTERNALCODE
);
204 if (convd
== (iconv_t
)(-1)) {
205 DEBUG(misc
, 0, "[iconv] conversion from codeset '%s' to '%s' unsupported", INTERNALCODE
, env
);
210 return convert_tofrom_fs(convd
, name
);
214 * Convert to OpenTTD's encoding from that of the local environment
215 * @param name pointer to a valid string that will be converted
216 * @return pointer to a new stringbuffer that contains the converted string
218 const char *FS2OTTD(const char *name
)
220 static iconv_t convd
= (iconv_t
)(-1);
222 if (convd
== (iconv_t
)(-1)) {
223 const char *env
= GetLocalCode();
224 convd
= iconv_open(INTERNALCODE
, env
);
225 if (convd
== (iconv_t
)(-1)) {
226 DEBUG(misc
, 0, "[iconv] conversion from codeset '%s' to '%s' unsupported", env
, INTERNALCODE
);
231 return convert_tofrom_fs(convd
, name
);
235 const char *FS2OTTD(const char *name
) {return name
;}
236 const char *OTTD2FS(const char *name
) {return name
;}
237 #endif /* WITH_ICONV */
239 void ShowInfo(const char *str
)
241 fprintf(stderr
, "%s\n", str
);
244 #if !defined(__APPLE__)
245 void ShowOSErrorBox(const char *buf
, bool system
)
247 /* All unix systems, except OSX. Only use escape codes on a TTY. */
248 if (isatty(fileno(stderr
))) {
249 fprintf(stderr
, "\033[1;31mError: %s\033[0;39m\n", buf
);
251 fprintf(stderr
, "Error: %s\n", buf
);
257 void cocoaSetupAutoreleasePool();
258 void cocoaReleaseAutoreleasePool();
261 int CDECL
main(int argc
, char *argv
[])
263 /* Make sure our arguments contain only valid UTF-8 characters. */
264 for (int i
= 0; i
< argc
; i
++) ValidateString(argv
[i
]);
267 cocoaSetupAutoreleasePool();
268 /* This is passed if we are launched by double-clicking */
269 if (argc
>= 2 && strncmp(argv
[1], "-psn", 4) == 0) {
274 CrashLog::InitialiseCrashLog();
276 SetRandomSeed(time(NULL
));
278 signal(SIGPIPE
, SIG_IGN
);
280 int ret
= openttd_main(argc
, argv
);
283 cocoaReleaseAutoreleasePool();
290 bool GetClipboardContents(char *buffer
, const char *last
)
297 /* multi os compatible sleep function */
300 /* usleep() implementation */
301 # include <devices/timer.h>
302 # include <dos/dos.h>
304 extern struct Device
*TimerBase
= NULL
;
305 extern struct MsgPort
*TimerPort
= NULL
;
306 extern struct timerequest
*TimerRequest
= NULL
;
307 #endif /* __AMIGA__ */
309 void CSleep(int milliseconds
)
312 sceKernelDelayThread(milliseconds
* 1000);
313 #elif defined(__BEOS__)
314 snooze(milliseconds
* 1000);
315 #elif defined(__AMIGA__)
318 ULONG TimerSigBit
= 1 << TimerPort
->mp_SigBit
;
321 TimerRequest
->tr_node
.io_Command
= TR_ADDREQUEST
;
322 TimerRequest
->tr_time
.tv_secs
= (milliseconds
* 1000) / 1000000;
323 TimerRequest
->tr_time
.tv_micro
= (milliseconds
* 1000) % 1000000;
324 SendIO((struct IORequest
*)TimerRequest
);
326 if (!((signals
= Wait(TimerSigBit
| SIGBREAKF_CTRL_C
)) & TimerSigBit
) ) {
327 AbortIO((struct IORequest
*)TimerRequest
);
329 WaitIO((struct IORequest
*)TimerRequest
);
332 usleep(milliseconds
* 1000);
338 uint
GetCPUCoreCount()
343 size_t len
= sizeof(ncpu
);
349 if (sysctl(name
, 2, &ncpu
, &len
, NULL
, 0) < 0) {
353 if (sysctlbyname("hw.availcpu", &ncpu
, &len
, NULL
, 0) < 0) {
354 sysctlbyname("hw.ncpu", &ncpu
, &len
, NULL
, 0);
356 #endif /* #ifdef OPENBSD */
358 if (ncpu
> 0) count
= ncpu
;
359 #elif defined(_SC_NPROCESSORS_ONLN)
360 long res
= sysconf(_SC_NPROCESSORS_ONLN
);
361 if (res
> 0) count
= res
;
367 void OSOpenBrowser(const char *url
)
369 pid_t child_pid
= fork();
370 if (child_pid
!= 0) return;
373 args
[0] = "xdg-open";
376 execvp(args
[0], const_cast<char * const *>(args
));
377 DEBUG(misc
, 0, "Failed to open url: %s", url
);