Newer
Older
// Gmsh - Copyright (C) 1997-2013 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>

Christophe Geuzaine
committed
#include "GmshConfig.h"

Christophe Geuzaine
committed
#include "StringUtils.h"
#include <sys/time.h>
#include <sys/resource.h>
#include <fcntl.h>
#include <iostream>
#include <fstream>
#endif
#if defined(__APPLE__)
#define RUSAGE_SELF 0
#define RUSAGE_CHILDREN -1
#endif

Christophe Geuzaine
committed
#include "GmshMessage.h"
#if defined(WIN32) && !defined(__CYGWIN__)
// UTF8 utility routines borrowed from FLTK
static unsigned utf8decode(const char* p, const char* end, int* len)
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
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 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;}
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 {
/* 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 ucs = utf8decode(p,e,&len);
p += len;
if (ucs >= 0x10000) ++count;
}
++count;
}
return count;
}
static wchar_t *wbuf[2] = {NULL, NULL};
static void setwbuf(int i, const char *f)
{
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;
}
#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]);
return fopen(f, mode);
#endif
}
const char *GetEnvironmentVar(const char *var)
{
#if defined(WIN32) && !defined(__CYGWIN__)
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);
const void SetEnvironmentVar(const char *var, const char *val)
{
#if defined(WIN32) && !defined(__CYGWIN__)
_putenv((std::string(var) + "=" + std::string(val)).c_str());
#else
setenv(var, val, 1);
#endif
}
#if defined(WIN32) && !defined(__CYGWIN__)
double t = 1.e-7 * 4294967296. * (double)ft.dwHighDateTime +
1.e-7 * (double)ft.dwLowDateTime;
#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
#if defined(WIN32) && !defined(__CYGWIN__)
#else
usleep((long)(1.e6 * s));
#endif
#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
}
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;
}
long GetMemoryUsage()
{
long mem = 0;
double s = 0.;
GetResources(&s, &mem);
return mem;
}
#if defined(WIN32) && !defined(__CYGWIN__)
#else
return getpid();
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]);
return unlink(fileName.c_str());
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);

Christophe Geuzaine
committed
int ret = stat(fileName.c_str(), &buf);

Christophe Geuzaine
committed
return ret;

Christophe Geuzaine
committed
int CreateDirectory(const std::string &dirName)
{
#if defined(WIN32) && !defined(__CYGWIN__)
setwbuf(0, dirName.c_str());
if(_wmkdir(wbuf[0])) return 0;

Christophe Geuzaine
committed
#else
if(mkdir(dirName.c_str(), 0777)) return 0;

Christophe Geuzaine
committed
#endif
return 1;
}
#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;
int SystemCall(const std::string &command, bool blocking)
// separate (potential) executable from arguments
std::string exe, args;
std::string::size_type pos = command.find_first_of(" ");
if(pos != std::string::npos){
exe = command.substr(0, pos);
args = command.substr(pos, command.size() - pos);
}

Christophe Geuzaine
committed
else
exe = command;
// get executable extension
std::vector<std::string> split = SplitFileName(exe);
// do we try to run a .py script or a .exe?
bool isPython = (split[2] == ".py" || split[2] == ".PY");
bool isExe = (split[2] == ".exe" || split[2] == ".EXE");
if(isPython || isExe){
if(StatFile(exe)){
Msg::Error("Unable to open file '%s'", exe.c_str());
return 1;
}
#if defined(WIN32) && !defined(__CYGWIN__)
Msg::Info("Shell opening '%s' with arguments '%s'", exe.c_str(),
args.c_str());
(char*)args.c_str(), NULL, 0);
STARTUPINFO suInfo;
PROCESS_INFORMATION prInfo;
memset(&suInfo, 0, sizeof(suInfo));
suInfo.cb = sizeof(suInfo);
Msg::Info("Calling '%s'", command.c_str());
if(blocking){
CreateProcess(NULL, (char*)command.c_str(), 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)
CreateProcess(NULL, (char*)command.c_str(), NULL, NULL, FALSE,
NORMAL_PRIORITY_CLASS|DETACHED_PROCESS, NULL, NULL,
&suInfo, &prInfo);
}

Christophe Geuzaine
committed
std::string cmd(command);

Christophe Geuzaine
committed
if(access(exe.c_str(), X_OK)){
if(isPython){
Msg::Info("Script '%s' is not executable: running with python", exe.c_str());
cmd = "python " + cmd;
}
else
Msg::Warning("File '%s' is not executable", exe.c_str());

Christophe Geuzaine
committed
}
else if(split[0].empty()){
// workaround if pwd is not in PATH
cmd = "./" + cmd;
}

Christophe Geuzaine
committed
}
Msg::Error("Could not find /bin/sh: aborting system call");
#if defined(WIN32) && !defined(__CYGWIN__)
if(!_getcwd(path, sizeof(path))) return "";
#else
if(!getcwd(path, sizeof(path))) return "";
// 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);
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);
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);
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
}