Skip to content
Snippets Groups Projects
OS.cpp 16.7 KiB
Newer Older
Christophe Geuzaine's avatar
Christophe Geuzaine committed
// Gmsh - Copyright (C) 1997-2015 C. Geuzaine, J.-F. Remacle
Christophe Geuzaine's avatar
Christophe Geuzaine committed
//
Christophe Geuzaine's avatar
Christophe Geuzaine committed
// See the LICENSE.txt file for license information. Please report all
Christophe Geuzaine's avatar
Christophe Geuzaine committed
// bugs and problems to the public mailing list <gmsh@geuz.org>.
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
// This file contains a bunch of functions that depend on OS-dependent
// features and/or system calls

// these are available on all OSes
#include <stdlib.h>
Christophe Geuzaine's avatar
Christophe Geuzaine committed
#include <stdio.h>
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
#include <time.h>
Christophe Geuzaine's avatar
Christophe Geuzaine committed
#include <math.h>
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed

#if defined(__APPLE__)
#include <sys/sysctl.h>
#include <mach-o/dyld.h>
#if defined(__linux__) && !defined(BUILD_ANDROID)
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
#if !defined(WIN32) || defined(__CYGWIN__)
#include <unistd.h>
#include <sys/time.h>
#include <sys/resource.h>
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
#endif

#if defined(WIN32)
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
#include <windows.h>
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
#include <process.h>
#include <psapi.h>
Christophe Geuzaine's avatar
Christophe Geuzaine committed
#include <io.h>
Christophe Geuzaine's avatar
Christophe Geuzaine committed
#include <direct.h>
#include <fcntl.h>
#include <iostream>
#include <fstream>
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed

#if defined(WIN32) && !defined(__CYGWIN__)

Christophe Geuzaine's avatar
Christophe Geuzaine committed
// Unicode utility routines borrowed from FLTK

static unsigned utf8decode(const char* p, const char* end, int* len)
  static unsigned short cp1252[32] = {
    0x20ac, 0x0081, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
    0x02c6, 0x2030, 0x0160, 0x2039, 0x0152, 0x008d, 0x017d, 0x008f,
    0x0090, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
    0x02dc, 0x2122, 0x0161, 0x203a, 0x0153, 0x009d, 0x017e, 0x0178
  };
  unsigned char c = *(unsigned char*)p;
  if (c < 0x80) {
    if (len) *len = 1;
    return c;
  } else if (c < 0xa0) {
    if (len) *len = 1;
    return cp1252[c-0x80];
  } else if (c < 0xc2) {
    goto FAIL;
  }
  if ( (end && p+1 >= end) || (p[1]&0xc0) != 0x80) goto FAIL;
  if (c < 0xe0) {
    if (len) *len = 2;
    return
      ((p[0] & 0x1f) << 6) +
      ((p[1] & 0x3f));
  } else if (c == 0xe0) {
    if (((unsigned char*)p)[1] < 0xa0) goto FAIL;
    goto UTF8_3;
  } else if (c < 0xf0) {
  UTF8_3:
    if ( (end && p+2 >= end) || (p[2]&0xc0) != 0x80) goto FAIL;
    if (len) *len = 3;
    return
      ((p[0] & 0x0f) << 12) +
      ((p[1] & 0x3f) << 6) +
      ((p[2] & 0x3f));
  } else if (c == 0xf0) {
    if (((unsigned char*)p)[1] < 0x90) goto FAIL;
    goto UTF8_4;
  } else if (c < 0xf4) {
  UTF8_4:
    if ( (end && p+3 >= end) || (p[2]&0xc0) != 0x80 || (p[3]&0xc0) != 0x80) goto FAIL;
    if (len) *len = 4;
    return
      ((p[0] & 0x07) << 18) +
      ((p[1] & 0x3f) << 12) +
      ((p[2] & 0x3f) << 6) +
      ((p[3] & 0x3f));
  } else if (c == 0xf4) {
Christophe Geuzaine's avatar
Christophe Geuzaine committed
    if (((unsigned char*)p)[1] > 0x8f) goto FAIL; // after 0x10ffff
    goto UTF8_4;
  } else {
  FAIL:
    if (len) *len = 1;
    return c;
  }
}

