Skip to content
Snippets Groups Projects
Select Git revision
  • fcecb101c342200368734ba25499b15bffcf4b34
  • master default protected
  • dof-renumbering
  • gdemesy-master-patch-30528
  • eval-space-time
  • oscillating_multiharm
  • MH_movement
  • axisqu
  • write_vtu_and_ensight_formats
  • movingband
  • CP_1972_add_vtu_file_writing
  • mortar
  • fast_freq_sweep_Resolution
  • applyresolvent_again
  • marteaua-master-patch-54323
  • patch-1
  • binde-master-patch-08072
  • binde-master-patch-52461
  • BCGSL
  • resolvent
  • TreeElementsOf
  • getdp_3_5_0
  • getdp_3_4_0
  • getdp_3_3_0
  • getdp_3_2_0
  • getdp_3_1_0
  • getdp_3_0_4
  • getdp_3_0_3
  • getdp_3_0_2
  • getdp_3_0_1
  • getdp_3_0_0
  • onelab_mobile_2.1.0
  • getdp_2_11_3 protected
  • getdp_2_11_2 protected
  • getdp_2_11_1 protected
  • getdp_2_11_0 protected
  • getdp_2_10_0 protected
  • getdp_2_9_2 protected
  • getdp_2_9_1 protected
  • getdp_2_9_0 protected
  • getdp_2_8_0 protected
41 results

Operation_IterativeLinearSolver.cpp

