# unix.cpp

Go to the documentation of this file.

    00001 /* $Id$ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * 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.
    00006  * 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.
    00007  * 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/>.
    00008  */
    00009
    00012 #include "../../stdafx.h"
    00013 #include "../../textbuf_gui.h"
    00014 #include "../../openttd.h"
    00015 #include "../../crashlog.h"
    00016 #include "../../core/random_func.hpp"
    00017 #include "../../debug.h"
    00018
    00019
    00020 #include <dirent.h>
    00021 #include <unistd.h>
    00022 #include <sys/stat.h>
    00023 #include <time.h>
    00024 #include <signal.h>
    00025
    00026 #ifdef __APPLE__
    00027   #include <sys/mount.h>
    00028 #elif (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L) || defined(__GLIBC__)
    00029   #define HAS_STATVFS
    00030 #endif
    00031
    00032 #if defined(OPENBSD) || defined(__NetBSD__) || defined(__FreeBSD__)
    00033   #define HAS_SYSCTL
    00034 #endif
    00035
    00036 #ifdef HAS_STATVFS
    00037 #include <sys/statvfs.h>
    00038 #endif
    00039
    00040 #ifdef HAS_SYSCTL
    00041 #include <sys/sysctl.h>
    00042 #endif
    00043
    00044
    00045 #ifdef __MORPHOS__
    00046 #include <exec/types.h>
    00047 ULONG __stack = (1024*1024)*2; // maybe not that much is needed actually ;)
    00048
    00049 /* The system supplied definition of SIG_IGN does not match */
    00050 #undef SIG_IGN
    00051 #define SIG_IGN (void (*)(int))1
    00052 #endif /* __MORPHOS__ */
    00053
    00054 #ifdef __AMIGA__
    00055 #warning add stack symbol to avoid that user needs to set stack manually (tokai)
    00056 // ULONG __stack =
    00057 #endif
    00058
    00059 #if defined(__APPLE__)
    00060   #if defined(WITH_SDL)
    00061     /* the mac implementation needs this file included in the same file as main() */
    00062     #include <SDL.h>
    00063   #endif
    00064 #endif
    00065
    00066 bool FiosIsRoot(const char *path)
    00067 {
    00068 #if !defined(__MORPHOS__) && !defined(__AMIGAOS__)
    00069   return path[1] == '\0';
    00070 #else
    00071   /* On MorphOS or AmigaOS paths look like: "Volume:directory/subdirectory" */
    00072   const char *s = strchr(path, ':');
    00073   return s != NULL && s[1] == '\0';
    00074 #endif
    00075 }
    00076
    00077 void FiosGetDrives()
    00078 {
    00079   return;
    00080 }
    00081
    00082 bool FiosGetDiskFreeSpace(const char *path, uint64 *tot)
    00083 {
    00084   uint64 free = 0;
    00085
    00086 #ifdef __APPLE__
    00087   struct statfs s;
    00088
    00089   if (statfs(path, &s) != 0) return false;
    00090   free = (uint64)s.f_bsize * s.f_bavail;
    00091 #elif defined(HAS_STATVFS)
    00092   struct statvfs s;
    00093
    00094   if (statvfs(path, &s) != 0) return false;
    00095   free = (uint64)s.f_frsize * s.f_bavail;
    00096 #endif
    00097   if (tot != NULL) *tot = free;
    00098   return true;
    00099 }
    00100
    00101 bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb)
    00102 {
    00103   char filename[MAX_PATH];
    00104   int res;
    00105 #if defined(__MORPHOS__) || defined(__AMIGAOS__)
    00106   /* On MorphOS or AmigaOS paths look like: "Volume:directory/subdirectory" */
    00107   if (FiosIsRoot(path)) {
    00108     res = snprintf(filename, lengthof(filename), "%s:%s", path, ent->d_name);
    00109   } else // XXX - only next line!
    00110 #else
    00111   assert(path[strlen(path) - 1] == PATHSEPCHAR);
    00112   if (strlen(path) > 2) assert(path[strlen(path) - 2] != PATHSEPCHAR);
    00113 #endif
    00114   res = snprintf(filename, lengthof(filename), "%s%s", path, ent->d_name);
    00115
    00116   /* Could we fully concatenate the path and filename? */
    00117   if (res >= (int)lengthof(filename) || res < 0) return false;
    00118
    00119   return stat(filename, sb) == 0;
    00120 }
    00121
    00122 bool FiosIsHiddenFile(const struct dirent *ent)
    00123 {
    00124   return ent->d_name[0] == '.';
    00125 }
    00126
    00127 #ifdef WITH_ICONV
    00128
    00129 #include <iconv.h>
    00130 #include <errno.h>
    00131 #include "../../debug.h"
    00132 #include "../../string_func.h"
    00133
    00134 const char *GetCurrentLocale(const char *param);
    00135
    00136 #define INTERNALCODE "UTF-8"
    00137
    00143 static const char *GetLocalCode()
    00144 {
    00145 #if defined(__APPLE__)
    00146   return "UTF-8-MAC";
    00147 #else
    00148   /* Strip locale (eg en_US.UTF-8) to only have UTF-8 */
    00149   const char *locale = GetCurrentLocale("LC_CTYPE");
    00150   if (locale != NULL) locale = strchr(locale, '.');
    00151
    00152   return (locale == NULL) ? "" : locale + 1;
    00153 #endif
    00154 }
    00155
    00160 static const char *convert_tofrom_fs(iconv_t convd, const char *name)
    00161 {
    00162   static char buf[1024];
    00163   /* There are different implementations of iconv. The older ones,
    00164    * e.g. SUSv2, pass a const pointer, whereas the newer ones, e.g.
    00165    * IEEE 1003.1 (2004), pass a non-const pointer. */
    00166 #ifdef HAVE_NON_CONST_ICONV
    00167   char *inbuf = const_cast<char*>(name);
    00168 #else
    00169   const char *inbuf = name;
    00170 #endif
    00171
    00172   char *outbuf  = buf;
    00173   size_t outlen = sizeof(buf) - 1;
    00174   size_t inlen  = strlen(name);
    00175
    00176   strecpy(outbuf, name, outbuf + outlen);
    00177
    00178   iconv(convd, NULL, NULL, NULL, NULL);
    00179   if (iconv(convd, &inbuf, &inlen, &outbuf, &outlen) == (size_t)(-1)) {
    00180     DEBUG(misc, 0, "[iconv] error converting '%s'. Errno %d", name, errno);
    00181   }
    00182
    00183   *outbuf = '\0';
    00184   /* FIX: invalid characters will abort conversion, but they shouldn't occur? */
    00185   return buf;
    00186 }
    00187
    00193 const char *OTTD2FS(const char *name)
    00194 {
    00195   static iconv_t convd = (iconv_t)(-1);
    00196
    00197   if (convd == (iconv_t)(-1)) {
    00198     const char *env = GetLocalCode();
    00199     convd = iconv_open(env, INTERNALCODE);
    00200     if (convd == (iconv_t)(-1)) {
    00201       DEBUG(misc, 0, "[iconv] conversion from codeset '%s' to '%s' unsupported", INTERNALCODE, env);
    00202       return name;
    00203     }
    00204   }
    00205
    00206   return convert_tofrom_fs(convd, name);
    00207 }
    00208
    00214 const char *FS2OTTD(const char *name)
    00215 {
    00216   static iconv_t convd = (iconv_t)(-1);
    00217
    00218   if (convd == (iconv_t)(-1)) {
    00219     const char *env = GetLocalCode();
    00220     convd = iconv_open(INTERNALCODE, env);
    00221     if (convd == (iconv_t)(-1)) {
    00222       DEBUG(misc, 0, "[iconv] conversion from codeset '%s' to '%s' unsupported", env, INTERNALCODE);
    00223       return name;
    00224     }
    00225   }
    00226
    00227   return convert_tofrom_fs(convd, name);
    00228 }
    00229
    00230 #else
    00231 const char *FS2OTTD(const char *name) {return name;}
    00232 const char *OTTD2FS(const char *name) {return name;}
    00233 #endif /* WITH_ICONV */
    00234
    00235 void ShowInfo(const char *str)
    00236 {
    00237   fprintf(stderr, "%s\n", str);
    00238 }
    00239
    00240 #if !defined(__APPLE__)
    00241 void ShowOSErrorBox(const char *buf, bool system)
    00242 {
    00243   /* All unix systems, except OSX. Only use escape codes on a TTY. */
    00244   if (isatty(fileno(stderr))) {
    00245     fprintf(stderr, "\033[1;31mError: %s\033[0;39m\n", buf);
    00246   } else {
    00247     fprintf(stderr, "Error: %s\n", buf);
    00248   }
    00249 }
    00250 #endif
    00251
    00252 #ifdef WITH_COCOA
    00253 void cocoaSetupAutoreleasePool();
    00254 void cocoaReleaseAutoreleasePool();
    00255 #endif
    00256
    00257 int CDECL main(int argc, char *argv[])
    00258 {
    00259   int ret;
    00260
    00261 #ifdef WITH_COCOA
    00262   cocoaSetupAutoreleasePool();
    00263   /* This is passed if we are launched by double-clicking */
    00264   if (argc >= 2 && strncmp(argv[1], "-psn", 4) == 0) {
    00265     argv[1] = NULL;
    00266     argc = 1;
    00267   }
    00268 #endif
    00269   CrashLog::InitialiseCrashLog();
    00270
    00271   SetRandomSeed(time(NULL));
    00272
    00273   signal(SIGPIPE, SIG_IGN);
    00274
    00275   ret = ttd_main(argc, argv);
    00276
    00277 #ifdef WITH_COCOA
    00278   cocoaReleaseAutoreleasePool();
    00279 #endif
    00280
    00281   return ret;
    00282 }
    00283
    00284 #ifndef WITH_COCOA
    00285 bool GetClipboardContents(char *buffer, size_t buff_len)
    00286 {
    00287   return false;
    00288 }
    00289 #endif
    00290
    00291
    00292 /* multi os compatible sleep function */
    00293
    00294 #ifdef __AMIGA__
    00295 /* usleep() implementation */
    00296 # include <devices/timer.h>
    00297 # include <dos/dos.h>
    00298
    00299   extern struct Device      *TimerBase    = NULL;
    00300   extern struct MsgPort     *TimerPort    = NULL;
    00301   extern struct timerequest *TimerRequest = NULL;
    00302 #endif /* __AMIGA__ */
    00303
    00304 void CSleep(int milliseconds)
    00305 {
    00306   #if defined(PSP)
    00307     sceKernelDelayThread(milliseconds * 1000);
    00308   #elif defined(__BEOS__)
    00309     snooze(milliseconds * 1000);
    00310   #elif defined(__AMIGA__)
    00311   {
    00312     ULONG signals;
    00313     ULONG TimerSigBit = 1 << TimerPort->mp_SigBit;
    00314
    00315     /* send IORequest */
    00316     TimerRequest->tr_node.io_Command = TR_ADDREQUEST;
    00317     TimerRequest->tr_time.tv_secs    = (milliseconds * 1000) / 1000000;
    00318     TimerRequest->tr_time.tv_micro   = (milliseconds * 1000) % 1000000;
    00319     SendIO((struct IORequest *)TimerRequest);
    00320
    00321     if (!((signals = Wait(TimerSigBit | SIGBREAKF_CTRL_C)) & TimerSigBit) ) {
    00322       AbortIO((struct IORequest *)TimerRequest);
    00323     }
    00324     WaitIO((struct IORequest *)TimerRequest);
    00325   }
    00326   #else
    00327     usleep(milliseconds * 1000);
    00328   #endif
    00329 }
    00330
    00331
    00332 #ifndef __APPLE__
    00333 uint GetCPUCoreCount()
    00334 {
    00335   uint count = 1;
    00336 #ifdef HAS_SYSCTL
    00337   int ncpu = 0;
    00338   size_t len = sizeof(ncpu);
    00339
    00340   if (sysctlbyname("hw.availcpu", &ncpu, &len, NULL, 0) < 0) {
    00341     sysctlbyname("hw.ncpu", &ncpu, &len, NULL, 0);
    00342   }
    00343
    00344   if (ncpu > 0) count = ncpu;
    00345 #elif defined(_SC_NPROCESSORS_ONLN)
    00346   long res = sysconf(_SC_NPROCESSORS_ONLN);
    00347   if (res > 0) count = res;
    00348 #endif
    00349
    00350   return count;
    00351 }
    00352
    00353 void OSOpenBrowser(const char *url)
    00354 {
    00355   pid_t child_pid = fork();
    00356   if (child_pid != 0) return;
    00357
    00358   const char *args[3];
    00359   args[0] = "/usr/bin/xdg-open";
    00360   args[1] = url;
    00361   args[2] = NULL;
    00362   execv(args[0], const_cast<char * const *>(args));
    00363   DEBUG(misc, 0, "Failed to open url: %s", url);
    00364   exit(0);
    00365 }
    00366 #endif