Fix for UBSan build
[platform/upstream/doxygen.git] / src / portable.cpp
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",fullCmd.data());
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) return -1;
88   if (pid==0)
89   {
90     const char * argv[4];
91     argv[0] = "sh";
92     argv[1] = "-c";
93     argv[2] = fullCmd.data();
94     argv[3] = 0;
95     execve("/bin/sh",(char * const *)argv,environ);
96     exit(127);
97   }
98   for (;;)
99   {
100     if (waitpid(pid,&status,0)==-1)
101     {
102       if (errno!=EINTR) return -1;
103     }
104     else
105     {
106       if (WIFEXITED(status))
107       {
108         return WEXITSTATUS(status);
109       }
110       else
111       {
112         return status;
113       }
114     }
115   }
116 #endif // !_OS_SOLARIS
117
118 #else // Win32 specific
119   if (commandHasConsole)
120   {
121     return system(fullCmd);
122   }
123   else
124   {
125     // Because ShellExecuteEx can delegate execution to Shell extensions 
126     // (data sources, context menu handlers, verb implementations) that 
127     // are activated using Component Object Model (COM), COM should be 
128     // initialized before ShellExecuteEx is called. Some Shell extensions 
129     // require the COM single-threaded apartment (STA) type. 
130     // For that case COM is initialized as follows
131     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
132
133     // gswin32 is a GUI api which will pop up a window and run
134     // asynchronously. To prevent both, we use ShellExecuteEx and
135     // WaitForSingleObject (thanks to Robert Golias for the code)
136
137     SHELLEXECUTEINFO sInfo = {
138       sizeof(SHELLEXECUTEINFO),   /* structure size */
139       SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI,  /* tell us the process
140                                                        *  handle so we can wait till it's done | 
141                                                        *  do not display msg box if error 
142                                                        */
143       NULL,                       /* window handle */
144       NULL,                       /* action to perform: open */
145       command,                    /* file to execute */
146       args,                       /* argument list */ 
147       NULL,                       /* use current working dir */
148       SW_HIDE,                    /* minimize on start-up */
149       0,                          /* application instance handle */
150       NULL,                       /* ignored: id list */
151       NULL,                       /* ignored: class name */
152       NULL,                       /* ignored: key class */
153       0,                          /* ignored: hot key */
154       NULL,                       /* ignored: icon */
155       NULL                        /* resulting application handle */
156     };
157     if (!ShellExecuteEx(&sInfo))
158     {
159       return -1;
160     }
161     else if (sInfo.hProcess)      /* executable was launched, wait for it to finish */
162     {
163       WaitForSingleObject(sInfo.hProcess,INFINITE); 
164       CloseHandle(sInfo.hProcess);
165     }
166   }
167   return 0;
168 #endif
169
170 }
171
172 uint portable_pid()
173 {
174   uint pid;
175 #if !defined(_WIN32) || defined(__CYGWIN__)
176   pid = (uint)getpid();
177 #else
178   pid = (uint)GetCurrentProcessId();
179 #endif
180   return pid;
181 }
182
183 static char **last_environ;
184
185 void portable_setenv(const char *name,const char *value)
186 {
187     if (value==0) value="";
188 #if defined(_WIN32) && !defined(__CYGWIN__)
189     SetEnvironmentVariable(name,value);
190 #else
191     register char **ep = 0;
192     register size_t size;
193     const size_t namelen=strlen(name);
194     const size_t vallen=strlen(value) + 1;
195
196     size = 0;
197     if (environ!=0)
198     {
199       for (ep = environ; *ep; ++ep)
200       {
201         if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=')
202           break;
203         else
204           ++size;
205       }
206     }
207
208     if (environ==0 || *ep==0) /* add new string */
209     {
210       char **new_environ;
211       if (environ == last_environ && environ!=0)
212       {
213         // We allocated this space; we can extend it. 
214         new_environ = (char **) realloc (last_environ, (size + 2) * sizeof (char *));
215       }
216       else
217       {
218         new_environ = (char **) malloc ((size + 2) * sizeof (char *));
219       }
220
221       if (new_environ==0) // no more memory 
222       {
223         return;
224       }
225
226       new_environ[size] = (char *)malloc (namelen + 1 + vallen);
227       if (new_environ[size]==0)
228       {
229         free (new_environ);
230         return;
231       }
232
233       if (environ != last_environ)
234       {
235         memcpy ((char *) new_environ, environ, size * sizeof (char *));
236       }
237
238       memcpy(new_environ[size], name, namelen);
239       new_environ[size][namelen] = '=';
240       memcpy(&new_environ[size][namelen + 1], value, vallen);
241       new_environ[size + 1] = 0;
242       last_environ = environ = new_environ;
243     }
244     else /* replace existing string */
245     {
246       size_t len = strlen (*ep);
247       if (len + 1 < namelen + 1 + vallen)
248       {
249         /* The existing string is too short; malloc a new one.  */
250         char *newString = (char *)malloc(namelen + 1 + vallen);
251         if (newString==0)
252         {
253           return;
254         }
255         *ep = newString;
256       }
257       memcpy(*ep, name, namelen);
258       (*ep)[namelen] = '=';
259       memcpy(&(*ep)[namelen + 1], value, vallen);
260     }
261
262 #endif
263 }
264
265 void portable_unsetenv(const char *variable)
266 {
267 #if defined(_WIN32) && !defined(__CYGWIN__)
268     SetEnvironmentVariable(variable,0);
269 #else
270     /* Some systems don't have unsetenv(), so we do it ourselves */
271     size_t len;
272     char **ep;
273
274     if (variable == NULL || *variable == '\0' || strchr (variable, '=') != NULL)
275     {
276       return; // not properly formatted
277     }
278
279     len = strlen(variable);
280
281     ep = environ;
282     while (*ep != NULL)
283     {
284       if (!strncmp(*ep, variable, len) && (*ep)[len]=='=')
285       {
286         /* Found it.  Remove this pointer by moving later ones back.  */
287         char **dp = ep;
288         do dp[0] = dp[1]; while (*dp++);
289         /* Continue the loop in case NAME appears again.  */
290       }
291       else
292       {
293         ++ep;
294       }
295     }
296 #endif
297 }
298
299 const char *portable_getenv(const char *variable)
300 {
301   return getenv(variable);
302 }
303
304 portable_off_t portable_fseek(FILE *f,portable_off_t offset, int whence)
305 {
306 #if defined(_WIN32) && !defined(__CYGWIN__)
307   return _fseeki64(f,offset,whence);
308 #else
309   return fseeko(f,offset,whence);
310 #endif
311 }
312
313 portable_off_t portable_ftell(FILE *f)
314 {
315 #if defined(_WIN32) && !defined(__CYGWIN__)
316   return _ftelli64(f);
317 #else
318   return ftello(f);
319 #endif
320 }
321
322 FILE *portable_fopen(const char *fileName,const char *mode)
323 {
324 #if defined(_WIN32) && !defined(__CYGWIN__)
325   QString fn(fileName);
326   QString m(mode);
327   return _wfopen((wchar_t*)fn.ucs2(),(wchar_t*)m.ucs2());
328 #else
329   return fopen(fileName,mode);
330 #endif
331 }
332
333 char  portable_pathSeparator()
334 {
335 #if defined(_WIN32) && !defined(__CYGWIN__)
336   return '\\';
337 #else
338   return '/';
339 #endif
340 }
341
342 char  portable_pathListSeparator()
343 {
344 #if defined(_WIN32) && !defined(__CYGWIN__)
345   return ';';
346 #else
347   return ':';
348 #endif
349 }
350
351 const char *portable_ghostScriptCommand()
352 {
353 #if defined(_WIN32) && !defined(__CYGWIN__)
354     return "gswin32c.exe";
355 #else
356     return "gs";
357 #endif
358 }
359
360 const char *portable_commandExtension()
361 {
362 #if defined(_WIN32) && !defined(__CYGWIN__)
363     return ".exe";
364 #else
365     return "";
366 #endif
367 }
368
369 bool portable_fileSystemIsCaseSensitive()
370 {
371 #if defined(_WIN32) || defined(macintosh) || defined(__MACOSX__) || defined(__APPLE__)
372   return FALSE;
373 #else
374   return TRUE;
375 #endif
376 }
377
378 FILE * portable_popen(const char *name,const char *type)
379 {
380   return popen(name,type);
381 }
382
383 int portable_pclose(FILE *stream)
384 {
385   return pclose(stream);
386 }
387
388 void portable_sysTimerStart()
389 {
390   g_time.start();
391 }
392
393 void portable_sysTimerStop()
394 {
395   g_sysElapsedTime+=((double)g_time.elapsed())/1000.0;
396 }
397
398 double portable_getSysElapsedTime()
399 {
400   return g_sysElapsedTime;
401 }
402
403 void portable_sleep(int ms)
404 {
405 #if defined(_WIN32) && !defined(__CYGWIN__)
406   Sleep(ms);
407 #else
408   usleep(1000*ms);
409 #endif
410 }