static unsigned utf8toUtf16(const char* src, unsigned srclen,
                            unsigned short* dst, unsigned dstlen)
{
  const char* p = src;
  const char* e = src+srclen;
  unsigned count = 0;
  if (dstlen) for (;;) {
    if (p >= e) {dst[count] = 0; return count;}
Christophe Geuzaine's avatar
Christophe Geuzaine committed
    if (!(*p & 0x80)) { // ascii
      dst[count] = *p++;
    } else {
      int len; unsigned ucs = utf8decode(p,e,&len);
      p += len;
      if (ucs < 0x10000) {
	dst[count] = ucs;
      } else {
Christophe Geuzaine's avatar
Christophe Geuzaine committed
	// make a surrogate pair:
	if (count+2 >= dstlen) {dst[count] = 0; count += 2; break;}
	dst[count] = (((ucs-0x10000u)>>10)&0x3ff) | 0xd800;
	dst[++count] = (ucs&0x3ff) | 0xdc00;
      }
    }
    if (++count == dstlen) {dst[count-1] = 0; break;}
  }
Christophe Geuzaine's avatar
Christophe Geuzaine committed
  // we filled dst, measure the rest:
  while (p < e) {
    if (!(*p & 0x80)) p++;
    else {
      int len; unsigned ucs = utf8decode(p,e,&len);
      p += len;
      if (ucs >= 0x10000) ++count;
    }
    ++count;
  }
  return count;
}

static unsigned utf8FromUtf16(char* dst, unsigned dstlen,
                              const wchar_t* src, unsigned srclen)
{
  unsigned i = 0;
  unsigned count = 0;
  if (dstlen) {
    for (;;) {
      unsigned ucs;
      if (i >= srclen) {dst[count] = 0; return count;}
      ucs = src[i++];
      if (ucs < 0x80U) {
        dst[count++] = ucs;
        if (count >= dstlen) {dst[count-1] = 0; break;}
      }
      else if (ucs < 0x800U) { /* 2 bytes */
        if (count+2 >= dstlen) {dst[count] = 0; count += 2; break;}
        dst[count++] = 0xc0 | (ucs >> 6);
        dst[count++] = 0x80 | (ucs & 0x3F);
      }
      else if (ucs >= 0xd800 && ucs <= 0xdbff && i < srclen &&
	       src[i] >= 0xdc00 && src[i] <= 0xdfff) {
        /* surrogate pair */
        unsigned ucs2 = src[i++];
        ucs = 0x10000U + ((ucs&0x3ff)<<10) + (ucs2&0x3ff);
        /* all surrogate pairs turn into 4-byte utf8 */
        if (count+4 >= dstlen) {dst[count] = 0; count += 4; break;}
        dst[count++] = 0xf0 | (ucs >> 18);
        dst[count++] = 0x80 | ((ucs >> 12) & 0x3F);
        dst[count++] = 0x80 | ((ucs >> 6) & 0x3F);
        dst[count++] = 0x80 | (ucs & 0x3F);
      }
      else {
        /* all others are 3 bytes: */
        if (count+3 >= dstlen) {dst[count] = 0; count += 3; break;}
        dst[count++] = 0xe0 | (ucs >> 12);
        dst[count++] = 0x80 | ((ucs >> 6) & 0x3F);
        dst[count++] = 0x80 | (ucs & 0x3F);
      }
    }
  }
  /* we filled dst, measure the rest: */
  while (i < srclen) {
    unsigned ucs = src[i++];
    if (ucs < 0x80U) {
      count++;
    }
    else if (ucs < 0x800U) { /* 2 bytes */
      count += 2;
    }
    else if (ucs >= 0xd800 && ucs <= 0xdbff && i < srclen-1 &&
             src[i+1] >= 0xdc00 && src[i+1] <= 0xdfff) {
      /* surrogate pair */
      ++i;
      count += 4;
    }
    else {
      count += 3;
    }
  }
  return count;
}

static wchar_t *wbuf[3] = {NULL, NULL, NULL};
Christophe Geuzaine's avatar
Christophe Geuzaine committed

