portable.cpp
Go to the documentation of this file.
1 #include <stdlib.h>
2 #include <ctype.h>
3 #if defined(_WIN32) && !defined(__CYGWIN__)
4 #undef UNICODE
5 #define _WIN32_DCOM
6 #include <windows.h>
7 #else
8 #include <unistd.h>
9 #include <stdlib.h>
10 #include <sys/types.h>
11 #include <sys/wait.h>
12 #include <errno.h>
13 extern char **environ;
14 #endif
15 
16 #include <qglobal.h>
17 #include <qdatetime.h>
18 
19 #if defined(_MSC_VER) || defined(__BORLANDC__)
20 #define popen _popen
21 #define pclose _pclose
22 #endif
23 
24 #include "portable.h"
25 #ifndef NODEBUG
26 #include "debug.h"
27 #endif
28 //#include "doxygen.h"
29 
30 static double g_sysElapsedTime;
31 static QTime g_time;
32 
33 int portable_system(const char *command,const char *args,bool commandHasConsole)
34 {
35 
36  if (command==0) return 1;
37 
38  QCString fullCmd=command;
39  fullCmd=fullCmd.stripWhiteSpace();
40  if (fullCmd.at(0)!='"' && fullCmd.find(' ')!=-1)
41  {
42  // add quotes around command as it contains spaces and is not quoted already
43  fullCmd="\""+fullCmd+"\"";
44  }
45  fullCmd += " ";
46  fullCmd += args;
47 #ifndef NODEBUG
48  Debug::print(Debug::ExtCmd,0,"Executing external command `%s`\n",qPrint(fullCmd));
49 #endif
50 
51 #if !defined(_WIN32) || defined(__CYGWIN__)
52  (void)commandHasConsole;
53  /*! taken from the system() manpage on my Linux box */
54  int pid,status=0;
55 
56 #ifdef _OS_SOLARIS // for Solaris we use vfork since it is more memory efficient
57 
58  // on Solaris fork() duplicates the memory usage
59  // so we use vfork instead
60 
61  // spawn shell
62  if ((pid=vfork())<0)
63  {
64  status=-1;
65  }
66  else if (pid==0)
67  {
68  execl("/bin/sh","sh","-c",fullCmd.data(),(char*)0);
69  _exit(127);
70  }
71  else
72  {
73  while (waitpid(pid,&status,0 )<0)
74  {
75  if (errno!=EINTR)
76  {
77  status=-1;
78  break;
79  }
80  }
81  }
82  return status;
83 
84 #else // Other Unices just use fork
85 
86  pid = fork();
87  if (pid==-1)
88  {
89  perror("fork error");
90  return -1;
91  }
92  if (pid==0)
93  {
94  const char * argv[4];
95  argv[0] = "sh";
96  argv[1] = "-c";
97  argv[2] = fullCmd.data();
98  argv[3] = 0;
99  execve("/bin/sh",(char * const *)argv,environ);
100  exit(127);
101  }
102  for (;;)
103  {
104  if (waitpid(pid,&status,0)==-1)
105  {
106  if (errno!=EINTR) return -1;
107  }
108  else
109  {
110  if (WIFEXITED(status))
111  {
112  return WEXITSTATUS(status);
113  }
114  else
115  {
116  return status;
117  }
118  }
119  }
120 #endif // !_OS_SOLARIS
121 
122 #else // Win32 specific
123  if (commandHasConsole)
124  {
125  return system(fullCmd);
126  }
127  else
128  {
129  // Because ShellExecuteEx can delegate execution to Shell extensions
130  // (data sources, context menu handlers, verb implementations) that
131  // are activated using Component Object Model (COM), COM should be
132  // initialized before ShellExecuteEx is called. Some Shell extensions
133  // require the COM single-threaded apartment (STA) type.
134  // For that case COM is initialized as follows
135  CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
136 
137  QString commandw = QString::fromUtf8( command );
138  QString argsw = QString::fromUtf8( args );
139 
140  // gswin32 is a GUI api which will pop up a window and run
141  // asynchronously. To prevent both, we use ShellExecuteEx and
142  // WaitForSingleObject (thanks to Robert Golias for the code)
143 
144  SHELLEXECUTEINFOW sInfo = {
145  sizeof(SHELLEXECUTEINFOW), /* structure size */
146  SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI, /* tell us the process
147  * handle so we can wait till it's done |
148  * do not display msg box if error
149  */
150  NULL, /* window handle */
151  NULL, /* action to perform: open */
152  (LPCWSTR)commandw.ucs2(), /* file to execute */
153  (LPCWSTR)argsw.ucs2(), /* argument list */
154  NULL, /* use current working dir */
155  SW_HIDE, /* minimize on start-up */
156  0, /* application instance handle */
157  NULL, /* ignored: id list */
158  NULL, /* ignored: class name */
159  NULL, /* ignored: key class */
160  0, /* ignored: hot key */
161  NULL, /* ignored: icon */
162  NULL /* resulting application handle */
163  };
164 
165  if (!ShellExecuteExW(&sInfo))
166  {
167  return -1;
168  }
169  else if (sInfo.hProcess) /* executable was launched, wait for it to finish */
170  {
171  WaitForSingleObject(sInfo.hProcess,INFINITE);
172  /* get process exit code */
173  DWORD exitCode;
174  if (!GetExitCodeProcess(sInfo.hProcess,&exitCode))
175  {
176  exitCode = -1;
177  }
178  CloseHandle(sInfo.hProcess);
179  return exitCode;
180  }
181  }
182 #endif
183 
184 }
185 
187 {
188  uint pid;
189 #if !defined(_WIN32) || defined(__CYGWIN__)
190  pid = (uint)getpid();
191 #else
192  pid = (uint)GetCurrentProcessId();
193 #endif
194  return pid;
195 }
196 
197 #if defined(_WIN32) && !defined(__CYGWIN__)
198 #else
199  static char **last_environ;
200 #endif
201 
202 void portable_setenv(const char *name,const char *value)
203 {
204  if (value==0) value="";
205 #if defined(_WIN32) && !defined(__CYGWIN__)
206  SetEnvironmentVariable(name,value);
207 #else
208  register char **ep = 0;
209  register size_t size;
210  const size_t namelen=qstrlen(name);
211  const size_t vallen=qstrlen(value) + 1;
212 
213  size = 0;
214  if (environ!=0)
215  {
216  for (ep = environ; *ep; ++ep)
217  {
218  if (!qstrncmp (*ep, name, (uint)namelen) &&
219  (*ep)[namelen] == '=')
220  break;
221  else
222  ++size;
223  }
224  }
225 
226  if (environ==0 || *ep==0) /* add new string */
227  {
228  char **new_environ;
229  if (environ == last_environ && environ!=0)
230  {
231  // We allocated this space; we can extend it.
232  new_environ = (char **) realloc (last_environ, (size + 2) * sizeof (char *));
233  }
234  else
235  {
236  new_environ = (char **) malloc ((size + 2) * sizeof (char *));
237  }
238 
239  if (new_environ==0) // no more memory
240  {
241  return;
242  }
243 
244  new_environ[size] = (char *)malloc (namelen + 1 + vallen);
245  if (new_environ[size]==0)
246  {
247  free (new_environ);
248  return;
249  }
250 
251  if (environ != last_environ)
252  {
253  memcpy ((char *) new_environ, environ, size * sizeof (char *));
254  }
255 
256  memcpy(new_environ[size], name, namelen);
257  new_environ[size][namelen] = '=';
258  memcpy(&new_environ[size][namelen + 1], value, vallen);
259  new_environ[size + 1] = 0;
260  last_environ = environ = new_environ;
261  }
262  else /* replace existing string */
263  {
264  size_t len = qstrlen (*ep);
265  if (len + 1 < namelen + 1 + vallen)
266  {
267  /* The existing string is too short; malloc a new one. */
268  char *newString = (char *)malloc(namelen + 1 + vallen);
269  if (newString==0)
270  {
271  return;
272  }
273  *ep = newString;
274  }
275  memcpy(*ep, name, namelen);
276  (*ep)[namelen] = '=';
277  memcpy(&(*ep)[namelen + 1], value, vallen);
278  }
279 
280 #endif
281 }
282 
283 void portable_unsetenv(const char *variable)
284 {
285 #if defined(_WIN32) && !defined(__CYGWIN__)
286  SetEnvironmentVariable(variable,0);
287 #else
288  /* Some systems don't have unsetenv(), so we do it ourselves */
289  size_t len;
290  char **ep;
291 
292  if (variable == NULL || *variable == '\0' || strchr (variable, '=') != NULL)
293  {
294  return; // not properly formatted
295  }
296 
297  len = qstrlen(variable);
298 
299  ep = environ;
300  while (*ep != NULL)
301  {
302  if (!qstrncmp(*ep, variable, (uint)len) && (*ep)[len]=='=')
303  {
304  /* Found it. Remove this pointer by moving later ones back. */
305  char **dp = ep;
306  do dp[0] = dp[1]; while (*dp++);
307  /* Continue the loop in case NAME appears again. */
308  }
309  else
310  {
311  ++ep;
312  }
313  }
314 #endif
315 }
316 
317 const char *portable_getenv(const char *variable)
318 {
319  return getenv(variable);
320 }
321 
323 {
324 #if defined(__MINGW32__)
325  return fseeko64(f,offset,whence);
326 #elif defined(_WIN32) && !defined(__CYGWIN__)
327  return _fseeki64(f,offset,whence);
328 #else
329  return fseeko(f,offset,whence);
330 #endif
331 }
332 
334 {
335 #if defined(__MINGW32__)
336  return ftello64(f);
337 #elif defined(_WIN32) && !defined(__CYGWIN__)
338  return _ftelli64(f);
339 #else
340  return ftello(f);
341 #endif
342 }
343 
344 FILE *portable_fopen(const char *fileName,const char *mode)
345 {
346 #if defined(_WIN32) && !defined(__CYGWIN__)
347  QString fn(fileName);
348  QString m(mode);
349  return _wfopen((wchar_t*)fn.ucs2(),(wchar_t*)m.ucs2());
350 #else
351  return fopen(fileName,mode);
352 #endif
353 }
354 
356 {
357 #if defined(_WIN32) && !defined(__CYGWIN__)
358  return '\\';
359 #else
360  return '/';
361 #endif
362 }
363 
365 {
366 #if defined(_WIN32) && !defined(__CYGWIN__)
367  return ';';
368 #else
369  return ':';
370 #endif
371 }
372 
374 {
375 #if defined(_WIN32) && !defined(__CYGWIN__)
376  return "gswin32c.exe";
377 #else
378  return "gs";
379 #endif
380 }
381 
383 {
384 #if defined(_WIN32) && !defined(__CYGWIN__)
385  return ".exe";
386 #else
387  return "";
388 #endif
389 }
390 
392 {
393 #if defined(_WIN32) || defined(macintosh) || defined(__MACOSX__) || defined(__APPLE__)
394  return FALSE;
395 #else
396  return TRUE;
397 #endif
398 }
399 
400 FILE * portable_popen(const char *name,const char *type)
401 {
402  return popen(name,type);
403 }
404 
406 {
407  return pclose(stream);
408 }
409 
411 {
412  g_time.start();
413 }
414 
416 {
417  g_sysElapsedTime+=((double)g_time.elapsed())/1000.0;
418 }
419 
421 {
422  return g_sysElapsedTime;
423 }
424 
426 {
427 #if defined(_WIN32) && !defined(__CYGWIN__)
428  Sleep(ms);
429 #else
430  usleep(1000*ms);
431 #endif
432 }
433 
435 {
436 # ifdef _WIN32
437  if (isalpha (fileName [0]) && fileName[1] == ':')
438  fileName += 2;
439 # endif
440  char const fst = fileName [0];
441  if (fst == '/') {
442  return true;
443  }
444 # ifdef _WIN32
445  if (fst == '\\')
446  return true;
447 # endif
448  return false;
449 }
450 
451 
static QCString name
Definition: declinfo.cpp:673
void portable_sleep(int ms)
Definition: portable.cpp:425
Q_EXPORT int qstrncmp(const char *str1, const char *str2, uint len)
Definition: qcstring.h:101
bool portable_isAbsolutePath(const char *fileName)
Definition: portable.cpp:434
void portable_sysTimerStop()
Definition: portable.cpp:415
QCString stripWhiteSpace() const
Definition: qcstring.cpp:295
void start()
Definition: qdatetime.cpp:949
FILE * portable_popen(const char *name, const char *type)
Definition: portable.cpp:400
const char * portable_getenv(const char *variable)
Definition: portable.cpp:317
off_t portable_off_t
Definition: portable.h:11
double portable_getSysElapsedTime()
Definition: portable.cpp:420
int command
char & at(uint i) const
Definition: qcstring.h:326
const bool FALSE
Definition: qglobal.h:370
void portable_unsetenv(const char *variable)
Definition: portable.cpp:283
The QString class provides an abstraction of Unicode text and the classic C null-terminated char arra...
Definition: qstring.h:350
const char * portable_ghostScriptCommand()
Definition: portable.cpp:373
int errno
Contains the last error code.
Definition: structcmd.h:53
int find(char c, int index=0, bool cs=TRUE) const
Definition: qcstring.cpp:41
static QCString args
Definition: declinfo.cpp:674
static double g_sysElapsedTime
Definition: portable.cpp:30
void portable_sysTimerStart()
Definition: portable.cpp:410
static constexpr double ms
Definition: Units.h:96
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:92
The QTime class provides clock time functions.
Definition: qdatetime.h:108
QAsciiDict< Entry > fn
Q_EXPORT uint qstrlen(const char *str)
Definition: qcstring.h:81
fileName
Definition: dumpTree.py:9
std::string getenv(std::string const &name)
Definition: getenv.cc:15
const unsigned short * ucs2() const
Definition: qstring.cpp:12092
static void print(DebugMask mask, int prio, const char *fmt,...)
Definition: debug.cpp:84
portable_off_t portable_fseek(FILE *f, portable_off_t offset, int whence)
Definition: portable.cpp:322
const char * data() const
Definition: qcstring.h:207
char portable_pathListSeparator()
Definition: portable.cpp:364
static char ** last_environ
Definition: portable.cpp:199
portable_off_t portable_ftell(FILE *f)
Definition: portable.cpp:333
char ** environ
bool portable_fileSystemIsCaseSensitive()
Definition: portable.cpp:391
void portable_setenv(const char *name, const char *value)
Definition: portable.cpp:202
static QString fromUtf8(const char *, int len=-1)
Definition: qstring.cpp:14523
int portable_pclose(FILE *stream)
Definition: portable.cpp:405
const char * portable_commandExtension()
Definition: portable.cpp:382
static QTime g_time
Definition: portable.cpp:31
char portable_pathSeparator()
Definition: portable.cpp:355
unsigned uint
Definition: qglobal.h:351
FILE * portable_fopen(const char *fileName, const char *mode)
Definition: portable.cpp:344
uint portable_pid()
Definition: portable.cpp:186
const char * qPrint(const char *s)
Definition: qcstring.h:797
const bool TRUE
Definition: qglobal.h:371
Portable versions of functions that are platform dependent.
int elapsed()
Definition: qdatetime.cpp:1000
int portable_system(const char *command, const char *args, bool commandHasConsole)
Definition: portable.cpp:33