# unix.cpp

Go to the documentation of this file.

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