|
1 #include <stdlib.h> |
|
2 #include <ctype.h> |
|
3 #if defined(_WIN32) && !defined(__CYGWIN__) |
|
4 #undef UNICODE |
|
5 #include <windows.h> |
|
6 #else |
|
7 #include <unistd.h> |
|
8 #include <stdlib.h> |
|
9 #include <sys/types.h> |
|
10 #include <sys/wait.h> |
|
11 #include <errno.h> |
|
12 extern char **environ; |
|
13 #endif |
|
14 |
|
15 #include <qglobal.h> |
|
16 #include <qdatetime.h> |
|
17 |
|
18 #if defined(_MSC_VER) || defined(__BORLANDC__) |
|
19 #define popen _popen |
|
20 #define pclose _pclose |
|
21 #endif |
|
22 |
|
23 #include "portable.h" |
|
24 #ifndef NODEBUG |
|
25 #include "debug.h" |
|
26 #endif |
|
27 //#include "doxygen.h" |
|
28 |
|
29 static double sysElapsedTime; |
|
30 |
|
31 int portable_system(const char *command,const char *args,bool commandHasConsole) |
|
32 { |
|
33 QTime time; |
|
34 time.start(); |
|
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 commandHasConsole=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 sysElapsedTime+=((double)time.elapsed())/1000.0; |
|
83 return status; |
|
84 |
|
85 #else // Other Unices just use fork |
|
86 |
|
87 pid = fork(); |
|
88 if (pid==-1) return -1; |
|
89 if (pid==0) |
|
90 { |
|
91 const char * argv[4]; |
|
92 argv[0] = "sh"; |
|
93 argv[1] = "-c"; |
|
94 argv[2] = fullCmd.data(); |
|
95 argv[3] = 0; |
|
96 execve("/bin/sh",(char * const *)argv,environ); |
|
97 exit(127); |
|
98 } |
|
99 for (;;) |
|
100 { |
|
101 if (waitpid(pid,&status,0)==-1) |
|
102 { |
|
103 if (errno!=EINTR) return -1; |
|
104 } |
|
105 else |
|
106 { |
|
107 sysElapsedTime+=((double)time.elapsed())/1000.0; |
|
108 if (WIFEXITED(status)) |
|
109 { |
|
110 return WEXITSTATUS(status); |
|
111 } |
|
112 else |
|
113 { |
|
114 return status; |
|
115 } |
|
116 } |
|
117 } |
|
118 #endif // !_OS_SOLARIS |
|
119 |
|
120 #else // Win32 specific |
|
121 if (commandHasConsole) |
|
122 { |
|
123 return system(fullCmd); |
|
124 } |
|
125 else |
|
126 { |
|
127 // gswin32 is a GUI api which will pop up a window and run |
|
128 // asynchronously. To prevent both, we use ShellExecuteEx and |
|
129 // WaitForSingleObject (thanks to Robert Golias for the code) |
|
130 |
|
131 SHELLEXECUTEINFO sInfo = { |
|
132 sizeof(SHELLEXECUTEINFO), /* structure size */ |
|
133 SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI, /* tell us the process |
|
134 * handle so we can wait till it's done | |
|
135 * do not display msg box if error |
|
136 */ |
|
137 NULL, /* window handle */ |
|
138 NULL, /* action to perform: open */ |
|
139 command, /* file to execute */ |
|
140 args, /* argument list */ |
|
141 NULL, /* use current working dir */ |
|
142 SW_HIDE, /* minimize on start-up */ |
|
143 0, /* application instance handle */ |
|
144 NULL, /* ignored: id list */ |
|
145 NULL, /* ignored: class name */ |
|
146 NULL, /* ignored: key class */ |
|
147 0, /* ignored: hot key */ |
|
148 NULL, /* ignored: icon */ |
|
149 NULL /* resulting application handle */ |
|
150 }; |
|
151 if (!ShellExecuteEx(&sInfo)) |
|
152 { |
|
153 return -1; |
|
154 } |
|
155 else if (sInfo.hProcess) /* executable was launched, wait for it to finish */ |
|
156 { |
|
157 WaitForSingleObject(sInfo.hProcess,INFINITE); |
|
158 CloseHandle(sInfo.hProcess); |
|
159 } |
|
160 } |
|
161 sysElapsedTime+=((double)time.elapsed())/1000.0; |
|
162 return 0; |
|
163 #endif |
|
164 |
|
165 } |
|
166 |
|
167 uint portable_pid() |
|
168 { |
|
169 uint pid; |
|
170 #if !defined(_WIN32) || defined(__CYGWIN__) |
|
171 pid = (uint)getpid(); |
|
172 #else |
|
173 pid = (uint)GetCurrentProcessId(); |
|
174 #endif |
|
175 return pid; |
|
176 } |
|
177 |
|
178 static char **last_environ; |
|
179 |
|
180 void portable_setenv(const char *name,const char *value) |
|
181 { |
|
182 #if defined(_WIN32) && !defined(__CYGWIN__) |
|
183 SetEnvironmentVariable(name,value); |
|
184 #else |
|
185 register char **ep = 0; |
|
186 register size_t size; |
|
187 const size_t namelen=strlen(name); |
|
188 const size_t vallen=strlen(value) + 1; |
|
189 |
|
190 size = 0; |
|
191 if (environ!=0) |
|
192 { |
|
193 for (ep = environ; *ep; ++ep) |
|
194 { |
|
195 if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=') |
|
196 break; |
|
197 else |
|
198 ++size; |
|
199 } |
|
200 } |
|
201 |
|
202 if (environ==0 || *ep==0) /* add new string */ |
|
203 { |
|
204 char **new_environ; |
|
205 if (environ == last_environ && environ!=0) |
|
206 { |
|
207 // We allocated this space; we can extend it. |
|
208 new_environ = (char **) realloc (last_environ, (size + 2) * sizeof (char *)); |
|
209 } |
|
210 else |
|
211 { |
|
212 new_environ = (char **) malloc ((size + 2) * sizeof (char *)); |
|
213 } |
|
214 |
|
215 if (new_environ==0) // no more memory |
|
216 { |
|
217 return; |
|
218 } |
|
219 |
|
220 new_environ[size] = (char *)malloc (namelen + 1 + vallen); |
|
221 if (new_environ[size]==0) |
|
222 { |
|
223 free (new_environ); |
|
224 return; |
|
225 } |
|
226 |
|
227 if (environ != last_environ) |
|
228 { |
|
229 memcpy ((char *) new_environ, environ, size * sizeof (char *)); |
|
230 } |
|
231 |
|
232 memcpy(new_environ[size], name, namelen); |
|
233 new_environ[size][namelen] = '='; |
|
234 memcpy(&new_environ[size][namelen + 1], value, vallen); |
|
235 new_environ[size + 1] = 0; |
|
236 last_environ = environ = new_environ; |
|
237 } |
|
238 else /* replace existing string */ |
|
239 { |
|
240 size_t len = strlen (*ep); |
|
241 if (len + 1 < namelen + 1 + vallen) |
|
242 { |
|
243 /* The existing string is too short; malloc a new one. */ |
|
244 char *newString = (char *)malloc(namelen + 1 + vallen); |
|
245 if (newString==0) |
|
246 { |
|
247 return; |
|
248 } |
|
249 *ep = newString; |
|
250 } |
|
251 memcpy(*ep, name, namelen); |
|
252 (*ep)[namelen] = '='; |
|
253 memcpy(&(*ep)[namelen + 1], value, vallen); |
|
254 } |
|
255 |
|
256 #endif |
|
257 } |
|
258 |
|
259 void portable_unsetenv(const char *variable) |
|
260 { |
|
261 #if defined(_WIN32) && !defined(__CYGWIN__) |
|
262 SetEnvironmentVariable(variable,0); |
|
263 #else |
|
264 /* Some systems don't have unsetenv(), so we do it ourselves */ |
|
265 size_t len; |
|
266 char **ep; |
|
267 |
|
268 if (variable == NULL || *variable == '\0' || strchr (variable, '=') != NULL) |
|
269 { |
|
270 return; // not properly formatted |
|
271 } |
|
272 |
|
273 len = strlen(variable); |
|
274 |
|
275 ep = environ; |
|
276 while (*ep != NULL) |
|
277 { |
|
278 if (!strncmp(*ep, variable, len) && (*ep)[len]=='=') |
|
279 { |
|
280 /* Found it. Remove this pointer by moving later ones back. */ |
|
281 char **dp = ep; |
|
282 do dp[0] = dp[1]; while (*dp++); |
|
283 /* Continue the loop in case NAME appears again. */ |
|
284 } |
|
285 else |
|
286 { |
|
287 ++ep; |
|
288 } |
|
289 } |
|
290 #endif |
|
291 } |
|
292 |
|
293 const char *portable_getenv(const char *variable) |
|
294 { |
|
295 return getenv(variable); |
|
296 } |
|
297 |
|
298 portable_off_t portable_fseek(FILE *f,portable_off_t offset, int whence) |
|
299 { |
|
300 #if defined(_WIN32) && !defined(__CYGWIN__) |
|
301 return _fseeki64(f,offset,whence); |
|
302 #else |
|
303 return fseeko(f,offset,whence); |
|
304 #endif |
|
305 } |
|
306 |
|
307 portable_off_t portable_ftell(FILE *f) |
|
308 { |
|
309 #if defined(_WIN32) && !defined(__CYGWIN__) |
|
310 return _ftelli64(f); |
|
311 #else |
|
312 return ftello(f); |
|
313 #endif |
|
314 } |
|
315 |
|
316 char portable_pathSeparator() |
|
317 { |
|
318 #if defined(_WIN32) && !defined(__CYGWIN__) |
|
319 return '\\'; |
|
320 #else |
|
321 return '/'; |
|
322 #endif |
|
323 } |
|
324 |
|
325 char portable_pathListSeparator() |
|
326 { |
|
327 #if defined(_WIN32) && !defined(__CYGWIN__) |
|
328 return ';'; |
|
329 #else |
|
330 return ':'; |
|
331 #endif |
|
332 } |
|
333 |
|
334 const char *portable_ghostScriptCommand() |
|
335 { |
|
336 #if defined(_WIN32) && !defined(__CYGWIN__) |
|
337 return "gswin32c.exe"; |
|
338 #else |
|
339 return "gs"; |
|
340 #endif |
|
341 } |
|
342 |
|
343 const char *portable_commandExtension() |
|
344 { |
|
345 #if defined(_WIN32) && !defined(__CYGWIN__) |
|
346 return ".exe"; |
|
347 #else |
|
348 return ""; |
|
349 #endif |
|
350 } |
|
351 |
|
352 bool portable_fileSystemIsCaseSensitive() |
|
353 { |
|
354 #if defined(_WIN32) || defined(macintosh) || defined(__MACOSX__) || defined(__APPLE__) |
|
355 return FALSE; |
|
356 #else |
|
357 return TRUE; |
|
358 #endif |
|
359 } |
|
360 |
|
361 FILE * portable_popen(const char *name,const char *type) |
|
362 { |
|
363 return popen(name,type); |
|
364 } |
|
365 |
|
366 int portable_pclose(FILE *stream) |
|
367 { |
|
368 return pclose(stream); |
|
369 } |
|
370 |
|
371 double portable_getSysElapsedTime() |
|
372 { |
|
373 return sysElapsedTime; |
|
374 } |
|
375 |