static void setwbuf(int i, const char *f)
{
Christophe Geuzaine's avatar
Christophe Geuzaine committed
  // all strings in Gmsh are supposed to be UTF8-encoded, which is natively
  // supported by Mac and Linux. Windows does not support UTF-8, but UTF-16
  // (through wchar_t), so we need to convert.
Christophe Geuzaine's avatar
Christophe Geuzaine committed
  size_t l = strlen(f);
  unsigned wn = utf8toUtf16(f, (unsigned) l, NULL, 0) + 1;
  wbuf[i] = (wchar_t*)realloc(wbuf[i], sizeof(wchar_t)*wn);
  wn = utf8toUtf16(f, (unsigned) l, (unsigned short *)wbuf[i], wn);
  wbuf[i][wn] = 0;
}
Christophe Geuzaine's avatar
Christophe Geuzaine committed
FILE *Fopen(const char *f, const char *mode)
{
#if defined (WIN32) && !defined(__CYGWIN__)
Christophe Geuzaine's avatar
Christophe Geuzaine committed
  setwbuf(0, f);
  setwbuf(1, mode);
  return _wfopen(wbuf[0], wbuf[1]);
  return fopen(f, mode);
#endif
}

const char *GetEnvironmentVar(const char *var)
{
#if defined(WIN32) && !defined(__CYGWIN__)
  // Should probably use the Unicode version
  const char *tmp = getenv(var);
  // Don't accept top dir or anything partially expanded like
  // c:\Documents and Settings\%USERPROFILE%, etc.
  if(!tmp || !strcmp(tmp, "/") || strstr(tmp, "%") || strstr(tmp, "$"))
    return 0;
  else
    return tmp;
#else
  return getenv(var);
Christophe Geuzaine's avatar
Christophe Geuzaine committed
void SetEnvironmentVar(const char *var, const char *val)
#if defined(WIN32) && !defined(__CYGWIN__)
  // should probably use Unicode version here
  _putenv((std::string(var) + "=" + std::string(val)).c_str());
#else
  setenv(var, val, 1);
double GetTimeInSeconds()
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
{
#if defined(WIN32) && !defined(__CYGWIN__)
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
  FILETIME ft;
  GetSystemTimeAsFileTime(&ft);
  double t =  1.e-7 * 4294967296. * (double)ft.dwHighDateTime +
              1.e-7 * (double)ft.dwLowDateTime;
Christophe Geuzaine's avatar
Christophe Geuzaine committed
  return t;
#else
  struct timeval tp;
  gettimeofday(&tp, (struct timezone *)0);
  double t = (double)tp.tv_sec + 1.e-6 * (double)tp.tv_usec;
  return t;
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
}
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed

Christophe Geuzaine's avatar
Christophe Geuzaine committed
void SleepInSeconds(double s)
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
{
#if defined(WIN32) && !defined(__CYGWIN__)
Christophe Geuzaine's avatar
Christophe Geuzaine committed
  Sleep((long)(1.e3 * s));
#else
  usleep((long)(1.e6 * s));
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
}

Christophe Geuzaine's avatar
Christophe Geuzaine committed
static void GetResources(double *s, long *mem)
#if defined(WIN32) && !defined(__CYGWIN__)
  FILETIME creation, exit, kernel, user;
  if(GetProcessTimes(GetCurrentProcess(), &creation, &exit, &kernel, &user)){
    *s = 1.e-7 * 4294967296. * (double)user.dwHighDateTime +
         1.e-7 * (double)user.dwLowDateTime;
  }
  PROCESS_MEMORY_COUNTERS info;
  GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info));
  *mem = (long)info.PeakWorkingSetSize;
#else
  static struct rusage r;
  getrusage(RUSAGE_SELF, &r);
  *s = (double)r.ru_utime.tv_sec + 1.e-6 * (double)r.ru_utime.tv_usec;
#if defined(__APPLE__)
  *mem = (long)r.ru_maxrss;
#else
  *mem = (long)(r.ru_maxrss * 1024L);
