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