Blame
  • OS.cpp 18.67 KiB
    // Gmsh - Copyright (C) 1997-2015 C. Geuzaine, J.-F. Remacle
    //
    // See the LICENSE.txt file for license information. Please report all
    // bugs and problems to the public mailing list <gmsh@geuz.org>.
    
    // 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>
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <signal.h>
    #include <time.h>
    #include <math.h>
    #include "FlGui.h"
    #include "GmshConfig.h"
    #include "StringUtils.h"
    #include "Context.h"
    
    #if defined(HAVE_ZIPPER)
    #include <iostream>
    #include <fstream>
    #include "zipper.h"
    #include "unzipper.h"
    #endif
    
    #if defined(__APPLE__)
    #include <sys/sysctl.h>
    #include <mach-o/dyld.h>
    #endif
    
    #if defined(__linux__) && !defined(BUILD_ANDROID)
    #include <sys/sysinfo.h>
    #endif
    
    #if !defined(WIN32) || defined(__CYGWIN__)
    #include <unistd.h>
    #include <sys/time.h>
    #include <sys/resource.h>
    #endif
    
    #if defined(WIN32)
    #include <windows.h>
    #include <process.h>
    #include <psapi.h>
    #include <io.h>
    #include <direct.h>
    #include <fcntl.h>
    #include <iostream>
    #include <fstream>
    #endif
    
    #include "GmshMessage.h"
    
    #if defined(WIN32) && !defined(__CYGWIN__)
    
    // Unicode utility routines borrowed from FLTK
    
    static unsigned int 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) {
        if (((unsigned char*)p)[1] > 0x8f) goto FAIL; // after 0x10ffff
        goto UTF8_4;
      } else {
      FAIL:
        if (len) *len = 1;
        return c;
      }
    }
    
    static unsigned int utf8toUtf16(const char* src, unsigned int srclen,
                                    unsigned short* dst, unsigned int dstlen)
    {
      const char* p = src;
      const char* e = src+srclen;
      unsigned int count = 0;
      if (dstlen) for (;;) {
        if (p >= e) {dst[count] = 0; return count;}
        if (!(*p & 0x80)) { // ascii
          dst[count] = *p++;
        } else {
          int len; unsigned int ucs = utf8decode(p,e,&len);
          p += len;
          if (ucs < 0x10000) {
    	dst[count] = ucs;
          } else {
    	// 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;}
      }
      // we filled dst, measure the rest:
      while (p < e) {
        if (!(*p & 0x80)) p++;
        else {
          int len; unsigned int ucs = utf8decode(p,e,&len);
          p += len;
          if (ucs >= 0x10000) ++count;
        }
        ++count;
      }
      return count;
    }
    
    static unsigned int utf8FromUtf16(char* dst, unsigned int dstlen,
                                      const wchar_t* src, unsigned int srclen)
    {
      unsigned int i = 0;
      unsigned int count = 0;
      if (dstlen) {
        for (;;) {
          unsigned int 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 int 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 int 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};
    
    static void setwbuf(int i, const char *f)
    {
      // 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.
      if(i < 0 || i > 2) return;
      size_t l = strlen(f);
      unsigned int wn = utf8toUtf16(f, (unsigned int) 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;
    }
    
    #endif
    
    FILE *Fopen(const char *f, const char *mode)
    {
    #if defined (WIN32) && !defined(__CYGWIN__)
      setwbuf(0, f);
      setwbuf(1, mode);
      return _wfopen(wbuf[0], wbuf[1]);
    #else
      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);
    #endif
    }
    
    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);
    #endif
    }
    
    double GetTimeInSeconds()
    {
    #if defined(WIN32) && !defined(__CYGWIN__)
      FILETIME ft;
      GetSystemTimeAsFileTime(&ft);
      double t =  1.e-7 * 4294967296. * (double)ft.dwHighDateTime +
                  1.e-7 * (double)ft.dwLowDateTime;
      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;
    #endif
    }
    
    void SleepInSeconds(double s)
    {
    #if defined(WIN32) && !defined(__CYGWIN__)
      Sleep((long)(1.e3 * s));
    #else
      usleep((long)(1.e6 * s));
    #endif
    }
    
    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
    #endif
    }
    
    void CheckResources()
    {
    #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
      // 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);
        r.rlim_cur = r.rlim_max;
        setrlimit(RLIMIT_STACK, &r);
      }
    #endif
    }
    
    double Cpu()
    {
      long mem = 0;
      double s = 0.;
      GetResources(&s, &mem);
      return s;
    }
    
    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;
    }
    
    int GetProcessId()
    {
    #if defined(WIN32) && !defined(__CYGWIN__)
      return _getpid();
    #else
      return getpid();
    #endif
    }
    
    std::string GetExecutableFileName()
    {
      std::string name = "";
    #if defined(WIN32) && !defined(__CYGWIN__)
      wchar_t src[MAX_PATH];
      unsigned long 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);
      if(_NSGetExecutablePath(path, &size) == 0){
        char real[PATH_MAX];
        if(realpath(path, real)){
          name = std::string(real);
        }
      }
    #elif defined(__linux__)
      char path[4096];
      if(readlink("/proc/self/exe", path, 4096) > 0){
        name = std::string(path);
      }
    #endif
      return name;
    }
    
    std::string GetAbsolutePath(const std::string &fileName)
    {
    #if defined(WIN32) && !defined(__CYGWIN__)
      setwbuf(0, fileName.c_str());
      wchar_t path[MAX_PATH];
      unsigned long size = GetFullPathNameW(wbuf[0], MAX_PATH, path, NULL);
      if(size){
        char dst[MAX_PATH];
        utf8FromUtf16(dst, MAX_PATH, path, size);
        return std::string(dst);
      }
    #else
      char path[4096];
      if(realpath(fileName.c_str(), path))
        return path;
    #endif
      return fileName;
    }
    
    std::string GetHostName()
    {
      char host[256];
      gethostname(host, sizeof(host));
      return std::string(host);
    }
    
    int UnlinkFile(const std::string &fileName)
    {
    #if defined(WIN32) && !defined(__CYGWIN__)
      setwbuf(0, fileName.c_str());
      return _wunlink(wbuf[0]);
    #else
      return unlink(fileName.c_str());
    #endif
    }
    
    int StatFile(const std::string &fileName)
    {
    #if defined(WIN32) && !defined(__CYGWIN__)
      struct _stat buf;
      setwbuf(0, fileName.c_str());
      int ret = _wstat(wbuf[0], &buf);
    #else
      struct stat buf;
      int ret = stat(fileName.c_str(), &buf);
    #endif
      return ret;
    }
    
    int CreateSingleDir(const std::string &dirName)
    {
    #if defined(WIN32) && !defined(__CYGWIN__)
      setwbuf(0, dirName.c_str());
      if(_wmkdir(wbuf[0])) return 0;
    #else
      if(mkdir(dirName.c_str(), 0777)) return 0;
    #endif
      return 1;
    }
    
    void CreatePath(const std::string &fullPath)
    {
      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));
      }
    }
    
    int KillProcess(int pid)
    {
    #if defined(WIN32) && !defined(__CYGWIN__)
      HANDLE hProc = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
      if(!TerminateProcess(hProc, 0)){
        CloseHandle(hProc);
        return 0;
      }
    #else
      if(kill(pid, 9))
        return 0;
    #endif
      return 1;
    }
    
    int SystemCallExe(const std::string &exe, const std::string &argsOrCommand,
                      bool blocking)
    {
      // do we try to run a .py script, .m script or an .exe?
      std::vector<std::string> split = SplitFileName(exe);
      bool isPython = (split[2] == ".py" || split[2] == ".PY");
      bool isOctave = (split[2] == ".m" || split[2] == ".M");
      bool isExe = (split[2] == ".exe" || split[2] == ".EXE");
    
      if(isPython || isOctave || isExe){
        if(StatFile(exe)){
          Msg::Error("Unable to open file '%s'", exe.c_str());
          return 1;
        }
      }
    
      std::string command;
      if(exe.size()){
        command.append("\"" + exe + "\""); // allows exe with white space
        if(argsOrCommand.size()) command.append(" ");
      }
      command.append(argsOrCommand);
    
    #if defined(WIN32) && !defined(__CYGWIN__)
      if(isPython || isOctave){
        Msg::Info("Shell opening '%s' with arguments '%s'", exe.c_str(),
                  argsOrCommand.c_str());
        setwbuf(0, "open");
        setwbuf(1, exe.c_str());
        setwbuf(2, argsOrCommand.c_str());
        ShellExecuteW(NULL, wbuf[0], wbuf[1], wbuf[2], NULL, 0);
      }
      else{
        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());
        if(blocking){
          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{
          // 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);
        }
      }
    #else
      std::string cmd(command);
      if(isPython || isOctave || isExe){
        if(access(exe.c_str(), X_OK)){
          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;
          }
          else
            Msg::Warning("File '%s' is not executable", exe.c_str());
        }
        else if(split[0].empty()){
          // workaround if pwd is not in PATH
          cmd = "./" + cmd;
        }
      }
      if(!system(NULL)) {
        Msg::Error("Could not find /bin/sh: aborting system call");
        return 1;
      }
      if(!blocking) cmd += " &";
    #if defined(HAVE_FLTK) // FIXME: remove
      if(FlGui::available()) FlGui::instance()->lock();
    #endif
      Msg::Info("Calling '%s'", cmd.c_str());
    #if defined(HAVE_FLTK) // FIXME: remove
      if(FlGui::available()) FlGui::instance()->unlock();
    #endif
      if(!system(cmd.c_str())) return 1;
    #endif
      return 0;
    }
    
    int SystemCall(const std::string &command, bool blocking)
    {
      return SystemCallExe("", command, blocking);
    }
    
    std::string GetCurrentWorkdir()
    {
      char path[1024];
    
    #if defined(WIN32) && !defined(__CYGWIN__)
      // should use Unicode version
      if(!_getcwd(path, sizeof(path))) return "";
    #else
      if(!getcwd(path, sizeof(path))) return "";
    #endif
    
      std::string str(path);
      // match the convention of SplitFileName that delivers directory path
      // ending with a directory separator
    #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
      // 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
      {
        intptr_t lStdHandle = (intptr_t)GetStdHandle(STD_OUTPUT_HANDLE);
        if(lStdHandle != (intptr_t)INVALID_HANDLE_VALUE){
          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);
        if(lStdHandle != (intptr_t)INVALID_HANDLE_VALUE){
          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);
        if(lStdHandle != (intptr_t)INVALID_HANDLE_VALUE){
          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
    }
    
    void UnzipFile(const std::string &fileName, const std::string &prependDir)
    {
    #if defined(HAVE_ZIPPER)
      std::string dir = prependDir;
      if(dir.size() && dir[dir.size()-1] != '/' && dir[dir.size()-1] != '\\')
        dir.push_back('/');
    
      ziputils::unzipper zipFile;
      zipFile.open(fileName.c_str());
      std::vector<std::string> dirnames = zipFile.getFolders();
      for (std::vector<std::string>::const_iterator it = dirnames.begin();
           it != dirnames.end(); it++){
        std::string folder = dir + *it;
        Msg::Info("Creating folder `%s'", folder.c_str());
        CreatePath(folder);
      }
      std::vector<std::string> filenames = zipFile.getFilenames();
      for (std::vector<std::string>::const_iterator it = filenames.begin();
           it != filenames.end(); it++){
        zipFile.openEntry(it->c_str());
        std::string name = dir + *it;
        Msg::Info("Extracting file `%s'", name.c_str());
        std::ofstream ofs;
        ofs.open(name.c_str());
        if(ofs.is_open()){
          zipFile >> ofs;
          ofs.close();
        }
        else
          Msg::Error("Could not create file `%s'", name.c_str());
      }
    #else
      Msg::Error("Gmsh must be compiled with Zipper support to extract zip files");
    #endif
    }