#endif
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
#endif
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
#if !defined (WIN32) || defined(__CYGWIN__)
  static struct rlimit r;

  getrlimit(RLIMIT_STACK, &r);

  // Try to get at least 16 MB of stack. Running with too small a stack
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
  // can cause crashes in the recursive calls (e.g. for tet
  // classification in 3D Delaunay)
  if(r.rlim_cur < 16 * 1024 * 1024){
    Msg::Info("Increasing process stack size (%d kB < 16 MB)", r.rlim_cur / 1024);
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
    r.rlim_cur = r.rlim_max;
    setrlimit(RLIMIT_STACK, &r);
  }
#endif
}

double Cpu()
{
  long mem = 0;
  double s = 0.;
  GetResources(&s, &mem);
  return s;
}
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed

double TotalRam()
{
  double ram = 0;
#if defined(__APPLE__)
  int name[] = {CTL_HW, HW_MEMSIZE};
  int64_t value;
  size_t len = sizeof(value);
  if(sysctl(name, 2, &value, &len, NULL, 0) != -1)
    ram = value / (1024 * 1024);
#elif defined (WIN32)
  MEMORYSTATUSEX status;
  status.dwLength = sizeof(status);
  GlobalMemoryStatusEx(&status);
  ram = status.ullTotalPhys  / ((double)1024 * 1024);
#elif defined(BUILD_ANDROID)
  ram = 1024;
#elif defined(__linux__)
  struct sysinfo infos;
  if(sysinfo(&infos) != -1)
    ram = infos.totalram * (unsigned long)infos.mem_unit / ((double)1024 * 1024);
#endif
  return ram;
}

long GetMemoryUsage()
{
  long mem = 0;
  double s = 0.;
  GetResources(&s, &mem);
  return mem;
}

Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
int GetProcessId()
{
#if defined(WIN32) && !defined(__CYGWIN__)
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
  return _getpid();
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
#endif
}

std::string GetExecutableName(const std::string &argv0)
{
  std::string name = "";
#if defined(WIN32) && !defined(__CYGWIN__)
  WCHAR src[MAX_PATH];
Christophe Geuzaine's avatar
Christophe Geuzaine committed
  DWORD size = GetModuleFileNameW(NULL, src, MAX_PATH);
  if(size){
    char dst[MAX_PATH];
    utf8FromUtf16(dst, MAX_PATH, src, size);
    name = std::string(dst);
  }
#elif defined(__APPLE__)
  char path[PATH_MAX];
  uint32_t size = sizeof(path);
Christophe Geuzaine's avatar
pp  
Christophe Geuzaine committed
  if(_NSGetExecutablePath(path, &size) == 0){
    char real[PATH_MAX];
    if(realpath(path, real)){
      name = std::string(real);
    }
  }
#elif defined(__linux__)
Christophe Geuzaine's avatar
pp  
Christophe Geuzaine committed
  char path[4096];
  if(readlink("/proc/self/exe", path, 4096) > 0){
    name = std::string(path);
  }
#endif
  if(name.empty()){
    name = argv0;
  }
  return name;
}

std::string GetHostName()
{
  char host[256];
  gethostname(host, sizeof(host));
  return std::string(host);
}

int UnlinkFile(const std::string &fileName)
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
{
#if defined(WIN32) && !defined(__CYGWIN__)
Christophe Geuzaine's avatar
Christophe Geuzaine committed
  setwbuf(0, fileName.c_str());
  return _wunlink(wbuf[0]);
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
#else
  return unlink(fileName.c_str());
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
#endif
}

int StatFile(const std::string &fileName)
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
{
#if defined(WIN32) && !defined(__CYGWIN__)
  struct _stat buf;
Christophe Geuzaine's avatar
Christophe Geuzaine committed
  setwbuf(0, fileName.c_str());
  int ret = _wstat(wbuf[0], &buf);
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
  struct stat buf;
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
#endif
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
}

int CreateSingleDir(const std::string &dirName)
#if defined(WIN32) && !defined(__CYGWIN__)
Christophe Geuzaine's avatar
Christophe Geuzaine committed
  setwbuf(0, dirName.c_str());
  if(_wmkdir(wbuf[0])) return 0;
  if(mkdir(dirName.c_str(), 0777)) return 0;
