# unix.cpp

Go to the documentation of this file.

    00001 /* $Id: unix.cpp 17708 2009-10-04 21:08:38Z michi_cc $ */
    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 "../../functions.h"
    00015 #include "../../crashlog.h"
    00016
    00017
    00018 #include <dirent.h>
    00019 #include <unistd.h>
    00020 #include <sys/stat.h>
    00021 #include <time.h>
    00022 #include <signal.h>
    00023
    00024 #ifdef __APPLE__
    00025   #include <sys/mount.h>
    00026 #elif (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L) || defined(__GLIBC__)
    00027   #define HAS_STATVFS
    00028 #endif
    00029
    00030 #ifdef HAS_STATVFS
    00031 #include <sys/statvfs.h>
    00032 #endif
    00033
    00034
    00035 #ifdef __MORPHOS__
    00036 #include <exec/types.h>
    00037 ULONG __stack = (1024*1024)*2; // maybe not that much is needed actually ;)
    00038
    00039 /* The system supplied definition of SIG_IGN does not match */
    00040 #undef SIG_IGN
    00041 #define SIG_IGN (void (*)(int))1
    00042 #endif /* __MORPHOS__ */
    00043
    00044 #ifdef __AMIGA__
    00045 #warning add stack symbol to avoid that user needs to set stack manually (tokai)
    00046 // ULONG __stack =
    00047 #endif
    00048
    00049 #if defined(__APPLE__)
    00050   #if defined(WITH_SDL)
    00051     /* the mac implementation needs this file included in the same file as main() */
    00052     #include <SDL.h>
    00053   #endif
    00054 #endif
    00055
    00056 bool FiosIsRoot(const char *path)
    00057 {
    00058 #if !defined(__MORPHOS__) && !defined(__AMIGAOS__)
    00059   return path[1] == '\0';
    00060 #else
    00061   /* On MorphOS or AmigaOS paths look like: "Volume:directory/subdirectory" */
    00062   const char *s = strchr(path, ':');
    00063   return s != NULL && s[1] == '\0';
    00064 #endif
    00065 }
    00066
    00067 void FiosGetDrives()
    00068 {
    00069   return;
    00070 }
    00071
    00072 bool FiosGetDiskFreeSpace(const char *path, uint64 *tot)
    00073 {
    00074   uint64 free = 0;
    00075
    00076 #ifdef __APPLE__
    00077   struct statfs s;
    00078
    00079   if (statfs(path, &s) != 0) return false;
    00080   free = (uint64)s.f_bsize * s.f_bavail;
    00081 #elif defined(HAS_STATVFS)
    00082   struct statvfs s;
    00083
    00084   if (statvfs(path, &s) != 0) return false;
    00085   free = (uint64)s.f_frsize * s.f_bavail;
    00086 #endif
    00087   if (tot != NULL) *tot = free;
    00088   return true;
    00089 }
    00090
    00091 bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb)
    00092 {
    00093   char filename[MAX_PATH];
    00094
    00095 #if defined(__MORPHOS__) || defined(__AMIGAOS__)
    00096   /* On MorphOS or AmigaOS paths look like: "Volume:directory/subdirectory" */
    00097   if (FiosIsRoot(path)) {
    00098     snprintf(filename, lengthof(filename), "%s:%s", path, ent->d_name);
    00099   } else // XXX - only next line!
    00100 #else
    00101   assert(path[strlen(path) - 1] == PATHSEPCHAR);
    00102   if (strlen(path) > 2) assert(path[strlen(path) - 2] != PATHSEPCHAR);
    00103 #endif
    00104   snprintf(filename, lengthof(filename), "%s%s", path, ent->d_name);
    00105
    00106   return stat(filename, sb) == 0;
    00107 }
    00108
    00109 bool FiosIsHiddenFile(const struct dirent *ent)
    00110 {
    00111   return ent->d_name[0] == '.';
    00112 }
    00113
    00114 #ifdef WITH_ICONV
    00115
    00116 #include <iconv.h>
    00117 #include <errno.h>
    00118 #include "../../debug.h"
    00119 #include "../../string_func.h"
    00120
    00121 const char *GetCurrentLocale(const char *param);
    00122
    00123 #define INTERNALCODE "UTF-8"
    00124
    00128 static const char *GetLocalCode()
    00129 {
    00130 #if defined(__APPLE__)
    00131   return "UTF-8-MAC";
    00132 #else
    00133   /* Strip locale (eg en_US.UTF-8) to only have UTF-8 */
    00134   const char *locale = GetCurrentLocale("LC_CTYPE");
    00135   if (locale != NULL) locale = strchr(locale, '.');
    00136
    00137   return (locale == NULL) ? "" : locale + 1;
    00138 #endif
    00139 }
    00140
    00145 static const char *convert_tofrom_fs(iconv_t convd, const char *name)
    00146 {
    00147   static char buf[1024];
    00148   /* Work around buggy iconv implementation where inbuf is wrongly typed as
    00149    * non-const. Correct implementation is at
    00150    * http://www.opengroup.org/onlinepubs/007908799/xsh/iconv.html */
    00151 #ifdef HAVE_BROKEN_ICONV
    00152   char *inbuf = const_cast<char*>(name);
    00153 #else
    00154   const char *inbuf = name;
    00155 #endif
    00156
    00157   char *outbuf  = buf;
    00158   size_t outlen = sizeof(buf) - 1;
    00159   size_t inlen  = strlen(name);
    00160
    00161   strecpy(outbuf, name, outbuf + outlen);
    00162
    00163   iconv(convd, NULL, NULL, NULL, NULL);
    00164   if (iconv(convd, &inbuf, &inlen, &outbuf, &outlen) == (size_t)(-1)) {
    00165     DEBUG(misc, 0, "[iconv] error converting '%s'. Errno %d", name, errno);
    00166   }
    00167
    00168   *outbuf = '\0';
    00169   /* FIX: invalid characters will abort conversion, but they shouldn't occur? */
    00170   return buf;
    00171 }
    00172
    00176 const char *OTTD2FS(const char *name)
    00177 {
    00178   static iconv_t convd = (iconv_t)(-1);
    00179
    00180   if (convd == (iconv_t)(-1)) {
    00181     const char *env = GetLocalCode();
    00182     convd = iconv_open(env, INTERNALCODE);
    00183     if (convd == (iconv_t)(-1)) {
    00184       DEBUG(misc, 0, "[iconv] conversion from codeset '%s' to '%s' unsupported", INTERNALCODE, env);
    00185       return name;
    00186     }
    00187   }
    00188
    00189   return convert_tofrom_fs(convd, name);
    00190 }
    00191
    00195 const char *FS2OTTD(const char *name)
    00196 {
    00197   static iconv_t convd = (iconv_t)(-1);
    00198
    00199   if (convd == (iconv_t)(-1)) {
    00200     const char *env = GetLocalCode();
    00201     convd = iconv_open(INTERNALCODE, env);
    00202     if (convd == (iconv_t)(-1)) {
    00203       DEBUG(misc, 0, "[iconv] conversion from codeset '%s' to '%s' unsupported", env, INTERNALCODE);
    00204       return name;
    00205     }
    00206   }
    00207
    00208   return convert_tofrom_fs(convd, name);
    00209 }
    00210
    00211 #else
    00212 const char *FS2OTTD(const char *name) {return name;}
    00213 const char *OTTD2FS(const char *name) {return name;}
    00214 #endif /* WITH_ICONV */
    00215
    00216 void ShowInfo(const char *str)
    00217 {
    00218   fprintf(stderr, "%s\n", str);
    00219 }
    00220
    00221 #if !defined(__APPLE__)
    00222 void ShowOSErrorBox(const char *buf, bool system)
    00223 {
    00224   /* All unix systems, except OSX. Only use escape codes on a TTY. */
    00225   if (isatty(fileno(stderr))) {
    00226     fprintf(stderr, "\033[1;31mError: %s\033[0;39m\n", buf);
    00227   } else {
    00228     fprintf(stderr, "Error: %s\n", buf);
    00229   }
    00230 }
    00231 #endif
    00232
    00233 #ifdef WITH_COCOA
    00234 void cocoaSetupAutoreleasePool();
    00235 void cocoaReleaseAutoreleasePool();
    00236 #endif
    00237
    00238 int CDECL main(int argc, char *argv[])
    00239 {
    00240   int ret;
    00241
    00242 #ifdef WITH_COCOA
    00243   cocoaSetupAutoreleasePool();
    00244   /* This is passed if we are launched by double-clicking */
    00245   if (argc >= 2 && strncmp(argv[1], "-psn", 4) == 0) {
    00246     argv[1] = NULL;
    00247     argc = 1;
    00248   }
    00249 #endif
    00250   CrashLog::InitialiseCrashLog();
    00251
    00252   SetRandomSeed(time(NULL));
    00253
    00254   signal(SIGPIPE, SIG_IGN);
    00255
    00256   ret = ttd_main(argc, argv);
    00257
    00258 #ifdef WITH_COCOA
    00259   cocoaReleaseAutoreleasePool();
    00260 #endif
    00261
    00262   return ret;
    00263 }
    00264
    00265 #ifndef WITH_COCOA
    00266 bool GetClipboardContents(char *buffer, size_t buff_len)
    00267 {
    00268   return false;
    00269 }
    00270 #endif
    00271
    00272
    00273 /* multi os compatible sleep function */
    00274
    00275 #ifdef __AMIGA__
    00276 /* usleep() implementation */
    00277 # include <devices/timer.h>
    00278 # include <dos/dos.h>
    00279
    00280   extern struct Device      *TimerBase    = NULL;
    00281   extern struct MsgPort     *TimerPort    = NULL;
    00282   extern struct timerequest *TimerRequest = NULL;
    00283 #endif /* __AMIGA__ */
    00284
    00285 void CSleep(int milliseconds)
    00286 {
    00287   #if defined(PSP)
    00288     sceKernelDelayThread(milliseconds * 1000);
    00289   #elif defined(__BEOS__)
    00290     snooze(milliseconds * 1000);
    00291   #elif defined(__AMIGA__)
    00292   {
    00293     ULONG signals;
    00294     ULONG TimerSigBit = 1 << TimerPort->mp_SigBit;
    00295
    00296     /* send IORequest */
    00297     TimerRequest->tr_node.io_Command = TR_ADDREQUEST;
    00298     TimerRequest->tr_time.tv_secs    = (milliseconds * 1000) / 1000000;
    00299     TimerRequest->tr_time.tv_micro   = (milliseconds * 1000) % 1000000;
    00300     SendIO((struct IORequest *)TimerRequest);
    00301
    00302     if (!((signals = Wait(TimerSigBit | SIGBREAKF_CTRL_C)) & TimerSigBit) ) {
    00303       AbortIO((struct IORequest *)TimerRequest);
    00304     }
    00305     WaitIO((struct IORequest *)TimerRequest);
    00306   }
    00307   #else
    00308     usleep(milliseconds * 1000);
    00309   #endif
    00310 }