void CreatePath(const std::string &fullPath)
{
Christophe Geuzaine's avatar
pp  
Christophe Geuzaine committed
  size_t lastp = fullPath.find_last_of('/'); // TODO: handle backslash for win?
  if(lastp == std::string::npos) return;
  std::string dirname = std::string(fullPath, 0, lastp);
  size_t cur = 0;
  while(cur != std::string::npos) {
    cur = dirname.find("/", cur + 1);
    CreateSingleDir(dirname.substr(0, cur));
Christophe Geuzaine's avatar
pp  
Christophe Geuzaine committed
  }
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
int KillProcess(int pid)
{
#if defined(WIN32) && !defined(__CYGWIN__)
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
  HANDLE hProc = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
  if(!TerminateProcess(hProc, 0)){
    CloseHandle(hProc);
    return 0;
  }
#else
  if(kill(pid, 9))
    return 0;
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
#endif
  return 1;
}

int SystemCallExe(const std::string &exe, const std::string &argsOrCommand,
                  bool blocking)
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
{
  // do we try to run a .py script, .m script or an .exe?
  std::vector<std::string> split = SplitFileName(exe);
Christophe Geuzaine's avatar
Christophe Geuzaine committed
  bool isPython = (split[2] == ".py" || split[2] == ".PY");
  bool isOctave = (split[2] == ".m" || split[2] == ".M");
Christophe Geuzaine's avatar
Christophe Geuzaine committed
  bool isExe = (split[2] == ".exe" || split[2] == ".EXE");

  if(isPython || isOctave || isExe){
Christophe Geuzaine's avatar
Christophe Geuzaine committed
    if(StatFile(exe)){
      Msg::Error("Unable to open file '%s'", exe.c_str());
      return 1;
    }
Christophe Geuzaine's avatar
Christophe Geuzaine committed
  if(exe.size()){
    command.append("\"" + exe + "\""); // allows exe with white space
    if(argsOrCommand.size()) command.append(" ");
Christophe Geuzaine's avatar
Christophe Geuzaine committed
  }
#if defined(WIN32) && !defined(__CYGWIN__)
    Msg::Info("Shell opening '%s' with arguments '%s'", exe.c_str(),
    setwbuf(0, "open");
    setwbuf(1, exe.c_str());
    ShellExecuteW(NULL, wbuf[0], wbuf[1], wbuf[2], NULL, 0);
Christophe Geuzaine's avatar
Christophe Geuzaine committed
    STARTUPINFOW suInfo;
    PROCESS_INFORMATION prInfo;
    memset(&suInfo, 0, sizeof(suInfo));
    suInfo.cb = sizeof(suInfo);
    Msg::Info("Calling '%s'", command.c_str());
    setwbuf(0, command.c_str());
      CreateProcessW(NULL, wbuf[0], NULL, NULL, FALSE,
		    NORMAL_PRIORITY_CLASS, NULL, NULL,
		    &suInfo, &prInfo);
      // wait until child process exits.
      WaitForSingleObject(prInfo.hProcess, INFINITE);
      // close process and thread handles.
      CloseHandle(prInfo.hProcess);
      CloseHandle(prInfo.hThread);
    }
    else{
Christophe Geuzaine's avatar
Christophe Geuzaine committed
      // DETACHED_PROCESS removes the console (useful if the program to launch
      // is a console-mode exe)
      CreateProcessW(NULL, wbuf[0], NULL, NULL, FALSE,
		    NORMAL_PRIORITY_CLASS|DETACHED_PROCESS, NULL, NULL,
		    &suInfo, &prInfo);
    }
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
#else
  if(isPython || isOctave || isExe){
Christophe Geuzaine's avatar
Christophe Geuzaine committed
      if(isPython){
        Msg::Info("Script '%s' is not executable: running with `%s'",
		  exe.c_str(), CTX::instance()->solver.pythonInterpreter.c_str());
        cmd = CTX::instance()->solver.pythonInterpreter + " " + cmd;
      }
      else if(isOctave){
        Msg::Info("Script '%s' is not executable: running with `%s'",
		  exe.c_str(), CTX::instance()->solver.octaveInterpreter.c_str());
        cmd = CTX::instance()->solver.octaveInterpreter + " " + cmd;
Christophe Geuzaine's avatar
Christophe Geuzaine committed
      }
      else
        Msg::Warning("File '%s' is not executable", exe.c_str());
Christophe Geuzaine's avatar
Christophe Geuzaine committed
    else if(split[0].empty()){
      // workaround if pwd is not in PATH
      cmd = "./" + cmd;
    }
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
  if(!system(NULL)) {
    Msg::Error("Could not find /bin/sh: aborting system call");
    return 1;
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
  }
Francois Henrotte's avatar
Francois Henrotte committed
  if(!blocking) cmd += " &";
  Msg::Info("Calling '%s'", cmd.c_str());
Gaetan Bricteux's avatar
Gaetan Bricteux committed
  if(!system(cmd.c_str())) return 1;
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
#endif
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
}
int SystemCall(const std::string &command, bool blocking)
{
  return SystemCallExe("", command, blocking);
}

Christophe Geuzaine's avatar
Christophe Geuzaine committed
std::string GetCurrentWorkdir()
Christophe Geuzaine's avatar
Christophe Geuzaine committed
{
  char path[1024];

#if defined(WIN32) && !defined(__CYGWIN__)
  // should use Unicode version
Christophe Geuzaine's avatar
Christophe Geuzaine committed
  if(!_getcwd(path, sizeof(path))) return "";
#else
  if(!getcwd(path, sizeof(path))) return "";
Francois Henrotte's avatar
Francois Henrotte committed
#endif
Christophe Geuzaine's avatar
Christophe Geuzaine committed
  std::string str(path);
Christophe Geuzaine's avatar
Christophe Geuzaine committed
  // match the convention of SplitFileName that delivers directory path
  // ending with a directory separator
Francois Henrotte's avatar
Francois Henrotte committed
#if defined(WIN32)
  str.append("\\");
#else
  str.append("/");
#endif
  return str;
}

void RedirectIOToConsole()
{
#if defined(WIN32) && !defined(__CYGWIN__)
  // Win32 GUI apps do not write to the DOS console; make it work again by
Christophe Geuzaine's avatar
Christophe Geuzaine committed
  // attaching to parent console, which allows to use the DOS shell to work with
  // Gmsh on the command line (without this hack, you need to either use a
  // better shell (e.g. bash), or compile a /subsystem:console version
  if(!AttachConsole(ATTACH_PARENT_PROCESS)) return;
  // redirect unbuffered stdout, stdin and stderr to the console
Christophe Geuzaine's avatar
Christophe Geuzaine committed
  {
    intptr_t lStdHandle = (intptr_t)GetStdHandle(STD_OUTPUT_HANDLE);
Christophe Geuzaine's avatar
Christophe Geuzaine committed
    if(lStdHandle != (intptr_t)INVALID_HANDLE_VALUE){
Christophe Geuzaine's avatar
Christophe Geuzaine committed
      int hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
      if(hConHandle >= 0){
        FILE *fp = _fdopen(hConHandle, "w");
        if(fp){
          *stdout = *fp;
          setvbuf(stdout, NULL, _IONBF, 0);
        }
      }
    }
  }
  {
    intptr_t lStdHandle = (intptr_t)GetStdHandle(STD_INPUT_HANDLE);
Christophe Geuzaine's avatar
Christophe Geuzaine committed
    if(lStdHandle != (intptr_t)INVALID_HANDLE_VALUE){
Christophe Geuzaine's avatar
Christophe Geuzaine committed
      int hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
      if(hConHandle >= 0){
        FILE *fp = _fdopen(hConHandle, "r");
        if(fp){
          *stdin = *fp;
          setvbuf(stdin, NULL, _IONBF, 0);
        }
      }
    }
  }
  {
    intptr_t lStdHandle = (intptr_t)GetStdHandle(STD_ERROR_HANDLE);
Christophe Geuzaine's avatar
Christophe Geuzaine committed
    if(lStdHandle != (intptr_t)INVALID_HANDLE_VALUE){
Christophe Geuzaine's avatar
Christophe Geuzaine committed
      int hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
      if(hConHandle >= 0){
        FILE *fp = _fdopen(hConHandle, "w");
        if(fp){
          *stderr = *fp;
          setvbuf(stderr, NULL, _IONBF, 0);
        }
      }
    }
  }
  // make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog point to console
  // as well
  std::ios::sync_with_stdio();
#endif
}